diff --git a/Examples/Datastore/PackageManager/Package.swift b/Examples/Datastore/PackageManager/Package.swift index 31c247c1b..4685deb0b 100644 --- a/Examples/Datastore/PackageManager/Package.swift +++ b/Examples/Datastore/PackageManager/Package.swift @@ -17,8 +17,8 @@ import PackageDescription let package = Package ( name: "Datastore", dependencies: [ - .Package(url: "https://github.com/grpc/grpc-swift.git", Version(0,1,13)), - .Package(url: "https://github.com/apple/swift-protobuf.git", Version(0,9,903)), + .Package(url: "https://github.com/grpc/grpc-swift.git", Version(0,2,0)), + .Package(url: "https://github.com/apple/swift-protobuf.git", Version(0,9,904)), .Package(url: "https://github.com/google/auth-library-swift.git", Version(0,2,2)), ] ) diff --git a/Examples/Echo/PackageManager/Package.swift b/Examples/Echo/PackageManager/Package.swift index fc95c1cce..16ff28dae 100644 --- a/Examples/Echo/PackageManager/Package.swift +++ b/Examples/Echo/PackageManager/Package.swift @@ -17,7 +17,7 @@ import PackageDescription let package = Package ( name: "Echo", dependencies: [ - .Package(url: "https://github.com/grpc/grpc-swift.git", Version(0,1,12)), - .Package(url: "https://github.com/apple/swift-protobuf.git", Version(0,9,903)), + .Package(url: "https://github.com/grpc/grpc-swift.git", Version(0,2,0)), + .Package(url: "https://github.com/apple/swift-protobuf.git", Version(0,9,904)), ] ) diff --git a/Examples/Echo/PackageManager/Sources/main.swift b/Examples/Echo/PackageManager/Sources/main.swift index 1f8f82a20..39a658307 100644 --- a/Examples/Echo/PackageManager/Sources/main.swift +++ b/Examples/Echo/PackageManager/Sources/main.swift @@ -83,6 +83,8 @@ if server { } if client != "" { + do { + print("Starting client") var service : Echo_EchoService @@ -175,6 +177,10 @@ if client != "" { // Wait for the call to complete. latch.wait() } + + } catch let error { + print("error:\(error)") + } } if test { diff --git a/Examples/Echo/PackageManager/ssl.crt b/Examples/Echo/PackageManager/ssl.crt index d1212fc4d..766a48e4e 100644 --- a/Examples/Echo/PackageManager/ssl.crt +++ b/Examples/Echo/PackageManager/ssl.crt @@ -1,17 +1,17 @@ -----BEGIN CERTIFICATE----- -MIICqDCCAZACCQC7L1EYvLe1FDANBgkqhkiG9w0BAQsFADAWMRQwEgYDVQQDDAtl -eGFtcGxlLmNvbTAeFw0xNjAzMzEyMTA3NDZaFw0xNzAzMzEyMTA3NDZaMBYxFDAS -BgNVBAMMC2V4YW1wbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC -AQEAu2KXnItyilAByNapgqAlkOrLP7bcr4FJEuZH5LEu5yGkUT/swcZxKtuvLS5u -5hU12gr27D9MbS7mSdBMFbayrWOf615vagf+D/ReTnPCvsn/4T+sQn3qdnSgIZJ5 -6dGFpLjk0aeEQX3kctUZxGEC8tUgkoP5W42zZvcEQR3EPyJr5plzzkw6t5ZEOQid -i6xk0S7rNI2B6KoN78JoCJQr2JoYyrua1tjHB8OCHF+IXmXHhMOjfVgx1s0aqTdR -BeYVUUrt9pKgjbnNE8W1E+ur0GkCkBhWEf+VoMq6BzpUe5H5L7lFJTaHkORvrlqt -uzMhM610ecQnXTUconCkHdPPWwIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQCNoKg/ -lkYiiJqabbNe18Ja+El3qCPWNgDrS13s1Q8MsBZ1db+SQL4r6bHARtzI7SJ7uyrP -r9YGq1q11uMJ8CGDJXJkeaK003pR1wYfruRhjulV0u3Q+9IRAezEsJbiKddNNnHv -rQFtK/DQIk0aokp359mWnsRwon1zuFY4lMyPV9MonLbU91ZlnxyRuuIWc5fPrviT -Mvo163V/B9N6qhZFzrCKl4p7iDqHuSRDGoGvvx6JBDOnJH/JFcmPv4oIqIXsbefu -hRWMFf2GJI52r1Gj53Vr8SKgfWdBJ14BXXDP9/QQgKuM4b3Tcv38PQeGuwQ+jVqW -fBonjE+i2znSdOH1 +MIICqDCCAZACCQCqiXoqUJivWDANBgkqhkiG9w0BAQUFADAWMRQwEgYDVQQDEwtl +eGFtcGxlLmNvbTAeFw0xNzA5MDIwMDI5NDVaFw0xODA5MDIwMDI5NDVaMBYxFDAS +BgNVBAMTC2V4YW1wbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEA1VsheX+pqTrOV23/BZlUselhrguBI1wt0IvY3hcEPddTzjzG33LDCw2DsY5m +zfITDjar0DaOcqGNdgoMFOOnja47BZgqgZS5hdl5XzC1N7QVZ4KrdYeY6N8eaVI4 +sHreD0oUDcHtLjRY8dSI/UcyeWmJQFNrf/nQVYD1Z57WTJrTbk+L7svRAKK41+Gv +h3Y5QPl07yBGLyMMTCO4mWeslFekSDnmknniUMq+7U8s7tCTi04U33h6UhBRm328 +RJLXiSbe6D5N2X5mf4MwXyqYKaYQRnloTJfRxWk33O/zhy688/cHxHU/H4YrjN2z +IowoHMg52KUCuZgr7F48mq6F3QIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQB6GMt8 +31wrtZtFm9GSDmYKbTUTItzME42H67KnkcLoTiBDOEC1cKSIIlxZsVgTIVgF09Ko +3HBbJ6JSDXbsgTZIzVcmHxEPsmxsNCEa2zmaSCZ57DE48iOekBi+Ts0oiSo2LjpB +fWARUNXEDHCE4EKwVzDwO0/DujFFj7PeZSU1WWU0qQbTagglOGEYgLPJYfYNVw9F +8CoZIdRJV3QH6XW21WS2/dRebEbTw3wDU3QJ4P7eRDmAoZGfR6Lvk0wKcZRdtwTf +2HfM/m0AsUSB5bo9ywp2Tdhh3CGSNz//h19RrgzQpwaX2+ncSajkODHGzZAkGTRo +mqj68/iiCGEfImUe -----END CERTIFICATE----- diff --git a/Examples/Echo/PackageManager/ssl.key b/Examples/Echo/PackageManager/ssl.key index 9d7b7e9cd..2c3561eca 100644 --- a/Examples/Echo/PackageManager/ssl.key +++ b/Examples/Echo/PackageManager/ssl.key @@ -1,27 +1,27 @@ -----BEGIN RSA PRIVATE KEY----- -MIIEowIBAAKCAQEAu2KXnItyilAByNapgqAlkOrLP7bcr4FJEuZH5LEu5yGkUT/s -wcZxKtuvLS5u5hU12gr27D9MbS7mSdBMFbayrWOf615vagf+D/ReTnPCvsn/4T+s -Qn3qdnSgIZJ56dGFpLjk0aeEQX3kctUZxGEC8tUgkoP5W42zZvcEQR3EPyJr5plz -zkw6t5ZEOQidi6xk0S7rNI2B6KoN78JoCJQr2JoYyrua1tjHB8OCHF+IXmXHhMOj -fVgx1s0aqTdRBeYVUUrt9pKgjbnNE8W1E+ur0GkCkBhWEf+VoMq6BzpUe5H5L7lF -JTaHkORvrlqtuzMhM610ecQnXTUconCkHdPPWwIDAQABAoIBADlxHbzVWoVfxUxF -0azDXwCvmSKs8bWzUi1C/mLylcgwnehySieUp3hV47tb8o8BjYKLvenp9Ym6yMlz -2v8FBHz2fz1ts4WzcYR+irJN9jL6RUBNfobbhpZNZhEkj87HdcprC2nhij9xUiiJ -ft6eRoMeJmADqNsR8x7rNhioAVLAufORDGa5ThpaLTe53C7gzMcHerxBT7ZRCKqS -J8EfxYHRF5k4VM0x2Xyo2DCIvoSP+ydcKiyuHQMAIbLt0GVZ+jOUQ/JJh+PNXGm6 -HJnv6O4+WB+O+D6TzxXkjeo8MBKyJCHHxTUCRMkU6ltPihvEzuGD+9M+amz5SK4G -gxfxOyECgYEA6f93N5ASd2OE/cMNBSbsImZWFwfjcNrDX9V5QfoJ4zXPE7/e2PO/ -tfNrW7rm35RkygRzI/s7vVHoUuA6nGkeHOXUrOwiBybMk+PAflEwwdQNtXt4BJTZ -mRIskcQGnJAITjw1zc8o9/V0tOZNOpbVeCR56ucHwxA+215CO4Y4jekCgYEAzQEd -swh0kpRP+X8Xwfnnb0yXt4HCWsM4OHetz79JcOhv0LENj7zwJ3L3k0MOMZpkFKz/ -ty7SS/u3lgY1hVkJUggjw57Y9ZdIJvopx/myCLgXOaLyo24PdjpRJKIvOqYC1wQu -o3D43pgtmjVVu8i1f/+X4akIURetA7pkeWGZVKMCgYAuDjUFv5qS2wia9aADapTB -dIjvQYM3fCdGHnseTDtT+AxI49PVuav7AO0ZgeDdEpT/2f5bj6BDc/KZFT8T9/CQ -WYARhOxxoeZUGViSxCInlDgahzGpHS7y3Mve6MkwWXz5AQrJ9kMnAq20yTtcE8Hy -QqOoY054yyLEBHpewt0wuQKBgQCzusO//6y8Cb1n3u4ESUWHRZ5J60Bq9HZowzwm -Q+1uSMonK+LY3uupmljFyec6w8H0gouanTkQFrqok/7+TsYmHi7ExZIvFpfSXEaf -JSHaFRN/m4WglNCHda9IL8y6XWtl+SuubVAzTzXD2fi1Ls05T+tnkxtQhTJRb2vB -IzkbgwKBgCuymXXQ41EzdJQoTWDe8CFLrP5ynKeaKzMN32ppUMbgb+DF4L9UpDm1 -CgckZ3THQEuh7yReY/2bU+XHK/GCdheNes+CXxu4dgSaVL/LONO08RuneDK1kQ5o -e1oy4f+51rbwNGoUQ73U+cm/LSFJOir5EuNenpVZeMeQMktkg806 +MIIEpAIBAAKCAQEA1VsheX+pqTrOV23/BZlUselhrguBI1wt0IvY3hcEPddTzjzG +33LDCw2DsY5mzfITDjar0DaOcqGNdgoMFOOnja47BZgqgZS5hdl5XzC1N7QVZ4Kr +dYeY6N8eaVI4sHreD0oUDcHtLjRY8dSI/UcyeWmJQFNrf/nQVYD1Z57WTJrTbk+L +7svRAKK41+Gvh3Y5QPl07yBGLyMMTCO4mWeslFekSDnmknniUMq+7U8s7tCTi04U +33h6UhBRm328RJLXiSbe6D5N2X5mf4MwXyqYKaYQRnloTJfRxWk33O/zhy688/cH +xHU/H4YrjN2zIowoHMg52KUCuZgr7F48mq6F3QIDAQABAoIBAQDMDuoYQ5Koidb6 +ZfjoiPspYhaLmPM9N5eWA3s7BvaGkyDTeuuWoTOMqbNQKeuHg8TX7lArx1I8rukW +gYuGmyoQ5xgKRLw6zV0XeKWN9o8MJM/n/WEx+quz5lo2z23q1Mj4BJjjg5vueiCr +wuP2opbS6q5b+K0zbGHmtX2BSriZ8CdzRyMwD2fY9x21q0k7onVw1jhMtRTi6spf +CPegLOndhdscE08QDvFr0x6++VWaijV3lKFzI093opzWDfJN4VLBz0Wyod1puB2C +OoVHi++czinQ4p3Ru0vstUW7gy37sq6dhhlAp5RzVmX9RPcdrYK5G+YS8cINSuak +v2uD+YdhAoGBAPKybPshE0XBJv0YC8XOiy4twEdCwgQb24lJHMVIJcQMKXrXNGCV +9p6IlVqAYYZ7TXX/hyv4/+XxteoDctJqPjSL5M6hjIfOdV7i3bhMoJHqcpV2NzJD +52MZ28TCPyGfGU7x80ohx4xBNgMFpstglAf0YPF5gtkSPgqH563OWF2lAoGBAOEM +/HH0fU/CsAEDgqY8XUkRSfGBbgMt1wx/frhetmzuTVZ+iM3wmFlyCdpJQb/GCrOk +72JACbM0NP3hbIDZeGper5UpyuMSLi/FKUaDyc1cCDzyPs9mv0ikcwkViGJ2V0Pq +YXP4YrNb3YKbH//rzhCvOCzUHwSV55knb+lqi4HZAoGAVLBIcTVweTXWehjq+sKB +NMMIRpWYCEEEUZqurHTpoMixrMjt4QpTfayhmWwVHA1o0VUygPipqz62QQulBKHI +RSPP2v7qf/VeZZb60bYDjgdmppsS1bp2QtGiK72ws/XFqhOp1uOEs3+J7nIJawyv +ezsenQTO0RqZhak5AiBwG3UCgYEAv8d5OQLH5rhZlAORymeWdzWsdYl+Xmcp4xSi +wCq1+o34icS6gASPT2nGy6WxyeLSK9RZyrgXjAbpQZBgDk1EOCEIL2y14FsV0M+L +JPQZfE75Fja5H7THPPgmr48R8hY2t0F8Wn9IXN/kG/BljIk9ySoIDOuWoym7euAI +ljidOcECgYALG9yPR4Kmc/WG5DzN3aMZqSEo5Jwt7L9T63RG+c5mo2BSbpTYGjnS +vumUg0l1tZERuDWKSbFkFhYRlcOpMlmcWf0cDdb4WeE8/mQZMq0tTI9gkdhdGgPq +LvsXSk4yVNt8SUAJI5QQpdPGMslRWNKS0D24ikqrGswRjdikJyyF8A== -----END RSA PRIVATE KEY----- diff --git a/Examples/Echo/Xcode/Echo.xcodeproj/project.pbxproj b/Examples/Echo/Xcode/Echo.xcodeproj/project.pbxproj index 502810887..59ae53c2c 100644 --- a/Examples/Echo/Xcode/Echo.xcodeproj/project.pbxproj +++ b/Examples/Echo/Xcode/Echo.xcodeproj/project.pbxproj @@ -7,7 +7,6 @@ objects = { /* Begin PBXBuildFile section */ - D315DF011EE8C591007670CE /* SwiftProtobuf.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D315DEEA1EE8B29B007670CE /* SwiftProtobuf.framework */; }; D35358201E219963007FA223 /* echo.client.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = D353581D1E219963007FA223 /* echo.client.pb.swift */; }; D35358211E219963007FA223 /* echo.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = D353581E1E219963007FA223 /* echo.pb.swift */; }; D35358221E219963007FA223 /* echo.server.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = D353581F1E219963007FA223 /* echo.server.pb.swift */; }; @@ -16,60 +15,16 @@ D35C9FAE1D74B079000443CD /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D35C9FAD1D74B079000443CD /* Assets.xcassets */; }; D35C9FB11D74B079000443CD /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = D35C9FAF1D74B079000443CD /* MainMenu.xib */; }; D35C9FC81D74B0C1000443CD /* EchoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D35C9FC71D74B0C1000443CD /* EchoViewController.swift */; }; + D36AB73D1F58DF10007D7184 /* BoringSSL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D36AB7281F58DEDB007D7184 /* BoringSSL.framework */; }; + D36AB73E1F58DF10007D7184 /* CgRPC.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D36AB7261F58DEDB007D7184 /* CgRPC.framework */; }; + D36AB73F1F58DF10007D7184 /* Czlib.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D36AB7241F58DEDB007D7184 /* Czlib.framework */; }; + D36AB7401F58DF10007D7184 /* gRPC.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D36AB72A1F58DEDB007D7184 /* gRPC.framework */; }; + D36AB7411F58DF10007D7184 /* SwiftProtobuf.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D36AB7341F58DEDB007D7184 /* SwiftProtobuf.framework */; }; D3971E211D89132E001A0B3F /* ssl.key in Resources */ = {isa = PBXBuildFile; fileRef = D3971E201D89132E001A0B3F /* ssl.key */; }; D3BFE28C1D87A45D00A648D8 /* ssl.crt in Resources */ = {isa = PBXBuildFile; fileRef = D3BFE28B1D87A45D00A648D8 /* ssl.crt */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ - D315DED31EE8B284007670CE /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = D315DECA1EE8B284007670CE /* SwiftGRPC.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = OBJ_803; - remoteInfo = "zlib-example"; - }; - D315DED51EE8B284007670CE /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = D315DECA1EE8B284007670CE /* SwiftGRPC.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = OBJ_804; - remoteInfo = Czlib; - }; - D315DED71EE8B284007670CE /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = D315DECA1EE8B284007670CE /* SwiftGRPC.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = OBJ_805; - remoteInfo = CgRPC; - }; - D315DED91EE8B284007670CE /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = D315DECA1EE8B284007670CE /* SwiftGRPC.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = OBJ_806; - remoteInfo = BoringSSL; - }; - D315DEDB1EE8B284007670CE /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = D315DECA1EE8B284007670CE /* SwiftGRPC.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = OBJ_807; - remoteInfo = gRPC; - }; - D315DEDD1EE8B284007670CE /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = D315DECA1EE8B284007670CE /* SwiftGRPC.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = OBJ_808; - remoteInfo = gRPCTests; - }; - D315DEE91EE8B29B007670CE /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = D315DEDF1EE8B29A007670CE /* SwiftProtobuf.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = "_____Product_Protobuf_macOS"; - remoteInfo = SwiftProtobuf_macOS; - }; D315DEEB1EE8B29B007670CE /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = D315DEDF1EE8B29A007670CE /* SwiftProtobuf.xcodeproj */; @@ -119,38 +74,86 @@ remoteGlobalIDString = "______Target_Protobuf"; remoteInfo = SwiftProtobuf_macOS; }; - D315DEF91EE8B2C7007670CE /* PBXContainerItemProxy */ = { + D36AB7211F58DEDB007D7184 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D36AB7181F58DEDB007D7184 /* SwiftGRPC.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = OBJ_867; + remoteInfo = "zlib-example"; + }; + D36AB7231F58DEDB007D7184 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D36AB7181F58DEDB007D7184 /* SwiftGRPC.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = OBJ_868; + remoteInfo = Czlib; + }; + D36AB7251F58DEDB007D7184 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D36AB7181F58DEDB007D7184 /* SwiftGRPC.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = OBJ_869; + remoteInfo = CgRPC; + }; + D36AB7271F58DEDB007D7184 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D36AB7181F58DEDB007D7184 /* SwiftGRPC.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = OBJ_870; + remoteInfo = BoringSSL; + }; + D36AB7291F58DEDB007D7184 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D36AB7181F58DEDB007D7184 /* SwiftGRPC.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = OBJ_871; + remoteInfo = gRPC; + }; + D36AB72B1F58DEDB007D7184 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D36AB7181F58DEDB007D7184 /* SwiftGRPC.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = OBJ_872; + remoteInfo = gRPCTests; + }; + D36AB7331F58DEDB007D7184 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D315DEDF1EE8B29A007670CE /* SwiftProtobuf.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = "_____Product_Protobuf_macOS"; + remoteInfo = SwiftProtobuf_macOS; + }; + D36AB7351F58DF02007D7184 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; - containerPortal = D315DECA1EE8B284007670CE /* SwiftGRPC.xcodeproj */; + containerPortal = D36AB7181F58DEDB007D7184 /* SwiftGRPC.xcodeproj */; proxyType = 1; - remoteGlobalIDString = OBJ_818; + remoteGlobalIDString = OBJ_882; remoteInfo = Czlib; }; - D315DEFB1EE8B2C7007670CE /* PBXContainerItemProxy */ = { + D36AB7371F58DF02007D7184 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; - containerPortal = D315DECA1EE8B284007670CE /* SwiftGRPC.xcodeproj */; + containerPortal = D36AB7181F58DEDB007D7184 /* SwiftGRPC.xcodeproj */; proxyType = 1; - remoteGlobalIDString = OBJ_840; + remoteGlobalIDString = OBJ_904; remoteInfo = CgRPC; }; - D315DEFD1EE8B2C7007670CE /* PBXContainerItemProxy */ = { + D36AB7391F58DF02007D7184 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; - containerPortal = D315DECA1EE8B284007670CE /* SwiftGRPC.xcodeproj */; + containerPortal = D36AB7181F58DEDB007D7184 /* SwiftGRPC.xcodeproj */; proxyType = 1; - remoteGlobalIDString = OBJ_1122; + remoteGlobalIDString = OBJ_1231; remoteInfo = BoringSSL; }; - D315DEFF1EE8B2C7007670CE /* PBXContainerItemProxy */ = { + D36AB73B1F58DF02007D7184 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; - containerPortal = D315DECA1EE8B284007670CE /* SwiftGRPC.xcodeproj */; + containerPortal = D36AB7181F58DEDB007D7184 /* SwiftGRPC.xcodeproj */; proxyType = 1; - remoteGlobalIDString = OBJ_1428; + remoteGlobalIDString = OBJ_1543; remoteInfo = gRPC; }; /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ - D315DECA1EE8B284007670CE /* SwiftGRPC.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = SwiftGRPC.xcodeproj; path = ../../../SwiftGRPC.xcodeproj; sourceTree = ""; }; D315DEDF1EE8B29A007670CE /* SwiftProtobuf.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = SwiftProtobuf.xcodeproj; path = "../../../third_party/swift-protobuf/SwiftProtobuf.xcodeproj"; sourceTree = ""; }; D353581D1E219963007FA223 /* echo.client.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = echo.client.pb.swift; path = ../Generated/echo.client.pb.swift; sourceTree = ""; }; D353581E1E219963007FA223 /* echo.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = echo.pb.swift; path = ../Generated/echo.pb.swift; sourceTree = ""; }; @@ -162,6 +165,7 @@ D35C9FB01D74B079000443CD /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; D35C9FB21D74B079000443CD /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; D35C9FC71D74B0C1000443CD /* EchoViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EchoViewController.swift; sourceTree = ""; }; + D36AB7181F58DEDB007D7184 /* SwiftGRPC.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = SwiftGRPC.xcodeproj; path = ../../../SwiftGRPC.xcodeproj; sourceTree = ""; }; D3971E201D89132E001A0B3F /* ssl.key */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = ssl.key; sourceTree = ""; }; D3BFE28B1D87A45D00A648D8 /* ssl.crt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = ssl.crt; sourceTree = ""; }; /* End PBXFileReference section */ @@ -171,30 +175,21 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - D315DF011EE8C591007670CE /* SwiftProtobuf.framework in Frameworks */, + D36AB73D1F58DF10007D7184 /* BoringSSL.framework in Frameworks */, + D36AB73E1F58DF10007D7184 /* CgRPC.framework in Frameworks */, + D36AB73F1F58DF10007D7184 /* Czlib.framework in Frameworks */, + D36AB7401F58DF10007D7184 /* gRPC.framework in Frameworks */, + D36AB7411F58DF10007D7184 /* SwiftProtobuf.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - D315DECB1EE8B284007670CE /* Products */ = { - isa = PBXGroup; - children = ( - D315DED41EE8B284007670CE /* zlib-example */, - D315DED61EE8B284007670CE /* Czlib.framework */, - D315DED81EE8B284007670CE /* CgRPC.framework */, - D315DEDA1EE8B284007670CE /* BoringSSL.framework */, - D315DEDC1EE8B284007670CE /* gRPC.framework */, - D315DEDE1EE8B284007670CE /* gRPCTests.xctest */, - ); - name = Products; - sourceTree = ""; - }; D315DEE01EE8B29A007670CE /* Products */ = { isa = PBXGroup; children = ( - D315DEEA1EE8B29B007670CE /* SwiftProtobuf.framework */, + D36AB7341F58DEDB007D7184 /* SwiftProtobuf.framework */, D315DEEC1EE8B29B007670CE /* SwiftProtobufTests.xctest */, D315DEEE1EE8B29B007670CE /* SwiftProtobuf.framework */, D315DEF01EE8B29B007670CE /* SwiftProtobufTests.xctest */, @@ -218,8 +213,8 @@ D35C9F9F1D74B079000443CD = { isa = PBXGroup; children = ( + D36AB7181F58DEDB007D7184 /* SwiftGRPC.xcodeproj */, D315DEDF1EE8B29A007670CE /* SwiftProtobuf.xcodeproj */, - D315DECA1EE8B284007670CE /* SwiftGRPC.xcodeproj */, D35C9FAA1D74B079000443CD /* Echo */, D35358231E219971007FA223 /* Generated */, D35358241E219980007FA223 /* EchoProvider.swift */, @@ -249,6 +244,19 @@ path = Echo; sourceTree = ""; }; + D36AB7191F58DEDB007D7184 /* Products */ = { + isa = PBXGroup; + children = ( + D36AB7221F58DEDB007D7184 /* zlib-example */, + D36AB7241F58DEDB007D7184 /* Czlib.framework */, + D36AB7261F58DEDB007D7184 /* CgRPC.framework */, + D36AB7281F58DEDB007D7184 /* BoringSSL.framework */, + D36AB72A1F58DEDB007D7184 /* gRPC.framework */, + D36AB72C1F58DEDB007D7184 /* gRPCTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -263,6 +271,10 @@ buildRules = ( ); dependencies = ( + D36AB7361F58DF02007D7184 /* PBXTargetDependency */, + D36AB7381F58DF02007D7184 /* PBXTargetDependency */, + D36AB73A1F58DF02007D7184 /* PBXTargetDependency */, + D36AB73C1F58DF02007D7184 /* PBXTargetDependency */, D315DEFA1EE8B2C7007670CE /* PBXTargetDependency */, D315DEFC1EE8B2C7007670CE /* PBXTargetDependency */, D315DEFE1EE8B2C7007670CE /* PBXTargetDependency */, @@ -304,8 +316,8 @@ projectDirPath = ""; projectReferences = ( { - ProductGroup = D315DECB1EE8B284007670CE /* Products */; - ProjectRef = D315DECA1EE8B284007670CE /* SwiftGRPC.xcodeproj */; + ProductGroup = D36AB7191F58DEDB007D7184 /* Products */; + ProjectRef = D36AB7181F58DEDB007D7184 /* SwiftGRPC.xcodeproj */; }, { ProductGroup = D315DEE01EE8B29A007670CE /* Products */; @@ -320,95 +332,95 @@ /* End PBXProject section */ /* Begin PBXReferenceProxy section */ - D315DED41EE8B284007670CE /* zlib-example */ = { + D315DEEC1EE8B29B007670CE /* SwiftProtobufTests.xctest */ = { isa = PBXReferenceProxy; - fileType = "compiled.mach-o.executable"; - path = "zlib-example"; - remoteRef = D315DED31EE8B284007670CE /* PBXContainerItemProxy */; + fileType = wrapper.cfbundle; + path = SwiftProtobufTests.xctest; + remoteRef = D315DEEB1EE8B29B007670CE /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; - D315DED61EE8B284007670CE /* Czlib.framework */ = { + D315DEEE1EE8B29B007670CE /* SwiftProtobuf.framework */ = { isa = PBXReferenceProxy; fileType = wrapper.framework; - path = Czlib.framework; - remoteRef = D315DED51EE8B284007670CE /* PBXContainerItemProxy */; + path = SwiftProtobuf.framework; + remoteRef = D315DEED1EE8B29B007670CE /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; - D315DED81EE8B284007670CE /* CgRPC.framework */ = { + D315DEF01EE8B29B007670CE /* SwiftProtobufTests.xctest */ = { isa = PBXReferenceProxy; - fileType = wrapper.framework; - path = CgRPC.framework; - remoteRef = D315DED71EE8B284007670CE /* PBXContainerItemProxy */; + fileType = wrapper.cfbundle; + path = SwiftProtobufTests.xctest; + remoteRef = D315DEEF1EE8B29B007670CE /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; - D315DEDA1EE8B284007670CE /* BoringSSL.framework */ = { + D315DEF21EE8B29B007670CE /* SwiftProtobuf.framework */ = { isa = PBXReferenceProxy; fileType = wrapper.framework; - path = BoringSSL.framework; - remoteRef = D315DED91EE8B284007670CE /* PBXContainerItemProxy */; + path = SwiftProtobuf.framework; + remoteRef = D315DEF11EE8B29B007670CE /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; - D315DEDC1EE8B284007670CE /* gRPC.framework */ = { + D315DEF41EE8B29B007670CE /* SwiftProtobufTests.xctest */ = { isa = PBXReferenceProxy; - fileType = wrapper.framework; - path = gRPC.framework; - remoteRef = D315DEDB1EE8B284007670CE /* PBXContainerItemProxy */; + fileType = wrapper.cfbundle; + path = SwiftProtobufTests.xctest; + remoteRef = D315DEF31EE8B29B007670CE /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; - D315DEDE1EE8B284007670CE /* gRPCTests.xctest */ = { + D315DEF61EE8B29B007670CE /* SwiftProtobuf.framework */ = { isa = PBXReferenceProxy; - fileType = file; - path = gRPCTests.xctest; - remoteRef = D315DEDD1EE8B284007670CE /* PBXContainerItemProxy */; + fileType = wrapper.framework; + path = SwiftProtobuf.framework; + remoteRef = D315DEF51EE8B29B007670CE /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; - D315DEEA1EE8B29B007670CE /* SwiftProtobuf.framework */ = { + D36AB7221F58DEDB007D7184 /* zlib-example */ = { isa = PBXReferenceProxy; - fileType = wrapper.framework; - path = SwiftProtobuf.framework; - remoteRef = D315DEE91EE8B29B007670CE /* PBXContainerItemProxy */; + fileType = "compiled.mach-o.executable"; + path = "zlib-example"; + remoteRef = D36AB7211F58DEDB007D7184 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; - D315DEEC1EE8B29B007670CE /* SwiftProtobufTests.xctest */ = { + D36AB7241F58DEDB007D7184 /* Czlib.framework */ = { isa = PBXReferenceProxy; - fileType = wrapper.cfbundle; - path = SwiftProtobufTests.xctest; - remoteRef = D315DEEB1EE8B29B007670CE /* PBXContainerItemProxy */; + fileType = wrapper.framework; + path = Czlib.framework; + remoteRef = D36AB7231F58DEDB007D7184 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; - D315DEEE1EE8B29B007670CE /* SwiftProtobuf.framework */ = { + D36AB7261F58DEDB007D7184 /* CgRPC.framework */ = { isa = PBXReferenceProxy; fileType = wrapper.framework; - path = SwiftProtobuf.framework; - remoteRef = D315DEED1EE8B29B007670CE /* PBXContainerItemProxy */; + path = CgRPC.framework; + remoteRef = D36AB7251F58DEDB007D7184 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; - D315DEF01EE8B29B007670CE /* SwiftProtobufTests.xctest */ = { + D36AB7281F58DEDB007D7184 /* BoringSSL.framework */ = { isa = PBXReferenceProxy; - fileType = wrapper.cfbundle; - path = SwiftProtobufTests.xctest; - remoteRef = D315DEEF1EE8B29B007670CE /* PBXContainerItemProxy */; + fileType = wrapper.framework; + path = BoringSSL.framework; + remoteRef = D36AB7271F58DEDB007D7184 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; - D315DEF21EE8B29B007670CE /* SwiftProtobuf.framework */ = { + D36AB72A1F58DEDB007D7184 /* gRPC.framework */ = { isa = PBXReferenceProxy; fileType = wrapper.framework; - path = SwiftProtobuf.framework; - remoteRef = D315DEF11EE8B29B007670CE /* PBXContainerItemProxy */; + path = gRPC.framework; + remoteRef = D36AB7291F58DEDB007D7184 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; - D315DEF41EE8B29B007670CE /* SwiftProtobufTests.xctest */ = { + D36AB72C1F58DEDB007D7184 /* gRPCTests.xctest */ = { isa = PBXReferenceProxy; - fileType = wrapper.cfbundle; - path = SwiftProtobufTests.xctest; - remoteRef = D315DEF31EE8B29B007670CE /* PBXContainerItemProxy */; + fileType = file; + path = gRPCTests.xctest; + remoteRef = D36AB72B1F58DEDB007D7184 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; - D315DEF61EE8B29B007670CE /* SwiftProtobuf.framework */ = { + D36AB7341F58DEDB007D7184 /* SwiftProtobuf.framework */ = { isa = PBXReferenceProxy; fileType = wrapper.framework; path = SwiftProtobuf.framework; - remoteRef = D315DEF51EE8B29B007670CE /* PBXContainerItemProxy */; + remoteRef = D36AB7331F58DEDB007D7184 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXReferenceProxy section */ @@ -452,22 +464,38 @@ D315DEFA1EE8B2C7007670CE /* PBXTargetDependency */ = { isa = PBXTargetDependency; name = Czlib; - targetProxy = D315DEF91EE8B2C7007670CE /* PBXContainerItemProxy */; }; D315DEFC1EE8B2C7007670CE /* PBXTargetDependency */ = { isa = PBXTargetDependency; name = CgRPC; - targetProxy = D315DEFB1EE8B2C7007670CE /* PBXContainerItemProxy */; }; D315DEFE1EE8B2C7007670CE /* PBXTargetDependency */ = { isa = PBXTargetDependency; name = BoringSSL; - targetProxy = D315DEFD1EE8B2C7007670CE /* PBXContainerItemProxy */; }; D315DF001EE8B2C7007670CE /* PBXTargetDependency */ = { isa = PBXTargetDependency; name = gRPC; - targetProxy = D315DEFF1EE8B2C7007670CE /* PBXContainerItemProxy */; + }; + D36AB7361F58DF02007D7184 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = Czlib; + targetProxy = D36AB7351F58DF02007D7184 /* PBXContainerItemProxy */; + }; + D36AB7381F58DF02007D7184 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = CgRPC; + targetProxy = D36AB7371F58DF02007D7184 /* PBXContainerItemProxy */; + }; + D36AB73A1F58DF02007D7184 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = BoringSSL; + targetProxy = D36AB7391F58DF02007D7184 /* PBXContainerItemProxy */; + }; + D36AB73C1F58DF02007D7184 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = gRPC; + targetProxy = D36AB73B1F58DF02007D7184 /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ diff --git a/Examples/Simple/PackageManager/Package.swift b/Examples/Simple/PackageManager/Package.swift index 3e77f432c..d21f7b252 100644 --- a/Examples/Simple/PackageManager/Package.swift +++ b/Examples/Simple/PackageManager/Package.swift @@ -17,6 +17,6 @@ import PackageDescription let package = Package ( name: "Simple", dependencies: [ - .Package(url: "https://github.com/grpc/grpc-swift.git", Version(0,1,12)), + .Package(url: "https://github.com/grpc/grpc-swift.git", Version(0,2,0)), ] ) diff --git a/Examples/Simple/Xcode/Simple.xcodeproj/project.pbxproj b/Examples/Simple/Xcode/Simple.xcodeproj/project.pbxproj index 29780a479..477eb5697 100644 --- a/Examples/Simple/Xcode/Simple.xcodeproj/project.pbxproj +++ b/Examples/Simple/Xcode/Simple.xcodeproj/project.pbxproj @@ -12,78 +12,82 @@ D30D73601D565E4400F90CCB /* Document.xib in Resources */ = {isa = PBXBuildFile; fileRef = D30D735E1D565E4400F90CCB /* Document.xib */; }; D30D73621D565E4400F90CCB /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D30D73611D565E4400F90CCB /* Assets.xcassets */; }; D30D73651D565E4400F90CCB /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = D30D73631D565E4400F90CCB /* MainMenu.xib */; }; + D394EF271F58DBA300E99633 /* BoringSSL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D394EF1A1F58DB7A00E99633 /* BoringSSL.framework */; }; + D394EF281F58DBA300E99633 /* CgRPC.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D394EF181F58DB7A00E99633 /* CgRPC.framework */; }; + D394EF291F58DBA300E99633 /* Czlib.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D394EF161F58DB7A00E99633 /* Czlib.framework */; }; + D394EF2A1F58DBA300E99633 /* gRPC.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D394EF1C1F58DB7A00E99633 /* gRPC.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ - D3E1EA701EE8AFEB0024A93A /* PBXContainerItemProxy */ = { + D394EF131F58DB7A00E99633 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; - containerPortal = D3E1EA671EE8AFEB0024A93A /* SwiftGRPC.xcodeproj */; + containerPortal = D394EF0A1F58DB7A00E99633 /* SwiftGRPC.xcodeproj */; proxyType = 2; - remoteGlobalIDString = OBJ_803; + remoteGlobalIDString = OBJ_867; remoteInfo = "zlib-example"; }; - D3E1EA721EE8AFEB0024A93A /* PBXContainerItemProxy */ = { + D394EF151F58DB7A00E99633 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; - containerPortal = D3E1EA671EE8AFEB0024A93A /* SwiftGRPC.xcodeproj */; + containerPortal = D394EF0A1F58DB7A00E99633 /* SwiftGRPC.xcodeproj */; proxyType = 2; - remoteGlobalIDString = OBJ_804; + remoteGlobalIDString = OBJ_868; remoteInfo = Czlib; }; - D3E1EA741EE8AFEB0024A93A /* PBXContainerItemProxy */ = { + D394EF171F58DB7A00E99633 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; - containerPortal = D3E1EA671EE8AFEB0024A93A /* SwiftGRPC.xcodeproj */; + containerPortal = D394EF0A1F58DB7A00E99633 /* SwiftGRPC.xcodeproj */; proxyType = 2; - remoteGlobalIDString = OBJ_805; + remoteGlobalIDString = OBJ_869; remoteInfo = CgRPC; }; - D3E1EA761EE8AFEB0024A93A /* PBXContainerItemProxy */ = { + D394EF191F58DB7A00E99633 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; - containerPortal = D3E1EA671EE8AFEB0024A93A /* SwiftGRPC.xcodeproj */; + containerPortal = D394EF0A1F58DB7A00E99633 /* SwiftGRPC.xcodeproj */; proxyType = 2; - remoteGlobalIDString = OBJ_806; + remoteGlobalIDString = OBJ_870; remoteInfo = BoringSSL; }; - D3E1EA781EE8AFEB0024A93A /* PBXContainerItemProxy */ = { + D394EF1B1F58DB7A00E99633 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; - containerPortal = D3E1EA671EE8AFEB0024A93A /* SwiftGRPC.xcodeproj */; + containerPortal = D394EF0A1F58DB7A00E99633 /* SwiftGRPC.xcodeproj */; proxyType = 2; - remoteGlobalIDString = OBJ_807; + remoteGlobalIDString = OBJ_871; remoteInfo = gRPC; }; - D3E1EA7A1EE8AFEB0024A93A /* PBXContainerItemProxy */ = { + D394EF1D1F58DB7A00E99633 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; - containerPortal = D3E1EA671EE8AFEB0024A93A /* SwiftGRPC.xcodeproj */; + containerPortal = D394EF0A1F58DB7A00E99633 /* SwiftGRPC.xcodeproj */; proxyType = 2; - remoteGlobalIDString = OBJ_808; + remoteGlobalIDString = OBJ_872; remoteInfo = gRPCTests; }; - D3E1EA7C1EE8B0070024A93A /* PBXContainerItemProxy */ = { + D394EF1F1F58DB9800E99633 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; - containerPortal = D3E1EA671EE8AFEB0024A93A /* SwiftGRPC.xcodeproj */; + containerPortal = D394EF0A1F58DB7A00E99633 /* SwiftGRPC.xcodeproj */; proxyType = 1; - remoteGlobalIDString = OBJ_1428; - remoteInfo = gRPC; + remoteGlobalIDString = OBJ_882; + remoteInfo = Czlib; }; - D3E1EA7E1EE8B00C0024A93A /* PBXContainerItemProxy */ = { + D394EF211F58DB9800E99633 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; - containerPortal = D3E1EA671EE8AFEB0024A93A /* SwiftGRPC.xcodeproj */; + containerPortal = D394EF0A1F58DB7A00E99633 /* SwiftGRPC.xcodeproj */; proxyType = 1; - remoteGlobalIDString = OBJ_840; + remoteGlobalIDString = OBJ_904; remoteInfo = CgRPC; }; - D3E1EA801EE8B0120024A93A /* PBXContainerItemProxy */ = { + D394EF231F58DB9800E99633 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; - containerPortal = D3E1EA671EE8AFEB0024A93A /* SwiftGRPC.xcodeproj */; + containerPortal = D394EF0A1F58DB7A00E99633 /* SwiftGRPC.xcodeproj */; proxyType = 1; - remoteGlobalIDString = OBJ_818; - remoteInfo = Czlib; + remoteGlobalIDString = OBJ_1231; + remoteInfo = BoringSSL; }; - D3E1EA821EE8B0120024A93A /* PBXContainerItemProxy */ = { + D394EF251F58DB9800E99633 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; - containerPortal = D3E1EA671EE8AFEB0024A93A /* SwiftGRPC.xcodeproj */; + containerPortal = D394EF0A1F58DB7A00E99633 /* SwiftGRPC.xcodeproj */; proxyType = 1; - remoteGlobalIDString = OBJ_1122; - remoteInfo = BoringSSL; + remoteGlobalIDString = OBJ_1543; + remoteInfo = gRPC; }; /* End PBXContainerItemProxy section */ @@ -95,7 +99,7 @@ D30D73611D565E4400F90CCB /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; D30D73641D565E4400F90CCB /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; D30D73661D565E4400F90CCB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - D3E1EA671EE8AFEB0024A93A /* SwiftGRPC.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = SwiftGRPC.xcodeproj; path = ../../../SwiftGRPC.xcodeproj; sourceTree = ""; }; + D394EF0A1F58DB7A00E99633 /* SwiftGRPC.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = SwiftGRPC.xcodeproj; path = ../../../SwiftGRPC.xcodeproj; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -103,6 +107,10 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + D394EF271F58DBA300E99633 /* BoringSSL.framework in Frameworks */, + D394EF281F58DBA300E99633 /* CgRPC.framework in Frameworks */, + D394EF291F58DBA300E99633 /* Czlib.framework in Frameworks */, + D394EF2A1F58DBA300E99633 /* gRPC.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -112,7 +120,7 @@ D30D734E1D565E4400F90CCB = { isa = PBXGroup; children = ( - D3E1EA671EE8AFEB0024A93A /* SwiftGRPC.xcodeproj */, + D394EF0A1F58DB7A00E99633 /* SwiftGRPC.xcodeproj */, D30D73591D565E4400F90CCB /* Simple */, D30D73581D565E4400F90CCB /* Products */, ); @@ -139,15 +147,15 @@ path = Simple; sourceTree = ""; }; - D3E1EA681EE8AFEB0024A93A /* Products */ = { + D394EF0B1F58DB7A00E99633 /* Products */ = { isa = PBXGroup; children = ( - D3E1EA711EE8AFEB0024A93A /* zlib-example */, - D3E1EA731EE8AFEB0024A93A /* Czlib.framework */, - D3E1EA751EE8AFEB0024A93A /* CgRPC.framework */, - D3E1EA771EE8AFEB0024A93A /* BoringSSL.framework */, - D3E1EA791EE8AFEB0024A93A /* gRPC.framework */, - D3E1EA7B1EE8AFEB0024A93A /* gRPCTests.xctest */, + D394EF141F58DB7A00E99633 /* zlib-example */, + D394EF161F58DB7A00E99633 /* Czlib.framework */, + D394EF181F58DB7A00E99633 /* CgRPC.framework */, + D394EF1A1F58DB7A00E99633 /* BoringSSL.framework */, + D394EF1C1F58DB7A00E99633 /* gRPC.framework */, + D394EF1E1F58DB7A00E99633 /* gRPCTests.xctest */, ); name = Products; sourceTree = ""; @@ -166,6 +174,10 @@ buildRules = ( ); dependencies = ( + D394EF201F58DB9800E99633 /* PBXTargetDependency */, + D394EF221F58DB9800E99633 /* PBXTargetDependency */, + D394EF241F58DB9800E99633 /* PBXTargetDependency */, + D394EF261F58DB9800E99633 /* PBXTargetDependency */, D3E1EA811EE8B0120024A93A /* PBXTargetDependency */, D3E1EA831EE8B0120024A93A /* PBXTargetDependency */, D3E1EA7F1EE8B00C0024A93A /* PBXTargetDependency */, @@ -210,8 +222,8 @@ projectDirPath = ""; projectReferences = ( { - ProductGroup = D3E1EA681EE8AFEB0024A93A /* Products */; - ProjectRef = D3E1EA671EE8AFEB0024A93A /* SwiftGRPC.xcodeproj */; + ProductGroup = D394EF0B1F58DB7A00E99633 /* Products */; + ProjectRef = D394EF0A1F58DB7A00E99633 /* SwiftGRPC.xcodeproj */; }, ); projectRoot = ""; @@ -222,46 +234,46 @@ /* End PBXProject section */ /* Begin PBXReferenceProxy section */ - D3E1EA711EE8AFEB0024A93A /* zlib-example */ = { + D394EF141F58DB7A00E99633 /* zlib-example */ = { isa = PBXReferenceProxy; fileType = "compiled.mach-o.executable"; path = "zlib-example"; - remoteRef = D3E1EA701EE8AFEB0024A93A /* PBXContainerItemProxy */; + remoteRef = D394EF131F58DB7A00E99633 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; - D3E1EA731EE8AFEB0024A93A /* Czlib.framework */ = { + D394EF161F58DB7A00E99633 /* Czlib.framework */ = { isa = PBXReferenceProxy; fileType = wrapper.framework; path = Czlib.framework; - remoteRef = D3E1EA721EE8AFEB0024A93A /* PBXContainerItemProxy */; + remoteRef = D394EF151F58DB7A00E99633 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; - D3E1EA751EE8AFEB0024A93A /* CgRPC.framework */ = { + D394EF181F58DB7A00E99633 /* CgRPC.framework */ = { isa = PBXReferenceProxy; fileType = wrapper.framework; path = CgRPC.framework; - remoteRef = D3E1EA741EE8AFEB0024A93A /* PBXContainerItemProxy */; + remoteRef = D394EF171F58DB7A00E99633 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; - D3E1EA771EE8AFEB0024A93A /* BoringSSL.framework */ = { + D394EF1A1F58DB7A00E99633 /* BoringSSL.framework */ = { isa = PBXReferenceProxy; fileType = wrapper.framework; path = BoringSSL.framework; - remoteRef = D3E1EA761EE8AFEB0024A93A /* PBXContainerItemProxy */; + remoteRef = D394EF191F58DB7A00E99633 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; - D3E1EA791EE8AFEB0024A93A /* gRPC.framework */ = { + D394EF1C1F58DB7A00E99633 /* gRPC.framework */ = { isa = PBXReferenceProxy; fileType = wrapper.framework; path = gRPC.framework; - remoteRef = D3E1EA781EE8AFEB0024A93A /* PBXContainerItemProxy */; + remoteRef = D394EF1B1F58DB7A00E99633 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; - D3E1EA7B1EE8AFEB0024A93A /* gRPCTests.xctest */ = { + D394EF1E1F58DB7A00E99633 /* gRPCTests.xctest */ = { isa = PBXReferenceProxy; fileType = file; path = gRPCTests.xctest; - remoteRef = D3E1EA7A1EE8AFEB0024A93A /* PBXContainerItemProxy */; + remoteRef = D394EF1D1F58DB7A00E99633 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXReferenceProxy section */ @@ -304,25 +316,41 @@ isa = PBXTargetDependency; name = gRPC; }; + D394EF201F58DB9800E99633 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = Czlib; + targetProxy = D394EF1F1F58DB9800E99633 /* PBXContainerItemProxy */; + }; + D394EF221F58DB9800E99633 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = CgRPC; + targetProxy = D394EF211F58DB9800E99633 /* PBXContainerItemProxy */; + }; + D394EF241F58DB9800E99633 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = BoringSSL; + targetProxy = D394EF231F58DB9800E99633 /* PBXContainerItemProxy */; + }; + D394EF261F58DB9800E99633 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = gRPC; + targetProxy = D394EF251F58DB9800E99633 /* PBXContainerItemProxy */; + }; D3E1EA7D1EE8B0070024A93A /* PBXTargetDependency */ = { isa = PBXTargetDependency; name = gRPC; - targetProxy = D3E1EA7C1EE8B0070024A93A /* PBXContainerItemProxy */; }; D3E1EA7F1EE8B00C0024A93A /* PBXTargetDependency */ = { isa = PBXTargetDependency; name = CgRPC; - targetProxy = D3E1EA7E1EE8B00C0024A93A /* PBXContainerItemProxy */; }; D3E1EA811EE8B0120024A93A /* PBXTargetDependency */ = { isa = PBXTargetDependency; name = Czlib; - targetProxy = D3E1EA801EE8B0120024A93A /* PBXContainerItemProxy */; }; D3E1EA831EE8B0120024A93A /* PBXTargetDependency */ = { isa = PBXTargetDependency; name = BoringSSL; - targetProxy = D3E1EA821EE8B0120024A93A /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ diff --git a/README.md b/README.md index e2ec0f839..e4dd38863 100644 --- a/README.md +++ b/README.md @@ -112,7 +112,7 @@ testing with the following versions: - Xcode 8.3.2 (8E2002) - Swift 3.1 (swiftlang-802.0.53 clang-802.0.42) -- swift-protobuf 0.9.903 +- swift-protobuf 0.9.904 ## License diff --git a/Sources/BoringSSL/crypto/aes/aes.c b/Sources/BoringSSL/crypto/aes/aes.c index 882391986..1aed63e51 100644 --- a/Sources/BoringSSL/crypto/aes/aes.c +++ b/Sources/BoringSSL/crypto/aes/aes.c @@ -1066,12 +1066,12 @@ static int hwaes_capable(void) { return CRYPTO_is_ARMv8_AES_capable(); } -int aes_v8_set_encrypt_key(const uint8_t *user_key, const int bits, +int aes_hw_set_encrypt_key(const uint8_t *user_key, const int bits, AES_KEY *key); -int aes_v8_set_decrypt_key(const uint8_t *user_key, const int bits, +int aes_hw_set_decrypt_key(const uint8_t *user_key, const int bits, AES_KEY *key); -void aes_v8_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key); -void aes_v8_decrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key); +void aes_hw_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key); +void aes_hw_decrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key); #else @@ -1079,19 +1079,19 @@ static int hwaes_capable(void) { return 0; } -static int aes_v8_set_encrypt_key(const uint8_t *user_key, int bits, AES_KEY *key) { +static int aes_hw_set_encrypt_key(const uint8_t *user_key, int bits, AES_KEY *key) { abort(); } -static int aes_v8_set_decrypt_key(const uint8_t *user_key, int bits, AES_KEY *key) { +static int aes_hw_set_decrypt_key(const uint8_t *user_key, int bits, AES_KEY *key) { abort(); } -static void aes_v8_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) { +static void aes_hw_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) { abort(); } -static void aes_v8_decrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) { +static void aes_hw_decrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) { abort(); } @@ -1106,7 +1106,7 @@ static void aes_v8_decrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) void asm_AES_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key); void AES_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) { if (hwaes_capable()) { - aes_v8_encrypt(in, out, key); + aes_hw_encrypt(in, out, key); } else { asm_AES_encrypt(in, out, key); } @@ -1115,7 +1115,7 @@ void AES_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) { void asm_AES_decrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key); void AES_decrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) { if (hwaes_capable()) { - aes_v8_decrypt(in, out, key); + aes_hw_decrypt(in, out, key); } else { asm_AES_decrypt(in, out, key); } @@ -1124,7 +1124,7 @@ void AES_decrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) { int asm_AES_set_encrypt_key(const uint8_t *key, unsigned bits, AES_KEY *aeskey); int AES_set_encrypt_key(const uint8_t *key, unsigned bits, AES_KEY *aeskey) { if (hwaes_capable()) { - return aes_v8_set_encrypt_key(key, bits, aeskey); + return aes_hw_set_encrypt_key(key, bits, aeskey); } else { return asm_AES_set_encrypt_key(key, bits, aeskey); } @@ -1133,7 +1133,7 @@ int AES_set_encrypt_key(const uint8_t *key, unsigned bits, AES_KEY *aeskey) { int asm_AES_set_decrypt_key(const uint8_t *key, unsigned bits, AES_KEY *aeskey); int AES_set_decrypt_key(const uint8_t *key, unsigned bits, AES_KEY *aeskey) { if (hwaes_capable()) { - return aes_v8_set_decrypt_key(key, bits, aeskey); + return aes_hw_set_decrypt_key(key, bits, aeskey); } else { return asm_AES_set_decrypt_key(key, bits, aeskey); } diff --git a/Sources/BoringSSL/crypto/aes/key_wrap.c b/Sources/BoringSSL/crypto/aes/key_wrap.c new file mode 100644 index 000000000..23553b7ad --- /dev/null +++ b/Sources/BoringSSL/crypto/aes/key_wrap.c @@ -0,0 +1,138 @@ +/* ==================================================================== + * Copyright (c) 2001-2011 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== */ + +#include + +#include +#include + +#include + +#include "../internal.h" + + +/* kDefaultIV is the default IV value given in RFC 3394, 2.2.3.1. */ +static const uint8_t kDefaultIV[] = { + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, +}; + +static const unsigned kBound = 6; + +int AES_wrap_key(const AES_KEY *key, const uint8_t *iv, uint8_t *out, + const uint8_t *in, size_t in_len) { + /* See RFC 3394, section 2.2.1. */ + + if (in_len > INT_MAX - 8 || in_len < 8 || in_len % 8 != 0) { + return -1; + } + + if (iv == NULL) { + iv = kDefaultIV; + } + + OPENSSL_memmove(out + 8, in, in_len); + uint8_t A[AES_BLOCK_SIZE]; + OPENSSL_memcpy(A, iv, 8); + + size_t n = in_len / 8; + + for (unsigned j = 0; j < kBound; j++) { + for (size_t i = 1; i <= n; i++) { + OPENSSL_memcpy(A + 8, out + 8 * i, 8); + AES_encrypt(A, A, key); + + uint32_t t = (uint32_t)(n * j + i); + A[7] ^= t & 0xff; + A[6] ^= (t >> 8) & 0xff; + A[5] ^= (t >> 16) & 0xff; + A[4] ^= (t >> 24) & 0xff; + OPENSSL_memcpy(out + 8 * i, A + 8, 8); + } + } + + OPENSSL_memcpy(out, A, 8); + return (int)in_len + 8; +} + +int AES_unwrap_key(const AES_KEY *key, const uint8_t *iv, uint8_t *out, + const uint8_t *in, size_t in_len) { + /* See RFC 3394, section 2.2.2. */ + + if (in_len > INT_MAX || in_len < 16 || in_len % 8 != 0) { + return -1; + } + + if (iv == NULL) { + iv = kDefaultIV; + } + + uint8_t A[AES_BLOCK_SIZE]; + OPENSSL_memcpy(A, in, 8); + OPENSSL_memmove(out, in + 8, in_len - 8); + + size_t n = (in_len / 8) - 1; + + for (unsigned j = kBound - 1; j < kBound; j--) { + for (size_t i = n; i > 0; i--) { + uint32_t t = (uint32_t)(n * j + i); + A[7] ^= t & 0xff; + A[6] ^= (t >> 8) & 0xff; + A[5] ^= (t >> 16) & 0xff; + A[4] ^= (t >> 24) & 0xff; + OPENSSL_memcpy(A + 8, out + 8 * (i - 1), 8); + AES_decrypt(A, A, key); + OPENSSL_memcpy(out + 8 * (i - 1), A + 8, 8); + } + } + + if (CRYPTO_memcmp(A, iv, 8) != 0) { + return -1; + } + + return (int)in_len - 8; +} diff --git a/Sources/BoringSSL/crypto/aes/mode_wrappers.c b/Sources/BoringSSL/crypto/aes/mode_wrappers.c index dc657dcd3..4929920f0 100644 --- a/Sources/BoringSSL/crypto/aes/mode_wrappers.c +++ b/Sources/BoringSSL/crypto/aes/mode_wrappers.c @@ -96,13 +96,17 @@ void AES_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t len, void AES_ofb128_encrypt(const uint8_t *in, uint8_t *out, size_t length, const AES_KEY *key, uint8_t *ivec, int *num) { - CRYPTO_ofb128_encrypt(in, out, length, key, ivec, num, + unsigned num_u = (unsigned)(*num); + CRYPTO_ofb128_encrypt(in, out, length, key, ivec, &num_u, (block128_f)AES_encrypt); + *num = (int)num_u; } void AES_cfb128_encrypt(const uint8_t *in, uint8_t *out, size_t length, const AES_KEY *key, uint8_t *ivec, int *num, int enc) { - CRYPTO_cfb128_encrypt(in, out, length, key, ivec, num, enc, + unsigned num_u = (unsigned)(*num); + CRYPTO_cfb128_encrypt(in, out, length, key, ivec, &num_u, enc, (block128_f)AES_encrypt); + *num = (int)num_u; } diff --git a/Sources/BoringSSL/crypto/asn1/a_bitstr.c b/Sources/BoringSSL/crypto/asn1/a_bitstr.c index 2705ea568..ea9da2475 100644 --- a/Sources/BoringSSL/crypto/asn1/a_bitstr.c +++ b/Sources/BoringSSL/crypto/asn1/a_bitstr.c @@ -61,6 +61,9 @@ #include #include +#include "../internal.h" + + int ASN1_BIT_STRING_set(ASN1_BIT_STRING *x, unsigned char *d, int len) { return M_ASN1_BIT_STRING_set(x, d, len); @@ -115,7 +118,7 @@ int i2c_ASN1_BIT_STRING(ASN1_BIT_STRING *a, unsigned char **pp) *(p++) = (unsigned char)bits; d = a->data; - memcpy(p, d, len); + OPENSSL_memcpy(p, d, len); p += len; if (len > 0) p[-1] &= (0xff << bits); @@ -162,7 +165,7 @@ ASN1_BIT_STRING *c2i_ASN1_BIT_STRING(ASN1_BIT_STRING **a, OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); goto err; } - memcpy(s, p, (int)len); + OPENSSL_memcpy(s, p, (int)len); s[len - 1] &= (0xff << padding); p += len; } else @@ -215,7 +218,7 @@ int ASN1_BIT_STRING_set_bit(ASN1_BIT_STRING *a, int n, int value) return 0; } if (w + 1 - a->length > 0) - memset(c + a->length, 0, w + 1 - a->length); + OPENSSL_memset(c + a->length, 0, w + 1 - a->length); a->data = c; a->length = w + 1; } diff --git a/Sources/BoringSSL/crypto/asn1/a_bytes.c b/Sources/BoringSSL/crypto/asn1/a_bytes.c deleted file mode 100644 index 7e2f85dc5..000000000 --- a/Sources/BoringSSL/crypto/asn1/a_bytes.c +++ /dev/null @@ -1,308 +0,0 @@ -/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) - * All rights reserved. - * - * This package is an SSL implementation written - * by Eric Young (eay@cryptsoft.com). - * The implementation was written so as to conform with Netscapes SSL. - * - * This library is free for commercial and non-commercial use as long as - * the following conditions are aheared to. The following conditions - * apply to all code found in this distribution, be it the RC4, RSA, - * lhash, DES, etc., code; not just the SSL code. The SSL documentation - * included with this distribution is covered by the same copyright terms - * except that the holder is Tim Hudson (tjh@cryptsoft.com). - * - * Copyright remains Eric Young's, and as such any Copyright notices in - * the code are not to be removed. - * If this package is used in a product, Eric Young should be given attribution - * as the author of the parts of the library used. - * This can be in the form of a textual message at program startup or - * in documentation (online or textual) provided with the package. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * "This product includes cryptographic software written by - * Eric Young (eay@cryptsoft.com)" - * The word 'cryptographic' can be left out if the rouines from the library - * being used are not cryptographic related :-). - * 4. If you include any Windows specific code (or a derivative thereof) from - * the apps directory (application code) you must include an acknowledgement: - * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" - * - * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * The licence and distribution terms for any publically available version or - * derivative of this code cannot be changed. i.e. this code cannot simply be - * copied and put under another distribution licence - * [including the GNU Public Licence.] */ - -#include - -#include - -#include -#include -#include - -static int asn1_collate_primitive(ASN1_STRING *a, ASN1_const_CTX *c); -/* - * type is a 'bitmap' of acceptable string types. - */ -ASN1_STRING *d2i_ASN1_type_bytes(ASN1_STRING **a, const unsigned char **pp, - long length, int type) -{ - ASN1_STRING *ret = NULL; - const unsigned char *p; - unsigned char *s; - long len; - int inf, tag, xclass; - int i = 0; - - p = *pp; - inf = ASN1_get_object(&p, &len, &tag, &xclass, length); - if (inf & 0x80) - goto err; - - if (tag >= 32) { - i = ASN1_R_TAG_VALUE_TOO_HIGH; - goto err; - } - if (!(ASN1_tag2bit(tag) & type)) { - i = ASN1_R_WRONG_TYPE; - goto err; - } - - /* If a bit-string, exit early */ - if (tag == V_ASN1_BIT_STRING) - return (d2i_ASN1_BIT_STRING(a, pp, length)); - - if ((a == NULL) || ((*a) == NULL)) { - if ((ret = ASN1_STRING_new()) == NULL) - return (NULL); - } else - ret = (*a); - - if (len != 0) { - s = (unsigned char *)OPENSSL_malloc((int)len + 1); - if (s == NULL) { - i = ERR_R_MALLOC_FAILURE; - goto err; - } - memcpy(s, p, (int)len); - s[len] = '\0'; - p += len; - } else - s = NULL; - - if (ret->data != NULL) - OPENSSL_free(ret->data); - ret->length = (int)len; - ret->data = s; - ret->type = tag; - if (a != NULL) - (*a) = ret; - *pp = p; - return (ret); - err: - OPENSSL_PUT_ERROR(ASN1, i); - if ((ret != NULL) && ((a == NULL) || (*a != ret))) - ASN1_STRING_free(ret); - return (NULL); -} - -int i2d_ASN1_bytes(ASN1_STRING *a, unsigned char **pp, int tag, int xclass) -{ - int ret, r, constructed; - unsigned char *p; - - if (a == NULL) - return (0); - - if (tag == V_ASN1_BIT_STRING) - return (i2d_ASN1_BIT_STRING(a, pp)); - - ret = a->length; - r = ASN1_object_size(0, ret, tag); - if (pp == NULL) - return (r); - p = *pp; - - if ((tag == V_ASN1_SEQUENCE) || (tag == V_ASN1_SET)) - constructed = 1; - else - constructed = 0; - ASN1_put_object(&p, constructed, ret, tag, xclass); - memcpy(p, a->data, a->length); - p += a->length; - *pp = p; - return (r); -} - -ASN1_STRING *d2i_ASN1_bytes(ASN1_STRING **a, const unsigned char **pp, - long length, int Ptag, int Pclass) -{ - ASN1_STRING *ret = NULL; - const unsigned char *p; - unsigned char *s; - long len; - int inf, tag, xclass; - int i = 0; - - if ((a == NULL) || ((*a) == NULL)) { - if ((ret = ASN1_STRING_new()) == NULL) - return (NULL); - } else - ret = (*a); - - p = *pp; - inf = ASN1_get_object(&p, &len, &tag, &xclass, length); - if (inf & 0x80) { - i = ASN1_R_BAD_OBJECT_HEADER; - goto err; - } - - if (tag != Ptag) { - i = ASN1_R_WRONG_TAG; - goto err; - } - - if (inf & V_ASN1_CONSTRUCTED) { - ASN1_const_CTX c; - - c.pp = pp; - c.p = p; - c.inf = inf; - c.slen = len; - c.tag = Ptag; - c.xclass = Pclass; - c.max = (length == 0) ? 0 : (p + length); - if (!asn1_collate_primitive(ret, &c)) - goto err; - else { - p = c.p; - } - } else { - if (len != 0) { - if ((ret->length < len) || (ret->data == NULL)) { - if (ret->data != NULL) - OPENSSL_free(ret->data); - s = (unsigned char *)OPENSSL_malloc((int)len + 1); - if (s == NULL) { - i = ERR_R_MALLOC_FAILURE; - goto err; - } - } else - s = ret->data; - memcpy(s, p, (int)len); - s[len] = '\0'; - p += len; - } else { - s = NULL; - if (ret->data != NULL) - OPENSSL_free(ret->data); - } - - ret->length = (int)len; - ret->data = s; - ret->type = Ptag; - } - - if (a != NULL) - (*a) = ret; - *pp = p; - return (ret); - err: - if ((ret != NULL) && ((a == NULL) || (*a != ret))) - ASN1_STRING_free(ret); - OPENSSL_PUT_ERROR(ASN1, i); - return (NULL); -} - -/* - * We are about to parse 0..n d2i_ASN1_bytes objects, we are to collapse them - * into the one structure that is then returned - */ -/* - * There have been a few bug fixes for this function from Paul Keogh - * , many thanks to him - */ -static int asn1_collate_primitive(ASN1_STRING *a, ASN1_const_CTX *c) -{ - ASN1_STRING *os = NULL; - BUF_MEM b; - int num; - - b.length = 0; - b.max = 0; - b.data = NULL; - - if (a == NULL) { - c->error = ERR_R_PASSED_NULL_PARAMETER; - goto err; - } - - num = 0; - for (;;) { - if (c->inf & 1) { - c->eos = ASN1_const_check_infinite_end(&c->p, - (long)(c->max - c->p)); - if (c->eos) - break; - } else { - if (c->slen <= 0) - break; - } - - c->q = c->p; - if (d2i_ASN1_bytes(&os, &c->p, c->max - c->p, c->tag, c->xclass) - == NULL) { - c->error = ERR_R_ASN1_LIB; - goto err; - } - - if (!BUF_MEM_grow_clean(&b, num + os->length)) { - c->error = ERR_R_BUF_LIB; - goto err; - } - memcpy(&(b.data[num]), os->data, os->length); - if (!(c->inf & 1)) - c->slen -= (c->p - c->q); - num += os->length; - } - - if (!asn1_const_Finish(c)) - goto err; - - a->length = num; - if (a->data != NULL) - OPENSSL_free(a->data); - a->data = (unsigned char *)b.data; - if (os != NULL) - ASN1_STRING_free(os); - return (1); - err: - OPENSSL_PUT_ERROR(ASN1, c->error); - if (os != NULL) - ASN1_STRING_free(os); - if (b.data != NULL) - OPENSSL_free(b.data); - return (0); -} diff --git a/Sources/BoringSSL/crypto/asn1/a_d2i_fp.c b/Sources/BoringSSL/crypto/asn1/a_d2i_fp.c index f8845d8a6..b54497191 100644 --- a/Sources/BoringSSL/crypto/asn1/a_d2i_fp.c +++ b/Sources/BoringSSL/crypto/asn1/a_d2i_fp.c @@ -141,6 +141,7 @@ void *ASN1_item_d2i_fp(const ASN1_ITEM *it, FILE *in, void *x) #endif #define HEADER_SIZE 8 +#define ASN1_CHUNK_INITIAL_SIZE (16 * 1024) static int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb) { BUF_MEM *b; @@ -217,28 +218,42 @@ static int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb) /* suck in c.slen bytes of data */ want = c.slen; if (want > (len - off)) { + size_t chunk_max = ASN1_CHUNK_INITIAL_SIZE; want -= (len - off); if (want > INT_MAX /* BIO_read takes an int length */ || len + want < len) { OPENSSL_PUT_ERROR(ASN1, ASN1_R_TOO_LONG); goto err; } - if (!BUF_MEM_grow_clean(b, len + want)) { - OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); - goto err; - } while (want > 0) { - i = BIO_read(in, &(b->data[len]), want); - if (i <= 0) { - OPENSSL_PUT_ERROR(ASN1, ASN1_R_NOT_ENOUGH_DATA); - goto err; - } /* - * This can't overflow because |len+want| didn't - * overflow. + * Read content in chunks of increasing size + * so we can return an error for EOF without + * having to allocate the entire content length + * in one go. */ - len += i; - want -= i; + size_t chunk = want > chunk_max ? chunk_max : want; + + if (!BUF_MEM_grow_clean(b, len + chunk)) { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + goto err; + } + want -= chunk; + while (chunk > 0) { + i = BIO_read(in, &(b->data[len]), chunk); + if (i <= 0) { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_NOT_ENOUGH_DATA); + goto err; + } + /* + * This can't overflow because |len+want| didn't + * overflow. + */ + len += i; + chunk -= i; + } + if (chunk_max < INT_MAX/2) + chunk_max *= 2; } } if (off + c.slen < off) { diff --git a/Sources/BoringSSL/crypto/asn1/a_enum.c b/Sources/BoringSSL/crypto/asn1/a_enum.c index 0b95fc95e..cc4690552 100644 --- a/Sources/BoringSSL/crypto/asn1/a_enum.c +++ b/Sources/BoringSSL/crypto/asn1/a_enum.c @@ -61,6 +61,9 @@ #include #include +#include "../internal.h" + + /* * Code for ENUMERATED type: identical to INTEGER apart from a different tag. * for comments on encoding see a_int.c @@ -79,7 +82,7 @@ int ASN1_ENUMERATED_set(ASN1_ENUMERATED *a, long v) OPENSSL_free(a->data); if ((a->data = (unsigned char *)OPENSSL_malloc(sizeof(long) + 1)) != NULL) - memset((char *)a->data, 0, sizeof(long) + 1); + OPENSSL_memset((char *)a->data, 0, sizeof(long) + 1); } if (a->data == NULL) { OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); diff --git a/Sources/BoringSSL/crypto/asn1/a_gentm.c b/Sources/BoringSSL/crypto/asn1/a_gentm.c index 09e4f171c..d130cdf80 100644 --- a/Sources/BoringSSL/crypto/asn1/a_gentm.c +++ b/Sources/BoringSSL/crypto/asn1/a_gentm.c @@ -61,7 +61,8 @@ #include #include -#include + +#include "asn1_locl.h" int asn1_generalizedtime_to_tm(struct tm *tm, const ASN1_GENERALIZEDTIME *d) { @@ -218,37 +219,43 @@ ASN1_GENERALIZEDTIME *ASN1_GENERALIZEDTIME_adj(ASN1_GENERALIZEDTIME *s, struct tm *ts; struct tm data; size_t len = 20; + ASN1_GENERALIZEDTIME *tmps = NULL; if (s == NULL) - s = M_ASN1_GENERALIZEDTIME_new(); - if (s == NULL) - return (NULL); + tmps = ASN1_GENERALIZEDTIME_new(); + else + tmps = s; + if (tmps == NULL) + return NULL; ts = OPENSSL_gmtime(&t, &data); if (ts == NULL) - return (NULL); + goto err; if (offset_day || offset_sec) { if (!OPENSSL_gmtime_adj(ts, offset_day, offset_sec)) - return NULL; + goto err; } - p = (char *)s->data; - if ((p == NULL) || ((size_t)s->length < len)) { + p = (char *)tmps->data; + if ((p == NULL) || ((size_t)tmps->length < len)) { p = OPENSSL_malloc(len); if (p == NULL) { OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); - return (NULL); + goto err; } - if (s->data != NULL) - OPENSSL_free(s->data); - s->data = (unsigned char *)p; + OPENSSL_free(tmps->data); + tmps->data = (unsigned char *)p; } BIO_snprintf(p, len, "%04d%02d%02d%02d%02d%02dZ", ts->tm_year + 1900, ts->tm_mon + 1, ts->tm_mday, ts->tm_hour, ts->tm_min, ts->tm_sec); - s->length = strlen(p); - s->type = V_ASN1_GENERALIZEDTIME; - return (s); + tmps->length = strlen(p); + tmps->type = V_ASN1_GENERALIZEDTIME; + return tmps; + err: + if (s == NULL) + ASN1_GENERALIZEDTIME_free(tmps); + return NULL; } diff --git a/Sources/BoringSSL/crypto/asn1/a_int.c b/Sources/BoringSSL/crypto/asn1/a_int.c index 38a01bcb8..617ba9624 100644 --- a/Sources/BoringSSL/crypto/asn1/a_int.c +++ b/Sources/BoringSSL/crypto/asn1/a_int.c @@ -61,6 +61,9 @@ #include #include +#include "../internal.h" + + ASN1_INTEGER *ASN1_INTEGER_dup(const ASN1_INTEGER *x) { return M_ASN1_INTEGER_dup(x); @@ -157,7 +160,7 @@ int i2c_ASN1_INTEGER(ASN1_INTEGER *a, unsigned char **pp) if (a->length == 0) *(p++) = 0; else if (!neg) - memcpy(p, a->data, (unsigned int)a->length); + OPENSSL_memcpy(p, a->data, (unsigned int)a->length); else { /* Begin at the end of the encoding */ n = a->data + a->length - 1; @@ -254,7 +257,7 @@ ASN1_INTEGER *c2i_ASN1_INTEGER(ASN1_INTEGER **a, const unsigned char **pp, p++; len--; } - memcpy(s, p, (int)len); + OPENSSL_memcpy(s, p, (int)len); } if (ret->data != NULL) @@ -322,7 +325,7 @@ ASN1_INTEGER *d2i_ASN1_UINTEGER(ASN1_INTEGER **a, const unsigned char **pp, p++; len--; } - memcpy(s, p, (int)len); + OPENSSL_memcpy(s, p, (int)len); p += len; } @@ -354,7 +357,7 @@ int ASN1_INTEGER_set(ASN1_INTEGER *a, long v) OPENSSL_free(a->data); if ((a->data = (unsigned char *)OPENSSL_malloc(sizeof(long) + 1)) != NULL) - memset((char *)a->data, 0, sizeof(long) + 1); + OPENSSL_memset((char *)a->data, 0, sizeof(long) + 1); } if (a->data == NULL) { OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); diff --git a/Sources/BoringSSL/crypto/asn1/a_object.c b/Sources/BoringSSL/crypto/asn1/a_object.c index 10f383987..a710addda 100644 --- a/Sources/BoringSSL/crypto/asn1/a_object.c +++ b/Sources/BoringSSL/crypto/asn1/a_object.c @@ -63,6 +63,9 @@ #include #include +#include "../internal.h" + + int i2d_ASN1_OBJECT(ASN1_OBJECT *a, unsigned char **pp) { unsigned char *p; @@ -72,12 +75,12 @@ int i2d_ASN1_OBJECT(ASN1_OBJECT *a, unsigned char **pp) return (0); objsize = ASN1_object_size(0, a->length, V_ASN1_OBJECT); - if (pp == NULL) + if (pp == NULL || objsize == -1) return objsize; p = *pp; ASN1_put_object(&p, 0, a->length, V_ASN1_OBJECT, V_ASN1_UNIVERSAL); - memcpy(p, a->data, a->length); + OPENSSL_memcpy(p, a->data, a->length); p += a->length; *pp = p; @@ -172,8 +175,12 @@ int a2d_ASN1_OBJECT(unsigned char *out, int olen, const char *buf, int num) if (!tmp) goto err; } - while (blsize--) - tmp[i++] = (unsigned char)BN_div_word(bl, 0x80L); + while (blsize--) { + BN_ULONG t = BN_div_word(bl, 0x80L); + if (t == (BN_ULONG)-1) + goto err; + tmp[i++] = (unsigned char)t; + } } else { for (;;) { @@ -317,7 +324,7 @@ ASN1_OBJECT *c2i_ASN1_OBJECT(ASN1_OBJECT **a, const unsigned char **pp, } ret->flags |= ASN1_OBJECT_FLAG_DYNAMIC_DATA; } - memcpy(data, p, length); + OPENSSL_memcpy(data, p, length); /* reattach data to object, after which it remains const */ ret->data = data; ret->length = length; diff --git a/Sources/BoringSSL/crypto/asn1/a_strnid.c b/Sources/BoringSSL/crypto/asn1/a_strnid.c index ba1224ef0..c558bce6c 100644 --- a/Sources/BoringSSL/crypto/asn1/a_strnid.c +++ b/Sources/BoringSSL/crypto/asn1/a_strnid.c @@ -247,6 +247,7 @@ int ASN1_STRING_TABLE_add(int nid, } tmp->flags = flags | STABLE_FLAGS_MALLOC; tmp->nid = nid; + tmp->minsize = tmp->maxsize = -1; new_nid = 1; } else tmp->flags = (tmp->flags & STABLE_FLAGS_MALLOC) | flags; diff --git a/Sources/BoringSSL/crypto/asn1/a_time.c b/Sources/BoringSSL/crypto/asn1/a_time.c index 4391092ac..4b584297e 100644 --- a/Sources/BoringSSL/crypto/asn1/a_time.c +++ b/Sources/BoringSSL/crypto/asn1/a_time.c @@ -63,7 +63,6 @@ #include #include #include -#include #include "asn1_locl.h" @@ -77,17 +76,6 @@ IMPLEMENT_ASN1_MSTRING(ASN1_TIME, B_ASN1_TIME) IMPLEMENT_ASN1_FUNCTIONS(ASN1_TIME) -#if 0 -int i2d_ASN1_TIME(ASN1_TIME *a, unsigned char **pp) -{ - if (a->type == V_ASN1_UTCTIME || a->type == V_ASN1_GENERALIZEDTIME) - return (i2d_ASN1_bytes((ASN1_STRING *)a, pp, - a->type, V_ASN1_UNIVERSAL)); - OPENSSL_PUT_ERROR(ASN1, ASN1_R_EXPECTING_A_TIME); - return -1; -} -#endif - ASN1_TIME *ASN1_TIME_set(ASN1_TIME *s, time_t t) { return ASN1_TIME_adj(s, t, 0, 0); diff --git a/Sources/BoringSSL/crypto/asn1/a_type.c b/Sources/BoringSSL/crypto/asn1/a_type.c index ecd473428..734ff8b4d 100644 --- a/Sources/BoringSSL/crypto/asn1/a_type.c +++ b/Sources/BoringSSL/crypto/asn1/a_type.c @@ -122,9 +122,7 @@ int ASN1_TYPE_cmp(const ASN1_TYPE *a, const ASN1_TYPE *b) result = a->value.boolean - b->value.boolean; break; case V_ASN1_INTEGER: - case V_ASN1_NEG_INTEGER: case V_ASN1_ENUMERATED: - case V_ASN1_NEG_ENUMERATED: case V_ASN1_BIT_STRING: case V_ASN1_OCTET_STRING: case V_ASN1_SEQUENCE: diff --git a/Sources/BoringSSL/crypto/asn1/a_utctm.c b/Sources/BoringSSL/crypto/asn1/a_utctm.c index 35eb1c9bf..193b83f82 100644 --- a/Sources/BoringSSL/crypto/asn1/a_utctm.c +++ b/Sources/BoringSSL/crypto/asn1/a_utctm.c @@ -61,39 +61,9 @@ #include #include -#include -#if 0 -int i2d_ASN1_UTCTIME(ASN1_UTCTIME *a, unsigned char **pp) -{ - return (i2d_ASN1_bytes((ASN1_STRING *)a, pp, - V_ASN1_UTCTIME, V_ASN1_UNIVERSAL)); -} +#include "asn1_locl.h" -ASN1_UTCTIME *d2i_ASN1_UTCTIME(ASN1_UTCTIME **a, unsigned char **pp, - long length) -{ - ASN1_UTCTIME *ret = NULL; - - ret = (ASN1_UTCTIME *)d2i_ASN1_bytes((ASN1_STRING **)a, pp, length, - V_ASN1_UTCTIME, V_ASN1_UNIVERSAL); - if (ret == NULL) { - OPENSSL_PUT_ERROR(ASN1, ERR_R_NESTED_ASN1_ERROR); - return (NULL); - } - if (!ASN1_UTCTIME_check(ret)) { - OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_TIME_FORMAT); - goto err; - } - - return (ret); - err: - if ((ret != NULL) && ((a == NULL) || (*a != ret))) - M_ASN1_UTCTIME_free(ret); - return (NULL); -} - -#endif int asn1_utctime_to_tm(struct tm *tm, const ASN1_UTCTIME *d) { @@ -299,7 +269,7 @@ time_t ASN1_UTCTIME_get(const ASN1_UTCTIME *s) struct tm tm; int offset; - memset(&tm, '\0', sizeof tm); + OPENSSL_memset(&tm, '\0', sizeof tm); # define g2(p) (((p)[0]-'0')*10+(p)[1]-'0') tm.tm_year = g2(s->data); diff --git a/Sources/BoringSSL/crypto/asn1/asn1_lib.c b/Sources/BoringSSL/crypto/asn1/asn1_lib.c index 0025a6761..774f151cd 100644 --- a/Sources/BoringSSL/crypto/asn1/asn1_lib.c +++ b/Sources/BoringSSL/crypto/asn1/asn1_lib.c @@ -63,39 +63,48 @@ #include #include -/* Cross-module errors from crypto/x509/i2d_pr.c */ -OPENSSL_DECLARE_ERROR_REASON(ASN1, UNSUPPORTED_PUBLIC_KEY_TYPE); +#include "../internal.h" + +/* Cross-module errors from crypto/x509/i2d_pr.c. */ +OPENSSL_DECLARE_ERROR_REASON(ASN1, UNSUPPORTED_PUBLIC_KEY_TYPE) + +/* Cross-module errors from crypto/x509/algorithm.c. */ +OPENSSL_DECLARE_ERROR_REASON(ASN1, CONTEXT_NOT_INITIALISED) +OPENSSL_DECLARE_ERROR_REASON(ASN1, DIGEST_AND_KEY_TYPE_NOT_SUPPORTED) +OPENSSL_DECLARE_ERROR_REASON(ASN1, UNKNOWN_MESSAGE_DIGEST_ALGORITHM) +OPENSSL_DECLARE_ERROR_REASON(ASN1, UNKNOWN_SIGNATURE_ALGORITHM) +OPENSSL_DECLARE_ERROR_REASON(ASN1, WRONG_PUBLIC_KEY_TYPE) /* * Cross-module errors from crypto/x509/asn1_gen.c. TODO(davidben): Remove * these once asn1_gen.c is gone. */ -OPENSSL_DECLARE_ERROR_REASON(ASN1, DEPTH_EXCEEDED); -OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_BITSTRING_FORMAT); -OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_BOOLEAN); -OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_FORMAT); -OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_HEX); -OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_IMPLICIT_TAG); -OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_INTEGER); -OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_NESTED_TAGGING); -OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_NULL_VALUE); -OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_OBJECT); -OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_TIME_VALUE); -OPENSSL_DECLARE_ERROR_REASON(ASN1, INTEGER_NOT_ASCII_FORMAT); -OPENSSL_DECLARE_ERROR_REASON(ASN1, INVALID_MODIFIER); -OPENSSL_DECLARE_ERROR_REASON(ASN1, INVALID_NUMBER); -OPENSSL_DECLARE_ERROR_REASON(ASN1, LIST_ERROR); -OPENSSL_DECLARE_ERROR_REASON(ASN1, MISSING_VALUE); -OPENSSL_DECLARE_ERROR_REASON(ASN1, NOT_ASCII_FORMAT); -OPENSSL_DECLARE_ERROR_REASON(ASN1, OBJECT_NOT_ASCII_FORMAT); -OPENSSL_DECLARE_ERROR_REASON(ASN1, SEQUENCE_OR_SET_NEEDS_CONFIG); -OPENSSL_DECLARE_ERROR_REASON(ASN1, TIME_NOT_ASCII_FORMAT); -OPENSSL_DECLARE_ERROR_REASON(ASN1, UNKNOWN_FORMAT); -OPENSSL_DECLARE_ERROR_REASON(ASN1, UNKNOWN_TAG); -OPENSSL_DECLARE_ERROR_REASON(ASN1, UNSUPPORTED_TYPE); +OPENSSL_DECLARE_ERROR_REASON(ASN1, DEPTH_EXCEEDED) +OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_BITSTRING_FORMAT) +OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_BOOLEAN) +OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_FORMAT) +OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_HEX) +OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_IMPLICIT_TAG) +OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_INTEGER) +OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_NESTED_TAGGING) +OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_NULL_VALUE) +OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_OBJECT) +OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_TIME_VALUE) +OPENSSL_DECLARE_ERROR_REASON(ASN1, INTEGER_NOT_ASCII_FORMAT) +OPENSSL_DECLARE_ERROR_REASON(ASN1, INVALID_MODIFIER) +OPENSSL_DECLARE_ERROR_REASON(ASN1, INVALID_NUMBER) +OPENSSL_DECLARE_ERROR_REASON(ASN1, LIST_ERROR) +OPENSSL_DECLARE_ERROR_REASON(ASN1, MISSING_VALUE) +OPENSSL_DECLARE_ERROR_REASON(ASN1, NOT_ASCII_FORMAT) +OPENSSL_DECLARE_ERROR_REASON(ASN1, OBJECT_NOT_ASCII_FORMAT) +OPENSSL_DECLARE_ERROR_REASON(ASN1, SEQUENCE_OR_SET_NEEDS_CONFIG) +OPENSSL_DECLARE_ERROR_REASON(ASN1, TIME_NOT_ASCII_FORMAT) +OPENSSL_DECLARE_ERROR_REASON(ASN1, UNKNOWN_FORMAT) +OPENSSL_DECLARE_ERROR_REASON(ASN1, UNKNOWN_TAG) +OPENSSL_DECLARE_ERROR_REASON(ASN1, UNSUPPORTED_TYPE) static int asn1_get_length(const unsigned char **pp, int *inf, long *rl, - int max); + long max); static void asn1_put_length(unsigned char **pp, int length); static int _asn1_check_infinite_end(const unsigned char **p, long len) @@ -167,7 +176,7 @@ int ASN1_get_object(const unsigned char **pp, long *plength, int *ptag, *ptag = tag; *pclass = xclass; - if (!asn1_get_length(&p, &inf, plength, (int)max)) + if (!asn1_get_length(&p, &inf, plength, max)) goto err; if (inf && !(ret & V_ASN1_CONSTRUCTED)) @@ -195,14 +204,14 @@ int ASN1_get_object(const unsigned char **pp, long *plength, int *ptag, } static int asn1_get_length(const unsigned char **pp, int *inf, long *rl, - int max) + long max) { const unsigned char *p = *pp; unsigned long ret = 0; - unsigned int i; + unsigned long i; if (max-- < 1) - return (0); + return 0; if (*p == 0x80) { *inf = 1; ret = 0; @@ -211,15 +220,11 @@ static int asn1_get_length(const unsigned char **pp, int *inf, long *rl, *inf = 0; i = *p & 0x7f; if (*(p++) & 0x80) { - if (i > sizeof(long)) + if (i > sizeof(ret) || max < (long)i) return 0; - if (max-- == 0) - return (0); while (i-- > 0) { ret <<= 8L; ret |= *(p++); - if (max-- == 0) - return (0); } } else ret = i; @@ -228,7 +233,7 @@ static int asn1_get_length(const unsigned char **pp, int *inf, long *rl, return 0; *pp = p; *rl = (long)ret; - return (1); + return 1; } /* @@ -296,26 +301,30 @@ static void asn1_put_length(unsigned char **pp, int length) int ASN1_object_size(int constructed, int length, int tag) { - int ret; - - ret = length; - ret++; + int ret = 1; + if (length < 0) + return -1; if (tag >= 31) { while (tag > 0) { tag >>= 7; ret++; } } - if (constructed == 2) - return ret + 3; - ret++; - if (length > 127) { - while (length > 0) { - length >>= 8; - ret++; + if (constructed == 2) { + ret += 3; + } else { + ret++; + if (length > 127) { + int tmplen = length; + while (tmplen > 0) { + tmplen >>= 8; + ret++; + } } } - return (ret); + if (ret >= INT_MAX - length) + return -1; + return ret + length; } static int _asn1_Finish(ASN1_const_CTX *c) @@ -343,32 +352,6 @@ int asn1_const_Finish(ASN1_const_CTX *c) return _asn1_Finish(c); } -int asn1_GetSequence(ASN1_const_CTX *c, long *length) -{ - const unsigned char *q; - - q = c->p; - c->inf = ASN1_get_object(&(c->p), &(c->slen), &(c->tag), &(c->xclass), - *length); - if (c->inf & 0x80) { - c->error = ASN1_R_BAD_GET_ASN1_OBJECT_CALL; - return (0); - } - if (c->tag != V_ASN1_SEQUENCE) { - c->error = ASN1_R_EXPECTING_AN_ASN1_SEQUENCE; - return (0); - } - (*length) -= (c->p - q); - if (c->max && (*length < 0)) { - c->error = ASN1_R_ASN1_LENGTH_MISMATCH; - return (0); - } - if (c->inf == (1 | V_ASN1_CONSTRUCTED)) - c->slen = *length + *(c->pp) - c->p; - c->eos = 0; - return (1); -} - int ASN1_STRING_copy(ASN1_STRING *dst, const ASN1_STRING *str) { if (str == NULL) @@ -406,7 +389,7 @@ int ASN1_STRING_set(ASN1_STRING *str, const void *_data, int len) else len = strlen(data); } - if ((str->length < len) || (str->data == NULL)) { + if ((str->length <= len) || (str->data == NULL)) { c = str->data; if (c == NULL) str->data = OPENSSL_malloc(len + 1); @@ -421,7 +404,7 @@ int ASN1_STRING_set(ASN1_STRING *str, const void *_data, int len) } str->length = len; if (data != NULL) { - memcpy(str->data, data, len); + OPENSSL_memcpy(str->data, data, len); /* an allowance for strings :-) */ str->data[len] = '\0'; } @@ -472,7 +455,7 @@ int ASN1_STRING_cmp(const ASN1_STRING *a, const ASN1_STRING *b) i = (a->length - b->length); if (i == 0) { - i = memcmp(a->data, b->data, a->length); + i = OPENSSL_memcmp(a->data, b->data, a->length); if (i == 0) return (a->type - b->type); else diff --git a/Sources/BoringSSL/crypto/asn1/asn1_locl.h b/Sources/BoringSSL/crypto/asn1/asn1_locl.h index 49eceb6b3..ce8146bf3 100644 --- a/Sources/BoringSSL/crypto/asn1/asn1_locl.h +++ b/Sources/BoringSSL/crypto/asn1/asn1_locl.h @@ -57,17 +57,42 @@ * */ +#ifndef OPENSSL_HEADER_ASN1_ASN1_LOCL_H +#define OPENSSL_HEADER_ASN1_ASN1_LOCL_H + +#include + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* Wrapper functions for time functions. */ + +/* OPENSSL_gmtime wraps |gmtime_r|. See the manual page for that function. */ +struct tm *OPENSSL_gmtime(const time_t *timer, struct tm *result); + +/* OPENSSL_gmtime_adj updates |tm| by adding |offset_day| days and |offset_sec| + * seconds. */ +int OPENSSL_gmtime_adj(struct tm *tm, int offset_day, long offset_sec); + +/* OPENSSL_gmtime_diff calculates the difference between |from| and |to| and + * outputs the difference as a number of days and seconds in |*out_days| and + * |*out_secs|. */ +int OPENSSL_gmtime_diff(int *out_days, int *out_secs, const struct tm *from, + const struct tm *to); + + /* Internal ASN1 structures and functions: not for application use */ int asn1_utctime_to_tm(struct tm *tm, const ASN1_UTCTIME *d); int asn1_generalizedtime_to_tm(struct tm *tm, const ASN1_GENERALIZEDTIME *d); -/* ASN1 print context structure */ -struct asn1_pctx_st { - unsigned long flags; - unsigned long nm_flags; - unsigned long cert_flags; - unsigned long oid_flags; - unsigned long str_flags; -} /* ASN1_PCTX */ ; +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_ASN1_ASN1_LOCL_H */ diff --git a/Sources/BoringSSL/crypto/asn1/asn1_par.c b/Sources/BoringSSL/crypto/asn1/asn1_par.c index fbdaae845..b1a01edae 100644 --- a/Sources/BoringSSL/crypto/asn1/asn1_par.c +++ b/Sources/BoringSSL/crypto/asn1/asn1_par.c @@ -56,328 +56,6 @@ #include -#include -#include -#include - -#define ASN1_PARSE_MAXDEPTH 128 - -static int asn1_print_info(BIO *bp, int tag, int xclass, int constructed, - int indent); -static int asn1_parse2(BIO *bp, const unsigned char **pp, long length, - int offset, int depth, int indent, int dump); -static int asn1_print_info(BIO *bp, int tag, int xclass, int constructed, - int indent) -{ - static const char fmt[] = "%-18s"; - char str[128]; - const char *p; - - if (constructed & V_ASN1_CONSTRUCTED) - p = "cons: "; - else - p = "prim: "; - if (BIO_write(bp, p, 6) < 6) - goto err; - BIO_indent(bp, indent, 128); - - p = str; - if ((xclass & V_ASN1_PRIVATE) == V_ASN1_PRIVATE) - BIO_snprintf(str, sizeof str, "priv [ %d ] ", tag); - else if ((xclass & V_ASN1_CONTEXT_SPECIFIC) == V_ASN1_CONTEXT_SPECIFIC) - BIO_snprintf(str, sizeof str, "cont [ %d ]", tag); - else if ((xclass & V_ASN1_APPLICATION) == V_ASN1_APPLICATION) - BIO_snprintf(str, sizeof str, "appl [ %d ]", tag); - else if (tag > 30) - BIO_snprintf(str, sizeof str, "", tag); - else - p = ASN1_tag2str(tag); - - if (BIO_printf(bp, fmt, p) <= 0) - goto err; - return (1); - err: - return (0); -} - -int ASN1_parse(BIO *bp, const unsigned char *pp, long len, int indent) -{ - return (asn1_parse2(bp, &pp, len, 0, 0, indent, 0)); -} - -int ASN1_parse_dump(BIO *bp, const unsigned char *pp, long len, int indent, - int dump) -{ - return (asn1_parse2(bp, &pp, len, 0, 0, indent, dump)); -} - -static int asn1_parse2(BIO *bp, const unsigned char **pp, long length, - int offset, int depth, int indent, int dump) -{ - const unsigned char *p, *ep, *tot, *op, *opp; - long len; - int tag, xclass, ret = 0; - int nl, hl, j, r; - ASN1_OBJECT *o = NULL; - ASN1_OCTET_STRING *os = NULL; - /* ASN1_BMPSTRING *bmp=NULL; */ - int dump_indent; - -#if 0 - dump_indent = indent; -#else - dump_indent = 6; /* Because we know BIO_dump_indent() */ -#endif - - if (depth > ASN1_PARSE_MAXDEPTH) { - BIO_puts(bp, "BAD RECURSION DEPTH\n"); - return 0; - } - - p = *pp; - tot = p + length; - op = p - 1; - while ((p < tot) && (op < p)) { - op = p; - j = ASN1_get_object(&p, &len, &tag, &xclass, length); -#ifdef LINT - j = j; -#endif - if (j & 0x80) { - if (BIO_puts(bp, "Error in encoding\n") <= 0) - goto end; - ret = 0; - goto end; - } - hl = (p - op); - length -= hl; - /* - * if j == 0x21 it is a constructed indefinite length object - */ - if (BIO_printf(bp, "%5ld:", (long)offset + (long)(op - *pp)) - <= 0) - goto end; - - if (j != (V_ASN1_CONSTRUCTED | 1)) { - if (BIO_printf(bp, "d=%-2d hl=%ld l=%4ld ", - depth, (long)hl, len) <= 0) - goto end; - } else { - if (BIO_printf(bp, "d=%-2d hl=%ld l=inf ", depth, (long)hl) <= 0) - goto end; - } - if (!asn1_print_info(bp, tag, xclass, j, (indent) ? depth : 0)) - goto end; - if (j & V_ASN1_CONSTRUCTED) { - ep = p + len; - if (BIO_puts(bp, "\n") <= 0) - goto end; - if (len > length) { - BIO_printf(bp, "length is greater than %ld\n", length); - ret = 0; - goto end; - } - if ((j == 0x21) && (len == 0)) { - for (;;) { - r = asn1_parse2(bp, &p, (long)(tot - p), - offset + (p - *pp), depth + 1, - indent, dump); - if (r == 0) { - ret = 0; - goto end; - } - if ((r == 2) || (p >= tot)) - break; - } - } else - while (p < ep) { - r = asn1_parse2(bp, &p, (long)len, - offset + (p - *pp), depth + 1, - indent, dump); - if (r == 0) { - ret = 0; - goto end; - } - } - } else if (xclass != 0) { - p += len; - if (BIO_puts(bp, "\n") <= 0) - goto end; - } else { - nl = 0; - if ((tag == V_ASN1_PRINTABLESTRING) || - (tag == V_ASN1_T61STRING) || - (tag == V_ASN1_IA5STRING) || - (tag == V_ASN1_VISIBLESTRING) || - (tag == V_ASN1_NUMERICSTRING) || - (tag == V_ASN1_UTF8STRING) || - (tag == V_ASN1_UTCTIME) || (tag == V_ASN1_GENERALIZEDTIME)) { - if (BIO_puts(bp, ":") <= 0) - goto end; - if ((len > 0) && BIO_write(bp, (const char *)p, (int)len) - != (int)len) - goto end; - } else if (tag == V_ASN1_OBJECT) { - opp = op; - if (d2i_ASN1_OBJECT(&o, &opp, len + hl) != NULL) { - if (BIO_puts(bp, ":") <= 0) - goto end; - i2a_ASN1_OBJECT(bp, o); - } else { - if (BIO_puts(bp, ":BAD OBJECT") <= 0) - goto end; - } - } else if (tag == V_ASN1_BOOLEAN) { - int ii; - - opp = op; - ii = d2i_ASN1_BOOLEAN(NULL, &opp, len + hl); - if (ii < 0) { - if (BIO_puts(bp, "Bad boolean\n") <= 0) - goto end; - } - BIO_printf(bp, ":%d", ii); - } else if (tag == V_ASN1_BMPSTRING) { - /* do the BMP thang */ - } else if (tag == V_ASN1_OCTET_STRING) { - int i, printable = 1; - - opp = op; - os = d2i_ASN1_OCTET_STRING(NULL, &opp, len + hl); - if (os != NULL && os->length > 0) { - opp = os->data; - /* - * testing whether the octet string is printable - */ - for (i = 0; i < os->length; i++) { - if (((opp[i] < ' ') && - (opp[i] != '\n') && - (opp[i] != '\r') && - (opp[i] != '\t')) || (opp[i] > '~')) { - printable = 0; - break; - } - } - if (printable) - /* printable string */ - { - if (BIO_puts(bp, ":") <= 0) - goto end; - if (BIO_write(bp, (const char *)opp, os->length) <= 0) - goto end; - } else if (!dump) - /* - * not printable => print octet string as hex dump - */ - { - if (BIO_puts(bp, "[HEX DUMP]:") <= 0) - goto end; - for (i = 0; i < os->length; i++) { - if (BIO_printf(bp, "%02X", opp[i]) <= 0) - goto end; - } - } else - /* print the normal dump */ - { - if (!nl) { - if (BIO_puts(bp, "\n") <= 0) - goto end; - } - if (!BIO_hexdump(bp, opp, - ((dump == -1 || dump > - os->length) ? os->length : dump), - dump_indent)) - goto end; - nl = 1; - } - } - if (os != NULL) { - M_ASN1_OCTET_STRING_free(os); - os = NULL; - } - } else if (tag == V_ASN1_INTEGER) { - ASN1_INTEGER *bs; - int i; - - opp = op; - bs = d2i_ASN1_INTEGER(NULL, &opp, len + hl); - if (bs != NULL) { - if (BIO_puts(bp, ":") <= 0) - goto end; - if (bs->type == V_ASN1_NEG_INTEGER) - if (BIO_puts(bp, "-") <= 0) - goto end; - for (i = 0; i < bs->length; i++) { - if (BIO_printf(bp, "%02X", bs->data[i]) <= 0) - goto end; - } - if (bs->length == 0) { - if (BIO_puts(bp, "00") <= 0) - goto end; - } - } else { - if (BIO_puts(bp, "BAD INTEGER") <= 0) - goto end; - } - M_ASN1_INTEGER_free(bs); - } else if (tag == V_ASN1_ENUMERATED) { - ASN1_ENUMERATED *bs; - int i; - - opp = op; - bs = d2i_ASN1_ENUMERATED(NULL, &opp, len + hl); - if (bs != NULL) { - if (BIO_puts(bp, ":") <= 0) - goto end; - if (bs->type == V_ASN1_NEG_ENUMERATED) - if (BIO_puts(bp, "-") <= 0) - goto end; - for (i = 0; i < bs->length; i++) { - if (BIO_printf(bp, "%02X", bs->data[i]) <= 0) - goto end; - } - if (bs->length == 0) { - if (BIO_puts(bp, "00") <= 0) - goto end; - } - } else { - if (BIO_puts(bp, "BAD ENUMERATED") <= 0) - goto end; - } - M_ASN1_ENUMERATED_free(bs); - } else if (len > 0 && dump) { - if (!nl) { - if (BIO_puts(bp, "\n") <= 0) - goto end; - } - if (!BIO_hexdump(bp, p, - ((dump == -1 || dump > len) ? len : dump), - dump_indent)) - goto end; - nl = 1; - } - - if (!nl) { - if (BIO_puts(bp, "\n") <= 0) - goto end; - } - p += len; - if ((tag == V_ASN1_EOC) && (xclass == 0)) { - ret = 2; /* End of sequence */ - goto end; - } - } - length -= len; - } - ret = 1; - end: - if (o != NULL) - ASN1_OBJECT_free(o); - if (os != NULL) - M_ASN1_OCTET_STRING_free(os); - *pp = p; - return (ret); -} const char *ASN1_tag2str(int tag) { diff --git a/Sources/BoringSSL/crypto/asn1/bio_asn1.c b/Sources/BoringSSL/crypto/asn1/bio_asn1.c deleted file mode 100644 index 03cc9a6e2..000000000 --- a/Sources/BoringSSL/crypto/asn1/bio_asn1.c +++ /dev/null @@ -1,477 +0,0 @@ -/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) - * All rights reserved. - * - * This package is an SSL implementation written - * by Eric Young (eay@cryptsoft.com). - * The implementation was written so as to conform with Netscapes SSL. - * - * This library is free for commercial and non-commercial use as long as - * the following conditions are aheared to. The following conditions - * apply to all code found in this distribution, be it the RC4, RSA, - * lhash, DES, etc., code; not just the SSL code. The SSL documentation - * included with this distribution is covered by the same copyright terms - * except that the holder is Tim Hudson (tjh@cryptsoft.com). - * - * Copyright remains Eric Young's, and as such any Copyright notices in - * the code are not to be removed. - * If this package is used in a product, Eric Young should be given attribution - * as the author of the parts of the library used. - * This can be in the form of a textual message at program startup or - * in documentation (online or textual) provided with the package. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * "This product includes cryptographic software written by - * Eric Young (eay@cryptsoft.com)" - * The word 'cryptographic' can be left out if the rouines from the library - * being used are not cryptographic related :-). - * 4. If you include any Windows specific code (or a derivative thereof) from - * the apps directory (application code) you must include an acknowledgement: - * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" - * - * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * The licence and distribution terms for any publically available version or - * derivative of this code cannot be changed. i.e. this code cannot simply be - * copied and put under another distribution licence - * [including the GNU Public Licence.] */ - -#include - -#include -#include - -#include -#include - -/* Must be large enough for biggest tag+length */ -#define DEFAULT_ASN1_BUF_SIZE 20 - -typedef enum { - ASN1_STATE_START, - ASN1_STATE_PRE_COPY, - ASN1_STATE_HEADER, - ASN1_STATE_HEADER_COPY, - ASN1_STATE_DATA_COPY, - ASN1_STATE_POST_COPY, - ASN1_STATE_DONE -} asn1_bio_state_t; - -typedef struct BIO_ASN1_EX_FUNCS_st { - asn1_ps_func *ex_func; - asn1_ps_func *ex_free_func; -} BIO_ASN1_EX_FUNCS; - -typedef struct BIO_ASN1_BUF_CTX_t { - /* Internal state */ - asn1_bio_state_t state; - /* Internal buffer */ - unsigned char *buf; - /* Size of buffer */ - int bufsize; - /* Current position in buffer */ - int bufpos; - /* Current buffer length */ - int buflen; - /* Amount of data to copy */ - int copylen; - /* Class and tag to use */ - int asn1_class, asn1_tag; - asn1_ps_func *prefix, *prefix_free, *suffix, *suffix_free; - /* Extra buffer for prefix and suffix data */ - unsigned char *ex_buf; - int ex_len; - int ex_pos; - void *ex_arg; -} BIO_ASN1_BUF_CTX; - -static int asn1_bio_write(BIO *h, const char *buf, int num); -static int asn1_bio_read(BIO *h, char *buf, int size); -static int asn1_bio_puts(BIO *h, const char *str); -static int asn1_bio_gets(BIO *h, char *str, int size); -static long asn1_bio_ctrl(BIO *h, int cmd, long arg1, void *arg2); -static int asn1_bio_new(BIO *h); -static int asn1_bio_free(BIO *data); -static long asn1_bio_callback_ctrl(BIO *h, int cmd, bio_info_cb fp); - -static int asn1_bio_init(BIO_ASN1_BUF_CTX *ctx, int size); -static int asn1_bio_flush_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx, - asn1_ps_func *cleanup, asn1_bio_state_t next); -static int asn1_bio_setup_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx, - asn1_ps_func *setup, - asn1_bio_state_t ex_state, - asn1_bio_state_t other_state); - -static const BIO_METHOD methods_asn1 = { - BIO_TYPE_ASN1, - "asn1", - asn1_bio_write, - asn1_bio_read, - asn1_bio_puts, - asn1_bio_gets, - asn1_bio_ctrl, - asn1_bio_new, - asn1_bio_free, - asn1_bio_callback_ctrl, -}; - -const BIO_METHOD *BIO_f_asn1(void) -{ - return (&methods_asn1); -} - -static int asn1_bio_new(BIO *b) -{ - BIO_ASN1_BUF_CTX *ctx; - ctx = OPENSSL_malloc(sizeof(BIO_ASN1_BUF_CTX)); - if (!ctx) - return 0; - if (!asn1_bio_init(ctx, DEFAULT_ASN1_BUF_SIZE)) { - OPENSSL_free(ctx); - return 0; - } - b->init = 1; - b->ptr = (char *)ctx; - b->flags = 0; - return 1; -} - -static int asn1_bio_init(BIO_ASN1_BUF_CTX *ctx, int size) -{ - ctx->buf = OPENSSL_malloc(size); - if (!ctx->buf) - return 0; - ctx->bufsize = size; - ctx->bufpos = 0; - ctx->buflen = 0; - ctx->copylen = 0; - ctx->asn1_class = V_ASN1_UNIVERSAL; - ctx->asn1_tag = V_ASN1_OCTET_STRING; - ctx->ex_buf = 0; - ctx->ex_pos = 0; - ctx->ex_len = 0; - ctx->state = ASN1_STATE_START; - return 1; -} - -static int asn1_bio_free(BIO *b) -{ - BIO_ASN1_BUF_CTX *ctx; - ctx = (BIO_ASN1_BUF_CTX *)b->ptr; - if (ctx == NULL) - return 0; - if (ctx->buf) - OPENSSL_free(ctx->buf); - OPENSSL_free(ctx); - b->init = 0; - b->ptr = NULL; - b->flags = 0; - return 1; -} - -static int asn1_bio_write(BIO *b, const char *in, int inl) -{ - BIO_ASN1_BUF_CTX *ctx; - int wrmax, wrlen, ret; - unsigned char *p; - if (!in || (inl < 0) || (b->next_bio == NULL)) - return 0; - ctx = (BIO_ASN1_BUF_CTX *)b->ptr; - if (ctx == NULL) - return 0; - - wrlen = 0; - ret = -1; - - for (;;) { - switch (ctx->state) { - - /* Setup prefix data, call it */ - case ASN1_STATE_START: - if (!asn1_bio_setup_ex(b, ctx, ctx->prefix, - ASN1_STATE_PRE_COPY, ASN1_STATE_HEADER)) - return 0; - break; - - /* Copy any pre data first */ - case ASN1_STATE_PRE_COPY: - - ret = asn1_bio_flush_ex(b, ctx, ctx->prefix_free, - ASN1_STATE_HEADER); - - if (ret <= 0) - goto done; - - break; - - case ASN1_STATE_HEADER: - ctx->buflen = ASN1_object_size(0, inl, ctx->asn1_tag) - inl; - assert(ctx->buflen <= ctx->bufsize); - p = ctx->buf; - ASN1_put_object(&p, 0, inl, ctx->asn1_tag, ctx->asn1_class); - ctx->copylen = inl; - ctx->state = ASN1_STATE_HEADER_COPY; - - break; - - case ASN1_STATE_HEADER_COPY: - ret = BIO_write(b->next_bio, ctx->buf + ctx->bufpos, ctx->buflen); - if (ret <= 0) - goto done; - - ctx->buflen -= ret; - if (ctx->buflen) - ctx->bufpos += ret; - else { - ctx->bufpos = 0; - ctx->state = ASN1_STATE_DATA_COPY; - } - - break; - - case ASN1_STATE_DATA_COPY: - - if (inl > ctx->copylen) - wrmax = ctx->copylen; - else - wrmax = inl; - ret = BIO_write(b->next_bio, in, wrmax); - if (ret <= 0) - break; - wrlen += ret; - ctx->copylen -= ret; - in += ret; - inl -= ret; - - if (ctx->copylen == 0) - ctx->state = ASN1_STATE_HEADER; - - if (inl == 0) - goto done; - - break; - - default: - BIO_clear_retry_flags(b); - return 0; - - } - - } - - done: - BIO_clear_retry_flags(b); - BIO_copy_next_retry(b); - - return (wrlen > 0) ? wrlen : ret; - -} - -static int asn1_bio_flush_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx, - asn1_ps_func *cleanup, asn1_bio_state_t next) -{ - int ret; - if (ctx->ex_len <= 0) - return 1; - for (;;) { - ret = BIO_write(b->next_bio, ctx->ex_buf + ctx->ex_pos, ctx->ex_len); - if (ret <= 0) - break; - ctx->ex_len -= ret; - if (ctx->ex_len > 0) - ctx->ex_pos += ret; - else { - if (cleanup) - cleanup(b, &ctx->ex_buf, &ctx->ex_len, &ctx->ex_arg); - ctx->state = next; - ctx->ex_pos = 0; - break; - } - } - return ret; -} - -static int asn1_bio_setup_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx, - asn1_ps_func *setup, - asn1_bio_state_t ex_state, - asn1_bio_state_t other_state) -{ - if (setup && !setup(b, &ctx->ex_buf, &ctx->ex_len, &ctx->ex_arg)) { - BIO_clear_retry_flags(b); - return 0; - } - if (ctx->ex_len > 0) - ctx->state = ex_state; - else - ctx->state = other_state; - return 1; -} - -static int asn1_bio_read(BIO *b, char *in, int inl) -{ - if (!b->next_bio) - return 0; - return BIO_read(b->next_bio, in, inl); -} - -static int asn1_bio_puts(BIO *b, const char *str) -{ - return asn1_bio_write(b, str, strlen(str)); -} - -static int asn1_bio_gets(BIO *b, char *str, int size) -{ - if (!b->next_bio) - return 0; - return BIO_gets(b->next_bio, str, size); -} - -static long asn1_bio_callback_ctrl(BIO *b, int cmd, bio_info_cb fp) -{ - if (b->next_bio == NULL) - return (0); - return BIO_callback_ctrl(b->next_bio, cmd, fp); -} - -static long asn1_bio_ctrl(BIO *b, int cmd, long arg1, void *arg2) -{ - BIO_ASN1_BUF_CTX *ctx; - BIO_ASN1_EX_FUNCS *ex_func; - long ret = 1; - ctx = (BIO_ASN1_BUF_CTX *)b->ptr; - if (ctx == NULL) - return 0; - switch (cmd) { - - case BIO_C_SET_PREFIX: - ex_func = arg2; - ctx->prefix = ex_func->ex_func; - ctx->prefix_free = ex_func->ex_free_func; - break; - - case BIO_C_GET_PREFIX: - ex_func = arg2; - ex_func->ex_func = ctx->prefix; - ex_func->ex_free_func = ctx->prefix_free; - break; - - case BIO_C_SET_SUFFIX: - ex_func = arg2; - ctx->suffix = ex_func->ex_func; - ctx->suffix_free = ex_func->ex_free_func; - break; - - case BIO_C_GET_SUFFIX: - ex_func = arg2; - ex_func->ex_func = ctx->suffix; - ex_func->ex_free_func = ctx->suffix_free; - break; - - case BIO_C_SET_EX_ARG: - ctx->ex_arg = arg2; - break; - - case BIO_C_GET_EX_ARG: - *(void **)arg2 = ctx->ex_arg; - break; - - case BIO_CTRL_FLUSH: - if (!b->next_bio) - return 0; - - /* Call post function if possible */ - if (ctx->state == ASN1_STATE_HEADER) { - if (!asn1_bio_setup_ex(b, ctx, ctx->suffix, - ASN1_STATE_POST_COPY, ASN1_STATE_DONE)) - return 0; - } - - if (ctx->state == ASN1_STATE_POST_COPY) { - ret = asn1_bio_flush_ex(b, ctx, ctx->suffix_free, - ASN1_STATE_DONE); - if (ret <= 0) - return ret; - } - - if (ctx->state == ASN1_STATE_DONE) - return BIO_ctrl(b->next_bio, cmd, arg1, arg2); - else { - BIO_clear_retry_flags(b); - return 0; - } - break; - - default: - if (!b->next_bio) - return 0; - return BIO_ctrl(b->next_bio, cmd, arg1, arg2); - - } - - return ret; -} - -static int asn1_bio_set_ex(BIO *b, int cmd, - asn1_ps_func *ex_func, asn1_ps_func *ex_free_func) -{ - BIO_ASN1_EX_FUNCS extmp; - extmp.ex_func = ex_func; - extmp.ex_free_func = ex_free_func; - return BIO_ctrl(b, cmd, 0, &extmp); -} - -static int asn1_bio_get_ex(BIO *b, int cmd, - asn1_ps_func **ex_func, - asn1_ps_func **ex_free_func) -{ - BIO_ASN1_EX_FUNCS extmp; - int ret; - ret = BIO_ctrl(b, cmd, 0, &extmp); - if (ret > 0) { - *ex_func = extmp.ex_func; - *ex_free_func = extmp.ex_free_func; - } - return ret; -} - -int BIO_asn1_set_prefix(BIO *b, asn1_ps_func *prefix, - asn1_ps_func *prefix_free) -{ - return asn1_bio_set_ex(b, BIO_C_SET_PREFIX, prefix, prefix_free); -} - -int BIO_asn1_get_prefix(BIO *b, asn1_ps_func **pprefix, - asn1_ps_func **pprefix_free) -{ - return asn1_bio_get_ex(b, BIO_C_GET_PREFIX, pprefix, pprefix_free); -} - -int BIO_asn1_set_suffix(BIO *b, asn1_ps_func *suffix, - asn1_ps_func *suffix_free) -{ - return asn1_bio_set_ex(b, BIO_C_SET_SUFFIX, suffix, suffix_free); -} - -int BIO_asn1_get_suffix(BIO *b, asn1_ps_func **psuffix, - asn1_ps_func **psuffix_free) -{ - return asn1_bio_get_ex(b, BIO_C_GET_SUFFIX, psuffix, psuffix_free); -} diff --git a/Sources/BoringSSL/crypto/asn1/bio_ndef.c b/Sources/BoringSSL/crypto/asn1/bio_ndef.c deleted file mode 100644 index 81a8aa7c8..000000000 --- a/Sources/BoringSSL/crypto/asn1/bio_ndef.c +++ /dev/null @@ -1,251 +0,0 @@ -/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) - * All rights reserved. - * - * This package is an SSL implementation written - * by Eric Young (eay@cryptsoft.com). - * The implementation was written so as to conform with Netscapes SSL. - * - * This library is free for commercial and non-commercial use as long as - * the following conditions are aheared to. The following conditions - * apply to all code found in this distribution, be it the RC4, RSA, - * lhash, DES, etc., code; not just the SSL code. The SSL documentation - * included with this distribution is covered by the same copyright terms - * except that the holder is Tim Hudson (tjh@cryptsoft.com). - * - * Copyright remains Eric Young's, and as such any Copyright notices in - * the code are not to be removed. - * If this package is used in a product, Eric Young should be given attribution - * as the author of the parts of the library used. - * This can be in the form of a textual message at program startup or - * in documentation (online or textual) provided with the package. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * "This product includes cryptographic software written by - * Eric Young (eay@cryptsoft.com)" - * The word 'cryptographic' can be left out if the rouines from the library - * being used are not cryptographic related :-). - * 4. If you include any Windows specific code (or a derivative thereof) from - * the apps directory (application code) you must include an acknowledgement: - * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" - * - * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * The licence and distribution terms for any publically available version or - * derivative of this code cannot be changed. i.e. this code cannot simply be - * copied and put under another distribution licence - * [including the GNU Public Licence.] */ - -#include - -#include - -#include -#include -#include -#include - -/* Experimental NDEF ASN1 BIO support routines */ - -/* - * The usage is quite simple, initialize an ASN1 structure, get a BIO from it - * then any data written through the BIO will end up translated to - * approptiate format on the fly. The data is streamed out and does *not* - * need to be all held in memory at once. When the BIO is flushed the output - * is finalized and any signatures etc written out. The BIO is a 'proper' - * BIO and can handle non blocking I/O correctly. The usage is simple. The - * implementation is *not*... - */ - -/* BIO support data stored in the ASN1 BIO ex_arg */ - -typedef struct ndef_aux_st { - /* ASN1 structure this BIO refers to */ - ASN1_VALUE *val; - const ASN1_ITEM *it; - /* Top of the BIO chain */ - BIO *ndef_bio; - /* Output BIO */ - BIO *out; - /* Boundary where content is inserted */ - unsigned char **boundary; - /* DER buffer start */ - unsigned char *derbuf; -} NDEF_SUPPORT; - -static int ndef_prefix(BIO *b, unsigned char **pbuf, int *plen, void *parg); -static int ndef_prefix_free(BIO *b, unsigned char **pbuf, int *plen, - void *parg); -static int ndef_suffix(BIO *b, unsigned char **pbuf, int *plen, void *parg); -static int ndef_suffix_free(BIO *b, unsigned char **pbuf, int *plen, - void *parg); - -BIO *BIO_new_NDEF(BIO *out, ASN1_VALUE *val, const ASN1_ITEM *it) -{ - NDEF_SUPPORT *ndef_aux = NULL; - BIO *asn_bio = NULL; - const ASN1_AUX *aux = it->funcs; - ASN1_STREAM_ARG sarg; - - if (!aux || !aux->asn1_cb) { - OPENSSL_PUT_ERROR(ASN1, ASN1_R_STREAMING_NOT_SUPPORTED); - return NULL; - } - ndef_aux = OPENSSL_malloc(sizeof(NDEF_SUPPORT)); - asn_bio = BIO_new(BIO_f_asn1()); - - /* ASN1 bio needs to be next to output BIO */ - - out = BIO_push(asn_bio, out); - - if (!ndef_aux || !asn_bio || !out) - goto err; - - BIO_asn1_set_prefix(asn_bio, ndef_prefix, ndef_prefix_free); - BIO_asn1_set_suffix(asn_bio, ndef_suffix, ndef_suffix_free); - - /* - * Now let callback prepend any digest, cipher etc BIOs ASN1 structure - * needs. - */ - - sarg.out = out; - sarg.ndef_bio = NULL; - sarg.boundary = NULL; - - if (aux->asn1_cb(ASN1_OP_STREAM_PRE, &val, it, &sarg) <= 0) - goto err; - - ndef_aux->val = val; - ndef_aux->it = it; - ndef_aux->ndef_bio = sarg.ndef_bio; - ndef_aux->boundary = sarg.boundary; - ndef_aux->out = out; - - BIO_ctrl(asn_bio, BIO_C_SET_EX_ARG, 0, ndef_aux); - - return sarg.ndef_bio; - - err: - if (asn_bio) - BIO_free(asn_bio); - if (ndef_aux) - OPENSSL_free(ndef_aux); - return NULL; -} - -static int ndef_prefix(BIO *b, unsigned char **pbuf, int *plen, void *parg) -{ - NDEF_SUPPORT *ndef_aux; - unsigned char *p; - int derlen; - - if (!parg) - return 0; - - ndef_aux = *(NDEF_SUPPORT **)parg; - - derlen = ASN1_item_ndef_i2d(ndef_aux->val, NULL, ndef_aux->it); - p = OPENSSL_malloc(derlen); - if (p == NULL) - return 0; - - ndef_aux->derbuf = p; - *pbuf = p; - derlen = ASN1_item_ndef_i2d(ndef_aux->val, &p, ndef_aux->it); - - if (!*ndef_aux->boundary) - return 0; - - *plen = *ndef_aux->boundary - *pbuf; - - return 1; -} - -static int ndef_prefix_free(BIO *b, unsigned char **pbuf, int *plen, - void *parg) -{ - NDEF_SUPPORT *ndef_aux; - - if (!parg) - return 0; - - ndef_aux = *(NDEF_SUPPORT **)parg; - - if (ndef_aux->derbuf) - OPENSSL_free(ndef_aux->derbuf); - - ndef_aux->derbuf = NULL; - *pbuf = NULL; - *plen = 0; - return 1; -} - -static int ndef_suffix_free(BIO *b, unsigned char **pbuf, int *plen, - void *parg) -{ - NDEF_SUPPORT **pndef_aux = (NDEF_SUPPORT **)parg; - if (!ndef_prefix_free(b, pbuf, plen, parg)) - return 0; - OPENSSL_free(*pndef_aux); - *pndef_aux = NULL; - return 1; -} - -static int ndef_suffix(BIO *b, unsigned char **pbuf, int *plen, void *parg) -{ - NDEF_SUPPORT *ndef_aux; - unsigned char *p; - int derlen; - const ASN1_AUX *aux; - ASN1_STREAM_ARG sarg; - - if (!parg) - return 0; - - ndef_aux = *(NDEF_SUPPORT **)parg; - - aux = ndef_aux->it->funcs; - - /* Finalize structures */ - sarg.ndef_bio = ndef_aux->ndef_bio; - sarg.out = ndef_aux->out; - sarg.boundary = ndef_aux->boundary; - if (aux->asn1_cb(ASN1_OP_STREAM_POST, - &ndef_aux->val, ndef_aux->it, &sarg) <= 0) - return 0; - - derlen = ASN1_item_ndef_i2d(ndef_aux->val, NULL, ndef_aux->it); - p = OPENSSL_malloc(derlen); - if (p == NULL) - return 0; - - ndef_aux->derbuf = p; - *pbuf = p; - derlen = ASN1_item_ndef_i2d(ndef_aux->val, &p, ndef_aux->it); - - if (!*ndef_aux->boundary) - return 0; - *pbuf = *ndef_aux->boundary; - *plen = derlen - (*ndef_aux->boundary - ndef_aux->derbuf); - - return 1; -} diff --git a/Sources/BoringSSL/crypto/asn1/f_enum.c b/Sources/BoringSSL/crypto/asn1/f_enum.c index 3af16f8a9..7ce479dc4 100644 --- a/Sources/BoringSSL/crypto/asn1/f_enum.c +++ b/Sources/BoringSSL/crypto/asn1/f_enum.c @@ -56,8 +56,7 @@ #include -#include -#include +#include /* Based on a_int.c: equivalent ENUMERATED functions */ @@ -92,109 +91,3 @@ int i2a_ASN1_ENUMERATED(BIO *bp, ASN1_ENUMERATED *a) err: return (-1); } - -int a2i_ASN1_ENUMERATED(BIO *bp, ASN1_ENUMERATED *bs, char *buf, int size) -{ - int ret = 0; - int i, j, k, m, n, again, bufsize; - unsigned char *s = NULL, *sp; - unsigned char *bufp; - int num = 0, slen = 0, first = 1; - - bs->type = V_ASN1_ENUMERATED; - - bufsize = BIO_gets(bp, buf, size); - for (;;) { - if (bufsize < 1) - goto err_sl; - i = bufsize; - if (buf[i - 1] == '\n') - buf[--i] = '\0'; - if (i == 0) - goto err_sl; - if (buf[i - 1] == '\r') - buf[--i] = '\0'; - if (i == 0) - goto err_sl; - again = (buf[i - 1] == '\\'); - - for (j = 0; j < i; j++) { - if (!(((buf[j] >= '0') && (buf[j] <= '9')) || - ((buf[j] >= 'a') && (buf[j] <= 'f')) || - ((buf[j] >= 'A') && (buf[j] <= 'F')))) { - i = j; - break; - } - } - buf[i] = '\0'; - /* - * We have now cleared all the crap off the end of the line - */ - if (i < 2) - goto err_sl; - - bufp = (unsigned char *)buf; - if (first) { - first = 0; - if ((bufp[0] == '0') && (buf[1] == '0')) { - bufp += 2; - i -= 2; - } - } - k = 0; - i -= again; - if (i % 2 != 0) { - OPENSSL_PUT_ERROR(ASN1, ASN1_R_ODD_NUMBER_OF_CHARS); - goto err; - } - i /= 2; - if (num + i > slen) { - if (s == NULL) - sp = (unsigned char *)OPENSSL_malloc((unsigned int)num + - i * 2); - else - sp = (unsigned char *)OPENSSL_realloc(s, - (unsigned int)num + - i * 2); - if (sp == NULL) { - OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); - goto err; - } - s = sp; - slen = num + i * 2; - } - for (j = 0; j < i; j++, k += 2) { - for (n = 0; n < 2; n++) { - m = bufp[k + n]; - if ((m >= '0') && (m <= '9')) - m -= '0'; - else if ((m >= 'a') && (m <= 'f')) - m = m - 'a' + 10; - else if ((m >= 'A') && (m <= 'F')) - m = m - 'A' + 10; - else { - OPENSSL_PUT_ERROR(ASN1, ASN1_R_NON_HEX_CHARACTERS); - goto err; - } - s[num + j] <<= 4; - s[num + j] |= m; - } - } - num += i; - if (again) - bufsize = BIO_gets(bp, buf, size); - else - break; - } - bs->length = num; - bs->data = s; - ret = 1; - err: - if (0) { - err_sl: - OPENSSL_PUT_ERROR(ASN1, ASN1_R_SHORT_LINE); - } - if (s != NULL) - OPENSSL_free(s); - return (ret); -} diff --git a/Sources/BoringSSL/crypto/asn1/f_int.c b/Sources/BoringSSL/crypto/asn1/f_int.c index 60c0f2f2b..79ea152b6 100644 --- a/Sources/BoringSSL/crypto/asn1/f_int.c +++ b/Sources/BoringSSL/crypto/asn1/f_int.c @@ -56,8 +56,7 @@ #include -#include -#include +#include int i2a_ASN1_INTEGER(BIO *bp, ASN1_INTEGER *a) { @@ -96,107 +95,3 @@ int i2a_ASN1_INTEGER(BIO *bp, ASN1_INTEGER *a) err: return (-1); } - -int a2i_ASN1_INTEGER(BIO *bp, ASN1_INTEGER *bs, char *buf, int size) -{ - int ret = 0; - int i, j, k, m, n, again, bufsize; - unsigned char *s = NULL, *sp; - unsigned char *bufp; - int num = 0, slen = 0, first = 1; - - bs->type = V_ASN1_INTEGER; - - bufsize = BIO_gets(bp, buf, size); - for (;;) { - if (bufsize < 1) - goto err_sl; - i = bufsize; - if (buf[i - 1] == '\n') - buf[--i] = '\0'; - if (i == 0) - goto err_sl; - if (buf[i - 1] == '\r') - buf[--i] = '\0'; - if (i == 0) - goto err_sl; - again = (buf[i - 1] == '\\'); - - for (j = 0; j < i; j++) { - if (!(((buf[j] >= '0') && (buf[j] <= '9')) || - ((buf[j] >= 'a') && (buf[j] <= 'f')) || - ((buf[j] >= 'A') && (buf[j] <= 'F')))) { - i = j; - break; - } - } - buf[i] = '\0'; - /* - * We have now cleared all the crap off the end of the line - */ - if (i < 2) - goto err_sl; - - bufp = (unsigned char *)buf; - if (first) { - first = 0; - if ((bufp[0] == '0') && (buf[1] == '0')) { - bufp += 2; - i -= 2; - } - } - k = 0; - i -= again; - if (i % 2 != 0) { - OPENSSL_PUT_ERROR(ASN1, ASN1_R_ODD_NUMBER_OF_CHARS); - goto err; - } - i /= 2; - if (num + i > slen) { - if (s == NULL) - sp = (unsigned char *)OPENSSL_malloc((unsigned int)num + - i * 2); - else - sp = OPENSSL_realloc_clean(s, slen, num + i * 2); - if (sp == NULL) { - OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); - goto err; - } - s = sp; - slen = num + i * 2; - } - for (j = 0; j < i; j++, k += 2) { - for (n = 0; n < 2; n++) { - m = bufp[k + n]; - if ((m >= '0') && (m <= '9')) - m -= '0'; - else if ((m >= 'a') && (m <= 'f')) - m = m - 'a' + 10; - else if ((m >= 'A') && (m <= 'F')) - m = m - 'A' + 10; - else { - OPENSSL_PUT_ERROR(ASN1, ASN1_R_NON_HEX_CHARACTERS); - goto err; - } - s[num + j] <<= 4; - s[num + j] |= m; - } - } - num += i; - if (again) - bufsize = BIO_gets(bp, buf, size); - else - break; - } - bs->length = num; - bs->data = s; - ret = 1; - err: - if (0) { - err_sl: - OPENSSL_PUT_ERROR(ASN1, ASN1_R_SHORT_LINE); - } - if (s != NULL) - OPENSSL_free(s); - return (ret); -} diff --git a/Sources/BoringSSL/crypto/asn1/f_string.c b/Sources/BoringSSL/crypto/asn1/f_string.c index ec9cb83d1..97c6ae7de 100644 --- a/Sources/BoringSSL/crypto/asn1/f_string.c +++ b/Sources/BoringSSL/crypto/asn1/f_string.c @@ -56,8 +56,7 @@ #include -#include -#include +#include int i2a_ASN1_STRING(BIO *bp, ASN1_STRING *a, int type) { @@ -90,107 +89,3 @@ int i2a_ASN1_STRING(BIO *bp, ASN1_STRING *a, int type) err: return (-1); } - -int a2i_ASN1_STRING(BIO *bp, ASN1_STRING *bs, char *buf, int size) -{ - int ret = 0; - int i, j, k, m, n, again, bufsize; - unsigned char *s = NULL, *sp; - unsigned char *bufp; - int num = 0, slen = 0, first = 1; - - bufsize = BIO_gets(bp, buf, size); - for (;;) { - if (bufsize < 1) { - if (first) - break; - else - goto err_sl; - } - first = 0; - - i = bufsize; - if (buf[i - 1] == '\n') - buf[--i] = '\0'; - if (i == 0) - goto err_sl; - if (buf[i - 1] == '\r') - buf[--i] = '\0'; - if (i == 0) - goto err_sl; - again = (buf[i - 1] == '\\'); - - for (j = i - 1; j > 0; j--) { - if (!(((buf[j] >= '0') && (buf[j] <= '9')) || - ((buf[j] >= 'a') && (buf[j] <= 'f')) || - ((buf[j] >= 'A') && (buf[j] <= 'F')))) { - i = j; - break; - } - } - buf[i] = '\0'; - /* - * We have now cleared all the crap off the end of the line - */ - if (i < 2) - goto err_sl; - - bufp = (unsigned char *)buf; - - k = 0; - i -= again; - if (i % 2 != 0) { - OPENSSL_PUT_ERROR(ASN1, ASN1_R_ODD_NUMBER_OF_CHARS); - goto err; - } - i /= 2; - if (num + i > slen) { - if (s == NULL) - sp = (unsigned char *)OPENSSL_malloc((unsigned int)num + - i * 2); - else - sp = (unsigned char *)OPENSSL_realloc(s, - (unsigned int)num + - i * 2); - if (sp == NULL) { - OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); - goto err; - } - s = sp; - slen = num + i * 2; - } - for (j = 0; j < i; j++, k += 2) { - for (n = 0; n < 2; n++) { - m = bufp[k + n]; - if ((m >= '0') && (m <= '9')) - m -= '0'; - else if ((m >= 'a') && (m <= 'f')) - m = m - 'a' + 10; - else if ((m >= 'A') && (m <= 'F')) - m = m - 'A' + 10; - else { - OPENSSL_PUT_ERROR(ASN1, ASN1_R_NON_HEX_CHARACTERS); - goto err; - } - s[num + j] <<= 4; - s[num + j] |= m; - } - } - num += i; - if (again) - bufsize = BIO_gets(bp, buf, size); - else - break; - } - bs->length = num; - bs->data = s; - ret = 1; - err: - if (0) { - err_sl: - OPENSSL_PUT_ERROR(ASN1, ASN1_R_SHORT_LINE); - } - if (s != NULL) - OPENSSL_free(s); - return (ret); -} diff --git a/Sources/BoringSSL/crypto/asn1/t_pkey.c b/Sources/BoringSSL/crypto/asn1/t_pkey.c deleted file mode 100644 index 2c4208946..000000000 --- a/Sources/BoringSSL/crypto/asn1/t_pkey.c +++ /dev/null @@ -1,110 +0,0 @@ -/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) - * All rights reserved. - * - * This package is an SSL implementation written - * by Eric Young (eay@cryptsoft.com). - * The implementation was written so as to conform with Netscapes SSL. - * - * This library is free for commercial and non-commercial use as long as - * the following conditions are aheared to. The following conditions - * apply to all code found in this distribution, be it the RC4, RSA, - * lhash, DES, etc., code; not just the SSL code. The SSL documentation - * included with this distribution is covered by the same copyright terms - * except that the holder is Tim Hudson (tjh@cryptsoft.com). - * - * Copyright remains Eric Young's, and as such any Copyright notices in - * the code are not to be removed. - * If this package is used in a product, Eric Young should be given attribution - * as the author of the parts of the library used. - * This can be in the form of a textual message at program startup or - * in documentation (online or textual) provided with the package. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * "This product includes cryptographic software written by - * Eric Young (eay@cryptsoft.com)" - * The word 'cryptographic' can be left out if the rouines from the library - * being used are not cryptographic related :-). - * 4. If you include any Windows specific code (or a derivative thereof) from - * the apps directory (application code) you must include an acknowledgement: - * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" - * - * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * The licence and distribution terms for any publically available version or - * derivative of this code cannot be changed. i.e. this code cannot simply be - * copied and put under another distribution licence - * [including the GNU Public Licence.] */ - -#include - -#include -#include - -int ASN1_bn_print(BIO *bp, const char *number, const BIGNUM *num, - unsigned char *buf, int off) -{ - int n, i; - const char *neg; - - if (num == NULL) - return (1); - neg = (BN_is_negative(num)) ? "-" : ""; - if (!BIO_indent(bp, off, 128)) - return 0; - if (BN_is_zero(num)) { - if (BIO_printf(bp, "%s 0\n", number) <= 0) - return 0; - return 1; - } - - if (BN_num_bytes(num) <= sizeof(long)) { - if (BIO_printf(bp, "%s %s%lu (%s0x%lx)\n", number, neg, - (unsigned long)num->d[0], neg, - (unsigned long)num->d[0]) - <= 0) - return (0); - } else { - buf[0] = 0; - if (BIO_printf(bp, "%s%s", number, - (neg[0] == '-') ? " (Negative)" : "") <= 0) - return (0); - n = BN_bn2bin(num, &buf[1]); - - if (buf[1] & 0x80) - n++; - else - buf++; - - for (i = 0; i < n; i++) { - if ((i % 15) == 0) { - if (BIO_puts(bp, "\n") <= 0 || !BIO_indent(bp, off + 4, 128)) - return 0; - } - if (BIO_printf(bp, "%02x%s", buf[i], ((i + 1) == n) ? "" : ":") - <= 0) - return (0); - } - if (BIO_write(bp, "\n", 1) <= 0) - return (0); - } - return (1); -} diff --git a/Sources/BoringSSL/crypto/asn1/tasn_dec.c b/Sources/BoringSSL/crypto/asn1/tasn_dec.c index fd07fa24c..bf008af1d 100644 --- a/Sources/BoringSSL/crypto/asn1/tasn_dec.c +++ b/Sources/BoringSSL/crypto/asn1/tasn_dec.c @@ -180,6 +180,7 @@ int ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len, int ret = 0; ASN1_VALUE **pchptr, *ptmpval; int combine = aclass & ASN1_TFLG_COMBINE; + aclass &= ~ASN1_TFLG_COMBINE; if (!pval) return 0; if (aux && aux->asn1_cb) @@ -399,7 +400,9 @@ int ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len, if (tt->flags & ASN1_TFLG_ADB_MASK) { const ASN1_TEMPLATE *seqtt; ASN1_VALUE **pseqval; - seqtt = asn1_do_adb(pval, tt, 1); + seqtt = asn1_do_adb(pval, tt, 0); + if (seqtt == NULL) + continue; pseqval = asn1_get_field_ptr(pval, seqtt); ASN1_template_free(pseqval, seqtt); } @@ -410,7 +413,7 @@ int ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len, const ASN1_TEMPLATE *seqtt; ASN1_VALUE **pseqval; seqtt = asn1_do_adb(pval, tt, 1); - if (!seqtt) + if (seqtt == NULL) goto err; pseqval = asn1_get_field_ptr(pval, seqtt); /* Have we ran out of data? */ @@ -475,7 +478,7 @@ int ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len, for (; i < it->tcount; tt++, i++) { const ASN1_TEMPLATE *seqtt; seqtt = asn1_do_adb(pval, tt, 1); - if (!seqtt) + if (seqtt == NULL) goto err; if (seqtt->flags & ASN1_TFLG_OPTIONAL) { ASN1_VALUE **pseqval; @@ -665,6 +668,7 @@ static int asn1_template_noexp_d2i(ASN1_VALUE **val, } len -= p - q; if (!sk_ASN1_VALUE_push((STACK_OF(ASN1_VALUE) *)*val, skfield)) { + ASN1_item_ex_free(&skfield, ASN1_ITEM_ptr(tt->item)); OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); goto err; } @@ -706,13 +710,12 @@ static int asn1_d2i_ex_primitive(ASN1_VALUE **pval, const unsigned char **in, long inlen, const ASN1_ITEM *it, int tag, int aclass, char opt, ASN1_TLC *ctx) - OPENSSL_SUPPRESS_POTENTIALLY_UNINITIALIZED_WARNINGS { int ret = 0, utype; long plen; char cst, inf, free_cont = 0; const unsigned char *p; - BUF_MEM buf; + BUF_MEM buf = {0, NULL, 0 }; const unsigned char *cont = NULL; long len; if (!pval) { @@ -786,7 +789,6 @@ static int asn1_d2i_ex_primitive(ASN1_VALUE **pval, } else { len = p - cont + plen; p += plen; - buf.data = NULL; } } else if (cst) { if (utype == V_ASN1_NULL || utype == V_ASN1_BOOLEAN @@ -797,9 +799,8 @@ static int asn1_d2i_ex_primitive(ASN1_VALUE **pval, return 0; } - buf.length = 0; - buf.max = 0; - buf.data = NULL; + /* Free any returned 'buf' content */ + free_cont = 1; /* * Should really check the internal tags are correct but some things * may get this wrong. The relevant specs say that constructed string @@ -807,18 +808,16 @@ static int asn1_d2i_ex_primitive(ASN1_VALUE **pval, * So instead just check for UNIVERSAL class and ignore the tag. */ if (!asn1_collect(&buf, &p, plen, inf, -1, V_ASN1_UNIVERSAL, 0)) { - free_cont = 1; goto err; } len = buf.length; /* Append a final null to string */ if (!BUF_MEM_grow_clean(&buf, len + 1)) { OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); - return 0; + goto err; } buf.data[len] = 0; cont = (const unsigned char *)buf.data; - free_cont = 1; } else { cont = p; len = plen; @@ -826,6 +825,7 @@ static int asn1_d2i_ex_primitive(ASN1_VALUE **pval, } /* We now have content length and type: translate into a structure */ + /* asn1_ex_c2i may reuse allocated buffer, and so sets free_cont to 0 */ if (!asn1_ex_c2i(pval, cont, len, utype, &free_cont, it)) goto err; @@ -898,9 +898,7 @@ int asn1_ex_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len, break; case V_ASN1_INTEGER: - case V_ASN1_NEG_INTEGER: case V_ASN1_ENUMERATED: - case V_ASN1_NEG_ENUMERATED: tint = (ASN1_INTEGER **)pval; if (!c2i_ASN1_INTEGER(tint, &cont, len)) goto err; @@ -1112,7 +1110,7 @@ static int collect_data(BUF_MEM *buf, const unsigned char **p, long plen) OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); return 0; } - memcpy(buf->data + len, *p, plen); + OPENSSL_memcpy(buf->data + len, *p, plen); } *p += plen; return 1; diff --git a/Sources/BoringSSL/crypto/asn1/tasn_enc.c b/Sources/BoringSSL/crypto/asn1/tasn_enc.c index a56d08ed8..9286ef641 100644 --- a/Sources/BoringSSL/crypto/asn1/tasn_enc.c +++ b/Sources/BoringSSL/crypto/asn1/tasn_enc.c @@ -56,11 +56,15 @@ #include +#include #include #include #include +#include "../internal.h" + + static int asn1_i2d_ex_primitive(ASN1_VALUE **pval, unsigned char **out, const ASN1_ITEM *it, int tag, int aclass); static int asn1_set_seq_out(STACK_OF(ASN1_VALUE) *sk, unsigned char **out, @@ -213,17 +217,19 @@ int ASN1_item_ex_i2d(ASN1_VALUE **pval, unsigned char **out, for (i = 0, tt = it->templates; i < it->tcount; tt++, i++) { const ASN1_TEMPLATE *seqtt; ASN1_VALUE **pseqval; + int tmplen; seqtt = asn1_do_adb(pval, tt, 1); if (!seqtt) return 0; pseqval = asn1_get_field_ptr(pval, seqtt); - /* FIXME: check for errors in enhanced version */ - seqcontlen += asn1_template_ex_i2d(pseqval, NULL, seqtt, - -1, aclass); + tmplen = asn1_template_ex_i2d(pseqval, NULL, seqtt, -1, aclass); + if (tmplen == -1 || (tmplen > INT_MAX - seqcontlen)) + return -1; + seqcontlen += tmplen; } seqlen = ASN1_object_size(ndef, seqcontlen, tag); - if (!out) + if (!out || seqlen == -1) return seqlen; /* Output SEQUENCE header */ ASN1_put_object(out, ndef, seqcontlen, tag, aclass); @@ -337,19 +343,24 @@ static int asn1_template_ex_i2d(ASN1_VALUE **pval, unsigned char **out, /* Determine total length of items */ skcontlen = 0; for (j = 0; j < sk_ASN1_VALUE_num(sk); j++) { + int tmplen; skitem = sk_ASN1_VALUE_value(sk, j); - skcontlen += ASN1_item_ex_i2d(&skitem, NULL, - ASN1_ITEM_ptr(tt->item), - -1, iclass); + tmplen = ASN1_item_ex_i2d(&skitem, NULL, ASN1_ITEM_ptr(tt->item), + -1, iclass); + if (tmplen == -1 || (skcontlen > INT_MAX - tmplen)) + return -1; + skcontlen += tmplen; } sklen = ASN1_object_size(ndef, skcontlen, sktag); + if (sklen == -1) + return -1; /* If EXPLICIT need length of surrounding tag */ if (flags & ASN1_TFLG_EXPTAG) ret = ASN1_object_size(ndef, sklen, ttag); else ret = sklen; - if (!out) + if (!out || ret == -1) return ret; /* Now encode this lot... */ @@ -378,7 +389,7 @@ static int asn1_template_ex_i2d(ASN1_VALUE **pval, unsigned char **out, return 0; /* Find length of EXPLICIT tag */ ret = ASN1_object_size(ndef, i, ttag); - if (out) { + if (out && ret != -1) { /* Output tag and item */ ASN1_put_object(out, ndef, i, ttag, tclass); ASN1_item_ex_i2d(pval, out, ASN1_ITEM_ptr(tt->item), -1, iclass); @@ -407,7 +418,7 @@ static int der_cmp(const void *a, const void *b) const DER_ENC *d1 = a, *d2 = b; int cmplen, i; cmplen = (d1->length < d2->length) ? d1->length : d2->length; - i = memcmp(d1->data, d2->data, cmplen); + i = OPENSSL_memcmp(d1->data, d2->data, cmplen); if (i) return i; return d1->length - d2->length; @@ -462,7 +473,7 @@ static int asn1_set_seq_out(STACK_OF(ASN1_VALUE) *sk, unsigned char **out, /* Output sorted DER encoding */ p = *out; for (i = 0, tder = derlst; i < sk_ASN1_VALUE_num(sk); i++, tder++) { - memcpy(p, tder->data, tder->length); + OPENSSL_memcpy(p, tder->data, tder->length); p += tder->length; } *out = p; @@ -609,9 +620,7 @@ int asn1_ex_i2c(ASN1_VALUE **pval, unsigned char *cout, int *putype, break; case V_ASN1_INTEGER: - case V_ASN1_NEG_INTEGER: case V_ASN1_ENUMERATED: - case V_ASN1_NEG_ENUMERATED: /* * These are all have the same content format as ASN1_INTEGER */ @@ -654,6 +663,6 @@ int asn1_ex_i2c(ASN1_VALUE **pval, unsigned char *cout, int *putype, } if (cout && len) - memcpy(cout, cont, len); + OPENSSL_memcpy(cout, cont, len); return len; } diff --git a/Sources/BoringSSL/crypto/asn1/tasn_new.c b/Sources/BoringSSL/crypto/asn1/tasn_new.c index 232fe46aa..10cf954f7 100644 --- a/Sources/BoringSSL/crypto/asn1/tasn_new.c +++ b/Sources/BoringSSL/crypto/asn1/tasn_new.c @@ -63,6 +63,9 @@ #include #include +#include "../internal.h" + + static int asn1_item_ex_combine_new(ASN1_VALUE **pval, const ASN1_ITEM *it, int combine); static void asn1_item_clear(ASN1_VALUE **pval, const ASN1_ITEM *it); @@ -153,11 +156,11 @@ static int asn1_item_ex_combine_new(ASN1_VALUE **pval, const ASN1_ITEM *it, *pval = OPENSSL_malloc(it->size); if (!*pval) goto memerr; - memset(*pval, 0, it->size); + OPENSSL_memset(*pval, 0, it->size); } asn1_set_choice_selector(pval, -1, it); if (asn1_cb && !asn1_cb(ASN1_OP_NEW_POST, pval, it, NULL)) - goto auxerr; + goto auxerr2; break; case ASN1_ITYPE_NDEF_SEQUENCE: @@ -178,17 +181,17 @@ static int asn1_item_ex_combine_new(ASN1_VALUE **pval, const ASN1_ITEM *it, *pval = OPENSSL_malloc(it->size); if (!*pval) goto memerr; - memset(*pval, 0, it->size); + OPENSSL_memset(*pval, 0, it->size); asn1_refcount_set_one(pval, it); asn1_enc_init(pval, it); } for (i = 0, tt = it->templates; i < it->tcount; tt++, i++) { pseqval = asn1_get_field_ptr(pval, tt); if (!ASN1_template_new(pseqval, tt)) - goto memerr; + goto memerr2; } if (asn1_cb && !asn1_cb(ASN1_OP_NEW_POST, pval, it, NULL)) - goto auxerr; + goto auxerr2; break; } #ifdef CRYPTO_MDEBUG @@ -197,18 +200,20 @@ static int asn1_item_ex_combine_new(ASN1_VALUE **pval, const ASN1_ITEM *it, #endif return 1; + memerr2: + ASN1_item_ex_free(pval, it); memerr: OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); - ASN1_item_ex_free(pval, it); #ifdef CRYPTO_MDEBUG if (it->sname) CRYPTO_pop_info(); #endif return 0; + auxerr2: + ASN1_item_ex_free(pval, it); auxerr: OPENSSL_PUT_ERROR(ASN1, ASN1_R_AUX_ERROR); - ASN1_item_ex_free(pval, it); #ifdef CRYPTO_MDEBUG if (it->sname) CRYPTO_pop_info(); diff --git a/Sources/BoringSSL/crypto/asn1/tasn_prn.c b/Sources/BoringSSL/crypto/asn1/tasn_prn.c deleted file mode 100644 index dd20cb4d7..000000000 --- a/Sources/BoringSSL/crypto/asn1/tasn_prn.c +++ /dev/null @@ -1,596 +0,0 @@ -/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) - * All rights reserved. - * - * This package is an SSL implementation written - * by Eric Young (eay@cryptsoft.com). - * The implementation was written so as to conform with Netscapes SSL. - * - * This library is free for commercial and non-commercial use as long as - * the following conditions are aheared to. The following conditions - * apply to all code found in this distribution, be it the RC4, RSA, - * lhash, DES, etc., code; not just the SSL code. The SSL documentation - * included with this distribution is covered by the same copyright terms - * except that the holder is Tim Hudson (tjh@cryptsoft.com). - * - * Copyright remains Eric Young's, and as such any Copyright notices in - * the code are not to be removed. - * If this package is used in a product, Eric Young should be given attribution - * as the author of the parts of the library used. - * This can be in the form of a textual message at program startup or - * in documentation (online or textual) provided with the package. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * "This product includes cryptographic software written by - * Eric Young (eay@cryptsoft.com)" - * The word 'cryptographic' can be left out if the rouines from the library - * being used are not cryptographic related :-). - * 4. If you include any Windows specific code (or a derivative thereof) from - * the apps directory (application code) you must include an acknowledgement: - * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" - * - * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * The licence and distribution terms for any publically available version or - * derivative of this code cannot be changed. i.e. this code cannot simply be - * copied and put under another distribution licence - * [including the GNU Public Licence.] */ - -#include - -#include - -#include -#include -#include -#include - -#include "asn1_locl.h" - -/* - * Print routines. - */ - -/* ASN1_PCTX routines */ - -static ASN1_PCTX default_pctx = { - ASN1_PCTX_FLAGS_SHOW_ABSENT, /* flags */ - 0, /* nm_flags */ - 0, /* cert_flags */ - 0, /* oid_flags */ - 0 /* str_flags */ -}; - -ASN1_PCTX *ASN1_PCTX_new(void) -{ - ASN1_PCTX *ret; - ret = OPENSSL_malloc(sizeof(ASN1_PCTX)); - if (ret == NULL) { - OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); - return NULL; - } - ret->flags = 0; - ret->nm_flags = 0; - ret->cert_flags = 0; - ret->oid_flags = 0; - ret->str_flags = 0; - return ret; -} - -void ASN1_PCTX_free(ASN1_PCTX *p) -{ - OPENSSL_free(p); -} - -unsigned long ASN1_PCTX_get_flags(ASN1_PCTX *p) -{ - return p->flags; -} - -void ASN1_PCTX_set_flags(ASN1_PCTX *p, unsigned long flags) -{ - p->flags = flags; -} - -unsigned long ASN1_PCTX_get_nm_flags(ASN1_PCTX *p) -{ - return p->nm_flags; -} - -void ASN1_PCTX_set_nm_flags(ASN1_PCTX *p, unsigned long flags) -{ - p->nm_flags = flags; -} - -unsigned long ASN1_PCTX_get_cert_flags(ASN1_PCTX *p) -{ - return p->cert_flags; -} - -void ASN1_PCTX_set_cert_flags(ASN1_PCTX *p, unsigned long flags) -{ - p->cert_flags = flags; -} - -unsigned long ASN1_PCTX_get_oid_flags(ASN1_PCTX *p) -{ - return p->oid_flags; -} - -void ASN1_PCTX_set_oid_flags(ASN1_PCTX *p, unsigned long flags) -{ - p->oid_flags = flags; -} - -unsigned long ASN1_PCTX_get_str_flags(ASN1_PCTX *p) -{ - return p->str_flags; -} - -void ASN1_PCTX_set_str_flags(ASN1_PCTX *p, unsigned long flags) -{ - p->str_flags = flags; -} - -/* Main print routines */ - -static int asn1_item_print_ctx(BIO *out, ASN1_VALUE **fld, int indent, - const ASN1_ITEM *it, - const char *fname, const char *sname, - int nohdr, const ASN1_PCTX *pctx); - -int asn1_template_print_ctx(BIO *out, ASN1_VALUE **fld, int indent, - const ASN1_TEMPLATE *tt, const ASN1_PCTX *pctx); - -static int asn1_primitive_print(BIO *out, ASN1_VALUE **fld, - const ASN1_ITEM *it, int indent, - const char *fname, const char *sname, - const ASN1_PCTX *pctx); - -static int asn1_print_fsname(BIO *out, int indent, - const char *fname, const char *sname, - const ASN1_PCTX *pctx); - -int ASN1_item_print(BIO *out, ASN1_VALUE *ifld, int indent, - const ASN1_ITEM *it, const ASN1_PCTX *pctx) -{ - const char *sname; - if (pctx == NULL) - pctx = &default_pctx; - if (pctx->flags & ASN1_PCTX_FLAGS_NO_STRUCT_NAME) - sname = NULL; - else - sname = it->sname; - return asn1_item_print_ctx(out, &ifld, indent, it, NULL, sname, 0, pctx); -} - -static int asn1_item_print_ctx(BIO *out, ASN1_VALUE **fld, int indent, - const ASN1_ITEM *it, - const char *fname, const char *sname, - int nohdr, const ASN1_PCTX *pctx) -{ - const ASN1_TEMPLATE *tt; - const ASN1_EXTERN_FUNCS *ef; - ASN1_VALUE **tmpfld; - const ASN1_AUX *aux = it->funcs; - ASN1_aux_cb *asn1_cb; - ASN1_PRINT_ARG parg; - int i; - if (aux && aux->asn1_cb) { - parg.out = out; - parg.indent = indent; - parg.pctx = pctx; - asn1_cb = aux->asn1_cb; - } else - asn1_cb = 0; - - if (*fld == NULL) { - if (pctx->flags & ASN1_PCTX_FLAGS_SHOW_ABSENT) { - if (!nohdr && !asn1_print_fsname(out, indent, fname, sname, pctx)) - return 0; - if (BIO_puts(out, "\n") <= 0) - return 0; - } - return 1; - } - - switch (it->itype) { - case ASN1_ITYPE_PRIMITIVE: - if (it->templates) { - if (!asn1_template_print_ctx(out, fld, indent, - it->templates, pctx)) - return 0; - break; - } - /* fall thru */ - case ASN1_ITYPE_MSTRING: - if (!asn1_primitive_print(out, fld, it, indent, fname, sname, pctx)) - return 0; - break; - - case ASN1_ITYPE_EXTERN: - if (!nohdr && !asn1_print_fsname(out, indent, fname, sname, pctx)) - return 0; - /* Use new style print routine if possible */ - ef = it->funcs; - if (ef && ef->asn1_ex_print) { - i = ef->asn1_ex_print(out, fld, indent, "", pctx); - if (!i) - return 0; - if ((i == 2) && (BIO_puts(out, "\n") <= 0)) - return 0; - return 1; - } else if (sname && - BIO_printf(out, ":EXTERNAL TYPE %s\n", sname) <= 0) - return 0; - break; - - case ASN1_ITYPE_CHOICE: -#if 0 - if (!nohdr && !asn1_print_fsname(out, indent, fname, sname, pctx)) - return 0; -#endif - /* CHOICE type, get selector */ - i = asn1_get_choice_selector(fld, it); - /* This should never happen... */ - if ((i < 0) || (i >= it->tcount)) { - if (BIO_printf(out, "ERROR: selector [%d] invalid\n", i) <= 0) - return 0; - return 1; - } - tt = it->templates + i; - tmpfld = asn1_get_field_ptr(fld, tt); - if (!asn1_template_print_ctx(out, tmpfld, indent, tt, pctx)) - return 0; - break; - - case ASN1_ITYPE_SEQUENCE: - case ASN1_ITYPE_NDEF_SEQUENCE: - if (!nohdr && !asn1_print_fsname(out, indent, fname, sname, pctx)) - return 0; - if (fname || sname) { - if (pctx->flags & ASN1_PCTX_FLAGS_SHOW_SEQUENCE) { - if (BIO_puts(out, " {\n") <= 0) - return 0; - } else { - if (BIO_puts(out, "\n") <= 0) - return 0; - } - } - - if (asn1_cb) { - i = asn1_cb(ASN1_OP_PRINT_PRE, fld, it, &parg); - if (i == 0) - return 0; - if (i == 2) - return 1; - } - - /* Print each field entry */ - for (i = 0, tt = it->templates; i < it->tcount; i++, tt++) { - const ASN1_TEMPLATE *seqtt; - seqtt = asn1_do_adb(fld, tt, 1); - if (!seqtt) - return 0; - tmpfld = asn1_get_field_ptr(fld, seqtt); - if (!asn1_template_print_ctx(out, tmpfld, - indent + 2, seqtt, pctx)) - return 0; - } - if (pctx->flags & ASN1_PCTX_FLAGS_SHOW_SEQUENCE) { - if (BIO_printf(out, "%*s}\n", indent, "") < 0) - return 0; - } - - if (asn1_cb) { - i = asn1_cb(ASN1_OP_PRINT_POST, fld, it, &parg); - if (i == 0) - return 0; - } - break; - - default: - BIO_printf(out, "Unprocessed type %d\n", it->itype); - return 0; - } - - return 1; -} - -int asn1_template_print_ctx(BIO *out, ASN1_VALUE **fld, int indent, - const ASN1_TEMPLATE *tt, const ASN1_PCTX *pctx) -{ - int flags; - size_t i; - const char *sname, *fname; - flags = tt->flags; - if (pctx->flags & ASN1_PCTX_FLAGS_SHOW_FIELD_STRUCT_NAME) - sname = ASN1_ITEM_ptr(tt->item)->sname; - else - sname = NULL; - if (pctx->flags & ASN1_PCTX_FLAGS_NO_FIELD_NAME) - fname = NULL; - else - fname = tt->field_name; - if (flags & ASN1_TFLG_SK_MASK) { - const char *tname; - ASN1_VALUE *skitem; - STACK_OF(ASN1_VALUE) *stack; - - /* SET OF, SEQUENCE OF */ - if (fname) { - if (pctx->flags & ASN1_PCTX_FLAGS_SHOW_SSOF) { - if (flags & ASN1_TFLG_SET_OF) - tname = "SET"; - else - tname = "SEQUENCE"; - if (BIO_printf(out, "%*s%s OF %s {\n", - indent, "", tname, tt->field_name) <= 0) - return 0; - } else if (BIO_printf(out, "%*s%s:\n", indent, "", fname) <= 0) - return 0; - } - stack = (STACK_OF(ASN1_VALUE) *)*fld; - for (i = 0; i < sk_ASN1_VALUE_num(stack); i++) { - if ((i > 0) && (BIO_puts(out, "\n") <= 0)) - return 0; - - skitem = sk_ASN1_VALUE_value(stack, i); - if (!asn1_item_print_ctx(out, &skitem, indent + 2, - ASN1_ITEM_ptr(tt->item), NULL, NULL, 1, - pctx)) - return 0; - } - if (!i && BIO_printf(out, "%*s\n", indent + 2, "") <= 0) - return 0; - if (pctx->flags & ASN1_PCTX_FLAGS_SHOW_SEQUENCE) { - if (BIO_printf(out, "%*s}\n", indent, "") <= 0) - return 0; - } - return 1; - } - return asn1_item_print_ctx(out, fld, indent, ASN1_ITEM_ptr(tt->item), - fname, sname, 0, pctx); -} - -static int asn1_print_fsname(BIO *out, int indent, - const char *fname, const char *sname, - const ASN1_PCTX *pctx) -{ - static char spaces[] = " "; - const int nspaces = sizeof(spaces) - 1; - -#if 0 - if (!sname && !fname) - return 1; -#endif - - while (indent > nspaces) { - if (BIO_write(out, spaces, nspaces) != nspaces) - return 0; - indent -= nspaces; - } - if (BIO_write(out, spaces, indent) != indent) - return 0; - if (pctx->flags & ASN1_PCTX_FLAGS_NO_STRUCT_NAME) - sname = NULL; - if (pctx->flags & ASN1_PCTX_FLAGS_NO_FIELD_NAME) - fname = NULL; - if (!sname && !fname) - return 1; - if (fname) { - if (BIO_puts(out, fname) <= 0) - return 0; - } - if (sname) { - if (fname) { - if (BIO_printf(out, " (%s)", sname) <= 0) - return 0; - } else { - if (BIO_puts(out, sname) <= 0) - return 0; - } - } - if (BIO_write(out, ": ", 2) != 2) - return 0; - return 1; -} - -static int asn1_print_boolean_ctx(BIO *out, int boolval, - const ASN1_PCTX *pctx) -{ - const char *str; - switch (boolval) { - case -1: - str = "BOOL ABSENT"; - break; - - case 0: - str = "FALSE"; - break; - - default: - str = "TRUE"; - break; - - } - - if (BIO_puts(out, str) <= 0) - return 0; - return 1; - -} - -static int asn1_print_integer_ctx(BIO *out, ASN1_INTEGER *str, - const ASN1_PCTX *pctx) -{ - BIGNUM *bn = NULL; - char *s = NULL; - int ret = 1; - - bn = ASN1_INTEGER_to_BN(str, NULL); - if (bn == NULL) { - return 0; - } - s = BN_bn2dec(bn); - BN_free(bn); - if (s == NULL) { - return 0; - } - - if (BIO_puts(out, s) <= 0) { - ret = 0; - } - OPENSSL_free(s); - return ret; -} - -static int asn1_print_oid_ctx(BIO *out, const ASN1_OBJECT *oid, - const ASN1_PCTX *pctx) -{ - char objbuf[80]; - const char *ln; - ln = OBJ_nid2ln(OBJ_obj2nid(oid)); - if (!ln) - ln = ""; - OBJ_obj2txt(objbuf, sizeof objbuf, oid, 1); - if (BIO_printf(out, "%s (%s)", ln, objbuf) <= 0) - return 0; - return 1; -} - -static int asn1_print_obstring_ctx(BIO *out, ASN1_STRING *str, int indent, - const ASN1_PCTX *pctx) -{ - if (str->type == V_ASN1_BIT_STRING) { - if (BIO_printf(out, " (%ld unused bits)\n", str->flags & 0x7) <= 0) - return 0; - } else if (BIO_puts(out, "\n") <= 0) - return 0; - if (str->length > 0 - && !BIO_hexdump(out, str->data, str->length, indent + 2)) { - return 0; - } - return 1; -} - -static int asn1_primitive_print(BIO *out, ASN1_VALUE **fld, - const ASN1_ITEM *it, int indent, - const char *fname, const char *sname, - const ASN1_PCTX *pctx) -{ - long utype; - ASN1_STRING *str; - int ret = 1, needlf = 1; - const char *pname; - const ASN1_PRIMITIVE_FUNCS *pf; - pf = it->funcs; - if (!asn1_print_fsname(out, indent, fname, sname, pctx)) - return 0; - if (pf && pf->prim_print) - return pf->prim_print(out, fld, it, indent, pctx); - str = (ASN1_STRING *)*fld; - if (it->itype == ASN1_ITYPE_MSTRING) - utype = str->type & ~V_ASN1_NEG; - else - utype = it->utype; - if (utype == V_ASN1_ANY) { - ASN1_TYPE *atype = (ASN1_TYPE *)*fld; - utype = atype->type; - fld = &atype->value.asn1_value; - str = (ASN1_STRING *)*fld; - if (pctx->flags & ASN1_PCTX_FLAGS_NO_ANY_TYPE) - pname = NULL; - else - pname = ASN1_tag2str(utype); - } else { - if (pctx->flags & ASN1_PCTX_FLAGS_SHOW_TYPE) - pname = ASN1_tag2str(utype); - else - pname = NULL; - } - - if (utype == V_ASN1_NULL) { - if (BIO_puts(out, "NULL\n") <= 0) - return 0; - return 1; - } - - if (pname) { - if (BIO_puts(out, pname) <= 0) - return 0; - if (BIO_puts(out, ":") <= 0) - return 0; - } - - switch (utype) { - case V_ASN1_BOOLEAN: - { - int boolval = *(int *)fld; - if (boolval == -1) - boolval = it->size; - ret = asn1_print_boolean_ctx(out, boolval, pctx); - } - break; - - case V_ASN1_INTEGER: - case V_ASN1_ENUMERATED: - ret = asn1_print_integer_ctx(out, str, pctx); - break; - - case V_ASN1_UTCTIME: - ret = ASN1_UTCTIME_print(out, str); - break; - - case V_ASN1_GENERALIZEDTIME: - ret = ASN1_GENERALIZEDTIME_print(out, str); - break; - - case V_ASN1_OBJECT: - ret = asn1_print_oid_ctx(out, (const ASN1_OBJECT *)*fld, pctx); - break; - - case V_ASN1_OCTET_STRING: - case V_ASN1_BIT_STRING: - ret = asn1_print_obstring_ctx(out, str, indent, pctx); - needlf = 0; - break; - - case V_ASN1_SEQUENCE: - case V_ASN1_SET: - case V_ASN1_OTHER: - if (BIO_puts(out, "\n") <= 0) - return 0; - if (ASN1_parse_dump(out, str->data, str->length, indent, 0) <= 0) - ret = 0; - needlf = 0; - break; - - default: - ret = ASN1_STRING_print_ex(out, str, pctx->str_flags); - - } - if (!ret) - return 0; - if (needlf && BIO_puts(out, "\n") <= 0) - return 0; - return 1; -} diff --git a/Sources/BoringSSL/crypto/asn1/tasn_typ.c b/Sources/BoringSSL/crypto/asn1/tasn_typ.c index daf02eae9..7c5bfd5ec 100644 --- a/Sources/BoringSSL/crypto/asn1/tasn_typ.c +++ b/Sources/BoringSSL/crypto/asn1/tasn_typ.c @@ -87,58 +87,45 @@ IMPLEMENT_ASN1_STRING_FUNCTIONS(ASN1_VISIBLESTRING) IMPLEMENT_ASN1_STRING_FUNCTIONS(ASN1_UNIVERSALSTRING) IMPLEMENT_ASN1_STRING_FUNCTIONS(ASN1_BMPSTRING) -IMPLEMENT_ASN1_TYPE(ASN1_NULL); -IMPLEMENT_ASN1_FUNCTIONS(ASN1_NULL); +IMPLEMENT_ASN1_TYPE(ASN1_NULL) +IMPLEMENT_ASN1_FUNCTIONS(ASN1_NULL) -IMPLEMENT_ASN1_TYPE(ASN1_OBJECT); +IMPLEMENT_ASN1_TYPE(ASN1_OBJECT) -IMPLEMENT_ASN1_TYPE(ASN1_ANY); +IMPLEMENT_ASN1_TYPE(ASN1_ANY) -/* - * Just swallow an ASN1_SEQUENCE in an ASN1_STRING - */ ; -IMPLEMENT_ASN1_TYPE(ASN1_SEQUENCE); +/* Just swallow an ASN1_SEQUENCE in an ASN1_STRING */ +IMPLEMENT_ASN1_TYPE(ASN1_SEQUENCE) -IMPLEMENT_ASN1_FUNCTIONS_fname(ASN1_TYPE, ASN1_ANY, ASN1_TYPE); +IMPLEMENT_ASN1_FUNCTIONS_fname(ASN1_TYPE, ASN1_ANY, ASN1_TYPE) -/* - * Multistring types - */ ; +/* Multistring types */ -IMPLEMENT_ASN1_MSTRING(ASN1_PRINTABLE, B_ASN1_PRINTABLE); -IMPLEMENT_ASN1_FUNCTIONS_name(ASN1_STRING, ASN1_PRINTABLE); +IMPLEMENT_ASN1_MSTRING(ASN1_PRINTABLE, B_ASN1_PRINTABLE) +IMPLEMENT_ASN1_FUNCTIONS_name(ASN1_STRING, ASN1_PRINTABLE) -IMPLEMENT_ASN1_MSTRING(DISPLAYTEXT, B_ASN1_DISPLAYTEXT); -IMPLEMENT_ASN1_FUNCTIONS_name(ASN1_STRING, DISPLAYTEXT); +IMPLEMENT_ASN1_MSTRING(DISPLAYTEXT, B_ASN1_DISPLAYTEXT) +IMPLEMENT_ASN1_FUNCTIONS_name(ASN1_STRING, DISPLAYTEXT) -IMPLEMENT_ASN1_MSTRING(DIRECTORYSTRING, B_ASN1_DIRECTORYSTRING); -IMPLEMENT_ASN1_FUNCTIONS_name(ASN1_STRING, DIRECTORYSTRING); +IMPLEMENT_ASN1_MSTRING(DIRECTORYSTRING, B_ASN1_DIRECTORYSTRING) +IMPLEMENT_ASN1_FUNCTIONS_name(ASN1_STRING, DIRECTORYSTRING) -/* - * Three separate BOOLEAN type: normal, DEFAULT TRUE and DEFAULT FALSE - */ ; -IMPLEMENT_ASN1_TYPE_ex(ASN1_BOOLEAN, ASN1_BOOLEAN, -1); -IMPLEMENT_ASN1_TYPE_ex(ASN1_TBOOLEAN, ASN1_BOOLEAN, 1); -IMPLEMENT_ASN1_TYPE_ex(ASN1_FBOOLEAN, ASN1_BOOLEAN, 0); +/* Three separate BOOLEAN type: normal, DEFAULT TRUE and DEFAULT FALSE */ +IMPLEMENT_ASN1_TYPE_ex(ASN1_BOOLEAN, ASN1_BOOLEAN, -1) +IMPLEMENT_ASN1_TYPE_ex(ASN1_TBOOLEAN, ASN1_BOOLEAN, 1) +IMPLEMENT_ASN1_TYPE_ex(ASN1_FBOOLEAN, ASN1_BOOLEAN, 0) -/* - * Special, OCTET STRING with indefinite length constructed support - */ ; +/* Special, OCTET STRING with indefinite length constructed support */ -IMPLEMENT_ASN1_TYPE_ex(ASN1_OCTET_STRING_NDEF, ASN1_OCTET_STRING, -ASN1_TFLG_NDEF); +IMPLEMENT_ASN1_TYPE_ex(ASN1_OCTET_STRING_NDEF, ASN1_OCTET_STRING, ASN1_TFLG_NDEF) ASN1_ITEM_TEMPLATE(ASN1_SEQUENCE_ANY) = - ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, ASN1_SEQUENCE_ANY, - ASN1_ANY); -ASN1_ITEM_TEMPLATE_END(ASN1_SEQUENCE_ANY); - -ASN1_ITEM_TEMPLATE(ASN1_SET_ANY) = ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SET_OF, 0, - ASN1_SET_ANY, - ASN1_ANY); -ASN1_ITEM_TEMPLATE_END(ASN1_SET_ANY); - -IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(ASN1_SEQUENCE_ANY, -ASN1_SEQUENCE_ANY, ASN1_SEQUENCE_ANY); -IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(ASN1_SEQUENCE_ANY, ASN1_SET_ANY, -ASN1_SET_ANY); + ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, ASN1_SEQUENCE_ANY, ASN1_ANY) +ASN1_ITEM_TEMPLATE_END(ASN1_SEQUENCE_ANY) + +ASN1_ITEM_TEMPLATE(ASN1_SET_ANY) = + ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SET_OF, 0, ASN1_SET_ANY, ASN1_ANY) +ASN1_ITEM_TEMPLATE_END(ASN1_SET_ANY) + +IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(ASN1_SEQUENCE_ANY, ASN1_SEQUENCE_ANY, ASN1_SEQUENCE_ANY) +IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(ASN1_SEQUENCE_ANY, ASN1_SET_ANY, ASN1_SET_ANY) diff --git a/Sources/BoringSSL/crypto/asn1/tasn_utl.c b/Sources/BoringSSL/crypto/asn1/tasn_utl.c index 960cdbb7a..a7516f6eb 100644 --- a/Sources/BoringSSL/crypto/asn1/tasn_utl.c +++ b/Sources/BoringSSL/crypto/asn1/tasn_utl.c @@ -56,6 +56,7 @@ #include +#include #include #include @@ -70,7 +71,7 @@ /* Utility functions for manipulating fields and offsets */ /* Add 'offset' to 'addr' */ -#define offset2ptr(addr, offset) (void *)(((char *) addr) + offset) +#define offset2ptr(addr, offset) (void *)(((char *)(addr)) + (offset)) /* Given an ASN1_ITEM CHOICE type return the selector value */ int asn1_get_choice_selector(ASN1_VALUE **pval, const ASN1_ITEM *it) { @@ -134,6 +135,8 @@ void asn1_enc_init(ASN1_VALUE **pval, const ASN1_ITEM *it) { if (enc) { enc->enc = NULL; enc->len = 0; + enc->alias_only = 0; + enc->alias_only_on_next_parse = 0; enc->modified = 1; } } @@ -142,11 +145,13 @@ void asn1_enc_free(ASN1_VALUE **pval, const ASN1_ITEM *it) { ASN1_ENCODING *enc; enc = asn1_get_enc_ptr(pval, it); if (enc) { - if (enc->enc) { + if (enc->enc && !enc->alias_only) { OPENSSL_free(enc->enc); } enc->enc = NULL; enc->len = 0; + enc->alias_only = 0; + enc->alias_only_on_next_parse = 0; enc->modified = 1; } } @@ -159,14 +164,23 @@ int asn1_enc_save(ASN1_VALUE **pval, const unsigned char *in, int inlen, return 1; } - if (enc->enc) { + if (!enc->alias_only) { OPENSSL_free(enc->enc); } - enc->enc = OPENSSL_malloc(inlen); - if (!enc->enc) { - return 0; + + enc->alias_only = enc->alias_only_on_next_parse; + enc->alias_only_on_next_parse = 0; + + if (enc->alias_only) { + enc->enc = (uint8_t *) in; + } else { + enc->enc = OPENSSL_malloc(inlen); + if (!enc->enc) { + return 0; + } + OPENSSL_memcpy(enc->enc, in, inlen); } - memcpy(enc->enc, in, inlen); + enc->len = inlen; enc->modified = 0; @@ -181,7 +195,7 @@ int asn1_enc_restore(int *len, unsigned char **out, ASN1_VALUE **pval, return 0; } if (out) { - memcpy(*out, enc->enc, enc->len); + OPENSSL_memcpy(*out, enc->enc, enc->len); *out += enc->len; } if (len) { @@ -222,7 +236,7 @@ const ASN1_TEMPLATE *asn1_do_adb(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt, sfld = offset2ptr(*pval, adb->offset); /* Check if NULL */ - if (!sfld) { + if (*sfld == NULL) { if (!adb->null_tt) { goto err; } diff --git a/Sources/BoringSSL/crypto/time_support.c b/Sources/BoringSSL/crypto/asn1/time_support.c similarity index 99% rename from Sources/BoringSSL/crypto/time_support.c rename to Sources/BoringSSL/crypto/asn1/time_support.c index ae0f49635..194dc3a79 100644 --- a/Sources/BoringSSL/crypto/time_support.c +++ b/Sources/BoringSSL/crypto/asn1/time_support.c @@ -59,7 +59,7 @@ #define _POSIX_C_SOURCE 201410L /* for gmtime_r */ #endif -#include +#include "asn1_locl.h" #include diff --git a/Sources/BoringSSL/crypto/asn1/x_long.c b/Sources/BoringSSL/crypto/asn1/x_long.c index bc4d27518..b53127a30 100644 --- a/Sources/BoringSSL/crypto/asn1/x_long.c +++ b/Sources/BoringSSL/crypto/asn1/x_long.c @@ -63,6 +63,9 @@ #include #include +#include "../internal.h" + + /* * Custom primitive type for long handling. This converts between an * ASN1_INTEGER and a long directly. @@ -117,7 +120,7 @@ static int long_i2c(ASN1_VALUE **pval, unsigned char *cont, int *putype, char *cp = (char *)pval; /* use memcpy, because we may not be long aligned */ - memcpy(<mp, cp, sizeof(long)); + OPENSSL_memcpy(<mp, cp, sizeof(long)); if (ltmp == it->size) return -1; @@ -186,7 +189,7 @@ static int long_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len, OPENSSL_PUT_ERROR(ASN1, ASN1_R_INTEGER_TOO_LARGE_FOR_LONG); return 0; } - memcpy(cp, <mp, sizeof(long)); + OPENSSL_memcpy(cp, <mp, sizeof(long)); return 1; } diff --git a/Sources/BoringSSL/crypto/base64/base64.c b/Sources/BoringSSL/crypto/base64/base64.c index 4822fb89e..7afadf746 100644 --- a/Sources/BoringSSL/crypto/base64/base64.c +++ b/Sources/BoringSSL/crypto/base64/base64.c @@ -60,118 +60,125 @@ #include #include +#include + +#include "../internal.h" + + +/* Encoding. */ static const unsigned char data_bin2ascii[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; #define conv_bin2ascii(a) (data_bin2ascii[(a) & 0x3f]) -/* 64 char lines - * pad input with 0 - * left over chars are set to = - * 1 byte => xx== - * 2 bytes => xxx= - * 3 bytes => xxxx - */ -#define BIN_PER_LINE (64/4*3) -#define CHUNKS_PER_LINE (64/4) -#define CHAR_PER_LINE (64+1) - -/* 0xF0 is a EOLN - * 0xF1 is ignore but next needs to be 0xF0 (for \r\n processing). - * 0xF2 is EOF - * 0xE0 is ignore at start of line. - * 0xFF is error */ - -#define B64_EOLN 0xF0 -#define B64_CR 0xF1 -#define B64_EOF 0xF2 -#define B64_WS 0xE0 -#define B64_ERROR 0xFF -#define B64_NOT_BASE64(a) (((a) | 0x13) == 0xF3) - -static const uint8_t data_ascii2bin[128] = { - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0xF0, 0xFF, - 0xFF, 0xF1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3E, 0xFF, 0xF2, 0xFF, 0x3F, - 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, - 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, - 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, - 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, - 0x31, 0x32, 0x33, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -}; +OPENSSL_COMPILE_ASSERT(sizeof(((EVP_ENCODE_CTX *)(NULL))->data) % 3 == 0, + data_length_must_be_multiple_of_base64_chunk_size); -static uint8_t conv_ascii2bin(uint8_t a) { - if (a >= 128) { - return 0xFF; +int EVP_EncodedLength(size_t *out_len, size_t len) { + if (len + 2 < len) { + return 0; } - return data_ascii2bin[a]; + len += 2; + len /= 3; + + if (((len << 2) >> 2) != len) { + return 0; + } + len <<= 2; + + if (len + 1 < len) { + return 0; + } + len++; + + *out_len = len; + return 1; } void EVP_EncodeInit(EVP_ENCODE_CTX *ctx) { - ctx->length = 48; - ctx->num = 0; - ctx->line_num = 0; + OPENSSL_memset(ctx, 0, sizeof(EVP_ENCODE_CTX)); } void EVP_EncodeUpdate(EVP_ENCODE_CTX *ctx, uint8_t *out, int *out_len, const uint8_t *in, size_t in_len) { - unsigned i, j; - unsigned total = 0; + size_t total = 0; *out_len = 0; if (in_len == 0) { return; } - assert(ctx->length <= sizeof(ctx->enc_data)); + assert(ctx->data_used < sizeof(ctx->data)); - if (ctx->num + in_len < ctx->length) { - memcpy(&ctx->enc_data[ctx->num], in, in_len); - ctx->num += in_len; + if (sizeof(ctx->data) - ctx->data_used > in_len) { + OPENSSL_memcpy(&ctx->data[ctx->data_used], in, in_len); + ctx->data_used += (unsigned)in_len; return; } - if (ctx->num != 0) { - i = ctx->length - ctx->num; - memcpy(&ctx->enc_data[ctx->num], in, i); - in += i; - in_len -= i; - j = EVP_EncodeBlock(out, ctx->enc_data, ctx->length); - ctx->num = 0; - out += j; + + if (ctx->data_used != 0) { + const size_t todo = sizeof(ctx->data) - ctx->data_used; + OPENSSL_memcpy(&ctx->data[ctx->data_used], in, todo); + in += todo; + in_len -= todo; + + size_t encoded = EVP_EncodeBlock(out, ctx->data, sizeof(ctx->data)); + ctx->data_used = 0; + + out += encoded; *(out++) = '\n'; *out = '\0'; - total = j + 1; + + total = encoded + 1; } - while (in_len >= ctx->length) { - j = EVP_EncodeBlock(out, in, ctx->length); - in += ctx->length; - in_len -= ctx->length; - out += j; + + while (in_len >= sizeof(ctx->data)) { + size_t encoded = EVP_EncodeBlock(out, in, sizeof(ctx->data)); + in += sizeof(ctx->data); + in_len -= sizeof(ctx->data); + + out += encoded; *(out++) = '\n'; *out = '\0'; - total += j + 1; + + if (total + encoded + 1 < total) { + *out_len = 0; + return; + } + + total += encoded + 1; } + if (in_len != 0) { - memcpy(&ctx->enc_data[0], in, in_len); + OPENSSL_memcpy(ctx->data, in, in_len); + } + + ctx->data_used = (unsigned)in_len; + + if (total > INT_MAX) { + /* We cannot signal an error, but we can at least avoid making *out_len + * negative. */ + total = 0; } - ctx->num = in_len; - *out_len = total; + *out_len = (int)total; } void EVP_EncodeFinal(EVP_ENCODE_CTX *ctx, uint8_t *out, int *out_len) { - unsigned ret = 0; - - if (ctx->num != 0) { - ret = EVP_EncodeBlock(out, ctx->enc_data, ctx->num); - out[ret++] = '\n'; - out[ret] = '\0'; - ctx->num = 0; + if (ctx->data_used == 0) { + *out_len = 0; + return; } - *out_len = ret; + + size_t encoded = EVP_EncodeBlock(out, ctx->data, ctx->data_used); + out[encoded++] = '\n'; + out[encoded] = '\0'; + ctx->data_used = 0; + + /* ctx->data_used is bounded by sizeof(ctx->data), so this does not + * overflow. */ + assert(encoded <= INT_MAX); + *out_len = (int)encoded; } size_t EVP_EncodeBlock(uint8_t *dst, const uint8_t *src, size_t src_len) { @@ -206,246 +213,223 @@ size_t EVP_EncodeBlock(uint8_t *dst, const uint8_t *src, size_t src_len) { return ret; } + +/* Decoding. */ + int EVP_DecodedLength(size_t *out_len, size_t len) { if (len % 4 != 0) { return 0; } + *out_len = (len / 4) * 3; return 1; } -int EVP_DecodeBase64(uint8_t *out, size_t *out_len, size_t max_out, - const uint8_t *in, size_t in_len) { - uint8_t a, b, c, d; - size_t pad_len = 0, len = 0, max_len, i; - uint32_t l; +void EVP_DecodeInit(EVP_ENCODE_CTX *ctx) { + OPENSSL_memset(ctx, 0, sizeof(EVP_ENCODE_CTX)); +} - if (!EVP_DecodedLength(&max_len, in_len) || max_out < max_len) { +/* kBase64ASCIIToBinData maps characters (c < 128) to their base64 value, or + * else 0xff if they are invalid. As a special case, the padding character + * ('=') is mapped to zero. */ +static const uint8_t kBase64ASCIIToBinData[128] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0xff, 0xff, + 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, + 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, + 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, + 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, + 0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, +}; + +static uint8_t base64_ascii_to_bin(uint8_t a) { + if (a >= 128) { + return 0xFF; + } + + return kBase64ASCIIToBinData[a]; +} + +/* base64_decode_quad decodes a single “quad” (i.e. four characters) of base64 + * data and writes up to three bytes to |out|. It sets |*out_num_bytes| to the + * number of bytes written, which will be less than three if the quad ended + * with padding. It returns one on success or zero on error. */ +static int base64_decode_quad(uint8_t *out, size_t *out_num_bytes, + const uint8_t *in) { + const uint8_t a = base64_ascii_to_bin(in[0]); + const uint8_t b = base64_ascii_to_bin(in[1]); + const uint8_t c = base64_ascii_to_bin(in[2]); + const uint8_t d = base64_ascii_to_bin(in[3]); + if (a == 0xff || b == 0xff || c == 0xff || d == 0xff) { return 0; } - for (i = 0; i < in_len; i += 4) { - a = conv_ascii2bin(*(in++)); - b = conv_ascii2bin(*(in++)); - if (i + 4 == in_len && in[1] == '=') { - if (in[0] == '=') { - pad_len = 2; - } else { - pad_len = 1; - } - } - if (pad_len < 2) { - c = conv_ascii2bin(*(in++)); - } else { - c = 0; - } - if (pad_len < 1) { - d = conv_ascii2bin(*(in++)); - } else { - d = 0; - } - if ((a & 0x80) || (b & 0x80) || (c & 0x80) || (d & 0x80)) { + const uint32_t v = ((uint32_t)a) << 18 | ((uint32_t)b) << 12 | + ((uint32_t)c) << 6 | (uint32_t)d; + + const unsigned padding_pattern = (in[0] == '=') << 3 | + (in[1] == '=') << 2 | + (in[2] == '=') << 1 | + (in[3] == '='); + + switch (padding_pattern) { + case 0: + /* The common case of no padding. */ + *out_num_bytes = 3; + out[0] = v >> 16; + out[1] = v >> 8; + out[2] = v; + break; + + case 1: /* xxx= */ + *out_num_bytes = 2; + out[0] = v >> 16; + out[1] = v >> 8; + break; + + case 3: /* xx== */ + *out_num_bytes = 1; + out[0] = v >> 16; + break; + + default: return 0; - } - l = ((((uint32_t)a) << 18L) | (((uint32_t)b) << 12L) | - (((uint32_t)c) << 6L) | (((uint32_t)d))); - *(out++) = (uint8_t)(l >> 16L) & 0xff; - if (pad_len < 2) { - *(out++) = (uint8_t)(l >> 8L) & 0xff; - } - if (pad_len < 1) { - *(out++) = (uint8_t)(l) & 0xff; - } - len += 3 - pad_len; } - *out_len = len; - return 1; -} -void EVP_DecodeInit(EVP_ENCODE_CTX *ctx) { - ctx->length = 30; - ctx->num = 0; - ctx->line_num = 0; - ctx->expect_nl = 0; + return 1; } int EVP_DecodeUpdate(EVP_ENCODE_CTX *ctx, uint8_t *out, int *out_len, const uint8_t *in, size_t in_len) { - int seof = -1, eof = 0, rv = -1, v, tmp, exp_nl; - uint8_t *d; - unsigned i, n, ln, ret = 0; - - n = ctx->num; - d = ctx->enc_data; - ln = ctx->line_num; - exp_nl = ctx->expect_nl; - - /* last line of input. */ - if (in_len == 0 || (n == 0 && conv_ascii2bin(in[0]) == B64_EOF)) { - rv = 0; - goto end; + *out_len = 0; + + if (ctx->error_encountered) { + return -1; } - /* We parse the input data */ + size_t bytes_out = 0, i; for (i = 0; i < in_len; i++) { - /* If the current line is > 80 characters, scream alot */ - if (ln >= 80) { - rv = -1; - goto end; + const char c = in[i]; + switch (c) { + case ' ': + case '\t': + case '\r': + case '\n': + continue; } - /* Get char and put it into the buffer */ - tmp = *(in++); - v = conv_ascii2bin(tmp); - /* only save the good data :-) */ - if (!B64_NOT_BASE64(v)) { - assert(n < sizeof(ctx->enc_data)); - d[n++] = tmp; - ln++; - } else if (v == B64_ERROR) { - rv = -1; - goto end; + if (base64_ascii_to_bin(c) == 0xff || ctx->eof_seen) { + ctx->error_encountered = 1; + return -1; } - /* have we seen a '=' which is 'definitly' the last - * input line. seof will point to the character that - * holds it. and eof will hold how many characters to - * chop off. */ - if (tmp == '=') { - if (seof == -1) { - seof = n; - } - eof++; - if (eof > 2) { - /* There are, at most, two equals signs at the end of base64 data. */ - rv = -1; - goto end; + ctx->data[ctx->data_used++] = c; + if (ctx->data_used == 4) { + size_t num_bytes_resulting; + if (!base64_decode_quad(out, &num_bytes_resulting, ctx->data)) { + ctx->error_encountered = 1; + return -1; } - } - if (v == B64_CR) { - ln = 0; - if (exp_nl) { - continue; - } - } + ctx->data_used = 0; + bytes_out += num_bytes_resulting; + out += num_bytes_resulting; - /* eoln */ - if (v == B64_EOLN) { - ln = 0; - if (exp_nl) { - exp_nl = 0; - continue; + if (num_bytes_resulting < 3) { + ctx->eof_seen = 1; } } - exp_nl = 0; - - /* If we are at the end of input and it looks like a - * line, process it. */ - if ((i + 1) == in_len && (((n & 3) == 0) || eof)) { - v = B64_EOF; - /* In case things were given us in really small - records (so two '=' were given in separate - updates), eof may contain the incorrect number - of ending bytes to skip, so let's redo the count */ - eof = 0; - if (d[n - 1] == '=') { - eof++; - } - if (d[n - 2] == '=') { - eof++; - } - /* There will never be more than two '=' */ - } + } - if ((v == B64_EOF && (n & 3) == 0) || n >= 64) { - /* This is needed to work correctly on 64 byte input - * lines. We process the line and then need to - * accept the '\n' */ - if (v != B64_EOF && n >= 64) { - exp_nl = 1; - } - if (n > 0) { - /* TODO(davidben): Switch this to EVP_DecodeBase64. */ - v = EVP_DecodeBlock(out, d, n); - n = 0; - if (v < 0) { - rv = 0; - goto end; - } - if (eof > v) { - rv = -1; - goto end; - } - ret += (v - eof); - } else { - eof = 1; - v = 0; - } + if (bytes_out > INT_MAX) { + ctx->error_encountered = 1; + *out_len = 0; + return -1; + } + *out_len = (int)bytes_out; - /* This is the case where we have had a short - * but valid input line */ - if (v < (int)ctx->length && eof) { - rv = 0; - goto end; - } else { - ctx->length = v; - } + if (ctx->eof_seen) { + return 0; + } - if (seof >= 0) { - rv = 0; - goto end; - } - out += v; - } + return 1; +} + +int EVP_DecodeFinal(EVP_ENCODE_CTX *ctx, uint8_t *out, int *out_len) { + *out_len = 0; + if (ctx->error_encountered || ctx->data_used != 0) { + return -1; } - rv = 1; - -end: - *out_len = ret; - ctx->num = n; - ctx->line_num = ln; - ctx->expect_nl = exp_nl; - return rv; + + return 1; } -int EVP_DecodeFinal(EVP_ENCODE_CTX *ctx, uint8_t *out, int *outl) { - int i; +int EVP_DecodeBase64(uint8_t *out, size_t *out_len, size_t max_out, + const uint8_t *in, size_t in_len) { + *out_len = 0; - *outl = 0; - if (ctx->num != 0) { - /* TODO(davidben): Switch this to EVP_DecodeBase64. */ - i = EVP_DecodeBlock(out, ctx->enc_data, ctx->num); - if (i < 0) { - return -1; + if (in_len % 4 != 0) { + return 0; + } + + size_t max_len; + if (!EVP_DecodedLength(&max_len, in_len) || + max_out < max_len) { + return 0; + } + + size_t i, bytes_out = 0; + for (i = 0; i < in_len; i += 4) { + size_t num_bytes_resulting; + + if (!base64_decode_quad(out, &num_bytes_resulting, &in[i])) { + return 0; + } + + bytes_out += num_bytes_resulting; + out += num_bytes_resulting; + if (num_bytes_resulting != 3 && i != in_len - 4) { + return 0; } - ctx->num = 0; - *outl = i; - return 1; - } else { - return 1; } + + *out_len = bytes_out; + return 1; } int EVP_DecodeBlock(uint8_t *dst, const uint8_t *src, size_t src_len) { - size_t dst_len; + /* Trim spaces and tabs from the beginning of the input. */ + while (src_len > 0) { + if (src[0] != ' ' && src[0] != '\t') { + break; + } - /* trim white space from the start of the line. */ - while (conv_ascii2bin(*src) == B64_WS && src_len > 0) { src++; src_len--; } - /* strip off stuff at the end of the line - * ascii2bin values B64_WS, B64_EOLN, B64_EOLN and B64_EOF */ - while (src_len > 3 && B64_NOT_BASE64(conv_ascii2bin(src[src_len - 1]))) { - src_len--; - } + /* Trim newlines, spaces and tabs from the end of the line. */ + while (src_len > 0) { + switch (src[src_len-1]) { + case ' ': + case '\t': + case '\r': + case '\n': + src_len--; + continue; + } - if (!EVP_DecodedLength(&dst_len, src_len) || dst_len > INT_MAX) { - return -1; + break; } - if (!EVP_DecodeBase64(dst, &dst_len, dst_len, src, src_len)) { + + size_t dst_len; + if (!EVP_DecodedLength(&dst_len, src_len) || + dst_len > INT_MAX || + !EVP_DecodeBase64(dst, &dst_len, dst_len, src, src_len)) { return -1; } @@ -456,23 +440,5 @@ int EVP_DecodeBlock(uint8_t *dst, const uint8_t *src, size_t src_len) { } assert(dst_len <= INT_MAX); - return dst_len; -} - -int EVP_EncodedLength(size_t *out_len, size_t len) { - if (len + 2 < len) { - return 0; - } - len += 2; - len /= 3; - if (((len << 2) >> 2) != len) { - return 0; - } - len <<= 2; - if (len + 1 < len) { - return 0; - } - len++; - *out_len = len; - return 1; + return (int)dst_len; } diff --git a/Sources/BoringSSL/crypto/bio/bio.c b/Sources/BoringSSL/crypto/bio/bio.c index 7a1a9e3b9..5cab843b5 100644 --- a/Sources/BoringSSL/crypto/bio/bio.c +++ b/Sources/BoringSSL/crypto/bio/bio.c @@ -68,25 +68,6 @@ #include "../internal.h" -/* BIO_set initialises a BIO structure to have the given type and sets the - * reference count to one. It returns one on success or zero on error. */ -static int bio_set(BIO *bio, const BIO_METHOD *method) { - /* This function can be called with a stack allocated |BIO| so we have to - * assume that the contents of |BIO| are arbitary. This also means that it'll - * leak memory if you call |BIO_set| twice on the same BIO. */ - memset(bio, 0, sizeof(BIO)); - - bio->method = method; - bio->shutdown = 1; - bio->references = 1; - - if (method->create != NULL && !method->create(bio)) { - return 0; - } - - return 1; -} - BIO *BIO_new(const BIO_METHOD *method) { BIO *ret = OPENSSL_malloc(sizeof(BIO)); if (ret == NULL) { @@ -94,9 +75,14 @@ BIO *BIO_new(const BIO_METHOD *method) { return NULL; } - if (!bio_set(ret, method)) { + OPENSSL_memset(ret, 0, sizeof(BIO)); + ret->method = method; + ret->shutdown = 1; + ret->references = 1; + + if (method->create != NULL && !method->create(ret)) { OPENSSL_free(ret); - ret = NULL; + return NULL; } return ret; @@ -128,9 +114,9 @@ int BIO_free(BIO *bio) { return 1; } -BIO *BIO_up_ref(BIO *bio) { +int BIO_up_ref(BIO *bio) { CRYPTO_refcount_inc(&bio->references); - return bio; + return 1; } void BIO_vfree(BIO *bio) { @@ -257,6 +243,10 @@ int BIO_reset(BIO *bio) { return BIO_ctrl(bio, BIO_CTRL_RESET, 0, NULL); } +int BIO_eof(BIO *bio) { + return BIO_ctrl(bio, BIO_CTRL_EOF, 0, NULL); +} + void BIO_set_flags(BIO *bio, int flags) { bio->flags |= flags; } @@ -346,7 +336,13 @@ long BIO_callback_ctrl(BIO *bio, int cmd, bio_info_cb fp) { } size_t BIO_pending(const BIO *bio) { - return BIO_ctrl((BIO *) bio, BIO_CTRL_PENDING, 0, NULL); + const long r = BIO_ctrl((BIO *) bio, BIO_CTRL_PENDING, 0, NULL); + assert(r >= 0); + + if (r < 0) { + return 0; + } + return r; } size_t BIO_ctrl_pending(const BIO *bio) { @@ -354,7 +350,13 @@ size_t BIO_ctrl_pending(const BIO *bio) { } size_t BIO_wpending(const BIO *bio) { - return BIO_ctrl((BIO *) bio, BIO_CTRL_WPENDING, 0, NULL); + const long r = BIO_ctrl((BIO *) bio, BIO_CTRL_WPENDING, 0, NULL); + assert(r >= 0); + + if (r < 0) { + return 0; + } + return r; } int BIO_set_close(BIO *bio, int close_flag) { @@ -458,12 +460,8 @@ static int print_bio(const char *str, size_t len, void *bio) { return BIO_write((BIO *)bio, str, len); } -void BIO_print_errors(BIO *bio) { - ERR_print_errors_cb(print_bio, bio); -} - void ERR_print_errors(BIO *bio) { - BIO_print_errors(bio); + ERR_print_errors_cb(print_bio, bio); } /* bio_read_all reads everything from |bio| and prepends |prefix| to it. On @@ -490,7 +488,7 @@ static int bio_read_all(BIO *bio, uint8_t **out, size_t *out_len, if (*out == NULL) { return 0; } - memcpy(*out, prefix, prefix_len); + OPENSSL_memcpy(*out, prefix, prefix_len); size_t done = prefix_len; for (;;) { @@ -597,7 +595,7 @@ int BIO_read_asn1(BIO *bio, uint8_t **out, size_t *out_len, size_t max_len) { if (*out == NULL) { return 0; } - memcpy(*out, header, header_len); + OPENSSL_memcpy(*out, header, header_len); if (BIO_read(bio, (*out) + header_len, len - header_len) != (int) (len - header_len)) { OPENSSL_free(*out); @@ -606,3 +604,9 @@ int BIO_read_asn1(BIO *bio, uint8_t **out, size_t *out_len, size_t max_len) { return 1; } + +void BIO_set_retry_special(BIO *bio) { + bio->flags |= BIO_FLAGS_READ | BIO_FLAGS_IO_SPECIAL; +} + +int BIO_set_write_buffer_size(BIO *bio, int buffer_size) { return 0; } diff --git a/Sources/BoringSSL/crypto/bio/bio_mem.c b/Sources/BoringSSL/crypto/bio/bio_mem.c index 6864f6f19..1cba8a89a 100644 --- a/Sources/BoringSSL/crypto/bio/bio_mem.c +++ b/Sources/BoringSSL/crypto/bio/bio_mem.c @@ -63,8 +63,10 @@ #include #include +#include "../internal.h" -BIO *BIO_new_mem_buf(void *buf, int len) { + +BIO *BIO_new_mem_buf(const void *buf, int len) { BIO *ret; BUF_MEM *b; const size_t size = len < 0 ? strlen((char *)buf) : (size_t)len; @@ -80,7 +82,8 @@ BIO *BIO_new_mem_buf(void *buf, int len) { } b = (BUF_MEM *)ret->ptr; - b->data = buf; + /* BIO_FLAGS_MEM_RDONLY ensures |b->data| is not written to. */ + b->data = (void *)buf; b->length = size; b->max = size; @@ -143,12 +146,12 @@ static int mem_read(BIO *bio, char *out, int outl) { } if (ret > 0) { - memcpy(out, b->data, ret); + OPENSSL_memcpy(out, b->data, ret); b->length -= ret; if (bio->flags & BIO_FLAGS_MEM_RDONLY) { b->data += ret; } else { - memmove(b->data, &b->data[ret], b->length); + OPENSSL_memmove(b->data, &b->data[ret], b->length); } } else if (b->length == 0) { ret = bio->num; @@ -179,17 +182,13 @@ static int mem_write(BIO *bio, const char *in, int inl) { if (BUF_MEM_grow_clean(b, blen + inl) != ((size_t) blen) + inl) { goto err; } - memcpy(&b->data[blen], in, inl); + OPENSSL_memcpy(&b->data[blen], in, inl); ret = inl; err: return ret; } -static int mem_puts(BIO *bp, const char *str) { - return mem_write(bp, str, strlen(str)); -} - static int mem_gets(BIO *bio, char *buf, int size) { int i, j; char *p; @@ -239,7 +238,7 @@ static long mem_ctrl(BIO *bio, int cmd, long num, void *ptr) { b->data -= b->max - b->length; b->length = b->max; } else { - memset(b->data, 0, b->max); + OPENSSL_memset(b->data, 0, b->max); b->length = 0; } } @@ -292,8 +291,12 @@ static long mem_ctrl(BIO *bio, int cmd, long num, void *ptr) { } static const BIO_METHOD mem_method = { - BIO_TYPE_MEM, "memory buffer", mem_write, mem_read, mem_puts, - mem_gets, mem_ctrl, mem_new, mem_free, NULL, }; + BIO_TYPE_MEM, "memory buffer", + mem_write, mem_read, + NULL /* puts */, mem_gets, + mem_ctrl, mem_new, + mem_free, NULL /* callback_ctrl */, +}; const BIO_METHOD *BIO_s_mem(void) { return &mem_method; } diff --git a/Sources/BoringSSL/crypto/bio/buffer.c b/Sources/BoringSSL/crypto/bio/buffer.c deleted file mode 100644 index 15574510c..000000000 --- a/Sources/BoringSSL/crypto/bio/buffer.c +++ /dev/null @@ -1,496 +0,0 @@ -/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) - * All rights reserved. - * - * This package is an SSL implementation written - * by Eric Young (eay@cryptsoft.com). - * The implementation was written so as to conform with Netscapes SSL. - * - * This library is free for commercial and non-commercial use as long as - * the following conditions are aheared to. The following conditions - * apply to all code found in this distribution, be it the RC4, RSA, - * lhash, DES, etc., code; not just the SSL code. The SSL documentation - * included with this distribution is covered by the same copyright terms - * except that the holder is Tim Hudson (tjh@cryptsoft.com). - * - * Copyright remains Eric Young's, and as such any Copyright notices in - * the code are not to be removed. - * If this package is used in a product, Eric Young should be given attribution - * as the author of the parts of the library used. - * This can be in the form of a textual message at program startup or - * in documentation (online or textual) provided with the package. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * "This product includes cryptographic software written by - * Eric Young (eay@cryptsoft.com)" - * The word 'cryptographic' can be left out if the rouines from the library - * being used are not cryptographic related :-). - * 4. If you include any Windows specific code (or a derivative thereof) from - * the apps directory (application code) you must include an acknowledgement: - * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" - * - * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * The licence and distribution terms for any publically available version or - * derivative of this code cannot be changed. i.e. this code cannot simply be - * copied and put under another distribution licence - * [including the GNU Public Licence.] */ - -#include - -#include - -#include -#include -#include - - -#define DEFAULT_BUFFER_SIZE 4096 - -typedef struct bio_f_buffer_ctx_struct { - /* Buffers are setup like this: - * - * <---------------------- size -----------------------> - * +---------------------------------------------------+ - * | consumed | remaining | free space | - * +---------------------------------------------------+ - * <-- off --><------- len -------> - */ - - int ibuf_size; /* how big is the input buffer */ - int obuf_size; /* how big is the output buffer */ - - char *ibuf; /* the char array */ - int ibuf_len; /* how many bytes are in it */ - int ibuf_off; /* write/read offset */ - - char *obuf; /* the char array */ - int obuf_len; /* how many bytes are in it */ - int obuf_off; /* write/read offset */ -} BIO_F_BUFFER_CTX; - -static int buffer_new(BIO *bio) { - BIO_F_BUFFER_CTX *ctx; - - ctx = OPENSSL_malloc(sizeof(BIO_F_BUFFER_CTX)); - if (ctx == NULL) { - return 0; - } - memset(ctx, 0, sizeof(BIO_F_BUFFER_CTX)); - - ctx->ibuf = OPENSSL_malloc(DEFAULT_BUFFER_SIZE); - if (ctx->ibuf == NULL) { - goto err1; - } - ctx->obuf = OPENSSL_malloc(DEFAULT_BUFFER_SIZE); - if (ctx->obuf == NULL) { - goto err2; - } - ctx->ibuf_size = DEFAULT_BUFFER_SIZE; - ctx->obuf_size = DEFAULT_BUFFER_SIZE; - - bio->init = 1; - bio->ptr = (char *)ctx; - return 1; - -err2: - OPENSSL_free(ctx->ibuf); - -err1: - OPENSSL_free(ctx); - return 0; -} - -static int buffer_free(BIO *bio) { - BIO_F_BUFFER_CTX *ctx; - - if (bio == NULL || bio->ptr == NULL) { - return 0; - } - - ctx = (BIO_F_BUFFER_CTX *)bio->ptr; - OPENSSL_free(ctx->ibuf); - OPENSSL_free(ctx->obuf); - OPENSSL_free(bio->ptr); - - bio->ptr = NULL; - bio->init = 0; - bio->flags = 0; - - return 1; -} - -static int buffer_read(BIO *bio, char *out, int outl) { - int i, num = 0; - BIO_F_BUFFER_CTX *ctx; - - ctx = (BIO_F_BUFFER_CTX *)bio->ptr; - - if (ctx == NULL || bio->next_bio == NULL) { - return 0; - } - - num = 0; - BIO_clear_retry_flags(bio); - - for (;;) { - i = ctx->ibuf_len; - /* If there is stuff left over, grab it */ - if (i != 0) { - if (i > outl) { - i = outl; - } - memcpy(out, &ctx->ibuf[ctx->ibuf_off], i); - ctx->ibuf_off += i; - ctx->ibuf_len -= i; - num += i; - if (outl == i) { - return num; - } - outl -= i; - out += i; - } - - /* We may have done a partial read. Try to do more. We have nothing in the - * buffer. If we get an error and have read some data, just return it and - * let them retry to get the error again. Copy direct to parent address - * space */ - if (outl > ctx->ibuf_size) { - for (;;) { - i = BIO_read(bio->next_bio, out, outl); - if (i <= 0) { - BIO_copy_next_retry(bio); - if (i < 0) { - return (num > 0) ? num : i; - } - return num; - } - num += i; - if (outl == i) { - return num; - } - out += i; - outl -= i; - } - } - /* else */ - - /* we are going to be doing some buffering */ - i = BIO_read(bio->next_bio, ctx->ibuf, ctx->ibuf_size); - if (i <= 0) { - BIO_copy_next_retry(bio); - if (i < 0) { - return (num > 0) ? num : i; - } - return num; - } - ctx->ibuf_off = 0; - ctx->ibuf_len = i; - } -} - -static int buffer_write(BIO *b, const char *in, int inl) { - int i, num = 0; - BIO_F_BUFFER_CTX *ctx; - - ctx = (BIO_F_BUFFER_CTX *)b->ptr; - if (ctx == NULL || b->next_bio == NULL) { - return 0; - } - - BIO_clear_retry_flags(b); - - for (;;) { - i = ctx->obuf_size - (ctx->obuf_off + ctx->obuf_len); - /* add to buffer and return */ - if (i >= inl) { - memcpy(&ctx->obuf[ctx->obuf_off + ctx->obuf_len], in, inl); - ctx->obuf_len += inl; - return num + inl; - } - /* else */ - /* stuff already in buffer, so add to it first, then flush */ - if (ctx->obuf_len != 0) { - if (i > 0) { - memcpy(&ctx->obuf[ctx->obuf_off + ctx->obuf_len], in, i); - in += i; - inl -= i; - num += i; - ctx->obuf_len += i; - } - - /* we now have a full buffer needing flushing */ - for (;;) { - i = BIO_write(b->next_bio, &ctx->obuf[ctx->obuf_off], ctx->obuf_len); - if (i <= 0) { - BIO_copy_next_retry(b); - - if (i < 0) { - return (num > 0) ? num : i; - } - return num; - } - ctx->obuf_off += i; - ctx->obuf_len -= i; - if (ctx->obuf_len == 0) { - break; - } - } - } - - /* we only get here if the buffer has been flushed and we - * still have stuff to write */ - ctx->obuf_off = 0; - - /* we now have inl bytes to write */ - while (inl >= ctx->obuf_size) { - i = BIO_write(b->next_bio, in, inl); - if (i <= 0) { - BIO_copy_next_retry(b); - if (i < 0) { - return (num > 0) ? num : i; - } - return num; - } - num += i; - in += i; - inl -= i; - if (inl == 0) { - return num; - } - } - - /* copy the rest into the buffer since we have only a small - * amount left */ - } -} - -static long buffer_ctrl(BIO *b, int cmd, long num, void *ptr) { - BIO_F_BUFFER_CTX *ctx; - long ret = 1; - char *p1, *p2; - int r, *ip; - int ibs, obs; - - ctx = (BIO_F_BUFFER_CTX *)b->ptr; - - switch (cmd) { - case BIO_CTRL_RESET: - ctx->ibuf_off = 0; - ctx->ibuf_len = 0; - ctx->obuf_off = 0; - ctx->obuf_len = 0; - if (b->next_bio == NULL) { - return 0; - } - ret = BIO_ctrl(b->next_bio, cmd, num, ptr); - break; - - case BIO_CTRL_INFO: - ret = ctx->obuf_len; - break; - - case BIO_CTRL_WPENDING: - ret = (long)ctx->obuf_len; - if (ret == 0) { - if (b->next_bio == NULL) { - return 0; - } - ret = BIO_ctrl(b->next_bio, cmd, num, ptr); - } - break; - - case BIO_CTRL_PENDING: - ret = (long)ctx->ibuf_len; - if (ret == 0) { - if (b->next_bio == NULL) { - return 0; - } - ret = BIO_ctrl(b->next_bio, cmd, num, ptr); - } - break; - - case BIO_C_SET_BUFF_SIZE: - ip = (int *)ptr; - if (*ip == 0) { - ibs = (int)num; - obs = ctx->obuf_size; - } else /* if (*ip == 1) */ { - ibs = ctx->ibuf_size; - obs = (int)num; - } - p1 = ctx->ibuf; - p2 = ctx->obuf; - if (ibs > DEFAULT_BUFFER_SIZE && ibs != ctx->ibuf_size) { - p1 = OPENSSL_malloc(ibs); - if (p1 == NULL) { - goto malloc_error; - } - } - if (obs > DEFAULT_BUFFER_SIZE && obs != ctx->obuf_size) { - p2 = OPENSSL_malloc(obs); - if (p2 == NULL) { - if (p1 != ctx->ibuf) { - OPENSSL_free(p1); - } - goto malloc_error; - } - } - - if (ctx->ibuf != p1) { - OPENSSL_free(ctx->ibuf); - ctx->ibuf = p1; - ctx->ibuf_size = ibs; - } - ctx->ibuf_off = 0; - ctx->ibuf_len = 0; - - if (ctx->obuf != p2) { - OPENSSL_free(ctx->obuf); - ctx->obuf = p2; - ctx->obuf_size = obs; - } - ctx->obuf_off = 0; - ctx->obuf_len = 0; - break; - - case BIO_CTRL_FLUSH: - if (b->next_bio == NULL) { - return 0; - } - - while (ctx->obuf_len > 0) { - BIO_clear_retry_flags(b); - r = BIO_write(b->next_bio, &(ctx->obuf[ctx->obuf_off]), - ctx->obuf_len); - BIO_copy_next_retry(b); - if (r <= 0) { - return r; - } - ctx->obuf_off += r; - ctx->obuf_len -= r; - } - - ctx->obuf_len = 0; - ctx->obuf_off = 0; - ret = BIO_ctrl(b->next_bio, cmd, num, ptr); - break; - - default: - if (b->next_bio == NULL) { - return 0; - } - BIO_clear_retry_flags(b); - ret = BIO_ctrl(b->next_bio, cmd, num, ptr); - BIO_copy_next_retry(b); - break; - } - return ret; - -malloc_error: - OPENSSL_PUT_ERROR(BIO, ERR_R_MALLOC_FAILURE); - return 0; -} - -static long buffer_callback_ctrl(BIO *b, int cmd, bio_info_cb fp) { - long ret = 1; - - if (b->next_bio == NULL) { - return 0; - } - - switch (cmd) { - default: - ret = BIO_callback_ctrl(b->next_bio, cmd, fp); - break; - } - return ret; -} - -static int buffer_gets(BIO *b, char *buf, int size) { - BIO_F_BUFFER_CTX *ctx; - int num = 0, i, flag; - char *p; - - ctx = (BIO_F_BUFFER_CTX *)b->ptr; - if (buf == NULL || size <= 0) { - return 0; - } - - size--; /* reserve space for a '\0' */ - BIO_clear_retry_flags(b); - - for (;;) { - if (ctx->ibuf_len > 0) { - p = &ctx->ibuf[ctx->ibuf_off]; - flag = 0; - for (i = 0; (i < ctx->ibuf_len) && (i < size); i++) { - *(buf++) = p[i]; - if (p[i] == '\n') { - flag = 1; - i++; - break; - } - } - num += i; - size -= i; - ctx->ibuf_len -= i; - ctx->ibuf_off += i; - if (flag || size == 0) { - *buf = '\0'; - return num; - } - } else /* read another chunk */ - { - i = BIO_read(b->next_bio, ctx->ibuf, ctx->ibuf_size); - if (i <= 0) { - BIO_copy_next_retry(b); - *buf = '\0'; - if (i < 0) { - return (num > 0) ? num : i; - } - return num; - } - ctx->ibuf_len = i; - ctx->ibuf_off = 0; - } - } -} - -static int buffer_puts(BIO *b, const char *str) { - return buffer_write(b, str, strlen(str)); -} - -static const BIO_METHOD methods_buffer = { - BIO_TYPE_BUFFER, "buffer", buffer_write, buffer_read, - buffer_puts, buffer_gets, buffer_ctrl, buffer_new, - buffer_free, buffer_callback_ctrl, -}; - -const BIO_METHOD *BIO_f_buffer(void) { return &methods_buffer; } - -int BIO_set_read_buffer_size(BIO *bio, int buffer_size) { - return BIO_int_ctrl(bio, BIO_C_SET_BUFF_SIZE, buffer_size, 0); -} - -int BIO_set_write_buffer_size(BIO *bio, int buffer_size) { - return BIO_int_ctrl(bio, BIO_C_SET_BUFF_SIZE, buffer_size, 1); -} diff --git a/Sources/BoringSSL/crypto/bio/connect.c b/Sources/BoringSSL/crypto/bio/connect.c index 0b0bf131c..d40dd530d 100644 --- a/Sources/BoringSSL/crypto/bio/connect.c +++ b/Sources/BoringSSL/crypto/bio/connect.c @@ -58,7 +58,6 @@ #include #include -#include #include #if !defined(OPENSSL_WINDOWS) @@ -67,10 +66,10 @@ #include #include #else -#pragma warning(push, 3) +OPENSSL_MSVC_PRAGMA(warning(push, 3)) #include #include -#pragma warning(pop) +OPENSSL_MSVC_PRAGMA(warning(pop)) #endif #include @@ -78,6 +77,7 @@ #include #include "internal.h" +#include "../internal.h" enum { @@ -299,7 +299,7 @@ static BIO_CONNECT *BIO_CONNECT_new(void) { if (ret == NULL) { return NULL; } - memset(ret, 0, sizeof(BIO_CONNECT)); + OPENSSL_memset(ret, 0, sizeof(BIO_CONNECT)); ret->state = BIO_CONN_S_BEFORE; return ret; @@ -468,14 +468,6 @@ static long conn_ctrl(BIO *bio, int cmd, long num, void *ptr) { break; case BIO_CTRL_FLUSH: break; - case BIO_CTRL_SET_CALLBACK: { -#if 0 /* FIXME: Should this be used? -- Richard Levitte */ - OPENSSL_PUT_ERROR(BIO, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); - ret = -1; -#else - ret = 0; -#endif - } break; case BIO_CTRL_GET_CALLBACK: { int (**fptr)(const BIO *bio, int state, int xret); fptr = (int (**)(const BIO *bio, int state, int xret))ptr; @@ -485,7 +477,7 @@ static long conn_ctrl(BIO *bio, int cmd, long num, void *ptr) { ret = 0; break; } - return (ret); + return ret; } static long conn_callback_ctrl(BIO *bio, int cmd, bio_info_cb fp) { @@ -495,9 +487,9 @@ static long conn_callback_ctrl(BIO *bio, int cmd, bio_info_cb fp) { data = (BIO_CONNECT *)bio->ptr; switch (cmd) { - case BIO_CTRL_SET_CALLBACK: { + case BIO_CTRL_SET_CALLBACK: data->info_callback = (int (*)(const struct bio_st *, int, int))fp; - } break; + break; default: ret = 0; break; @@ -505,10 +497,6 @@ static long conn_callback_ctrl(BIO *bio, int cmd, bio_info_cb fp) { return ret; } -static int conn_puts(BIO *bp, const char *str) { - return conn_write(bp, str, strlen(str)); -} - BIO *BIO_new_connect(const char *hostname) { BIO *ret; @@ -524,8 +512,8 @@ BIO *BIO_new_connect(const char *hostname) { } static const BIO_METHOD methods_connectp = { - BIO_TYPE_CONNECT, "socket connect", conn_write, conn_read, - conn_puts, NULL /* connect_gets, */, conn_ctrl, conn_new, + BIO_TYPE_CONNECT, "socket connect", conn_write, conn_read, + NULL /* puts */, NULL /* gets */, conn_ctrl, conn_new, conn_free, conn_callback_ctrl, }; @@ -539,6 +527,16 @@ int BIO_set_conn_port(BIO *bio, const char *port_str) { return BIO_ctrl(bio, BIO_C_SET_CONNECT, 1, (void*) port_str); } +int BIO_set_conn_int_port(BIO *bio, const int *port) { + char buf[DECIMAL_SIZE(int) + 1]; + BIO_snprintf(buf, sizeof(buf), "%d", *port); + return BIO_set_conn_port(bio, buf); +} + int BIO_set_nbio(BIO *bio, int on) { return BIO_ctrl(bio, BIO_C_SET_NBIO, on, NULL); } + +int BIO_do_connect(BIO *bio) { + return BIO_ctrl(bio, BIO_C_DO_STATE_MACHINE, 0, NULL); +} diff --git a/Sources/BoringSSL/crypto/bio/fd.c b/Sources/BoringSSL/crypto/bio/fd.c index 0b3484c9d..4e9eeacfa 100644 --- a/Sources/BoringSSL/crypto/bio/fd.c +++ b/Sources/BoringSSL/crypto/bio/fd.c @@ -63,15 +63,17 @@ #include #else #include -#pragma warning(push, 3) +OPENSSL_MSVC_PRAGMA(warning(push, 3)) #include -#pragma warning(pop) +OPENSSL_MSVC_PRAGMA(warning(pop)) #endif #include #include #include +#include "internal.h" + static int bio_fd_non_fatal_error(int err) { if ( @@ -106,20 +108,25 @@ static int bio_fd_non_fatal_error(int err) { } #if defined(OPENSSL_WINDOWS) -int bio_fd_should_retry(int i) { - if (i == -1) { - return bio_fd_non_fatal_error((int)GetLastError()); - } - return 0; -} + #define BORINGSSL_ERRNO (int)GetLastError() + #define BORINGSSL_CLOSE _close + #define BORINGSSL_LSEEK _lseek + #define BORINGSSL_READ _read + #define BORINGSSL_WRITE _write #else + #define BORINGSSL_ERRNO errno + #define BORINGSSL_CLOSE close + #define BORINGSSL_LSEEK lseek + #define BORINGSSL_READ read + #define BORINGSSL_WRITE write +#endif + int bio_fd_should_retry(int i) { if (i == -1) { - return bio_fd_non_fatal_error(errno); + return bio_fd_non_fatal_error(BORINGSSL_ERRNO); } return 0; } -#endif BIO *BIO_new_fd(int fd, int close_flag) { BIO *ret = BIO_new(BIO_s_fd()); @@ -143,7 +150,7 @@ static int fd_free(BIO *bio) { if (bio->shutdown) { if (bio->init) { - close(bio->num); + BORINGSSL_CLOSE(bio->num); } bio->init = 0; } @@ -153,7 +160,7 @@ static int fd_free(BIO *bio) { static int fd_read(BIO *b, char *out, int outl) { int ret = 0; - ret = read(b->num, out, outl); + ret = BORINGSSL_READ(b->num, out, outl); BIO_clear_retry_flags(b); if (ret <= 0) { if (bio_fd_should_retry(ret)) { @@ -165,7 +172,7 @@ static int fd_read(BIO *b, char *out, int outl) { } static int fd_write(BIO *b, const char *in, int inl) { - int ret = write(b->num, in, inl); + int ret = BORINGSSL_WRITE(b->num, in, inl); BIO_clear_retry_flags(b); if (ret <= 0) { if (bio_fd_should_retry(ret)) { @@ -186,14 +193,14 @@ static long fd_ctrl(BIO *b, int cmd, long num, void *ptr) { case BIO_C_FILE_SEEK: ret = 0; if (b->init) { - ret = (long)lseek(b->num, num, SEEK_SET); + ret = (long)BORINGSSL_LSEEK(b->num, num, SEEK_SET); } break; case BIO_C_FILE_TELL: case BIO_CTRL_INFO: ret = 0; if (b->init) { - ret = (long)lseek(b->num, 0, SEEK_CUR); + ret = (long)BORINGSSL_LSEEK(b->num, 0, SEEK_CUR); } break; case BIO_C_SET_FD: @@ -234,10 +241,6 @@ static long fd_ctrl(BIO *b, int cmd, long num, void *ptr) { return ret; } -static int fd_puts(BIO *bp, const char *str) { - return fd_write(bp, str, strlen(str)); -} - static int fd_gets(BIO *bp, char *buf, int size) { char *ptr = buf; char *end = buf + size - 1; @@ -256,8 +259,9 @@ static int fd_gets(BIO *bp, char *buf, int size) { } static const BIO_METHOD methods_fdp = { - BIO_TYPE_FD, "file descriptor", fd_write, fd_read, fd_puts, - fd_gets, fd_ctrl, fd_new, fd_free, NULL, }; + BIO_TYPE_FD, "file descriptor", fd_write, fd_read, NULL /* puts */, + fd_gets, fd_ctrl, fd_new, fd_free, NULL /* callback_ctrl */, +}; const BIO_METHOD *BIO_s_fd(void) { return &methods_fdp; } diff --git a/Sources/BoringSSL/crypto/bio/file.c b/Sources/BoringSSL/crypto/bio/file.c index 9e29b43c7..3580cd1c2 100644 --- a/Sources/BoringSSL/crypto/bio/file.c +++ b/Sources/BoringSSL/crypto/bio/file.c @@ -87,47 +87,11 @@ #define BIO_FP_WRITE 0x04 #define BIO_FP_APPEND 0x08 -static FILE *open_file(const char *filename, const char *mode) { -#if defined(OPENSSL_WINDOWS) && defined(CP_UTF8) - int sz, len_0 = (int)strlen(filename) + 1; - DWORD flags; - - /* Basically there are three cases to cover: a) filename is pure ASCII - * string; b) actual UTF-8 encoded string and c) locale-ized string, i.e. one - * containing 8-bit characters that are meaningful in current system locale. - * If filename is pure ASCII or real UTF-8 encoded string, - * MultiByteToWideChar succeeds and _wfopen works. If filename is locale-ized - * string, chances are that MultiByteToWideChar fails reporting - * ERROR_NO_UNICODE_TRANSLATION, in which case we fall back to fopen... */ - if ((sz = MultiByteToWideChar(CP_UTF8, (flags = MB_ERR_INVALID_CHARS), - filename, len_0, NULL, 0)) > 0 || - (GetLastError() == ERROR_INVALID_FLAGS && - (sz = MultiByteToWideChar(CP_UTF8, (flags = 0), filename, len_0, NULL, - 0)) > 0)) { - WCHAR wmode[8]; - WCHAR *wfilename = _alloca(sz * sizeof(WCHAR)); - - if (MultiByteToWideChar(CP_UTF8, flags, filename, len_0, wfilename, sz) && - MultiByteToWideChar(CP_UTF8, 0, mode, strlen(mode) + 1, wmode, - sizeof(wmode) / sizeof(wmode[0])) && - (file = _wfopen(wfilename, wmode)) == NULL && - (errno == ENOENT || - errno == EBADF)) /* UTF-8 decode succeeded, but no file, filename - * could still have been locale-ized... */ - return fopen(filename, mode); - } else if (GetLastError() == ERROR_NO_UNICODE_TRANSLATION) { - return fopen(filename, mode); - } -#else - return fopen(filename, mode); -#endif -} - BIO *BIO_new_file(const char *filename, const char *mode) { BIO *ret; FILE *file; - file = open_file(filename, mode); + file = fopen(filename, mode); if (file == NULL) { OPENSSL_PUT_SYSTEM_ERROR(); @@ -256,7 +220,7 @@ static long file_ctrl(BIO *b, int cmd, long num, void *ptr) { ret = 0; break; } - fp = open_file(ptr, p); + fp = fopen(ptr, p); if (fp == NULL) { OPENSSL_PUT_SYSTEM_ERROR(); ERR_add_error_data(5, "fopen('", ptr, "','", p, "')"); @@ -309,13 +273,13 @@ static int file_gets(BIO *bp, char *buf, int size) { return ret; } -static int file_puts(BIO *bp, const char *str) { - return file_write(bp, str, strlen(str)); -} - static const BIO_METHOD methods_filep = { - BIO_TYPE_FILE, "FILE pointer", file_write, file_read, file_puts, - file_gets, file_ctrl, file_new, file_free, NULL, }; + BIO_TYPE_FILE, "FILE pointer", + file_write, file_read, + NULL /* puts */, file_gets, + file_ctrl, file_new, + file_free, NULL /* callback_ctrl */, +}; const BIO_METHOD *BIO_s_file(void) { return &methods_filep; } diff --git a/Sources/BoringSSL/crypto/bio/hexdump.c b/Sources/BoringSSL/crypto/bio/hexdump.c index 17f55183f..d55df6209 100644 --- a/Sources/BoringSSL/crypto/bio/hexdump.c +++ b/Sources/BoringSSL/crypto/bio/hexdump.c @@ -59,6 +59,8 @@ #include #include +#include "../internal.h" + /* hexdump_ctx contains the state of a hexdump. */ struct hexdump_ctx { @@ -86,7 +88,6 @@ static char to_char(uint8_t b) { * |ctx|. */ static int hexdump_write(struct hexdump_ctx *ctx, const uint8_t *data, size_t len) { - size_t i; char buf[10]; unsigned l; @@ -95,7 +96,7 @@ static int hexdump_write(struct hexdump_ctx *ctx, const uint8_t *data, * ^ offset ^ extra space ^ ASCII of line */ - for (i = 0; i < len; i++) { + for (size_t i = 0; i < len; i++) { if (ctx->used == 0) { /* The beginning of a line. */ BIO_indent(ctx->bio, ctx->indent, UINT_MAX); @@ -155,7 +156,7 @@ static int finish(struct hexdump_ctx *ctx) { return 1; } - memset(buf, ' ', 4); + OPENSSL_memset(buf, ' ', 4); buf[4] = '|'; for (; ctx->used < 16; ctx->used++) { @@ -180,7 +181,7 @@ static int finish(struct hexdump_ctx *ctx) { int BIO_hexdump(BIO *bio, const uint8_t *data, size_t len, unsigned indent) { struct hexdump_ctx ctx; - memset(&ctx, 0, sizeof(ctx)); + OPENSSL_memset(&ctx, 0, sizeof(ctx)); ctx.bio = bio; ctx.indent = indent; diff --git a/Sources/BoringSSL/crypto/bio/internal.h b/Sources/BoringSSL/crypto/bio/internal.h index d9a34f18e..4ec77fadb 100644 --- a/Sources/BoringSSL/crypto/bio/internal.h +++ b/Sources/BoringSSL/crypto/bio/internal.h @@ -67,6 +67,9 @@ typedef unsigned short u_short; #include #include #else +OPENSSL_MSVC_PRAGMA(warning(push, 3)) +#include +OPENSSL_MSVC_PRAGMA(warning(pop)) typedef int socklen_t; #endif diff --git a/Sources/BoringSSL/crypto/bio/pair.c b/Sources/BoringSSL/crypto/bio/pair.c index fba4be2cc..8ba382d19 100644 --- a/Sources/BoringSSL/crypto/bio/pair.c +++ b/Sources/BoringSSL/crypto/bio/pair.c @@ -59,6 +59,8 @@ #include #include +#include "../internal.h" + struct bio_bio_st { BIO *peer; /* NULL if buf == NULL. @@ -72,12 +74,6 @@ struct bio_bio_st { size_t offset; /* valid iff buf != NULL; 0 if len == 0 */ size_t size; uint8_t *buf; /* "size" elements (if != NULL) */ - char buf_externally_allocated; /* true iff buf was externally allocated. */ - - char zero_copy_read_lock; /* true iff a zero copy read operation - * is in progress. */ - char zero_copy_write_lock; /* true iff a zero copy write operation - * is in progress. */ size_t request; /* valid iff peer != NULL; 0 if len != 0, * otherwise set by peer to number of bytes @@ -92,7 +88,7 @@ static int bio_new(BIO *bio) { if (b == NULL) { return 0; } - memset(b, 0, sizeof(struct bio_bio_st)); + OPENSSL_memset(b, 0, sizeof(struct bio_bio_st)); b->size = 17 * 1024; /* enough for one TLS record (just a default) */ bio->ptr = b; @@ -145,263 +141,12 @@ static int bio_free(BIO *bio) { bio_destroy_pair(bio); } - if (!b->buf_externally_allocated) { - OPENSSL_free(b->buf); - } - + OPENSSL_free(b->buf); OPENSSL_free(b); return 1; } -static size_t bio_zero_copy_get_read_buf(struct bio_bio_st* peer_b, - uint8_t** out_read_buf, - size_t* out_buf_offset) { - size_t max_available; - if (peer_b->len > peer_b->size - peer_b->offset) { - /* Only the first half of the ring buffer can be read. */ - max_available = peer_b->size - peer_b->offset; - } else { - max_available = peer_b->len; - } - - *out_read_buf = peer_b->buf; - *out_buf_offset = peer_b->offset; - return max_available; -} - -int BIO_zero_copy_get_read_buf(BIO* bio, uint8_t** out_read_buf, - size_t* out_buf_offset, - size_t* out_available_bytes) { - struct bio_bio_st* b; - struct bio_bio_st* peer_b; - size_t max_available; - *out_available_bytes = 0; - - BIO_clear_retry_flags(bio); - - if (!bio->init) { - OPENSSL_PUT_ERROR(BIO, BIO_R_UNINITIALIZED); - return 0; - } - - b = bio->ptr; - - if (!b || !b->peer) { - OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD); - return 0; - } - - peer_b = b->peer->ptr; - if (!peer_b || !peer_b->peer || peer_b->peer->ptr != b) { - OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD); - return 0; - } - - if (peer_b->zero_copy_read_lock) { - OPENSSL_PUT_ERROR(BIO, BIO_R_INVALID_ARGUMENT); - return 0; - } - - peer_b->request = 0; /* Is not used by zero-copy API. */ - - max_available = - bio_zero_copy_get_read_buf(peer_b, out_read_buf, out_buf_offset); - - assert(peer_b->buf != NULL); - if (max_available > 0) { - peer_b->zero_copy_read_lock = 1; - } - - *out_available_bytes = max_available; - return 1; -} - -int BIO_zero_copy_get_read_buf_done(BIO* bio, size_t bytes_read) { - struct bio_bio_st* b; - struct bio_bio_st* peer_b; - size_t max_available; - size_t dummy_read_offset; - uint8_t* dummy_read_buf; - - assert(BIO_get_retry_flags(bio) == 0); - - if (!bio->init) { - OPENSSL_PUT_ERROR(BIO, BIO_R_UNINITIALIZED); - return 0; - } - - b = bio->ptr; - - if (!b || !b->peer) { - OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD); - return 0; - } - - peer_b = b->peer->ptr; - if (!peer_b || !peer_b->peer || peer_b->peer->ptr != b) { - OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD); - return 0; - } - - if (!peer_b->zero_copy_read_lock) { - OPENSSL_PUT_ERROR(BIO, BIO_R_INVALID_ARGUMENT); - return 0; - } - - max_available = - bio_zero_copy_get_read_buf(peer_b, &dummy_read_buf, &dummy_read_offset); - if (bytes_read > max_available) { - OPENSSL_PUT_ERROR(BIO, BIO_R_INVALID_ARGUMENT); - return 0; - } - - assert(peer_b->len >= bytes_read); - peer_b->len -= bytes_read; - assert(peer_b->offset + bytes_read <= peer_b->size); - - /* Move read offset. If zero_copy_write_lock == 1 we must advance the - * offset even if buffer becomes empty, to make sure - * write_offset = (offset + len) mod size does not change. */ - if (peer_b->offset + bytes_read == peer_b->size || - (!peer_b->zero_copy_write_lock && peer_b->len == 0)) { - peer_b->offset = 0; - } else { - peer_b->offset += bytes_read; - } - - bio->num_read += bytes_read; - peer_b->zero_copy_read_lock = 0; - return 1; -} - -static size_t bio_zero_copy_get_write_buf(struct bio_bio_st* b, - uint8_t** out_write_buf, - size_t* out_buf_offset) { - size_t write_offset; - size_t max_available; - - assert(b->len <= b->size); - - write_offset = b->offset + b->len; - - if (write_offset >= b->size) { - /* Only the first half of the ring buffer can be written to. */ - write_offset -= b->size; - /* write up to the start of the ring buffer. */ - max_available = b->offset - write_offset; - } else { - /* write up to the end the buffer. */ - max_available = b->size - write_offset; - } - - *out_write_buf = b->buf; - *out_buf_offset = write_offset; - return max_available; -} - -int BIO_zero_copy_get_write_buf(BIO* bio, uint8_t** out_write_buf, - size_t* out_buf_offset, - size_t* out_available_bytes) { - struct bio_bio_st* b; - struct bio_bio_st* peer_b; - size_t max_available; - - *out_available_bytes = 0; - BIO_clear_retry_flags(bio); - - if (!bio->init) { - OPENSSL_PUT_ERROR(BIO, BIO_R_UNINITIALIZED); - return 0; - } - - b = bio->ptr; - - if (!b || !b->buf || !b->peer) { - OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD); - return 0; - } - peer_b = b->peer->ptr; - if (!peer_b || !peer_b->peer || peer_b->peer->ptr != b) { - OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD); - return 0; - } - - assert(b->buf != NULL); - - if (b->zero_copy_write_lock) { - OPENSSL_PUT_ERROR(BIO, BIO_R_INVALID_ARGUMENT); - return 0; - } - - b->request = 0; - if (b->closed) { - /* Bio is already closed. */ - OPENSSL_PUT_ERROR(BIO, BIO_R_BROKEN_PIPE); - return 0; - } - - max_available = bio_zero_copy_get_write_buf(b, out_write_buf, out_buf_offset); - - if (max_available > 0) { - b->zero_copy_write_lock = 1; - } - - *out_available_bytes = max_available; - return 1; -} - -int BIO_zero_copy_get_write_buf_done(BIO* bio, size_t bytes_written) { - struct bio_bio_st* b; - struct bio_bio_st* peer_b; - - size_t rest; - size_t dummy_write_offset; - uint8_t* dummy_write_buf; - - if (!bio->init) { - OPENSSL_PUT_ERROR(BIO, BIO_R_UNINITIALIZED); - return 0; - } - - b = bio->ptr; - - if (!b || !b->buf || !b->peer) { - OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD); - return 0; - } - peer_b = b->peer->ptr; - if (!peer_b || !peer_b->peer || peer_b->peer->ptr != b) { - OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD); - return 0; - } - - b->request = 0; - if (b->closed) { - /* BIO is already closed. */ - OPENSSL_PUT_ERROR(BIO, BIO_R_BROKEN_PIPE); - return 0; - } - - if (!b->zero_copy_write_lock) { - OPENSSL_PUT_ERROR(BIO, BIO_R_INVALID_ARGUMENT); - return 0; - } - - rest = bio_zero_copy_get_write_buf(b, &dummy_write_buf, &dummy_write_offset); - - if (bytes_written > rest) { - OPENSSL_PUT_ERROR(BIO, BIO_R_INVALID_ARGUMENT); - return 0; - } - - bio->num_write += bytes_written; - /* Move write offset. */ - b->len += bytes_written; - b->zero_copy_write_lock = 0; - return 1; -} - static int bio_read(BIO *bio, char *buf, int size_) { size_t size = size_; size_t rest; @@ -422,7 +167,7 @@ static int bio_read(BIO *bio, char *buf, int size_) { peer_b->request = 0; /* will be set in "retry_read" situation */ - if (buf == NULL || size == 0 || peer_b->zero_copy_read_lock) { + if (buf == NULL || size == 0) { return 0; } @@ -464,13 +209,10 @@ static int bio_read(BIO *bio, char *buf, int size_) { } assert(peer_b->offset + chunk <= peer_b->size); - memcpy(buf, peer_b->buf + peer_b->offset, chunk); + OPENSSL_memcpy(buf, peer_b->buf + peer_b->offset, chunk); peer_b->len -= chunk; - /* If zero_copy_write_lock == 1 we must advance the offset even if buffer - * becomes empty, to make sure write_offset = (offset + len) % size - * does not change. */ - if (peer_b->len || peer_b->zero_copy_write_lock) { + if (peer_b->len) { peer_b->offset += chunk; assert(peer_b->offset <= peer_b->size); if (peer_b->offset == peer_b->size) { @@ -504,10 +246,6 @@ static int bio_write(BIO *bio, const char *buf, int num_) { assert(b->peer != NULL); assert(b->buf != NULL); - if (b->zero_copy_write_lock) { - return 0; - } - b->request = 0; if (b->closed) { /* we already closed */ @@ -551,7 +289,7 @@ static int bio_write(BIO *bio, const char *buf, int num_) { chunk = b->size - write_offset; } - memcpy(b->buf + write_offset, buf, chunk); + OPENSSL_memcpy(b->buf + write_offset, buf, chunk); b->len += chunk; @@ -564,9 +302,8 @@ static int bio_write(BIO *bio, const char *buf, int num_) { return num; } -static int bio_make_pair(BIO* bio1, BIO* bio2, - size_t writebuf1_len, uint8_t* ext_writebuf1, - size_t writebuf2_len, uint8_t* ext_writebuf2) { +static int bio_make_pair(BIO *bio1, BIO *bio2, size_t writebuf1_len, + size_t writebuf2_len) { struct bio_bio_st *b1, *b2; assert(bio1 != NULL); @@ -580,23 +317,14 @@ static int bio_make_pair(BIO* bio1, BIO* bio2, return 0; } - assert(b1->buf_externally_allocated == 0); - assert(b2->buf_externally_allocated == 0); - if (b1->buf == NULL) { if (writebuf1_len) { b1->size = writebuf1_len; } - if (!ext_writebuf1) { - b1->buf_externally_allocated = 0; - b1->buf = OPENSSL_malloc(b1->size); - if (b1->buf == NULL) { - OPENSSL_PUT_ERROR(BIO, ERR_R_MALLOC_FAILURE); - return 0; - } - } else { - b1->buf = ext_writebuf1; - b1->buf_externally_allocated = 1; + b1->buf = OPENSSL_malloc(b1->size); + if (b1->buf == NULL) { + OPENSSL_PUT_ERROR(BIO, ERR_R_MALLOC_FAILURE); + return 0; } b1->len = 0; b1->offset = 0; @@ -606,16 +334,10 @@ static int bio_make_pair(BIO* bio1, BIO* bio2, if (writebuf2_len) { b2->size = writebuf2_len; } - if (!ext_writebuf2) { - b2->buf_externally_allocated = 0; - b2->buf = OPENSSL_malloc(b2->size); - if (b2->buf == NULL) { - OPENSSL_PUT_ERROR(BIO, ERR_R_MALLOC_FAILURE); - return 0; - } - } else { - b2->buf = ext_writebuf2; - b2->buf_externally_allocated = 1; + b2->buf = OPENSSL_malloc(b2->size); + if (b2->buf == NULL) { + OPENSSL_PUT_ERROR(BIO, ERR_R_MALLOC_FAILURE); + return 0; } b2->len = 0; b2->offset = 0; @@ -624,13 +346,9 @@ static int bio_make_pair(BIO* bio1, BIO* bio2, b1->peer = bio2; b1->closed = 0; b1->request = 0; - b1->zero_copy_read_lock = 0; - b1->zero_copy_write_lock = 0; b2->peer = bio1; b2->closed = 0; b2->request = 0; - b2->zero_copy_read_lock = 0; - b2->zero_copy_write_lock = 0; bio1->init = 1; bio2->init = 1; @@ -732,62 +450,30 @@ static long bio_ctrl(BIO *bio, int cmd, long num, void *ptr) { return ret; } -static int bio_puts(BIO *bio, const char *str) { - return bio_write(bio, str, strlen(str)); -} static const BIO_METHOD methods_biop = { - BIO_TYPE_BIO, "BIO pair", bio_write, bio_read, - bio_puts, NULL /* no bio_gets */, bio_ctrl, bio_new, - bio_free, NULL /* no bio_callback_ctrl */ + BIO_TYPE_BIO, "BIO pair", bio_write, bio_read, NULL /* puts */, + NULL /* gets */, bio_ctrl, bio_new, bio_free, NULL /* callback_ctrl */ }; -const BIO_METHOD *bio_s_bio(void) { return &methods_biop; } - -int BIO_new_bio_pair(BIO** bio1_p, size_t writebuf1, - BIO** bio2_p, size_t writebuf2) { - return BIO_new_bio_pair_external_buf(bio1_p, writebuf1, NULL, bio2_p, - writebuf2, NULL); -} +static const BIO_METHOD *bio_s_bio(void) { return &methods_biop; } -int BIO_new_bio_pair_external_buf(BIO** bio1_p, size_t writebuf1_len, - uint8_t* ext_writebuf1, - BIO** bio2_p, size_t writebuf2_len, - uint8_t* ext_writebuf2) { - BIO *bio1 = NULL, *bio2 = NULL; - int ret = 0; - - /* External buffers must have sizes greater than 0. */ - if ((ext_writebuf1 && !writebuf1_len) || (ext_writebuf2 && !writebuf2_len)) { - goto err; - } - - bio1 = BIO_new(bio_s_bio()); - if (bio1 == NULL) { - goto err; - } - bio2 = BIO_new(bio_s_bio()); - if (bio2 == NULL) { - goto err; - } - - if (!bio_make_pair(bio1, bio2, writebuf1_len, ext_writebuf1, writebuf2_len, - ext_writebuf2)) { - goto err; - } - ret = 1; - -err: - if (ret == 0) { +int BIO_new_bio_pair(BIO** bio1_p, size_t writebuf1_len, + BIO** bio2_p, size_t writebuf2_len) { + BIO *bio1 = BIO_new(bio_s_bio()); + BIO *bio2 = BIO_new(bio_s_bio()); + if (bio1 == NULL || bio2 == NULL || + !bio_make_pair(bio1, bio2, writebuf1_len, writebuf2_len)) { BIO_free(bio1); - bio1 = NULL; BIO_free(bio2); - bio2 = NULL; + *bio1_p = NULL; + *bio2_p = NULL; + return 0; } *bio1_p = bio1; *bio2_p = bio2; - return ret; + return 1; } size_t BIO_ctrl_get_read_request(BIO *bio) { diff --git a/Sources/BoringSSL/crypto/bio/socket.c b/Sources/BoringSSL/crypto/bio/socket.c index 98f32a62e..111761fa8 100644 --- a/Sources/BoringSSL/crypto/bio/socket.c +++ b/Sources/BoringSSL/crypto/bio/socket.c @@ -63,11 +63,11 @@ #if !defined(OPENSSL_WINDOWS) #include #else -#pragma warning(push, 3) +OPENSSL_MSVC_PRAGMA(warning(push, 3)) #include -#pragma warning(pop) +OPENSSL_MSVC_PRAGMA(warning(pop)) -#pragma comment(lib, "Ws2_32.lib") +OPENSSL_MSVC_PRAGMA(comment(lib, "Ws2_32.lib")) #endif #include "internal.h" @@ -110,7 +110,11 @@ static int sock_read(BIO *b, char *out, int outl) { } bio_clear_socket_error(); +#if defined(OPENSSL_WINDOWS) ret = recv(b->num, out, outl, 0); +#else + ret = read(b->num, out, outl); +#endif BIO_clear_retry_flags(b); if (ret <= 0) { if (bio_fd_should_retry(ret)) { @@ -124,7 +128,11 @@ static int sock_write(BIO *b, const char *in, int inl) { int ret; bio_clear_socket_error(); +#if defined(OPENSSL_WINDOWS) ret = send(b->num, in, inl, 0); +#else + ret = write(b->num, in, inl); +#endif BIO_clear_retry_flags(b); if (ret <= 0) { if (bio_fd_should_retry(ret)) { @@ -134,10 +142,6 @@ static int sock_write(BIO *b, const char *in, int inl) { return ret; } -static int sock_puts(BIO *bp, const char *str) { - return sock_write(bp, str, strlen(str)); -} - static long sock_ctrl(BIO *b, int cmd, long num, void *ptr) { long ret = 1; int *ip; @@ -177,8 +181,11 @@ static long sock_ctrl(BIO *b, int cmd, long num, void *ptr) { } static const BIO_METHOD methods_sockp = { - BIO_TYPE_SOCKET, "socket", sock_write, sock_read, sock_puts, - NULL /* gets, */, sock_ctrl, sock_new, sock_free, NULL, + BIO_TYPE_SOCKET, "socket", + sock_write, sock_read, + NULL /* puts */, NULL /* gets, */, + sock_ctrl, sock_new, + sock_free, NULL /* callback_ctrl */, }; const BIO_METHOD *BIO_s_socket(void) { return &methods_sockp; } diff --git a/Sources/BoringSSL/crypto/bio/socket_helper.c b/Sources/BoringSSL/crypto/bio/socket_helper.c index 4ddc094dd..268405a6d 100644 --- a/Sources/BoringSSL/crypto/bio/socket_helper.c +++ b/Sources/BoringSSL/crypto/bio/socket_helper.c @@ -26,13 +26,14 @@ #include #include #else -#pragma warning(push, 3) +OPENSSL_MSVC_PRAGMA(warning(push, 3)) #include #include -#pragma warning(pop) +OPENSSL_MSVC_PRAGMA(warning(pop)) #endif #include "internal.h" +#include "../internal.h" int bio_ip_and_port_to_socket_and_addr(int *out_sock, @@ -45,7 +46,7 @@ int bio_ip_and_port_to_socket_and_addr(int *out_sock, *out_sock = -1; - memset(&hint, 0, sizeof(hint)); + OPENSSL_memset(&hint, 0, sizeof(hint)); hint.ai_family = AF_UNSPEC; hint.ai_socktype = SOCK_STREAM; @@ -62,8 +63,8 @@ int bio_ip_and_port_to_socket_and_addr(int *out_sock, if ((size_t) cur->ai_addrlen > sizeof(struct sockaddr_storage)) { continue; } - memset(out_addr, 0, sizeof(struct sockaddr_storage)); - memcpy(out_addr, cur->ai_addr, cur->ai_addrlen); + OPENSSL_memset(out_addr, 0, sizeof(struct sockaddr_storage)); + OPENSSL_memcpy(out_addr, cur->ai_addr, cur->ai_addrlen); *out_addr_length = cur->ai_addrlen; *out_sock = socket(cur->ai_family, cur->ai_socktype, cur->ai_protocol); diff --git a/Sources/BoringSSL/crypto/bn/add.c b/Sources/BoringSSL/crypto/bn/add.c index 23f9f802c..cfa3bbe39 100644 --- a/Sources/BoringSSL/crypto/bn/add.c +++ b/Sources/BoringSSL/crypto/bn/add.c @@ -314,7 +314,7 @@ int BN_usub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) { } if (dif > 0 && rp != ap) { - memcpy(rp, ap, sizeof(*rp) * dif); + OPENSSL_memcpy(rp, ap, sizeof(*rp) * dif); } r->top = max; diff --git a/Sources/BoringSSL/crypto/bn/bn.c b/Sources/BoringSSL/crypto/bn/bn.c index 2263701f8..e3c55f281 100644 --- a/Sources/BoringSSL/crypto/bn/bn.c +++ b/Sources/BoringSSL/crypto/bn/bn.c @@ -73,14 +73,14 @@ BIGNUM *BN_new(void) { return NULL; } - memset(bn, 0, sizeof(BIGNUM)); + OPENSSL_memset(bn, 0, sizeof(BIGNUM)); bn->flags = BN_FLG_MALLOCED; return bn; } void BN_init(BIGNUM *bn) { - memset(bn, 0, sizeof(BIGNUM)); + OPENSSL_memset(bn, 0, sizeof(BIGNUM)); } void BN_free(BIGNUM *bn) { @@ -149,7 +149,7 @@ BIGNUM *BN_copy(BIGNUM *dest, const BIGNUM *src) { return NULL; } - memcpy(dest->d, src->d, sizeof(src->d[0]) * src->top); + OPENSSL_memcpy(dest->d, src->d, sizeof(src->d[0]) * src->top); dest->top = src->top; dest->neg = src->neg; @@ -158,7 +158,7 @@ BIGNUM *BN_copy(BIGNUM *dest, const BIGNUM *src) { void BN_clear(BIGNUM *bn) { if (bn->d != NULL) { - memset(bn->d, 0, bn->dmax * sizeof(bn->d[0])); + OPENSSL_memset(bn->d, 0, bn->dmax * sizeof(bn->d[0])); } bn->top = 0; @@ -172,12 +172,6 @@ const BIGNUM *BN_value_one(void) { return &kOne; } -void BN_with_flags(BIGNUM *out, const BIGNUM *in, int flags) { - memcpy(out, in, sizeof(BIGNUM)); - out->flags &= ~BN_FLG_MALLOCED; - out->flags |= BN_FLG_STATIC_DATA | flags; -} - /* BN_num_bits_word returns the minimum number of bits needed to represent the * value in |l|. */ unsigned BN_num_bits_word(BN_ULONG l) { @@ -266,6 +260,40 @@ int BN_set_word(BIGNUM *bn, BN_ULONG value) { return 1; } +int BN_set_u64(BIGNUM *bn, uint64_t value) { +#if BN_BITS2 == 64 + return BN_set_word(bn, value); +#elif BN_BITS2 == 32 + if (value <= BN_MASK2) { + return BN_set_word(bn, (BN_ULONG)value); + } + + if (bn_wexpand(bn, 2) == NULL) { + return 0; + } + + bn->neg = 0; + bn->d[0] = (BN_ULONG)value; + bn->d[1] = (BN_ULONG)(value >> 32); + bn->top = 2; + return 1; +#else +#error "BN_BITS2 must be 32 or 64." +#endif +} + +int bn_set_words(BIGNUM *bn, const BN_ULONG *words, size_t num) { + if (bn_wexpand(bn, num) == NULL) { + return 0; + } + OPENSSL_memmove(bn->d, words, num * sizeof(BN_ULONG)); + /* |bn_wexpand| verified that |num| isn't too large. */ + bn->top = (int)num; + bn_correct_top(bn); + bn->neg = 0; + return 1; +} + int BN_is_negative(const BIGNUM *bn) { return bn->neg != 0; } @@ -301,7 +329,7 @@ BIGNUM *bn_wexpand(BIGNUM *bn, size_t words) { return NULL; } - memcpy(a, bn->d, sizeof(BN_ULONG) * bn->top); + OPENSSL_memcpy(a, bn->d, sizeof(BN_ULONG) * bn->top); OPENSSL_free(bn->d); bn->d = a; @@ -330,12 +358,8 @@ void bn_correct_top(BIGNUM *bn) { } bn->top = tmp_top; } -} - -int BN_get_flags(const BIGNUM *bn, int flags) { - return bn->flags & flags; -} -void BN_set_flags(BIGNUM *bn, int flags) { - bn->flags |= flags; + if (bn->top == 0) { + bn->neg = 0; + } } diff --git a/Sources/BoringSSL/crypto/bn/cmp.c b/Sources/BoringSSL/crypto/bn/cmp.c index fce72339f..71c04658c 100644 --- a/Sources/BoringSSL/crypto/bn/cmp.c +++ b/Sources/BoringSSL/crypto/bn/cmp.c @@ -56,6 +56,8 @@ #include +#include + #include "internal.h" @@ -183,6 +185,17 @@ int BN_abs_is_word(const BIGNUM *bn, BN_ULONG w) { } } +int BN_cmp_word(const BIGNUM *a, BN_ULONG b) { + BIGNUM b_bn; + BN_init(&b_bn); + + b_bn.d = &b; + b_bn.top = b > 0; + b_bn.dmax = 1; + b_bn.flags = BN_FLG_STATIC_DATA; + return BN_cmp(a, &b_bn); +} + int BN_is_zero(const BIGNUM *bn) { return bn->top == 0; } @@ -198,3 +211,29 @@ int BN_is_word(const BIGNUM *bn, BN_ULONG w) { int BN_is_odd(const BIGNUM *bn) { return bn->top > 0 && (bn->d[0] & 1) == 1; } + +int BN_is_pow2(const BIGNUM *bn) { + if (bn->top == 0 || bn->neg) { + return 0; + } + + for (int i = 0; i < bn->top - 1; i++) { + if (bn->d[i] != 0) { + return 0; + } + } + + return 0 == (bn->d[bn->top-1] & (bn->d[bn->top-1] - 1)); +} + +int BN_equal_consttime(const BIGNUM *a, const BIGNUM *b) { + if (a->top != b->top) { + return 0; + } + + int limbs_are_equal = + CRYPTO_memcmp(a->d, b->d, (size_t)a->top * sizeof(a->d[0])) == 0; + + return constant_time_select_int(constant_time_eq_int(a->neg, b->neg), + limbs_are_equal, 0); +} diff --git a/Sources/BoringSSL/crypto/bn/convert.c b/Sources/BoringSSL/crypto/bn/convert.c index 542f523fe..1fa0dd4f5 100644 --- a/Sources/BoringSSL/crypto/bn/convert.c +++ b/Sources/BoringSSL/crypto/bn/convert.c @@ -118,6 +118,42 @@ BIGNUM *BN_bin2bn(const uint8_t *in, size_t len, BIGNUM *ret) { return ret; } +BIGNUM *BN_le2bn(const uint8_t *in, size_t len, BIGNUM *ret) { + BIGNUM *bn = NULL; + if (ret == NULL) { + bn = BN_new(); + ret = bn; + } + + if (ret == NULL) { + return NULL; + } + + if (len == 0) { + ret->top = 0; + ret->neg = 0; + return ret; + } + + /* Reserve enough space in |ret|. */ + size_t num_words = ((len - 1) / BN_BYTES) + 1; + if (!bn_wexpand(ret, num_words)) { + BN_free(bn); + return NULL; + } + ret->top = num_words; + + /* Make sure the top bytes will be zeroed. */ + ret->d[num_words - 1] = 0; + + /* We only support little-endian platforms, so we can simply memcpy the + * internal representation. */ + OPENSSL_memcpy(ret->d, in, len); + + bn_correct_top(ret); + return ret; +} + size_t BN_bn2bin(const BIGNUM *in, uint8_t *out) { size_t n, i; BN_ULONG l; @@ -130,6 +166,23 @@ size_t BN_bn2bin(const BIGNUM *in, uint8_t *out) { return n; } +int BN_bn2le_padded(uint8_t *out, size_t len, const BIGNUM *in) { + /* If we don't have enough space, fail out. */ + size_t num_bytes = BN_num_bytes(in); + if (len < num_bytes) { + return 0; + } + + /* We only support little-endian platforms, so we can simply memcpy into the + * internal representation. */ + OPENSSL_memcpy(out, in->d, num_bytes); + + /* Pad out the rest of the buffer with zeroes. */ + OPENSSL_memset(out + num_bytes, 0, len - num_bytes); + + return 1; +} + /* constant_time_select_ulong returns |x| if |v| is 1 and |y| if |v| is 0. Its * behavior is undefined if |v| takes any other value. */ static BN_ULONG constant_time_select_ulong(int v, BN_ULONG x, BN_ULONG y) { @@ -160,12 +213,9 @@ static BN_ULONG read_word_padded(const BIGNUM *in, size_t i) { } int BN_bn2bin_padded(uint8_t *out, size_t len, const BIGNUM *in) { - size_t i; - BN_ULONG l; - /* Special case for |in| = 0. Just branch as the probability is negligible. */ if (BN_is_zero(in)) { - memset(out, 0, len); + OPENSSL_memset(out, 0, len); return 1; } @@ -175,7 +225,7 @@ int BN_bn2bin_padded(uint8_t *out, size_t len, const BIGNUM *in) { return 0; } if ((len % BN_BYTES) != 0) { - l = read_word_padded(in, len / BN_BYTES); + BN_ULONG l = read_word_padded(in, len / BN_BYTES); if (l >> (8 * (len % BN_BYTES)) != 0) { return 0; } @@ -188,9 +238,9 @@ int BN_bn2bin_padded(uint8_t *out, size_t len, const BIGNUM *in) { * leading zero octets is low. * * See Falko Stenzke, "Manger's Attack revisited", ICICS 2010. */ - i = len; + size_t i = len; while (i--) { - l = read_word_padded(in, i / BN_BYTES); + BN_ULONG l = read_word_padded(in, i / BN_BYTES); *(out++) = (uint8_t)(l >> (8 * (i % BN_BYTES))) & 0xff; } return 1; @@ -204,17 +254,14 @@ int BN_bn2cbb_padded(CBB *out, size_t len, const BIGNUM *in) { static const char hextable[] = "0123456789abcdef"; char *BN_bn2hex(const BIGNUM *bn) { - int i, j, v, z = 0; - char *buf; - char *p; - - buf = OPENSSL_malloc(bn->top * BN_BYTES * 2 + 2); + char *buf = OPENSSL_malloc(1 /* leading '-' */ + 1 /* zero is non-empty */ + + bn->top * BN_BYTES * 2 + 1 /* trailing NUL */); if (buf == NULL) { OPENSSL_PUT_ERROR(BN, ERR_R_MALLOC_FAILURE); return NULL; } - p = buf; + char *p = buf; if (bn->neg) { *(p++) = '-'; } @@ -223,10 +270,11 @@ char *BN_bn2hex(const BIGNUM *bn) { *(p++) = '0'; } - for (i = bn->top - 1; i >= 0; i--) { - for (j = BN_BITS2 - 8; j >= 0; j -= 8) { + int z = 0; + for (int i = bn->top - 1; i >= 0; i--) { + for (int j = BN_BITS2 - 8; j >= 0; j -= 8) { /* strip leading zeros */ - v = ((int)(bn->d[i] >> (long)j)) & 0xff; + int v = ((int)(bn->d[i] >> (long)j)) & 0xff; if (z || v != 0) { *(p++) = hextable[v >> 4]; *(p++) = hextable[v & 0x0f]; @@ -372,72 +420,69 @@ int BN_hex2bn(BIGNUM **outp, const char *in) { } char *BN_bn2dec(const BIGNUM *a) { - int i = 0, num, ok = 0; - char *buf = NULL; - char *p; - BIGNUM *t = NULL; - BN_ULONG *bn_data = NULL, *lp; - - /* get an upper bound for the length of the decimal integer - * num <= (BN_num_bits(a) + 1) * log(2) - * <= 3 * BN_num_bits(a) * 0.1001 + log(2) + 1 (rounding error) - * <= BN_num_bits(a)/10 + BN_num_bits/1000 + 1 + 1 - */ - i = BN_num_bits(a) * 3; - num = i / 10 + i / 1000 + 1 + 1; - bn_data = OPENSSL_malloc((num / BN_DEC_NUM + 1) * sizeof(BN_ULONG)); - buf = OPENSSL_malloc(num + 3); - if ((buf == NULL) || (bn_data == NULL)) { - OPENSSL_PUT_ERROR(BN, ERR_R_MALLOC_FAILURE); - goto err; - } - t = BN_dup(a); - if (t == NULL) { - goto err; - } - -#define BUF_REMAIN (num + 3 - (size_t)(p - buf)) - p = buf; - lp = bn_data; - if (BN_is_zero(t)) { - *(p++) = '0'; - *(p++) = '\0'; + /* It is easier to print strings little-endian, so we assemble it in reverse + * and fix at the end. */ + BIGNUM *copy = NULL; + CBB cbb; + if (!CBB_init(&cbb, 16) || + !CBB_add_u8(&cbb, 0 /* trailing NUL */)) { + goto cbb_err; + } + + if (BN_is_zero(a)) { + if (!CBB_add_u8(&cbb, '0')) { + goto cbb_err; + } } else { - if (BN_is_negative(t)) { - *p++ = '-'; + copy = BN_dup(a); + if (copy == NULL) { + goto err; } - while (!BN_is_zero(t)) { - *lp = BN_div_word(t, BN_DEC_CONV); - lp++; - } - lp--; - /* We now have a series of blocks, BN_DEC_NUM chars - * in length, where the last one needs truncation. - * The blocks need to be reversed in order. */ - BIO_snprintf(p, BUF_REMAIN, BN_DEC_FMT1, *lp); - while (*p) { - p++; - } - while (lp != bn_data) { - lp--; - BIO_snprintf(p, BUF_REMAIN, BN_DEC_FMT2, *lp); - while (*p) { - p++; + while (!BN_is_zero(copy)) { + BN_ULONG word = BN_div_word(copy, BN_DEC_CONV); + if (word == (BN_ULONG)-1) { + goto err; } + + const int add_leading_zeros = !BN_is_zero(copy); + for (int i = 0; i < BN_DEC_NUM && (add_leading_zeros || word != 0); i++) { + if (!CBB_add_u8(&cbb, '0' + word % 10)) { + goto cbb_err; + } + word /= 10; + } + assert(word == 0); } } - ok = 1; -err: - OPENSSL_free(bn_data); - BN_free(t); - if (!ok) { - OPENSSL_free(buf); - buf = NULL; + if (BN_is_negative(a) && + !CBB_add_u8(&cbb, '-')) { + goto cbb_err; } - return buf; + uint8_t *data; + size_t len; + if (!CBB_finish(&cbb, &data, &len)) { + goto cbb_err; + } + + /* Reverse the buffer. */ + for (size_t i = 0; i < len/2; i++) { + uint8_t tmp = data[i]; + data[i] = data[len - 1 - i]; + data[len - 1 - i] = tmp; + } + + BN_free(copy); + return (char *)data; + +cbb_err: + OPENSSL_PUT_ERROR(BN, ERR_R_MALLOC_FAILURE); +err: + BN_free(copy); + CBB_cleanup(&cbb); + return NULL; } int BN_dec2bn(BIGNUM **outp, const char *in) { @@ -523,6 +568,24 @@ BN_ULONG BN_get_word(const BIGNUM *bn) { } } +int BN_get_u64(const BIGNUM *bn, uint64_t *out) { + switch (bn->top) { + case 0: + *out = 0; + return 1; + case 1: + *out = bn->d[0]; + return 1; +#if defined(OPENSSL_32_BIT) + case 2: + *out = (uint64_t) bn->d[0] | (((uint64_t) bn->d[1]) << 32); + return 1; +#endif + default: + return 0; + } +} + size_t BN_bn2mpi(const BIGNUM *in, uint8_t *out) { const size_t bits = BN_num_bits(in); const size_t bytes = (bits + 7) / 8; @@ -540,7 +603,7 @@ size_t BN_bn2mpi(const BIGNUM *in, uint8_t *out) { /* If we cannot represent the number then we emit zero as the interface * doesn't allow an error to be signalled. */ if (out) { - memset(out, 0, 4); + OPENSSL_memset(out, 0, 4); } return 4; } @@ -577,12 +640,14 @@ BIGNUM *BN_mpi2bn(const uint8_t *in, size_t len, BIGNUM *out) { return NULL; } + int out_is_alloced = 0; if (out == NULL) { out = BN_new(); - } - if (out == NULL) { - OPENSSL_PUT_ERROR(BN, ERR_R_MALLOC_FAILURE); - return NULL; + if (out == NULL) { + OPENSSL_PUT_ERROR(BN, ERR_R_MALLOC_FAILURE); + return NULL; + } + out_is_alloced = 1; } if (in_len == 0) { @@ -592,6 +657,9 @@ BIGNUM *BN_mpi2bn(const uint8_t *in, size_t len, BIGNUM *out) { in += 4; if (BN_bin2bn(in, in_len, out) == NULL) { + if (out_is_alloced) { + BN_free(out); + } return NULL; } out->neg = ((*in) & 0x80) != 0; diff --git a/Sources/BoringSSL/crypto/bn/ctx.c b/Sources/BoringSSL/crypto/bn/ctx.c index 48d9adf65..bca6619af 100644 --- a/Sources/BoringSSL/crypto/bn/ctx.c +++ b/Sources/BoringSSL/crypto/bn/ctx.c @@ -59,6 +59,8 @@ #include #include +#include "../internal.h" + /* How many bignums are in each "pool item"; */ #define BN_CTX_POOL_SIZE 16 @@ -218,7 +220,7 @@ static int BN_STACK_push(BN_STACK *st, unsigned int idx) { return 0; } if (st->depth) { - memcpy(newitems, st->indexes, st->depth * sizeof(unsigned int)); + OPENSSL_memcpy(newitems, st->indexes, st->depth * sizeof(unsigned int)); } OPENSSL_free(st->indexes); st->indexes = newitems; diff --git a/Sources/BoringSSL/crypto/bn/div.c b/Sources/BoringSSL/crypto/bn/div.c index 5a239bcee..de3fa1f1f 100644 --- a/Sources/BoringSSL/crypto/bn/div.c +++ b/Sources/BoringSSL/crypto/bn/div.c @@ -56,62 +56,139 @@ #include +#include #include + #include #include "internal.h" -#define asm __asm__ - -#if !defined(OPENSSL_NO_ASM) -# if defined(__GNUC__) && __GNUC__>=2 -# if defined(OPENSSL_X86) - /* - * There were two reasons for implementing this template: - * - GNU C generates a call to a function (__udivdi3 to be exact) - * in reply to ((((BN_ULLONG)n0)< - */ -#undef div_asm -# define div_asm(n0,n1,d0) \ - ({ asm volatile ( \ - "divl %4" \ - : "=a"(q), "=d"(rem) \ - : "a"(n1), "d"(n0), "g"(d0) \ - : "cc"); \ - q; \ - }) -# define REMAINDER_IS_ALREADY_CALCULATED -# elif defined(OPENSSL_X86_64) - /* - * Same story here, but it's 128-bit by 64-bit division. Wow! - * - */ -# undef div_asm -# define div_asm(n0,n1,d0) \ - ({ asm volatile ( \ - "divq %4" \ - : "=a"(q), "=d"(rem) \ - : "a"(n1), "d"(n0), "g"(d0) \ - : "cc"); \ - q; \ - }) -# define REMAINDER_IS_ALREADY_CALCULATED -# endif /* __ */ -# endif /* __GNUC__ */ -#endif /* OPENSSL_NO_ASM */ +#if !defined(BN_ULLONG) +/* bn_div_words divides a double-width |h|,|l| by |d| and returns the result, + * which must fit in a |BN_ULONG|. */ +static BN_ULONG bn_div_words(BN_ULONG h, BN_ULONG l, BN_ULONG d) { + BN_ULONG dh, dl, q, ret = 0, th, tl, t; + int i, count = 2; + + if (d == 0) { + return BN_MASK2; + } + + i = BN_num_bits_word(d); + assert((i == BN_BITS2) || (h <= (BN_ULONG)1 << i)); + + i = BN_BITS2 - i; + if (h >= d) { + h -= d; + } + + if (i) { + d <<= i; + h = (h << i) | (l >> (BN_BITS2 - i)); + l <<= i; + } + dh = (d & BN_MASK2h) >> BN_BITS4; + dl = (d & BN_MASK2l); + for (;;) { + if ((h >> BN_BITS4) == dh) { + q = BN_MASK2l; + } else { + q = h / dh; + } + + th = q * dh; + tl = dl * q; + for (;;) { + t = h - th; + if ((t & BN_MASK2h) || + ((tl) <= ((t << BN_BITS4) | ((l & BN_MASK2h) >> BN_BITS4)))) { + break; + } + q--; + th -= dh; + tl -= dl; + } + t = (tl >> BN_BITS4); + tl = (tl << BN_BITS4) & BN_MASK2h; + th += t; + + if (l < tl) { + th++; + } + l -= tl; + if (h < th) { + h += d; + q--; + } + h -= th; + + if (--count == 0) { + break; + } + + ret = q << BN_BITS4; + h = ((h << BN_BITS4) | (l >> BN_BITS4)) & BN_MASK2; + l = (l & BN_MASK2l) << BN_BITS4; + } + + ret |= q; + return ret; +} +#endif /* !defined(BN_ULLONG) */ + +static inline void bn_div_rem_words(BN_ULONG *quotient_out, BN_ULONG *rem_out, + BN_ULONG n0, BN_ULONG n1, BN_ULONG d0) { + /* GCC and Clang generate function calls to |__udivdi3| and |__umoddi3| when + * the |BN_ULLONG|-based C code is used. + * + * GCC bugs: + * * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=14224 + * * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=43721 + * * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54183 + * * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58897 + * * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65668 + * + * Clang bugs: + * * https://llvm.org/bugs/show_bug.cgi?id=6397 + * * https://llvm.org/bugs/show_bug.cgi?id=12418 + * + * These issues aren't specific to x86 and x86_64, so it might be worthwhile + * to add more assembly language implementations. */ +#if !defined(OPENSSL_NO_ASM) && defined(OPENSSL_X86) && defined(__GNUC__) + __asm__ volatile ( + "divl %4" + : "=a"(*quotient_out), "=d"(*rem_out) + : "a"(n1), "d"(n0), "rm"(d0) + : "cc" ); +#elif !defined(OPENSSL_NO_ASM) && defined(OPENSSL_X86_64) && defined(__GNUC__) + __asm__ volatile ( + "divq %4" + : "=a"(*quotient_out), "=d"(*rem_out) + : "a"(n1), "d"(n0), "rm"(d0) + : "cc" ); +#else +#if defined(BN_ULLONG) + BN_ULLONG n = (((BN_ULLONG)n0) << BN_BITS2) | n1; + *quotient_out = (BN_ULONG)(n / d0); +#else + *quotient_out = bn_div_words(n0, n1, d0); +#endif + *rem_out = n1 - (*quotient_out * d0); +#endif +} /* BN_div computes dv := num / divisor, rounding towards * zero, and sets up rm such that dv*divisor + rm = num holds. * Thus: * dv->neg == num->neg ^ divisor->neg (unless the result is zero) * rm->neg == num->neg (unless the remainder is zero) - * If 'dv' or 'rm' is NULL, the respective value is not returned. */ + * If 'dv' or 'rm' is NULL, the respective value is not returned. + * + * This was specifically designed to contain fewer branches that may leak + * sensitive information; see "New Branch Prediction Vulnerabilities in OpenSSL + * and Necessary Software Countermeasures" by Onur Acıçmez, Shay Gueron, and + * Jean-Pierre Seifert. */ int BN_div(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num, const BIGNUM *divisor, BN_CTX *ctx) { int norm_shift, i, loop; @@ -119,7 +196,6 @@ int BN_div(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num, const BIGNUM *divisor, BN_ULONG *resp, *wnump; BN_ULONG d0, d1; int num_n, div_n; - int no_branch = 0; /* Invalid zero-padding would have particularly bad consequences * so don't just rely on bn_check_top() here */ @@ -129,28 +205,11 @@ int BN_div(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num, const BIGNUM *divisor, return 0; } - if ((num->flags & BN_FLG_CONSTTIME) != 0 || - (divisor->flags & BN_FLG_CONSTTIME) != 0) { - no_branch = 1; - } - if (BN_is_zero(divisor)) { OPENSSL_PUT_ERROR(BN, BN_R_DIV_BY_ZERO); return 0; } - if (!no_branch && BN_ucmp(num, divisor) < 0) { - if (rm != NULL) { - if (BN_copy(rm, num) == NULL) { - return 0; - } - } - if (dv != NULL) { - BN_zero(dv); - } - return 1; - } - BN_CTX_start(ctx); tmp = BN_CTX_get(ctx); snum = BN_CTX_get(ctx); @@ -176,26 +235,23 @@ int BN_div(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num, const BIGNUM *divisor, } snum->neg = 0; - if (no_branch) { - /* Since we don't know whether snum is larger than sdiv, - * we pad snum with enough zeroes without changing its - * value. - */ - if (snum->top <= sdiv->top + 1) { - if (bn_wexpand(snum, sdiv->top + 2) == NULL) { - goto err; - } - for (i = snum->top; i < sdiv->top + 2; i++) { - snum->d[i] = 0; - } - snum->top = sdiv->top + 2; - } else { - if (bn_wexpand(snum, snum->top + 1) == NULL) { - goto err; - } - snum->d[snum->top] = 0; - snum->top++; + /* Since we don't want to have special-case logic for the case where snum is + * larger than sdiv, we pad snum with enough zeroes without changing its + * value. */ + if (snum->top <= sdiv->top + 1) { + if (bn_wexpand(snum, sdiv->top + 2) == NULL) { + goto err; } + for (i = snum->top; i < sdiv->top + 2; i++) { + snum->d[i] = 0; + } + snum->top = sdiv->top + 2; + } else { + if (bn_wexpand(snum, snum->top + 1) == NULL) { + goto err; + } + snum->d[snum->top] = 0; + snum->top++; } div_n = sdiv->top; @@ -223,7 +279,7 @@ int BN_div(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num, const BIGNUM *divisor, if (!bn_wexpand(res, (loop + 1))) { goto err; } - res->top = loop - no_branch; + res->top = loop - 1; resp = &(res->d[loop - 1]); /* space for temp */ @@ -231,15 +287,6 @@ int BN_div(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num, const BIGNUM *divisor, goto err; } - if (!no_branch) { - if (BN_ucmp(&wnum, sdiv) >= 0) { - bn_sub_words(wnum.d, wnum.d, sdiv->d, div_n); - *resp = 1; - } else { - res->top--; - } - } - /* if res->top == 0 then clear the neg value otherwise decrease * the resp pointer */ if (res->top == 0) { @@ -260,23 +307,10 @@ int BN_div(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num, const BIGNUM *divisor, q = BN_MASK2; } else { /* n0 < d0 */ -#ifdef BN_ULLONG - BN_ULLONG t2; - -#if defined(BN_ULLONG) && !defined(div_asm) - q = (BN_ULONG)(((((BN_ULLONG)n0) << BN_BITS2) | n1) / d0); -#else - q = div_asm(n0, n1, d0); -#endif - -#ifndef REMAINDER_IS_ALREADY_CALCULATED - /* rem doesn't have to be BN_ULLONG. The least we know it's less that d0, - * isn't it? */ - rem = (n1 - q * d0) & BN_MASK2; -#endif - - t2 = (BN_ULLONG)d1 * q; + bn_div_rem_words(&q, &rem, n0, n1, d0); +#ifdef BN_ULLONG + BN_ULLONG t2 = (BN_ULLONG)d1 * q; for (;;) { if (t2 <= ((((BN_ULLONG)rem) << BN_BITS2) | wnump[-2])) { break; @@ -290,13 +324,7 @@ int BN_div(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num, const BIGNUM *divisor, } #else /* !BN_ULLONG */ BN_ULONG t2l, t2h; - - q = bn_div_words(n0, n1, d0); - - rem = (n1 - q * d0) & BN_MASK2; - BN_UMULT_LOHI(t2l, t2h, d1, q); - for (;;) { if ((t2h < rem) || ((t2h == rem) && (t2l <= wnump[-2]))) { break; @@ -349,9 +377,7 @@ int BN_div(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num, const BIGNUM *divisor, rm->neg = neg; } } - if (no_branch) { - bn_correct_top(res); - } + bn_correct_top(res); BN_CTX_end(ctx); return 1; @@ -556,7 +582,7 @@ BN_ULONG BN_div_word(BIGNUM *a, BN_ULONG w) { return 0; } - /* normalize input (so bn_div_words doesn't complain) */ + /* normalize input for |bn_div_rem_words|. */ j = BN_BITS2 - BN_num_bits_word(w); w <<= j; if (!BN_lshift(a, a, j)) { @@ -564,10 +590,10 @@ BN_ULONG BN_div_word(BIGNUM *a, BN_ULONG w) { } for (i = a->top - 1; i >= 0; i--) { - BN_ULONG l, d; - - l = a->d[i]; - d = bn_div_words(ret, l, w); + BN_ULONG l = a->d[i]; + BN_ULONG d; + BN_ULONG unused_rem; + bn_div_rem_words(&d, &unused_rem, ret, l, w); ret = (l - ((d * w) & BN_MASK2)) & BN_MASK2; a->d[i] = d; } @@ -576,6 +602,10 @@ BN_ULONG BN_div_word(BIGNUM *a, BN_ULONG w) { a->top--; } + if (a->top == 0) { + a->neg = 0; + } + ret >>= j; return ret; } @@ -592,6 +622,20 @@ BN_ULONG BN_mod_word(const BIGNUM *a, BN_ULONG w) { return (BN_ULONG) -1; } +#ifndef BN_ULLONG + /* If |w| is too long and we don't have |BN_ULLONG| then we need to fall back + * to using |BN_div_word|. */ + if (w > ((BN_ULONG)1 << BN_BITS4)) { + BIGNUM *tmp = BN_dup(a); + if (tmp == NULL) { + return (BN_ULONG)-1; + } + ret = BN_div_word(tmp, w); + BN_free(tmp); + return ret; + } +#endif + w &= BN_MASK2; for (i = a->top - 1; i >= 0; i--) { #ifndef BN_ULLONG @@ -603,3 +647,82 @@ BN_ULONG BN_mod_word(const BIGNUM *a, BN_ULONG w) { } return (BN_ULONG)ret; } + +int BN_mod_pow2(BIGNUM *r, const BIGNUM *a, size_t e) { + if (e == 0 || a->top == 0) { + BN_zero(r); + return 1; + } + + size_t num_words = 1 + ((e - 1) / BN_BITS2); + + /* If |a| definitely has less than |e| bits, just BN_copy. */ + if ((size_t) a->top < num_words) { + return BN_copy(r, a) != NULL; + } + + /* Otherwise, first make sure we have enough space in |r|. + * Note that this will fail if num_words > INT_MAX. */ + if (bn_wexpand(r, num_words) == NULL) { + return 0; + } + + /* Copy the content of |a| into |r|. */ + OPENSSL_memcpy(r->d, a->d, num_words * sizeof(BN_ULONG)); + + /* If |e| isn't word-aligned, we have to mask off some of our bits. */ + size_t top_word_exponent = e % (sizeof(BN_ULONG) * 8); + if (top_word_exponent != 0) { + r->d[num_words - 1] &= (((BN_ULONG) 1) << top_word_exponent) - 1; + } + + /* Fill in the remaining fields of |r|. */ + r->neg = a->neg; + r->top = (int) num_words; + bn_correct_top(r); + return 1; +} + +int BN_nnmod_pow2(BIGNUM *r, const BIGNUM *a, size_t e) { + if (!BN_mod_pow2(r, a, e)) { + return 0; + } + + /* If the returned value was non-negative, we're done. */ + if (BN_is_zero(r) || !r->neg) { + return 1; + } + + size_t num_words = 1 + (e - 1) / BN_BITS2; + + /* Expand |r| to the size of our modulus. */ + if (bn_wexpand(r, num_words) == NULL) { + return 0; + } + + /* Clear the upper words of |r|. */ + OPENSSL_memset(&r->d[r->top], 0, (num_words - r->top) * BN_BYTES); + + /* Set parameters of |r|. */ + r->neg = 0; + r->top = (int) num_words; + + /* Now, invert every word. The idea here is that we want to compute 2^e-|x|, + * which is actually equivalent to the twos-complement representation of |x| + * in |e| bits, which is -x = ~x + 1. */ + for (int i = 0; i < r->top; i++) { + r->d[i] = ~r->d[i]; + } + + /* If our exponent doesn't span the top word, we have to mask the rest. */ + size_t top_word_exponent = e % BN_BITS2; + if (top_word_exponent != 0) { + r->d[r->top - 1] &= (((BN_ULONG) 1) << top_word_exponent) - 1; + } + + /* Keep the correct_top invariant for BN_add. */ + bn_correct_top(r); + + /* Finally, add one, for the reason described above. */ + return BN_add(r, r, BN_value_one()); +} diff --git a/Sources/BoringSSL/crypto/bn/exponentiation.c b/Sources/BoringSSL/crypto/bn/exponentiation.c index f7100ac3c..933a731c0 100644 --- a/Sources/BoringSSL/crypto/bn/exponentiation.c +++ b/Sources/BoringSSL/crypto/bn/exponentiation.c @@ -140,12 +140,6 @@ int BN_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx) { int i, bits, ret = 0; BIGNUM *v, *rr; - if ((p->flags & BN_FLG_CONSTTIME) != 0) { - /* BN_FLG_CONSTTIME only supported by BN_mod_exp_mont() */ - OPENSSL_PUT_ERROR(BN, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); - return 0; - } - BN_CTX_start(ctx); if (r == a || r == p) { rr = BN_CTX_get(ctx); @@ -209,6 +203,7 @@ static void BN_RECP_CTX_init(BN_RECP_CTX *recp) { BN_init(&recp->N); BN_init(&recp->Nr); recp->num_bits = 0; + recp->shift = 0; recp->flags = 0; } @@ -436,12 +431,6 @@ static int mod_exp_recp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, BIGNUM *val[TABLE_SIZE]; BN_RECP_CTX recp; - if (BN_get_flags(p, BN_FLG_CONSTTIME) != 0) { - /* BN_FLG_CONSTTIME only supported by BN_mod_exp_mont() */ - OPENSSL_PUT_ERROR(BN, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); - return 0; - } - bits = BN_num_bits(p); if (bits == 0) { @@ -575,41 +564,7 @@ static int mod_exp_recp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, int BN_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx) { - /* For even modulus m = 2^k*m_odd, it might make sense to compute - * a^p mod m_odd and a^p mod 2^k separately (with Montgomery - * exponentiation for the odd part), using appropriate exponent - * reductions, and combine the results using the CRT. - * - * For now, we use Montgomery only if the modulus is odd; otherwise, - * exponentiation using the reciprocal-based quick remaindering - * algorithm is used. - * - * (Timing obtained with expspeed.c [computations a^p mod m - * where a, p, m are of the same length: 256, 512, 1024, 2048, - * 4096, 8192 bits], compared to the running time of the - * standard algorithm: - * - * BN_mod_exp_mont 33 .. 40 % [AMD K6-2, Linux, debug configuration] - * 55 .. 77 % [UltraSparc processor, but - * debug-solaris-sparcv8-gcc conf.] - * - * BN_mod_exp_recp 50 .. 70 % [AMD K6-2, Linux, debug configuration] - * 62 .. 118 % [UltraSparc, debug-solaris-sparcv8-gcc] - * - * On the Sparc, BN_mod_exp_recp was faster than BN_mod_exp_mont - * at 2048 and more bits, but at 512 and 1024 bits, it was - * slower even than the standard algorithm! - * - * "Real" timings [linux-elf, solaris-sparcv9-gcc configurations] - * should be obtained when the new Montgomery reduction code - * has been integrated into OpenSSL.) */ - if (BN_is_odd(m)) { - if (a->top == 1 && !a->neg && BN_get_flags(p, BN_FLG_CONSTTIME) == 0) { - BN_ULONG A = a->d[0]; - return BN_mod_exp_mont_word(r, A, p, m, ctx, NULL); - } - return BN_mod_exp_mont(r, a, p, m, ctx, NULL); } @@ -626,10 +581,6 @@ int BN_mod_exp_mont(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p, BIGNUM *val[TABLE_SIZE]; BN_MONT_CTX *new_mont = NULL; - if (BN_get_flags(p, BN_FLG_CONSTTIME) != 0) { - return BN_mod_exp_mont_consttime(rr, a, p, m, ctx, mont); - } - if (!BN_is_odd(m)) { OPENSSL_PUT_ERROR(BN, BN_R_CALLED_WITH_EVEN_MODULUS); return 0; @@ -787,29 +738,65 @@ int BN_mod_exp_mont(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p, * pattern as far as cache lines are concerned. The following functions are * used to transfer a BIGNUM from/to that table. */ static int copy_to_prebuf(const BIGNUM *b, int top, unsigned char *buf, int idx, - int width) { - size_t i, j; + int window) { + int i, j; + const int width = 1 << window; + BN_ULONG *table = (BN_ULONG *) buf; if (top > b->top) { top = b->top; /* this works because 'buf' is explicitly zeroed */ } - for (i = 0, j = idx; i < top * sizeof b->d[0]; i++, j += width) { - buf[j] = ((unsigned char *)b->d)[i]; + + for (i = 0, j = idx; i < top; i++, j += width) { + table[j] = b->d[i]; } return 1; } static int copy_from_prebuf(BIGNUM *b, int top, unsigned char *buf, int idx, - int width) { - size_t i, j; + int window) { + int i, j; + const int width = 1 << window; + volatile BN_ULONG *table = (volatile BN_ULONG *)buf; if (bn_wexpand(b, top) == NULL) { return 0; } - for (i = 0, j = idx; i < top * sizeof b->d[0]; i++, j += width) { - ((unsigned char *)b->d)[i] = buf[j]; + if (window <= 3) { + for (i = 0; i < top; i++, table += width) { + BN_ULONG acc = 0; + + for (j = 0; j < width; j++) { + acc |= table[j] & ((BN_ULONG)0 - (constant_time_eq_int(j, idx) & 1)); + } + + b->d[i] = acc; + } + } else { + int xstride = 1 << (window - 2); + BN_ULONG y0, y1, y2, y3; + + i = idx >> (window - 2); /* equivalent of idx / xstride */ + idx &= xstride - 1; /* equivalent of idx % xstride */ + + y0 = (BN_ULONG)0 - (constant_time_eq_int(i, 0) & 1); + y1 = (BN_ULONG)0 - (constant_time_eq_int(i, 1) & 1); + y2 = (BN_ULONG)0 - (constant_time_eq_int(i, 2) & 1); + y3 = (BN_ULONG)0 - (constant_time_eq_int(i, 3) & 1); + + for (i = 0; i < top; i++, table += width) { + BN_ULONG acc = 0; + + for (j = 0; j < xstride; j++) { + acc |= ((table[j + 0 * xstride] & y0) | (table[j + 1 * xstride] & y1) | + (table[j + 2 * xstride] & y2) | (table[j + 3 * xstride] & y3)) & + ((BN_ULONG)0 - (constant_time_eq_int(j, idx) & 1)); + } + + b->d[i] = acc; + } } b->top = top; @@ -873,6 +860,7 @@ int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p, int powerbufLen = 0; unsigned char *powerbuf = NULL; BIGNUM tmp, am; + BIGNUM *new_a = NULL; if (!BN_is_odd(m)) { OPENSSL_PUT_ERROR(BN, BN_R_CALLED_WITH_EVEN_MODULUS); @@ -891,8 +879,6 @@ int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p, return BN_one(rr); } - BN_CTX_start(ctx); - /* Allocate a montgomery context if it was not supplied by the caller. */ if (mont == NULL) { new_mont = BN_MONT_CTX_new(); @@ -902,6 +888,15 @@ int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p, mont = new_mont; } + if (a->neg || BN_ucmp(a, m) >= 0) { + new_a = BN_new(); + if (new_a == NULL || + !BN_nnmod(new_a, a, m, ctx)) { + goto err; + } + a = new_a; + } + #ifdef RSAZ_ENABLED /* If the size of the operands allow it, perform the optimized * RSAZ exponentiation. For further information see @@ -917,16 +912,6 @@ int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p, bn_correct_top(rr); ret = 1; goto err; - } else if ((8 == a->top) && (8 == p->top) && (BN_num_bits(m) == 512)) { - if (NULL == bn_wexpand(rr, 8)) { - goto err; - } - RSAZ_512_mod_exp(rr->d, a->d, p->d, m->d, mont->n0[0], mont->RR.d); - rr->top = 8; - rr->neg = 0; - bn_correct_top(rr); - ret = 1; - goto err; } #endif @@ -935,9 +920,8 @@ int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p, #if defined(OPENSSL_BN_ASM_MONT5) if (window >= 5) { window = 5; /* ~5% improvement for RSA2048 sign, and even for RSA4096 */ - if ((top & 7) == 0) { - powerbufLen += 2 * top * sizeof(m->d[0]); - } + /* reserve space for mont->N.d[] copy */ + powerbufLen += top * sizeof(mont->N.d[0]); } #endif @@ -961,7 +945,7 @@ int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p, } powerbuf = MOD_EXP_CTIME_ALIGN(powerbufFree); - memset(powerbuf, 0, powerbufLen); + OPENSSL_memset(powerbuf, 0, powerbufLen); #ifdef alloca if (powerbufLen < 3072) { @@ -991,12 +975,9 @@ int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p, } /* prepare a^1 in Montgomery domain */ - if (a->neg || BN_ucmp(a, m) >= 0) { - if (!BN_mod(&am, a, m, ctx) || - !BN_to_montgomery(&am, &am, mont, ctx)) { - goto err; - } - } else if (!BN_to_montgomery(&am, a, mont, ctx)) { + assert(!a->neg); + assert(BN_ucmp(a, m) < 0); + if (!BN_to_montgomery(&am, a, mont, ctx)) { goto err; } @@ -1008,7 +989,8 @@ int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p, /* Dedicated window==4 case improves 512-bit RSA sign by ~15%, but as * 512-bit RSA is hardly relevant, we omit it to spare size... */ if (window == 5 && top > 1) { - const BN_ULONG *np = mont->N.d, *n0 = mont->n0, *np2; + const BN_ULONG *n0 = mont->n0; + BN_ULONG *np; /* BN_to_montgomery can contaminate words above .top * [in BN_DEBUG[_DEBUG] build]... */ @@ -1019,14 +1001,9 @@ int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p, tmp.d[i] = 0; } - if (top & 7) { - np2 = np; - } else { - BN_ULONG *np_double = am.d + top; - for (i = 0; i < top; i++) { - np_double[2 * i] = np[i]; - } - np2 = np_double; + /* copy mont->N.d[] to improve cache locality */ + for (np = am.d + top, i = 0; i < top; i++) { + np[i] = mont->N.d[i]; } bn_scatter5(tmp.d, top, powerbuf, 0); @@ -1041,7 +1018,7 @@ int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p, } for (i = 3; i < 8; i += 2) { int j; - bn_mul_mont_gather5(tmp.d, am.d, powerbuf, np2, n0, top, i - 1); + bn_mul_mont_gather5(tmp.d, am.d, powerbuf, np, n0, top, i - 1); bn_scatter5(tmp.d, top, powerbuf, i); for (j = 2 * i; j < 32; j *= 2) { bn_mul_mont(tmp.d, tmp.d, tmp.d, np, n0, top); @@ -1049,13 +1026,13 @@ int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p, } } for (; i < 16; i += 2) { - bn_mul_mont_gather5(tmp.d, am.d, powerbuf, np2, n0, top, i - 1); + bn_mul_mont_gather5(tmp.d, am.d, powerbuf, np, n0, top, i - 1); bn_scatter5(tmp.d, top, powerbuf, i); bn_mul_mont(tmp.d, tmp.d, tmp.d, np, n0, top); bn_scatter5(tmp.d, top, powerbuf, 2 * i); } for (; i < 32; i += 2) { - bn_mul_mont_gather5(tmp.d, am.d, powerbuf, np2, n0, top, i - 1); + bn_mul_mont_gather5(tmp.d, am.d, powerbuf, np, n0, top, i - 1); bn_scatter5(tmp.d, top, powerbuf, i); } @@ -1103,7 +1080,7 @@ int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p, wvalue >>= (bits - 4) & 7; wvalue &= 0x1f; bits -= 5; - bn_power5(tmp.d, tmp.d, powerbuf, np2, n0, top, wvalue); + bn_power5(tmp.d, tmp.d, powerbuf, np, n0, top, wvalue); } while (bits >= 0) { /* Read five bits from |bits-4| through |bits|, inclusive. */ @@ -1112,11 +1089,11 @@ int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p, wvalue >>= first_bit & 7; wvalue &= 0x1f; bits -= 5; - bn_power5(tmp.d, tmp.d, powerbuf, np2, n0, top, wvalue); + bn_power5(tmp.d, tmp.d, powerbuf, np, n0, top, wvalue); } } - ret = bn_from_montgomery(tmp.d, tmp.d, NULL, np2, n0, top); + ret = bn_from_montgomery(tmp.d, tmp.d, NULL, np, n0, top); tmp.top = top; bn_correct_top(&tmp); if (ret) { @@ -1128,8 +1105,8 @@ int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p, } else #endif { - if (!copy_to_prebuf(&tmp, top, powerbuf, 0, numPowers) || - !copy_to_prebuf(&am, top, powerbuf, 1, numPowers)) { + if (!copy_to_prebuf(&tmp, top, powerbuf, 0, window) || + !copy_to_prebuf(&am, top, powerbuf, 1, window)) { goto err; } @@ -1140,13 +1117,13 @@ int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p, */ if (window > 1) { if (!BN_mod_mul_montgomery(&tmp, &am, &am, mont, ctx) || - !copy_to_prebuf(&tmp, top, powerbuf, 2, numPowers)) { + !copy_to_prebuf(&tmp, top, powerbuf, 2, window)) { goto err; } for (i = 3; i < numPowers; i++) { /* Calculate a^i = a^(i-1) * a */ if (!BN_mod_mul_montgomery(&tmp, &am, &tmp, mont, ctx) || - !copy_to_prebuf(&tmp, top, powerbuf, i, numPowers)) { + !copy_to_prebuf(&tmp, top, powerbuf, i, window)) { goto err; } } @@ -1156,7 +1133,7 @@ int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p, for (wvalue = 0, i = bits % window; i >= 0; i--, bits--) { wvalue = (wvalue << 1) + BN_is_bit_set(p, bits); } - if (!copy_from_prebuf(&tmp, top, powerbuf, wvalue, numPowers)) { + if (!copy_from_prebuf(&tmp, top, powerbuf, wvalue, window)) { goto err; } @@ -1175,7 +1152,7 @@ int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p, } /* Fetch the appropriate pre-computed value from the pre-buf */ - if (!copy_from_prebuf(&am, top, powerbuf, wvalue, numPowers)) { + if (!copy_from_prebuf(&am, top, powerbuf, wvalue, window)) { goto err; } @@ -1194,162 +1171,32 @@ int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p, err: BN_MONT_CTX_free(new_mont); + BN_clear_free(new_a); if (powerbuf != NULL) { OPENSSL_cleanse(powerbuf, powerbufLen); OPENSSL_free(powerbufFree); } - BN_CTX_end(ctx); return (ret); } int BN_mod_exp_mont_word(BIGNUM *rr, BN_ULONG a, const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx, const BN_MONT_CTX *mont) { - BN_MONT_CTX *new_mont = NULL; - int b, bits, ret = 0; - int r_is_one; - BN_ULONG w, next_w; - BIGNUM *d, *r, *t; - BIGNUM *swap_tmp; -#define BN_MOD_MUL_WORD(r, w, m) \ - (BN_mul_word(r, (w)) && \ - (/* BN_ucmp(r, (m)) < 0 ? 1 :*/ \ - (BN_mod(t, r, m, ctx) && (swap_tmp = r, r = t, t = swap_tmp, 1)))) - /* BN_MOD_MUL_WORD is only used with 'w' large, so the BN_ucmp test is - * probably more overhead than always using BN_mod (which uses BN_copy if a - * similar test returns true). We can use BN_mod and do not need BN_nnmod - * because our accumulator is never negative (the result of BN_mod does not - * depend on the sign of the modulus). */ -#define BN_TO_MONTGOMERY_WORD(r, w, mont) \ - (BN_set_word(r, (w)) && BN_to_montgomery(r, r, (mont), ctx)) - - if (BN_get_flags(p, BN_FLG_CONSTTIME) != 0) { - /* BN_FLG_CONSTTIME only supported by BN_mod_exp_mont() */ - OPENSSL_PUT_ERROR(BN, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); - return 0; - } - - if (!BN_is_odd(m)) { - OPENSSL_PUT_ERROR(BN, BN_R_CALLED_WITH_EVEN_MODULUS); - return 0; - } - - if (m->top == 1) { - a %= m->d[0]; /* make sure that 'a' is reduced */ - } + BIGNUM a_bignum; + BN_init(&a_bignum); - bits = BN_num_bits(p); - if (bits == 0) { - /* x**0 mod 1 is still zero. */ - if (BN_is_one(m)) { - BN_zero(rr); - return 1; - } - return BN_one(rr); - } - if (a == 0) { - BN_zero(rr); - return 1; - } + int ret = 0; - BN_CTX_start(ctx); - d = BN_CTX_get(ctx); - r = BN_CTX_get(ctx); - t = BN_CTX_get(ctx); - if (d == NULL || r == NULL || t == NULL) { + if (!BN_set_word(&a_bignum, a)) { + OPENSSL_PUT_ERROR(BN, ERR_R_INTERNAL_ERROR); goto err; } - /* Allocate a montgomery context if it was not supplied by the caller. */ - if (mont == NULL) { - new_mont = BN_MONT_CTX_new(); - if (new_mont == NULL || !BN_MONT_CTX_set(new_mont, m, ctx)) { - goto err; - } - mont = new_mont; - } - - r_is_one = 1; /* except for Montgomery factor */ - - /* bits-1 >= 0 */ - - /* The result is accumulated in the product r*w. */ - w = a; /* bit 'bits-1' of 'p' is always set */ - for (b = bits - 2; b >= 0; b--) { - /* First, square r*w. */ - next_w = w * w; - if ((next_w / w) != w) { - /* overflow */ - if (r_is_one) { - if (!BN_TO_MONTGOMERY_WORD(r, w, mont)) { - goto err; - } - r_is_one = 0; - } else { - if (!BN_MOD_MUL_WORD(r, w, m)) { - goto err; - } - } - next_w = 1; - } - - w = next_w; - if (!r_is_one) { - if (!BN_mod_mul_montgomery(r, r, r, mont, ctx)) { - goto err; - } - } - - /* Second, multiply r*w by 'a' if exponent bit is set. */ - if (BN_is_bit_set(p, b)) { - next_w = w * a; - if ((next_w / a) != w) { - /* overflow */ - if (r_is_one) { - if (!BN_TO_MONTGOMERY_WORD(r, w, mont)) { - goto err; - } - r_is_one = 0; - } else { - if (!BN_MOD_MUL_WORD(r, w, m)) { - goto err; - } - } - next_w = a; - } - w = next_w; - } - } - - /* Finally, set r:=r*w. */ - if (w != 1) { - if (r_is_one) { - if (!BN_TO_MONTGOMERY_WORD(r, w, mont)) { - goto err; - } - r_is_one = 0; - } else { - if (!BN_MOD_MUL_WORD(r, w, m)) { - goto err; - } - } - } - - if (r_is_one) { - /* can happen only if a == 1*/ - if (!BN_one(rr)) { - goto err; - } - } else { - if (!BN_from_montgomery(rr, r, mont, ctx)) { - goto err; - } - } - ret = 1; + ret = BN_mod_exp_mont(rr, &a_bignum, p, m, ctx, mont); err: - BN_MONT_CTX_free(new_mont); - BN_CTX_end(ctx); + BN_free(&a_bignum); + return ret; } @@ -1358,36 +1205,11 @@ int BN_mod_exp_mont_word(BIGNUM *rr, BN_ULONG a, const BIGNUM *p, int BN_mod_exp2_mont(BIGNUM *rr, const BIGNUM *a1, const BIGNUM *p1, const BIGNUM *a2, const BIGNUM *p2, const BIGNUM *m, BN_CTX *ctx, const BN_MONT_CTX *mont) { - int i, j, bits, b, bits1, bits2, ret = 0, wpos1, wpos2, window1, window2, - wvalue1, wvalue2; - int r_is_one = 1; - BIGNUM *d, *r; - const BIGNUM *a_mod_m; - /* Tables of variables obtained from 'ctx' */ - BIGNUM *val1[TABLE_SIZE], *val2[TABLE_SIZE]; - BN_MONT_CTX *new_mont = NULL; + BIGNUM tmp; + BN_init(&tmp); - if (!(m->d[0] & 1)) { - OPENSSL_PUT_ERROR(BN, BN_R_CALLED_WITH_EVEN_MODULUS); - return 0; - } - bits1 = BN_num_bits(p1); - bits2 = BN_num_bits(p2); - if (bits1 == 0 && bits2 == 0) { - ret = BN_one(rr); - return ret; - } - - bits = (bits1 > bits2) ? bits1 : bits2; - - BN_CTX_start(ctx); - d = BN_CTX_get(ctx); - r = BN_CTX_get(ctx); - val1[0] = BN_CTX_get(ctx); - val2[0] = BN_CTX_get(ctx); - if (!d || !r || !val1[0] || !val2[0]) { - goto err; - } + int ret = 0; + BN_MONT_CTX *new_mont = NULL; /* Allocate a montgomery context if it was not supplied by the caller. */ if (mont == NULL) { @@ -1398,156 +1220,21 @@ int BN_mod_exp2_mont(BIGNUM *rr, const BIGNUM *a1, const BIGNUM *p1, mont = new_mont; } - window1 = BN_window_bits_for_exponent_size(bits1); - window2 = BN_window_bits_for_exponent_size(bits2); - - /* Build table for a1: val1[i] := a1^(2*i + 1) mod m for i = 0 .. - * 2^(window1-1) */ - if (a1->neg || BN_ucmp(a1, m) >= 0) { - if (!BN_mod(val1[0], a1, m, ctx)) { - goto err; - } - a_mod_m = val1[0]; - } else { - a_mod_m = a1; - } - - if (BN_is_zero(a_mod_m)) { - BN_zero(rr); - ret = 1; - goto err; - } - - if (!BN_to_montgomery(val1[0], a_mod_m, mont, ctx)) { - goto err; - } - - if (window1 > 1) { - if (!BN_mod_mul_montgomery(d, val1[0], val1[0], mont, ctx)) { - goto err; - } - - j = 1 << (window1 - 1); - for (i = 1; i < j; i++) { - if (((val1[i] = BN_CTX_get(ctx)) == NULL) || - !BN_mod_mul_montgomery(val1[i], val1[i - 1], d, mont, ctx)) { - goto err; - } - } - } - - /* Build table for a2: val2[i] := a2^(2*i + 1) mod m for i = 0 .. - * 2^(window2-1) */ - if (a2->neg || BN_ucmp(a2, m) >= 0) { - if (!BN_mod(val2[0], a2, m, ctx)) { - goto err; - } - a_mod_m = val2[0]; - } else { - a_mod_m = a2; - } - - if (BN_is_zero(a_mod_m)) { - BN_zero(rr); - ret = 1; - goto err; - } - - if (!BN_to_montgomery(val2[0], a_mod_m, mont, ctx)) { - goto err; - } - - if (window2 > 1) { - if (!BN_mod_mul_montgomery(d, val2[0], val2[0], mont, ctx)) { - goto err; - } - - j = 1 << (window2 - 1); - for (i = 1; i < j; i++) { - if (((val2[i] = BN_CTX_get(ctx)) == NULL) || - !BN_mod_mul_montgomery(val2[i], val2[i - 1], d, mont, ctx)) { - goto err; - } - } - } - - /* Now compute the power product, using independent windows. */ - r_is_one = 1; - wvalue1 = 0; /* The 'value' of the first window */ - wvalue2 = 0; /* The 'value' of the second window */ - wpos1 = 0; /* If wvalue1 > 0, the bottom bit of the first window */ - wpos2 = 0; /* If wvalue2 > 0, the bottom bit of the second window */ - - if (!BN_to_montgomery(r, BN_value_one(), mont, ctx)) { + /* BN_mod_mul_montgomery removes one Montgomery factor, so passing one + * Montgomery-encoded and one non-Montgomery-encoded value gives a + * non-Montgomery-encoded result. */ + if (!BN_mod_exp_mont(rr, a1, p1, m, ctx, mont) || + !BN_mod_exp_mont(&tmp, a2, p2, m, ctx, mont) || + !BN_to_montgomery(rr, rr, mont, ctx) || + !BN_mod_mul_montgomery(rr, rr, &tmp, mont, ctx)) { goto err; } - for (b = bits - 1; b >= 0; b--) { - if (!r_is_one) { - if (!BN_mod_mul_montgomery(r, r, r, mont, ctx)) { - goto err; - } - } - - if (!wvalue1 && BN_is_bit_set(p1, b)) { - /* consider bits b-window1+1 .. b for this window */ - i = b - window1 + 1; - /* works for i<0 */ - while (!BN_is_bit_set(p1, i)) { - i++; - } - wpos1 = i; - wvalue1 = 1; - for (i = b - 1; i >= wpos1; i--) { - wvalue1 <<= 1; - if (BN_is_bit_set(p1, i)) { - wvalue1++; - } - } - } - - if (!wvalue2 && BN_is_bit_set(p2, b)) { - /* consider bits b-window2+1 .. b for this window */ - i = b - window2 + 1; - while (!BN_is_bit_set(p2, i)) { - i++; - } - wpos2 = i; - wvalue2 = 1; - for (i = b - 1; i >= wpos2; i--) { - wvalue2 <<= 1; - if (BN_is_bit_set(p2, i)) { - wvalue2++; - } - } - } - - if (wvalue1 && b == wpos1) { - /* wvalue1 is odd and < 2^window1 */ - if (!BN_mod_mul_montgomery(r, r, val1[wvalue1 >> 1], mont, ctx)) { - goto err; - } - wvalue1 = 0; - r_is_one = 0; - } - - if (wvalue2 && b == wpos2) { - /* wvalue2 is odd and < 2^window2 */ - if (!BN_mod_mul_montgomery(r, r, val2[wvalue2 >> 1], mont, ctx)) { - goto err; - } - wvalue2 = 0; - r_is_one = 0; - } - } - - if (!BN_from_montgomery(rr, r, mont, ctx)) { - goto err; - } ret = 1; err: BN_MONT_CTX_free(new_mont); - BN_CTX_end(ctx); + BN_free(&tmp); + return ret; } diff --git a/Sources/BoringSSL/crypto/bn/gcd.c b/Sources/BoringSSL/crypto/bn/gcd.c index 41ca6d21e..7c20b8e2b 100644 --- a/Sources/BoringSSL/crypto/bn/gcd.c +++ b/Sources/BoringSSL/crypto/bn/gcd.c @@ -108,6 +108,8 @@ #include +#include + #include #include "internal.h" @@ -223,54 +225,44 @@ int BN_gcd(BIGNUM *r, const BIGNUM *in_a, const BIGNUM *in_b, BN_CTX *ctx) { } /* solves ax == 1 (mod n) */ -static BIGNUM *BN_mod_inverse_no_branch(BIGNUM *out, int *out_no_inverse, - const BIGNUM *a, const BIGNUM *n, - BN_CTX *ctx); - -BIGNUM *BN_mod_inverse_ex(BIGNUM *out, int *out_no_inverse, const BIGNUM *a, - const BIGNUM *n, BN_CTX *ctx) { - BIGNUM *A, *B, *X, *Y, *M, *D, *T, *R = NULL; - BIGNUM *ret = NULL; - int sign; +static int bn_mod_inverse_general(BIGNUM *out, int *out_no_inverse, + const BIGNUM *a, const BIGNUM *n, + BN_CTX *ctx); + +int BN_mod_inverse_odd(BIGNUM *out, int *out_no_inverse, const BIGNUM *a, + const BIGNUM *n, BN_CTX *ctx) { + *out_no_inverse = 0; - if ((a->flags & BN_FLG_CONSTTIME) != 0 || - (n->flags & BN_FLG_CONSTTIME) != 0) { - return BN_mod_inverse_no_branch(out, out_no_inverse, a, n, ctx); + if (!BN_is_odd(n)) { + OPENSSL_PUT_ERROR(BN, BN_R_CALLED_WITH_EVEN_MODULUS); + return 0; } - *out_no_inverse = 0; + if (BN_is_negative(a) || BN_cmp(a, n) >= 0) { + OPENSSL_PUT_ERROR(BN, BN_R_INPUT_NOT_REDUCED); + return 0; + } + + BIGNUM *A, *B, *X, *Y; + int ret = 0; + int sign; BN_CTX_start(ctx); A = BN_CTX_get(ctx); B = BN_CTX_get(ctx); X = BN_CTX_get(ctx); - D = BN_CTX_get(ctx); - M = BN_CTX_get(ctx); Y = BN_CTX_get(ctx); - T = BN_CTX_get(ctx); - if (T == NULL) { + if (Y == NULL) { goto err; } - if (out == NULL) { - R = BN_new(); - } else { - R = out; - } - if (R == NULL) { - goto err; - } + BIGNUM *R = out; BN_zero(Y); if (!BN_one(X) || BN_copy(B, a) == NULL || BN_copy(A, n) == NULL) { goto err; } A->neg = 0; - if (B->neg || (BN_ucmp(B, A) >= 0)) { - if (!BN_nnmod(B, B, A, ctx)) { - goto err; - } - } sign = -1; /* From B = a mod |n|, A = |n| it follows that * @@ -279,227 +271,101 @@ BIGNUM *BN_mod_inverse_ex(BIGNUM *out, int *out_no_inverse, const BIGNUM *a, * sign*Y*a == A (mod |n|). */ - if (BN_is_odd(n) && (BN_num_bits(n) <= (BN_BITS2 <= 32 ? 450 : 2048))) { - /* Binary inversion algorithm; requires odd modulus. - * This is faster than the general algorithm if the modulus - * is sufficiently small (about 400 .. 500 bits on 32-bit - * sytems, but much more on 64-bit systems) */ - int shift; - - while (!BN_is_zero(B)) { - /* 0 < B < |n|, - * 0 < A <= |n|, - * (1) -sign*X*a == B (mod |n|), - * (2) sign*Y*a == A (mod |n|) */ - - /* Now divide B by the maximum possible power of two in the integers, - * and divide X by the same value mod |n|. - * When we're done, (1) still holds. */ - shift = 0; - while (!BN_is_bit_set(B, shift)) { - /* note that 0 < B */ - shift++; - - if (BN_is_odd(X)) { - if (!BN_uadd(X, X, n)) { - goto err; - } - } - /* now X is even, so we can easily divide it by two */ - if (!BN_rshift1(X, X)) { + /* Binary inversion algorithm; requires odd modulus. This is faster than the + * general algorithm if the modulus is sufficiently small (about 400 .. 500 + * bits on 32-bit systems, but much more on 64-bit systems) */ + int shift; + + while (!BN_is_zero(B)) { + /* 0 < B < |n|, + * 0 < A <= |n|, + * (1) -sign*X*a == B (mod |n|), + * (2) sign*Y*a == A (mod |n|) */ + + /* Now divide B by the maximum possible power of two in the integers, + * and divide X by the same value mod |n|. + * When we're done, (1) still holds. */ + shift = 0; + while (!BN_is_bit_set(B, shift)) { + /* note that 0 < B */ + shift++; + + if (BN_is_odd(X)) { + if (!BN_uadd(X, X, n)) { goto err; } } - if (shift > 0) { - if (!BN_rshift(B, B, shift)) { - goto err; - } + /* now X is even, so we can easily divide it by two */ + if (!BN_rshift1(X, X)) { + goto err; } + } + if (shift > 0) { + if (!BN_rshift(B, B, shift)) { + goto err; + } + } - /* Same for A and Y. Afterwards, (2) still holds. */ - shift = 0; - while (!BN_is_bit_set(A, shift)) { - /* note that 0 < A */ - shift++; + /* Same for A and Y. Afterwards, (2) still holds. */ + shift = 0; + while (!BN_is_bit_set(A, shift)) { + /* note that 0 < A */ + shift++; - if (BN_is_odd(Y)) { - if (!BN_uadd(Y, Y, n)) { - goto err; - } - } - /* now Y is even */ - if (!BN_rshift1(Y, Y)) { + if (BN_is_odd(Y)) { + if (!BN_uadd(Y, Y, n)) { goto err; } } - if (shift > 0) { - if (!BN_rshift(A, A, shift)) { - goto err; - } + /* now Y is even */ + if (!BN_rshift1(Y, Y)) { + goto err; } - - /* We still have (1) and (2). - * Both A and B are odd. - * The following computations ensure that - * - * 0 <= B < |n|, - * 0 < A < |n|, - * (1) -sign*X*a == B (mod |n|), - * (2) sign*Y*a == A (mod |n|), - * - * and that either A or B is even in the next iteration. */ - if (BN_ucmp(B, A) >= 0) { - /* -sign*(X + Y)*a == B - A (mod |n|) */ - if (!BN_uadd(X, X, Y)) { - goto err; - } - /* NB: we could use BN_mod_add_quick(X, X, Y, n), but that - * actually makes the algorithm slower */ - if (!BN_usub(B, B, A)) { - goto err; - } - } else { - /* sign*(X + Y)*a == A - B (mod |n|) */ - if (!BN_uadd(Y, Y, X)) { - goto err; - } - /* as above, BN_mod_add_quick(Y, Y, X, n) would slow things down */ - if (!BN_usub(A, A, B)) { - goto err; - } + } + if (shift > 0) { + if (!BN_rshift(A, A, shift)) { + goto err; } } - } else { - /* general inversion algorithm */ - while (!BN_is_zero(B)) { - BIGNUM *tmp; - - /* - * 0 < B < A, - * (*) -sign*X*a == B (mod |n|), - * sign*Y*a == A (mod |n|) */ - - /* (D, M) := (A/B, A%B) ... */ - if (BN_num_bits(A) == BN_num_bits(B)) { - if (!BN_one(D)) { - goto err; - } - if (!BN_sub(M, A, B)) { - goto err; - } - } else if (BN_num_bits(A) == BN_num_bits(B) + 1) { - /* A/B is 1, 2, or 3 */ - if (!BN_lshift1(T, B)) { - goto err; - } - if (BN_ucmp(A, T) < 0) { - /* A < 2*B, so D=1 */ - if (!BN_one(D)) { - goto err; - } - if (!BN_sub(M, A, B)) { - goto err; - } - } else { - /* A >= 2*B, so D=2 or D=3 */ - if (!BN_sub(M, A, T)) { - goto err; - } - if (!BN_add(D, T, B)) { - goto err; /* use D (:= 3*B) as temp */ - } - if (BN_ucmp(A, D) < 0) { - /* A < 3*B, so D=2 */ - if (!BN_set_word(D, 2)) { - goto err; - } - /* M (= A - 2*B) already has the correct value */ - } else { - /* only D=3 remains */ - if (!BN_set_word(D, 3)) { - goto err; - } - /* currently M = A - 2*B, but we need M = A - 3*B */ - if (!BN_sub(M, M, B)) { - goto err; - } - } - } - } else { - if (!BN_div(D, M, A, B, ctx)) { - goto err; - } + /* We still have (1) and (2). + * Both A and B are odd. + * The following computations ensure that + * + * 0 <= B < |n|, + * 0 < A < |n|, + * (1) -sign*X*a == B (mod |n|), + * (2) sign*Y*a == A (mod |n|), + * + * and that either A or B is even in the next iteration. */ + if (BN_ucmp(B, A) >= 0) { + /* -sign*(X + Y)*a == B - A (mod |n|) */ + if (!BN_uadd(X, X, Y)) { + goto err; } - - /* Now - * A = D*B + M; - * thus we have - * (**) sign*Y*a == D*B + M (mod |n|). */ - - tmp = A; /* keep the BIGNUM object, the value does not matter */ - - /* (A, B) := (B, A mod B) ... */ - A = B; - B = M; - /* ... so we have 0 <= B < A again */ - - /* Since the former M is now B and the former B is now A, - * (**) translates into - * sign*Y*a == D*A + B (mod |n|), - * i.e. - * sign*Y*a - D*A == B (mod |n|). - * Similarly, (*) translates into - * -sign*X*a == A (mod |n|). - * - * Thus, - * sign*Y*a + D*sign*X*a == B (mod |n|), - * i.e. - * sign*(Y + D*X)*a == B (mod |n|). - * - * So if we set (X, Y, sign) := (Y + D*X, X, -sign), we arrive back at - * -sign*X*a == B (mod |n|), - * sign*Y*a == A (mod |n|). - * Note that X and Y stay non-negative all the time. */ - - /* most of the time D is very small, so we can optimize tmp := D*X+Y */ - if (BN_is_one(D)) { - if (!BN_add(tmp, X, Y)) { - goto err; - } - } else { - if (BN_is_word(D, 2)) { - if (!BN_lshift1(tmp, X)) { - goto err; - } - } else if (BN_is_word(D, 4)) { - if (!BN_lshift(tmp, X, 2)) { - goto err; - } - } else if (D->top == 1) { - if (!BN_copy(tmp, X)) { - goto err; - } - if (!BN_mul_word(tmp, D->d[0])) { - goto err; - } - } else { - if (!BN_mul(tmp, D, X, ctx)) { - goto err; - } - } - if (!BN_add(tmp, tmp, Y)) { - goto err; - } + /* NB: we could use BN_mod_add_quick(X, X, Y, n), but that + * actually makes the algorithm slower */ + if (!BN_usub(B, B, A)) { + goto err; + } + } else { + /* sign*(X + Y)*a == A - B (mod |n|) */ + if (!BN_uadd(Y, Y, X)) { + goto err; + } + /* as above, BN_mod_add_quick(Y, Y, X, n) would slow things down */ + if (!BN_usub(A, A, B)) { + goto err; } - - M = Y; /* keep the BIGNUM object, the value does not matter */ - Y = X; - X = tmp; - sign = -sign; } } + if (!BN_is_one(A)) { + *out_no_inverse = 1; + OPENSSL_PUT_ERROR(BN, BN_R_NO_INVERSE); + goto err; + } + /* The while loop (Euclid's algorithm) ends when * A == gcd(a,n); * we have @@ -513,47 +379,107 @@ BIGNUM *BN_mod_inverse_ex(BIGNUM *out, int *out_no_inverse, const BIGNUM *a, } /* Now Y*a == A (mod |n|). */ - if (BN_is_one(A)) { - /* Y*a == 1 (mod |n|) */ - if (!Y->neg && BN_ucmp(Y, n) < 0) { - if (!BN_copy(R, Y)) { - goto err; - } - } else { - if (!BN_nnmod(R, Y, n, ctx)) { - goto err; - } + /* Y*a == 1 (mod |n|) */ + if (!Y->neg && BN_ucmp(Y, n) < 0) { + if (!BN_copy(R, Y)) { + goto err; } } else { - *out_no_inverse = 1; - OPENSSL_PUT_ERROR(BN, BN_R_NO_INVERSE); - goto err; + if (!BN_nnmod(R, Y, n, ctx)) { + goto err; + } } - ret = R; + + ret = 1; err: - if (ret == NULL && out == NULL) { - BN_free(R); - } BN_CTX_end(ctx); return ret; } BIGNUM *BN_mod_inverse(BIGNUM *out, const BIGNUM *a, const BIGNUM *n, BN_CTX *ctx) { + BIGNUM *new_out = NULL; + if (out == NULL) { + new_out = BN_new(); + if (new_out == NULL) { + OPENSSL_PUT_ERROR(BN, ERR_R_MALLOC_FAILURE); + return NULL; + } + out = new_out; + } + + int ok = 0; + BIGNUM *a_reduced = NULL; + if (a->neg || BN_ucmp(a, n) >= 0) { + a_reduced = BN_dup(a); + if (a_reduced == NULL) { + goto err; + } + if (!BN_nnmod(a_reduced, a_reduced, n, ctx)) { + goto err; + } + a = a_reduced; + } + int no_inverse; - return BN_mod_inverse_ex(out, &no_inverse, a, n, ctx); + if (!BN_is_odd(n)) { + if (!bn_mod_inverse_general(out, &no_inverse, a, n, ctx)) { + goto err; + } + } else if (!BN_mod_inverse_odd(out, &no_inverse, a, n, ctx)) { + goto err; + } + + ok = 1; + +err: + if (!ok) { + BN_free(new_out); + out = NULL; + } + BN_free(a_reduced); + return out; +} + +int BN_mod_inverse_blinded(BIGNUM *out, int *out_no_inverse, const BIGNUM *a, + const BN_MONT_CTX *mont, BN_CTX *ctx) { + *out_no_inverse = 0; + + if (BN_is_negative(a) || BN_cmp(a, &mont->N) >= 0) { + OPENSSL_PUT_ERROR(BN, BN_R_INPUT_NOT_REDUCED); + return 0; + } + + int ret = 0; + BIGNUM blinding_factor; + BN_init(&blinding_factor); + + if (!BN_rand_range_ex(&blinding_factor, 1, &mont->N) || + !BN_mod_mul_montgomery(out, &blinding_factor, a, mont, ctx) || + !BN_mod_inverse_odd(out, out_no_inverse, out, &mont->N, ctx) || + !BN_mod_mul_montgomery(out, &blinding_factor, out, mont, ctx)) { + OPENSSL_PUT_ERROR(BN, ERR_R_BN_LIB); + goto err; + } + + ret = 1; + +err: + BN_free(&blinding_factor); + return ret; } -/* BN_mod_inverse_no_branch is a special version of BN_mod_inverse. - * It does not contain branches that may leak sensitive information. */ -static BIGNUM *BN_mod_inverse_no_branch(BIGNUM *out, int *out_no_inverse, - const BIGNUM *a, const BIGNUM *n, - BN_CTX *ctx) { - BIGNUM *A, *B, *X, *Y, *M, *D, *T, *R = NULL; - BIGNUM local_A, local_B; - BIGNUM *pA, *pB; - BIGNUM *ret = NULL; +/* bn_mod_inverse_general is the general inversion algorithm that works for + * both even and odd |n|. It was specifically designed to contain fewer + * branches that may leak sensitive information; see "New Branch Prediction + * Vulnerabilities in OpenSSL and Necessary Software Countermeasures" by + * Onur Acıçmez, Shay Gueron, and Jean-Pierre Seifert. */ +static int bn_mod_inverse_general(BIGNUM *out, int *out_no_inverse, + const BIGNUM *a, const BIGNUM *n, + BN_CTX *ctx) { + BIGNUM *A, *B, *X, *Y, *M, *D, *T; + int ret = 0; int sign; *out_no_inverse = 0; @@ -570,14 +496,7 @@ static BIGNUM *BN_mod_inverse_no_branch(BIGNUM *out, int *out_no_inverse, goto err; } - if (out == NULL) { - R = BN_new(); - } else { - R = out; - } - if (R == NULL) { - goto err; - } + BIGNUM *R = out; BN_zero(Y); if (!BN_one(X) || BN_copy(B, a) == NULL || BN_copy(A, n) == NULL) { @@ -585,16 +504,6 @@ static BIGNUM *BN_mod_inverse_no_branch(BIGNUM *out, int *out_no_inverse, } A->neg = 0; - if (B->neg || (BN_ucmp(B, A) >= 0)) { - /* Turn BN_FLG_CONSTTIME flag on, so that when BN_div is invoked, - * BN_div_no_branch will be called eventually. - */ - pB = &local_B; - BN_with_flags(pB, B, BN_FLG_CONSTTIME); - if (!BN_nnmod(B, pB, A, ctx)) { - goto err; - } - } sign = -1; /* From B = a mod |n|, A = |n| it follows that * @@ -612,14 +521,8 @@ static BIGNUM *BN_mod_inverse_no_branch(BIGNUM *out, int *out_no_inverse, * sign*Y*a == A (mod |n|) */ - /* Turn BN_FLG_CONSTTIME flag on, so that when BN_div is invoked, - * BN_div_no_branch will be called eventually. - */ - pA = &local_A; - BN_with_flags(pA, A, BN_FLG_CONSTTIME); - /* (D, M) := (A/B, A%B) ... */ - if (!BN_div(D, M, pA, B, ctx)) { + if (!BN_div(D, M, A, B, ctx)) { goto err; } @@ -668,6 +571,12 @@ static BIGNUM *BN_mod_inverse_no_branch(BIGNUM *out, int *out_no_inverse, sign = -sign; } + if (!BN_is_one(A)) { + *out_no_inverse = 1; + OPENSSL_PUT_ERROR(BN, BN_R_NO_INVERSE); + goto err; + } + /* * The while loop (Euclid's algorithm) ends when * A == gcd(a,n); @@ -683,29 +592,44 @@ static BIGNUM *BN_mod_inverse_no_branch(BIGNUM *out, int *out_no_inverse, } /* Now Y*a == A (mod |n|). */ - if (BN_is_one(A)) { - /* Y*a == 1 (mod |n|) */ - if (!Y->neg && BN_ucmp(Y, n) < 0) { - if (!BN_copy(R, Y)) { - goto err; - } - } else { - if (!BN_nnmod(R, Y, n, ctx)) { - goto err; - } + /* Y*a == 1 (mod |n|) */ + if (!Y->neg && BN_ucmp(Y, n) < 0) { + if (!BN_copy(R, Y)) { + goto err; } } else { - *out_no_inverse = 1; - OPENSSL_PUT_ERROR(BN, BN_R_NO_INVERSE); - goto err; + if (!BN_nnmod(R, Y, n, ctx)) { + goto err; + } } - ret = R; -err: - if (ret == NULL && out == NULL) { - BN_free(R); - } + ret = 1; +err: BN_CTX_end(ctx); return ret; } + +int bn_mod_inverse_prime(BIGNUM *out, const BIGNUM *a, const BIGNUM *p, + BN_CTX *ctx, const BN_MONT_CTX *mont_p) { + BN_CTX_start(ctx); + BIGNUM *p_minus_2 = BN_CTX_get(ctx); + int ok = p_minus_2 != NULL && + BN_copy(p_minus_2, p) && + BN_sub_word(p_minus_2, 2) && + BN_mod_exp_mont(out, a, p_minus_2, p, ctx, mont_p); + BN_CTX_end(ctx); + return ok; +} + +int bn_mod_inverse_secret_prime(BIGNUM *out, const BIGNUM *a, const BIGNUM *p, + BN_CTX *ctx, const BN_MONT_CTX *mont_p) { + BN_CTX_start(ctx); + BIGNUM *p_minus_2 = BN_CTX_get(ctx); + int ok = p_minus_2 != NULL && + BN_copy(p_minus_2, p) && + BN_sub_word(p_minus_2, 2) && + BN_mod_exp_mont_consttime(out, a, p_minus_2, p, ctx, mont_p); + BN_CTX_end(ctx); + return ok; +} diff --git a/Sources/BoringSSL/crypto/bn/generic.c b/Sources/BoringSSL/crypto/bn/generic.c index cf2db8b83..de77cc573 100644 --- a/Sources/BoringSSL/crypto/bn/generic.c +++ b/Sources/BoringSSL/crypto/bn/generic.c @@ -67,34 +67,34 @@ !(defined(OPENSSL_X86) || (defined(OPENSSL_X86_64) && defined(__GNUC__))) #ifdef BN_ULLONG -#define mul_add(r, a, w, c) \ - { \ - BN_ULLONG t; \ - t = (BN_ULLONG)w * (a) + (r) + (c); \ - (r) = Lw(t); \ - (c) = Hw(t); \ - } +#define mul_add(r, a, w, c) \ + do { \ + BN_ULLONG t; \ + t = (BN_ULLONG)(w) * (a) + (r) + (c); \ + (r) = Lw(t); \ + (c) = Hw(t); \ + } while (0) -#define mul(r, a, w, c) \ - { \ - BN_ULLONG t; \ - t = (BN_ULLONG)w * (a) + (c); \ - (r) = Lw(t); \ - (c) = Hw(t); \ - } +#define mul(r, a, w, c) \ + do { \ + BN_ULLONG t; \ + t = (BN_ULLONG)(w) * (a) + (c); \ + (r) = Lw(t); \ + (c) = Hw(t); \ + } while (0) #define sqr(r0, r1, a) \ - { \ + do { \ BN_ULLONG t; \ t = (BN_ULLONG)(a) * (a); \ (r0) = Lw(t); \ (r1) = Hw(t); \ - } + } while (0) #else #define mul_add(r, a, w, c) \ - { \ + do { \ BN_ULONG high, low, ret, tmp = (a); \ ret = (r); \ BN_UMULT_LOHI(low, high, w, tmp); \ @@ -104,23 +104,23 @@ ret += low; \ (c) += (ret < low) ? 1 : 0; \ (r) = ret; \ - } + } while (0) #define mul(r, a, w, c) \ - { \ + do { \ BN_ULONG high, low, ret, ta = (a); \ BN_UMULT_LOHI(low, high, w, ta); \ ret = low + (c); \ (c) = high; \ (c) += (ret < low) ? 1 : 0; \ (r) = ret; \ - } + } while (0) #define sqr(r0, r1, a) \ - { \ + do { \ BN_ULONG tmp = (a); \ BN_UMULT_LOHI(r0, r1, tmp, tmp); \ - } + } while (0) #endif /* !BN_ULLONG */ @@ -202,86 +202,6 @@ void bn_sqr_words(BN_ULONG *r, const BN_ULONG *a, int n) { } } -#if defined(BN_ULLONG) - -BN_ULONG bn_div_words(BN_ULONG h, BN_ULONG l, BN_ULONG d) { - return (BN_ULONG)(((((BN_ULLONG)h) << BN_BITS2) | l) / (BN_ULLONG)d); -} - -#else - -/* Divide h,l by d and return the result. */ -BN_ULONG bn_div_words(BN_ULONG h, BN_ULONG l, BN_ULONG d) { - BN_ULONG dh, dl, q, ret = 0, th, tl, t; - int i, count = 2; - - if (d == 0) { - return BN_MASK2; - } - - i = BN_num_bits_word(d); - assert((i == BN_BITS2) || (h <= (BN_ULONG)1 << i)); - - i = BN_BITS2 - i; - if (h >= d) { - h -= d; - } - - if (i) { - d <<= i; - h = (h << i) | (l >> (BN_BITS2 - i)); - l <<= i; - } - dh = (d & BN_MASK2h) >> BN_BITS4; - dl = (d & BN_MASK2l); - for (;;) { - if ((h >> BN_BITS4) == dh) { - q = BN_MASK2l; - } else { - q = h / dh; - } - - th = q * dh; - tl = dl * q; - for (;;) { - t = h - th; - if ((t & BN_MASK2h) || - ((tl) <= ((t << BN_BITS4) | ((l & BN_MASK2h) >> BN_BITS4)))) { - break; - } - q--; - th -= dh; - tl -= dl; - } - t = (tl >> BN_BITS4); - tl = (tl << BN_BITS4) & BN_MASK2h; - th += t; - - if (l < tl) { - th++; - } - l -= tl; - if (h < th) { - h += d; - q--; - } - h -= th; - - if (--count == 0) { - break; - } - - ret = q << BN_BITS4; - h = ((h << BN_BITS4) | (l >> BN_BITS4)) & BN_MASK2; - l = (l & BN_MASK2l) << BN_BITS4; - } - - ret |= q; - return ret; -} - -#endif /* !defined(BN_ULLONG) */ - #ifdef BN_ULLONG BN_ULONG bn_add_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b, int n) { @@ -449,42 +369,46 @@ BN_ULONG bn_sub_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b, do { \ BN_ULONG hi; \ BN_ULLONG t = (BN_ULLONG)(a) * (b); \ - t += c0; /* no carry */ \ - c0 = (BN_ULONG)Lw(t); \ + t += (c0); /* no carry */ \ + (c0) = (BN_ULONG)Lw(t); \ hi = (BN_ULONG)Hw(t); \ - c1 = (c1 + hi) & BN_MASK2; \ - if (c1 < hi) \ - c2++; \ + (c1) = ((c1) + (hi)) & BN_MASK2; \ + if ((c1) < hi) { \ + (c2)++; \ + } \ } while (0) -#define mul_add_c2(a, b, c0, c1, c2) \ - do { \ - BN_ULONG hi; \ - BN_ULLONG t = (BN_ULLONG)(a) * (b); \ - BN_ULLONG tt = t + c0; /* no carry */ \ - c0 = (BN_ULONG)Lw(tt); \ - hi = (BN_ULONG)Hw(tt); \ - c1 = (c1 + hi) & BN_MASK2; \ - if (c1 < hi) \ - c2++; \ - t += c0; /* no carry */ \ - c0 = (BN_ULONG)Lw(t); \ - hi = (BN_ULONG)Hw(t); \ - c1 = (c1 + hi) & BN_MASK2; \ - if (c1 < hi) \ - c2++; \ +#define mul_add_c2(a, b, c0, c1, c2) \ + do { \ + BN_ULONG hi; \ + BN_ULLONG t = (BN_ULLONG)(a) * (b); \ + BN_ULLONG tt = t + (c0); /* no carry */ \ + (c0) = (BN_ULONG)Lw(tt); \ + hi = (BN_ULONG)Hw(tt); \ + (c1) = ((c1) + hi) & BN_MASK2; \ + if ((c1) < hi) { \ + (c2)++; \ + } \ + t += (c0); /* no carry */ \ + (c0) = (BN_ULONG)Lw(t); \ + hi = (BN_ULONG)Hw(t); \ + (c1) = ((c1) + hi) & BN_MASK2; \ + if ((c1) < hi) { \ + (c2)++; \ + } \ } while (0) -#define sqr_add_c(a, i, c0, c1, c2) \ - do { \ - BN_ULONG hi; \ - BN_ULLONG t = (BN_ULLONG)a[i] * a[i]; \ - t += c0; /* no carry */ \ - c0 = (BN_ULONG)Lw(t); \ - hi = (BN_ULONG)Hw(t); \ - c1 = (c1 + hi) & BN_MASK2; \ - if (c1 < hi) \ - c2++; \ +#define sqr_add_c(a, i, c0, c1, c2) \ + do { \ + BN_ULONG hi; \ + BN_ULLONG t = (BN_ULLONG)(a)[i] * (a)[i]; \ + t += (c0); /* no carry */ \ + (c0) = (BN_ULONG)Lw(t); \ + hi = (BN_ULONG)Hw(t); \ + (c1) = ((c1) + hi) & BN_MASK2; \ + if ((c1) < hi) { \ + (c2)++; \ + } \ } while (0) #define sqr_add_c2(a, i, j, c0, c1, c2) mul_add_c2((a)[i], (a)[j], c0, c1, c2) @@ -498,10 +422,10 @@ BN_ULONG bn_sub_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b, BN_ULONG ta = (a), tb = (b); \ BN_ULONG lo, hi; \ BN_UMULT_LOHI(lo, hi, ta, tb); \ - c0 += lo; \ - hi += (c0 < lo) ? 1 : 0; \ - c1 += hi; \ - c2 += (c1 < hi) ? 1 : 0; \ + (c0) += lo; \ + hi += ((c0) < lo) ? 1 : 0; \ + (c1) += hi; \ + (c2) += ((c1) < hi) ? 1 : 0; \ } while (0) #define mul_add_c2(a, b, c0, c1, c2) \ @@ -509,14 +433,14 @@ BN_ULONG bn_sub_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b, BN_ULONG ta = (a), tb = (b); \ BN_ULONG lo, hi, tt; \ BN_UMULT_LOHI(lo, hi, ta, tb); \ - c0 += lo; \ - tt = hi + ((c0 < lo) ? 1 : 0); \ - c1 += tt; \ - c2 += (c1 < tt) ? 1 : 0; \ - c0 += lo; \ + (c0) += lo; \ + tt = hi + (((c0) < lo) ? 1 : 0); \ + (c1) += tt; \ + (c2) += ((c1) < tt) ? 1 : 0; \ + (c0) += lo; \ hi += (c0 < lo) ? 1 : 0; \ - c1 += hi; \ - c2 += (c1 < hi) ? 1 : 0; \ + (c1) += hi; \ + (c2) += ((c1) < hi) ? 1 : 0; \ } while (0) #define sqr_add_c(a, i, c0, c1, c2) \ @@ -524,10 +448,10 @@ BN_ULONG bn_sub_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b, BN_ULONG ta = (a)[i]; \ BN_ULONG lo, hi; \ BN_UMULT_LOHI(lo, hi, ta, ta); \ - c0 += lo; \ + (c0) += lo; \ hi += (c0 < lo) ? 1 : 0; \ - c1 += hi; \ - c2 += (c1 < hi) ? 1 : 0; \ + (c1) += hi; \ + (c2) += ((c1) < hi) ? 1 : 0; \ } while (0) #define sqr_add_c2(a, i, j, c0, c1, c2) mul_add_c2((a)[i], (a)[j], c0, c1, c2) diff --git a/Sources/BoringSSL/crypto/bn/internal.h b/Sources/BoringSSL/crypto/bn/internal.h index 5c9baa4fa..1ee29fd49 100644 --- a/Sources/BoringSSL/crypto/bn/internal.h +++ b/Sources/BoringSSL/crypto/bn/internal.h @@ -126,9 +126,9 @@ #include #if defined(OPENSSL_X86_64) && defined(_MSC_VER) -#pragma warning(push, 3) +OPENSSL_MSVC_PRAGMA(warning(push, 3)) #include -#pragma warning(pop) +OPENSSL_MSVC_PRAGMA(warning(pop)) #pragma intrinsic(__umulh, _umul128) #endif @@ -156,10 +156,11 @@ BIGNUM *bn_expand(BIGNUM *bn, size_t bits); #define BN_MASK2l (0xffffffffUL) #define BN_MASK2h (0xffffffff00000000UL) #define BN_MASK2h1 (0xffffffff80000000UL) +#define BN_MONT_CTX_N0_LIMBS 1 #define BN_TBIT (0x8000000000000000UL) #define BN_DEC_CONV (10000000000000000000UL) #define BN_DEC_NUM 19 -#define TOBN(hi, lo) ((BN_ULONG)hi << 32 | lo) +#define TOBN(hi, lo) ((BN_ULONG)(hi) << 32 | (lo)) #elif defined(OPENSSL_32_BIT) @@ -171,20 +172,26 @@ BIGNUM *bn_expand(BIGNUM *bn, size_t bits); #define BN_MASK2l (0xffffUL) #define BN_MASK2h1 (0xffff8000UL) #define BN_MASK2h (0xffff0000UL) +/* On some 32-bit platforms, Montgomery multiplication is done using 64-bit + * arithmetic with SIMD instructions. On such platforms, |BN_MONT_CTX::n0| + * needs to be two words long. Only certain 32-bit platforms actually make use + * of n0[1] and shorter R value would suffice for the others. However, + * currently only the assembly files know which is which. */ +#define BN_MONT_CTX_N0_LIMBS 2 #define BN_TBIT (0x80000000UL) #define BN_DEC_CONV (1000000000UL) #define BN_DEC_NUM 9 -#define TOBN(hi, lo) lo, hi +#define TOBN(hi, lo) (lo), (hi) #else #error "Must define either OPENSSL_32_BIT or OPENSSL_64_BIT" #endif -#define STATIC_BIGNUM(x) \ - { \ - (BN_ULONG *)x, sizeof(x) / sizeof(BN_ULONG), \ - sizeof(x) / sizeof(BN_ULONG), 0, BN_FLG_STATIC_DATA \ +#define STATIC_BIGNUM(x) \ + { \ + (BN_ULONG *)(x), sizeof(x) / sizeof(BN_ULONG), \ + sizeof(x) / sizeof(BN_ULONG), 0, BN_FLG_STATIC_DATA \ } #if defined(BN_ULLONG) @@ -192,10 +199,13 @@ BIGNUM *bn_expand(BIGNUM *bn, size_t bits); #define Hw(t) (((BN_ULONG)((t)>>BN_BITS2))&BN_MASK2) #endif +/* bn_set_words sets |bn| to the value encoded in the |num| words in |words|, + * least significant word first. */ +int bn_set_words(BIGNUM *bn, const BN_ULONG *words, size_t num); + BN_ULONG bn_mul_add_words(BN_ULONG *rp, const BN_ULONG *ap, int num, BN_ULONG w); BN_ULONG bn_mul_words(BN_ULONG *rp, const BN_ULONG *ap, int num, BN_ULONG w); void bn_sqr_words(BN_ULONG *rp, const BN_ULONG *ap, int num); -BN_ULONG bn_div_words(BN_ULONG h, BN_ULONG l, BN_ULONG d); BN_ULONG bn_add_words(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,int num); BN_ULONG bn_sub_words(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,int num); @@ -217,6 +227,9 @@ int bn_cmp_part_words(const BN_ULONG *a, const BN_ULONG *b, int cl, int dl); int bn_mul_mont(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp, const BN_ULONG *np, const BN_ULONG *n0, int num); +uint64_t bn_mont_n0(const BIGNUM *n); +int bn_mod_exp_base_2_vartime(BIGNUM *r, unsigned p, const BIGNUM *n); + #if defined(OPENSSL_X86_64) && defined(_MSC_VER) #define BN_UMULT_LOHI(low, high, a, b) ((low) = _umul128((a), (b), &(high))) #endif @@ -225,6 +238,18 @@ int bn_mul_mont(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp, #error "Either BN_ULLONG or BN_UMULT_LOHI must be defined on every platform." #endif +/* bn_mod_inverse_prime sets |out| to the modular inverse of |a| modulo |p|, + * computed with Fermat's Little Theorem. It returns one on success and zero on + * error. If |mont_p| is NULL, one will be computed temporarily. */ +int bn_mod_inverse_prime(BIGNUM *out, const BIGNUM *a, const BIGNUM *p, + BN_CTX *ctx, const BN_MONT_CTX *mont_p); + +/* bn_mod_inverse_secret_prime behaves like |bn_mod_inverse_prime| but uses + * |BN_mod_exp_mont_consttime| instead of |BN_mod_exp_mont| in hopes of + * protecting the exponent. */ +int bn_mod_inverse_secret_prime(BIGNUM *out, const BIGNUM *a, const BIGNUM *p, + BN_CTX *ctx, const BN_MONT_CTX *mont_p); + #if defined(__cplusplus) } /* extern C */ diff --git a/Sources/BoringSSL/crypto/bn/kronecker.c b/Sources/BoringSSL/crypto/bn/kronecker.c index 23ef79afa..208985185 100644 --- a/Sources/BoringSSL/crypto/bn/kronecker.c +++ b/Sources/BoringSSL/crypto/bn/kronecker.c @@ -144,6 +144,7 @@ int BN_kronecker(const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx) { i++; } if (!BN_rshift(A, A, i)) { + ret = -2; goto end; } if (i & 1) { diff --git a/Sources/BoringSSL/crypto/bn/montgomery.c b/Sources/BoringSSL/crypto/bn/montgomery.c index d956d62bb..aa5bc4246 100644 --- a/Sources/BoringSSL/crypto/bn/montgomery.c +++ b/Sources/BoringSSL/crypto/bn/montgomery.c @@ -108,6 +108,7 @@ #include +#include #include #include @@ -131,7 +132,7 @@ BN_MONT_CTX *BN_MONT_CTX_new(void) { return NULL; } - memset(ret, 0, sizeof(BN_MONT_CTX)); + OPENSSL_memset(ret, 0, sizeof(BN_MONT_CTX)); BN_init(&ret->RR); BN_init(&ret->N); @@ -162,141 +163,69 @@ BN_MONT_CTX *BN_MONT_CTX_copy(BN_MONT_CTX *to, const BN_MONT_CTX *from) { return to; } -int BN_MONT_CTX_set(BN_MONT_CTX *mont, const BIGNUM *mod, BN_CTX *ctx) { - int ret = 0; - BIGNUM *Ri, *R; - BIGNUM tmod; - BN_ULONG buf[2]; +OPENSSL_COMPILE_ASSERT(BN_MONT_CTX_N0_LIMBS == 1 || BN_MONT_CTX_N0_LIMBS == 2, + BN_MONT_CTX_N0_LIMBS_VALUE_INVALID); +OPENSSL_COMPILE_ASSERT(sizeof(BN_ULONG) * BN_MONT_CTX_N0_LIMBS == + sizeof(uint64_t), BN_MONT_CTX_set_64_bit_mismatch); +int BN_MONT_CTX_set(BN_MONT_CTX *mont, const BIGNUM *mod, BN_CTX *ctx) { if (BN_is_zero(mod)) { OPENSSL_PUT_ERROR(BN, BN_R_DIV_BY_ZERO); return 0; } - - BN_CTX_start(ctx); - Ri = BN_CTX_get(ctx); - if (Ri == NULL) { - goto err; - } - R = &mont->RR; /* grab RR as a temp */ - if (!BN_copy(&mont->N, mod)) { - goto err; /* Set N */ - } - mont->N.neg = 0; - - BN_init(&tmod); - tmod.d = buf; - tmod.dmax = 2; - tmod.neg = 0; - -#if defined(OPENSSL_BN_ASM_MONT) && (BN_BITS2 <= 32) - /* Only certain BN_BITS2<=32 platforms actually make use of - * n0[1], and we could use the #else case (with a shorter R - * value) for the others. However, currently only the assembler - * files do know which is which. */ - - BN_zero(R); - if (!BN_set_bit(R, 2 * BN_BITS2)) { - goto err; - } - - tmod.top = 0; - if ((buf[0] = mod->d[0])) { - tmod.top = 1; + if (!BN_is_odd(mod)) { + OPENSSL_PUT_ERROR(BN, BN_R_CALLED_WITH_EVEN_MODULUS); + return 0; } - if ((buf[1] = mod->top > 1 ? mod->d[1] : 0)) { - tmod.top = 2; + if (BN_is_negative(mod)) { + OPENSSL_PUT_ERROR(BN, BN_R_NEGATIVE_NUMBER); + return 0; } - if (BN_mod_inverse(Ri, R, &tmod, ctx) == NULL) { - goto err; - } - if (!BN_lshift(Ri, Ri, 2 * BN_BITS2)) { - goto err; /* R*Ri */ - } - if (!BN_is_zero(Ri)) { - if (!BN_sub_word(Ri, 1)) { - goto err; - } - } else { - /* if N mod word size == 1 */ - if (bn_expand(Ri, (int)sizeof(BN_ULONG) * 2) == NULL) { - goto err; - } - /* Ri-- (mod double word size) */ - Ri->neg = 0; - Ri->d[0] = BN_MASK2; - Ri->d[1] = BN_MASK2; - Ri->top = 2; + /* Save the modulus. */ + if (!BN_copy(&mont->N, mod)) { + OPENSSL_PUT_ERROR(BN, ERR_R_INTERNAL_ERROR); + return 0; } - if (!BN_div(Ri, NULL, Ri, &tmod, ctx)) { - goto err; - } - /* Ni = (R*Ri-1)/N, - * keep only couple of least significant words: */ - mont->n0[0] = (Ri->top > 0) ? Ri->d[0] : 0; - mont->n0[1] = (Ri->top > 1) ? Ri->d[1] : 0; + /* Find n0 such that n0 * N == -1 (mod r). + * + * Only certain BN_BITS2<=32 platforms actually make use of n0[1]. For the + * others, we could use a shorter R value and use faster |BN_ULONG|-based + * math instead of |uint64_t|-based math, which would be double-precision. + * However, currently only the assembler files know which is which. */ + uint64_t n0 = bn_mont_n0(mod); + mont->n0[0] = (BN_ULONG)n0; +#if BN_MONT_CTX_N0_LIMBS == 2 + mont->n0[1] = (BN_ULONG)(n0 >> BN_BITS2); #else - BN_zero(R); - if (!BN_set_bit(R, BN_BITS2)) { - goto err; /* R */ - } - - buf[0] = mod->d[0]; /* tmod = N mod word size */ - buf[1] = 0; - tmod.top = buf[0] != 0 ? 1 : 0; - /* Ri = R^-1 mod N*/ - if (BN_mod_inverse(Ri, R, &tmod, ctx) == NULL) { - goto err; - } - if (!BN_lshift(Ri, Ri, BN_BITS2)) { - goto err; /* R*Ri */ - } - if (!BN_is_zero(Ri)) { - if (!BN_sub_word(Ri, 1)) { - goto err; - } - } else { - /* if N mod word size == 1 */ - if (!BN_set_word(Ri, BN_MASK2)) { - goto err; /* Ri-- (mod word size) */ - } - } - if (!BN_div(Ri, NULL, Ri, &tmod, ctx)) { - goto err; - } - /* Ni = (R*Ri-1)/N, - * keep only least significant word: */ - mont->n0[0] = (Ri->top > 0) ? Ri->d[0] : 0; mont->n0[1] = 0; #endif - /* RR = (2^ri)^2 == 2^(ri*2) == 1 << (ri*2), which has its (ri*2)th bit set. */ - int ri = (BN_num_bits(mod) + (BN_BITS2 - 1)) / BN_BITS2 * BN_BITS2; - BN_zero(&(mont->RR)); - if (!BN_set_bit(&(mont->RR), ri * 2)) { - goto err; - } - if (!BN_mod(&(mont->RR), &(mont->RR), &(mont->N), ctx)) { - goto err; + /* Save RR = R**2 (mod N). R is the smallest power of 2**BN_BITS such that R + * > mod. Even though the assembly on some 32-bit platforms works with 64-bit + * values, using |BN_BITS2| here, rather than |BN_MONT_CTX_N0_LIMBS * + * BN_BITS2|, is correct because R**2 will still be a multiple of the latter + * as |BN_MONT_CTX_N0_LIMBS| is either one or two. + * + * XXX: This is not constant time with respect to |mont->N|, but it should + * be. */ + unsigned lgBigR = (BN_num_bits(mod) + (BN_BITS2 - 1)) / BN_BITS2 * BN_BITS2; + if (!bn_mod_exp_base_2_vartime(&mont->RR, lgBigR * 2, &mont->N)) { + return 0; } - ret = 1; - -err: - BN_CTX_end(ctx); - return ret; + return 1; } -BN_MONT_CTX *BN_MONT_CTX_set_locked(BN_MONT_CTX **pmont, CRYPTO_MUTEX *lock, - const BIGNUM *mod, BN_CTX *bn_ctx) { +int BN_MONT_CTX_set_locked(BN_MONT_CTX **pmont, CRYPTO_MUTEX *lock, + const BIGNUM *mod, BN_CTX *bn_ctx) { CRYPTO_MUTEX_lock_read(lock); BN_MONT_CTX *ctx = *pmont; - CRYPTO_MUTEX_unlock(lock); + CRYPTO_MUTEX_unlock_read(lock); if (ctx) { - return ctx; + return 1; } CRYPTO_MUTEX_lock_write(lock); @@ -317,8 +246,8 @@ BN_MONT_CTX *BN_MONT_CTX_set_locked(BN_MONT_CTX **pmont, CRYPTO_MUTEX *lock, *pmont = ctx; out: - CRYPTO_MUTEX_unlock(lock); - return ctx; + CRYPTO_MUTEX_unlock_write(lock); + return ctx != NULL; } int BN_to_montgomery(BIGNUM *ret, const BIGNUM *a, const BN_MONT_CTX *mont, @@ -326,14 +255,12 @@ int BN_to_montgomery(BIGNUM *ret, const BIGNUM *a, const BN_MONT_CTX *mont, return BN_mod_mul_montgomery(ret, a, &mont->RR, mont, ctx); } -#if 0 static int BN_from_montgomery_word(BIGNUM *ret, BIGNUM *r, const BN_MONT_CTX *mont) { - const BIGNUM *n; BN_ULONG *ap, *np, *rp, n0, v, carry; int nl, max, i; - n = &mont->N; + const BIGNUM *n = &mont->N; nl = n->top; if (nl == 0) { ret->top = 0; @@ -351,7 +278,7 @@ static int BN_from_montgomery_word(BIGNUM *ret, BIGNUM *r, /* clear the top words of T */ if (max > r->top) { - memset(&rp[r->top], 0, (max - r->top) * sizeof(BN_ULONG)); + OPENSSL_memset(&rp[r->top], 0, (max - r->top) * sizeof(BN_ULONG)); } r->top = max; @@ -376,13 +303,13 @@ static int BN_from_montgomery_word(BIGNUM *ret, BIGNUM *r, { BN_ULONG *nrp; - size_t m; + uintptr_t m; v = bn_sub_words(rp, ap, np, nl) - carry; /* if subtraction result is real, then trick unconditional memcpy below to * perform in-place "refresh" instead of actual copy. */ - m = (0 - (size_t)v); - nrp = (BN_ULONG *)(((intptr_t)rp & ~m) | ((intptr_t)ap & m)); + m = (0u - (uintptr_t)v); + nrp = (BN_ULONG *)(((uintptr_t)rp & ~m) | ((uintptr_t)ap & m)); for (i = 0, nl -= 4; i < nl; i += 4) { BN_ULONG t1, t2, t3, t4; @@ -411,103 +338,25 @@ static int BN_from_montgomery_word(BIGNUM *ret, BIGNUM *r, return 1; } -#endif - -#define PTR_SIZE_INT size_t - -static int BN_from_montgomery_word(BIGNUM *ret, BIGNUM *r, const BN_MONT_CTX *mont) - { - BN_ULONG *ap,*np,*rp,n0,v,carry; - int nl,max,i; - - const BIGNUM *n = &mont->N; - nl=n->top; - if (nl == 0) { ret->top=0; return(1); } - max=(2*nl); /* carry is stored separately */ - if (bn_wexpand(r,max) == NULL) return(0); - - r->neg^=n->neg; - np=n->d; - rp=r->d; - - /* clear the top words of T */ -#if 1 - for (i=r->top; itop]),0,(max-r->top)*sizeof(BN_ULONG)); -#endif - - r->top=max; - n0=mont->n0[0]; - - for (carry=0, i=0; itop=nl; - ret->neg=r->neg; - - rp=ret->d; - ap=&(r->d[nl]); - - { - BN_ULONG *nrp; - size_t m; - - v=bn_sub_words(rp,ap,np,nl)-carry; - /* if subtraction result is real, then - * trick unconditional memcpy below to perform in-place - * "refresh" instead of actual copy. */ - m=(0-(size_t)v); - nrp=(BN_ULONG *)(((PTR_SIZE_INT)rp&~m)|((PTR_SIZE_INT)ap&m)); - - for (i=0,nl-=4; i + +#include + +#include "internal.h" +#include "../internal.h" + + +static uint64_t bn_neg_inv_mod_r_u64(uint64_t n); + +OPENSSL_COMPILE_ASSERT(BN_MONT_CTX_N0_LIMBS == 1 || BN_MONT_CTX_N0_LIMBS == 2, + BN_MONT_CTX_N0_LIMBS_VALUE_INVALID); +OPENSSL_COMPILE_ASSERT(sizeof(uint64_t) == + BN_MONT_CTX_N0_LIMBS * sizeof(BN_ULONG), + BN_MONT_CTX_N0_LIMBS_DOES_NOT_MATCH_UINT64_T); + +/* LG_LITTLE_R is log_2(r). */ +#define LG_LITTLE_R (BN_MONT_CTX_N0_LIMBS * BN_BITS2) + +uint64_t bn_mont_n0(const BIGNUM *n) { + /* These conditions are checked by the caller, |BN_MONT_CTX_set|. */ + assert(!BN_is_zero(n)); + assert(!BN_is_negative(n)); + assert(BN_is_odd(n)); + + /* r == 2**(BN_MONT_CTX_N0_LIMBS * BN_BITS2) and LG_LITTLE_R == lg(r). This + * ensures that we can do integer division by |r| by simply ignoring + * |BN_MONT_CTX_N0_LIMBS| limbs. Similarly, we can calculate values modulo + * |r| by just looking at the lowest |BN_MONT_CTX_N0_LIMBS| limbs. This is + * what makes Montgomery multiplication efficient. + * + * As shown in Algorithm 1 of "Fast Prime Field Elliptic Curve Cryptography + * with 256 Bit Primes" by Shay Gueron and Vlad Krasnov, in the loop of a + * multi-limb Montgomery multiplication of |a * b (mod n)|, given the + * unreduced product |t == a * b|, we repeatedly calculate: + * + * t1 := t % r |t1| is |t|'s lowest limb (see previous paragraph). + * t2 := t1*n0*n + * t3 := t + t2 + * t := t3 / r copy all limbs of |t3| except the lowest to |t|. + * + * In the last step, it would only make sense to ignore the lowest limb of + * |t3| if it were zero. The middle steps ensure that this is the case: + * + * t3 == 0 (mod r) + * t + t2 == 0 (mod r) + * t + t1*n0*n == 0 (mod r) + * t1*n0*n == -t (mod r) + * t*n0*n == -t (mod r) + * n0*n == -1 (mod r) + * n0 == -1/n (mod r) + * + * Thus, in each iteration of the loop, we multiply by the constant factor + * |n0|, the negative inverse of n (mod r). */ + + /* n_mod_r = n % r. As explained above, this is done by taking the lowest + * |BN_MONT_CTX_N0_LIMBS| limbs of |n|. */ + uint64_t n_mod_r = n->d[0]; +#if BN_MONT_CTX_N0_LIMBS == 2 + if (n->top > 1) { + n_mod_r |= (uint64_t)n->d[1] << BN_BITS2; + } +#endif + + return bn_neg_inv_mod_r_u64(n_mod_r); +} + +/* bn_neg_inv_r_mod_n_u64 calculates the -1/n mod r; i.e. it calculates |v| + * such that u*r - v*n == 1. |r| is the constant defined in |bn_mont_n0|. |n| + * must be odd. + * + * This is derived from |xbinGCD| in Henry S. Warren, Jr.'s "Montgomery + * Multiplication" (http://www.hackersdelight.org/MontgomeryMultiplication.pdf). + * It is very similar to the MODULAR-INVERSE function in Stephen R. Dussé's and + * Burton S. Kaliski Jr.'s "A Cryptographic Library for the Motorola DSP56000" + * (http://link.springer.com/chapter/10.1007%2F3-540-46877-3_21). + * + * This is inspired by Joppe W. Bos's "Constant Time Modular Inversion" + * (http://www.joppebos.com/files/CTInversion.pdf) so that the inversion is + * constant-time with respect to |n|. We assume uint64_t additions, + * subtractions, shifts, and bitwise operations are all constant time, which + * may be a large leap of faith on 32-bit targets. We avoid division and + * multiplication, which tend to be the most problematic in terms of timing + * leaks. + * + * Most GCD implementations return values such that |u*r + v*n == 1|, so the + * caller would have to negate the resultant |v| for the purpose of Montgomery + * multiplication. This implementation does the negation implicitly by doing + * the computations as a difference instead of a sum. */ +static uint64_t bn_neg_inv_mod_r_u64(uint64_t n) { + assert(n % 2 == 1); + + /* alpha == 2**(lg r - 1) == r / 2. */ + static const uint64_t alpha = UINT64_C(1) << (LG_LITTLE_R - 1); + + const uint64_t beta = n; + + uint64_t u = 1; + uint64_t v = 0; + + /* The invariant maintained from here on is: + * 2**(lg r - i) == u*2*alpha - v*beta. */ + for (size_t i = 0; i < LG_LITTLE_R; ++i) { +#if BN_BITS2 == 64 && defined(BN_ULLONG) + assert((BN_ULLONG)(1) << (LG_LITTLE_R - i) == + ((BN_ULLONG)u * 2 * alpha) - ((BN_ULLONG)v * beta)); +#endif + + /* Delete a common factor of 2 in u and v if |u| is even. Otherwise, set + * |u = (u + beta) / 2| and |v = (v / 2) + alpha|. */ + + uint64_t u_is_odd = UINT64_C(0) - (u & 1); /* Either 0xff..ff or 0. */ + + /* The addition can overflow, so use Dietz's method for it. + * + * Dietz calculates (x+y)/2 by (x⊕y)>>1 + x&y. This is valid for all + * (unsigned) x and y, even when x+y overflows. Evidence for 32-bit values + * (embedded in 64 bits to so that overflow can be ignored): + * + * (declare-fun x () (_ BitVec 64)) + * (declare-fun y () (_ BitVec 64)) + * (assert (let ( + * (one (_ bv1 64)) + * (thirtyTwo (_ bv32 64))) + * (and + * (bvult x (bvshl one thirtyTwo)) + * (bvult y (bvshl one thirtyTwo)) + * (not (= + * (bvadd (bvlshr (bvxor x y) one) (bvand x y)) + * (bvlshr (bvadd x y) one))) + * ))) + * (check-sat) */ + uint64_t beta_if_u_is_odd = beta & u_is_odd; /* Either |beta| or 0. */ + u = ((u ^ beta_if_u_is_odd) >> 1) + (u & beta_if_u_is_odd); + + uint64_t alpha_if_u_is_odd = alpha & u_is_odd; /* Either |alpha| or 0. */ + v = (v >> 1) + alpha_if_u_is_odd; + } + + /* The invariant now shows that u*r - v*n == 1 since r == 2 * alpha. */ +#if BN_BITS2 == 64 && defined(BN_ULLONG) + assert(1 == ((BN_ULLONG)u * 2 * alpha) - ((BN_ULLONG)v * beta)); +#endif + + return v; +} + +/* bn_mod_exp_base_2_vartime calculates r = 2**p (mod n). |p| must be larger + * than log_2(n); i.e. 2**p must be larger than |n|. |n| must be positive and + * odd. */ +int bn_mod_exp_base_2_vartime(BIGNUM *r, unsigned p, const BIGNUM *n) { + assert(!BN_is_zero(n)); + assert(!BN_is_negative(n)); + assert(BN_is_odd(n)); + + BN_zero(r); + + unsigned n_bits = BN_num_bits(n); + assert(n_bits != 0); + if (n_bits == 1) { + return 1; + } + + /* Set |r| to the smallest power of two larger than |n|. */ + assert(p > n_bits); + if (!BN_set_bit(r, n_bits)) { + return 0; + } + + /* Unconditionally reduce |r|. */ + assert(BN_cmp(r, n) > 0); + if (!BN_usub(r, r, n)) { + return 0; + } + assert(BN_cmp(r, n) < 0); + + for (unsigned i = n_bits; i < p; ++i) { + /* This is like |BN_mod_lshift1_quick| except using |BN_usub|. + * + * TODO: Replace this with the use of a constant-time variant of + * |BN_mod_lshift1_quick|. */ + if (!BN_lshift1(r, r)) { + return 0; + } + if (BN_cmp(r, n) >= 0) { + if (!BN_usub(r, r, n)) { + return 0; + } + } + } + + return 1; +} diff --git a/Sources/BoringSSL/crypto/bn/mul.c b/Sources/BoringSSL/crypto/bn/mul.c index d2d8fd8c0..fdf2c6927 100644 --- a/Sources/BoringSSL/crypto/bn/mul.c +++ b/Sources/BoringSSL/crypto/bn/mul.c @@ -66,7 +66,8 @@ #define BN_SQR_RECURSIVE_SIZE_NORMAL BN_MUL_RECURSIVE_SIZE_NORMAL -void bn_mul_normal(BN_ULONG *r, BN_ULONG *a, int na, BN_ULONG *b, int nb) { +static void bn_mul_normal(BN_ULONG *r, BN_ULONG *a, int na, BN_ULONG *b, + int nb) { BN_ULONG *rr; if (na < nb) { @@ -311,7 +312,8 @@ static void bn_mul_recursive(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n2, if (n2 < BN_MUL_RECURSIVE_SIZE_NORMAL) { bn_mul_normal(r, a, n2 + dna, b, n2 + dnb); if ((dna + dnb) < 0) { - memset(&r[2 * n2 + dna + dnb], 0, sizeof(BN_ULONG) * -(dna + dnb)); + OPENSSL_memset(&r[2 * n2 + dna + dnb], 0, + sizeof(BN_ULONG) * -(dna + dnb)); } return; } @@ -357,7 +359,7 @@ static void bn_mul_recursive(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n2, if (!zero) { bn_mul_comba4(&(t[n2]), t, &(t[n])); } else { - memset(&(t[n2]), 0, 8 * sizeof(BN_ULONG)); + OPENSSL_memset(&(t[n2]), 0, 8 * sizeof(BN_ULONG)); } bn_mul_comba4(r, a, b); @@ -367,7 +369,7 @@ static void bn_mul_recursive(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n2, if (!zero) { bn_mul_comba8(&(t[n2]), t, &(t[n])); } else { - memset(&(t[n2]), 0, 16 * sizeof(BN_ULONG)); + OPENSSL_memset(&(t[n2]), 0, 16 * sizeof(BN_ULONG)); } bn_mul_comba8(r, a, b); @@ -377,7 +379,7 @@ static void bn_mul_recursive(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n2, if (!zero) { bn_mul_recursive(&(t[n2]), t, &(t[n]), n, 0, 0, p); } else { - memset(&(t[n2]), 0, n2 * sizeof(BN_ULONG)); + OPENSSL_memset(&(t[n2]), 0, n2 * sizeof(BN_ULONG)); } bn_mul_recursive(r, a, b, n, 0, 0, p); bn_mul_recursive(&(r[n2]), &(a[n]), &(b[n]), n, dna, dnb, p); @@ -472,7 +474,7 @@ static void bn_mul_part_recursive(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n, bn_mul_comba8(&(t[n2]), t, &(t[n])); bn_mul_comba8(r, a, b); bn_mul_normal(&(r[n2]), &(a[n]), tna, &(b[n]), tnb); - memset(&(r[n2 + tna + tnb]), 0, sizeof(BN_ULONG) * (n2 - tna - tnb)); + OPENSSL_memset(&(r[n2 + tna + tnb]), 0, sizeof(BN_ULONG) * (n2 - tna - tnb)); } else { p = &(t[n2 * 2]); bn_mul_recursive(&(t[n2]), t, &(t[n]), n, 0, 0, p); @@ -488,14 +490,15 @@ static void bn_mul_part_recursive(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n, if (j == 0) { bn_mul_recursive(&(r[n2]), &(a[n]), &(b[n]), i, tna - i, tnb - i, p); - memset(&(r[n2 + i * 2]), 0, sizeof(BN_ULONG) * (n2 - i * 2)); + OPENSSL_memset(&(r[n2 + i * 2]), 0, sizeof(BN_ULONG) * (n2 - i * 2)); } else if (j > 0) { /* eg, n == 16, i == 8 and tn == 11 */ bn_mul_part_recursive(&(r[n2]), &(a[n]), &(b[n]), i, tna - i, tnb - i, p); - memset(&(r[n2 + tna + tnb]), 0, sizeof(BN_ULONG) * (n2 - tna - tnb)); + OPENSSL_memset(&(r[n2 + tna + tnb]), 0, + sizeof(BN_ULONG) * (n2 - tna - tnb)); } else { /* (j < 0) eg, n == 16, i == 8 and tn == 5 */ - memset(&(r[n2]), 0, sizeof(BN_ULONG) * n2); + OPENSSL_memset(&(r[n2]), 0, sizeof(BN_ULONG) * n2); if (tna < BN_MUL_RECURSIVE_SIZE_NORMAL && tnb < BN_MUL_RECURSIVE_SIZE_NORMAL) { bn_mul_normal(&(r[n2]), &(a[n]), tna, &(b[n]), tnb); @@ -734,7 +737,7 @@ static void bn_sqr_recursive(BN_ULONG *r, const BN_ULONG *a, int n2, BN_ULONG *t if (!zero) { bn_sqr_recursive(&(t[n2]), t, n, p); } else { - memset(&(t[n2]), 0, n2 * sizeof(BN_ULONG)); + OPENSSL_memset(&(t[n2]), 0, n2 * sizeof(BN_ULONG)); } bn_sqr_recursive(r, a, n, p); bn_sqr_recursive(&(r[n2]), &(a[n]), n, p); diff --git a/Sources/BoringSSL/crypto/bn/prime.c b/Sources/BoringSSL/crypto/bn/prime.c index d07e6094b..0f668d728 100644 --- a/Sources/BoringSSL/crypto/bn/prime.c +++ b/Sources/BoringSSL/crypto/bn/prime.c @@ -496,7 +496,11 @@ int BN_is_prime_fasttest_ex(const BIGNUM *a, int checks, BN_CTX *ctx_passed, if (do_trial_division) { for (i = 1; i < NUMPRIMES; i++) { - if (BN_mod_word(a, primes[i]) == 0) { + BN_ULONG mod = BN_mod_word(a, primes[i]); + if (mod == (BN_ULONG)-1) { + goto err; + } + if (mod == 0) { return 0; } } @@ -647,13 +651,17 @@ static int probable_prime(BIGNUM *rnd, int bits) { char is_single_word = bits <= BN_BITS2; again: - if (!BN_rand(rnd, bits, 1, 1)) { + if (!BN_rand(rnd, bits, BN_RAND_TOP_TWO, BN_RAND_BOTTOM_ODD)) { return 0; } /* we now have a random number 'rnd' to test. */ for (i = 1; i < NUMPRIMES; i++) { - mods[i] = (uint16_t)BN_mod_word(rnd, (BN_ULONG)primes[i]); + BN_ULONG mod = BN_mod_word(rnd, (BN_ULONG)primes[i]); + if (mod == (BN_ULONG)-1) { + return 0; + } + mods[i] = (uint16_t)mod; } /* If bits is so small that it fits into a single word then we * additionally don't want to exceed that many bits. */ @@ -727,7 +735,7 @@ static int probable_prime_dh(BIGNUM *rnd, int bits, const BIGNUM *add, goto err; } - if (!BN_rand(rnd, bits, 0, 1)) { + if (!BN_rand(rnd, bits, BN_RAND_TOP_ONE, BN_RAND_BOTTOM_ODD)) { goto err; } @@ -753,7 +761,11 @@ static int probable_prime_dh(BIGNUM *rnd, int bits, const BIGNUM *add, loop: for (i = 1; i < NUMPRIMES; i++) { /* check that rnd is a prime */ - if (BN_mod_word(rnd, (BN_ULONG)primes[i]) <= 1) { + BN_ULONG mod = BN_mod_word(rnd, (BN_ULONG)primes[i]); + if (mod == (BN_ULONG)-1) { + goto err; + } + if (mod <= 1) { if (!BN_add(rnd, rnd, add)) { goto err; } @@ -786,7 +798,7 @@ static int probable_prime_dh_safe(BIGNUM *p, int bits, const BIGNUM *padd, goto err; } - if (!BN_rand(q, bits, 0, 1)) { + if (!BN_rand(q, bits, BN_RAND_TOP_ONE, BN_RAND_BOTTOM_ODD)) { goto err; } @@ -825,8 +837,12 @@ static int probable_prime_dh_safe(BIGNUM *p, int bits, const BIGNUM *padd, /* check that p and q are prime */ /* check that for p and q * gcd(p-1,primes) == 1 (except for 2) */ - if ((BN_mod_word(p, (BN_ULONG)primes[i]) == 0) || - (BN_mod_word(q, (BN_ULONG)primes[i]) == 0)) { + BN_ULONG pmod = BN_mod_word(p, (BN_ULONG)primes[i]); + BN_ULONG qmod = BN_mod_word(q, (BN_ULONG)primes[i]); + if (pmod == (BN_ULONG)-1 || qmod == (BN_ULONG)-1) { + goto err; + } + if (pmod == 0 || qmod == 0) { if (!BN_add(p, p, padd)) { goto err; } diff --git a/Sources/BoringSSL/crypto/bn/random.c b/Sources/BoringSSL/crypto/bn/random.c index 3116e5473..6f922c094 100644 --- a/Sources/BoringSSL/crypto/bn/random.c +++ b/Sources/BoringSSL/crypto/bn/random.c @@ -115,6 +115,9 @@ #include #include +#include "../internal.h" + + int BN_rand(BIGNUM *rnd, int bits, int top, int bottom) { uint8_t *buf = NULL; int ret = 0, bit, bytes, mask; @@ -123,6 +126,17 @@ int BN_rand(BIGNUM *rnd, int bits, int top, int bottom) { return 0; } + if (top != BN_RAND_TOP_ANY && top != BN_RAND_TOP_ONE && + top != BN_RAND_TOP_TWO) { + OPENSSL_PUT_ERROR(BN, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + + if (bottom != BN_RAND_BOTTOM_ANY && bottom != BN_RAND_BOTTOM_ODD) { + OPENSSL_PUT_ERROR(BN, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + if (bits == 0) { BN_zero(rnd); return 1; @@ -143,8 +157,8 @@ int BN_rand(BIGNUM *rnd, int bits, int top, int bottom) { goto err; } - if (top != -1) { - if (top && bits > 1) { + if (top != BN_RAND_TOP_ANY) { + if (top == BN_RAND_TOP_TWO && bits > 1) { if (bit == 0) { buf[0] = 1; buf[1] |= 0x80; @@ -158,8 +172,8 @@ int BN_rand(BIGNUM *rnd, int bits, int top, int bottom) { buf[0] &= ~mask; - /* set bottom bit if requested */ - if (bottom) { + /* Set the bottom bit if requested, */ + if (bottom == BN_RAND_BOTTOM_ODD) { buf[bytes - 1] |= 1; } @@ -181,65 +195,68 @@ int BN_pseudo_rand(BIGNUM *rnd, int bits, int top, int bottom) { return BN_rand(rnd, bits, top, bottom); } -int BN_rand_range(BIGNUM *r, const BIGNUM *range) { +int BN_rand_range_ex(BIGNUM *r, BN_ULONG min_inclusive, + const BIGNUM *max_exclusive) { unsigned n; unsigned count = 100; - if (range->neg || BN_is_zero(range)) { + if (BN_cmp_word(max_exclusive, min_inclusive) <= 0) { OPENSSL_PUT_ERROR(BN, BN_R_INVALID_RANGE); return 0; } - n = BN_num_bits(range); /* n > 0 */ + n = BN_num_bits(max_exclusive); /* n > 0 */ /* BN_is_bit_set(range, n - 1) always holds */ if (n == 1) { BN_zero(r); - } else if (!BN_is_bit_set(range, n - 2) && !BN_is_bit_set(range, n - 3)) { - /* range = 100..._2, - * so 3*range (= 11..._2) is exactly one bit longer than range */ - do { - if (!BN_rand(r, n + 1, -1 /* don't set most significant bits */, - 0 /* don't set least significant bits */)) { + return 1; + } + + do { + if (!--count) { + OPENSSL_PUT_ERROR(BN, BN_R_TOO_MANY_ITERATIONS); + return 0; + } + + if (!BN_is_bit_set(max_exclusive, n - 2) && + !BN_is_bit_set(max_exclusive, n - 3)) { + /* range = 100..._2, so 3*range (= 11..._2) is exactly one bit longer + * than range. This is a common scenario when generating a random value + * modulo an RSA public modulus, e.g. for RSA base blinding. */ + if (!BN_rand(r, n + 1, BN_RAND_TOP_ANY, BN_RAND_BOTTOM_ANY)) { return 0; } /* If r < 3*range, use r := r MOD range (which is either r, r - range, or * r - 2*range). Otherwise, iterate again. Since 3*range = 11..._2, each * iteration succeeds with probability >= .75. */ - if (BN_cmp(r, range) >= 0) { - if (!BN_sub(r, r, range)) { + if (BN_cmp(r, max_exclusive) >= 0) { + if (!BN_sub(r, r, max_exclusive)) { return 0; } - if (BN_cmp(r, range) >= 0) { - if (!BN_sub(r, r, range)) { + if (BN_cmp(r, max_exclusive) >= 0) { + if (!BN_sub(r, r, max_exclusive)) { return 0; } } } - - if (!--count) { - OPENSSL_PUT_ERROR(BN, BN_R_TOO_MANY_ITERATIONS); - return 0; - } - } while (BN_cmp(r, range) >= 0); - } else { - do { + } else { /* range = 11..._2 or range = 101..._2 */ - if (!BN_rand(r, n, -1, 0)) { + if (!BN_rand(r, n, BN_RAND_TOP_ANY, BN_RAND_BOTTOM_ANY)) { return 0; } - - if (!--count) { - OPENSSL_PUT_ERROR(BN, BN_R_TOO_MANY_ITERATIONS); - return 0; - } - } while (BN_cmp(r, range) >= 0); - } + } + } while (BN_cmp_word(r, min_inclusive) < 0 || + BN_cmp(r, max_exclusive) >= 0); return 1; } +int BN_rand_range(BIGNUM *r, const BIGNUM *range) { + return BN_rand_range_ex(r, 0, range); +} + int BN_pseudo_rand_range(BIGNUM *r, const BIGNUM *range) { return BN_rand_range(r, range); } @@ -284,8 +301,8 @@ int BN_generate_dsa_nonce(BIGNUM *out, const BIGNUM *range, const BIGNUM *priv, OPENSSL_PUT_ERROR(BN, BN_R_PRIVATE_KEY_TOO_LARGE); goto err; } - memcpy(private_bytes, priv->d, todo); - memset(private_bytes + todo, 0, sizeof(private_bytes) - todo); + OPENSSL_memcpy(private_bytes, priv->d, todo); + OPENSSL_memset(private_bytes + todo, 0, sizeof(private_bytes) - todo); for (attempt = 0;; attempt++) { for (done = 0; done < num_k_bytes;) { @@ -304,7 +321,7 @@ int BN_generate_dsa_nonce(BIGNUM *out, const BIGNUM *range, const BIGNUM *priv, if (todo > SHA512_DIGEST_LENGTH) { todo = SHA512_DIGEST_LENGTH; } - memcpy(k_bytes + done, digest, todo); + OPENSSL_memcpy(k_bytes + done, digest, todo); done += todo; } diff --git a/Sources/BoringSSL/crypto/bn/rsaz_exp.c b/Sources/BoringSSL/crypto/bn/rsaz_exp.c index 30f08e5f8..c7eed38e1 100644 --- a/Sources/BoringSSL/crypto/bn/rsaz_exp.c +++ b/Sources/BoringSSL/crypto/bn/rsaz_exp.c @@ -251,69 +251,4 @@ void RSAZ_1024_mod_exp_avx2(BN_ULONG result_norm[16], OPENSSL_cleanse(storage,sizeof(storage)); } -/* - * See crypto/bn/rsaz-x86_64.pl for further details. - */ -void rsaz_512_mul(void *ret,const void *a,const void *b,const void *n,BN_ULONG k); -void rsaz_512_mul_scatter4(void *ret,const void *a,const void *n,BN_ULONG k,const void *tbl,unsigned int power); -void rsaz_512_mul_gather4(void *ret,const void *a,const void *tbl,const void *n,BN_ULONG k,unsigned int power); -void rsaz_512_mul_by_one(void *ret,const void *a,const void *n,BN_ULONG k); -void rsaz_512_sqr(void *ret,const void *a,const void *n,BN_ULONG k,int cnt); -void rsaz_512_scatter4(void *tbl, const BN_ULONG *val, int power); -void rsaz_512_gather4(BN_ULONG *val, const void *tbl, int power); - -void RSAZ_512_mod_exp(BN_ULONG result[8], - const BN_ULONG base[8], const BN_ULONG exponent[8], - const BN_ULONG m[8], BN_ULONG k0, const BN_ULONG RR[8]) -{ - alignas(64) uint8_t storage[(16*8*8) + (64 * 2)]; /* 1.2KB */ - unsigned char *table = storage; - BN_ULONG *a_inv = (BN_ULONG *)(table+16*8*8), - *temp = (BN_ULONG *)(table+16*8*8+8*8); - int index; - unsigned int wvalue; - - /* table[0] = 1_inv */ - temp[0] = 0-m[0]; temp[1] = ~m[1]; - temp[2] = ~m[2]; temp[3] = ~m[3]; - temp[4] = ~m[4]; temp[5] = ~m[5]; - temp[6] = ~m[6]; temp[7] = ~m[7]; - rsaz_512_scatter4(table, temp, 0); - - /* table [1] = a_inv^1 */ - rsaz_512_mul(a_inv, base, RR, m, k0); - rsaz_512_scatter4(table, a_inv, 1); - - /* table [2] = a_inv^2 */ - rsaz_512_sqr(temp, a_inv, m, k0, 1); - rsaz_512_scatter4(table, temp, 2); - - for (index=3; index<16; index++) - rsaz_512_mul_scatter4(temp, a_inv, m, k0, table, index); - - const uint8_t *p_str = (const uint8_t *)exponent; - - /* load first window */ - wvalue = p_str[63]; - - rsaz_512_gather4(temp, table, wvalue>>4); - rsaz_512_sqr(temp, temp, m, k0, 4); - rsaz_512_mul_gather4(temp, temp, table, m, k0, wvalue&0xf); - - for (index=62; index>=0; index--) { - wvalue = p_str[index]; - - rsaz_512_sqr(temp, temp, m, k0, 4); - rsaz_512_mul_gather4(temp, temp, table, m, k0, wvalue>>4); - - rsaz_512_sqr(temp, temp, m, k0, 4); - rsaz_512_mul_gather4(temp, temp, table, m, k0, wvalue&0x0f); - } - - /* from Montgomery */ - rsaz_512_mul_by_one(result, temp, m, k0); - - OPENSSL_cleanse(storage,sizeof(storage)); -} - #endif /* OPENSSL_X86_64 */ diff --git a/Sources/BoringSSL/crypto/bn/rsaz_exp.h b/Sources/BoringSSL/crypto/bn/rsaz_exp.h index c752b45f2..4a8967c39 100644 --- a/Sources/BoringSSL/crypto/bn/rsaz_exp.h +++ b/Sources/BoringSSL/crypto/bn/rsaz_exp.h @@ -50,7 +50,4 @@ void RSAZ_1024_mod_exp_avx2(BN_ULONG result[16], const BN_ULONG m_norm[16], const BN_ULONG RR[16], BN_ULONG k0); int rsaz_avx2_eligible(void); -void RSAZ_512_mod_exp(BN_ULONG result[8], - const BN_ULONG base_norm[8], const BN_ULONG exponent[8], - const BN_ULONG m_norm[8], BN_ULONG k0, const BN_ULONG RR[8]); #endif diff --git a/Sources/BoringSSL/crypto/bn/shift.c b/Sources/BoringSSL/crypto/bn/shift.c index defec9291..dc9b795dc 100644 --- a/Sources/BoringSSL/crypto/bn/shift.c +++ b/Sources/BoringSSL/crypto/bn/shift.c @@ -94,7 +94,7 @@ int BN_lshift(BIGNUM *r, const BIGNUM *a, int n) { t[nw + i] = (l << lb) & BN_MASK2; } } - memset(t, 0, nw * sizeof(t[0])); + OPENSSL_memset(t, 0, nw * sizeof(t[0])); r->top = a->top + nw + 1; bn_correct_top(r); @@ -182,6 +182,10 @@ int BN_rshift(BIGNUM *r, const BIGNUM *a, int n) { } } + if (r->top == 0) { + r->neg = 0; + } + return 1; } @@ -215,6 +219,10 @@ int BN_rshift1(BIGNUM *r, const BIGNUM *a) { } r->top = j; + if (r->top == 0) { + r->neg = 0; + } + return 1; } diff --git a/Sources/BoringSSL/crypto/bn/sqrt.c b/Sources/BoringSSL/crypto/bn/sqrt.c index 2ed66c22c..fb962a98b 100644 --- a/Sources/BoringSSL/crypto/bn/sqrt.c +++ b/Sources/BoringSSL/crypto/bn/sqrt.c @@ -57,12 +57,11 @@ #include -/* Returns 'ret' such that - * ret^2 == a (mod p), - * using the Tonelli/Shanks algorithm (cf. Henri Cohen, "A Course - * in Algebraic Computational Number Theory", algorithm 1.5.1). - * 'p' must be prime! */ BIGNUM *BN_mod_sqrt(BIGNUM *in, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx) { + /* Compute a square root of |a| mod |p| using the Tonelli/Shanks algorithm + * (cf. Henri Cohen, "A Course in Algebraic Computational Number Theory", + * algorithm 1.5.1). |p| is assumed to be a prime. */ + BIGNUM *ret = in; int err = 1; int r; @@ -457,7 +456,9 @@ int BN_sqrt(BIGNUM *out_sqrt, const BIGNUM *in, BN_CTX *ctx) { } /* We estimate that the square root of an n-bit number is 2^{n/2}. */ - BN_lshift(estimate, BN_value_one(), BN_num_bits(in)/2); + if (!BN_lshift(estimate, BN_value_one(), BN_num_bits(in)/2)) { + goto err; + } /* This is Newton's method for finding a root of the equation |estimate|^2 - * |in| = 0. */ diff --git a/Sources/BoringSSL/crypto/buf/buf.c b/Sources/BoringSSL/crypto/buf/buf.c index b918f01f1..ca1d70b04 100644 --- a/Sources/BoringSSL/crypto/buf/buf.c +++ b/Sources/BoringSSL/crypto/buf/buf.c @@ -61,6 +61,8 @@ #include #include +#include "../internal.h" + BUF_MEM *BUF_MEM_new(void) { BUF_MEM *ret; @@ -71,7 +73,7 @@ BUF_MEM *BUF_MEM_new(void) { return NULL; } - memset(ret, 0, sizeof(BUF_MEM)); + OPENSSL_memset(ret, 0, sizeof(BUF_MEM)); return ret; } @@ -88,34 +90,26 @@ void BUF_MEM_free(BUF_MEM *buf) { OPENSSL_free(buf); } -static size_t buf_mem_grow(BUF_MEM *buf, size_t len, char clean) { - char *new_buf; - size_t n, alloc_size; - - if (buf->length >= len) { - buf->length = len; - return len; - } - if (buf->max >= len) { - memset(&buf->data[buf->length], 0, len - buf->length); - buf->length = len; - return len; +static int buf_mem_reserve(BUF_MEM *buf, size_t cap, int clean) { + if (buf->max >= cap) { + return 1; } - n = len + 3; - if (n < len) { + size_t n = cap + 3; + if (n < cap) { /* overflow */ OPENSSL_PUT_ERROR(BUF, ERR_R_MALLOC_FAILURE); return 0; } n = n / 3; - alloc_size = n * 4; + size_t alloc_size = n * 4; if (alloc_size / 4 != n) { /* overflow */ OPENSSL_PUT_ERROR(BUF, ERR_R_MALLOC_FAILURE); return 0; } + char *new_buf; if (buf->data == NULL) { new_buf = OPENSSL_malloc(alloc_size); } else { @@ -128,14 +122,26 @@ static size_t buf_mem_grow(BUF_MEM *buf, size_t len, char clean) { if (new_buf == NULL) { OPENSSL_PUT_ERROR(BUF, ERR_R_MALLOC_FAILURE); - len = 0; - } else { - buf->data = new_buf; - buf->max = alloc_size; - memset(&buf->data[buf->length], 0, len - buf->length); - buf->length = len; + return 0; } + buf->data = new_buf; + buf->max = alloc_size; + return 1; +} + +int BUF_MEM_reserve(BUF_MEM *buf, size_t cap) { + return buf_mem_reserve(buf, cap, 0 /* don't clear old buffer contents. */); +} + +static size_t buf_mem_grow(BUF_MEM *buf, size_t len, int clean) { + if (!buf_mem_reserve(buf, len, clean)) { + return 0; + } + if (buf->length < len) { + OPENSSL_memset(&buf->data[buf->length], 0, len - buf->length); + } + buf->length = len; return len; } @@ -189,7 +195,7 @@ char *BUF_strndup(const char *buf, size_t size) { return NULL; } - memcpy(ret, buf, size); + OPENSSL_memcpy(ret, buf, size); ret[size] = '\0'; return ret; } @@ -230,6 +236,6 @@ void *BUF_memdup(const void *data, size_t dst_size) { return NULL; } - memcpy(ret, data, dst_size); + OPENSSL_memcpy(ret, data, dst_size); return ret; } diff --git a/Sources/BoringSSL/crypto/bytestring/asn1_compat.c b/Sources/BoringSSL/crypto/bytestring/asn1_compat.c index b17d2d121..50df9cce0 100644 --- a/Sources/BoringSSL/crypto/bytestring/asn1_compat.c +++ b/Sources/BoringSSL/crypto/bytestring/asn1_compat.c @@ -22,6 +22,7 @@ #include #include "internal.h" +#include "../internal.h" int CBB_finish_i2d(CBB *cbb, uint8_t **outp) { @@ -42,7 +43,7 @@ int CBB_finish_i2d(CBB *cbb, uint8_t **outp) { *outp = der; der = NULL; } else { - memcpy(*outp, der, der_len); + OPENSSL_memcpy(*outp, der, der_len); *outp += der_len; } } diff --git a/Sources/BoringSSL/crypto/bytestring/ber.c b/Sources/BoringSSL/crypto/bytestring/ber.c index 2a968e160..ee3cd0a06 100644 --- a/Sources/BoringSSL/crypto/bytestring/ber.c +++ b/Sources/BoringSSL/crypto/bytestring/ber.c @@ -18,6 +18,7 @@ #include #include "internal.h" +#include "../internal.h" /* kMaxDepth is a just a sanity limit. The code should be such that the length @@ -34,6 +35,7 @@ static int is_string_type(unsigned tag) { switch (tag & 0x1f) { case CBS_ASN1_BITSTRING: case CBS_ASN1_OCTETSTRING: + case CBS_ASN1_UTF8STRING: case CBS_ASN1_NUMERICSTRING: case CBS_ASN1_PRINTABLESTRING: case CBS_ASN1_T16STRING: @@ -99,7 +101,7 @@ static int cbs_find_ber(const CBS *orig_in, char *ber_found, unsigned depth) { * |CBS_get_any_ber_asn1_element|, indicate an "end of contents" (EOC) value. */ static char is_eoc(size_t header_len, CBS *contents) { return header_len == 2 && CBS_len(contents) == 2 && - memcmp(CBS_data(contents), "\x00\x00", 2) == 0; + OPENSSL_memcmp(CBS_data(contents), "\x00\x00", 2) == 0; } /* cbs_convert_ber reads BER data from |in| and writes DER data to |out|. If diff --git a/Sources/BoringSSL/crypto/bytestring/cbb.c b/Sources/BoringSSL/crypto/bytestring/cbb.c index 8fc518794..14116be57 100644 --- a/Sources/BoringSSL/crypto/bytestring/cbb.c +++ b/Sources/BoringSSL/crypto/bytestring/cbb.c @@ -19,9 +19,11 @@ #include +#include "../internal.h" + void CBB_zero(CBB *cbb) { - memset(cbb, 0, sizeof(CBB)); + OPENSSL_memset(cbb, 0, sizeof(CBB)); } static int cbb_init(CBB *cbb, uint8_t *buf, size_t cap) { @@ -37,6 +39,7 @@ static int cbb_init(CBB *cbb, uint8_t *buf, size_t cap) { base->len = 0; base->cap = cap; base->can_resize = 1; + base->error = 0; cbb->base = base; cbb->is_top_level = 1; @@ -95,7 +98,7 @@ static int cbb_buffer_reserve(struct cbb_buffer_st *base, uint8_t **out, newlen = base->len + len; if (newlen < base->len) { /* Overflow */ - return 0; + goto err; } if (newlen > base->cap) { @@ -103,7 +106,7 @@ static int cbb_buffer_reserve(struct cbb_buffer_st *base, uint8_t **out, uint8_t *newbuf; if (!base->can_resize) { - return 0; + goto err; } if (newcap < base->cap || newcap < newlen) { @@ -111,7 +114,7 @@ static int cbb_buffer_reserve(struct cbb_buffer_st *base, uint8_t **out, } newbuf = OPENSSL_realloc(base->buf, newcap); if (newbuf == NULL) { - return 0; + goto err; } base->buf = newbuf; @@ -123,6 +126,10 @@ static int cbb_buffer_reserve(struct cbb_buffer_st *base, uint8_t **out, } return 1; + +err: + base->error = 1; + return 0; } static int cbb_buffer_add(struct cbb_buffer_st *base, uint8_t **out, @@ -137,20 +144,25 @@ static int cbb_buffer_add(struct cbb_buffer_st *base, uint8_t **out, static int cbb_buffer_add_u(struct cbb_buffer_st *base, uint32_t v, size_t len_len) { - uint8_t *buf; - size_t i; - if (len_len == 0) { return 1; } + + uint8_t *buf; if (!cbb_buffer_add(base, &buf, len_len)) { return 0; } - for (i = len_len - 1; i < len_len; i--) { + for (size_t i = len_len - 1; i < len_len; i--) { buf[i] = v; v >>= 8; } + + if (v != 0) { + base->error = 1; + return 0; + } + return 1; } @@ -185,7 +197,10 @@ int CBB_finish(CBB *cbb, uint8_t **out_data, size_t *out_len) { int CBB_flush(CBB *cbb) { size_t child_start, i, len; - if (cbb->base == NULL) { + /* If |cbb->base| has hit an error, the buffer is in an undefined state, so + * fail all following calls. In particular, |cbb->child| may point to invalid + * memory. */ + if (cbb->base == NULL || cbb->base->error) { return 0; } @@ -198,7 +213,7 @@ int CBB_flush(CBB *cbb) { if (!CBB_flush(cbb->child) || child_start < cbb->child->offset || cbb->base->len < child_start) { - return 0; + goto err; } len = cbb->base->len - child_start; @@ -207,14 +222,14 @@ int CBB_flush(CBB *cbb) { /* For ASN.1 we assume that we'll only need a single byte for the length. * If that turned out to be incorrect, we have to move the contents along * in order to make space. */ - size_t len_len; + uint8_t len_len; uint8_t initial_length_byte; assert (cbb->child->pending_len_len == 1); if (len > 0xfffffffe) { /* Too large. */ - return 0; + goto err; } else if (len > 0xffffff) { len_len = 5; initial_length_byte = 0x80 | 4; @@ -229,7 +244,7 @@ int CBB_flush(CBB *cbb) { initial_length_byte = 0x80 | 1; } else { len_len = 1; - initial_length_byte = len; + initial_length_byte = (uint8_t)len; len = 0; } @@ -237,10 +252,10 @@ int CBB_flush(CBB *cbb) { /* We need to move the contents along in order to make space. */ size_t extra_bytes = len_len - 1; if (!cbb_buffer_add(cbb->base, NULL, extra_bytes)) { - return 0; + goto err; } - memmove(cbb->base->buf + child_start + extra_bytes, - cbb->base->buf + child_start, len); + OPENSSL_memmove(cbb->base->buf + child_start + extra_bytes, + cbb->base->buf + child_start, len); } cbb->base->buf[cbb->child->offset++] = initial_length_byte; cbb->child->pending_len_len = len_len - 1; @@ -248,17 +263,21 @@ int CBB_flush(CBB *cbb) { for (i = cbb->child->pending_len_len - 1; i < cbb->child->pending_len_len; i--) { - cbb->base->buf[cbb->child->offset + i] = len; + cbb->base->buf[cbb->child->offset + i] = (uint8_t)len; len >>= 8; } if (len != 0) { - return 0; + goto err; } cbb->child->base = NULL; cbb->child = NULL; return 1; + +err: + cbb->base->error = 1; + return 0; } const uint8_t *CBB_data(const CBB *cbb) { @@ -274,7 +293,7 @@ size_t CBB_len(const CBB *cbb) { } static int cbb_add_length_prefixed(CBB *cbb, CBB *out_contents, - size_t len_len) { + uint8_t len_len) { uint8_t *prefix_bytes; if (!CBB_flush(cbb)) { @@ -286,8 +305,8 @@ static int cbb_add_length_prefixed(CBB *cbb, CBB *out_contents, return 0; } - memset(prefix_bytes, 0, len_len); - memset(out_contents, 0, sizeof(CBB)); + OPENSSL_memset(prefix_bytes, 0, len_len); + OPENSSL_memset(out_contents, 0, sizeof(CBB)); out_contents->base = cbb->base; cbb->child = out_contents; cbb->child->offset = offset; @@ -309,14 +328,18 @@ int CBB_add_u24_length_prefixed(CBB *cbb, CBB *out_contents) { return cbb_add_length_prefixed(cbb, out_contents, 3); } -int CBB_add_asn1(CBB *cbb, CBB *out_contents, uint8_t tag) { - if ((tag & 0x1f) == 0x1f) { - /* Long form identifier octets are not supported. */ +int CBB_add_asn1(CBB *cbb, CBB *out_contents, unsigned tag) { + if (tag > 0xff || + (tag & 0x1f) == 0x1f) { + /* Long form identifier octets are not supported. Further, all current valid + * tag serializations are 8 bits. */ + cbb->base->error = 1; return 0; } if (!CBB_flush(cbb) || - !CBB_add_u8(cbb, tag)) { + /* |tag|'s representation matches the DER encoding. */ + !CBB_add_u8(cbb, (uint8_t)tag)) { return 0; } @@ -325,7 +348,7 @@ int CBB_add_asn1(CBB *cbb, CBB *out_contents, uint8_t tag) { return 0; } - memset(out_contents, 0, sizeof(CBB)); + OPENSSL_memset(out_contents, 0, sizeof(CBB)); out_contents->base = cbb->base; cbb->child = out_contents; cbb->child->offset = offset; @@ -342,7 +365,7 @@ int CBB_add_bytes(CBB *cbb, const uint8_t *data, size_t len) { !cbb_buffer_add(cbb->base, &dest, len)) { return 0; } - memcpy(dest, data, len); + OPENSSL_memcpy(dest, data, len); return 1; } @@ -397,6 +420,14 @@ int CBB_add_u24(CBB *cbb, uint32_t value) { return cbb_buffer_add_u(cbb->base, value, 3); } +int CBB_add_u32(CBB *cbb, uint32_t value) { + if (!CBB_flush(cbb)) { + return 0; + } + + return cbb_buffer_add_u(cbb->base, value, 4); +} + void CBB_discard_child(CBB *cbb) { if (cbb->child == NULL) { return; @@ -410,14 +441,13 @@ void CBB_discard_child(CBB *cbb) { int CBB_add_asn1_uint64(CBB *cbb, uint64_t value) { CBB child; - size_t i; int started = 0; if (!CBB_add_asn1(cbb, &child, CBS_ASN1_INTEGER)) { return 0; } - for (i = 0; i < 8; i++) { + for (size_t i = 0; i < 8; i++) { uint8_t byte = (value >> 8*(7-i)) & 0xff; if (!started) { if (byte == 0) { diff --git a/Sources/BoringSSL/crypto/bytestring/cbs.c b/Sources/BoringSSL/crypto/bytestring/cbs.c index 5e0c538a1..14c55a4dc 100644 --- a/Sources/BoringSSL/crypto/bytestring/cbs.c +++ b/Sources/BoringSSL/crypto/bytestring/cbs.c @@ -20,6 +20,7 @@ #include #include "internal.h" +#include "../internal.h" void CBS_init(CBS *cbs, const uint8_t *data, size_t len) { @@ -76,7 +77,7 @@ int CBS_strdup(const CBS *cbs, char **out_ptr) { } int CBS_contains_zero_byte(const CBS *cbs) { - return memchr(cbs->data, 0, cbs->len) != NULL; + return OPENSSL_memchr(cbs->data, 0, cbs->len) != NULL; } int CBS_mem_equal(const CBS *cbs, const uint8_t *data, size_t len) { @@ -88,13 +89,12 @@ int CBS_mem_equal(const CBS *cbs, const uint8_t *data, size_t len) { static int cbs_get_u(CBS *cbs, uint32_t *out, size_t len) { uint32_t result = 0; - size_t i; const uint8_t *data; if (!cbs_get(cbs, &data, len)) { return 0; } - for (i = 0; i < len; i++) { + for (size_t i = 0; i < len; i++) { result <<= 8; result |= data[i]; } @@ -128,6 +128,15 @@ int CBS_get_u32(CBS *cbs, uint32_t *out) { return cbs_get_u(cbs, out, 4); } +int CBS_get_last_u8(CBS *cbs, uint8_t *out) { + if (cbs->len == 0) { + return 0; + } + *out = cbs->data[cbs->len - 1]; + cbs->len--; + return 1; +} + int CBS_get_bytes(CBS *cbs, CBS *out, size_t len) { const uint8_t *v; if (!cbs_get(cbs, &v, len)) { @@ -142,7 +151,7 @@ int CBS_copy_bytes(CBS *cbs, uint8_t *out, size_t len) { if (!cbs_get(cbs, &v, len)) { return 0; } - memcpy(out, v, len); + OPENSSL_memcpy(out, v, len); return 1; } @@ -181,8 +190,14 @@ static int cbs_get_any_asn1_element(CBS *cbs, CBS *out, unsigned *out_tag, return 0; } + /* ITU-T X.690 section 8.1.2.3 specifies the format for identifiers with a tag + * number no greater than 30. + * + * If the number portion is 31 (0x1f, the largest value that fits in the + * allotted bits), then the tag is more than one byte long and the + * continuation bytes contain the tag number. This parser only supports tag + * numbers less than 31 (and thus single-byte tags). */ if ((tag & 0x1f) == 0x1f) { - /* Long form tags are not supported. */ return 0; } @@ -191,6 +206,8 @@ static int cbs_get_any_asn1_element(CBS *cbs, CBS *out, unsigned *out_tag, } size_t len; + /* The format for the length encoding is specified in ITU-T X.690 section + * 8.1.3. */ if ((length_byte & 0x80) == 0) { /* Short form length. */ len = ((size_t) length_byte) + 2; @@ -198,7 +215,9 @@ static int cbs_get_any_asn1_element(CBS *cbs, CBS *out, unsigned *out_tag, *out_header_len = 2; } } else { - /* Long form length. */ + /* The high bit indicate that this is the long form, while the next 7 bits + * encode the number of subsequent octets used to encode the length (ITU-T + * X.690 clause 8.1.3.5.b). */ const size_t num_bytes = length_byte & 0x7f; uint32_t len32; @@ -210,12 +229,18 @@ static int cbs_get_any_asn1_element(CBS *cbs, CBS *out, unsigned *out_tag, return CBS_get_bytes(cbs, out, 2); } + /* ITU-T X.690 clause 8.1.3.5.c specifies that the value 0xff shall not be + * used as the first byte of the length. If this parser encounters that + * value, num_bytes will be parsed as 127, which will fail the check below. + */ if (num_bytes == 0 || num_bytes > 4) { return 0; } if (!cbs_get_u(&header, &len32, num_bytes)) { return 0; } + /* ITU-T X.690 section 10.1 (DER length forms) requires encoding the length + * with the minimum number of octets. */ if (len32 < 128) { /* Length should have used short-form encoding. */ return 0; @@ -238,6 +263,20 @@ static int cbs_get_any_asn1_element(CBS *cbs, CBS *out, unsigned *out_tag, return CBS_get_bytes(cbs, out, len); } +int CBS_get_any_asn1(CBS *cbs, CBS *out, unsigned *out_tag) { + size_t header_len; + if (!CBS_get_any_asn1_element(cbs, out, out_tag, &header_len)) { + return 0; + } + + if (!CBS_skip(out, header_len)) { + assert(0); + return 0; + } + + return 1; +} + int CBS_get_any_asn1_element(CBS *cbs, CBS *out, unsigned *out_tag, size_t *out_header_len) { return cbs_get_any_asn1_element(cbs, out, out_tag, out_header_len, @@ -413,3 +452,40 @@ int CBS_get_optional_asn1_bool(CBS *cbs, int *out, unsigned tag, } return 1; } + +int CBS_is_valid_asn1_bitstring(const CBS *cbs) { + CBS in = *cbs; + uint8_t num_unused_bits; + if (!CBS_get_u8(&in, &num_unused_bits) || + num_unused_bits > 7) { + return 0; + } + + if (num_unused_bits == 0) { + return 1; + } + + /* All num_unused_bits bits must exist and be zeros. */ + uint8_t last; + if (!CBS_get_last_u8(&in, &last) || + (last & ((1 << num_unused_bits) - 1)) != 0) { + return 0; + } + + return 1; +} + +int CBS_asn1_bitstring_has_bit(const CBS *cbs, unsigned bit) { + if (!CBS_is_valid_asn1_bitstring(cbs)) { + return 0; + } + + const unsigned byte_num = (bit >> 3) + 1; + const unsigned bit_num = 7 - (bit & 7); + + /* Unused bits are zero, and this function does not distinguish between + * missing and unset bits. Thus it is sufficient to do a byte-level length + * check. */ + return byte_num < CBS_len(cbs) && + (CBS_data(cbs)[byte_num] & (1 << bit_num)) != 0; +} diff --git a/Sources/BoringSSL/crypto/chacha/chacha_generic.c b/Sources/BoringSSL/crypto/chacha/chacha.c similarity index 64% rename from Sources/BoringSSL/crypto/chacha/chacha_generic.c rename to Sources/BoringSSL/crypto/chacha/chacha.c index f262033c4..fe32596a2 100644 --- a/Sources/BoringSSL/crypto/chacha/chacha_generic.c +++ b/Sources/BoringSSL/crypto/chacha/chacha.c @@ -16,21 +16,64 @@ #include +#include #include #include +#include "../internal.h" -#if defined(OPENSSL_WINDOWS) || (!defined(OPENSSL_X86_64) && !defined(OPENSSL_X86)) || !defined(__SSE2__) + +#define U8TO32_LITTLE(p) \ + (((uint32_t)((p)[0])) | ((uint32_t)((p)[1]) << 8) | \ + ((uint32_t)((p)[2]) << 16) | ((uint32_t)((p)[3]) << 24)) + +#if !defined(OPENSSL_NO_ASM) && \ + (defined(OPENSSL_X86) || defined(OPENSSL_X86_64) || \ + defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64)) + +/* ChaCha20_ctr32 is defined in asm/chacha-*.pl. */ +void ChaCha20_ctr32(uint8_t *out, const uint8_t *in, size_t in_len, + const uint32_t key[8], const uint32_t counter[4]); + +void CRYPTO_chacha_20(uint8_t *out, const uint8_t *in, size_t in_len, + const uint8_t key[32], const uint8_t nonce[12], + uint32_t counter) { + assert(!buffers_alias(out, in_len, in, in_len) || in == out); + + uint32_t counter_nonce[4]; counter_nonce[0] = counter; + counter_nonce[1] = U8TO32_LITTLE(nonce + 0); + counter_nonce[2] = U8TO32_LITTLE(nonce + 4); + counter_nonce[3] = U8TO32_LITTLE(nonce + 8); + + const uint32_t *key_ptr = (const uint32_t *)key; +#if !defined(OPENSSL_X86) && !defined(OPENSSL_X86_64) + /* The assembly expects the key to be four-byte aligned. */ + uint32_t key_u32[8]; + if ((((uintptr_t)key) & 3) != 0) { + key_u32[0] = U8TO32_LITTLE(key + 0); + key_u32[1] = U8TO32_LITTLE(key + 4); + key_u32[2] = U8TO32_LITTLE(key + 8); + key_u32[3] = U8TO32_LITTLE(key + 12); + key_u32[4] = U8TO32_LITTLE(key + 16); + key_u32[5] = U8TO32_LITTLE(key + 20); + key_u32[6] = U8TO32_LITTLE(key + 24); + key_u32[7] = U8TO32_LITTLE(key + 28); + + key_ptr = key_u32; + } +#endif + + ChaCha20_ctr32(out, in, in_len, key_ptr, counter_nonce); +} + +#else /* sigma contains the ChaCha constants, which happen to be an ASCII string. */ static const uint8_t sigma[16] = { 'e', 'x', 'p', 'a', 'n', 'd', ' ', '3', '2', '-', 'b', 'y', 't', 'e', ' ', 'k' }; #define ROTATE(v, n) (((v) << (n)) | ((v) >> (32 - (n)))) -#define XOR(v, w) ((v) ^ (w)) -#define PLUS(x, y) ((x) + (y)) -#define PLUSONE(v) (PLUS((v), 1)) #define U32TO8_LITTLE(p, v) \ { \ @@ -40,23 +83,12 @@ static const uint8_t sigma[16] = { 'e', 'x', 'p', 'a', 'n', 'd', ' ', '3', (p)[3] = (v >> 24) & 0xff; \ } -#define U8TO32_LITTLE(p) \ - (((uint32_t)((p)[0])) | ((uint32_t)((p)[1]) << 8) | \ - ((uint32_t)((p)[2]) << 16) | ((uint32_t)((p)[3]) << 24)) - /* QUARTERROUND updates a, b, c, d with a ChaCha "quarter" round. */ -#define QUARTERROUND(a,b,c,d) \ - x[a] = PLUS(x[a],x[b]); x[d] = ROTATE(XOR(x[d],x[a]),16); \ - x[c] = PLUS(x[c],x[d]); x[b] = ROTATE(XOR(x[b],x[c]),12); \ - x[a] = PLUS(x[a],x[b]); x[d] = ROTATE(XOR(x[d],x[a]), 8); \ - x[c] = PLUS(x[c],x[d]); x[b] = ROTATE(XOR(x[b],x[c]), 7); - -#if defined(OPENSSL_ARM) && !defined(OPENSSL_NO_ASM) -/* Defined in chacha_vec.c */ -void CRYPTO_chacha_20_neon(uint8_t *out, const uint8_t *in, size_t in_len, - const uint8_t key[32], const uint8_t nonce[12], - uint32_t counter); -#endif +#define QUARTERROUND(a, b, c, d) \ + x[a] += x[b]; x[d] = ROTATE(x[d] ^ x[a], 16); \ + x[c] += x[d]; x[b] = ROTATE(x[b] ^ x[c], 12); \ + x[a] += x[b]; x[d] = ROTATE(x[d] ^ x[a], 8); \ + x[c] += x[d]; x[b] = ROTATE(x[b] ^ x[c], 7); /* chacha_core performs 20 rounds of ChaCha on the input words in * |input| and writes the 64 output bytes to |output|. */ @@ -64,7 +96,7 @@ static void chacha_core(uint8_t output[64], const uint32_t input[16]) { uint32_t x[16]; int i; - memcpy(x, input, sizeof(uint32_t) * 16); + OPENSSL_memcpy(x, input, sizeof(uint32_t) * 16); for (i = 20; i > 0; i -= 2) { QUARTERROUND(0, 4, 8, 12) QUARTERROUND(1, 5, 9, 13) @@ -77,7 +109,7 @@ static void chacha_core(uint8_t output[64], const uint32_t input[16]) { } for (i = 0; i < 16; ++i) { - x[i] = PLUS(x[i], input[i]); + x[i] += input[i]; } for (i = 0; i < 16; ++i) { U32TO8_LITTLE(output + 4 * i, x[i]); @@ -87,17 +119,12 @@ static void chacha_core(uint8_t output[64], const uint32_t input[16]) { void CRYPTO_chacha_20(uint8_t *out, const uint8_t *in, size_t in_len, const uint8_t key[32], const uint8_t nonce[12], uint32_t counter) { + assert(!buffers_alias(out, in_len, in, in_len) || in == out); + uint32_t input[16]; uint8_t buf[64]; size_t todo, i; -#if defined(OPENSSL_ARM) && !defined(OPENSSL_NO_ASM) - if (CRYPTO_is_NEON_capable()) { - CRYPTO_chacha_20_neon(out, in, in_len, key, nonce, counter); - return; - } -#endif - input[0] = U8TO32_LITTLE(sigma + 0); input[1] = U8TO32_LITTLE(sigma + 4); input[2] = U8TO32_LITTLE(sigma + 8); @@ -137,4 +164,4 @@ void CRYPTO_chacha_20(uint8_t *out, const uint8_t *in, size_t in_len, } } -#endif /* OPENSSL_WINDOWS || !OPENSSL_X86_64 && !OPENSSL_X86 || !__SSE2__ */ +#endif diff --git a/Sources/BoringSSL/crypto/chacha/chacha_vec.c b/Sources/BoringSSL/crypto/chacha/chacha_vec.c deleted file mode 100644 index 90d62002f..000000000 --- a/Sources/BoringSSL/crypto/chacha/chacha_vec.c +++ /dev/null @@ -1,328 +0,0 @@ -/* Copyright (c) 2014, Google Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ - -/* ==================================================================== - * - * When updating this file, also update chacha_vec_arm.S - * - * ==================================================================== */ - - -/* This implementation is by Ted Krovetz and was submitted to SUPERCOP and - * marked as public domain. It was been altered to allow for non-aligned inputs - * and to allow the block counter to be passed in specifically. */ - -#include - -#include "../internal.h" - - -#if defined(ASM_GEN) || \ - !defined(OPENSSL_WINDOWS) && \ - (defined(OPENSSL_X86_64) || defined(OPENSSL_X86)) && defined(__SSE2__) - -#define CHACHA_RNDS 20 /* 8 (high speed), 20 (conservative), 12 (middle) */ - -/* Architecture-neutral way to specify 16-byte vector of ints */ -typedef unsigned vec __attribute__((vector_size(16))); - -/* This implementation is designed for Neon, SSE and AltiVec machines. The - * following specify how to do certain vector operations efficiently on - * each architecture, using intrinsics. - * This implementation supports parallel processing of multiple blocks, - * including potentially using general-purpose registers. */ -#if __ARM_NEON__ -#include -#include -#define GPR_TOO 1 -#define VBPI 2 -#define ONE (vec) vsetq_lane_u32(1, vdupq_n_u32(0), 0) -#define LOAD_ALIGNED(m) (vec)(*((vec *)(m))) -#define LOAD(m) ({ \ - memcpy(alignment_buffer, m, 16); \ - LOAD_ALIGNED(alignment_buffer); \ - }) -#define STORE(m, r) ({ \ - (*((vec *)(alignment_buffer))) = (r); \ - memcpy(m, alignment_buffer, 16); \ - }) -#define ROTV1(x) (vec) vextq_u32((uint32x4_t)x, (uint32x4_t)x, 1) -#define ROTV2(x) (vec) vextq_u32((uint32x4_t)x, (uint32x4_t)x, 2) -#define ROTV3(x) (vec) vextq_u32((uint32x4_t)x, (uint32x4_t)x, 3) -#define ROTW16(x) (vec) vrev32q_u16((uint16x8_t)x) -#if __clang__ -#define ROTW7(x) (x << ((vec) {7, 7, 7, 7})) ^ (x >> ((vec) {25, 25, 25, 25})) -#define ROTW8(x) (x << ((vec) {8, 8, 8, 8})) ^ (x >> ((vec) {24, 24, 24, 24})) -#define ROTW12(x) \ - (x << ((vec) {12, 12, 12, 12})) ^ (x >> ((vec) {20, 20, 20, 20})) -#else -#define ROTW7(x) \ - (vec) vsriq_n_u32(vshlq_n_u32((uint32x4_t)x, 7), (uint32x4_t)x, 25) -#define ROTW8(x) \ - (vec) vsriq_n_u32(vshlq_n_u32((uint32x4_t)x, 8), (uint32x4_t)x, 24) -#define ROTW12(x) \ - (vec) vsriq_n_u32(vshlq_n_u32((uint32x4_t)x, 12), (uint32x4_t)x, 20) -#endif -#elif __SSE2__ -#include -#define GPR_TOO 0 -#if __clang__ -#define VBPI 4 -#else -#define VBPI 3 -#endif -#define ONE (vec) _mm_set_epi32(0, 0, 0, 1) -#define LOAD(m) (vec) _mm_loadu_si128((const __m128i *)(m)) -#define LOAD_ALIGNED(m) (vec) _mm_load_si128((const __m128i *)(m)) -#define STORE(m, r) _mm_storeu_si128((__m128i *)(m), (__m128i)(r)) -#define ROTV1(x) (vec) _mm_shuffle_epi32((__m128i)x, _MM_SHUFFLE(0, 3, 2, 1)) -#define ROTV2(x) (vec) _mm_shuffle_epi32((__m128i)x, _MM_SHUFFLE(1, 0, 3, 2)) -#define ROTV3(x) (vec) _mm_shuffle_epi32((__m128i)x, _MM_SHUFFLE(2, 1, 0, 3)) -#define ROTW7(x) \ - (vec)(_mm_slli_epi32((__m128i)x, 7) ^ _mm_srli_epi32((__m128i)x, 25)) -#define ROTW12(x) \ - (vec)(_mm_slli_epi32((__m128i)x, 12) ^ _mm_srli_epi32((__m128i)x, 20)) -#if __SSSE3__ -#include -#define ROTW8(x) \ - (vec) _mm_shuffle_epi8((__m128i)x, _mm_set_epi8(14, 13, 12, 15, 10, 9, 8, \ - 11, 6, 5, 4, 7, 2, 1, 0, 3)) -#define ROTW16(x) \ - (vec) _mm_shuffle_epi8((__m128i)x, _mm_set_epi8(13, 12, 15, 14, 9, 8, 11, \ - 10, 5, 4, 7, 6, 1, 0, 3, 2)) -#else -#define ROTW8(x) \ - (vec)(_mm_slli_epi32((__m128i)x, 8) ^ _mm_srli_epi32((__m128i)x, 24)) -#define ROTW16(x) \ - (vec)(_mm_slli_epi32((__m128i)x, 16) ^ _mm_srli_epi32((__m128i)x, 16)) -#endif -#else -#error-- Implementation supports only machines with neon or SSE2 -#endif - -#ifndef REVV_BE -#define REVV_BE(x) (x) -#endif - -#ifndef REVW_BE -#define REVW_BE(x) (x) -#endif - -#define BPI (VBPI + GPR_TOO) /* Blocks computed per loop iteration */ - -#define DQROUND_VECTORS(a,b,c,d) \ - a += b; d ^= a; d = ROTW16(d); \ - c += d; b ^= c; b = ROTW12(b); \ - a += b; d ^= a; d = ROTW8(d); \ - c += d; b ^= c; b = ROTW7(b); \ - b = ROTV1(b); c = ROTV2(c); d = ROTV3(d); \ - a += b; d ^= a; d = ROTW16(d); \ - c += d; b ^= c; b = ROTW12(b); \ - a += b; d ^= a; d = ROTW8(d); \ - c += d; b ^= c; b = ROTW7(b); \ - b = ROTV3(b); c = ROTV2(c); d = ROTV1(d); - -#define QROUND_WORDS(a,b,c,d) \ - a = a+b; d ^= a; d = d<<16 | d>>16; \ - c = c+d; b ^= c; b = b<<12 | b>>20; \ - a = a+b; d ^= a; d = d<< 8 | d>>24; \ - c = c+d; b ^= c; b = b<< 7 | b>>25; - -#define WRITE_XOR(in, op, d, v0, v1, v2, v3) \ - STORE(op + d + 0, LOAD(in + d + 0) ^ REVV_BE(v0)); \ - STORE(op + d + 4, LOAD(in + d + 4) ^ REVV_BE(v1)); \ - STORE(op + d + 8, LOAD(in + d + 8) ^ REVV_BE(v2)); \ - STORE(op + d +12, LOAD(in + d +12) ^ REVV_BE(v3)); - -#if __ARM_NEON__ -/* For ARM, we can't depend on NEON support, so this function is compiled with - * a different name, along with the generic code, and can be enabled at - * run-time. */ -void CRYPTO_chacha_20_neon( -#else -void CRYPTO_chacha_20( -#endif - uint8_t *out, - const uint8_t *in, - size_t inlen, - const uint8_t key[32], - const uint8_t nonce[12], - uint32_t counter) - { - unsigned iters, i; - unsigned *op = (unsigned *)out; - const unsigned *ip = (const unsigned *)in; - const unsigned *kp = (const unsigned *)key; -#if defined(__ARM_NEON__) - uint32_t np[3]; - alignas(16) uint8_t alignment_buffer[16]; -#endif - vec s0, s1, s2, s3; - alignas(16) unsigned chacha_const[] = - {0x61707865,0x3320646E,0x79622D32,0x6B206574}; -#if defined(__ARM_NEON__) - memcpy(np, nonce, 12); -#endif - s0 = LOAD_ALIGNED(chacha_const); - s1 = LOAD(&((const vec*)kp)[0]); - s2 = LOAD(&((const vec*)kp)[1]); - s3 = (vec){ - counter, - ((const uint32_t*)nonce)[0], - ((const uint32_t*)nonce)[1], - ((const uint32_t*)nonce)[2] - }; - - for (iters = 0; iters < inlen/(BPI*64); iters++) - { -#if GPR_TOO - register unsigned x0, x1, x2, x3, x4, x5, x6, x7, x8, - x9, x10, x11, x12, x13, x14, x15; -#endif -#if VBPI > 2 - vec v8,v9,v10,v11; -#endif -#if VBPI > 3 - vec v12,v13,v14,v15; -#endif - - vec v0,v1,v2,v3,v4,v5,v6,v7; - v4 = v0 = s0; v5 = v1 = s1; v6 = v2 = s2; v3 = s3; - v7 = v3 + ONE; -#if VBPI > 2 - v8 = v4; v9 = v5; v10 = v6; - v11 = v7 + ONE; -#endif -#if VBPI > 3 - v12 = v8; v13 = v9; v14 = v10; - v15 = v11 + ONE; -#endif -#if GPR_TOO - x0 = chacha_const[0]; x1 = chacha_const[1]; - x2 = chacha_const[2]; x3 = chacha_const[3]; - x4 = kp[0]; x5 = kp[1]; x6 = kp[2]; x7 = kp[3]; - x8 = kp[4]; x9 = kp[5]; x10 = kp[6]; x11 = kp[7]; - x12 = counter+BPI*iters+(BPI-1); x13 = np[0]; - x14 = np[1]; x15 = np[2]; -#endif - for (i = CHACHA_RNDS/2; i; i--) - { - DQROUND_VECTORS(v0,v1,v2,v3) - DQROUND_VECTORS(v4,v5,v6,v7) -#if VBPI > 2 - DQROUND_VECTORS(v8,v9,v10,v11) -#endif -#if VBPI > 3 - DQROUND_VECTORS(v12,v13,v14,v15) -#endif -#if GPR_TOO - QROUND_WORDS( x0, x4, x8,x12) - QROUND_WORDS( x1, x5, x9,x13) - QROUND_WORDS( x2, x6,x10,x14) - QROUND_WORDS( x3, x7,x11,x15) - QROUND_WORDS( x0, x5,x10,x15) - QROUND_WORDS( x1, x6,x11,x12) - QROUND_WORDS( x2, x7, x8,x13) - QROUND_WORDS( x3, x4, x9,x14) -#endif - } - - WRITE_XOR(ip, op, 0, v0+s0, v1+s1, v2+s2, v3+s3) - s3 += ONE; - WRITE_XOR(ip, op, 16, v4+s0, v5+s1, v6+s2, v7+s3) - s3 += ONE; -#if VBPI > 2 - WRITE_XOR(ip, op, 32, v8+s0, v9+s1, v10+s2, v11+s3) - s3 += ONE; -#endif -#if VBPI > 3 - WRITE_XOR(ip, op, 48, v12+s0, v13+s1, v14+s2, v15+s3) - s3 += ONE; -#endif - ip += VBPI*16; - op += VBPI*16; -#if GPR_TOO - op[0] = REVW_BE(REVW_BE(ip[0]) ^ (x0 + chacha_const[0])); - op[1] = REVW_BE(REVW_BE(ip[1]) ^ (x1 + chacha_const[1])); - op[2] = REVW_BE(REVW_BE(ip[2]) ^ (x2 + chacha_const[2])); - op[3] = REVW_BE(REVW_BE(ip[3]) ^ (x3 + chacha_const[3])); - op[4] = REVW_BE(REVW_BE(ip[4]) ^ (x4 + kp[0])); - op[5] = REVW_BE(REVW_BE(ip[5]) ^ (x5 + kp[1])); - op[6] = REVW_BE(REVW_BE(ip[6]) ^ (x6 + kp[2])); - op[7] = REVW_BE(REVW_BE(ip[7]) ^ (x7 + kp[3])); - op[8] = REVW_BE(REVW_BE(ip[8]) ^ (x8 + kp[4])); - op[9] = REVW_BE(REVW_BE(ip[9]) ^ (x9 + kp[5])); - op[10] = REVW_BE(REVW_BE(ip[10]) ^ (x10 + kp[6])); - op[11] = REVW_BE(REVW_BE(ip[11]) ^ (x11 + kp[7])); - op[12] = REVW_BE(REVW_BE(ip[12]) ^ (x12 + counter+BPI*iters+(BPI-1))); - op[13] = REVW_BE(REVW_BE(ip[13]) ^ (x13 + np[0])); - op[14] = REVW_BE(REVW_BE(ip[14]) ^ (x14 + np[1])); - op[15] = REVW_BE(REVW_BE(ip[15]) ^ (x15 + np[2])); - s3 += ONE; - ip += 16; - op += 16; -#endif - } - - for (iters = inlen%(BPI*64)/64; iters != 0; iters--) - { - vec v0 = s0, v1 = s1, v2 = s2, v3 = s3; - for (i = CHACHA_RNDS/2; i; i--) - { - DQROUND_VECTORS(v0,v1,v2,v3); - } - WRITE_XOR(ip, op, 0, v0+s0, v1+s1, v2+s2, v3+s3) - s3 += ONE; - ip += 16; - op += 16; - } - - inlen = inlen % 64; - if (inlen) - { - alignas(16) vec buf[4]; - vec v0,v1,v2,v3; - v0 = s0; v1 = s1; v2 = s2; v3 = s3; - for (i = CHACHA_RNDS/2; i; i--) - { - DQROUND_VECTORS(v0,v1,v2,v3); - } - - if (inlen >= 16) - { - STORE(op + 0, LOAD(ip + 0) ^ REVV_BE(v0 + s0)); - if (inlen >= 32) - { - STORE(op + 4, LOAD(ip + 4) ^ REVV_BE(v1 + s1)); - if (inlen >= 48) - { - STORE(op + 8, LOAD(ip + 8) ^ - REVV_BE(v2 + s2)); - buf[3] = REVV_BE(v3 + s3); - } - else - buf[2] = REVV_BE(v2 + s2); - } - else - buf[1] = REVV_BE(v1 + s1); - } - else - buf[0] = REVV_BE(v0 + s0); - - for (i=inlen & ~15; i #include "internal.h" +#include "../internal.h" size_t EVP_AEAD_key_length(const EVP_AEAD *aead) { return aead->key_len; } @@ -31,7 +32,7 @@ size_t EVP_AEAD_max_overhead(const EVP_AEAD *aead) { return aead->overhead; } size_t EVP_AEAD_max_tag_len(const EVP_AEAD *aead) { return aead->max_tag_len; } void EVP_AEAD_CTX_zero(EVP_AEAD_CTX *ctx) { - memset(ctx, 0, sizeof(EVP_AEAD_CTX)); + OPENSSL_memset(ctx, 0, sizeof(EVP_AEAD_CTX)); } int EVP_AEAD_CTX_init(EVP_AEAD_CTX *ctx, const EVP_AEAD *aead, @@ -80,21 +81,15 @@ void EVP_AEAD_CTX_cleanup(EVP_AEAD_CTX *ctx) { ctx->aead = NULL; } -/* check_alias returns 0 if |out| points within the buffer determined by |in| - * and |in_len| and 1 otherwise. - * - * When processing, there's only an issue if |out| points within in[:in_len] - * and isn't equal to |in|. If that's the case then writing the output will - * stomp input that hasn't been read yet. - * - * This function checks for that case. */ -static int check_alias(const uint8_t *in, size_t in_len, const uint8_t *out) { - if (out <= in) { - return 1; - } else if (in + in_len <= out) { +/* check_alias returns 1 if |out| is compatible with |in| and 0 otherwise. If + * |in| and |out| alias, we require that |in| == |out|. */ +static int check_alias(const uint8_t *in, size_t in_len, const uint8_t *out, + size_t out_len) { + if (!buffers_alias(in, in_len, out, out_len)) { return 1; } - return 0; + + return in == out; } int EVP_AEAD_CTX_seal(const EVP_AEAD_CTX *ctx, uint8_t *out, size_t *out_len, @@ -108,7 +103,7 @@ int EVP_AEAD_CTX_seal(const EVP_AEAD_CTX *ctx, uint8_t *out, size_t *out_len, goto error; } - if (!check_alias(in, in_len, out)) { + if (!check_alias(in, in_len, out, max_out_len)) { OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_OUTPUT_ALIASES_INPUT); goto error; } @@ -121,7 +116,7 @@ int EVP_AEAD_CTX_seal(const EVP_AEAD_CTX *ctx, uint8_t *out, size_t *out_len, error: /* In the event of an error, clear the output buffer so that a caller * that doesn't check the return value doesn't send raw data. */ - memset(out, 0, max_out_len); + OPENSSL_memset(out, 0, max_out_len); *out_len = 0; return 0; } @@ -130,7 +125,7 @@ int EVP_AEAD_CTX_open(const EVP_AEAD_CTX *ctx, uint8_t *out, size_t *out_len, size_t max_out_len, const uint8_t *nonce, size_t nonce_len, const uint8_t *in, size_t in_len, const uint8_t *ad, size_t ad_len) { - if (!check_alias(in, in_len, out)) { + if (!check_alias(in, in_len, out, max_out_len)) { OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_OUTPUT_ALIASES_INPUT); goto error; } @@ -144,18 +139,12 @@ int EVP_AEAD_CTX_open(const EVP_AEAD_CTX *ctx, uint8_t *out, size_t *out_len, /* In the event of an error, clear the output buffer so that a caller * that doesn't check the return value doesn't try and process bad * data. */ - memset(out, 0, max_out_len); + OPENSSL_memset(out, 0, max_out_len); *out_len = 0; return 0; } -int EVP_AEAD_CTX_get_rc4_state(const EVP_AEAD_CTX *ctx, const RC4_KEY **out_key) { - if (ctx->aead->get_rc4_state == NULL) { - return 0; - } - - return ctx->aead->get_rc4_state(ctx, out_key); -} +const EVP_AEAD *EVP_AEAD_CTX_aead(const EVP_AEAD_CTX *ctx) { return ctx->aead; } int EVP_AEAD_CTX_get_iv(const EVP_AEAD_CTX *ctx, const uint8_t **out_iv, size_t *out_len) { diff --git a/Sources/BoringSSL/crypto/cipher/cipher.c b/Sources/BoringSSL/crypto/cipher/cipher.c index 440186752..e46e43ef1 100644 --- a/Sources/BoringSSL/crypto/cipher/cipher.c +++ b/Sources/BoringSSL/crypto/cipher/cipher.c @@ -61,9 +61,10 @@ #include #include -#include +#include #include "internal.h" +#include "../internal.h" const EVP_CIPHER *EVP_get_cipherbynid(int nid) { @@ -88,7 +89,7 @@ const EVP_CIPHER *EVP_get_cipherbynid(int nid) { } void EVP_CIPHER_CTX_init(EVP_CIPHER_CTX *ctx) { - memset(ctx, 0, sizeof(EVP_CIPHER_CTX)); + OPENSSL_memset(ctx, 0, sizeof(EVP_CIPHER_CTX)); } EVP_CIPHER_CTX *EVP_CIPHER_CTX_new(void) { @@ -108,7 +109,7 @@ int EVP_CIPHER_CTX_cleanup(EVP_CIPHER_CTX *c) { } OPENSSL_free(c->cipher_data); - memset(c, 0, sizeof(EVP_CIPHER_CTX)); + OPENSSL_memset(c, 0, sizeof(EVP_CIPHER_CTX)); return 1; } @@ -126,19 +127,23 @@ int EVP_CIPHER_CTX_copy(EVP_CIPHER_CTX *out, const EVP_CIPHER_CTX *in) { } EVP_CIPHER_CTX_cleanup(out); - memcpy(out, in, sizeof(EVP_CIPHER_CTX)); + OPENSSL_memcpy(out, in, sizeof(EVP_CIPHER_CTX)); if (in->cipher_data && in->cipher->ctx_size) { out->cipher_data = OPENSSL_malloc(in->cipher->ctx_size); if (!out->cipher_data) { + out->cipher = NULL; OPENSSL_PUT_ERROR(CIPHER, ERR_R_MALLOC_FAILURE); return 0; } - memcpy(out->cipher_data, in->cipher_data, in->cipher->ctx_size); + OPENSSL_memcpy(out->cipher_data, in->cipher_data, in->cipher->ctx_size); } if (in->cipher->flags & EVP_CIPH_CUSTOM_COPY) { - return in->cipher->ctrl((EVP_CIPHER_CTX *)in, EVP_CTRL_COPY, 0, out); + if (!in->cipher->ctrl((EVP_CIPHER_CTX *)in, EVP_CTRL_COPY, 0, out)) { + out->cipher = NULL; + return 0; + } } return 1; @@ -210,9 +215,9 @@ int EVP_CipherInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, case EVP_CIPH_CBC_MODE: assert(EVP_CIPHER_CTX_iv_length(ctx) <= sizeof(ctx->iv)); if (iv) { - memcpy(ctx->oiv, iv, EVP_CIPHER_CTX_iv_length(ctx)); + OPENSSL_memcpy(ctx->oiv, iv, EVP_CIPHER_CTX_iv_length(ctx)); } - memcpy(ctx->iv, ctx->oiv, EVP_CIPHER_CTX_iv_length(ctx)); + OPENSSL_memcpy(ctx->iv, ctx->oiv, EVP_CIPHER_CTX_iv_length(ctx)); break; case EVP_CIPH_CTR_MODE: @@ -220,7 +225,7 @@ int EVP_CipherInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, ctx->num = 0; /* Don't reuse IV for CTR mode */ if (iv) { - memcpy(ctx->iv, iv, EVP_CIPHER_CTX_iv_length(ctx)); + OPENSSL_memcpy(ctx->iv, iv, EVP_CIPHER_CTX_iv_length(ctx)); } break; @@ -284,14 +289,14 @@ int EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, uint8_t *out, int *out_len, bl = ctx->cipher->block_size; assert(bl <= (int)sizeof(ctx->buf)); if (i != 0) { - if (i + in_len < bl) { - memcpy(&ctx->buf[i], in, in_len); + if (bl - i > in_len) { + OPENSSL_memcpy(&ctx->buf[i], in, in_len); ctx->buf_len += in_len; *out_len = 0; return 1; } else { j = bl - i; - memcpy(&ctx->buf[i], in, j); + OPENSSL_memcpy(&ctx->buf[i], in, j); if (!ctx->cipher->cipher(ctx, out, ctx->buf, bl)) { return 0; } @@ -314,7 +319,7 @@ int EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, uint8_t *out, int *out_len, } if (i != 0) { - memcpy(ctx->buf, &in[in_len], i); + OPENSSL_memcpy(ctx->buf, &in[in_len], i); } ctx->buf_len = i; return 1; @@ -393,7 +398,7 @@ int EVP_DecryptUpdate(EVP_CIPHER_CTX *ctx, uint8_t *out, int *out_len, assert(b <= sizeof(ctx->final)); if (ctx->final_used) { - memcpy(out, ctx->final, b); + OPENSSL_memcpy(out, ctx->final, b); out += b; fix_len = 1; } else { @@ -409,7 +414,7 @@ int EVP_DecryptUpdate(EVP_CIPHER_CTX *ctx, uint8_t *out, int *out_len, if (b > 1 && !ctx->buf_len) { *out_len -= b; ctx->final_used = 1; - memcpy(ctx->final, &out[*out_len], b); + OPENSSL_memcpy(ctx->final, &out[*out_len], b); } else { ctx->final_used = 0; } diff --git a/Sources/BoringSSL/crypto/cipher/e_aes.c b/Sources/BoringSSL/crypto/cipher/e_aes.c index f7b6fa317..f67cdadbc 100644 --- a/Sources/BoringSSL/crypto/cipher/e_aes.c +++ b/Sources/BoringSSL/crypto/cipher/e_aes.c @@ -54,7 +54,7 @@ #include #include #include -#include +#include #include #include @@ -67,6 +67,8 @@ #endif +OPENSSL_MSVC_PRAGMA(warning(disable: 4702)) /* Unreachable code. */ + typedef struct { union { double align; @@ -123,18 +125,15 @@ static int hwaes_capable(void) { return CRYPTO_is_ARMv8_AES_capable(); } -int aes_v8_set_encrypt_key(const uint8_t *user_key, const int bits, - AES_KEY *key); -int aes_v8_set_decrypt_key(const uint8_t *user_key, const int bits, - AES_KEY *key); -void aes_v8_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key); -void aes_v8_decrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key); -void aes_v8_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t length, - const AES_KEY *key, uint8_t *ivec, const int enc); -void aes_v8_ctr32_encrypt_blocks(const uint8_t *in, uint8_t *out, size_t len, - const AES_KEY *key, const uint8_t ivec[16]); +#elif !defined(OPENSSL_NO_ASM) && defined(OPENSSL_PPC64LE) + +#define HWAES +static int hwaes_capable(void) { + return CRYPTO_is_PPC64LE_vcrypto_capable(); +} + +#endif /* OPENSSL_PPC64LE */ -#endif /* OPENSSL_ARM */ #if defined(BSAES) /* On platforms where BSAES gets defined (just above), then these functions are @@ -200,39 +199,50 @@ static void vpaes_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t length, } #endif -#if !defined(HWAES) +#if defined(HWAES) +int aes_hw_set_encrypt_key(const uint8_t *user_key, const int bits, + AES_KEY *key); +int aes_hw_set_decrypt_key(const uint8_t *user_key, const int bits, + AES_KEY *key); +void aes_hw_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key); +void aes_hw_decrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key); +void aes_hw_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t length, + const AES_KEY *key, uint8_t *ivec, const int enc); +void aes_hw_ctr32_encrypt_blocks(const uint8_t *in, uint8_t *out, size_t len, + const AES_KEY *key, const uint8_t ivec[16]); +#else /* If HWAES isn't defined then we provide dummy functions for each of the hwaes * functions. */ static int hwaes_capable(void) { return 0; } -static int aes_v8_set_encrypt_key(const uint8_t *user_key, int bits, +static int aes_hw_set_encrypt_key(const uint8_t *user_key, int bits, AES_KEY *key) { abort(); } -static int aes_v8_set_decrypt_key(const uint8_t *user_key, int bits, +static int aes_hw_set_decrypt_key(const uint8_t *user_key, int bits, AES_KEY *key) { abort(); } -static void aes_v8_encrypt(const uint8_t *in, uint8_t *out, +static void aes_hw_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) { abort(); } -static void aes_v8_decrypt(const uint8_t *in, uint8_t *out, +static void aes_hw_decrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) { abort(); } -static void aes_v8_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t length, +static void aes_hw_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t length, const AES_KEY *key, uint8_t *ivec, int enc) { abort(); } -static void aes_v8_ctr32_encrypt_blocks(const uint8_t *in, uint8_t *out, +static void aes_hw_ctr32_encrypt_blocks(const uint8_t *in, uint8_t *out, size_t len, const AES_KEY *key, const uint8_t ivec[16]) { abort(); @@ -252,22 +262,6 @@ void aesni_ecb_encrypt(const uint8_t *in, uint8_t *out, size_t length, void aesni_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t length, const AES_KEY *key, uint8_t *ivec, int enc); -void aesni_ctr32_encrypt_blocks(const uint8_t *in, uint8_t *out, size_t blocks, - const void *key, const uint8_t *ivec); - -#if defined(OPENSSL_X86_64) -size_t aesni_gcm_encrypt(const uint8_t *in, uint8_t *out, size_t len, - const void *key, uint8_t ivec[16], uint64_t *Xi); -#define AES_gcm_encrypt aesni_gcm_encrypt -size_t aesni_gcm_decrypt(const uint8_t *in, uint8_t *out, size_t len, - const void *key, uint8_t ivec[16], uint64_t *Xi); -#define AES_gcm_decrypt aesni_gcm_decrypt -void gcm_ghash_avx(uint64_t Xi[2], const u128 Htable[16], const uint8_t *in, - size_t len); -#define AES_GCM_ASM(gctx) \ - (gctx->ctr == aesni_ctr32_encrypt_blocks && gctx->gcm.ghash == gcm_ghash_avx) -#endif /* OPENSSL_X86_64 */ - #else /* On other platforms, aesni_capable() will always return false and so the @@ -288,19 +282,18 @@ static void aesni_ctr32_encrypt_blocks(const uint8_t *in, uint8_t *out, #endif static int aes_init_key(EVP_CIPHER_CTX *ctx, const uint8_t *key, - const uint8_t *iv, int enc) - OPENSSL_SUPPRESS_UNREACHABLE_CODE_WARNINGS { + const uint8_t *iv, int enc) { int ret, mode; EVP_AES_KEY *dat = (EVP_AES_KEY *)ctx->cipher_data; mode = ctx->cipher->flags & EVP_CIPH_MODE_MASK; if ((mode == EVP_CIPH_ECB_MODE || mode == EVP_CIPH_CBC_MODE) && !enc) { if (hwaes_capable()) { - ret = aes_v8_set_decrypt_key(key, ctx->key_len * 8, &dat->ks.ks); - dat->block = (block128_f)aes_v8_decrypt; + ret = aes_hw_set_decrypt_key(key, ctx->key_len * 8, &dat->ks.ks); + dat->block = (block128_f)aes_hw_decrypt; dat->stream.cbc = NULL; if (mode == EVP_CIPH_CBC_MODE) { - dat->stream.cbc = (cbc128_f)aes_v8_cbc_encrypt; + dat->stream.cbc = (cbc128_f)aes_hw_cbc_encrypt; } } else if (bsaes_capable() && mode == EVP_CIPH_CBC_MODE) { ret = AES_set_decrypt_key(key, ctx->key_len * 8, &dat->ks.ks); @@ -318,13 +311,13 @@ static int aes_init_key(EVP_CIPHER_CTX *ctx, const uint8_t *key, mode == EVP_CIPH_CBC_MODE ? (cbc128_f)AES_cbc_encrypt : NULL; } } else if (hwaes_capable()) { - ret = aes_v8_set_encrypt_key(key, ctx->key_len * 8, &dat->ks.ks); - dat->block = (block128_f)aes_v8_encrypt; + ret = aes_hw_set_encrypt_key(key, ctx->key_len * 8, &dat->ks.ks); + dat->block = (block128_f)aes_hw_encrypt; dat->stream.cbc = NULL; if (mode == EVP_CIPH_CBC_MODE) { - dat->stream.cbc = (cbc128_f)aes_v8_cbc_encrypt; + dat->stream.cbc = (cbc128_f)aes_hw_cbc_encrypt; } else if (mode == EVP_CIPH_CTR_MODE) { - dat->stream.ctr = (ctr128_f)aes_v8_ctr32_encrypt_blocks; + dat->stream.ctr = (ctr128_f)aes_hw_ctr32_encrypt_blocks; } } else if (bsaes_capable() && mode == EVP_CIPH_CTR_MODE) { ret = AES_set_encrypt_key(key, ctx->key_len * 8, &dat->ks.ks); @@ -368,14 +361,14 @@ static int aes_cbc_cipher(EVP_CIPHER_CTX *ctx, uint8_t *out, const uint8_t *in, static int aes_ecb_cipher(EVP_CIPHER_CTX *ctx, uint8_t *out, const uint8_t *in, size_t len) { size_t bl = ctx->cipher->block_size; - size_t i; EVP_AES_KEY *dat = (EVP_AES_KEY *)ctx->cipher_data; if (len < bl) { return 1; } - for (i = 0, len -= bl; i <= len; i += bl) { + len -= bl; + for (size_t i = 0; i <= len; i += bl) { (*dat->block)(in + i, out + i, &dat->ks); } @@ -384,17 +377,15 @@ static int aes_ecb_cipher(EVP_CIPHER_CTX *ctx, uint8_t *out, const uint8_t *in, static int aes_ctr_cipher(EVP_CIPHER_CTX *ctx, uint8_t *out, const uint8_t *in, size_t len) { - unsigned num = (unsigned)ctx->num; EVP_AES_KEY *dat = (EVP_AES_KEY *)ctx->cipher_data; if (dat->stream.ctr) { - CRYPTO_ctr128_encrypt_ctr32(in, out, len, &dat->ks, ctx->iv, ctx->buf, &num, - dat->stream.ctr); + CRYPTO_ctr128_encrypt_ctr32(in, out, len, &dat->ks, ctx->iv, ctx->buf, + &ctx->num, dat->stream.ctr); } else { - CRYPTO_ctr128_encrypt(in, out, len, &dat->ks, ctx->iv, ctx->buf, &num, + CRYPTO_ctr128_encrypt(in, out, len, &dat->ks, ctx->iv, ctx->buf, &ctx->num, dat->block); } - ctx->num = (int)num; return 1; } @@ -410,8 +401,7 @@ static char aesni_capable(void); static ctr128_f aes_ctr_set_key(AES_KEY *aes_key, GCM128_CONTEXT *gcm_ctx, block128_f *out_block, const uint8_t *key, - size_t key_len) - OPENSSL_SUPPRESS_UNREACHABLE_CODE_WARNINGS { + size_t key_len) { if (aesni_capable()) { aesni_set_encrypt_key(key, key_len * 8, aes_key); if (gcm_ctx != NULL) { @@ -424,14 +414,14 @@ static ctr128_f aes_ctr_set_key(AES_KEY *aes_key, GCM128_CONTEXT *gcm_ctx, } if (hwaes_capable()) { - aes_v8_set_encrypt_key(key, key_len * 8, aes_key); + aes_hw_set_encrypt_key(key, key_len * 8, aes_key); if (gcm_ctx != NULL) { - CRYPTO_gcm128_init(gcm_ctx, aes_key, (block128_f)aes_v8_encrypt); + CRYPTO_gcm128_init(gcm_ctx, aes_key, (block128_f)aes_hw_encrypt); } if (out_block) { - *out_block = (block128_f) aes_v8_encrypt; + *out_block = (block128_f) aes_hw_encrypt; } - return (ctr128_f)aes_v8_ctr32_encrypt_blocks; + return (ctr128_f)aes_hw_ctr32_encrypt_blocks; } if (bsaes_capable()) { @@ -489,7 +479,7 @@ static int aes_gcm_init_key(EVP_CIPHER_CTX *ctx, const uint8_t *key, if (gctx->key_set) { CRYPTO_gcm128_setiv(&gctx->gcm, &gctx->ks.ks, iv, gctx->ivlen); } else { - memcpy(gctx->iv, iv, gctx->ivlen); + OPENSSL_memcpy(gctx->iv, iv, gctx->ivlen); } gctx->iv_set = 1; gctx->iv_gen = 0; @@ -555,7 +545,7 @@ static int aes_gcm_ctrl(EVP_CIPHER_CTX *c, int type, int arg, void *ptr) { if (arg <= 0 || arg > 16 || c->encrypt) { return 0; } - memcpy(c->buf, ptr, arg); + OPENSSL_memcpy(c->buf, ptr, arg); gctx->taglen = arg; return 1; @@ -563,13 +553,13 @@ static int aes_gcm_ctrl(EVP_CIPHER_CTX *c, int type, int arg, void *ptr) { if (arg <= 0 || arg > 16 || !c->encrypt || gctx->taglen < 0) { return 0; } - memcpy(ptr, c->buf, arg); + OPENSSL_memcpy(ptr, c->buf, arg); return 1; case EVP_CTRL_GCM_SET_IV_FIXED: /* Special case: -1 length restores whole IV */ if (arg == -1) { - memcpy(gctx->iv, ptr, gctx->ivlen); + OPENSSL_memcpy(gctx->iv, ptr, gctx->ivlen); gctx->iv_gen = 1; return 1; } @@ -579,7 +569,7 @@ static int aes_gcm_ctrl(EVP_CIPHER_CTX *c, int type, int arg, void *ptr) { return 0; } if (arg) { - memcpy(gctx->iv, ptr, arg); + OPENSSL_memcpy(gctx->iv, ptr, arg); } if (c->encrypt && !RAND_bytes(gctx->iv + arg, gctx->ivlen - arg)) { return 0; @@ -595,7 +585,7 @@ static int aes_gcm_ctrl(EVP_CIPHER_CTX *c, int type, int arg, void *ptr) { if (arg <= 0 || arg > gctx->ivlen) { arg = gctx->ivlen; } - memcpy(ptr, gctx->iv + gctx->ivlen - arg, arg); + OPENSSL_memcpy(ptr, gctx->iv + gctx->ivlen - arg, arg); /* Invocation field will be at least 8 bytes in size and * so no need to check wrap around or increment more than * last 8 bytes. */ @@ -607,7 +597,7 @@ static int aes_gcm_ctrl(EVP_CIPHER_CTX *c, int type, int arg, void *ptr) { if (gctx->iv_gen == 0 || gctx->key_set == 0 || c->encrypt) { return 0; } - memcpy(gctx->iv + gctx->ivlen - arg, ptr, arg); + OPENSSL_memcpy(gctx->iv + gctx->ivlen - arg, ptr, arg); CRYPTO_gcm128_setiv(&gctx->gcm, &gctx->ks.ks, gctx->iv, gctx->ivlen); gctx->iv_set = 1; return 1; @@ -622,7 +612,7 @@ static int aes_gcm_ctrl(EVP_CIPHER_CTX *c, int type, int arg, void *ptr) { if (!gctx_out->iv) { return 0; } - memcpy(gctx_out->iv, gctx->iv, gctx->ivlen); + OPENSSL_memcpy(gctx_out->iv, gctx->iv, gctx->ivlen); } return 1; } @@ -651,57 +641,23 @@ static int aes_gcm_cipher(EVP_CIPHER_CTX *ctx, uint8_t *out, const uint8_t *in, } } else if (ctx->encrypt) { if (gctx->ctr) { - size_t bulk = 0; -#if defined(AES_GCM_ASM) - if (len >= 32 && AES_GCM_ASM(gctx)) { - size_t res = (16 - gctx->gcm.mres) % 16; - - if (!CRYPTO_gcm128_encrypt(&gctx->gcm, &gctx->ks.ks, in, out, res)) { - return -1; - } - - bulk = AES_gcm_encrypt(in + res, out + res, len - res, &gctx->ks.ks, - gctx->gcm.Yi.c, gctx->gcm.Xi.u); - gctx->gcm.len.u[1] += bulk; - bulk += res; - } -#endif - if (!CRYPTO_gcm128_encrypt_ctr32(&gctx->gcm, &gctx->ks.ks, in + bulk, - out + bulk, len - bulk, gctx->ctr)) { + if (!CRYPTO_gcm128_encrypt_ctr32(&gctx->gcm, &gctx->ks.ks, in, out, len, + gctx->ctr)) { return -1; } } else { - size_t bulk = 0; - if (!CRYPTO_gcm128_encrypt(&gctx->gcm, &gctx->ks.ks, in + bulk, - out + bulk, len - bulk)) { + if (!CRYPTO_gcm128_encrypt(&gctx->gcm, &gctx->ks.ks, in, out, len)) { return -1; } } } else { if (gctx->ctr) { - size_t bulk = 0; -#if defined(AES_GCM_ASM) - if (len >= 16 && AES_GCM_ASM(gctx)) { - size_t res = (16 - gctx->gcm.mres) % 16; - - if (!CRYPTO_gcm128_decrypt(&gctx->gcm, &gctx->ks.ks, in, out, res)) { - return -1; - } - - bulk = AES_gcm_decrypt(in + res, out + res, len - res, &gctx->ks.ks, - gctx->gcm.Yi.c, gctx->gcm.Xi.u); - gctx->gcm.len.u[1] += bulk; - bulk += res; - } -#endif - if (!CRYPTO_gcm128_decrypt_ctr32(&gctx->gcm, &gctx->ks.ks, in + bulk, - out + bulk, len - bulk, gctx->ctr)) { + if (!CRYPTO_gcm128_decrypt_ctr32(&gctx->gcm, &gctx->ks.ks, in, out, len, + gctx->ctr)) { return -1; } } else { - size_t bulk = 0; - if (!CRYPTO_gcm128_decrypt(&gctx->gcm, &gctx->ks.ks, in + bulk, - out + bulk, len - bulk)) { + if (!CRYPTO_gcm128_decrypt(&gctx->gcm, &gctx->ks.ks, in, out, len)) { return -1; } } @@ -904,7 +860,7 @@ static int aesni_gcm_init_key(EVP_CIPHER_CTX *ctx, const uint8_t *key, if (gctx->key_set) { CRYPTO_gcm128_setiv(&gctx->gcm, &gctx->ks.ks, iv, gctx->ivlen); } else { - memcpy(gctx->iv, iv, gctx->ivlen); + OPENSSL_memcpy(gctx->iv, iv, gctx->ivlen); } gctx->iv_set = 1; gctx->iv_gen = 0; @@ -1117,7 +1073,7 @@ static int aead_aes_gcm_seal(const EVP_AEAD_CTX *ctx, uint8_t *out, const AES_KEY *key = &gcm_ctx->ks.ks; - memcpy(&gcm, &gcm_ctx->gcm, sizeof(gcm)); + OPENSSL_memcpy(&gcm, &gcm_ctx->gcm, sizeof(gcm)); CRYPTO_gcm128_setiv(&gcm, key, nonce, nonce_len); if (ad_len > 0 && !CRYPTO_gcm128_aad(&gcm, ad, ad_len)) { @@ -1164,7 +1120,7 @@ static int aead_aes_gcm_open(const EVP_AEAD_CTX *ctx, uint8_t *out, const AES_KEY *key = &gcm_ctx->ks.ks; - memcpy(&gcm, &gcm_ctx->gcm, sizeof(gcm)); + OPENSSL_memcpy(&gcm, &gcm_ctx->gcm, sizeof(gcm)); CRYPTO_gcm128_setiv(&gcm, key, nonce, nonce_len); if (!CRYPTO_gcm128_aad(&gcm, ad, ad_len)) { @@ -1202,7 +1158,6 @@ static const EVP_AEAD aead_aes_128_gcm = { aead_aes_gcm_cleanup, aead_aes_gcm_seal, aead_aes_gcm_open, - NULL, /* get_rc4_state */ NULL, /* get_iv */ }; @@ -1216,7 +1171,6 @@ static const EVP_AEAD aead_aes_256_gcm = { aead_aes_gcm_cleanup, aead_aes_gcm_seal, aead_aes_gcm_open, - NULL, /* get_rc4_state */ NULL, /* get_iv */ }; @@ -1225,268 +1179,6 @@ const EVP_AEAD *EVP_aead_aes_128_gcm(void) { return &aead_aes_128_gcm; } const EVP_AEAD *EVP_aead_aes_256_gcm(void) { return &aead_aes_256_gcm; } -/* AES Key Wrap is specified in - * http://csrc.nist.gov/groups/ST/toolkit/documents/kms/key-wrap.pdf - * or https://tools.ietf.org/html/rfc3394 */ - -struct aead_aes_key_wrap_ctx { - uint8_t key[32]; - unsigned key_bits; -}; - -static int aead_aes_key_wrap_init(EVP_AEAD_CTX *ctx, const uint8_t *key, - size_t key_len, size_t tag_len) { - struct aead_aes_key_wrap_ctx *kw_ctx; - const size_t key_bits = key_len * 8; - - if (key_bits != 128 && key_bits != 256) { - OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_KEY_LENGTH); - return 0; /* EVP_AEAD_CTX_init should catch this. */ - } - - if (tag_len == EVP_AEAD_DEFAULT_TAG_LENGTH) { - tag_len = 8; - } - - if (tag_len != 8) { - OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_TAG_SIZE); - return 0; - } - - kw_ctx = OPENSSL_malloc(sizeof(struct aead_aes_key_wrap_ctx)); - if (kw_ctx == NULL) { - OPENSSL_PUT_ERROR(CIPHER, ERR_R_MALLOC_FAILURE); - return 0; - } - - memcpy(kw_ctx->key, key, key_len); - kw_ctx->key_bits = key_bits; - - ctx->aead_state = kw_ctx; - return 1; -} - -static void aead_aes_key_wrap_cleanup(EVP_AEAD_CTX *ctx) { - struct aead_aes_key_wrap_ctx *kw_ctx = ctx->aead_state; - OPENSSL_cleanse(kw_ctx, sizeof(struct aead_aes_key_wrap_ctx)); - OPENSSL_free(kw_ctx); -} - -/* kDefaultAESKeyWrapNonce is the default nonce value given in 2.2.3.1. */ -static const uint8_t kDefaultAESKeyWrapNonce[8] = {0xa6, 0xa6, 0xa6, 0xa6, - 0xa6, 0xa6, 0xa6, 0xa6}; - - -static int aead_aes_key_wrap_seal(const EVP_AEAD_CTX *ctx, uint8_t *out, - size_t *out_len, size_t max_out_len, - const uint8_t *nonce, size_t nonce_len, - const uint8_t *in, size_t in_len, - const uint8_t *ad, size_t ad_len) { - const struct aead_aes_key_wrap_ctx *kw_ctx = ctx->aead_state; - union { - double align; - AES_KEY ks; - } ks; - /* Variables in this function match up with the variables in the second half - * of section 2.2.1. */ - unsigned i, j, n; - uint8_t A[AES_BLOCK_SIZE]; - - if (ad_len != 0) { - OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_AD_SIZE); - return 0; - } - - if (nonce_len == 0) { - nonce = kDefaultAESKeyWrapNonce; - nonce_len = sizeof(kDefaultAESKeyWrapNonce); - } - - if (nonce_len != 8) { - OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_NONCE_SIZE); - return 0; - } - - if (in_len % 8 != 0) { - OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_INPUT_SIZE); - return 0; - } - - /* The code below only handles a 32-bit |t| thus 6*|n| must be less than - * 2^32, where |n| is |in_len| / 8. So in_len < 4/3 * 2^32 and we - * conservatively cap it to 2^32-16 to stop 32-bit platforms complaining that - * a comparison is always true. */ - if (in_len > 0xfffffff0) { - OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE); - return 0; - } - - n = in_len / 8; - - if (n < 2) { - OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_INPUT_SIZE); - return 0; - } - - if (in_len + 8 < in_len) { - OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE); - return 0; - } - - if (max_out_len < in_len + 8) { - OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL); - return 0; - } - - if (AES_set_encrypt_key(kw_ctx->key, kw_ctx->key_bits, &ks.ks) < 0) { - OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_AES_KEY_SETUP_FAILED); - return 0; - } - - memmove(out + 8, in, in_len); - memcpy(A, nonce, 8); - - for (j = 0; j < 6; j++) { - for (i = 1; i <= n; i++) { - uint32_t t; - - memcpy(A + 8, out + 8 * i, 8); - AES_encrypt(A, A, &ks.ks); - t = n * j + i; - A[7] ^= t & 0xff; - A[6] ^= (t >> 8) & 0xff; - A[5] ^= (t >> 16) & 0xff; - A[4] ^= (t >> 24) & 0xff; - memcpy(out + 8 * i, A + 8, 8); - } - } - - memcpy(out, A, 8); - *out_len = in_len + 8; - return 1; -} - -static int aead_aes_key_wrap_open(const EVP_AEAD_CTX *ctx, uint8_t *out, - size_t *out_len, size_t max_out_len, - const uint8_t *nonce, size_t nonce_len, - const uint8_t *in, size_t in_len, - const uint8_t *ad, size_t ad_len) { - const struct aead_aes_key_wrap_ctx *kw_ctx = ctx->aead_state; - union { - double align; - AES_KEY ks; - } ks; - /* Variables in this function match up with the variables in the second half - * of section 2.2.1. */ - unsigned i, j, n; - uint8_t A[AES_BLOCK_SIZE]; - - if (ad_len != 0) { - OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_AD_SIZE); - return 0; - } - - if (nonce_len == 0) { - nonce = kDefaultAESKeyWrapNonce; - nonce_len = sizeof(kDefaultAESKeyWrapNonce); - } - - if (nonce_len != 8) { - OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_NONCE_SIZE); - return 0; - } - - if (in_len % 8 != 0) { - OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_INPUT_SIZE); - return 0; - } - - /* The code below only handles a 32-bit |t| thus 6*|n| must be less than - * 2^32, where |n| is |in_len| / 8. So in_len < 4/3 * 2^32 and we - * conservatively cap it to 2^32-8 to stop 32-bit platforms complaining that - * a comparison is always true. */ - if (in_len > 0xfffffff8) { - OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE); - return 0; - } - - if (in_len < 24) { - OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); - return 0; - } - - n = (in_len / 8) - 1; - - if (max_out_len < in_len - 8) { - OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL); - return 0; - } - - if (AES_set_decrypt_key(kw_ctx->key, kw_ctx->key_bits, &ks.ks) < 0) { - OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_AES_KEY_SETUP_FAILED); - return 0; - } - - memcpy(A, in, 8); - memmove(out, in + 8, in_len - 8); - - for (j = 5; j < 6; j--) { - for (i = n; i > 0; i--) { - uint32_t t; - - t = n * j + i; - A[7] ^= t & 0xff; - A[6] ^= (t >> 8) & 0xff; - A[5] ^= (t >> 16) & 0xff; - A[4] ^= (t >> 24) & 0xff; - memcpy(A + 8, out + 8 * (i - 1), 8); - AES_decrypt(A, A, &ks.ks); - memcpy(out + 8 * (i - 1), A + 8, 8); - } - } - - if (CRYPTO_memcmp(A, nonce, 8) != 0) { - OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); - return 0; - } - - *out_len = in_len - 8; - return 1; -} - -static const EVP_AEAD aead_aes_128_key_wrap = { - 16, /* key len */ - 8, /* nonce len */ - 8, /* overhead */ - 8, /* max tag length */ - aead_aes_key_wrap_init, - NULL, /* init_with_direction */ - aead_aes_key_wrap_cleanup, - aead_aes_key_wrap_seal, - aead_aes_key_wrap_open, - NULL, /* get_rc4_state */ - NULL, /* get_iv */ -}; - -static const EVP_AEAD aead_aes_256_key_wrap = { - 32, /* key len */ - 8, /* nonce len */ - 8, /* overhead */ - 8, /* max tag length */ - aead_aes_key_wrap_init, - NULL, /* init_with_direction */ - aead_aes_key_wrap_cleanup, - aead_aes_key_wrap_seal, - aead_aes_key_wrap_open, - NULL, /* get_rc4_state */ - NULL, /* get_iv */ -}; - -const EVP_AEAD *EVP_aead_aes_128_key_wrap(void) { return &aead_aes_128_key_wrap; } - -const EVP_AEAD *EVP_aead_aes_256_key_wrap(void) { return &aead_aes_256_key_wrap; } - - #define EVP_AEAD_AES_CTR_HMAC_SHA256_TAG_LEN SHA256_DIGEST_LENGTH #define EVP_AEAD_AES_CTR_HMAC_SHA256_NONCE_LEN 12 @@ -1506,8 +1198,8 @@ static void hmac_init(SHA256_CTX *out_inner, SHA256_CTX *out_outer, const uint8_t hmac_key[32]) { static const size_t hmac_key_len = 32; uint8_t block[SHA256_CBLOCK]; - memcpy(block, hmac_key, hmac_key_len); - memset(block + hmac_key_len, 0x36, sizeof(block) - hmac_key_len); + OPENSSL_memcpy(block, hmac_key, hmac_key_len); + OPENSSL_memset(block + hmac_key_len, 0x36, sizeof(block) - hmac_key_len); unsigned i; for (i = 0; i < hmac_key_len; i++) { @@ -1517,7 +1209,7 @@ static void hmac_init(SHA256_CTX *out_inner, SHA256_CTX *out_outer, SHA256_Init(out_inner); SHA256_Update(out_inner, block, sizeof(block)); - memset(block + hmac_key_len, 0x5c, sizeof(block) - hmac_key_len); + OPENSSL_memset(block + hmac_key_len, 0x5c, sizeof(block) - hmac_key_len); for (i = 0; i < hmac_key_len; i++) { block[i] ^= (0x36 ^ 0x5c); } @@ -1592,7 +1284,7 @@ static void hmac_calculate(uint8_t out[SHA256_DIGEST_LENGTH], const uint8_t *nonce, const uint8_t *ciphertext, size_t ciphertext_len) { SHA256_CTX sha256; - memcpy(&sha256, inner_init_state, sizeof(sha256)); + OPENSSL_memcpy(&sha256, inner_init_state, sizeof(sha256)); hmac_update_uint64(&sha256, ad_len); hmac_update_uint64(&sha256, ciphertext_len); SHA256_Update(&sha256, nonce, EVP_AEAD_AES_CTR_HMAC_SHA256_NONCE_LEN); @@ -1605,7 +1297,7 @@ static void hmac_calculate(uint8_t out[SHA256_DIGEST_LENGTH], SHA256_CBLOCK)) % SHA256_CBLOCK; uint8_t padding[SHA256_CBLOCK]; - memset(padding, 0, num_padding); + OPENSSL_memset(padding, 0, num_padding); SHA256_Update(&sha256, padding, num_padding); SHA256_Update(&sha256, ciphertext, ciphertext_len); @@ -1613,7 +1305,7 @@ static void hmac_calculate(uint8_t out[SHA256_DIGEST_LENGTH], uint8_t inner_digest[SHA256_DIGEST_LENGTH]; SHA256_Final(inner_digest, &sha256); - memcpy(&sha256, outer_init_state, sizeof(sha256)); + OPENSSL_memcpy(&sha256, outer_init_state, sizeof(sha256)); SHA256_Update(&sha256, inner_digest, sizeof(inner_digest)); SHA256_Final(out, &sha256); } @@ -1625,11 +1317,11 @@ static void aead_aes_ctr_hmac_sha256_crypt( * bytes is pointless. However, |CRYPTO_ctr128_encrypt| requires it. */ uint8_t partial_block_buffer[AES_BLOCK_SIZE]; unsigned partial_block_offset = 0; - memset(partial_block_buffer, 0, sizeof(partial_block_buffer)); + OPENSSL_memset(partial_block_buffer, 0, sizeof(partial_block_buffer)); uint8_t counter[AES_BLOCK_SIZE]; - memcpy(counter, nonce, EVP_AEAD_AES_CTR_HMAC_SHA256_NONCE_LEN); - memset(counter + EVP_AEAD_AES_CTR_HMAC_SHA256_NONCE_LEN, 0, 4); + OPENSSL_memcpy(counter, nonce, EVP_AEAD_AES_CTR_HMAC_SHA256_NONCE_LEN); + OPENSSL_memset(counter + EVP_AEAD_AES_CTR_HMAC_SHA256_NONCE_LEN, 0, 4); if (aes_ctx->ctr) { CRYPTO_ctr128_encrypt_ctr32(in, out, len, &aes_ctx->ks.ks, counter, @@ -1672,7 +1364,7 @@ static int aead_aes_ctr_hmac_sha256_seal(const EVP_AEAD_CTX *ctx, uint8_t *out, uint8_t hmac_result[SHA256_DIGEST_LENGTH]; hmac_calculate(hmac_result, &aes_ctx->inner_init_state, &aes_ctx->outer_init_state, ad, ad_len, nonce, out, in_len); - memcpy(out + in_len, hmac_result, aes_ctx->tag_len); + OPENSSL_memcpy(out + in_len, hmac_result, aes_ctx->tag_len); *out_len = in_len + aes_ctx->tag_len; return 1; @@ -1729,7 +1421,6 @@ static const EVP_AEAD aead_aes_128_ctr_hmac_sha256 = { aead_aes_ctr_hmac_sha256_cleanup, aead_aes_ctr_hmac_sha256_seal, aead_aes_ctr_hmac_sha256_open, - NULL /* get_rc4_state */, NULL /* get_iv */, }; @@ -1744,7 +1435,6 @@ static const EVP_AEAD aead_aes_256_ctr_hmac_sha256 = { aead_aes_ctr_hmac_sha256_cleanup, aead_aes_ctr_hmac_sha256_seal, aead_aes_ctr_hmac_sha256_open, - NULL /* get_rc4_state */, NULL /* get_iv */, }; @@ -1756,6 +1446,320 @@ const EVP_AEAD *EVP_aead_aes_256_ctr_hmac_sha256(void) { return &aead_aes_256_ctr_hmac_sha256; } +#if !defined(OPENSSL_SMALL) + +#define EVP_AEAD_AES_GCM_SIV_NONCE_LEN 12 +#define EVP_AEAD_AES_GCM_SIV_TAG_LEN 16 + +struct aead_aes_gcm_siv_ctx { + union { + double align; + AES_KEY ks; + } ks; + block128_f kgk_block; + unsigned is_256:1; +}; + +static int aead_aes_gcm_siv_init(EVP_AEAD_CTX *ctx, const uint8_t *key, + size_t key_len, size_t tag_len) { + const size_t key_bits = key_len * 8; + + if (key_bits != 128 && key_bits != 256) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_KEY_LENGTH); + return 0; /* EVP_AEAD_CTX_init should catch this. */ + } + + if (tag_len == EVP_AEAD_DEFAULT_TAG_LENGTH) { + tag_len = EVP_AEAD_AES_GCM_SIV_TAG_LEN; + } + + if (tag_len != EVP_AEAD_AES_GCM_SIV_TAG_LEN) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TAG_TOO_LARGE); + return 0; + } + + struct aead_aes_gcm_siv_ctx *gcm_siv_ctx = + OPENSSL_malloc(sizeof(struct aead_aes_gcm_siv_ctx)); + if (gcm_siv_ctx == NULL) { + return 0; + } + OPENSSL_memset(gcm_siv_ctx, 0, sizeof(struct aead_aes_gcm_siv_ctx)); + + if (aesni_capable()) { + aesni_set_encrypt_key(key, key_len * 8, &gcm_siv_ctx->ks.ks); + gcm_siv_ctx->kgk_block = (block128_f)aesni_encrypt; + } else if (hwaes_capable()) { + aes_hw_set_encrypt_key(key, key_len * 8, &gcm_siv_ctx->ks.ks); + gcm_siv_ctx->kgk_block = (block128_f)aes_hw_encrypt; + } else if (vpaes_capable()) { + vpaes_set_encrypt_key(key, key_len * 8, &gcm_siv_ctx->ks.ks); + gcm_siv_ctx->kgk_block = (block128_f)vpaes_encrypt; + } else { + AES_set_encrypt_key(key, key_len * 8, &gcm_siv_ctx->ks.ks); + gcm_siv_ctx->kgk_block = (block128_f)AES_encrypt; + } + + gcm_siv_ctx->is_256 = (key_len == 32); + ctx->aead_state = gcm_siv_ctx; + + return 1; +} + +static void aead_aes_gcm_siv_cleanup(EVP_AEAD_CTX *ctx) { + struct aead_aes_gcm_siv_ctx *gcm_siv_ctx = ctx->aead_state; + OPENSSL_cleanse(gcm_siv_ctx, sizeof(struct aead_aes_gcm_siv_ctx)); + OPENSSL_free(gcm_siv_ctx); +} + +/* gcm_siv_crypt encrypts (or decrypts—it's the same thing) |in_len| bytes from + * |in| to |out|, using the block function |enc_block| with |key| in counter + * mode, starting at |initial_counter|. This differs from the traditional + * counter mode code in that the counter is handled little-endian, only the + * first four bytes are used and the GCM-SIV tweak to the final byte is + * applied. The |in| and |out| pointers may be equal but otherwise must not + * alias. */ +static void gcm_siv_crypt(uint8_t *out, const uint8_t *in, size_t in_len, + const uint8_t initial_counter[AES_BLOCK_SIZE], + block128_f enc_block, const AES_KEY *key) { + union { + uint32_t w[4]; + uint8_t c[16]; + } counter; + + OPENSSL_memcpy(counter.c, initial_counter, AES_BLOCK_SIZE); + counter.c[15] |= 0x80; + + for (size_t done = 0; done < in_len;) { + uint8_t keystream[AES_BLOCK_SIZE]; + enc_block(counter.c, keystream, key); + counter.w[0]++; + + size_t todo = AES_BLOCK_SIZE; + if (in_len - done < todo) { + todo = in_len - done; + } + + for (size_t i = 0; i < todo; i++) { + out[done + i] = keystream[i] ^ in[done + i]; + } + + done += todo; + } +} + +/* gcm_siv_polyval evaluates POLYVAL at |auth_key| on the given plaintext and + * AD. The result is written to |out_tag|. */ +static void gcm_siv_polyval( + uint8_t out_tag[16], const uint8_t *in, size_t in_len, const uint8_t *ad, + size_t ad_len, const uint8_t auth_key[16], + const uint8_t nonce[EVP_AEAD_AES_GCM_SIV_NONCE_LEN]) { + struct polyval_ctx polyval_ctx; + CRYPTO_POLYVAL_init(&polyval_ctx, auth_key); + + CRYPTO_POLYVAL_update_blocks(&polyval_ctx, ad, ad_len & ~15); + + uint8_t scratch[16]; + if (ad_len & 15) { + OPENSSL_memset(scratch, 0, sizeof(scratch)); + OPENSSL_memcpy(scratch, &ad[ad_len & ~15], ad_len & 15); + CRYPTO_POLYVAL_update_blocks(&polyval_ctx, scratch, sizeof(scratch)); + } + + CRYPTO_POLYVAL_update_blocks(&polyval_ctx, in, in_len & ~15); + if (in_len & 15) { + OPENSSL_memset(scratch, 0, sizeof(scratch)); + OPENSSL_memcpy(scratch, &in[in_len & ~15], in_len & 15); + CRYPTO_POLYVAL_update_blocks(&polyval_ctx, scratch, sizeof(scratch)); + } + + union { + uint8_t c[16]; + struct { + uint64_t ad; + uint64_t in; + } bitlens; + } length_block; + + length_block.bitlens.ad = ad_len * 8; + length_block.bitlens.in = in_len * 8; + CRYPTO_POLYVAL_update_blocks(&polyval_ctx, length_block.c, + sizeof(length_block)); + + CRYPTO_POLYVAL_finish(&polyval_ctx, out_tag); + for (size_t i = 0; i < EVP_AEAD_AES_GCM_SIV_NONCE_LEN; i++) { + out_tag[i] ^= nonce[i]; + } + out_tag[15] &= 0x7f; +} + +/* gcm_siv_record_keys contains the keys used for a specific GCM-SIV record. */ +struct gcm_siv_record_keys { + uint8_t auth_key[16]; + union { + double align; + AES_KEY ks; + } enc_key; + block128_f enc_block; +}; + +/* gcm_siv_keys calculates the keys for a specific GCM-SIV record with the + * given nonce and writes them to |*out_keys|. */ +static void gcm_siv_keys( + const struct aead_aes_gcm_siv_ctx *gcm_siv_ctx, + struct gcm_siv_record_keys *out_keys, + const uint8_t nonce[EVP_AEAD_AES_GCM_SIV_NONCE_LEN]) { + const AES_KEY *const key = &gcm_siv_ctx->ks.ks; + uint8_t key_material[(128 /* POLYVAL key */ + 256 /* max AES key */) / 8]; + const size_t blocks_needed = gcm_siv_ctx->is_256 ? 6 : 4; + + uint8_t counter[AES_BLOCK_SIZE]; + OPENSSL_memset(counter, 0, AES_BLOCK_SIZE - EVP_AEAD_AES_GCM_SIV_NONCE_LEN); + OPENSSL_memcpy(counter + AES_BLOCK_SIZE - EVP_AEAD_AES_GCM_SIV_NONCE_LEN, + nonce, EVP_AEAD_AES_GCM_SIV_NONCE_LEN); + for (size_t i = 0; i < blocks_needed; i++) { + counter[0] = i; + + uint8_t ciphertext[AES_BLOCK_SIZE]; + gcm_siv_ctx->kgk_block(counter, ciphertext, key); + OPENSSL_memcpy(&key_material[i * 8], ciphertext, 8); + } + + OPENSSL_memcpy(out_keys->auth_key, key_material, 16); + aes_ctr_set_key(&out_keys->enc_key.ks, NULL, &out_keys->enc_block, + key_material + 16, gcm_siv_ctx->is_256 ? 32 : 16); +} + +static int aead_aes_gcm_siv_seal(const EVP_AEAD_CTX *ctx, uint8_t *out, + size_t *out_len, size_t max_out_len, + const uint8_t *nonce, size_t nonce_len, + const uint8_t *in, size_t in_len, + const uint8_t *ad, size_t ad_len) { + const struct aead_aes_gcm_siv_ctx *gcm_siv_ctx = ctx->aead_state; + const uint64_t in_len_64 = in_len; + const uint64_t ad_len_64 = ad_len; + + if (in_len + EVP_AEAD_AES_GCM_SIV_TAG_LEN < in_len || + in_len_64 > (UINT64_C(1) << 36) || + ad_len_64 >= (UINT64_C(1) << 61)) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE); + return 0; + } + + if (max_out_len < in_len + EVP_AEAD_AES_GCM_SIV_TAG_LEN) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL); + return 0; + } + + if (nonce_len != EVP_AEAD_AES_GCM_SIV_NONCE_LEN) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_NONCE_SIZE); + return 0; + } + + struct gcm_siv_record_keys keys; + gcm_siv_keys(gcm_siv_ctx, &keys, nonce); + + uint8_t tag[16]; + gcm_siv_polyval(tag, in, in_len, ad, ad_len, keys.auth_key, nonce); + keys.enc_block(tag, tag, &keys.enc_key.ks); + + gcm_siv_crypt(out, in, in_len, tag, keys.enc_block, &keys.enc_key.ks); + + OPENSSL_memcpy(&out[in_len], tag, EVP_AEAD_AES_GCM_SIV_TAG_LEN); + *out_len = in_len + EVP_AEAD_AES_GCM_SIV_TAG_LEN; + + return 1; +} + +static int aead_aes_gcm_siv_open(const EVP_AEAD_CTX *ctx, uint8_t *out, + size_t *out_len, size_t max_out_len, + const uint8_t *nonce, size_t nonce_len, + const uint8_t *in, size_t in_len, + const uint8_t *ad, size_t ad_len) { + const uint64_t ad_len_64 = ad_len; + if (ad_len_64 >= (UINT64_C(1) << 61)) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE); + return 0; + } + + const uint64_t in_len_64 = in_len; + if (in_len < EVP_AEAD_AES_GCM_SIV_TAG_LEN || + in_len_64 > (UINT64_C(1) << 36) + AES_BLOCK_SIZE) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); + return 0; + } + + if (nonce_len != EVP_AEAD_AES_GCM_SIV_NONCE_LEN) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_NONCE_SIZE); + return 0; + } + + const struct aead_aes_gcm_siv_ctx *gcm_siv_ctx = ctx->aead_state; + const size_t plaintext_len = in_len - EVP_AEAD_AES_GCM_SIV_TAG_LEN; + + if (max_out_len < plaintext_len) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL); + return 0; + } + + struct gcm_siv_record_keys keys; + gcm_siv_keys(gcm_siv_ctx, &keys, nonce); + + gcm_siv_crypt(out, in, plaintext_len, &in[plaintext_len], keys.enc_block, + &keys.enc_key.ks); + + uint8_t expected_tag[EVP_AEAD_AES_GCM_SIV_TAG_LEN]; + gcm_siv_polyval(expected_tag, out, plaintext_len, ad, ad_len, keys.auth_key, + nonce); + keys.enc_block(expected_tag, expected_tag, &keys.enc_key.ks); + + if (CRYPTO_memcmp(expected_tag, &in[plaintext_len], sizeof(expected_tag)) != + 0) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); + return 0; + } + + *out_len = plaintext_len; + return 1; +} + +static const EVP_AEAD aead_aes_128_gcm_siv = { + 16, /* key length */ + EVP_AEAD_AES_GCM_SIV_NONCE_LEN, /* nonce length */ + EVP_AEAD_AES_GCM_SIV_TAG_LEN, /* overhead */ + EVP_AEAD_AES_GCM_SIV_TAG_LEN, /* max tag length */ + + aead_aes_gcm_siv_init, + NULL /* init_with_direction */, + aead_aes_gcm_siv_cleanup, + aead_aes_gcm_siv_seal, + aead_aes_gcm_siv_open, + NULL /* get_iv */, +}; + +static const EVP_AEAD aead_aes_256_gcm_siv = { + 32, /* key length */ + EVP_AEAD_AES_GCM_SIV_NONCE_LEN, /* nonce length */ + EVP_AEAD_AES_GCM_SIV_TAG_LEN, /* overhead */ + EVP_AEAD_AES_GCM_SIV_TAG_LEN, /* max tag length */ + + aead_aes_gcm_siv_init, + NULL /* init_with_direction */, + aead_aes_gcm_siv_cleanup, + aead_aes_gcm_siv_seal, + aead_aes_gcm_siv_open, + NULL /* get_iv */, +}; + +const EVP_AEAD *EVP_aead_aes_128_gcm_siv(void) { + return &aead_aes_128_gcm_siv; +} + +const EVP_AEAD *EVP_aead_aes_256_gcm_siv(void) { + return &aead_aes_256_gcm_siv; +} + +#endif /* !OPENSSL_SMALL */ + int EVP_has_aes_hardware(void) { #if defined(OPENSSL_X86) || defined(OPENSSL_X86_64) return aesni_capable() && crypto_gcm_clmul_enabled(); diff --git a/Sources/BoringSSL/crypto/cipher/e_chacha20poly1305.c b/Sources/BoringSSL/crypto/cipher/e_chacha20poly1305.c index de8c9b4be..c6e81ab87 100644 --- a/Sources/BoringSSL/crypto/cipher/e_chacha20poly1305.c +++ b/Sources/BoringSSL/crypto/cipher/e_chacha20poly1305.c @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -33,6 +34,51 @@ struct aead_chacha20_poly1305_ctx { unsigned char tag_len; }; +#if defined(OPENSSL_X86_64) && !defined(OPENSSL_NO_ASM) && \ + !defined(OPENSSL_WINDOWS) +static int asm_capable(void) { + const int sse41_capable = (OPENSSL_ia32cap_P[1] & (1 << 19)) != 0; + return sse41_capable; +} + +// chacha20_poly1305_open is defined in chacha20_poly1305_x86_64.pl. It +// decrypts |plaintext_len| bytes from |ciphertext| and writes them to +// |out_plaintext|. On entry, |aead_data| must contain the final 48 bytes of +// the initial ChaCha20 block, i.e. the key, followed by four zeros, followed +// by the nonce. On exit, it will contain the calculated tag value, which the +// caller must check. +extern void chacha20_poly1305_open(uint8_t *out_plaintext, + const uint8_t *ciphertext, + size_t plaintext_len, const uint8_t *ad, + size_t ad_len, uint8_t *aead_data); + +// chacha20_poly1305_open is defined in chacha20_poly1305_x86_64.pl. It +// encrypts |plaintext_len| bytes from |plaintext| and writes them to +// |out_ciphertext|. On entry, |aead_data| must contain the final 48 bytes of +// the initial ChaCha20 block, i.e. the key, followed by four zeros, followed +// by the nonce. On exit, it will contain the calculated tag value, which the +// caller must append to the ciphertext. +extern void chacha20_poly1305_seal(uint8_t *out_ciphertext, + const uint8_t *plaintext, + size_t plaintext_len, const uint8_t *ad, + size_t ad_len, uint8_t *aead_data); +#else +static int asm_capable(void) { + return 0; +} + + +static void chacha20_poly1305_open(uint8_t *out_plaintext, + const uint8_t *ciphertext, + size_t plaintext_len, const uint8_t *ad, + size_t ad_len, uint8_t *aead_data) {} + +static void chacha20_poly1305_seal(uint8_t *out_ciphertext, + const uint8_t *plaintext, + size_t plaintext_len, const uint8_t *ad, + size_t ad_len, uint8_t *aead_data) {} +#endif + static int aead_chacha20_poly1305_init(EVP_AEAD_CTX *ctx, const uint8_t *key, size_t key_len, size_t tag_len) { struct aead_chacha20_poly1305_ctx *c20_ctx; @@ -55,7 +101,7 @@ static int aead_chacha20_poly1305_init(EVP_AEAD_CTX *ctx, const uint8_t *key, return 0; } - memcpy(c20_ctx->key, key, key_len); + OPENSSL_memcpy(c20_ctx->key, key, key_len); c20_ctx->tag_len = tag_len; ctx->aead_state = c20_ctx; @@ -70,9 +116,8 @@ static void aead_chacha20_poly1305_cleanup(EVP_AEAD_CTX *ctx) { static void poly1305_update_length(poly1305_state *poly1305, size_t data_len) { uint8_t length_bytes[8]; - unsigned i; - for (i = 0; i < sizeof(length_bytes); i++) { + for (unsigned i = 0; i < sizeof(length_bytes); i++) { length_bytes[i] = data_len; data_len >>= 8; } @@ -80,44 +125,56 @@ static void poly1305_update_length(poly1305_state *poly1305, size_t data_len) { CRYPTO_poly1305_update(poly1305, length_bytes, sizeof(length_bytes)); } -typedef void (*aead_poly1305_update)(poly1305_state *ctx, const uint8_t *ad, - size_t ad_len, const uint8_t *ciphertext, - size_t ciphertext_len); - -/* aead_poly1305 fills |tag| with the authentication tag for the given - * inputs, using |update| to control the order and format that the inputs are - * signed/authenticated. */ -static void aead_poly1305(aead_poly1305_update update, - uint8_t tag[POLY1305_TAG_LEN], - const struct aead_chacha20_poly1305_ctx *c20_ctx, - const uint8_t nonce[12], const uint8_t *ad, - size_t ad_len, const uint8_t *ciphertext, - size_t ciphertext_len) { +static void poly1305_update_padded_16(poly1305_state *poly1305, + const uint8_t *data, size_t data_len) { + static const uint8_t padding[16] = { 0 }; /* Padding is all zeros. */ + + CRYPTO_poly1305_update(poly1305, data, data_len); + if (data_len % 16 != 0) { + CRYPTO_poly1305_update(poly1305, padding, + sizeof(padding) - (data_len % 16)); + } +} + +/* calc_tag fills |tag| with the authentication tag for the given inputs. */ +static void calc_tag(uint8_t tag[POLY1305_TAG_LEN], + const struct aead_chacha20_poly1305_ctx *c20_ctx, + const uint8_t nonce[12], const uint8_t *ad, size_t ad_len, + const uint8_t *ciphertext, size_t ciphertext_len) { alignas(16) uint8_t poly1305_key[32]; - memset(poly1305_key, 0, sizeof(poly1305_key)); + OPENSSL_memset(poly1305_key, 0, sizeof(poly1305_key)); CRYPTO_chacha_20(poly1305_key, poly1305_key, sizeof(poly1305_key), c20_ctx->key, nonce, 0); + poly1305_state ctx; CRYPTO_poly1305_init(&ctx, poly1305_key); - update(&ctx, ad, ad_len, ciphertext, ciphertext_len); + poly1305_update_padded_16(&ctx, ad, ad_len); + poly1305_update_padded_16(&ctx, ciphertext, ciphertext_len); + poly1305_update_length(&ctx, ad_len); + poly1305_update_length(&ctx, ciphertext_len); CRYPTO_poly1305_finish(&ctx, tag); } -static int seal_impl(aead_poly1305_update poly1305_update, - const EVP_AEAD_CTX *ctx, uint8_t *out, size_t *out_len, - size_t max_out_len, const uint8_t nonce[12], - const uint8_t *in, size_t in_len, const uint8_t *ad, - size_t ad_len) { +static int aead_chacha20_poly1305_seal(const EVP_AEAD_CTX *ctx, uint8_t *out, + size_t *out_len, size_t max_out_len, + const uint8_t *nonce, size_t nonce_len, + const uint8_t *in, size_t in_len, + const uint8_t *ad, size_t ad_len) { const struct aead_chacha20_poly1305_ctx *c20_ctx = ctx->aead_state; const uint64_t in_len_64 = in_len; + if (nonce_len != 12) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_NONCE_SIZE); + return 0; + } + /* |CRYPTO_chacha_20| uses a 32-bit block counter. Therefore we disallow * individual operations that work on more than 256GB at a time. * |in_len_64| is needed because, on 32-bit platforms, size_t is only * 32-bits and this produces a warning because it's always false. * Casting to uint64_t inside the conditional is not sufficient to stop * the warning. */ - if (in_len_64 >= (1ull << 32) * 64 - 64) { + if (in_len_64 >= (UINT64_C(1) << 32) * 64 - 64) { OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE); return 0; } @@ -132,25 +189,37 @@ static int seal_impl(aead_poly1305_update poly1305_update, return 0; } - CRYPTO_chacha_20(out, in, in_len, c20_ctx->key, nonce, 1); + alignas(16) uint8_t tag[48]; - alignas(16) uint8_t tag[POLY1305_TAG_LEN]; - aead_poly1305(poly1305_update, tag, c20_ctx, nonce, ad, ad_len, out, in_len); + if (asm_capable()) { + OPENSSL_memcpy(tag, c20_ctx->key, 32); + OPENSSL_memset(tag + 32, 0, 4); + OPENSSL_memcpy(tag + 32 + 4, nonce, 12); + chacha20_poly1305_seal(out, in, in_len, ad, ad_len, tag); + } else { + CRYPTO_chacha_20(out, in, in_len, c20_ctx->key, nonce, 1); + calc_tag(tag, c20_ctx, nonce, ad, ad_len, out, in_len); + } - memcpy(out + in_len, tag, c20_ctx->tag_len); + OPENSSL_memcpy(out + in_len, tag, c20_ctx->tag_len); *out_len = in_len + c20_ctx->tag_len; return 1; } -static int open_impl(aead_poly1305_update poly1305_update, - const EVP_AEAD_CTX *ctx, uint8_t *out, size_t *out_len, - size_t max_out_len, const uint8_t nonce[12], - const uint8_t *in, size_t in_len, const uint8_t *ad, - size_t ad_len) { +static int aead_chacha20_poly1305_open(const EVP_AEAD_CTX *ctx, uint8_t *out, + size_t *out_len, size_t max_out_len, + const uint8_t *nonce, size_t nonce_len, + const uint8_t *in, size_t in_len, + const uint8_t *ad, size_t ad_len) { const struct aead_chacha20_poly1305_ctx *c20_ctx = ctx->aead_state; size_t plaintext_len; const uint64_t in_len_64 = in_len; + if (nonce_len != 12) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_NONCE_SIZE); + return 0; + } + if (in_len < c20_ctx->tag_len) { OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); return 0; @@ -162,70 +231,33 @@ static int open_impl(aead_poly1305_update poly1305_update, * 32-bits and this produces a warning because it's always false. * Casting to uint64_t inside the conditional is not sufficient to stop * the warning. */ - if (in_len_64 >= (1ull << 32) * 64 - 64) { + if (in_len_64 >= (UINT64_C(1) << 32) * 64 - 64) { OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE); return 0; } plaintext_len = in_len - c20_ctx->tag_len; - alignas(16) uint8_t tag[POLY1305_TAG_LEN]; - aead_poly1305(poly1305_update, tag, c20_ctx, nonce, ad, ad_len, in, - plaintext_len); + alignas(16) uint8_t tag[48]; + + if (asm_capable()) { + OPENSSL_memcpy(tag, c20_ctx->key, 32); + OPENSSL_memset(tag + 32, 0, 4); + OPENSSL_memcpy(tag + 32 + 4, nonce, 12); + chacha20_poly1305_open(out, in, plaintext_len, ad, ad_len, tag); + } else { + calc_tag(tag, c20_ctx, nonce, ad, ad_len, in, plaintext_len); + CRYPTO_chacha_20(out, in, plaintext_len, c20_ctx->key, nonce, 1); + } + if (CRYPTO_memcmp(tag, in + plaintext_len, c20_ctx->tag_len) != 0) { OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); return 0; } - CRYPTO_chacha_20(out, in, plaintext_len, c20_ctx->key, nonce, 1); *out_len = plaintext_len; return 1; } -static void poly1305_update_padded_16(poly1305_state *poly1305, - const uint8_t *data, size_t data_len) { - static const uint8_t padding[16] = { 0 }; /* Padding is all zeros. */ - - CRYPTO_poly1305_update(poly1305, data, data_len); - if (data_len % 16 != 0) { - CRYPTO_poly1305_update(poly1305, padding, sizeof(padding) - (data_len % 16)); - } -} - -static void poly1305_update(poly1305_state *ctx, const uint8_t *ad, - size_t ad_len, const uint8_t *ciphertext, - size_t ciphertext_len) { - poly1305_update_padded_16(ctx, ad, ad_len); - poly1305_update_padded_16(ctx, ciphertext, ciphertext_len); - poly1305_update_length(ctx, ad_len); - poly1305_update_length(ctx, ciphertext_len); -} - -static int aead_chacha20_poly1305_seal(const EVP_AEAD_CTX *ctx, uint8_t *out, - size_t *out_len, size_t max_out_len, - const uint8_t *nonce, size_t nonce_len, - const uint8_t *in, size_t in_len, - const uint8_t *ad, size_t ad_len) { - if (nonce_len != 12) { - OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_NONCE_SIZE); - return 0; - } - return seal_impl(poly1305_update, ctx, out, out_len, max_out_len, nonce, in, - in_len, ad, ad_len); -} - -static int aead_chacha20_poly1305_open(const EVP_AEAD_CTX *ctx, uint8_t *out, - size_t *out_len, size_t max_out_len, - const uint8_t *nonce, size_t nonce_len, - const uint8_t *in, size_t in_len, - const uint8_t *ad, size_t ad_len) { - if (nonce_len != 12) { - OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_NONCE_SIZE); - return 0; - } - return open_impl(poly1305_update, ctx, out, out_len, max_out_len, nonce, in, - in_len, ad, ad_len); -} - static const EVP_AEAD aead_chacha20_poly1305 = { 32, /* key len */ 12, /* nonce len */ @@ -236,71 +268,9 @@ static const EVP_AEAD aead_chacha20_poly1305 = { aead_chacha20_poly1305_cleanup, aead_chacha20_poly1305_seal, aead_chacha20_poly1305_open, - NULL, /* get_rc4_state */ NULL, /* get_iv */ }; const EVP_AEAD *EVP_aead_chacha20_poly1305(void) { return &aead_chacha20_poly1305; } - -const EVP_AEAD *EVP_aead_chacha20_poly1305_rfc7539(void) { - return EVP_aead_chacha20_poly1305(); -} - -static void poly1305_update_old(poly1305_state *ctx, const uint8_t *ad, - size_t ad_len, const uint8_t *ciphertext, - size_t ciphertext_len) { - CRYPTO_poly1305_update(ctx, ad, ad_len); - poly1305_update_length(ctx, ad_len); - CRYPTO_poly1305_update(ctx, ciphertext, ciphertext_len); - poly1305_update_length(ctx, ciphertext_len); -} - -static int aead_chacha20_poly1305_old_seal( - const EVP_AEAD_CTX *ctx, uint8_t *out, size_t *out_len, size_t max_out_len, - const uint8_t *nonce, size_t nonce_len, const uint8_t *in, size_t in_len, - const uint8_t *ad, size_t ad_len) { - if (nonce_len != 8) { - OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_NONCE_SIZE); - return 0; - } - uint8_t nonce_96[12]; - memset(nonce_96, 0, 4); - memcpy(nonce_96 + 4, nonce, 8); - return seal_impl(poly1305_update_old, ctx, out, out_len, max_out_len, - nonce_96, in, in_len, ad, ad_len); -} - -static int aead_chacha20_poly1305_old_open( - const EVP_AEAD_CTX *ctx, uint8_t *out, size_t *out_len, size_t max_out_len, - const uint8_t *nonce, size_t nonce_len, const uint8_t *in, size_t in_len, - const uint8_t *ad, size_t ad_len) { - if (nonce_len != 8) { - OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_NONCE_SIZE); - return 0; - } - uint8_t nonce_96[12]; - memset(nonce_96, 0, 4); - memcpy(nonce_96 + 4, nonce, 8); - return open_impl(poly1305_update_old, ctx, out, out_len, max_out_len, - nonce_96, in, in_len, ad, ad_len); -} - -static const EVP_AEAD aead_chacha20_poly1305_old = { - 32, /* key len */ - 8, /* nonce len */ - POLY1305_TAG_LEN, /* overhead */ - POLY1305_TAG_LEN, /* max tag length */ - aead_chacha20_poly1305_init, - NULL, /* init_with_direction */ - aead_chacha20_poly1305_cleanup, - aead_chacha20_poly1305_old_seal, - aead_chacha20_poly1305_old_open, - NULL, /* get_rc4_state */ - NULL, /* get_iv */ -}; - -const EVP_AEAD *EVP_aead_chacha20_poly1305_old(void) { - return &aead_chacha20_poly1305_old; -} diff --git a/Sources/BoringSSL/crypto/cipher/e_des.c b/Sources/BoringSSL/crypto/cipher/e_des.c index b1d312c3d..6834a42c3 100644 --- a/Sources/BoringSSL/crypto/cipher/e_des.c +++ b/Sources/BoringSSL/crypto/cipher/e_des.c @@ -56,7 +56,7 @@ #include #include -#include +#include #include "internal.h" @@ -104,8 +104,7 @@ static int des_ecb_cipher(EVP_CIPHER_CTX *ctx, uint8_t *out, const uint8_t *in, in_len -= ctx->cipher->block_size; EVP_DES_KEY *dat = (EVP_DES_KEY *) ctx->cipher_data; - size_t i; - for (i = 0; i <= in_len; i += ctx->cipher->block_size) { + for (size_t i = 0; i <= in_len; i += ctx->cipher->block_size) { DES_ecb_encrypt((DES_cblock *) (in + i), (DES_cblock *) (out + i), &dat->ks.ks, ctx->encrypt); } @@ -189,8 +188,7 @@ static int des_ede_ecb_cipher(EVP_CIPHER_CTX *ctx, uint8_t *out, in_len -= ctx->cipher->block_size; DES_EDE_KEY *dat = (DES_EDE_KEY *) ctx->cipher_data; - size_t i; - for (i = 0; i <= in_len; i += ctx->cipher->block_size) { + for (size_t i = 0; i <= in_len; i += ctx->cipher->block_size) { DES_ecb3_encrypt((DES_cblock *) (in + i), (DES_cblock *) (out + i), &dat->ks.ks[0], &dat->ks.ks[1], &dat->ks.ks[2], ctx->encrypt); diff --git a/Sources/BoringSSL/crypto/cipher/e_null.c b/Sources/BoringSSL/crypto/cipher/e_null.c index cfe1d1b29..9f8930850 100644 --- a/Sources/BoringSSL/crypto/cipher/e_null.c +++ b/Sources/BoringSSL/crypto/cipher/e_null.c @@ -58,8 +58,9 @@ #include -#include +#include +#include "../internal.h" #include "internal.h" @@ -71,7 +72,7 @@ static int null_init_key(EVP_CIPHER_CTX *ctx, const uint8_t *key, static int null_cipher(EVP_CIPHER_CTX *ctx, uint8_t *out, const uint8_t *in, size_t in_len) { if (in != out) { - memcpy(out, in, in_len); + OPENSSL_memcpy(out, in, in_len); } return 1; } diff --git a/Sources/BoringSSL/crypto/cipher/e_rc2.c b/Sources/BoringSSL/crypto/cipher/e_rc2.c index 8ca7bba66..e1b4301e6 100644 --- a/Sources/BoringSSL/crypto/cipher/e_rc2.c +++ b/Sources/BoringSSL/crypto/cipher/e_rc2.c @@ -55,68 +55,73 @@ * [including the GNU Public Licence.] */ #include -#include +#include #include "internal.h" -#define c2l(c, l) \ - (l = ((uint32_t)(*((c)++))), l |= ((uint32_t)(*((c)++))) << 8L, \ - l |= ((uint32_t)(*((c)++))) << 16L, \ - l |= ((uint32_t)(*((c)++))) << 24L) - -#define c2ln(c, l1, l2, n) \ - { \ - c += n; \ - l1 = l2 = 0; \ - switch (n) { \ - case 8: \ - l2 = ((uint32_t)(*(--(c)))) << 24L; \ - case 7: \ - l2 |= ((uint32_t)(*(--(c)))) << 16L; \ - case 6: \ - l2 |= ((uint32_t)(*(--(c)))) << 8L; \ - case 5: \ - l2 |= ((uint32_t)(*(--(c)))); \ - case 4: \ - l1 = ((uint32_t)(*(--(c)))) << 24L; \ - case 3: \ - l1 |= ((uint32_t)(*(--(c)))) << 16L; \ - case 2: \ - l1 |= ((uint32_t)(*(--(c)))) << 8L; \ - case 1: \ - l1 |= ((uint32_t)(*(--(c)))); \ - } \ - } - -#define l2c(l, c) \ - (*((c)++) = (uint8_t)(((l)) & 0xff), \ - *((c)++) = (uint8_t)(((l) >> 8L) & 0xff), \ - *((c)++) = (uint8_t)(((l) >> 16L) & 0xff), \ - *((c)++) = (uint8_t)(((l) >> 24L) & 0xff)) - -#define l2cn(l1, l2, c, n) \ - { \ - c += n; \ - switch (n) { \ - case 8: \ +#define c2l(c, l) \ + do { \ + (l) = ((uint32_t)(*((c)++))); \ + (l) |= ((uint32_t)(*((c)++))) << 8L; \ + (l) |= ((uint32_t)(*((c)++))) << 16L; \ + (l) |= ((uint32_t)(*((c)++))) << 24L; \ + } while (0) + +#define c2ln(c, l1, l2, n) \ + do { \ + (c) += (n); \ + (l1) = (l2) = 0; \ + switch (n) { \ + case 8: \ + (l2) = ((uint32_t)(*(--(c)))) << 24L; \ + case 7: \ + (l2) |= ((uint32_t)(*(--(c)))) << 16L; \ + case 6: \ + (l2) |= ((uint32_t)(*(--(c)))) << 8L; \ + case 5: \ + (l2) |= ((uint32_t)(*(--(c)))); \ + case 4: \ + (l1) = ((uint32_t)(*(--(c)))) << 24L; \ + case 3: \ + (l1) |= ((uint32_t)(*(--(c)))) << 16L; \ + case 2: \ + (l1) |= ((uint32_t)(*(--(c)))) << 8L; \ + case 1: \ + (l1) |= ((uint32_t)(*(--(c)))); \ + } \ + } while (0) + +#define l2c(l, c) \ + do { \ + *((c)++) = (uint8_t)(((l)) & 0xff); \ + *((c)++) = (uint8_t)(((l) >> 8L) & 0xff); \ + *((c)++) = (uint8_t)(((l) >> 16L) & 0xff); \ + *((c)++) = (uint8_t)(((l) >> 24L) & 0xff); \ + } while (0) + +#define l2cn(l1, l2, c, n) \ + do { \ + (c) += (n); \ + switch (n) { \ + case 8: \ *(--(c)) = (uint8_t)(((l2) >> 24L) & 0xff); \ - case 7: \ + case 7: \ *(--(c)) = (uint8_t)(((l2) >> 16L) & 0xff); \ - case 6: \ + case 6: \ *(--(c)) = (uint8_t)(((l2) >> 8L) & 0xff); \ - case 5: \ + case 5: \ *(--(c)) = (uint8_t)(((l2)) & 0xff); \ - case 4: \ + case 4: \ *(--(c)) = (uint8_t)(((l1) >> 24L) & 0xff); \ - case 3: \ + case 3: \ *(--(c)) = (uint8_t)(((l1) >> 16L) & 0xff); \ - case 2: \ + case 2: \ *(--(c)) = (uint8_t)(((l1) >> 8L) & 0xff); \ - case 1: \ + case 1: \ *(--(c)) = (uint8_t)(((l1)) & 0xff); \ - } \ - } + } \ + } while (0) typedef struct rc2_key_st { uint16_t data[64]; } RC2_KEY; diff --git a/Sources/BoringSSL/crypto/cipher/e_rc4.c b/Sources/BoringSSL/crypto/cipher/e_rc4.c index 3a2c166a3..e7c2ccaff 100644 --- a/Sources/BoringSSL/crypto/cipher/e_rc4.c +++ b/Sources/BoringSSL/crypto/cipher/e_rc4.c @@ -58,7 +58,7 @@ #include #include -#include +#include #include diff --git a/Sources/BoringSSL/crypto/cipher/e_ssl3.c b/Sources/BoringSSL/crypto/cipher/e_ssl3.c index 7dddf242f..f1dad2ba1 100644 --- a/Sources/BoringSSL/crypto/cipher/e_ssl3.c +++ b/Sources/BoringSSL/crypto/cipher/e_ssl3.c @@ -25,6 +25,7 @@ #include #include "internal.h" +#include "../internal.h" typedef struct { @@ -49,7 +50,7 @@ static int ssl3_mac(AEAD_SSL3_CTX *ssl3_ctx, uint8_t *out, unsigned *out_len, uint8_t pad[48]; uint8_t tmp[EVP_MAX_MD_SIZE]; - memset(pad, 0x36, pad_len); + OPENSSL_memset(pad, 0x36, pad_len); if (!EVP_MD_CTX_copy_ex(&md_ctx, &ssl3_ctx->md_ctx) || !EVP_DigestUpdate(&md_ctx, pad, pad_len) || !EVP_DigestUpdate(&md_ctx, ad, ad_len) || @@ -60,7 +61,7 @@ static int ssl3_mac(AEAD_SSL3_CTX *ssl3_ctx, uint8_t *out, unsigned *out_len, return 0; } - memset(pad, 0x5c, pad_len); + OPENSSL_memset(pad, 0x5c, pad_len); if (!EVP_MD_CTX_copy_ex(&md_ctx, &ssl3_ctx->md_ctx) || !EVP_DigestUpdate(&md_ctx, pad, pad_len) || !EVP_DigestUpdate(&md_ctx, tmp, md_size) || @@ -97,8 +98,6 @@ static int aead_ssl3_init(EVP_AEAD_CTX *ctx, const uint8_t *key, size_t key_len, size_t mac_key_len = EVP_MD_size(md); size_t enc_key_len = EVP_CIPHER_key_length(cipher); assert(mac_key_len + enc_key_len + EVP_CIPHER_iv_length(cipher) == key_len); - /* Although EVP_rc4() is a variable-length cipher, the default key size is - * correct for SSL3. */ AEAD_SSL3_CTX *ssl3_ctx = OPENSSL_malloc(sizeof(AEAD_SSL3_CTX)); if (ssl3_ctx == NULL) { @@ -190,7 +189,7 @@ static int aead_ssl3_seal(const EVP_AEAD_CTX *ctx, uint8_t *out, /* Compute padding and feed that into the cipher. */ uint8_t padding[256]; unsigned padding_len = block_size - ((in_len + mac_len) % block_size); - memset(padding, 0, padding_len - 1); + OPENSSL_memset(padding, 0, padding_len - 1); padding[padding_len - 1] = padding_len - 1; if (!EVP_EncryptUpdate(&ssl3_ctx->cipher_ctx, out + total, &len, padding, (int)padding_len)) { @@ -263,10 +262,10 @@ static int aead_ssl3_open(const EVP_AEAD_CTX *ctx, uint8_t *out, total += len; assert(total == in_len); - /* Remove CBC padding and MAC. This would normally be timing-sensitive, but SSLv3 CBC - * ciphers are already broken. Support will be removed eventually. + /* Remove CBC padding and MAC. This would normally be timing-sensitive, but + * SSLv3 CBC ciphers are already broken. Support will be removed eventually. * https://www.openssl.org/~bodo/ssl-poodle.pdf */ - unsigned data_len; + size_t data_len; if (EVP_CIPHER_CTX_mode(&ssl3_ctx->cipher_ctx) == EVP_CIPH_CBC_MODE) { unsigned padding_length = out[total - 1]; if (total < padding_length + 1 + mac_len) { @@ -297,16 +296,6 @@ static int aead_ssl3_open(const EVP_AEAD_CTX *ctx, uint8_t *out, return 1; } -static int aead_ssl3_get_rc4_state(const EVP_AEAD_CTX *ctx, const RC4_KEY **out_key) { - AEAD_SSL3_CTX *ssl3_ctx = (AEAD_SSL3_CTX *)ctx->aead_state; - if (EVP_CIPHER_CTX_cipher(&ssl3_ctx->cipher_ctx) != EVP_rc4()) { - return 0; - } - - *out_key = (RC4_KEY*) ssl3_ctx->cipher_ctx.cipher_data; - return 1; -} - static int aead_ssl3_get_iv(const EVP_AEAD_CTX *ctx, const uint8_t **out_iv, size_t *out_iv_len) { AEAD_SSL3_CTX *ssl3_ctx = (AEAD_SSL3_CTX *)ctx->aead_state; @@ -320,18 +309,6 @@ static int aead_ssl3_get_iv(const EVP_AEAD_CTX *ctx, const uint8_t **out_iv, return 1; } -static int aead_rc4_md5_ssl3_init(EVP_AEAD_CTX *ctx, const uint8_t *key, - size_t key_len, size_t tag_len, - enum evp_aead_direction_t dir) { - return aead_ssl3_init(ctx, key, key_len, tag_len, dir, EVP_rc4(), EVP_md5()); -} - -static int aead_rc4_sha1_ssl3_init(EVP_AEAD_CTX *ctx, const uint8_t *key, - size_t key_len, size_t tag_len, - enum evp_aead_direction_t dir) { - return aead_ssl3_init(ctx, key, key_len, tag_len, dir, EVP_rc4(), EVP_sha1()); -} - static int aead_aes_128_cbc_sha1_ssl3_init(EVP_AEAD_CTX *ctx, const uint8_t *key, size_t key_len, size_t tag_len, enum evp_aead_direction_t dir) { @@ -360,34 +337,6 @@ static int aead_null_sha1_ssl3_init(EVP_AEAD_CTX *ctx, const uint8_t *key, EVP_sha1()); } -static const EVP_AEAD aead_rc4_md5_ssl3 = { - MD5_DIGEST_LENGTH + 16, /* key len (MD5 + RC4) */ - 0, /* nonce len */ - MD5_DIGEST_LENGTH, /* overhead */ - MD5_DIGEST_LENGTH, /* max tag length */ - NULL, /* init */ - aead_rc4_md5_ssl3_init, - aead_ssl3_cleanup, - aead_ssl3_seal, - aead_ssl3_open, - aead_ssl3_get_rc4_state, - NULL, /* get_iv */ -}; - -static const EVP_AEAD aead_rc4_sha1_ssl3 = { - SHA_DIGEST_LENGTH + 16, /* key len (SHA1 + RC4) */ - 0, /* nonce len */ - SHA_DIGEST_LENGTH, /* overhead */ - SHA_DIGEST_LENGTH, /* max tag length */ - NULL, /* init */ - aead_rc4_sha1_ssl3_init, - aead_ssl3_cleanup, - aead_ssl3_seal, - aead_ssl3_open, - aead_ssl3_get_rc4_state, - NULL, /* get_iv */ -}; - static const EVP_AEAD aead_aes_128_cbc_sha1_ssl3 = { SHA_DIGEST_LENGTH + 16 + 16, /* key len (SHA1 + AES128 + IV) */ 0, /* nonce len */ @@ -398,7 +347,6 @@ static const EVP_AEAD aead_aes_128_cbc_sha1_ssl3 = { aead_ssl3_cleanup, aead_ssl3_seal, aead_ssl3_open, - NULL, /* get_rc4_state */ aead_ssl3_get_iv, }; @@ -412,7 +360,6 @@ static const EVP_AEAD aead_aes_256_cbc_sha1_ssl3 = { aead_ssl3_cleanup, aead_ssl3_seal, aead_ssl3_open, - NULL, /* get_rc4_state */ aead_ssl3_get_iv, }; @@ -426,7 +373,6 @@ static const EVP_AEAD aead_des_ede3_cbc_sha1_ssl3 = { aead_ssl3_cleanup, aead_ssl3_seal, aead_ssl3_open, - NULL, /* get_rc4_state */ aead_ssl3_get_iv, }; @@ -440,14 +386,9 @@ static const EVP_AEAD aead_null_sha1_ssl3 = { aead_ssl3_cleanup, aead_ssl3_seal, aead_ssl3_open, - NULL, /* get_rc4_state */ NULL, /* get_iv */ }; -const EVP_AEAD *EVP_aead_rc4_md5_ssl3(void) { return &aead_rc4_md5_ssl3; } - -const EVP_AEAD *EVP_aead_rc4_sha1_ssl3(void) { return &aead_rc4_sha1_ssl3; } - const EVP_AEAD *EVP_aead_aes_128_cbc_sha1_ssl3(void) { return &aead_aes_128_cbc_sha1_ssl3; } diff --git a/Sources/BoringSSL/crypto/cipher/e_tls.c b/Sources/BoringSSL/crypto/cipher/e_tls.c index b87b0d6eb..7d9bbeea5 100644 --- a/Sources/BoringSSL/crypto/cipher/e_tls.c +++ b/Sources/BoringSSL/crypto/cipher/e_tls.c @@ -25,7 +25,7 @@ #include #include -#include "../crypto/internal.h" +#include "../internal.h" #include "internal.h" @@ -71,8 +71,6 @@ static int aead_tls_init(EVP_AEAD_CTX *ctx, const uint8_t *key, size_t key_len, size_t enc_key_len = EVP_CIPHER_key_length(cipher); assert(mac_key_len + enc_key_len + (implicit_iv ? EVP_CIPHER_iv_length(cipher) : 0) == key_len); - /* Although EVP_rc4() is a variable-length cipher, the default key size is - * correct for TLS. */ AEAD_TLS_CTX *tls_ctx = OPENSSL_malloc(sizeof(AEAD_TLS_CTX)); if (tls_ctx == NULL) { @@ -82,7 +80,7 @@ static int aead_tls_init(EVP_AEAD_CTX *ctx, const uint8_t *key, size_t key_len, EVP_CIPHER_CTX_init(&tls_ctx->cipher_ctx); HMAC_CTX_init(&tls_ctx->hmac_ctx); assert(mac_key_len <= EVP_MAX_MD_SIZE); - memcpy(tls_ctx->mac_key, key, mac_key_len); + OPENSSL_memcpy(tls_ctx->mac_key, key, mac_key_len); tls_ctx->mac_key_len = (uint8_t)mac_key_len; tls_ctx->implicit_iv = implicit_iv; @@ -184,7 +182,7 @@ static int aead_tls_seal(const EVP_AEAD_CTX *ctx, uint8_t *out, /* Compute padding and feed that into the cipher. */ uint8_t padding[256]; unsigned padding_len = block_size - ((in_len + mac_len) % block_size); - memset(padding, padding_len - 1, padding_len); + OPENSSL_memset(padding, padding_len - 1, padding_len); if (!EVP_EncryptUpdate(&tls_ctx->cipher_ctx, out + total, &len, padding, (int)padding_len)) { return 0; @@ -264,35 +262,33 @@ static int aead_tls_open(const EVP_AEAD_CTX *ctx, uint8_t *out, /* Remove CBC padding. Code from here on is timing-sensitive with respect to * |padding_ok| and |data_plus_mac_len| for CBC ciphers. */ - int padding_ok; - unsigned data_plus_mac_len, data_len; + unsigned padding_ok, data_plus_mac_len; if (EVP_CIPHER_CTX_mode(&tls_ctx->cipher_ctx) == EVP_CIPH_CBC_MODE) { - padding_ok = EVP_tls_cbc_remove_padding( - &data_plus_mac_len, out, total, - EVP_CIPHER_CTX_block_size(&tls_ctx->cipher_ctx), - (unsigned)HMAC_size(&tls_ctx->hmac_ctx)); - /* Publicly invalid. This can be rejected in non-constant time. */ - if (padding_ok == 0) { + if (!EVP_tls_cbc_remove_padding( + &padding_ok, &data_plus_mac_len, out, total, + EVP_CIPHER_CTX_block_size(&tls_ctx->cipher_ctx), + (unsigned)HMAC_size(&tls_ctx->hmac_ctx))) { + /* Publicly invalid. This can be rejected in non-constant time. */ OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); return 0; } } else { - padding_ok = 1; + padding_ok = ~0u; data_plus_mac_len = total; /* |data_plus_mac_len| = |total| = |in_len| at this point. |in_len| has * already been checked against the MAC size at the top of the function. */ assert(data_plus_mac_len >= HMAC_size(&tls_ctx->hmac_ctx)); } - data_len = data_plus_mac_len - HMAC_size(&tls_ctx->hmac_ctx); + unsigned data_len = data_plus_mac_len - HMAC_size(&tls_ctx->hmac_ctx); - /* At this point, |padding_ok| is 1 or -1. If 1, the padding is valid and the - * first |data_plus_mac_size| bytes after |out| are the plaintext and - * MAC. Either way, |data_plus_mac_size| is large enough to extract a MAC. */ + /* At this point, if the padding is valid, the first |data_plus_mac_len| bytes + * after |out| are the plaintext and MAC. Otherwise, |data_plus_mac_len| is + * still large enough to extract a MAC, but it will be irrelevant. */ /* To allow for CBC mode which changes cipher length, |ad| doesn't include the * length for legacy ciphers. */ uint8_t ad_fixed[13]; - memcpy(ad_fixed, ad, 11); + OPENSSL_memcpy(ad_fixed, ad, 11); ad_fixed[11] = (uint8_t)(data_len >> 8); ad_fixed[12] = (uint8_t)(data_len & 0xff); ad_len += 2; @@ -338,7 +334,7 @@ static int aead_tls_open(const EVP_AEAD_CTX *ctx, uint8_t *out, * EVP_tls_cbc_remove_padding. */ unsigned good = constant_time_eq_int(CRYPTO_memcmp(record_mac, mac, mac_len), 0); - good &= constant_time_eq_int(padding_ok, 1); + good &= padding_ok; if (!good) { OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); return 0; @@ -350,20 +346,6 @@ static int aead_tls_open(const EVP_AEAD_CTX *ctx, uint8_t *out, return 1; } -static int aead_rc4_md5_tls_init(EVP_AEAD_CTX *ctx, const uint8_t *key, - size_t key_len, size_t tag_len, - enum evp_aead_direction_t dir) { - return aead_tls_init(ctx, key, key_len, tag_len, dir, EVP_rc4(), EVP_md5(), - 0); -} - -static int aead_rc4_sha1_tls_init(EVP_AEAD_CTX *ctx, const uint8_t *key, - size_t key_len, size_t tag_len, - enum evp_aead_direction_t dir) { - return aead_tls_init(ctx, key, key_len, tag_len, dir, EVP_rc4(), EVP_sha1(), - 0); -} - static int aead_aes_128_cbc_sha1_tls_init(EVP_AEAD_CTX *ctx, const uint8_t *key, size_t key_len, size_t tag_len, enum evp_aead_direction_t dir) { @@ -431,17 +413,6 @@ static int aead_des_ede3_cbc_sha1_tls_implicit_iv_init( EVP_sha1(), 1); } -static int aead_rc4_tls_get_rc4_state(const EVP_AEAD_CTX *ctx, - const RC4_KEY **out_key) { - const AEAD_TLS_CTX *tls_ctx = (AEAD_TLS_CTX*) ctx->aead_state; - if (EVP_CIPHER_CTX_cipher(&tls_ctx->cipher_ctx) != EVP_rc4()) { - return 0; - } - - *out_key = (const RC4_KEY*) tls_ctx->cipher_ctx.cipher_data; - return 1; -} - static int aead_tls_get_iv(const EVP_AEAD_CTX *ctx, const uint8_t **out_iv, size_t *out_iv_len) { const AEAD_TLS_CTX *tls_ctx = (AEAD_TLS_CTX*) ctx->aead_state; @@ -462,34 +433,6 @@ static int aead_null_sha1_tls_init(EVP_AEAD_CTX *ctx, const uint8_t *key, EVP_sha1(), 1 /* implicit iv */); } -static const EVP_AEAD aead_rc4_md5_tls = { - MD5_DIGEST_LENGTH + 16, /* key len (MD5 + RC4) */ - 0, /* nonce len */ - MD5_DIGEST_LENGTH, /* overhead */ - MD5_DIGEST_LENGTH, /* max tag length */ - NULL, /* init */ - aead_rc4_md5_tls_init, - aead_tls_cleanup, - aead_tls_seal, - aead_tls_open, - aead_rc4_tls_get_rc4_state, /* get_rc4_state */ - NULL, /* get_iv */ -}; - -static const EVP_AEAD aead_rc4_sha1_tls = { - SHA_DIGEST_LENGTH + 16, /* key len (SHA1 + RC4) */ - 0, /* nonce len */ - SHA_DIGEST_LENGTH, /* overhead */ - SHA_DIGEST_LENGTH, /* max tag length */ - NULL, /* init */ - aead_rc4_sha1_tls_init, - aead_tls_cleanup, - aead_tls_seal, - aead_tls_open, - aead_rc4_tls_get_rc4_state, /* get_rc4_state */ - NULL, /* get_iv */ -}; - static const EVP_AEAD aead_aes_128_cbc_sha1_tls = { SHA_DIGEST_LENGTH + 16, /* key len (SHA1 + AES128) */ 16, /* nonce len (IV) */ @@ -500,7 +443,6 @@ static const EVP_AEAD aead_aes_128_cbc_sha1_tls = { aead_tls_cleanup, aead_tls_seal, aead_tls_open, - NULL, /* get_rc4_state */ NULL, /* get_iv */ }; @@ -514,7 +456,6 @@ static const EVP_AEAD aead_aes_128_cbc_sha1_tls_implicit_iv = { aead_tls_cleanup, aead_tls_seal, aead_tls_open, - NULL, /* get_rc4_state */ aead_tls_get_iv, /* get_iv */ }; @@ -528,7 +469,6 @@ static const EVP_AEAD aead_aes_128_cbc_sha256_tls = { aead_tls_cleanup, aead_tls_seal, aead_tls_open, - NULL, /* get_rc4_state */ NULL, /* get_iv */ }; @@ -542,7 +482,6 @@ static const EVP_AEAD aead_aes_256_cbc_sha1_tls = { aead_tls_cleanup, aead_tls_seal, aead_tls_open, - NULL, /* get_rc4_state */ NULL, /* get_iv */ }; @@ -556,7 +495,6 @@ static const EVP_AEAD aead_aes_256_cbc_sha1_tls_implicit_iv = { aead_tls_cleanup, aead_tls_seal, aead_tls_open, - NULL, /* get_rc4_state */ aead_tls_get_iv, /* get_iv */ }; @@ -570,7 +508,6 @@ static const EVP_AEAD aead_aes_256_cbc_sha256_tls = { aead_tls_cleanup, aead_tls_seal, aead_tls_open, - NULL, /* get_rc4_state */ NULL, /* get_iv */ }; @@ -584,7 +521,6 @@ static const EVP_AEAD aead_aes_256_cbc_sha384_tls = { aead_tls_cleanup, aead_tls_seal, aead_tls_open, - NULL, /* get_rc4_state */ NULL, /* get_iv */ }; @@ -598,7 +534,6 @@ static const EVP_AEAD aead_des_ede3_cbc_sha1_tls = { aead_tls_cleanup, aead_tls_seal, aead_tls_open, - NULL, /* get_rc4_state */ NULL, /* get_iv */ }; @@ -612,7 +547,6 @@ static const EVP_AEAD aead_des_ede3_cbc_sha1_tls_implicit_iv = { aead_tls_cleanup, aead_tls_seal, aead_tls_open, - NULL, /* get_rc4_state */ aead_tls_get_iv, /* get_iv */ }; @@ -626,14 +560,9 @@ static const EVP_AEAD aead_null_sha1_tls = { aead_tls_cleanup, aead_tls_seal, aead_tls_open, - NULL, /* get_rc4_state */ NULL, /* get_iv */ }; -const EVP_AEAD *EVP_aead_rc4_md5_tls(void) { return &aead_rc4_md5_tls; } - -const EVP_AEAD *EVP_aead_rc4_sha1_tls(void) { return &aead_rc4_sha1_tls; } - const EVP_AEAD *EVP_aead_aes_128_cbc_sha1_tls(void) { return &aead_aes_128_cbc_sha1_tls; } diff --git a/Sources/BoringSSL/crypto/cipher/internal.h b/Sources/BoringSSL/crypto/cipher/internal.h index 72ac1189f..d29ce599c 100644 --- a/Sources/BoringSSL/crypto/cipher/internal.h +++ b/Sources/BoringSSL/crypto/cipher/internal.h @@ -95,8 +95,6 @@ struct evp_aead_st { const uint8_t *in, size_t in_len, const uint8_t *ad, size_t ad_len); - int (*get_rc4_state)(const EVP_AEAD_CTX *ctx, const RC4_KEY **out_key); - int (*get_iv)(const EVP_AEAD_CTX *ctx, const uint8_t **out_iv, size_t *out_len); }; @@ -104,15 +102,15 @@ struct evp_aead_st { /* EVP_tls_cbc_get_padding determines the padding from the decrypted, TLS, CBC * record in |in|. This decrypted record should not include any "decrypted" - * explicit IV. It sets |*out_len| to the length with the padding removed or - * |in_len| if invalid. + * explicit IV. If the record is publicly invalid, it returns zero. Otherwise, + * it returns one and sets |*out_padding_ok| to all ones (0xfff..f) if the + * padding is valid and zero otherwise. It then sets |*out_len| to the length + * with the padding removed or |in_len| if invalid. * - * block_size: the block size of the cipher used to encrypt the record. - * returns: - * 0: (in non-constant time) if the record is publicly invalid. - * 1: if the padding was valid - * -1: otherwise. */ -int EVP_tls_cbc_remove_padding(unsigned *out_len, + * If the function returns one, it runs in time independent of the contents of + * |in|. It is also guaranteed that |*out_len| >= |mac_size|, satisfying + * |EVP_tls_cbc_copy_mac|'s precondition. */ +int EVP_tls_cbc_remove_padding(unsigned *out_padding_ok, unsigned *out_len, const uint8_t *in, unsigned in_len, unsigned block_size, unsigned mac_size); diff --git a/Sources/BoringSSL/crypto/cipher/tls_cbc.c b/Sources/BoringSSL/crypto/cipher/tls_cbc.c index e6aaabc8b..52880b0c6 100644 --- a/Sources/BoringSSL/crypto/cipher/tls_cbc.c +++ b/Sources/BoringSSL/crypto/cipher/tls_cbc.c @@ -54,10 +54,11 @@ #include #include -#include +#include #include #include "../internal.h" +#include "internal.h" /* TODO(davidben): unsigned should be size_t. The various constant_time @@ -72,7 +73,7 @@ * supported by TLS.) */ #define MAX_HASH_BLOCK_SIZE 128 -int EVP_tls_cbc_remove_padding(unsigned *out_len, +int EVP_tls_cbc_remove_padding(unsigned *out_padding_ok, unsigned *out_len, const uint8_t *in, unsigned in_len, unsigned block_size, unsigned mac_size) { unsigned padding_length, good, to_check, i; @@ -118,140 +119,97 @@ int EVP_tls_cbc_remove_padding(unsigned *out_len, * bad padding would give POODLE's padding oracle. */ padding_length = good & (padding_length + 1); *out_len = in_len - padding_length; - - return constant_time_select_int(good, 1, -1); + *out_padding_ok = good; + return 1; } -/* If CBC_MAC_ROTATE_IN_PLACE is defined then EVP_tls_cbc_copy_mac is performed - * with variable accesses in a 64-byte-aligned buffer. Assuming that this fits - * into a single or pair of cache-lines, then the variable memory accesses don't - * actually affect the timing. CPUs with smaller cache-lines [if any] are not - * multi-core and are not considered vulnerable to cache-timing attacks. */ -#define CBC_MAC_ROTATE_IN_PLACE - void EVP_tls_cbc_copy_mac(uint8_t *out, unsigned md_size, const uint8_t *in, unsigned in_len, unsigned orig_len) { -#if defined(CBC_MAC_ROTATE_IN_PLACE) - uint8_t rotated_mac_buf[64 + EVP_MAX_MD_SIZE]; - uint8_t *rotated_mac; -#else - uint8_t rotated_mac[EVP_MAX_MD_SIZE]; -#endif + uint8_t rotated_mac1[EVP_MAX_MD_SIZE], rotated_mac2[EVP_MAX_MD_SIZE]; + uint8_t *rotated_mac = rotated_mac1; + uint8_t *rotated_mac_tmp = rotated_mac2; /* mac_end is the index of |in| just after the end of the MAC. */ unsigned mac_end = in_len; unsigned mac_start = mac_end - md_size; - /* scan_start contains the number of bytes that we can ignore because - * the MAC's position can only vary by 255 bytes. */ - unsigned scan_start = 0; - unsigned i, j; - unsigned rotate_offset; assert(orig_len >= in_len); assert(in_len >= md_size); assert(md_size <= EVP_MAX_MD_SIZE); -#if defined(CBC_MAC_ROTATE_IN_PLACE) - rotated_mac = rotated_mac_buf + ((0 - (size_t)rotated_mac_buf) & 63); -#endif - + /* scan_start contains the number of bytes that we can ignore because + * the MAC's position can only vary by 255 bytes. */ + unsigned scan_start = 0; /* This information is public so it's safe to branch based on it. */ if (orig_len > md_size + 255 + 1) { scan_start = orig_len - (md_size + 255 + 1); } - /* Ideally the next statement would be: - * - * rotate_offset = (mac_start - scan_start) % md_size; - * - * However, division is not a constant-time operation (at least on Intel - * chips). Thus we enumerate the possible values of md_size and handle each - * separately. The value of |md_size| is public information (it's determined - * by the cipher suite in the ServerHello) so our timing can vary based on - * its value. */ - - rotate_offset = mac_start - scan_start; - /* rotate_offset can be, at most, 255 (bytes of padding) + 1 (padding length) - * + md_size = 256 + 48 (since SHA-384 is the largest hash) = 304. */ - assert(rotate_offset <= 304); - - if (md_size == 16) { - rotate_offset &= 15; - } else if (md_size == 20) { - /* 1/20 is approximated as 25/512 and then Barrett reduction is used. - * Analytically, this is correct for 0 <= rotate_offset <= 853. */ - unsigned q = (rotate_offset * 25) >> 9; - rotate_offset -= q * 20; - rotate_offset -= - constant_time_select(constant_time_ge(rotate_offset, 20), 20, 0); - } else if (md_size == 32) { - rotate_offset &= 31; - } else if (md_size == 48) { - /* 1/48 is approximated as 10/512 and then Barrett reduction is used. - * Analytically, this is correct for 0 <= rotate_offset <= 768. */ - unsigned q = (rotate_offset * 10) >> 9; - rotate_offset -= q * 48; - rotate_offset -= - constant_time_select(constant_time_ge(rotate_offset, 48), 48, 0); - } else { - /* This should be impossible therefore this path doesn't run in constant - * time. */ - assert(0); - rotate_offset = rotate_offset % md_size; - } - - memset(rotated_mac, 0, md_size); - for (i = scan_start, j = 0; i < orig_len; i++) { - uint8_t mac_started = constant_time_ge_8(i, mac_start); + unsigned rotate_offset = 0; + uint8_t mac_started = 0; + OPENSSL_memset(rotated_mac, 0, md_size); + for (unsigned i = scan_start, j = 0; i < orig_len; i++, j++) { + if (j >= md_size) { + j -= md_size; + } + unsigned is_mac_start = constant_time_eq(i, mac_start); + mac_started |= is_mac_start; uint8_t mac_ended = constant_time_ge_8(i, mac_end); - uint8_t b = in[i]; - rotated_mac[j++] |= b & mac_started & ~mac_ended; - j &= constant_time_lt(j, md_size); + rotated_mac[j] |= in[i] & mac_started & ~mac_ended; + /* Save the offset that |mac_start| is mapped to. */ + rotate_offset |= j & is_mac_start; } -/* Now rotate the MAC */ -#if defined(CBC_MAC_ROTATE_IN_PLACE) - j = 0; - for (i = 0; i < md_size; i++) { - /* in case cache-line is 32 bytes, touch second line */ - ((volatile uint8_t *)rotated_mac)[rotate_offset ^ 32]; - out[j++] = rotated_mac[rotate_offset++]; - rotate_offset &= constant_time_lt(rotate_offset, md_size); - } -#else - memset(out, 0, md_size); - rotate_offset = md_size - rotate_offset; - rotate_offset &= constant_time_lt(rotate_offset, md_size); - for (i = 0; i < md_size; i++) { - for (j = 0; j < md_size; j++) { - out[j] |= rotated_mac[i] & constant_time_eq_8(j, rotate_offset); + /* Now rotate the MAC. We rotate in log(md_size) steps, one for each bit + * position. */ + for (unsigned offset = 1; offset < md_size; + offset <<= 1, rotate_offset >>= 1) { + /* Rotate by |offset| iff the corresponding bit is set in + * |rotate_offset|, placing the result in |rotated_mac_tmp|. */ + const uint8_t skip_rotate = (rotate_offset & 1) - 1; + for (unsigned i = 0, j = offset; i < md_size; i++, j++) { + if (j >= md_size) { + j -= md_size; + } + rotated_mac_tmp[i] = + constant_time_select_8(skip_rotate, rotated_mac[i], rotated_mac[j]); } - rotate_offset++; - rotate_offset &= constant_time_lt(rotate_offset, md_size); + + /* Swap pointers so |rotated_mac| contains the (possibly) rotated value. + * Note the number of iterations and thus the identity of these pointers is + * public information. */ + uint8_t *tmp = rotated_mac; + rotated_mac = rotated_mac_tmp; + rotated_mac_tmp = tmp; } -#endif + + OPENSSL_memcpy(out, rotated_mac, md_size); } /* u32toBE serialises an unsigned, 32-bit number (n) as four bytes at (p) in * big-endian order. The value of p is advanced by four. */ -#define u32toBE(n, p) \ - (*((p)++)=(uint8_t)(n>>24), \ - *((p)++)=(uint8_t)(n>>16), \ - *((p)++)=(uint8_t)(n>>8), \ - *((p)++)=(uint8_t)(n)) +#define u32toBE(n, p) \ + do { \ + *((p)++) = (uint8_t)((n) >> 24); \ + *((p)++) = (uint8_t)((n) >> 16); \ + *((p)++) = (uint8_t)((n) >> 8); \ + *((p)++) = (uint8_t)((n)); \ + } while (0) /* u64toBE serialises an unsigned, 64-bit number (n) as eight bytes at (p) in * big-endian order. The value of p is advanced by eight. */ -#define u64toBE(n, p) \ - (*((p)++)=(uint8_t)(n>>56), \ - *((p)++)=(uint8_t)(n>>48), \ - *((p)++)=(uint8_t)(n>>40), \ - *((p)++)=(uint8_t)(n>>32), \ - *((p)++)=(uint8_t)(n>>24), \ - *((p)++)=(uint8_t)(n>>16), \ - *((p)++)=(uint8_t)(n>>8), \ - *((p)++)=(uint8_t)(n)) +#define u64toBE(n, p) \ + do { \ + *((p)++) = (uint8_t)((n) >> 56); \ + *((p)++) = (uint8_t)((n) >> 48); \ + *((p)++) = (uint8_t)((n) >> 40); \ + *((p)++) = (uint8_t)((n) >> 32); \ + *((p)++) = (uint8_t)((n) >> 24); \ + *((p)++) = (uint8_t)((n) >> 16); \ + *((p)++) = (uint8_t)((n) >> 8); \ + *((p)++) = (uint8_t)((n)); \ + } while (0) /* These functions serialize the state of a hash and thus perform the standard * "final" operation without adding the padding and length that such a function @@ -424,16 +382,16 @@ int EVP_tls_cbc_digest_record(const EVP_MD *md, uint8_t *md_out, /* Compute the initial HMAC block. */ bits += 8 * md_block_size; - memset(hmac_pad, 0, md_block_size); + OPENSSL_memset(hmac_pad, 0, md_block_size); assert(mac_secret_length <= sizeof(hmac_pad)); - memcpy(hmac_pad, mac_secret, mac_secret_length); + OPENSSL_memcpy(hmac_pad, mac_secret, mac_secret_length); for (i = 0; i < md_block_size; i++) { hmac_pad[i] ^= 0x36; } md_transform(md_state.c, hmac_pad); - memset(length_bytes, 0, md_length_size - 4); + OPENSSL_memset(length_bytes, 0, md_length_size - 4); length_bytes[md_length_size - 4] = (uint8_t)(bits >> 24); length_bytes[md_length_size - 3] = (uint8_t)(bits >> 16); length_bytes[md_length_size - 2] = (uint8_t)(bits >> 8); @@ -441,15 +399,15 @@ int EVP_tls_cbc_digest_record(const EVP_MD *md, uint8_t *md_out, if (k > 0) { /* k is a multiple of md_block_size. */ - memcpy(first_block, header, 13); - memcpy(first_block + 13, data, md_block_size - 13); + OPENSSL_memcpy(first_block, header, 13); + OPENSSL_memcpy(first_block + 13, data, md_block_size - 13); md_transform(md_state.c, first_block); for (i = 1; i < k / md_block_size; i++) { md_transform(md_state.c, data + md_block_size * i - 13); } } - memset(mac_out, 0, sizeof(mac_out)); + OPENSSL_memset(mac_out, 0, sizeof(mac_out)); /* We now process the final hash blocks. For each block, we construct * it in constant time. If the |i==index_a| then we'll include the 0x80 diff --git a/Sources/BoringSSL/crypto/cmac/cmac.c b/Sources/BoringSSL/crypto/cmac/cmac.c index fa4c3c49b..a9a527d58 100644 --- a/Sources/BoringSSL/crypto/cmac/cmac.c +++ b/Sources/BoringSSL/crypto/cmac/cmac.c @@ -55,6 +55,8 @@ #include #include +#include "../internal.h" + struct cmac_ctx_st { EVP_CIPHER_CTX cipher_ctx; @@ -176,7 +178,7 @@ int CMAC_Update(CMAC_CTX *ctx, const uint8_t *in, size_t in_len) { todo = in_len; } - memcpy(ctx->block + ctx->block_used, in, todo); + OPENSSL_memcpy(ctx->block + ctx->block_used, in, todo); in += todo; in_len -= todo; ctx->block_used += todo; @@ -206,7 +208,7 @@ int CMAC_Update(CMAC_CTX *ctx, const uint8_t *in, size_t in_len) { in_len -= AES_BLOCK_SIZE; } - memcpy(ctx->block, in, in_len); + OPENSSL_memcpy(ctx->block, in, in_len); ctx->block_used = in_len; return 1; @@ -224,8 +226,8 @@ int CMAC_Final(CMAC_CTX *ctx, uint8_t *out, size_t *out_len) { /* If the last block is incomplete, terminate it with a single 'one' bit * followed by zeros. */ ctx->block[ctx->block_used] = 0x80; - memset(ctx->block + ctx->block_used + 1, 0, - AES_BLOCK_SIZE - (ctx->block_used + 1)); + OPENSSL_memset(ctx->block + ctx->block_used + 1, 0, + AES_BLOCK_SIZE - (ctx->block_used + 1)); mask = ctx->k2; } diff --git a/Sources/BoringSSL/crypto/conf/conf.c b/Sources/BoringSSL/crypto/conf/conf.c index 6bdcc4dcc..5b51d225b 100644 --- a/Sources/BoringSSL/crypto/conf/conf.c +++ b/Sources/BoringSSL/crypto/conf/conf.c @@ -65,6 +65,8 @@ #include #include "conf_def.h" +#include "internal.h" +#include "../internal.h" static uint32_t conf_value_hash(const CONF_VALUE *v) { @@ -117,7 +119,7 @@ CONF_VALUE *CONF_VALUE_new(void) { OPENSSL_PUT_ERROR(CONF, ERR_R_MALLOC_FAILURE); return NULL; } - memset(v, 0, sizeof(CONF_VALUE)); + OPENSSL_memset(v, 0, sizeof(CONF_VALUE)); return v; } @@ -152,7 +154,7 @@ void NCONF_free(CONF *conf) { OPENSSL_free(conf); } -CONF_VALUE *NCONF_new_section(const CONF *conf, const char *section) { +static CONF_VALUE *NCONF_new_section(const CONF *conf, const char *section) { STACK_OF(CONF_VALUE) *sk = NULL; int ok = 0; CONF_VALUE *v = NULL, *old_value; @@ -352,7 +354,7 @@ static int str_copy(CONF *conf, char *section, char **pto, char *from) { static CONF_VALUE *get_section(const CONF *conf, const char *section) { CONF_VALUE template; - memset(&template, 0, sizeof(template)); + OPENSSL_memset(&template, 0, sizeof(template)); template.section = (char *) section; return lh_CONF_VALUE_retrieve(conf->data, &template); } @@ -369,7 +371,7 @@ const char *NCONF_get_string(const CONF *conf, const char *section, const char *name) { CONF_VALUE template, *value; - memset(&template, 0, sizeof(template)); + OPENSSL_memset(&template, 0, sizeof(template)); template.section = (char *) section; template.name = (char *) name; value = lh_CONF_VALUE_retrieve(conf->data, &template); @@ -785,3 +787,5 @@ int CONF_modules_load_file(CONF_MUST_BE_NULL *filename, const char *appname, void CONF_modules_free(void) {} void OPENSSL_config(CONF_MUST_BE_NULL *config_name) {} + +void OPENSSL_no_config(void) {} diff --git a/Sources/BoringSSL/crypto/cpu-aarch64-linux.c b/Sources/BoringSSL/crypto/cpu-aarch64-linux.c new file mode 100644 index 000000000..1b0f39552 --- /dev/null +++ b/Sources/BoringSSL/crypto/cpu-aarch64-linux.c @@ -0,0 +1,61 @@ +/* Copyright (c) 2016, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include + +#if defined(OPENSSL_AARCH64) && !defined(OPENSSL_STATIC_ARMCAP) + +#include + +#include + +#include "internal.h" + + +extern uint32_t OPENSSL_armcap_P; + +void OPENSSL_cpuid_setup(void) { + unsigned long hwcap = getauxval(AT_HWCAP); + + /* See /usr/include/asm/hwcap.h on an aarch64 installation for the source of + * these values. */ + static const unsigned long kNEON = 1 << 1; + static const unsigned long kAES = 1 << 3; + static const unsigned long kPMULL = 1 << 4; + static const unsigned long kSHA1 = 1 << 5; + static const unsigned long kSHA256 = 1 << 6; + + if ((hwcap & kNEON) == 0) { + /* Matching OpenSSL, if NEON is missing, don't report other features + * either. */ + return; + } + + OPENSSL_armcap_P |= ARMV7_NEON; + + if (hwcap & kAES) { + OPENSSL_armcap_P |= ARMV8_AES; + } + if (hwcap & kPMULL) { + OPENSSL_armcap_P |= ARMV8_PMULL; + } + if (hwcap & kSHA1) { + OPENSSL_armcap_P |= ARMV8_SHA1; + } + if (hwcap & kSHA256) { + OPENSSL_armcap_P |= ARMV8_SHA256; + } +} + +#endif /* OPENSSL_AARCH64 && !OPENSSL_STATIC_ARMCAP */ diff --git a/Sources/BoringSSL/crypto/cpu-arm-linux.c b/Sources/BoringSSL/crypto/cpu-arm-linux.c new file mode 100644 index 000000000..95bb5ee36 --- /dev/null +++ b/Sources/BoringSSL/crypto/cpu-arm-linux.c @@ -0,0 +1,360 @@ +/* Copyright (c) 2016, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include + +#if defined(OPENSSL_ARM) && !defined(OPENSSL_STATIC_ARMCAP) + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "internal.h" + + +#define AT_HWCAP 16 +#define AT_HWCAP2 26 + +#define HWCAP_NEON (1 << 12) + +/* See /usr/include/asm/hwcap.h on an ARM installation for the source of + * these values. */ +#define HWCAP2_AES (1 << 0) +#define HWCAP2_PMULL (1 << 1) +#define HWCAP2_SHA1 (1 << 2) +#define HWCAP2_SHA2 (1 << 3) + +/* |getauxval| is not available on Android until API level 20. Link it as a weak + * symbol and use other methods as fallback. */ +unsigned long getauxval(unsigned long type) __attribute__((weak)); + +static int open_eintr(const char *path, int flags) { + int ret; + do { + ret = open(path, flags); + } while (ret < 0 && errno == EINTR); + return ret; +} + +static ssize_t read_eintr(int fd, void *out, size_t len) { + ssize_t ret; + do { + ret = read(fd, out, len); + } while (ret < 0 && errno == EINTR); + return ret; +} + +/* read_full reads exactly |len| bytes from |fd| to |out|. On error or end of + * file, it returns zero. */ +static int read_full(int fd, void *out, size_t len) { + char *outp = out; + while (len > 0) { + ssize_t ret = read_eintr(fd, outp, len); + if (ret <= 0) { + return 0; + } + outp += ret; + len -= ret; + } + return 1; +} + +/* read_file opens |path| and reads until end-of-file. On success, it returns + * one and sets |*out_ptr| and |*out_len| to a newly-allocated buffer with the + * contents. Otherwise, it returns zero. */ +static int read_file(char **out_ptr, size_t *out_len, const char *path) { + int fd = open_eintr(path, O_RDONLY); + if (fd < 0) { + return 0; + } + + static const size_t kReadSize = 1024; + int ret = 0; + size_t cap = kReadSize, len = 0; + char *buf = OPENSSL_malloc(cap); + if (buf == NULL) { + goto err; + } + + for (;;) { + if (cap - len < kReadSize) { + size_t new_cap = cap * 2; + if (new_cap < cap) { + goto err; + } + char *new_buf = OPENSSL_realloc(buf, new_cap); + if (new_buf == NULL) { + goto err; + } + buf = new_buf; + cap = new_cap; + } + + ssize_t bytes_read = read_eintr(fd, buf + len, kReadSize); + if (bytes_read < 0) { + goto err; + } + if (bytes_read == 0) { + break; + } + len += bytes_read; + } + + *out_ptr = buf; + *out_len = len; + ret = 1; + buf = NULL; + +err: + OPENSSL_free(buf); + close(fd); + return ret; +} + +/* getauxval_proc behaves like |getauxval| but reads from /proc/self/auxv. */ +static unsigned long getauxval_proc(unsigned long type) { + int fd = open_eintr("/proc/self/auxv", O_RDONLY); + if (fd < 0) { + return 0; + } + + struct { + unsigned long tag; + unsigned long value; + } entry; + + for (;;) { + if (!read_full(fd, &entry, sizeof(entry)) || + (entry.tag == 0 && entry.value == 0)) { + break; + } + if (entry.tag == type) { + close(fd); + return entry.value; + } + } + close(fd); + return 0; +} + +typedef struct { + const char *data; + size_t len; +} STRING_PIECE; + +static int STRING_PIECE_equals(const STRING_PIECE *a, const char *b) { + size_t b_len = strlen(b); + return a->len == b_len && OPENSSL_memcmp(a->data, b, b_len) == 0; +} + +/* STRING_PIECE_split finds the first occurence of |sep| in |in| and, if found, + * sets |*out_left| and |*out_right| to |in| split before and after it. It + * returns one if |sep| was found and zero otherwise. */ +static int STRING_PIECE_split(STRING_PIECE *out_left, STRING_PIECE *out_right, + const STRING_PIECE *in, char sep) { + const char *p = OPENSSL_memchr(in->data, sep, in->len); + if (p == NULL) { + return 0; + } + /* |out_left| or |out_right| may alias |in|, so make a copy. */ + STRING_PIECE in_copy = *in; + out_left->data = in_copy.data; + out_left->len = p - in_copy.data; + out_right->data = in_copy.data + out_left->len + 1; + out_right->len = in_copy.len - out_left->len - 1; + return 1; +} + +/* STRING_PIECE_trim removes leading and trailing whitespace from |s|. */ +static void STRING_PIECE_trim(STRING_PIECE *s) { + while (s->len != 0 && (s->data[0] == ' ' || s->data[0] == '\t')) { + s->data++; + s->len--; + } + while (s->len != 0 && + (s->data[s->len - 1] == ' ' || s->data[s->len - 1] == '\t')) { + s->len--; + } +} + +/* extract_cpuinfo_field extracts a /proc/cpuinfo field named |field| from + * |in|. If found, it sets |*out| to the value and returns one. Otherwise, it + * returns zero. */ +static int extract_cpuinfo_field(STRING_PIECE *out, const STRING_PIECE *in, + const char *field) { + /* Process |in| one line at a time. */ + STRING_PIECE remaining = *in, line; + while (STRING_PIECE_split(&line, &remaining, &remaining, '\n')) { + STRING_PIECE key, value; + if (!STRING_PIECE_split(&key, &value, &line, ':')) { + continue; + } + STRING_PIECE_trim(&key); + if (STRING_PIECE_equals(&key, field)) { + STRING_PIECE_trim(&value); + *out = value; + return 1; + } + } + + return 0; +} + +static int cpuinfo_field_equals(const STRING_PIECE *cpuinfo, const char *field, + const char *value) { + STRING_PIECE extracted; + return extract_cpuinfo_field(&extracted, cpuinfo, field) && + STRING_PIECE_equals(&extracted, value); +} + +/* has_list_item treats |list| as a space-separated list of items and returns + * one if |item| is contained in |list| and zero otherwise. */ +static int has_list_item(const STRING_PIECE *list, const char *item) { + STRING_PIECE remaining = *list, feature; + while (STRING_PIECE_split(&feature, &remaining, &remaining, ' ')) { + if (STRING_PIECE_equals(&feature, item)) { + return 1; + } + } + return 0; +} + +static unsigned long get_hwcap_cpuinfo(const STRING_PIECE *cpuinfo) { + if (cpuinfo_field_equals(cpuinfo, "CPU architecture", "8")) { + /* This is a 32-bit ARM binary running on a 64-bit kernel. NEON is always + * available on ARMv8. Linux omits required features, so reading the + * "Features" line does not work. (For simplicity, use strict equality. We + * assume everything running on future ARM architectures will have a + * working |getauxval|.) */ + return HWCAP_NEON; + } + + STRING_PIECE features; + if (extract_cpuinfo_field(&features, cpuinfo, "Features") && + has_list_item(&features, "neon")) { + return HWCAP_NEON; + } + return 0; +} + +static unsigned long get_hwcap2_cpuinfo(const STRING_PIECE *cpuinfo) { + STRING_PIECE features; + if (!extract_cpuinfo_field(&features, cpuinfo, "Features")) { + return 0; + } + + unsigned long ret = 0; + if (has_list_item(&features, "aes")) { + ret |= HWCAP2_AES; + } + if (has_list_item(&features, "pmull")) { + ret |= HWCAP2_PMULL; + } + if (has_list_item(&features, "sha1")) { + ret |= HWCAP2_SHA1; + } + if (has_list_item(&features, "sha2")) { + ret |= HWCAP2_SHA2; + } + return ret; +} + +/* has_broken_neon returns one if |in| matches a CPU known to have a broken + * NEON unit. See https://crbug.com/341598. */ +static int has_broken_neon(const STRING_PIECE *cpuinfo) { + return cpuinfo_field_equals(cpuinfo, "CPU implementer", "0x51") && + cpuinfo_field_equals(cpuinfo, "CPU architecture", "7") && + cpuinfo_field_equals(cpuinfo, "CPU variant", "0x1") && + cpuinfo_field_equals(cpuinfo, "CPU part", "0x04d") && + cpuinfo_field_equals(cpuinfo, "CPU revision", "0"); +} + +extern uint32_t OPENSSL_armcap_P; + +static int g_has_broken_neon; + +void OPENSSL_cpuid_setup(void) { + char *cpuinfo_data; + size_t cpuinfo_len; + if (!read_file(&cpuinfo_data, &cpuinfo_len, "/proc/cpuinfo")) { + return; + } + STRING_PIECE cpuinfo; + cpuinfo.data = cpuinfo_data; + cpuinfo.len = cpuinfo_len; + + /* |getauxval| is not available on Android until API level 20. If it is + * unavailable, read from /proc/self/auxv as a fallback. This is unreadable + * on some versions of Android, so further fall back to /proc/cpuinfo. + * + * See + * https://android.googlesource.com/platform/ndk/+/882ac8f3392858991a0e1af33b4b7387ec856bd2 + * and b/13679666 (Google-internal) for details. */ + unsigned long hwcap = 0; + if (getauxval != NULL) { + hwcap = getauxval(AT_HWCAP); + } + if (hwcap == 0) { + hwcap = getauxval_proc(AT_HWCAP); + } + if (hwcap == 0) { + hwcap = get_hwcap_cpuinfo(&cpuinfo); + } + + /* Clear NEON support if known broken. */ + g_has_broken_neon = has_broken_neon(&cpuinfo); + if (g_has_broken_neon) { + hwcap &= ~HWCAP_NEON; + } + + /* Matching OpenSSL, only report other features if NEON is present. */ + if (hwcap & HWCAP_NEON) { + OPENSSL_armcap_P |= ARMV7_NEON; + + /* Some ARMv8 Android devices don't expose AT_HWCAP2. Fall back to + * /proc/cpuinfo. See https://crbug.com/596156. */ + unsigned long hwcap2 = 0; + if (getauxval != NULL) { + hwcap2 = getauxval(AT_HWCAP2); + } + if (hwcap2 == 0) { + hwcap2 = get_hwcap2_cpuinfo(&cpuinfo); + } + + if (hwcap2 & HWCAP2_AES) { + OPENSSL_armcap_P |= ARMV8_AES; + } + if (hwcap2 & HWCAP2_PMULL) { + OPENSSL_armcap_P |= ARMV8_PMULL; + } + if (hwcap2 & HWCAP2_SHA1) { + OPENSSL_armcap_P |= ARMV8_SHA1; + } + if (hwcap2 & HWCAP2_SHA2) { + OPENSSL_armcap_P |= ARMV8_SHA256; + } + } + + OPENSSL_free(cpuinfo_data); +} + +int CRYPTO_has_broken_NEON(void) { return g_has_broken_neon; } + +#endif /* OPENSSL_ARM && !OPENSSL_STATIC_ARMCAP */ diff --git a/Sources/BoringSSL/crypto/cpu-arm.c b/Sources/BoringSSL/crypto/cpu-arm.c index 675d174e4..ef395eaeb 100644 --- a/Sources/BoringSSL/crypto/cpu-arm.c +++ b/Sources/BoringSSL/crypto/cpu-arm.c @@ -17,52 +17,15 @@ #if (defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64)) && \ !defined(OPENSSL_STATIC_ARMCAP) -#include -#include - -#include -#include - #include -/* We can't include because the Android SDK version against which - * Chromium builds is too old to have it. Instead we define all the constants - * that we need and have a weak pointer to getauxval. */ - -unsigned long getauxval(unsigned long type) __attribute__((weak)); - extern uint32_t OPENSSL_armcap_P; char CRYPTO_is_NEON_capable_at_runtime(void) { return (OPENSSL_armcap_P & ARMV7_NEON) != 0; } -static char g_set_neon_called = 0; - -void CRYPTO_set_NEON_capable(char neon_capable) { - g_set_neon_called = 1; - - if (neon_capable) { - OPENSSL_armcap_P |= ARMV7_NEON; - } else { - OPENSSL_armcap_P &= ~ARMV7_NEON; - } -} - -char CRYPTO_is_NEON_functional(void) { - static const uint32_t kWantFlags = ARMV7_NEON | ARMV7_NEON_FUNCTIONAL; - return (OPENSSL_armcap_P & kWantFlags) == kWantFlags; -} - -void CRYPTO_set_NEON_functional(char neon_functional) { - if (neon_functional) { - OPENSSL_armcap_P |= ARMV7_NEON_FUNCTIONAL; - } else { - OPENSSL_armcap_P &= ~ARMV7_NEON_FUNCTIONAL; - } -} - int CRYPTO_is_ARMv8_AES_capable(void) { return (OPENSSL_armcap_P & ARMV8_AES) != 0; } @@ -71,129 +34,5 @@ int CRYPTO_is_ARMv8_PMULL_capable(void) { return (OPENSSL_armcap_P & ARMV8_PMULL) != 0; } -#if !defined(OPENSSL_NO_ASM) && defined(OPENSSL_ARM) - -static sigjmp_buf sigill_jmp; - -static void sigill_handler(int signal) { - siglongjmp(sigill_jmp, signal); -} - -void CRYPTO_arm_neon_probe(void); - -// probe_for_NEON returns 1 if a NEON instruction runs successfully. Because -// getauxval doesn't exist on Android until Jelly Bean, supporting NEON on -// older devices requires this. -static int probe_for_NEON(void) { - int supported = 0; - - sigset_t sigmask; - sigfillset(&sigmask); - sigdelset(&sigmask, SIGILL); - sigdelset(&sigmask, SIGTRAP); - sigdelset(&sigmask, SIGFPE); - sigdelset(&sigmask, SIGBUS); - sigdelset(&sigmask, SIGSEGV); - - struct sigaction sigill_original_action, sigill_action; - memset(&sigill_action, 0, sizeof(sigill_action)); - sigill_action.sa_handler = sigill_handler; - sigill_action.sa_mask = sigmask; - - sigset_t original_sigmask; - sigprocmask(SIG_SETMASK, &sigmask, &original_sigmask); - - if (sigsetjmp(sigill_jmp, 1 /* save signals */) == 0) { - sigaction(SIGILL, &sigill_action, &sigill_original_action); - - // This function cannot be inline asm because GCC will refuse to compile - // inline NEON instructions unless building with -mfpu=neon, which would - // defeat the point of probing for support at runtime. - CRYPTO_arm_neon_probe(); - supported = 1; - } - // Note that Android up to and including Lollipop doesn't restore the signal - // mask correctly after returning from a sigsetjmp. So that would need to be - // set again here if more probes were added. - // See https://android-review.googlesource.com/#/c/127624/ - - sigaction(SIGILL, &sigill_original_action, NULL); - sigprocmask(SIG_SETMASK, &original_sigmask, NULL); - - return supported; -} - -#else - -static int probe_for_NEON(void) { - return 0; -} - -#endif /* !OPENSSL_NO_ASM && OPENSSL_ARM */ - -void OPENSSL_cpuid_setup(void) { - if (getauxval == NULL) { - // On ARM, but not AArch64, try a NEON instruction and see whether it works - // in order to probe for NEON support. - // - // Note that |CRYPTO_is_NEON_capable| can be true even if - // |CRYPTO_set_NEON_capable| has never been called if the code was compiled - // with NEON support enabled (e.g. -mfpu=neon). - if (!g_set_neon_called && !CRYPTO_is_NEON_capable() && probe_for_NEON()) { - OPENSSL_armcap_P |= ARMV7_NEON; - } - return; - } - - static const unsigned long AT_HWCAP = 16; - unsigned long hwcap = getauxval(AT_HWCAP); - -#if defined(OPENSSL_ARM) - static const unsigned long kNEON = 1 << 12; - if ((hwcap & kNEON) == 0) { - return; - } - - /* In 32-bit mode, the ARMv8 feature bits are in a different aux vector - * value. */ - static const unsigned long AT_HWCAP2 = 26; - hwcap = getauxval(AT_HWCAP2); - - /* See /usr/include/asm/hwcap.h on an ARM installation for the source of - * these values. */ - static const unsigned long kAES = 1 << 0; - static const unsigned long kPMULL = 1 << 1; - static const unsigned long kSHA1 = 1 << 2; - static const unsigned long kSHA256 = 1 << 3; -#elif defined(OPENSSL_AARCH64) - /* See /usr/include/asm/hwcap.h on an aarch64 installation for the source of - * these values. */ - static const unsigned long kNEON = 1 << 1; - static const unsigned long kAES = 1 << 3; - static const unsigned long kPMULL = 1 << 4; - static const unsigned long kSHA1 = 1 << 5; - static const unsigned long kSHA256 = 1 << 6; - - if ((hwcap & kNEON) == 0) { - return; - } -#endif - - OPENSSL_armcap_P |= ARMV7_NEON; - - if (hwcap & kAES) { - OPENSSL_armcap_P |= ARMV8_AES; - } - if (hwcap & kPMULL) { - OPENSSL_armcap_P |= ARMV8_PMULL; - } - if (hwcap & kSHA1) { - OPENSSL_armcap_P |= ARMV8_SHA1; - } - if (hwcap & kSHA256) { - OPENSSL_armcap_P |= ARMV8_SHA256; - } -} - #endif /* (defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64)) && !defined(OPENSSL_STATIC_ARMCAP) */ diff --git a/Sources/BoringSSL/crypto/cpu-intel.c b/Sources/BoringSSL/crypto/cpu-intel.c index 6614f63f1..f2e0c4cbc 100644 --- a/Sources/BoringSSL/crypto/cpu-intel.c +++ b/Sources/BoringSSL/crypto/cpu-intel.c @@ -64,17 +64,19 @@ #if !defined(OPENSSL_NO_ASM) && (defined(OPENSSL_X86) || defined(OPENSSL_X86_64)) #include -#include #include +#include #include #if defined(OPENSSL_WINDOWS) -#pragma warning(push, 3) +OPENSSL_MSVC_PRAGMA(warning(push, 3)) #include #include -#pragma warning(pop) +OPENSSL_MSVC_PRAGMA(warning(pop)) #endif +#include "internal.h" + /* OPENSSL_cpuid runs the cpuid instruction. |leaf| is passed in as EAX and ECX * is set to zero. It writes EAX, EBX, ECX, and EDX to |*out_eax| through diff --git a/Sources/BoringSSL/crypto/cpu-ppc64le.c b/Sources/BoringSSL/crypto/cpu-ppc64le.c new file mode 100644 index 000000000..c431c818f --- /dev/null +++ b/Sources/BoringSSL/crypto/cpu-ppc64le.c @@ -0,0 +1,40 @@ +/* Copyright (c) 2016, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include + +#if defined(OPENSSL_PPC64LE) + +#include + +#include "internal.h" + + +#if !defined(PPC_FEATURE2_HAS_VCRYPTO) +/* PPC_FEATURE2_HAS_VCRYPTO was taken from section 4.1.2.3 of the “OpenPOWER + * ABI for Linux Supplement”. */ +#define PPC_FEATURE2_HAS_VCRYPTO 0x02000000 +#endif + +static unsigned long g_ppc64le_hwcap2 = 0; + +void OPENSSL_cpuid_setup(void) { + g_ppc64le_hwcap2 = getauxval(AT_HWCAP2); +} + +int CRYPTO_is_PPC64LE_vcrypto_capable(void) { + return (g_ppc64le_hwcap2 & PPC_FEATURE2_HAS_VCRYPTO) != 0; +} + +#endif /* OPENSSL_PPC64LE */ diff --git a/Sources/BoringSSL/crypto/crypto.c b/Sources/BoringSSL/crypto/crypto.c index da8807db7..c32f5144d 100644 --- a/Sources/BoringSSL/crypto/crypto.c +++ b/Sources/BoringSSL/crypto/crypto.c @@ -21,9 +21,11 @@ #if !defined(OPENSSL_NO_ASM) && !defined(OPENSSL_STATIC_ARMCAP) && \ (defined(OPENSSL_X86) || defined(OPENSSL_X86_64) || \ - defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64)) -/* x86, x86_64 and the ARMs need to record the result of a cpuid call for the - * asm to work correctly, unless compiled without asm code. */ + defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64) || \ + defined(OPENSSL_PPC64LE)) +/* x86, x86_64, the ARMs and ppc64le need to record the result of a + * cpuid/getauxval call for the asm to work correctly, unless compiled without + * asm code. */ #define NEED_CPUID #else @@ -63,7 +65,7 @@ uint32_t OPENSSL_ia32cap_P[4] = {0}; uint32_t OPENSSL_armcap_P = #if defined(OPENSSL_STATIC_ARMCAP_NEON) || defined(__ARM_NEON__) - ARMV7_NEON | ARMV7_NEON_FUNCTIONAL | + ARMV7_NEON | #endif #if defined(OPENSSL_STATIC_ARMCAP_AES) ARMV8_AES | @@ -79,10 +81,8 @@ uint32_t OPENSSL_armcap_P = #endif 0; -#elif defined(__ARM_NEON__) -uint32_t OPENSSL_armcap_P = ARMV7_NEON | ARMV7_NEON_FUNCTIONAL; #else -uint32_t OPENSSL_armcap_P = ARMV7_NEON_FUNCTIONAL; +uint32_t OPENSSL_armcap_P = 0; #endif #endif @@ -125,6 +125,22 @@ void CRYPTO_library_init(void) { #endif } +int CRYPTO_is_confidential_build(void) { +#if defined(BORINGSSL_CONFIDENTIAL) + return 1; +#else + return 0; +#endif +} + +int CRYPTO_has_asm(void) { +#if defined(OPENSSL_NO_ASM) + return 0; +#else + return 1; +#endif +} + const char *SSLeay_version(int unused) { return "BoringSSL"; } @@ -139,4 +155,10 @@ int CRYPTO_malloc_init(void) { void ENGINE_load_builtin_engines(void) {} +int ENGINE_register_all_complete(void) { + return 1; +} + void OPENSSL_load_builtin_modules(void) {} + +int FIPS_mode(void) { return 0; } diff --git a/Sources/BoringSSL/crypto/curve25519/curve25519.c b/Sources/BoringSSL/crypto/curve25519/curve25519.c index 61bbdcedc..c91e78eaa 100644 --- a/Sources/BoringSSL/crypto/curve25519/curve25519.c +++ b/Sources/BoringSSL/crypto/curve25519/curve25519.c @@ -29,13 +29,13 @@ #include #include "internal.h" +#include "../internal.h" -/* fe means field element. Here the field is \Z/(2^255-19). An element t, - * entries t[0]...t[9], represents the integer t[0]+2^26 t[1]+2^51 t[2]+2^77 - * t[3]+2^102 t[4]+...+2^230 t[9]. Bounds on each t[i] vary depending on - * context. */ -typedef int32_t fe[10]; +static const int64_t kBottom25Bits = INT64_C(0x1ffffff); +static const int64_t kBottom26Bits = INT64_C(0x3ffffff); +static const int64_t kTop39Bits = INT64_C(0xfffffffffe000000); +static const int64_t kTop38Bits = INT64_C(0xfffffffffc000000); static uint64_t load_3(const uint8_t *in) { uint64_t result; @@ -77,17 +77,17 @@ static void fe_frombytes(fe h, const uint8_t *s) { int64_t carry8; int64_t carry9; - carry9 = (h9 + (int64_t) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25; - carry1 = (h1 + (int64_t) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25; - carry3 = (h3 + (int64_t) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25; - carry5 = (h5 + (int64_t) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25; - carry7 = (h7 + (int64_t) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25; + carry9 = h9 + (1 << 24); h0 += (carry9 >> 25) * 19; h9 -= carry9 & kTop39Bits; + carry1 = h1 + (1 << 24); h2 += carry1 >> 25; h1 -= carry1 & kTop39Bits; + carry3 = h3 + (1 << 24); h4 += carry3 >> 25; h3 -= carry3 & kTop39Bits; + carry5 = h5 + (1 << 24); h6 += carry5 >> 25; h5 -= carry5 & kTop39Bits; + carry7 = h7 + (1 << 24); h8 += carry7 >> 25; h7 -= carry7 & kTop39Bits; - carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26; - carry2 = (h2 + (int64_t) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26; - carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26; - carry6 = (h6 + (int64_t) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26; - carry8 = (h8 + (int64_t) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26; + carry0 = h0 + (1 << 25); h1 += carry0 >> 26; h0 -= carry0 & kTop38Bits; + carry2 = h2 + (1 << 25); h3 += carry2 >> 26; h2 -= carry2 & kTop38Bits; + carry4 = h4 + (1 << 25); h5 += carry4 >> 26; h4 -= carry4 & kTop38Bits; + carry6 = h6 + (1 << 25); h7 += carry6 >> 26; h6 -= carry6 & kTop38Bits; + carry8 = h8 + (1 << 25); h9 += carry8 >> 26; h8 -= carry8 & kTop38Bits; h[0] = h0; h[1] = h1; @@ -135,16 +135,6 @@ static void fe_tobytes(uint8_t *s, const fe h) { int32_t h8 = h[8]; int32_t h9 = h[9]; int32_t q; - int32_t carry0; - int32_t carry1; - int32_t carry2; - int32_t carry3; - int32_t carry4; - int32_t carry5; - int32_t carry6; - int32_t carry7; - int32_t carry8; - int32_t carry9; q = (19 * h9 + (((int32_t) 1) << 24)) >> 25; q = (h0 + q) >> 26; @@ -162,16 +152,16 @@ static void fe_tobytes(uint8_t *s, const fe h) { h0 += 19 * q; /* Goal: Output h-2^255 q, which is between 0 and 2^255-20. */ - carry0 = h0 >> 26; h1 += carry0; h0 -= carry0 << 26; - carry1 = h1 >> 25; h2 += carry1; h1 -= carry1 << 25; - carry2 = h2 >> 26; h3 += carry2; h2 -= carry2 << 26; - carry3 = h3 >> 25; h4 += carry3; h3 -= carry3 << 25; - carry4 = h4 >> 26; h5 += carry4; h4 -= carry4 << 26; - carry5 = h5 >> 25; h6 += carry5; h5 -= carry5 << 25; - carry6 = h6 >> 26; h7 += carry6; h6 -= carry6 << 26; - carry7 = h7 >> 25; h8 += carry7; h7 -= carry7 << 25; - carry8 = h8 >> 26; h9 += carry8; h8 -= carry8 << 26; - carry9 = h9 >> 25; h9 -= carry9 << 25; + h1 += h0 >> 26; h0 &= kBottom26Bits; + h2 += h1 >> 25; h1 &= kBottom25Bits; + h3 += h2 >> 26; h2 &= kBottom26Bits; + h4 += h3 >> 25; h3 &= kBottom25Bits; + h5 += h4 >> 26; h4 &= kBottom26Bits; + h6 += h5 >> 25; h5 &= kBottom25Bits; + h7 += h6 >> 26; h6 &= kBottom26Bits; + h8 += h7 >> 25; h7 &= kBottom25Bits; + h9 += h8 >> 26; h8 &= kBottom26Bits; + h9 &= kBottom25Bits; /* h10 = carry9 */ /* Goal: Output h0+...+2^255 h10-2^255 q, which is between 0 and 2^255-20. @@ -182,32 +172,32 @@ static void fe_tobytes(uint8_t *s, const fe h) { s[0] = h0 >> 0; s[1] = h0 >> 8; s[2] = h0 >> 16; - s[3] = (h0 >> 24) | (h1 << 2); + s[3] = (h0 >> 24) | ((uint32_t)(h1) << 2); s[4] = h1 >> 6; s[5] = h1 >> 14; - s[6] = (h1 >> 22) | (h2 << 3); + s[6] = (h1 >> 22) | ((uint32_t)(h2) << 3); s[7] = h2 >> 5; s[8] = h2 >> 13; - s[9] = (h2 >> 21) | (h3 << 5); + s[9] = (h2 >> 21) | ((uint32_t)(h3) << 5); s[10] = h3 >> 3; s[11] = h3 >> 11; - s[12] = (h3 >> 19) | (h4 << 6); + s[12] = (h3 >> 19) | ((uint32_t)(h4) << 6); s[13] = h4 >> 2; s[14] = h4 >> 10; s[15] = h4 >> 18; s[16] = h5 >> 0; s[17] = h5 >> 8; s[18] = h5 >> 16; - s[19] = (h5 >> 24) | (h6 << 1); + s[19] = (h5 >> 24) | ((uint32_t)(h6) << 1); s[20] = h6 >> 7; s[21] = h6 >> 15; - s[22] = (h6 >> 23) | (h7 << 3); + s[22] = (h6 >> 23) | ((uint32_t)(h7) << 3); s[23] = h7 >> 5; s[24] = h7 >> 13; - s[25] = (h7 >> 21) | (h8 << 4); + s[25] = (h7 >> 21) | ((uint32_t)(h8) << 4); s[26] = h8 >> 4; s[27] = h8 >> 12; - s[28] = (h8 >> 20) | (h9 << 6); + s[28] = (h8 >> 20) | ((uint32_t)(h9) << 6); s[29] = h9 >> 2; s[30] = h9 >> 10; s[31] = h9 >> 18; @@ -215,15 +205,15 @@ static void fe_tobytes(uint8_t *s, const fe h) { /* h = f */ static void fe_copy(fe h, const fe f) { - memmove(h, f, sizeof(int32_t) * 10); + OPENSSL_memmove(h, f, sizeof(int32_t) * 10); } /* h = 0 */ -static void fe_0(fe h) { memset(h, 0, sizeof(int32_t) * 10); } +static void fe_0(fe h) { OPENSSL_memset(h, 0, sizeof(int32_t) * 10); } /* h = 1 */ static void fe_1(fe h) { - memset(h, 0, sizeof(int32_t) * 10); + OPENSSL_memset(h, 0, sizeof(int32_t) * 10); h[0] = 1; } @@ -447,46 +437,46 @@ static void fe_mul(fe h, const fe f, const fe g) { * |h1| <= (1.65*1.65*2^51*(1+1+19+19+19+19+19+19+19+19)) * i.e. |h1| <= 1.7*2^59; narrower ranges for h3, h5, h7, h9 */ - carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26; - carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26; + carry0 = h0 + (1 << 25); h1 += carry0 >> 26; h0 -= carry0 & kTop38Bits; + carry4 = h4 + (1 << 25); h5 += carry4 >> 26; h4 -= carry4 & kTop38Bits; /* |h0| <= 2^25 */ /* |h4| <= 2^25 */ /* |h1| <= 1.71*2^59 */ /* |h5| <= 1.71*2^59 */ - carry1 = (h1 + (int64_t) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25; - carry5 = (h5 + (int64_t) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25; + carry1 = h1 + (1 << 24); h2 += carry1 >> 25; h1 -= carry1 & kTop39Bits; + carry5 = h5 + (1 << 24); h6 += carry5 >> 25; h5 -= carry5 & kTop39Bits; /* |h1| <= 2^24; from now on fits into int32 */ /* |h5| <= 2^24; from now on fits into int32 */ /* |h2| <= 1.41*2^60 */ /* |h6| <= 1.41*2^60 */ - carry2 = (h2 + (int64_t) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26; - carry6 = (h6 + (int64_t) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26; + carry2 = h2 + (1 << 25); h3 += carry2 >> 26; h2 -= carry2 & kTop38Bits; + carry6 = h6 + (1 << 25); h7 += carry6 >> 26; h6 -= carry6 & kTop38Bits; /* |h2| <= 2^25; from now on fits into int32 unchanged */ /* |h6| <= 2^25; from now on fits into int32 unchanged */ /* |h3| <= 1.71*2^59 */ /* |h7| <= 1.71*2^59 */ - carry3 = (h3 + (int64_t) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25; - carry7 = (h7 + (int64_t) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25; + carry3 = h3 + (1 << 24); h4 += carry3 >> 25; h3 -= carry3 & kTop39Bits; + carry7 = h7 + (1 << 24); h8 += carry7 >> 25; h7 -= carry7 & kTop39Bits; /* |h3| <= 2^24; from now on fits into int32 unchanged */ /* |h7| <= 2^24; from now on fits into int32 unchanged */ /* |h4| <= 1.72*2^34 */ /* |h8| <= 1.41*2^60 */ - carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26; - carry8 = (h8 + (int64_t) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26; + carry4 = h4 + (1 << 25); h5 += carry4 >> 26; h4 -= carry4 & kTop38Bits; + carry8 = h8 + (1 << 25); h9 += carry8 >> 26; h8 -= carry8 & kTop38Bits; /* |h4| <= 2^25; from now on fits into int32 unchanged */ /* |h8| <= 2^25; from now on fits into int32 unchanged */ /* |h5| <= 1.01*2^24 */ /* |h9| <= 1.71*2^59 */ - carry9 = (h9 + (int64_t) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25; + carry9 = h9 + (1 << 24); h0 += (carry9 >> 25) * 19; h9 -= carry9 & kTop39Bits; /* |h9| <= 2^24; from now on fits into int32 unchanged */ /* |h0| <= 1.1*2^39 */ - carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26; + carry0 = h0 + (1 << 25); h1 += carry0 >> 26; h0 -= carry0 & kTop38Bits; /* |h0| <= 2^25; from now on fits into int32 unchanged */ /* |h1| <= 1.01*2^24 */ @@ -612,24 +602,24 @@ static void fe_sq(fe h, const fe f) { int64_t carry8; int64_t carry9; - carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26; - carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26; + carry0 = h0 + (1 << 25); h1 += carry0 >> 26; h0 -= carry0 & kTop38Bits; + carry4 = h4 + (1 << 25); h5 += carry4 >> 26; h4 -= carry4 & kTop38Bits; - carry1 = (h1 + (int64_t) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25; - carry5 = (h5 + (int64_t) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25; + carry1 = h1 + (1 << 24); h2 += carry1 >> 25; h1 -= carry1 & kTop39Bits; + carry5 = h5 + (1 << 24); h6 += carry5 >> 25; h5 -= carry5 & kTop39Bits; - carry2 = (h2 + (int64_t) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26; - carry6 = (h6 + (int64_t) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26; + carry2 = h2 + (1 << 25); h3 += carry2 >> 26; h2 -= carry2 & kTop38Bits; + carry6 = h6 + (1 << 25); h7 += carry6 >> 26; h6 -= carry6 & kTop38Bits; - carry3 = (h3 + (int64_t) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25; - carry7 = (h7 + (int64_t) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25; + carry3 = h3 + (1 << 24); h4 += carry3 >> 25; h3 -= carry3 & kTop39Bits; + carry7 = h7 + (1 << 24); h8 += carry7 >> 25; h7 -= carry7 & kTop39Bits; - carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26; - carry8 = (h8 + (int64_t) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26; + carry4 = h4 + (1 << 25); h5 += carry4 >> 26; h4 -= carry4 & kTop38Bits; + carry8 = h8 + (1 << 25); h9 += carry8 >> 26; h8 -= carry8 & kTop38Bits; - carry9 = (h9 + (int64_t) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25; + carry9 = h9 + (1 << 24); h0 += (carry9 >> 25) * 19; h9 -= carry9 & kTop39Bits; - carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26; + carry0 = h0 + (1 << 25); h1 += carry0 >> 26; h0 -= carry0 & kTop38Bits; h[0] = h0; h[1] = h1; @@ -651,9 +641,6 @@ static void fe_invert(fe out, const fe z) { int i; fe_sq(t0, z); - for (i = 1; i < 1; ++i) { - fe_sq(t0, t0); - } fe_sq(t1, t0); for (i = 1; i < 2; ++i) { fe_sq(t1, t1); @@ -661,9 +648,6 @@ static void fe_invert(fe out, const fe z) { fe_mul(t1, z, t1); fe_mul(t0, t0, t1); fe_sq(t2, t0); - for (i = 1; i < 1; ++i) { - fe_sq(t2, t2); - } fe_mul(t1, t1, t2); fe_sq(t2, t1); for (i = 1; i < 5; ++i) { @@ -880,24 +864,24 @@ static void fe_sq2(fe h, const fe f) { h8 += h8; h9 += h9; - carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26; - carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26; + carry0 = h0 + (1 << 25); h1 += carry0 >> 26; h0 -= carry0 & kTop38Bits; + carry4 = h4 + (1 << 25); h5 += carry4 >> 26; h4 -= carry4 & kTop38Bits; - carry1 = (h1 + (int64_t) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25; - carry5 = (h5 + (int64_t) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25; + carry1 = h1 + (1 << 24); h2 += carry1 >> 25; h1 -= carry1 & kTop39Bits; + carry5 = h5 + (1 << 24); h6 += carry5 >> 25; h5 -= carry5 & kTop39Bits; - carry2 = (h2 + (int64_t) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26; - carry6 = (h6 + (int64_t) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26; + carry2 = h2 + (1 << 25); h3 += carry2 >> 26; h2 -= carry2 & kTop38Bits; + carry6 = h6 + (1 << 25); h7 += carry6 >> 26; h6 -= carry6 & kTop38Bits; - carry3 = (h3 + (int64_t) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25; - carry7 = (h7 + (int64_t) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25; + carry3 = h3 + (1 << 24); h4 += carry3 >> 25; h3 -= carry3 & kTop39Bits; + carry7 = h7 + (1 << 24); h8 += carry7 >> 25; h7 -= carry7 & kTop39Bits; - carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26; - carry8 = (h8 + (int64_t) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26; + carry4 = h4 + (1 << 25); h5 += carry4 >> 26; h4 -= carry4 & kTop38Bits; + carry8 = h8 + (1 << 25); h9 += carry8 >> 26; h8 -= carry8 & kTop38Bits; - carry9 = (h9 + (int64_t) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25; + carry9 = h9 + (1 << 24); h0 += (carry9 >> 25) * 19; h9 -= carry9 & kTop39Bits; - carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26; + carry0 = h0 + (1 << 25); h1 += carry0 >> 26; h0 -= carry0 & kTop38Bits; h[0] = h0; h[1] = h1; @@ -918,9 +902,6 @@ static void fe_pow22523(fe out, const fe z) { int i; fe_sq(t0, z); - for (i = 1; i < 1; ++i) { - fe_sq(t0, t0); - } fe_sq(t1, t0); for (i = 1; i < 2; ++i) { fe_sq(t1, t1); @@ -928,9 +909,6 @@ static void fe_pow22523(fe out, const fe z) { fe_mul(t1, z, t1); fe_mul(t0, t0, t1); fe_sq(t0, t0); - for (i = 1; i < 1; ++i) { - fe_sq(t0, t0); - } fe_mul(t0, t1, t0); fe_sq(t1, t0); for (i = 1; i < 5; ++i) { @@ -974,52 +952,7 @@ static void fe_pow22523(fe out, const fe z) { fe_mul(out, t0, z); } -/* ge means group element. - - * Here the group is the set of pairs (x,y) of field elements (see fe.h) - * satisfying -x^2 + y^2 = 1 + d x^2y^2 - * where d = -121665/121666. - * - * Representations: - * ge_p2 (projective): (X:Y:Z) satisfying x=X/Z, y=Y/Z - * ge_p3 (extended): (X:Y:Z:T) satisfying x=X/Z, y=Y/Z, XY=ZT - * ge_p1p1 (completed): ((X:Z),(Y:T)) satisfying x=X/Z, y=Y/T - * ge_precomp (Duif): (y+x,y-x,2dxy) */ - -typedef struct { - fe X; - fe Y; - fe Z; -} ge_p2; - -typedef struct { - fe X; - fe Y; - fe Z; - fe T; -} ge_p3; - -typedef struct { - fe X; - fe Y; - fe Z; - fe T; -} ge_p1p1; - -typedef struct { - fe yplusx; - fe yminusx; - fe xy2d; -} ge_precomp; - -typedef struct { - fe YplusX; - fe YminusX; - fe Z; - fe T2d; -} ge_cached; - -static void ge_tobytes(uint8_t *s, const ge_p2 *h) { +void x25519_ge_tobytes(uint8_t *s, const ge_p2 *h) { fe recip; fe x; fe y; @@ -1049,7 +982,7 @@ static const fe d = {-10913610, 13857413, -15372611, 6949391, 114729, static const fe sqrtm1 = {-32595792, -7943725, 9377950, 3500415, 12389472, -272473, -25146209, -2005654, 326686, 11406482}; -static int ge_frombytes_vartime(ge_p3 *h, const uint8_t *s) { +int x25519_ge_frombytes_vartime(ge_p3 *h, const uint8_t *s) { fe u; fe v; fe v3; @@ -1105,6 +1038,13 @@ static void ge_p3_0(ge_p3 *h) { fe_0(h->T); } +static void ge_cached_0(ge_cached *h) { + fe_1(h->YplusX); + fe_1(h->YminusX); + fe_1(h->Z); + fe_0(h->T2d); +} + static void ge_precomp_0(ge_precomp *h) { fe_1(h->yplusx); fe_1(h->yminusx); @@ -1122,7 +1062,7 @@ static const fe d2 = {-21827239, -5839606, -30745221, 13898782, 229458, 15978800, -12551817, -6495438, 29715968, 9444199}; /* r = p */ -static void ge_p3_to_cached(ge_cached *r, const ge_p3 *p) { +void x25519_ge_p3_to_cached(ge_cached *r, const ge_p3 *p) { fe_add(r->YplusX, p->Y, p->X); fe_sub(r->YminusX, p->Y, p->X); fe_copy(r->Z, p->Z); @@ -1130,20 +1070,27 @@ static void ge_p3_to_cached(ge_cached *r, const ge_p3 *p) { } /* r = p */ -static void ge_p1p1_to_p2(ge_p2 *r, const ge_p1p1 *p) { +void x25519_ge_p1p1_to_p2(ge_p2 *r, const ge_p1p1 *p) { fe_mul(r->X, p->X, p->T); fe_mul(r->Y, p->Y, p->Z); fe_mul(r->Z, p->Z, p->T); } /* r = p */ -static void ge_p1p1_to_p3(ge_p3 *r, const ge_p1p1 *p) { +void x25519_ge_p1p1_to_p3(ge_p3 *r, const ge_p1p1 *p) { fe_mul(r->X, p->X, p->T); fe_mul(r->Y, p->Y, p->Z); fe_mul(r->Z, p->Z, p->T); fe_mul(r->T, p->X, p->Y); } +/* r = p */ +static void ge_p1p1_to_cached(ge_cached *r, const ge_p1p1 *p) { + ge_p3 t; + x25519_ge_p1p1_to_p3(&t, p); + x25519_ge_p3_to_cached(r, &t); +} + /* r = 2 * p */ static void ge_p2_dbl(ge_p1p1 *r, const ge_p2 *p) { fe t0; @@ -1199,7 +1146,7 @@ static void ge_msub(ge_p1p1 *r, const ge_p3 *p, const ge_precomp *q) { } /* r = p + q */ -static void ge_add(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q) { +void x25519_ge_add(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q) { fe t0; fe_add(r->X, p->Y, p->X); @@ -1216,7 +1163,7 @@ static void ge_add(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q) { } /* r = p - q */ -static void ge_sub(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q) { +void x25519_ge_sub(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q) { fe t0; fe_add(r->X, p->Y, p->X); @@ -1242,12 +1189,64 @@ static uint8_t equal(signed char b, signed char c) { return y; } -static void cmov(ge_precomp *t, ge_precomp *u, uint8_t b) { +static void cmov(ge_precomp *t, const ge_precomp *u, uint8_t b) { fe_cmov(t->yplusx, u->yplusx, b); fe_cmov(t->yminusx, u->yminusx, b); fe_cmov(t->xy2d, u->xy2d, b); } +void x25519_ge_scalarmult_small_precomp( + ge_p3 *h, const uint8_t a[32], const uint8_t precomp_table[15 * 2 * 32]) { + /* precomp_table is first expanded into matching |ge_precomp| + * elements. */ + ge_precomp multiples[15]; + + unsigned i; + for (i = 0; i < 15; i++) { + const uint8_t *bytes = &precomp_table[i*(2 * 32)]; + fe x, y; + fe_frombytes(x, bytes); + fe_frombytes(y, bytes + 32); + + ge_precomp *out = &multiples[i]; + fe_add(out->yplusx, y, x); + fe_sub(out->yminusx, y, x); + fe_mul(out->xy2d, x, y); + fe_mul(out->xy2d, out->xy2d, d2); + } + + /* See the comment above |k25519SmallPrecomp| about the structure of the + * precomputed elements. This loop does 64 additions and 64 doublings to + * calculate the result. */ + ge_p3_0(h); + + for (i = 63; i < 64; i--) { + unsigned j; + signed char index = 0; + + for (j = 0; j < 4; j++) { + const uint8_t bit = 1 & (a[(8 * j) + (i / 8)] >> (i & 7)); + index |= (bit << j); + } + + ge_precomp e; + ge_precomp_0(&e); + + for (j = 1; j < 16; j++) { + cmov(&e, &multiples[j-1], equal(index, j)); + } + + ge_cached cached; + ge_p1p1 r; + x25519_ge_p3_to_cached(&cached, h); + x25519_ge_add(&r, h, &cached); + x25519_ge_p1p1_to_p3(h, &r); + + ge_madd(&r, h, &e); + x25519_ge_p1p1_to_p3(h, &r); + } +} + #if defined(OPENSSL_SMALL) /* This block of code replaces the standard base-point table with a much smaller @@ -1341,61 +1340,14 @@ static const uint8_t k25519SmallPrecomp[15 * 2 * 32] = { 0x45, 0xc9, 0x8b, 0x17, 0x79, 0xe7, 0xc7, 0x90, 0x99, 0x3a, 0x18, 0x25, }; -static void ge_scalarmult_base(ge_p3 *h, const uint8_t a[32]) { - /* k25519SmallPrecomp is first expanded into matching |ge_precomp| - * elements. */ - ge_precomp multiples[15]; - - unsigned i; - for (i = 0; i < 15; i++) { - const uint8_t *bytes = &k25519SmallPrecomp[i*(2 * 32)]; - fe x, y; - fe_frombytes(x, bytes); - fe_frombytes(y, bytes + 32); - - ge_precomp *out = &multiples[i]; - fe_add(out->yplusx, y, x); - fe_sub(out->yminusx, y, x); - fe_mul(out->xy2d, x, y); - fe_mul(out->xy2d, out->xy2d, d2); - } - - /* See the comment above |k25519SmallPrecomp| about the structure of the - * precomputed elements. This loop does 64 additions and 64 doublings to - * calculate the result. */ - ge_p3_0(h); - - for (i = 63; i < 64; i--) { - unsigned j; - signed char index = 0; - - for (j = 0; j < 4; j++) { - const uint8_t bit = 1 & (a[(8 * j) + (i / 8)] >> (i & 7)); - index |= (bit << j); - } - - ge_precomp e; - ge_precomp_0(&e); - - for (j = 1; j < 16; j++) { - cmov(&e, &multiples[j-1], equal(index, j)); - } - - ge_cached cached; - ge_p1p1 r; - ge_p3_to_cached(&cached, h); - ge_add(&r, h, &cached); - ge_p1p1_to_p3(h, &r); - - ge_madd(&r, h, &e); - ge_p1p1_to_p3(h, &r); - } +void x25519_ge_scalarmult_base(ge_p3 *h, const uint8_t a[32]) { + x25519_ge_scalarmult_small_precomp(h, a, k25519SmallPrecomp); } #else /* k25519Precomp[i][j] = (j+1)*256^i*B */ -static ge_precomp k25519Precomp[32][8] = { +static const ge_precomp k25519Precomp[32][8] = { { { {25967493, -14356035, 29566456, 3660896, -12694345, 4014787, @@ -3519,7 +3471,7 @@ static uint8_t negative(signed char b) { static void table_select(ge_precomp *t, int pos, signed char b) { ge_precomp minust; uint8_t bnegative = negative(b); - uint8_t babs = b - (((-bnegative) & b) << 1); + uint8_t babs = b - ((uint8_t)((-bnegative) & b) << 1); ge_precomp_0(t); cmov(t, &k25519Precomp[pos][0], equal(babs, 1)); @@ -3542,7 +3494,7 @@ static void table_select(ge_precomp *t, int pos, signed char b) { * * Preconditions: * a[31] <= 127 */ -static void ge_scalarmult_base(ge_p3 *h, const uint8_t *a) { +void x25519_ge_scalarmult_base(ge_p3 *h, const uint8_t *a) { signed char e[64]; signed char carry; ge_p1p1 r; @@ -3571,27 +3523,88 @@ static void ge_scalarmult_base(ge_p3 *h, const uint8_t *a) { for (i = 1; i < 64; i += 2) { table_select(&t, i / 2, e[i]); ge_madd(&r, h, &t); - ge_p1p1_to_p3(h, &r); + x25519_ge_p1p1_to_p3(h, &r); } ge_p3_dbl(&r, h); - ge_p1p1_to_p2(&s, &r); + x25519_ge_p1p1_to_p2(&s, &r); ge_p2_dbl(&r, &s); - ge_p1p1_to_p2(&s, &r); + x25519_ge_p1p1_to_p2(&s, &r); ge_p2_dbl(&r, &s); - ge_p1p1_to_p2(&s, &r); + x25519_ge_p1p1_to_p2(&s, &r); ge_p2_dbl(&r, &s); - ge_p1p1_to_p3(h, &r); + x25519_ge_p1p1_to_p3(h, &r); for (i = 0; i < 64; i += 2) { table_select(&t, i / 2, e[i]); ge_madd(&r, h, &t); - ge_p1p1_to_p3(h, &r); + x25519_ge_p1p1_to_p3(h, &r); } } #endif +static void cmov_cached(ge_cached *t, ge_cached *u, uint8_t b) { + fe_cmov(t->YplusX, u->YplusX, b); + fe_cmov(t->YminusX, u->YminusX, b); + fe_cmov(t->Z, u->Z, b); + fe_cmov(t->T2d, u->T2d, b); +} + +/* r = scalar * A. + * where a = a[0]+256*a[1]+...+256^31 a[31]. */ +void x25519_ge_scalarmult(ge_p2 *r, const uint8_t *scalar, const ge_p3 *A) { + ge_p2 Ai_p2[8]; + ge_cached Ai[16]; + ge_p1p1 t; + + ge_cached_0(&Ai[0]); + x25519_ge_p3_to_cached(&Ai[1], A); + ge_p3_to_p2(&Ai_p2[1], A); + + unsigned i; + for (i = 2; i < 16; i += 2) { + ge_p2_dbl(&t, &Ai_p2[i / 2]); + ge_p1p1_to_cached(&Ai[i], &t); + if (i < 8) { + x25519_ge_p1p1_to_p2(&Ai_p2[i], &t); + } + x25519_ge_add(&t, A, &Ai[i]); + ge_p1p1_to_cached(&Ai[i + 1], &t); + if (i < 7) { + x25519_ge_p1p1_to_p2(&Ai_p2[i + 1], &t); + } + } + + ge_p2_0(r); + ge_p3 u; + + for (i = 0; i < 256; i += 4) { + ge_p2_dbl(&t, r); + x25519_ge_p1p1_to_p2(r, &t); + ge_p2_dbl(&t, r); + x25519_ge_p1p1_to_p2(r, &t); + ge_p2_dbl(&t, r); + x25519_ge_p1p1_to_p2(r, &t); + ge_p2_dbl(&t, r); + x25519_ge_p1p1_to_p3(&u, &t); + + uint8_t index = scalar[31 - i/8]; + index >>= 4 - (i & 4); + index &= 0xf; + + unsigned j; + ge_cached selected; + ge_cached_0(&selected); + for (j = 0; j < 16; j++) { + cmov_cached(&selected, &Ai[j], equal(j, index)); + } + + x25519_ge_add(&t, &u, &selected); + x25519_ge_p1p1_to_p2(r, &t); + } +} + static void slide(signed char *r, const uint8_t *a) { int i; int b; @@ -3626,7 +3639,7 @@ static void slide(signed char *r, const uint8_t *a) { } } -static ge_precomp Bi[8] = { +static const ge_precomp Bi[8] = { { {25967493, -14356035, 29566456, 3660896, -12694345, 4014787, 27544626, -11754271, -6079156, 2047605}, @@ -3697,8 +3710,8 @@ static ge_precomp Bi[8] = { * where a = a[0]+256*a[1]+...+256^31 a[31]. * and b = b[0]+256*b[1]+...+256^31 b[31]. * B is the Ed25519 base point (x,4/5) with x positive. */ -void ge_double_scalarmult_vartime(ge_p2 *r, const uint8_t *a, - const ge_p3 *A, const uint8_t *b) { +static void ge_double_scalarmult_vartime(ge_p2 *r, const uint8_t *a, + const ge_p3 *A, const uint8_t *b) { signed char aslide[256]; signed char bslide[256]; ge_cached Ai[8]; /* A,3A,5A,7A,9A,11A,13A,15A */ @@ -3710,30 +3723,30 @@ void ge_double_scalarmult_vartime(ge_p2 *r, const uint8_t *a, slide(aslide, a); slide(bslide, b); - ge_p3_to_cached(&Ai[0], A); + x25519_ge_p3_to_cached(&Ai[0], A); ge_p3_dbl(&t, A); - ge_p1p1_to_p3(&A2, &t); - ge_add(&t, &A2, &Ai[0]); - ge_p1p1_to_p3(&u, &t); - ge_p3_to_cached(&Ai[1], &u); - ge_add(&t, &A2, &Ai[1]); - ge_p1p1_to_p3(&u, &t); - ge_p3_to_cached(&Ai[2], &u); - ge_add(&t, &A2, &Ai[2]); - ge_p1p1_to_p3(&u, &t); - ge_p3_to_cached(&Ai[3], &u); - ge_add(&t, &A2, &Ai[3]); - ge_p1p1_to_p3(&u, &t); - ge_p3_to_cached(&Ai[4], &u); - ge_add(&t, &A2, &Ai[4]); - ge_p1p1_to_p3(&u, &t); - ge_p3_to_cached(&Ai[5], &u); - ge_add(&t, &A2, &Ai[5]); - ge_p1p1_to_p3(&u, &t); - ge_p3_to_cached(&Ai[6], &u); - ge_add(&t, &A2, &Ai[6]); - ge_p1p1_to_p3(&u, &t); - ge_p3_to_cached(&Ai[7], &u); + x25519_ge_p1p1_to_p3(&A2, &t); + x25519_ge_add(&t, &A2, &Ai[0]); + x25519_ge_p1p1_to_p3(&u, &t); + x25519_ge_p3_to_cached(&Ai[1], &u); + x25519_ge_add(&t, &A2, &Ai[1]); + x25519_ge_p1p1_to_p3(&u, &t); + x25519_ge_p3_to_cached(&Ai[2], &u); + x25519_ge_add(&t, &A2, &Ai[2]); + x25519_ge_p1p1_to_p3(&u, &t); + x25519_ge_p3_to_cached(&Ai[3], &u); + x25519_ge_add(&t, &A2, &Ai[3]); + x25519_ge_p1p1_to_p3(&u, &t); + x25519_ge_p3_to_cached(&Ai[4], &u); + x25519_ge_add(&t, &A2, &Ai[4]); + x25519_ge_p1p1_to_p3(&u, &t); + x25519_ge_p3_to_cached(&Ai[5], &u); + x25519_ge_add(&t, &A2, &Ai[5]); + x25519_ge_p1p1_to_p3(&u, &t); + x25519_ge_p3_to_cached(&Ai[6], &u); + x25519_ge_add(&t, &A2, &Ai[6]); + x25519_ge_p1p1_to_p3(&u, &t); + x25519_ge_p3_to_cached(&Ai[7], &u); ge_p2_0(r); @@ -3747,22 +3760,22 @@ void ge_double_scalarmult_vartime(ge_p2 *r, const uint8_t *a, ge_p2_dbl(&t, r); if (aslide[i] > 0) { - ge_p1p1_to_p3(&u, &t); - ge_add(&t, &u, &Ai[aslide[i] / 2]); + x25519_ge_p1p1_to_p3(&u, &t); + x25519_ge_add(&t, &u, &Ai[aslide[i] / 2]); } else if (aslide[i] < 0) { - ge_p1p1_to_p3(&u, &t); - ge_sub(&t, &u, &Ai[(-aslide[i]) / 2]); + x25519_ge_p1p1_to_p3(&u, &t); + x25519_ge_sub(&t, &u, &Ai[(-aslide[i]) / 2]); } if (bslide[i] > 0) { - ge_p1p1_to_p3(&u, &t); + x25519_ge_p1p1_to_p3(&u, &t); ge_madd(&t, &u, &Bi[bslide[i] / 2]); } else if (bslide[i] < 0) { - ge_p1p1_to_p3(&u, &t); + x25519_ge_p1p1_to_p3(&u, &t); ge_msub(&t, &u, &Bi[(-bslide[i]) / 2]); } - ge_p1p1_to_p2(r, &t); + x25519_ge_p1p1_to_p2(r, &t); } } @@ -3776,7 +3789,7 @@ void ge_double_scalarmult_vartime(ge_p2 *r, const uint8_t *a, * s[0]+256*s[1]+...+256^31*s[31] = s mod l * where l = 2^252 + 27742317777372353535851937790883648493. * Overwrites s in place. */ -static void sc_reduce(uint8_t *s) { +void x25519_sc_reduce(uint8_t *s) { int64_t s0 = 2097151 & load_3(s); int64_t s1 = 2097151 & (load_4(s + 2) >> 5); int64_t s2 = 2097151 & (load_3(s + 5) >> 2); @@ -4601,20 +4614,7 @@ static void sc_muladd(uint8_t *s, const uint8_t *a, const uint8_t *b, void ED25519_keypair(uint8_t out_public_key[32], uint8_t out_private_key[64]) { uint8_t seed[32]; RAND_bytes(seed, 32); - - uint8_t az[SHA512_DIGEST_LENGTH]; - SHA512(seed, 32, az); - - az[0] &= 248; - az[31] &= 63; - az[31] |= 64; - - ge_p3 A; - ge_scalarmult_base(&A, az); - ge_p3_tobytes(out_public_key, &A); - - memcpy(out_private_key, seed, 32); - memmove(out_private_key + 32, out_public_key, 32); + ED25519_keypair_from_seed(out_public_key, out_private_key, seed); } int ED25519_sign(uint8_t *out_sig, const uint8_t *message, size_t message_len, @@ -4633,9 +4633,9 @@ int ED25519_sign(uint8_t *out_sig, const uint8_t *message, size_t message_len, uint8_t nonce[SHA512_DIGEST_LENGTH]; SHA512_Final(nonce, &hash_ctx); - sc_reduce(nonce); + x25519_sc_reduce(nonce); ge_p3 R; - ge_scalarmult_base(&R, nonce); + x25519_ge_scalarmult_base(&R, nonce); ge_p3_tobytes(out_sig, &R); SHA512_Init(&hash_ctx); @@ -4645,7 +4645,7 @@ int ED25519_sign(uint8_t *out_sig, const uint8_t *message, size_t message_len, uint8_t hram[SHA512_DIGEST_LENGTH]; SHA512_Final(hram, &hash_ctx); - sc_reduce(hram); + x25519_sc_reduce(hram); sc_muladd(out_sig + 32, hram, az, nonce); return 1; @@ -4655,7 +4655,7 @@ int ED25519_verify(const uint8_t *message, size_t message_len, const uint8_t signature[64], const uint8_t public_key[32]) { ge_p3 A; if ((signature[63] & 224) != 0 || - ge_frombytes_vartime(&A, public_key) != 0) { + x25519_ge_frombytes_vartime(&A, public_key) != 0) { return 0; } @@ -4663,11 +4663,11 @@ int ED25519_verify(const uint8_t *message, size_t message_len, fe_neg(A.T, A.T); uint8_t pkcopy[32]; - memcpy(pkcopy, public_key, 32); + OPENSSL_memcpy(pkcopy, public_key, 32); uint8_t rcopy[32]; - memcpy(rcopy, signature, 32); + OPENSSL_memcpy(rcopy, signature, 32); uint8_t scopy[32]; - memcpy(scopy, signature + 32, 32); + OPENSSL_memcpy(scopy, signature + 32, 32); SHA512_CTX hash_ctx; SHA512_Init(&hash_ctx); @@ -4677,17 +4677,35 @@ int ED25519_verify(const uint8_t *message, size_t message_len, uint8_t h[SHA512_DIGEST_LENGTH]; SHA512_Final(h, &hash_ctx); - sc_reduce(h); + x25519_sc_reduce(h); ge_p2 R; ge_double_scalarmult_vartime(&R, h, &A, scopy); uint8_t rcheck[32]; - ge_tobytes(rcheck, &R); + x25519_ge_tobytes(rcheck, &R); return CRYPTO_memcmp(rcheck, rcopy, sizeof(rcheck)) == 0; } +void ED25519_keypair_from_seed(uint8_t out_public_key[32], + uint8_t out_private_key[64], + const uint8_t seed[32]) { + uint8_t az[SHA512_DIGEST_LENGTH]; + SHA512(seed, 32, az); + + az[0] &= 248; + az[31] &= 63; + az[31] |= 64; + + ge_p3 A; + x25519_ge_scalarmult_base(&A, az); + ge_p3_tobytes(out_public_key, &A); + + OPENSSL_memcpy(out_private_key, seed, 32); + OPENSSL_memcpy(out_private_key + 32, out_public_key, 32); +} + #if defined(BORINGSSL_X25519_X86_64) @@ -4753,17 +4771,17 @@ static void fe_mul121666(fe h, fe f) { int64_t carry8; int64_t carry9; - carry9 = (h9 + (int64_t) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25; - carry1 = (h1 + (int64_t) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25; - carry3 = (h3 + (int64_t) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25; - carry5 = (h5 + (int64_t) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25; - carry7 = (h7 + (int64_t) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25; + carry9 = h9 + (1 << 24); h0 += (carry9 >> 25) * 19; h9 -= carry9 & kTop39Bits; + carry1 = h1 + (1 << 24); h2 += carry1 >> 25; h1 -= carry1 & kTop39Bits; + carry3 = h3 + (1 << 24); h4 += carry3 >> 25; h3 -= carry3 & kTop39Bits; + carry5 = h5 + (1 << 24); h6 += carry5 >> 25; h5 -= carry5 & kTop39Bits; + carry7 = h7 + (1 << 24); h8 += carry7 >> 25; h7 -= carry7 & kTop39Bits; - carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26; - carry2 = (h2 + (int64_t) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26; - carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26; - carry6 = (h6 + (int64_t) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26; - carry8 = (h8 + (int64_t) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26; + carry0 = h0 + (1 << 25); h1 += carry0 >> 26; h0 -= carry0 & kTop38Bits; + carry2 = h2 + (1 << 25); h3 += carry2 >> 26; h2 -= carry2 & kTop38Bits; + carry4 = h4 + (1 << 25); h5 += carry4 >> 26; h4 -= carry4 & kTop38Bits; + carry6 = h6 + (1 << 25); h7 += carry6 >> 26; h6 -= carry6 & kTop38Bits; + carry8 = h8 + (1 << 25); h9 += carry8 >> 26; h8 -= carry8 & kTop38Bits; h[0] = h0; h[1] = h1; @@ -4783,7 +4801,7 @@ static void x25519_scalar_mult_generic(uint8_t out[32], fe x1, x2, z2, x3, z3, tmp0, tmp1; uint8_t e[32]; - memcpy(e, scalar, 32); + OPENSSL_memcpy(e, scalar, 32); e[0] &= 248; e[31] &= 127; e[31] |= 64; @@ -4845,6 +4863,24 @@ static void x25519_scalar_mult(uint8_t out[32], const uint8_t scalar[32], void X25519_keypair(uint8_t out_public_value[32], uint8_t out_private_key[32]) { RAND_bytes(out_private_key, 32); + + /* All X25519 implementations should decode scalars correctly (see + * https://tools.ietf.org/html/rfc7748#section-5). However, if an + * implementation doesn't then it might interoperate with random keys a + * fraction of the time because they'll, randomly, happen to be correctly + * formed. + * + * Thus we do the opposite of the masking here to make sure that our private + * keys are never correctly masked and so, hopefully, any incorrect + * implementations are deterministically broken. + * + * This does not affect security because, although we're throwing away + * entropy, a valid implementation of scalarmult should throw away the exact + * same bits anyway. */ + out_private_key[0] |= 7; + out_private_key[31] &= 63; + out_private_key[31] |= 128; + X25519_public_from_private(out_public_value, out_private_key); } @@ -4881,13 +4917,13 @@ void X25519_public_from_private(uint8_t out_public_value[32], #endif uint8_t e[32]; - memcpy(e, private_key, 32); + OPENSSL_memcpy(e, private_key, 32); e[0] &= 248; e[31] &= 127; e[31] |= 64; ge_p3 A; - ge_scalarmult_base(&A, e); + x25519_ge_scalarmult_base(&A, e); /* We only need the u-coordinate of the curve25519 point. The map is * u=(y+1)/(1-y). Since y=Y/Z, this gives u=(Z+Y)/(Z-Y). */ diff --git a/Sources/BoringSSL/crypto/curve25519/internal.h b/Sources/BoringSSL/crypto/curve25519/internal.h index 27994b7b4..ea206a3e9 100644 --- a/Sources/BoringSSL/crypto/curve25519/internal.h +++ b/Sources/BoringSSL/crypto/curve25519/internal.h @@ -37,6 +37,70 @@ void x25519_NEON(uint8_t out[32], const uint8_t scalar[32], const uint8_t point[32]); #endif +/* fe means field element. Here the field is \Z/(2^255-19). An element t, + * entries t[0]...t[9], represents the integer t[0]+2^26 t[1]+2^51 t[2]+2^77 + * t[3]+2^102 t[4]+...+2^230 t[9]. Bounds on each t[i] vary depending on + * context. */ +typedef int32_t fe[10]; + +/* ge means group element. + + * Here the group is the set of pairs (x,y) of field elements (see fe.h) + * satisfying -x^2 + y^2 = 1 + d x^2y^2 + * where d = -121665/121666. + * + * Representations: + * ge_p2 (projective): (X:Y:Z) satisfying x=X/Z, y=Y/Z + * ge_p3 (extended): (X:Y:Z:T) satisfying x=X/Z, y=Y/Z, XY=ZT + * ge_p1p1 (completed): ((X:Z),(Y:T)) satisfying x=X/Z, y=Y/T + * ge_precomp (Duif): (y+x,y-x,2dxy) */ + +typedef struct { + fe X; + fe Y; + fe Z; +} ge_p2; + +typedef struct { + fe X; + fe Y; + fe Z; + fe T; +} ge_p3; + +typedef struct { + fe X; + fe Y; + fe Z; + fe T; +} ge_p1p1; + +typedef struct { + fe yplusx; + fe yminusx; + fe xy2d; +} ge_precomp; + +typedef struct { + fe YplusX; + fe YminusX; + fe Z; + fe T2d; +} ge_cached; + +void x25519_ge_tobytes(uint8_t *s, const ge_p2 *h); +int x25519_ge_frombytes_vartime(ge_p3 *h, const uint8_t *s); +void x25519_ge_p3_to_cached(ge_cached *r, const ge_p3 *p); +void x25519_ge_p1p1_to_p2(ge_p2 *r, const ge_p1p1 *p); +void x25519_ge_p1p1_to_p3(ge_p3 *r, const ge_p1p1 *p); +void x25519_ge_add(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q); +void x25519_ge_sub(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q); +void x25519_ge_scalarmult_small_precomp( + ge_p3 *h, const uint8_t a[32], const uint8_t precomp_table[15 * 2 * 32]); +void x25519_ge_scalarmult_base(ge_p3 *h, const uint8_t a[32]); +void x25519_ge_scalarmult(ge_p2 *r, const uint8_t *scalar, const ge_p3 *A); +void x25519_sc_reduce(uint8_t *s); + #if defined(__cplusplus) } /* extern C */ diff --git a/Sources/BoringSSL/crypto/curve25519/spake25519.c b/Sources/BoringSSL/crypto/curve25519/spake25519.c new file mode 100644 index 000000000..5b794b377 --- /dev/null +++ b/Sources/BoringSSL/crypto/curve25519/spake25519.c @@ -0,0 +1,465 @@ +/* Copyright (c) 2016, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include + +#include + +#include +#include +#include +#include + +#include "internal.h" +#include "../internal.h" + + +/* The following precomputation tables are for the following + * points used in the SPAKE2 protocol. + * + * N: + * x: 49918732221787544735331783592030787422991506689877079631459872391322455579424 + * y: 54629554431565467720832445949441049581317094546788069926228343916274969994000 + * encoded: 10e3df0ae37d8e7a99b5fe74b44672103dbddcbd06af680d71329a11693bc778 + * + * M: + * x: 31406539342727633121250288103050113562375374900226415211311216773867585644232 + * y: 21177308356423958466833845032658859666296341766942662650232962324899758529114 + * encoded: 5ada7e4bf6ddd9adb6626d32131c6b5c51a1e347a3478f53cfcf441b88eed12e + * + * These points and their precomputation tables are generated with the + * following Python code. For a description of the precomputation table, + * see curve25519.c in this directory. + * + * Exact copies of the source code are kept in bug 27296743. + * + * import hashlib + * import ed25519 as E # http://ed25519.cr.yp.to/python/ed25519.py + * + * SEED_N = 'edwards25519 point generation seed (N)' + * SEED_M = 'edwards25519 point generation seed (M)' + * + * def genpoint(seed): + * v = hashlib.sha256(seed).digest() + * it = 1 + * while True: + * try: + * x,y = E.decodepoint(v) + * except Exception, e: + * print e + * it += 1 + * v = hashlib.sha256(v).digest() + * continue + * print "Found in %d iterations:" % it + * print " x = %d" % x + * print " y = %d" % y + * print " Encoded (hex)" + * print E.encodepoint((x,y)).encode('hex') + * return (x,y) + * + * def gentable(P): + * t = [] + * for i in range(1,16): + * k = (i >> 3 & 1) * (1 << 192) + \ + * (i >> 2 & 1) * (1 << 128) + \ + * (i >> 1 & 1) * (1 << 64) + \ + * (i & 1) + * t.append(E.scalarmult(P, k)) + * return ''.join(E.encodeint(x) + E.encodeint(y) for (x,y) in t) + * + * def printtable(table, name): + * print "static const uint8_t %s[15 * 2 * 32] = {" % name, + * for i in range(15 * 2 * 32): + * if i % 12 == 0: + * print "\n ", + * print " 0x%02x," % ord(table[i]), + * print "\n};" + * + * if __name__ == "__main__": + * print "Searching for N" + * N = genpoint(SEED_N) + * print "Generating precomputation table for N" + * Ntable = gentable(N) + * printtable(Ntable, "kSpakeNSmallPrecomp") + * + * print "Searching for M" + * M = genpoint(SEED_M) + * print "Generating precomputation table for M" + * Mtable = gentable(M) + * printtable(Mtable, "kSpakeMSmallPrecomp") + */ +static const uint8_t kSpakeNSmallPrecomp[15 * 2 * 32] = { + 0x20, 0x1b, 0xc5, 0xb3, 0x43, 0x17, 0x71, 0x10, 0x44, 0x1e, 0x73, 0xb3, + 0xae, 0x3f, 0xbf, 0x9f, 0xf5, 0x44, 0xc8, 0x13, 0x8f, 0xd1, 0x01, 0xc2, + 0x8a, 0x1a, 0x6d, 0xea, 0x4d, 0x00, 0x5d, 0x6e, 0x10, 0xe3, 0xdf, 0x0a, + 0xe3, 0x7d, 0x8e, 0x7a, 0x99, 0xb5, 0xfe, 0x74, 0xb4, 0x46, 0x72, 0x10, + 0x3d, 0xbd, 0xdc, 0xbd, 0x06, 0xaf, 0x68, 0x0d, 0x71, 0x32, 0x9a, 0x11, + 0x69, 0x3b, 0xc7, 0x78, 0x93, 0xf1, 0x57, 0x97, 0x6e, 0xf0, 0x6e, 0x45, + 0x37, 0x4a, 0xf4, 0x0b, 0x18, 0x51, 0xf5, 0x4f, 0x67, 0x3c, 0xdc, 0xec, + 0x84, 0xed, 0xd0, 0xeb, 0xca, 0xfb, 0xdb, 0xff, 0x7f, 0xeb, 0xa8, 0x23, + 0x68, 0x87, 0x13, 0x64, 0x6a, 0x10, 0xf7, 0x45, 0xe0, 0x0f, 0x32, 0x21, + 0x59, 0x7c, 0x0e, 0x50, 0xad, 0x56, 0xd7, 0x12, 0x69, 0x7b, 0x58, 0xf8, + 0xb9, 0x3b, 0xa5, 0xbb, 0x4d, 0x1b, 0x87, 0x1c, 0x46, 0xa7, 0x17, 0x9d, + 0x6d, 0x84, 0x45, 0xbe, 0x7f, 0x95, 0xd2, 0x34, 0xcd, 0x89, 0x95, 0xc0, + 0xf0, 0xd3, 0xdf, 0x6e, 0x10, 0x4a, 0xe3, 0x7b, 0xce, 0x7f, 0x40, 0x27, + 0xc7, 0x2b, 0xab, 0x66, 0x03, 0x59, 0xb4, 0x7b, 0xc7, 0xc7, 0xf0, 0x39, + 0x9a, 0x33, 0x35, 0xbf, 0xcc, 0x2f, 0xf3, 0x2e, 0x68, 0x9d, 0x53, 0x5c, + 0x88, 0x52, 0xe3, 0x77, 0x90, 0xa1, 0x27, 0x85, 0xc5, 0x74, 0x7f, 0x23, + 0x0e, 0x93, 0x01, 0x3e, 0xe7, 0x2e, 0x2e, 0x95, 0xf3, 0x0d, 0xc2, 0x25, + 0x25, 0x39, 0x39, 0x3d, 0x6e, 0x8e, 0x89, 0xbd, 0xe8, 0xbb, 0x67, 0x5e, + 0x8c, 0x66, 0x8b, 0x63, 0x28, 0x1e, 0x4e, 0x74, 0x85, 0xa8, 0xaf, 0x0f, + 0x12, 0x5d, 0xb6, 0x8a, 0x83, 0x1a, 0x77, 0x76, 0x5e, 0x62, 0x8a, 0xa7, + 0x3c, 0xb8, 0x05, 0x57, 0x2b, 0xaf, 0x36, 0x2e, 0x10, 0x90, 0xb2, 0x39, + 0xb4, 0x3e, 0x75, 0x6d, 0x3a, 0xa8, 0x31, 0x35, 0xc2, 0x1e, 0x8f, 0xc2, + 0x79, 0x89, 0x35, 0x16, 0x26, 0xd1, 0xc7, 0x0b, 0x04, 0x1f, 0x1d, 0xf9, + 0x9c, 0x05, 0xa6, 0x6b, 0xb5, 0x19, 0x5a, 0x24, 0x6d, 0x91, 0xc5, 0x31, + 0xfd, 0xc5, 0xfa, 0xe7, 0xa6, 0xcb, 0x0e, 0x4b, 0x18, 0x0d, 0x94, 0xc7, + 0xee, 0x1d, 0x46, 0x1f, 0x92, 0xb1, 0xb2, 0x4a, 0x2b, 0x43, 0x37, 0xfe, + 0xc2, 0x15, 0x11, 0x89, 0xef, 0x59, 0x73, 0x3c, 0x06, 0x76, 0x78, 0xcb, + 0xa6, 0x0d, 0x79, 0x5f, 0x28, 0x0b, 0x5b, 0x8c, 0x9e, 0xe4, 0xaa, 0x51, + 0x9a, 0x42, 0x6f, 0x11, 0x50, 0x3d, 0x01, 0xd6, 0x21, 0xc0, 0x99, 0x5e, + 0x1a, 0xe8, 0x81, 0x25, 0x80, 0xeb, 0xed, 0x5d, 0x37, 0x47, 0x30, 0x70, + 0xa0, 0x4e, 0x0b, 0x43, 0x17, 0xbe, 0xb6, 0x47, 0xe7, 0x2a, 0x62, 0x9d, + 0x5d, 0xa6, 0xc5, 0x33, 0x62, 0x9d, 0x56, 0x24, 0x9d, 0x1d, 0xb2, 0x13, + 0xbc, 0x17, 0x66, 0x43, 0xd1, 0x68, 0xd5, 0x3b, 0x17, 0x69, 0x17, 0xa6, + 0x06, 0x9e, 0x12, 0xb8, 0x7c, 0xd5, 0xaf, 0x3e, 0x21, 0x1b, 0x31, 0xeb, + 0x0b, 0xa4, 0x98, 0x1c, 0xf2, 0x6a, 0x5e, 0x7c, 0x9b, 0x45, 0x8f, 0xb2, + 0x12, 0x06, 0xd5, 0x8c, 0x1d, 0xb2, 0xa7, 0x57, 0x5f, 0x2f, 0x4f, 0xdb, + 0x52, 0x99, 0x7c, 0x58, 0x01, 0x5f, 0xf2, 0xa5, 0xf6, 0x51, 0x86, 0x21, + 0x2f, 0x5b, 0x8d, 0x6a, 0xae, 0x83, 0x34, 0x6d, 0x58, 0x4b, 0xef, 0xfe, + 0xbf, 0x73, 0x5d, 0xdb, 0xc4, 0x97, 0x2a, 0x85, 0xf3, 0x6c, 0x46, 0x42, + 0xb3, 0x90, 0xc1, 0x57, 0x97, 0x50, 0x35, 0xb1, 0x9d, 0xb7, 0xc7, 0x3c, + 0x85, 0x6d, 0x6c, 0xfd, 0xce, 0xb0, 0xc9, 0xa2, 0x77, 0xee, 0xc3, 0x6b, + 0x0c, 0x37, 0xfa, 0x30, 0x91, 0xd1, 0x2c, 0xb8, 0x5e, 0x7f, 0x81, 0x5f, + 0x87, 0xfd, 0x18, 0x02, 0x5a, 0x30, 0x4e, 0x62, 0xbc, 0x65, 0xc6, 0xce, + 0x1a, 0xcf, 0x2b, 0xaa, 0x56, 0x3e, 0x4d, 0xcf, 0xba, 0x62, 0x5f, 0x9a, + 0xd0, 0x72, 0xff, 0xef, 0x28, 0xbd, 0xbe, 0xd8, 0x57, 0x3d, 0xf5, 0x57, + 0x7d, 0xe9, 0x71, 0x31, 0xec, 0x98, 0x90, 0x94, 0xd9, 0x54, 0xbf, 0x84, + 0x0b, 0xe3, 0x06, 0x47, 0x19, 0x9a, 0x13, 0x1d, 0xef, 0x9d, 0x13, 0xf3, + 0xdb, 0xc3, 0x5c, 0x72, 0x9e, 0xed, 0x24, 0xaa, 0x64, 0xed, 0xe7, 0x0d, + 0xa0, 0x7c, 0x73, 0xba, 0x9b, 0x86, 0xa7, 0x3b, 0x55, 0xab, 0x58, 0x30, + 0xf1, 0x15, 0x81, 0x83, 0x2f, 0xf9, 0x62, 0x84, 0x98, 0x66, 0xf6, 0x55, + 0x21, 0xd8, 0xf2, 0x25, 0x64, 0x71, 0x4b, 0x12, 0x76, 0x59, 0xc5, 0xaa, + 0x93, 0x67, 0xc3, 0x86, 0x25, 0xab, 0x4e, 0x4b, 0xf6, 0xd8, 0x3f, 0x44, + 0x2e, 0x11, 0xe0, 0xbd, 0x6a, 0xf2, 0x5d, 0xf5, 0xf9, 0x53, 0xea, 0xa4, + 0xc8, 0xd9, 0x50, 0x33, 0x81, 0xd9, 0xa8, 0x2d, 0x91, 0x7d, 0x13, 0x2a, + 0x11, 0xcf, 0xde, 0x3f, 0x0a, 0xd2, 0xbc, 0x33, 0xb2, 0x62, 0x53, 0xea, + 0x77, 0x88, 0x43, 0x66, 0x27, 0x43, 0x85, 0xe9, 0x5f, 0x55, 0xf5, 0x2a, + 0x8a, 0xac, 0xdf, 0xff, 0x9b, 0x4c, 0x96, 0x9c, 0xa5, 0x7a, 0xce, 0xd5, + 0x79, 0x18, 0xf1, 0x0b, 0x58, 0x95, 0x7a, 0xe7, 0xd3, 0x74, 0x65, 0x0b, + 0xa4, 0x64, 0x30, 0xe8, 0x5c, 0xfc, 0x55, 0x56, 0xee, 0x14, 0x14, 0xd3, + 0x45, 0x3b, 0xf8, 0xde, 0x05, 0x3e, 0xb9, 0x3c, 0xd7, 0x6a, 0x52, 0x72, + 0x5b, 0x39, 0x09, 0xbe, 0x82, 0x23, 0x10, 0x4a, 0xb7, 0xc3, 0xdc, 0x4c, + 0x5d, 0xc9, 0xf1, 0x14, 0x83, 0xf9, 0x0b, 0x9b, 0xe9, 0x23, 0x84, 0x6a, + 0xc4, 0x08, 0x3d, 0xda, 0x3d, 0x12, 0x95, 0x87, 0x18, 0xa4, 0x7d, 0x3f, + 0x23, 0xde, 0xd4, 0x1e, 0xa8, 0x47, 0xc3, 0x71, 0xdb, 0xf5, 0x03, 0x6c, + 0x57, 0xe7, 0xa4, 0x43, 0x82, 0x33, 0x7b, 0x62, 0x46, 0x7d, 0xf7, 0x10, + 0x69, 0x18, 0x38, 0x27, 0x9a, 0x6f, 0x38, 0xac, 0xfa, 0x92, 0xc5, 0xae, + 0x66, 0xa6, 0x73, 0x95, 0x15, 0x0e, 0x4c, 0x04, 0xb6, 0xfc, 0xf5, 0xc7, + 0x21, 0x3a, 0x99, 0xdb, 0x0e, 0x36, 0xf0, 0x56, 0xbc, 0x75, 0xf9, 0x87, + 0x9b, 0x11, 0x18, 0x92, 0x64, 0x1a, 0xe7, 0xc7, 0xab, 0x5a, 0xc7, 0x26, + 0x7f, 0x13, 0x98, 0x42, 0x52, 0x43, 0xdb, 0xc8, 0x6d, 0x0b, 0xb7, 0x31, + 0x93, 0x24, 0xd6, 0xe8, 0x24, 0x1f, 0x6f, 0x21, 0xa7, 0x8c, 0xeb, 0xdb, + 0x83, 0xb8, 0x89, 0xe3, 0xc1, 0xd7, 0x69, 0x3b, 0x02, 0x6b, 0x54, 0x0f, + 0x84, 0x2f, 0xb5, 0x5c, 0x17, 0x77, 0xbe, 0xe5, 0x61, 0x0d, 0xc5, 0xdf, + 0x3b, 0xcf, 0x3e, 0x93, 0x4f, 0xf5, 0x89, 0xb9, 0x5a, 0xc5, 0x29, 0x31, + 0xc0, 0xc2, 0xff, 0xe5, 0x3f, 0xa6, 0xac, 0x03, 0xca, 0xf5, 0xff, 0xe0, + 0x36, 0xce, 0xf3, 0xe2, 0xb7, 0x9c, 0x02, 0xe9, 0x9e, 0xd2, 0xbc, 0x87, + 0x2f, 0x3d, 0x9a, 0x1d, 0x8f, 0xc5, 0x72, 0xb8, 0xa2, 0x01, 0xd4, 0x68, + 0xb1, 0x84, 0x16, 0x10, 0xf6, 0xf3, 0x52, 0x25, 0xd9, 0xdc, 0x4c, 0xdd, + 0x0f, 0xd6, 0x4a, 0xcf, 0x60, 0x96, 0x7e, 0xcc, 0x42, 0x0f, 0x64, 0x9d, + 0x72, 0x46, 0x04, 0x07, 0xf2, 0x5b, 0xf4, 0x07, 0xd1, 0xf4, 0x59, 0x71, +}; + +static const uint8_t kSpakeMSmallPrecomp[15 * 2 * 32] = { + 0xc8, 0xa6, 0x63, 0xc5, 0x97, 0xf1, 0xee, 0x40, 0xab, 0x62, 0x42, 0xee, + 0x25, 0x6f, 0x32, 0x6c, 0x75, 0x2c, 0xa7, 0xd3, 0xbd, 0x32, 0x3b, 0x1e, + 0x11, 0x9c, 0xbd, 0x04, 0xa9, 0x78, 0x6f, 0x45, 0x5a, 0xda, 0x7e, 0x4b, + 0xf6, 0xdd, 0xd9, 0xad, 0xb6, 0x62, 0x6d, 0x32, 0x13, 0x1c, 0x6b, 0x5c, + 0x51, 0xa1, 0xe3, 0x47, 0xa3, 0x47, 0x8f, 0x53, 0xcf, 0xcf, 0x44, 0x1b, + 0x88, 0xee, 0xd1, 0x2e, 0x03, 0x89, 0xaf, 0xc0, 0x61, 0x2d, 0x9e, 0x35, + 0xeb, 0x0e, 0x03, 0xe0, 0xb7, 0xfb, 0xa5, 0xbc, 0x44, 0xbe, 0x0c, 0x89, + 0x0a, 0x0f, 0xd6, 0x59, 0x47, 0x9e, 0xe6, 0x3d, 0x36, 0x9d, 0xff, 0x44, + 0x5e, 0xac, 0xab, 0xe5, 0x3a, 0xd5, 0xb0, 0x35, 0x9f, 0x6d, 0x7f, 0xba, + 0xc0, 0x85, 0x0e, 0xf4, 0x70, 0x3f, 0x13, 0x90, 0x4c, 0x50, 0x1a, 0xee, + 0xc5, 0xeb, 0x69, 0xfe, 0x98, 0x42, 0x87, 0x1d, 0xce, 0x6c, 0x29, 0xaa, + 0x2b, 0x31, 0xc2, 0x38, 0x7b, 0x6b, 0xee, 0x88, 0x0b, 0xba, 0xce, 0xa8, + 0xca, 0x19, 0x60, 0x1b, 0x16, 0xf1, 0x25, 0x1e, 0xcf, 0x63, 0x66, 0x1e, + 0xbb, 0x63, 0xeb, 0x7d, 0xca, 0xd2, 0xb4, 0x23, 0x5a, 0x01, 0x6f, 0x05, + 0xd1, 0xdc, 0x41, 0x73, 0x75, 0xc0, 0xfd, 0x30, 0x91, 0x52, 0x68, 0x96, + 0x45, 0xb3, 0x66, 0x01, 0x3b, 0x53, 0x89, 0x3c, 0x69, 0xbc, 0x6c, 0x69, + 0xe3, 0x51, 0x8f, 0xe3, 0xd2, 0x84, 0xd5, 0x28, 0x66, 0xb5, 0xe6, 0x06, + 0x09, 0xfe, 0x6d, 0xb0, 0x72, 0x16, 0xe0, 0x8a, 0xce, 0x61, 0x65, 0xa9, + 0x21, 0x32, 0x48, 0xdc, 0x7a, 0x1d, 0xe1, 0x38, 0x7f, 0x8c, 0x75, 0x88, + 0x3d, 0x08, 0xa9, 0x4a, 0x6f, 0x3d, 0x9f, 0x7f, 0x3f, 0xbd, 0x57, 0x6b, + 0x19, 0xce, 0x3f, 0x4a, 0xc9, 0xd3, 0xf9, 0x6e, 0x72, 0x7b, 0x5b, 0x74, + 0xea, 0xbe, 0x9c, 0x7a, 0x6d, 0x9c, 0x40, 0x49, 0xe6, 0xfb, 0x2a, 0x1a, + 0x75, 0x70, 0xe5, 0x4e, 0xed, 0x74, 0xe0, 0x75, 0xac, 0xc0, 0xb1, 0x11, + 0x3e, 0xf2, 0xaf, 0x88, 0x4d, 0x66, 0xb6, 0xf6, 0x15, 0x4f, 0x3c, 0x6c, + 0x77, 0xae, 0x47, 0x51, 0x63, 0x9a, 0xfe, 0xe1, 0xb4, 0x1a, 0x12, 0xdf, + 0xe9, 0x54, 0x8d, 0x3b, 0x30, 0x2a, 0x75, 0xe3, 0xe5, 0x29, 0xb1, 0x4c, + 0xb0, 0x7c, 0x6d, 0xb5, 0xae, 0x85, 0xdb, 0x1e, 0x38, 0x55, 0x96, 0xa5, + 0x5b, 0x9f, 0x15, 0x23, 0x28, 0x36, 0xb8, 0xa2, 0x41, 0xb4, 0xd7, 0x19, + 0x91, 0x8d, 0x26, 0x3e, 0xca, 0x9c, 0x05, 0x7a, 0x2b, 0x60, 0x45, 0x86, + 0x8b, 0xee, 0x64, 0x6f, 0x5c, 0x09, 0x4d, 0x4b, 0x5a, 0x7f, 0xb0, 0xc3, + 0x26, 0x9d, 0x8b, 0xb8, 0x83, 0x69, 0xcf, 0x16, 0x72, 0x62, 0x3e, 0x5e, + 0x53, 0x4f, 0x9c, 0x73, 0x76, 0xfc, 0x19, 0xef, 0xa0, 0x74, 0x3a, 0x11, + 0x1e, 0xd0, 0x4d, 0xb7, 0x87, 0xa1, 0xd6, 0x87, 0x6c, 0x0e, 0x6c, 0x8c, + 0xe9, 0xa0, 0x44, 0xc4, 0x72, 0x3e, 0x73, 0x17, 0x13, 0xd1, 0x4e, 0x3d, + 0x8e, 0x1d, 0x5a, 0x8b, 0x75, 0xcb, 0x59, 0x2c, 0x47, 0x87, 0x15, 0x41, + 0xfe, 0x08, 0xe9, 0xa6, 0x97, 0x17, 0x08, 0x26, 0x6a, 0xb5, 0xbb, 0x73, + 0xaa, 0xb8, 0x5b, 0x65, 0x65, 0x5b, 0x30, 0x9e, 0x62, 0x59, 0x02, 0xf8, + 0xb8, 0x0f, 0x32, 0x10, 0xc1, 0x36, 0x08, 0x52, 0x98, 0x4a, 0x1e, 0xf0, + 0xab, 0x21, 0x5e, 0xde, 0x16, 0x0c, 0xda, 0x09, 0x99, 0x6b, 0x9e, 0xc0, + 0x90, 0xa5, 0x5a, 0xcc, 0xb0, 0xb7, 0xbb, 0xd2, 0x8b, 0x5f, 0xd3, 0x3b, + 0x3e, 0x8c, 0xa5, 0x71, 0x66, 0x06, 0xe3, 0x28, 0xd4, 0xf8, 0x3f, 0xe5, + 0x27, 0xdf, 0xfe, 0x0f, 0x09, 0xb2, 0x8a, 0x09, 0x5a, 0x23, 0x61, 0x0d, + 0x2d, 0xf5, 0x44, 0xf1, 0x5c, 0xf8, 0x82, 0x4e, 0xdc, 0x78, 0x7a, 0xab, + 0xc3, 0x57, 0x91, 0xaf, 0x65, 0x6e, 0x71, 0xf1, 0x44, 0xbf, 0xed, 0x43, + 0x50, 0xb4, 0x67, 0x48, 0xef, 0x5a, 0x10, 0x46, 0x81, 0xb4, 0x0c, 0xc8, + 0x48, 0xed, 0x99, 0x7a, 0x45, 0xa5, 0x92, 0xc3, 0x69, 0xd6, 0xd7, 0x8a, + 0x20, 0x1b, 0xeb, 0x8f, 0xb2, 0xff, 0xec, 0x6d, 0x76, 0x04, 0xf8, 0xc2, + 0x58, 0x9b, 0xf2, 0x20, 0x53, 0xc4, 0x74, 0x91, 0x19, 0xdd, 0x2d, 0x12, + 0x53, 0xc7, 0x6e, 0xd0, 0x02, 0x51, 0x3c, 0xa6, 0x7d, 0x80, 0x75, 0x6b, + 0x1d, 0xdf, 0xf8, 0x6a, 0x52, 0xbb, 0x81, 0xf8, 0x30, 0x45, 0xef, 0x51, + 0x85, 0x36, 0xbe, 0x8e, 0xcf, 0x0b, 0x9a, 0x46, 0xe8, 0x3f, 0x99, 0xfd, + 0xf7, 0xd9, 0x3e, 0x84, 0xe5, 0xe3, 0x37, 0xcf, 0x98, 0x7f, 0xeb, 0x5e, + 0x5a, 0x53, 0x77, 0x1c, 0x20, 0xdc, 0xf1, 0x20, 0x99, 0xec, 0x60, 0x40, + 0x93, 0xef, 0x5c, 0x1c, 0x81, 0xe2, 0xa5, 0xad, 0x2a, 0xc2, 0xdb, 0x6b, + 0xc1, 0x7e, 0x8f, 0xa9, 0x23, 0x5b, 0xd9, 0x0d, 0xfe, 0xa0, 0xac, 0x11, + 0x28, 0xba, 0x8e, 0x92, 0x07, 0x2d, 0x07, 0x40, 0x83, 0x14, 0x4c, 0x35, + 0x8d, 0xd0, 0x11, 0xff, 0x98, 0xdb, 0x00, 0x30, 0x6f, 0x65, 0xb6, 0xa0, + 0x7f, 0x9c, 0x08, 0xb8, 0xce, 0xb3, 0xa8, 0x42, 0xd3, 0x84, 0x45, 0xe1, + 0xe3, 0x8f, 0xa6, 0x89, 0x21, 0xd7, 0x74, 0x02, 0x4d, 0x64, 0xdf, 0x54, + 0x15, 0x9e, 0xba, 0x12, 0x49, 0x09, 0x41, 0xf6, 0x10, 0x24, 0xa1, 0x84, + 0x15, 0xfd, 0x68, 0x6a, 0x57, 0x66, 0xb3, 0x6d, 0x4c, 0xea, 0xbf, 0xbc, + 0x60, 0x3f, 0x52, 0x1c, 0x44, 0x1b, 0xc0, 0x4a, 0x25, 0xe3, 0xd9, 0x4c, + 0x9a, 0x74, 0xad, 0xfc, 0x9e, 0x8d, 0x0b, 0x18, 0x66, 0x24, 0xd1, 0x06, + 0xac, 0x68, 0xc1, 0xae, 0x14, 0xce, 0xb1, 0xf3, 0x86, 0x9f, 0x87, 0x11, + 0xd7, 0x9f, 0x30, 0x92, 0xdb, 0xec, 0x0b, 0x4a, 0xe8, 0xf6, 0x53, 0x36, + 0x68, 0x12, 0x11, 0x5e, 0xe0, 0x34, 0xa4, 0xff, 0x00, 0x0a, 0x26, 0xb8, + 0x62, 0x79, 0x9c, 0x0c, 0xd5, 0xe5, 0xf5, 0x1c, 0x1a, 0x16, 0x84, 0x4d, + 0x8e, 0x5d, 0x31, 0x7e, 0xf7, 0xe2, 0xd3, 0xa1, 0x41, 0x90, 0x61, 0x5d, + 0x04, 0xb2, 0x9a, 0x18, 0x9e, 0x54, 0xfb, 0xd1, 0x61, 0x95, 0x1b, 0x08, + 0xca, 0x7c, 0x49, 0x44, 0x74, 0x1d, 0x2f, 0xca, 0xc4, 0x7a, 0xe1, 0x8b, + 0x2f, 0xbb, 0x96, 0xee, 0x19, 0x8a, 0x5d, 0xfb, 0x3e, 0x82, 0xe7, 0x15, + 0xdb, 0x29, 0x14, 0xee, 0xc9, 0x4d, 0x9a, 0xfb, 0x9f, 0x8a, 0xbb, 0x17, + 0x37, 0x1b, 0x6e, 0x28, 0x6c, 0xf9, 0xff, 0xb5, 0xb5, 0x8b, 0x9d, 0x88, + 0x20, 0x08, 0x10, 0xd7, 0xca, 0x58, 0xf6, 0xe1, 0x32, 0x91, 0x6f, 0x36, + 0xc0, 0xad, 0xc1, 0x57, 0x5d, 0x76, 0x31, 0x43, 0xf3, 0xdd, 0xec, 0xf1, + 0xa9, 0x79, 0xe9, 0xe9, 0x85, 0xd7, 0x91, 0xc7, 0x31, 0x62, 0x3c, 0xd2, + 0x90, 0x2c, 0x9c, 0xa4, 0x56, 0x37, 0x7b, 0xbe, 0x40, 0x58, 0xc0, 0x81, + 0x83, 0x22, 0xe8, 0x13, 0x79, 0x18, 0xdb, 0x3a, 0x1b, 0x31, 0x0d, 0x00, + 0x6c, 0x22, 0x62, 0x75, 0x70, 0xd8, 0x96, 0x59, 0x99, 0x44, 0x79, 0x71, + 0xa6, 0x76, 0x81, 0x28, 0xb2, 0x65, 0xe8, 0x47, 0x14, 0xc6, 0x39, 0x06, +}; + +enum spake2_state_t { + spake2_state_init = 0, + spake2_state_msg_generated, + spake2_state_key_generated, +}; + +struct spake2_ctx_st { + uint8_t private_key[32]; + uint8_t my_msg[32]; + uint8_t password_scalar[32]; + uint8_t password_hash[SHA512_DIGEST_LENGTH]; + uint8_t *my_name; + size_t my_name_len; + uint8_t *their_name; + size_t their_name_len; + enum spake2_role_t my_role; + enum spake2_state_t state; +}; + +SPAKE2_CTX *SPAKE2_CTX_new(enum spake2_role_t my_role, + const uint8_t *my_name, size_t my_name_len, + const uint8_t *their_name, size_t their_name_len) { + SPAKE2_CTX *ctx = OPENSSL_malloc(sizeof(SPAKE2_CTX)); + if (ctx == NULL) { + return NULL; + } + + OPENSSL_memset(ctx, 0, sizeof(SPAKE2_CTX)); + ctx->my_role = my_role; + + CBS my_name_cbs, their_name_cbs; + CBS_init(&my_name_cbs, my_name, my_name_len); + CBS_init(&their_name_cbs, their_name, their_name_len); + if (!CBS_stow(&my_name_cbs, &ctx->my_name, &ctx->my_name_len) || + !CBS_stow(&their_name_cbs, &ctx->their_name, &ctx->their_name_len)) { + SPAKE2_CTX_free(ctx); + return NULL; + } + + return ctx; +} + +void SPAKE2_CTX_free(SPAKE2_CTX *ctx) { + if (ctx == NULL) { + return; + } + + OPENSSL_free(ctx->my_name); + OPENSSL_free(ctx->their_name); + OPENSSL_free(ctx); +} + +/* left_shift_3 sets |n| to |n|*8, where |n| is represented in little-endian + * order. */ +static void left_shift_3(uint8_t n[32]) { + uint8_t carry = 0; + unsigned i; + + for (i = 0; i < 32; i++) { + const uint8_t next_carry = n[i] >> 5; + n[i] = (n[i] << 3) | carry; + carry = next_carry; + } +} + +int SPAKE2_generate_msg(SPAKE2_CTX *ctx, uint8_t *out, size_t *out_len, + size_t max_out_len, const uint8_t *password, + size_t password_len) { + if (ctx->state != spake2_state_init) { + return 0; + } + + if (max_out_len < sizeof(ctx->my_msg)) { + return 0; + } + + uint8_t private_tmp[64]; + RAND_bytes(private_tmp, sizeof(private_tmp)); + x25519_sc_reduce(private_tmp); + /* Multiply by the cofactor (eight) so that we'll clear it when operating on + * the peer's point later in the protocol. */ + left_shift_3(private_tmp); + OPENSSL_memcpy(ctx->private_key, private_tmp, sizeof(ctx->private_key)); + + ge_p3 P; + x25519_ge_scalarmult_base(&P, ctx->private_key); + + /* mask = h(password) * . */ + uint8_t password_tmp[SHA512_DIGEST_LENGTH]; + SHA512(password, password_len, password_tmp); + OPENSSL_memcpy(ctx->password_hash, password_tmp, sizeof(ctx->password_hash)); + x25519_sc_reduce(password_tmp); + OPENSSL_memcpy(ctx->password_scalar, password_tmp, sizeof(ctx->password_scalar)); + + ge_p3 mask; + x25519_ge_scalarmult_small_precomp(&mask, ctx->password_scalar, + ctx->my_role == spake2_role_alice + ? kSpakeMSmallPrecomp + : kSpakeNSmallPrecomp); + + /* P* = P + mask. */ + ge_cached mask_cached; + x25519_ge_p3_to_cached(&mask_cached, &mask); + ge_p1p1 Pstar; + x25519_ge_add(&Pstar, &P, &mask_cached); + + /* Encode P* */ + ge_p2 Pstar_proj; + x25519_ge_p1p1_to_p2(&Pstar_proj, &Pstar); + x25519_ge_tobytes(ctx->my_msg, &Pstar_proj); + + OPENSSL_memcpy(out, ctx->my_msg, sizeof(ctx->my_msg)); + *out_len = sizeof(ctx->my_msg); + ctx->state = spake2_state_msg_generated; + + return 1; +} + +static void update_with_length_prefix(SHA512_CTX *sha, const uint8_t *data, + const size_t len) { + uint8_t len_le[8]; + size_t l = len; + unsigned i; + + for (i = 0; i < 8; i++) { + len_le[i] = l & 0xff; + l >>= 8; + } + + SHA512_Update(sha, len_le, sizeof(len_le)); + SHA512_Update(sha, data, len); +} + +int SPAKE2_process_msg(SPAKE2_CTX *ctx, uint8_t *out_key, size_t *out_key_len, + size_t max_out_key_len, const uint8_t *their_msg, + size_t their_msg_len) { + if (ctx->state != spake2_state_msg_generated || + their_msg_len != 32) { + return 0; + } + + ge_p3 Qstar; + if (0 != x25519_ge_frombytes_vartime(&Qstar, their_msg)) { + /* Point received from peer was not on the curve. */ + return 0; + } + + /* Unmask peer's value. */ + ge_p3 peers_mask; + x25519_ge_scalarmult_small_precomp(&peers_mask, ctx->password_scalar, + ctx->my_role == spake2_role_alice + ? kSpakeNSmallPrecomp + : kSpakeMSmallPrecomp); + + ge_cached peers_mask_cached; + x25519_ge_p3_to_cached(&peers_mask_cached, &peers_mask); + + ge_p1p1 Q_compl; + ge_p3 Q_ext; + x25519_ge_sub(&Q_compl, &Qstar, &peers_mask_cached); + x25519_ge_p1p1_to_p3(&Q_ext, &Q_compl); + + ge_p2 dh_shared; + x25519_ge_scalarmult(&dh_shared, ctx->private_key, &Q_ext); + + uint8_t dh_shared_encoded[32]; + x25519_ge_tobytes(dh_shared_encoded, &dh_shared); + + SHA512_CTX sha; + SHA512_Init(&sha); + if (ctx->my_role == spake2_role_alice) { + update_with_length_prefix(&sha, ctx->my_name, ctx->my_name_len); + update_with_length_prefix(&sha, ctx->their_name, ctx->their_name_len); + update_with_length_prefix(&sha, ctx->my_msg, sizeof(ctx->my_msg)); + update_with_length_prefix(&sha, their_msg, 32); + } else { + update_with_length_prefix(&sha, ctx->their_name, ctx->their_name_len); + update_with_length_prefix(&sha, ctx->my_name, ctx->my_name_len); + update_with_length_prefix(&sha, their_msg, 32); + update_with_length_prefix(&sha, ctx->my_msg, sizeof(ctx->my_msg)); + } + update_with_length_prefix(&sha, dh_shared_encoded, sizeof(dh_shared_encoded)); + update_with_length_prefix(&sha, ctx->password_hash, + sizeof(ctx->password_hash)); + + uint8_t key[SHA512_DIGEST_LENGTH]; + SHA512_Final(key, &sha); + + size_t to_copy = max_out_key_len; + if (to_copy > sizeof(key)) { + to_copy = sizeof(key); + } + OPENSSL_memcpy(out_key, key, to_copy); + *out_key_len = to_copy; + ctx->state = spake2_state_key_generated; + + return 1; +} diff --git a/Sources/BoringSSL/crypto/curve25519/x25519-x86_64.c b/Sources/BoringSSL/crypto/curve25519/x25519-x86_64.c index 9776c755f..9c3d41447 100644 --- a/Sources/BoringSSL/crypto/curve25519/x25519-x86_64.c +++ b/Sources/BoringSSL/crypto/curve25519/x25519-x86_64.c @@ -1,7 +1,29 @@ +/* Copyright (c) 2015, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +/* This code is mostly taken from the ref10 version of Ed25519 in SUPERCOP + * 20141124 (http://bench.cr.yp.to/supercop.html). That code is released as + * public domain but this file has the ISC license just to keep licencing + * simple. + * + * The field functions are shared by Ed25519 and X25519 where possible. */ + #include #include +#include "../internal.h" #include "internal.h" @@ -207,7 +229,7 @@ static void mladder(fe25519 *xr, fe25519 *zr, const uint8_t s[32]) { void x25519_x86_64(uint8_t out[32], const uint8_t scalar[32], const uint8_t point[32]) { uint8_t e[32]; - memcpy(e, scalar, sizeof(e)); + OPENSSL_memcpy(e, scalar, sizeof(e)); e[0] &= 248; e[31] &= 127; diff --git a/Sources/BoringSSL/crypto/des/des.c b/Sources/BoringSSL/crypto/des/des.c index 1d27ebe4b..cada7d104 100644 --- a/Sources/BoringSSL/crypto/des/des.c +++ b/Sources/BoringSSL/crypto/des/des.c @@ -291,7 +291,7 @@ static const uint32_t DES_SPtrans[8][64] = { #define HPERM_OP(a, t, n, m) \ ((t) = ((((a) << (16 - (n))) ^ (a)) & (m)), \ - (a) = (a) ^ (t) ^ (t >> (16 - (n)))) + (a) = (a) ^ (t) ^ ((t) >> (16 - (n)))) void DES_set_key(const DES_cblock *key, DES_key_schedule *schedule) { static const int shifts2[16] = {0, 0, 1, 1, 1, 1, 1, 1, diff --git a/Sources/BoringSSL/crypto/des/internal.h b/Sources/BoringSSL/crypto/des/internal.h index 00b45586f..21eb93357 100644 --- a/Sources/BoringSSL/crypto/des/internal.h +++ b/Sources/BoringSSL/crypto/des/internal.h @@ -64,45 +64,51 @@ extern "C" { #endif -#define c2l(c, l) \ - (l = ((uint32_t)(*((c)++))), l |= ((uint32_t)(*((c)++))) << 8L, \ - l |= ((uint32_t)(*((c)++))) << 16L, l |= ((uint32_t)(*((c)++))) << 24L) - -#define l2c(l, c) \ - (*((c)++) = (unsigned char)(((l)) & 0xff), \ - *((c)++) = (unsigned char)(((l) >> 8L) & 0xff), \ - *((c)++) = (unsigned char)(((l) >> 16L) & 0xff), \ - *((c)++) = (unsigned char)(((l) >> 24L) & 0xff)) +#define c2l(c, l) \ + do { \ + (l) = ((uint32_t)(*((c)++))); \ + (l) |= ((uint32_t)(*((c)++))) << 8L; \ + (l) |= ((uint32_t)(*((c)++))) << 16L; \ + (l) |= ((uint32_t)(*((c)++))) << 24L; \ + } while (0) + +#define l2c(l, c) \ + do { \ + *((c)++) = (unsigned char)(((l)) & 0xff); \ + *((c)++) = (unsigned char)(((l) >> 8L) & 0xff); \ + *((c)++) = (unsigned char)(((l) >> 16L) & 0xff); \ + *((c)++) = (unsigned char)(((l) >> 24L) & 0xff); \ + } while (0) /* NOTE - c is not incremented as per c2l */ -#define c2ln(c, l1, l2, n) \ - { \ - c += n; \ - l1 = l2 = 0; \ - switch (n) { \ - case 8: \ - l2 = ((uint32_t)(*(--(c)))) << 24L; \ - case 7: \ - l2 |= ((uint32_t)(*(--(c)))) << 16L; \ - case 6: \ - l2 |= ((uint32_t)(*(--(c)))) << 8L; \ - case 5: \ - l2 |= ((uint32_t)(*(--(c)))); \ - case 4: \ - l1 = ((uint32_t)(*(--(c)))) << 24L; \ - case 3: \ - l1 |= ((uint32_t)(*(--(c)))) << 16L; \ - case 2: \ - l1 |= ((uint32_t)(*(--(c)))) << 8L; \ - case 1: \ - l1 |= ((uint32_t)(*(--(c)))); \ - } \ - } +#define c2ln(c, l1, l2, n) \ + do { \ + (c) += (n); \ + (l1) = (l2) = 0; \ + switch (n) { \ + case 8: \ + (l2) = ((uint32_t)(*(--(c)))) << 24L; \ + case 7: \ + (l2) |= ((uint32_t)(*(--(c)))) << 16L; \ + case 6: \ + (l2) |= ((uint32_t)(*(--(c)))) << 8L; \ + case 5: \ + (l2) |= ((uint32_t)(*(--(c)))); \ + case 4: \ + (l1) = ((uint32_t)(*(--(c)))) << 24L; \ + case 3: \ + (l1) |= ((uint32_t)(*(--(c)))) << 16L; \ + case 2: \ + (l1) |= ((uint32_t)(*(--(c)))) << 8L; \ + case 1: \ + (l1) |= ((uint32_t)(*(--(c)))); \ + } \ + } while (0) /* NOTE - c is not incremented as per l2c */ #define l2cn(l1, l2, c, n) \ - { \ - c += n; \ + do { \ + (c) += (n); \ switch (n) { \ case 8: \ *(--(c)) = (unsigned char)(((l2) >> 24L) & 0xff); \ @@ -121,7 +127,7 @@ extern "C" { case 1: \ *(--(c)) = (unsigned char)(((l1)) & 0xff); \ } \ - } + } while (0) /* IP and FP * The problem is more of a geometric problem that random bit fiddling. @@ -160,44 +166,50 @@ When I finally started to think of the problem in 2D I first got ~42 operations without xors. When I remembered how to use xors :-) I got it to its final state. */ -#define PERM_OP(a, b, t, n, m) \ - ((t) = ((((a) >> (n)) ^ (b)) & (m)), (b) ^= (t), (a) ^= ((t) << (n))) +#define PERM_OP(a, b, t, n, m) \ + do { \ + (t) = ((((a) >> (n)) ^ (b)) & (m)); \ + (b) ^= (t); \ + (a) ^= ((t) << (n)); \ + } while (0) #define IP(l, r) \ - { \ + do { \ uint32_t tt; \ PERM_OP(r, l, tt, 4, 0x0f0f0f0fL); \ PERM_OP(l, r, tt, 16, 0x0000ffffL); \ PERM_OP(r, l, tt, 2, 0x33333333L); \ PERM_OP(l, r, tt, 8, 0x00ff00ffL); \ PERM_OP(r, l, tt, 1, 0x55555555L); \ - } + } while (0) #define FP(l, r) \ - { \ + do { \ uint32_t tt; \ PERM_OP(l, r, tt, 1, 0x55555555L); \ PERM_OP(r, l, tt, 8, 0x00ff00ffL); \ PERM_OP(l, r, tt, 2, 0x33333333L); \ PERM_OP(r, l, tt, 16, 0x0000ffffL); \ PERM_OP(l, r, tt, 4, 0x0f0f0f0fL); \ - } + } while (0) #define LOAD_DATA(ks, R, S, u, t, E0, E1) \ - u = R ^ ks->subkeys[S][0]; \ - t = R ^ ks->subkeys[S][1] + do { \ + (u) = (R) ^ (ks)->subkeys[S][0]; \ + (t) = (R) ^ (ks)->subkeys[S][1]; \ + } while (0) #define D_ENCRYPT(ks, LL, R, S) \ - { \ + do { \ LOAD_DATA(ks, R, S, u, t, E0, E1); \ t = ROTATE(t, 4); \ - LL ^= \ + (LL) ^= \ DES_SPtrans[0][(u >> 2L) & 0x3f] ^ DES_SPtrans[2][(u >> 10L) & 0x3f] ^ \ DES_SPtrans[4][(u >> 18L) & 0x3f] ^ \ DES_SPtrans[6][(u >> 26L) & 0x3f] ^ DES_SPtrans[1][(t >> 2L) & 0x3f] ^ \ DES_SPtrans[3][(t >> 10L) & 0x3f] ^ \ DES_SPtrans[5][(t >> 18L) & 0x3f] ^ DES_SPtrans[7][(t >> 26L) & 0x3f]; \ - } + } while (0) #define ITERATIONS 16 #define HALF_ITERATIONS 8 diff --git a/Sources/BoringSSL/crypto/dh/check.c b/Sources/BoringSSL/crypto/dh/check.c index d27fdf154..f40e03419 100644 --- a/Sources/BoringSSL/crypto/dh/check.c +++ b/Sources/BoringSSL/crypto/dh/check.c @@ -58,8 +58,6 @@ #include -#include "internal.h" - int DH_check_pub_key(const DH *dh, const BIGNUM *pub_key, int *ret) { *ret = 0; @@ -120,7 +118,7 @@ int DH_check(const DH *dh, int *ret) { * for 5, p mod 10 == 3 or 7 * should hold. */ - int ok = 0; + int ok = 0, r; BN_CTX *ctx = NULL; BN_ULONG l; BIGNUM *t1 = NULL, *t2 = NULL; @@ -154,7 +152,11 @@ int DH_check(const DH *dh, int *ret) { *ret |= DH_CHECK_NOT_SUITABLE_GENERATOR; } } - if (!BN_is_prime_ex(dh->q, BN_prime_checks, ctx, NULL)) { + r = BN_is_prime_ex(dh->q, BN_prime_checks, ctx, NULL); + if (r < 0) { + goto err; + } + if (!r) { *ret |= DH_CHECK_Q_NOT_PRIME; } /* Check p == 1 mod q i.e. q divides p - 1 */ @@ -169,11 +171,17 @@ int DH_check(const DH *dh, int *ret) { } } else if (BN_is_word(dh->g, DH_GENERATOR_2)) { l = BN_mod_word(dh->p, 24); + if (l == (BN_ULONG)-1) { + goto err; + } if (l != 11) { *ret |= DH_CHECK_NOT_SUITABLE_GENERATOR; } } else if (BN_is_word(dh->g, DH_GENERATOR_5)) { l = BN_mod_word(dh->p, 10); + if (l == (BN_ULONG)-1) { + goto err; + } if (l != 3 && l != 7) { *ret |= DH_CHECK_NOT_SUITABLE_GENERATOR; } @@ -181,13 +189,21 @@ int DH_check(const DH *dh, int *ret) { *ret |= DH_CHECK_UNABLE_TO_CHECK_GENERATOR; } - if (!BN_is_prime_ex(dh->p, BN_prime_checks, ctx, NULL)) { + r = BN_is_prime_ex(dh->p, BN_prime_checks, ctx, NULL); + if (r < 0) { + goto err; + } + if (!r) { *ret |= DH_CHECK_P_NOT_PRIME; } else if (!dh->q) { if (!BN_rshift1(t1, dh->p)) { goto err; } - if (!BN_is_prime_ex(t1, BN_prime_checks, ctx, NULL)) { + r = BN_is_prime_ex(t1, BN_prime_checks, ctx, NULL); + if (r < 0) { + goto err; + } + if (!r) { *ret |= DH_CHECK_P_NOT_SAFE_PRIME; } } diff --git a/Sources/BoringSSL/crypto/dh/dh.c b/Sources/BoringSSL/crypto/dh/dh.c index aed8720bc..33c36f31f 100644 --- a/Sources/BoringSSL/crypto/dh/dh.c +++ b/Sources/BoringSSL/crypto/dh/dh.c @@ -65,7 +65,6 @@ #include #include -#include "internal.h" #include "../internal.h" @@ -80,7 +79,7 @@ DH *DH_new(void) { return NULL; } - memset(dh, 0, sizeof(DH)); + OPENSSL_memset(dh, 0, sizeof(DH)); CRYPTO_MUTEX_init(&dh->method_mont_p_lock); @@ -115,6 +114,29 @@ void DH_free(DH *dh) { OPENSSL_free(dh); } +void DH_get0_key(const DH *dh, const BIGNUM **out_pub_key, + const BIGNUM **out_priv_key) { + if (out_pub_key != NULL) { + *out_pub_key = dh->pub_key; + } + if (out_priv_key != NULL) { + *out_priv_key = dh->priv_key; + } +} + +void DH_get0_pqg(const DH *dh, const BIGNUM **out_p, const BIGNUM **out_q, + const BIGNUM **out_g) { + if (out_p != NULL) { + *out_p = dh->p; + } + if (out_q != NULL) { + *out_q = dh->q; + } + if (out_g != NULL) { + *out_g = dh->g; + } +} + int DH_generate_parameters_ex(DH *dh, int prime_bits, int generator, BN_GENCB *cb) { /* We generate DH parameters as follows * find a prime q which is prime_bits/2 bits long. @@ -234,11 +256,8 @@ int DH_generate_parameters_ex(DH *dh, int prime_bits, int generator, BN_GENCB *c int DH_generate_key(DH *dh) { int ok = 0; int generate_new_key = 0; - unsigned l; BN_CTX *ctx = NULL; - BN_MONT_CTX *mont = NULL; BIGNUM *pub_key = NULL, *priv_key = NULL; - BIGNUM local_priv; if (BN_num_bits(dh->p) > OPENSSL_DH_MAX_MODULUS_BITS) { OPENSSL_PUT_ERROR(DH, DH_R_MODULUS_TOO_LARGE); @@ -269,31 +288,36 @@ int DH_generate_key(DH *dh) { pub_key = dh->pub_key; } - mont = BN_MONT_CTX_set_locked(&dh->method_mont_p, &dh->method_mont_p_lock, - dh->p, ctx); - if (!mont) { + if (!BN_MONT_CTX_set_locked(&dh->method_mont_p, &dh->method_mont_p_lock, + dh->p, ctx)) { goto err; } if (generate_new_key) { if (dh->q) { - do { - if (!BN_rand_range(priv_key, dh->q)) { - goto err; - } - } while (BN_is_zero(priv_key) || BN_is_one(priv_key)); + if (!BN_rand_range_ex(priv_key, 2, dh->q)) { + goto err; + } } else { /* secret exponent length */ - DH_check_standard_parameters(dh); - l = dh->priv_length ? dh->priv_length : BN_num_bits(dh->p) - 1; - if (!BN_rand(priv_key, l, 0, 0)) { + unsigned priv_bits = dh->priv_length; + if (priv_bits == 0) { + const unsigned p_bits = BN_num_bits(dh->p); + if (p_bits == 0) { + goto err; + } + + priv_bits = p_bits - 1; + } + + if (!BN_rand(priv_key, priv_bits, BN_RAND_TOP_ONE, BN_RAND_BOTTOM_ANY)) { goto err; } } } - BN_with_flags(&local_priv, priv_key, BN_FLG_CONSTTIME); - if (!BN_mod_exp_mont(pub_key, dh->g, &local_priv, dh->p, ctx, mont)) { + if (!BN_mod_exp_mont_consttime(pub_key, dh->g, priv_key, dh->p, ctx, + dh->method_mont_p)) { goto err; } @@ -318,11 +342,9 @@ int DH_generate_key(DH *dh) { int DH_compute_key(unsigned char *out, const BIGNUM *peers_key, DH *dh) { BN_CTX *ctx = NULL; - BN_MONT_CTX *mont = NULL; BIGNUM *shared_key; int ret = -1; int check_result; - BIGNUM local_priv; if (BN_num_bits(dh->p) > OPENSSL_DH_MAX_MODULUS_BITS) { OPENSSL_PUT_ERROR(DH, DH_R_MODULUS_TOO_LARGE); @@ -344,9 +366,8 @@ int DH_compute_key(unsigned char *out, const BIGNUM *peers_key, DH *dh) { goto err; } - mont = BN_MONT_CTX_set_locked(&dh->method_mont_p, &dh->method_mont_p_lock, - dh->p, ctx); - if (!mont) { + if (!BN_MONT_CTX_set_locked(&dh->method_mont_p, &dh->method_mont_p_lock, + dh->p, ctx)) { goto err; } @@ -355,9 +376,8 @@ int DH_compute_key(unsigned char *out, const BIGNUM *peers_key, DH *dh) { goto err; } - BN_with_flags(&local_priv, dh->priv_key, BN_FLG_CONSTTIME); - if (!BN_mod_exp_mont(shared_key, peers_key, &local_priv, dh->p, ctx, - mont)) { + if (!BN_mod_exp_mont_consttime(shared_key, peers_key, dh->priv_key, dh->p, + ctx, dh->method_mont_p)) { OPENSSL_PUT_ERROR(DH, ERR_R_BN_LIB); goto err; } diff --git a/Sources/BoringSSL/crypto/dh/dh_asn1.c b/Sources/BoringSSL/crypto/dh/dh_asn1.c index 73cd4df75..1a147eea9 100644 --- a/Sources/BoringSSL/crypto/dh/dh_asn1.c +++ b/Sources/BoringSSL/crypto/dh/dh_asn1.c @@ -55,30 +55,106 @@ #include -#include -#include - -#include "internal.h" - -/* Override the default free and new methods */ -static int dh_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it, - void *exarg) { - if (operation == ASN1_OP_NEW_PRE) { - *pval = (ASN1_VALUE *)DH_new(); - if (*pval) { - return 2; +#include +#include + +#include +#include +#include + +#include "../bytestring/internal.h" + + +static int parse_integer(CBS *cbs, BIGNUM **out) { + assert(*out == NULL); + *out = BN_new(); + if (*out == NULL) { + return 0; + } + return BN_parse_asn1_unsigned(cbs, *out); +} + +static int marshal_integer(CBB *cbb, BIGNUM *bn) { + if (bn == NULL) { + /* A DH object may be missing some components. */ + OPENSSL_PUT_ERROR(DH, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + return BN_marshal_asn1(cbb, bn); +} + +DH *DH_parse_parameters(CBS *cbs) { + DH *ret = DH_new(); + if (ret == NULL) { + return NULL; + } + + CBS child; + if (!CBS_get_asn1(cbs, &child, CBS_ASN1_SEQUENCE) || + !parse_integer(&child, &ret->p) || + !parse_integer(&child, &ret->g)) { + goto err; + } + + uint64_t priv_length; + if (CBS_len(&child) != 0) { + if (!CBS_get_asn1_uint64(&child, &priv_length) || + priv_length > UINT_MAX) { + goto err; } + ret->priv_length = (unsigned)priv_length; + } + + if (CBS_len(&child) != 0) { + goto err; + } + + return ret; + +err: + OPENSSL_PUT_ERROR(DH, DH_R_DECODE_ERROR); + DH_free(ret); + return NULL; +} + +int DH_marshal_parameters(CBB *cbb, const DH *dh) { + CBB child; + if (!CBB_add_asn1(cbb, &child, CBS_ASN1_SEQUENCE) || + !marshal_integer(&child, dh->p) || + !marshal_integer(&child, dh->g) || + (dh->priv_length != 0 && + !CBB_add_asn1_uint64(&child, dh->priv_length)) || + !CBB_flush(cbb)) { + OPENSSL_PUT_ERROR(DH, DH_R_ENCODE_ERROR); return 0; - } else if (operation == ASN1_OP_FREE_PRE) { - DH_free((DH *)*pval); - *pval = NULL; - return 2; } return 1; } -ASN1_SEQUENCE_cb(DHparams, dh_cb) = { - ASN1_SIMPLE(DH, p, BIGNUM), ASN1_SIMPLE(DH, g, BIGNUM), - ASN1_OPT(DH, priv_length, ZLONG)} ASN1_SEQUENCE_END_cb(DH, DHparams); +DH *d2i_DHparams(DH **out, const uint8_t **inp, long len) { + if (len < 0) { + return NULL; + } + CBS cbs; + CBS_init(&cbs, *inp, (size_t)len); + DH *ret = DH_parse_parameters(&cbs); + if (ret == NULL) { + return NULL; + } + if (out != NULL) { + DH_free(*out); + *out = ret; + } + *inp = CBS_data(&cbs); + return ret; +} -IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(DH, DHparams, DHparams) +int i2d_DHparams(const DH *in, uint8_t **outp) { + CBB cbb; + if (!CBB_init(&cbb, 0) || + !DH_marshal_parameters(&cbb, in)) { + CBB_cleanup(&cbb); + return -1; + } + return CBB_finish_i2d(&cbb, outp); +} diff --git a/Sources/BoringSSL/crypto/dh/params.c b/Sources/BoringSSL/crypto/dh/params.c index 7e8102a01..4cec700a2 100644 --- a/Sources/BoringSSL/crypto/dh/params.c +++ b/Sources/BoringSSL/crypto/dh/params.c @@ -54,7 +54,6 @@ #include -#include "internal.h" #include "../bn/internal.h" @@ -166,58 +165,6 @@ static const BN_ULONG dh2048_256_q[] = { TOBN(0xB4479976, 0x40129DA2), TOBN(0x8CF83642, 0xA709A097), }; -/* dh1024_safe_prime_1 is hard-coded in Apache httpd 2.2, - * modules/ssl/ssl_engine_dh.c. */ -static const BN_ULONG dh1024_safe_prime_1[] = { - TOBN(0xE7393E0F, 0x24218EB3), TOBN(0x7DE0F4D6, 0xE2BD68B0), - TOBN(0x07DD62DB, 0x88AEAA74), TOBN(0x10EA9FCC, 0x9DDD3305), - TOBN(0xA7DBCA78, 0x74087D15), TOBN(0xDAE88600, 0x78045B07), - TOBN(0x33168A46, 0x1AAD3B72), TOBN(0xFF590137, 0x7BEDDCFD), - TOBN(0xFE324A46, 0x7A635E81), TOBN(0x5AC179BA, 0x420B2A29), - TOBN(0x13B4B4D7, 0x177E16D5), TOBN(0x849F912E, 0x639C72FB), - TOBN(0xB88174CB, 0x98BCE951), TOBN(0x0C84D239, 0xA45F520B), - TOBN(0x36D693D3, 0x4AFD0AD5), TOBN(0xD67DE440, 0xCBBBDC19), -}; - -/* dh1024_safe_prime_2 is hard-coded in nginx, - * src/event/ngx_event_openssl.c. */ -static const BN_ULONG dh1024_safe_prime_2[] = { - TOBN(0x071DF045, 0xCFE16B9B), TOBN(0x88D0F65D, 0x146757DA), - TOBN(0x4A63AB1E, 0x58FAFD49), TOBN(0x35D8CECE, 0xEF9EA027), - TOBN(0x25ECE662, 0x70CC9A50), TOBN(0xF29BA5DF, 0x81DC2CA7), - TOBN(0x8F68B076, 0xF7D36CC8), TOBN(0x60E91A92, 0xA757E304), - TOBN(0x87A2BC04, 0x9BE67780), TOBN(0xBEECA565, 0xA5FDF1D2), - TOBN(0x5CCBBAA8, 0x922614C5), TOBN(0x6C030276, 0xE710800C), - TOBN(0x08EED4EB, 0x0FB3504C), TOBN(0xD958A3F5, 0x68B42D4B), - TOBN(0x7C43FCF5, 0x80E9CFDB), TOBN(0xBBBC2DCA, 0xD8467490), -}; - -/* dh1024_safe_prime_3 is offered as a parameter by several high-traffic sites, - * including mozilla.org, as of Jan 2015. */ -static const BN_ULONG dh1024_safe_prime_3[] = { - TOBN(0x671746AE, 0x349E721B), TOBN(0x258A0655, 0xD75E93B2), - TOBN(0xD425E6FB, 0x25592EB6), TOBN(0x0C46AB04, 0xBF7CDD9A), - TOBN(0x0AD0BC99, 0x28968680), TOBN(0xF53907FB, 0xD0B7EB49), - TOBN(0x202EABB3, 0xEBC85C1D), TOBN(0x3129C693, 0x364D8C71), - TOBN(0x53728351, 0x2D46F195), TOBN(0xDF326DD6, 0x8C76CC85), - TOBN(0xF898B3F9, 0x9188E24E), TOBN(0x95EFB13C, 0x2855DFD2), - TOBN(0x1F5DAC48, 0x7B2241FE), TOBN(0x117B6BF7, 0x99A13D9F), - TOBN(0x0F97CDDA, 0x3A3468C7), TOBN(0xC9BBF5F7, 0x74A8297B)}; - -/* dh1024_safe_prime_4 is hard-coded in Apache httpd 2.0, - * modules/ssl/ssl_engine_dh.c. */ -static const BN_ULONG dh1024_safe_prime_4[] = { - TOBN(0x5085E21F, 0x0DD5C86B), TOBN(0x871538DF, 0xD823C650), - TOBN(0x125136F7, 0x262E56A8), TOBN(0x974E9EF1, 0x839EB5DB), - TOBN(0xEA9BAD99, 0x1B13A63C), TOBN(0x6044CF02, 0x3D76E05E), - TOBN(0x611EBBBE, 0x1BAC9B5C), TOBN(0x3E371D79, 0x4E5327DF), - TOBN(0x000E6EDD, 0x061CBC05), TOBN(0x2F971F3C, 0x20129B48), - TOBN(0xA6EF09C4, 0x3048D5A2), TOBN(0xFA15A259, 0xCBD523A6), - TOBN(0x2A206490, 0x4A79A770), TOBN(0x91B78182, 0x51BB055E), - TOBN(0x7CF180C3, 0xBDD4798E), TOBN(0xE6969D3D, 0x495BE32C)}; - -static const BN_ULONG bn_two_data[] = {2}; - struct standard_parameters { BIGNUM p, q, g; }; @@ -240,15 +187,6 @@ static const struct standard_parameters dh2048_256 = { STATIC_BIGNUM(dh2048_256_g), }; -static const BIGNUM dh1024_safe_prime[] = { - STATIC_BIGNUM(dh1024_safe_prime_1), - STATIC_BIGNUM(dh1024_safe_prime_2), - STATIC_BIGNUM(dh1024_safe_prime_3), - STATIC_BIGNUM(dh1024_safe_prime_4) -}; - -static BIGNUM bn_two = STATIC_BIGNUM(bn_two_data); - static DH *get_standard_parameters(const struct standard_parameters *params, const ENGINE *engine) { DH *dh = DH_new(); @@ -279,23 +217,37 @@ DH *DH_get_2048_256(const ENGINE *engine) { return get_standard_parameters(&dh2048_256, engine); } -void DH_check_standard_parameters(DH *dh) { - unsigned i; - - if (dh->p == NULL || - dh->g == NULL || - BN_num_bytes(dh->p) != (1024 / 8) || - BN_cmp(dh->g, &bn_two) != 0) { - return; +BIGNUM *BN_get_rfc3526_prime_1536(BIGNUM *ret) { + static const BN_ULONG kPrime1536Data[] = { + TOBN(0xffffffff, 0xffffffff), TOBN(0xf1746c08, 0xca237327), + TOBN(0x670c354e, 0x4abc9804), TOBN(0x9ed52907, 0x7096966d), + TOBN(0x1c62f356, 0x208552bb), TOBN(0x83655d23, 0xdca3ad96), + TOBN(0x69163fa8, 0xfd24cf5f), TOBN(0x98da4836, 0x1c55d39a), + TOBN(0xc2007cb8, 0xa163bf05), TOBN(0x49286651, 0xece45b3d), + TOBN(0xae9f2411, 0x7c4b1fe6), TOBN(0xee386bfb, 0x5a899fa5), + TOBN(0x0bff5cb6, 0xf406b7ed), TOBN(0xf44c42e9, 0xa637ed6b), + TOBN(0xe485b576, 0x625e7ec6), TOBN(0x4fe1356d, 0x6d51c245), + TOBN(0x302b0a6d, 0xf25f1437), TOBN(0xef9519b3, 0xcd3a431b), + TOBN(0x514a0879, 0x8e3404dd), TOBN(0x020bbea6, 0x3b139b22), + TOBN(0x29024e08, 0x8a67cc74), TOBN(0xc4c6628b, 0x80dc1cd1), + TOBN(0xc90fdaa2, 0x2168c234), TOBN(0xffffffff, 0xffffffff), + }; + + static const BIGNUM kPrime1536BN = STATIC_BIGNUM(kPrime1536Data); + + BIGNUM *alloc = NULL; + if (ret == NULL) { + alloc = BN_new(); + if (alloc == NULL) { + return NULL; + } + ret = alloc; } - for (i = 0; i < sizeof(dh1024_safe_prime) / sizeof(dh1024_safe_prime[0]); - i++) { - if (BN_cmp(dh->p, &dh1024_safe_prime[i]) == 0) { - /* The well-known DH groups are known to have safe primes. In this case - * we can safely reduce the size of the private key. */ - dh->priv_length = 161; - break; - } + if (!BN_copy(ret, &kPrime1536BN)) { + BN_free(alloc); + return NULL; } + + return ret; } diff --git a/Sources/BoringSSL/crypto/digest/digest.c b/Sources/BoringSSL/crypto/digest/digest.c index eb71b0732..9c9962b53 100644 --- a/Sources/BoringSSL/crypto/digest/digest.c +++ b/Sources/BoringSSL/crypto/digest/digest.c @@ -60,10 +60,10 @@ #include #include -#include #include #include "internal.h" +#include "../internal.h" int EVP_MD_type(const EVP_MD *md) { return md->type; } @@ -75,7 +75,9 @@ size_t EVP_MD_size(const EVP_MD *md) { return md->md_size; } size_t EVP_MD_block_size(const EVP_MD *md) { return md->block_size; } -void EVP_MD_CTX_init(EVP_MD_CTX *ctx) { memset(ctx, 0, sizeof(EVP_MD_CTX)); } +void EVP_MD_CTX_init(EVP_MD_CTX *ctx) { + OPENSSL_memset(ctx, 0, sizeof(EVP_MD_CTX)); +} EVP_MD_CTX *EVP_MD_CTX_create(void) { EVP_MD_CTX *ctx = OPENSSL_malloc(sizeof(EVP_MD_CTX)); @@ -141,7 +143,7 @@ int EVP_MD_CTX_copy_ex(EVP_MD_CTX *out, const EVP_MD_CTX *in) { return 0; } } - memcpy(out->md_data, in->md_data, in->digest->ctx_size); + OPENSSL_memcpy(out->md_data, in->md_data, in->digest->ctx_size); } assert(in->pctx == NULL || in->pctx_ops != NULL); @@ -166,6 +168,7 @@ int EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *engine) { if (ctx->digest != type) { if (ctx->digest && ctx->digest->ctx_size > 0) { OPENSSL_free(ctx->md_data); + ctx->md_data = NULL; } ctx->digest = type; if (type->ctx_size > 0) { @@ -231,11 +234,11 @@ const EVP_MD *EVP_MD_CTX_md(const EVP_MD_CTX *ctx) { return ctx->digest; } -unsigned EVP_MD_CTX_size(const EVP_MD_CTX *ctx) { +size_t EVP_MD_CTX_size(const EVP_MD_CTX *ctx) { return EVP_MD_size(EVP_MD_CTX_md(ctx)); } -unsigned EVP_MD_CTX_block_size(const EVP_MD_CTX *ctx) { +size_t EVP_MD_CTX_block_size(const EVP_MD_CTX *ctx) { return EVP_MD_block_size(EVP_MD_CTX_md(ctx)); } diff --git a/Sources/BoringSSL/crypto/digest/digests.c b/Sources/BoringSSL/crypto/digest/digests.c index 3307f2656..fd2a939ab 100644 --- a/Sources/BoringSSL/crypto/digest/digests.c +++ b/Sources/BoringSSL/crypto/digest/digests.c @@ -59,12 +59,14 @@ #include #include +#include #include #include -#include +#include #include #include "internal.h" +#include "../internal.h" #if defined(NDEBUG) #define CHECK(x) (void) (x) @@ -262,36 +264,41 @@ struct nid_to_digest { }; static const struct nid_to_digest nid_to_digest_mapping[] = { - { NID_md4, EVP_md4, SN_md4, LN_md4 }, - { NID_md5, EVP_md5, SN_md5, LN_md5 }, - { NID_sha1, EVP_sha1, SN_sha1, LN_sha1 }, - { NID_sha224, EVP_sha224, SN_sha224, LN_sha224 }, - { NID_sha256, EVP_sha256, SN_sha256, LN_sha256 }, - { NID_sha384, EVP_sha384, SN_sha384, LN_sha384 }, - { NID_sha512, EVP_sha512, SN_sha512, LN_sha512 }, - { NID_md5_sha1, EVP_md5_sha1, SN_md5_sha1, LN_md5_sha1 }, - { NID_dsaWithSHA, EVP_sha1, SN_dsaWithSHA, LN_dsaWithSHA }, - { NID_dsaWithSHA1, EVP_sha1, SN_dsaWithSHA1, LN_dsaWithSHA1 }, - { NID_ecdsa_with_SHA1, EVP_sha1, SN_ecdsa_with_SHA1, NULL }, - { NID_md5WithRSAEncryption, EVP_md5, SN_md5WithRSAEncryption, - LN_md5WithRSAEncryption }, - { NID_sha1WithRSAEncryption, EVP_sha1, SN_sha1WithRSAEncryption, - LN_sha1WithRSAEncryption }, - { NID_sha224WithRSAEncryption, EVP_sha224, SN_sha224WithRSAEncryption, - LN_sha224WithRSAEncryption }, - { NID_sha256WithRSAEncryption, EVP_sha256, SN_sha256WithRSAEncryption, - LN_sha256WithRSAEncryption }, - { NID_sha384WithRSAEncryption, EVP_sha384, SN_sha384WithRSAEncryption, - LN_sha384WithRSAEncryption }, - { NID_sha512WithRSAEncryption, EVP_sha512, SN_sha512WithRSAEncryption, - LN_sha512WithRSAEncryption }, + {NID_md4, EVP_md4, SN_md4, LN_md4}, + {NID_md5, EVP_md5, SN_md5, LN_md5}, + {NID_sha1, EVP_sha1, SN_sha1, LN_sha1}, + {NID_sha224, EVP_sha224, SN_sha224, LN_sha224}, + {NID_sha256, EVP_sha256, SN_sha256, LN_sha256}, + {NID_sha384, EVP_sha384, SN_sha384, LN_sha384}, + {NID_sha512, EVP_sha512, SN_sha512, LN_sha512}, + {NID_md5_sha1, EVP_md5_sha1, SN_md5_sha1, LN_md5_sha1}, + /* As a remnant of signing |EVP_MD|s, OpenSSL returned the corresponding + * hash function when given a signature OID. To avoid unintended lax parsing + * of hash OIDs, this is no longer supported for lookup by OID or NID. + * Node.js, however, exposes |EVP_get_digestbyname|'s full behavior to + * consumers so we retain it there. */ + {NID_undef, EVP_sha1, SN_dsaWithSHA, LN_dsaWithSHA}, + {NID_undef, EVP_sha1, SN_dsaWithSHA1, LN_dsaWithSHA1}, + {NID_undef, EVP_sha1, SN_ecdsa_with_SHA1, NULL}, + {NID_undef, EVP_md5, SN_md5WithRSAEncryption, LN_md5WithRSAEncryption}, + {NID_undef, EVP_sha1, SN_sha1WithRSAEncryption, LN_sha1WithRSAEncryption}, + {NID_undef, EVP_sha224, SN_sha224WithRSAEncryption, + LN_sha224WithRSAEncryption}, + {NID_undef, EVP_sha256, SN_sha256WithRSAEncryption, + LN_sha256WithRSAEncryption}, + {NID_undef, EVP_sha384, SN_sha384WithRSAEncryption, + LN_sha384WithRSAEncryption}, + {NID_undef, EVP_sha512, SN_sha512WithRSAEncryption, + LN_sha512WithRSAEncryption}, }; const EVP_MD* EVP_get_digestbynid(int nid) { - unsigned i; + if (nid == NID_undef) { + /* Skip the |NID_undef| entries in |nid_to_digest_mapping|. */ + return NULL; + } - for (i = 0; i < sizeof(nid_to_digest_mapping) / sizeof(struct nid_to_digest); - i++) { + for (unsigned i = 0; i < OPENSSL_ARRAY_SIZE(nid_to_digest_mapping); i++) { if (nid_to_digest_mapping[i].nid == nid) { return nid_to_digest_mapping[i].md_func(); } @@ -300,15 +307,45 @@ const EVP_MD* EVP_get_digestbynid(int nid) { return NULL; } -const EVP_MD* EVP_get_digestbyobj(const ASN1_OBJECT *obj) { - return EVP_get_digestbynid(OBJ_obj2nid(obj)); +static const struct { + uint8_t oid[9]; + uint8_t oid_len; + const EVP_MD *(*md_func) (void); +} kMDOIDs[] = { + /* 1.2.840.113549.2.4 */ + { {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x04}, 8, EVP_md4 }, + /* 1.2.840.113549.2.5 */ + { {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05}, 8, EVP_md5 }, + /* 1.3.14.3.2.26 */ + { {0x2b, 0x0e, 0x03, 0x02, 0x1a}, 5, EVP_sha1 }, + /* 2.16.840.1.101.3.4.2.1 */ + { {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01}, 9, EVP_sha256 }, + /* 2.16.840.1.101.3.4.2.2 */ + { {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02}, 9, EVP_sha384 }, + /* 2.16.840.1.101.3.4.2.3 */ + { {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03}, 9, EVP_sha512 }, + /* 2.16.840.1.101.3.4.2.4 */ + { {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04}, 9, EVP_sha224 }, +}; + +const EVP_MD *EVP_get_digestbyobj(const ASN1_OBJECT *obj) { + /* Handle objects with no corresponding OID. */ + if (obj->nid != NID_undef) { + return EVP_get_digestbynid(obj->nid); + } + + for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(kMDOIDs); i++) { + if (obj->length == kMDOIDs[i].oid_len && + memcmp(obj->data, kMDOIDs[i].oid, obj->length) == 0) { + return kMDOIDs[i].md_func(); + } + } + + return NULL; } const EVP_MD *EVP_get_digestbyname(const char *name) { - unsigned i; - - for (i = 0; i < sizeof(nid_to_digest_mapping) / sizeof(struct nid_to_digest); - i++) { + for (unsigned i = 0; i < OPENSSL_ARRAY_SIZE(nid_to_digest_mapping); i++) { const char *short_name = nid_to_digest_mapping[i].short_name; const char *long_name = nid_to_digest_mapping[i].long_name; if ((short_name && strcmp(short_name, name) == 0) || diff --git a/Sources/BoringSSL/crypto/digest/md32_common.h b/Sources/BoringSSL/crypto/digest/md32_common.h index 4cf050cae..45fe93951 100644 --- a/Sources/BoringSSL/crypto/digest/md32_common.h +++ b/Sources/BoringSSL/crypto/digest/md32_common.h @@ -53,6 +53,8 @@ #include +#include "../internal.h" + #if defined(__cplusplus) extern "C" { #endif @@ -140,29 +142,39 @@ extern "C" { #if defined(DATA_ORDER_IS_BIG_ENDIAN) -#define HOST_c2l(c, l) \ - (void)(l = (((uint32_t)(*((c)++))) << 24), \ - l |= (((uint32_t)(*((c)++))) << 16), \ - l |= (((uint32_t)(*((c)++))) << 8), l |= (((uint32_t)(*((c)++))))) - -#define HOST_l2c(l, c) \ - (void)(*((c)++) = (uint8_t)(((l) >> 24) & 0xff), \ - *((c)++) = (uint8_t)(((l) >> 16) & 0xff), \ - *((c)++) = (uint8_t)(((l) >> 8) & 0xff), \ - *((c)++) = (uint8_t)(((l)) & 0xff)) +#define HOST_c2l(c, l) \ + do { \ + (l) = (((uint32_t)(*((c)++))) << 24); \ + (l) |= (((uint32_t)(*((c)++))) << 16); \ + (l) |= (((uint32_t)(*((c)++))) << 8); \ + (l) |= (((uint32_t)(*((c)++)))); \ + } while (0) + +#define HOST_l2c(l, c) \ + do { \ + *((c)++) = (uint8_t)(((l) >> 24) & 0xff); \ + *((c)++) = (uint8_t)(((l) >> 16) & 0xff); \ + *((c)++) = (uint8_t)(((l) >> 8) & 0xff); \ + *((c)++) = (uint8_t)(((l)) & 0xff); \ + } while (0) #elif defined(DATA_ORDER_IS_LITTLE_ENDIAN) -#define HOST_c2l(c, l) \ - (void)(l = (((uint32_t)(*((c)++)))), l |= (((uint32_t)(*((c)++))) << 8), \ - l |= (((uint32_t)(*((c)++))) << 16), \ - l |= (((uint32_t)(*((c)++))) << 24)) - -#define HOST_l2c(l, c) \ - (void)(*((c)++) = (uint8_t)(((l)) & 0xff), \ - *((c)++) = (uint8_t)(((l) >> 8) & 0xff), \ - *((c)++) = (uint8_t)(((l) >> 16) & 0xff), \ - *((c)++) = (uint8_t)(((l) >> 24) & 0xff)) +#define HOST_c2l(c, l) \ + do { \ + (l) = (((uint32_t)(*((c)++)))); \ + (l) |= (((uint32_t)(*((c)++))) << 8); \ + (l) |= (((uint32_t)(*((c)++))) << 16); \ + (l) |= (((uint32_t)(*((c)++))) << 24); \ + } while (0) + +#define HOST_l2c(l, c) \ + do { \ + *((c)++) = (uint8_t)(((l)) & 0xff); \ + *((c)++) = (uint8_t)(((l) >> 8) & 0xff); \ + *((c)++) = (uint8_t)(((l) >> 16) & 0xff); \ + *((c)++) = (uint8_t)(((l) >> 24) & 0xff); \ + } while (0) #endif /* DATA_ORDER */ @@ -184,16 +196,16 @@ int HASH_UPDATE(HASH_CTX *c, const void *data_, size_t len) { size_t n = c->num; if (n != 0) { if (len >= HASH_CBLOCK || len + n >= HASH_CBLOCK) { - memcpy(c->data + n, data, HASH_CBLOCK - n); + OPENSSL_memcpy(c->data + n, data, HASH_CBLOCK - n); HASH_BLOCK_DATA_ORDER(c->h, c->data, 1); n = HASH_CBLOCK - n; data += n; len -= n; c->num = 0; /* Keep |c->data| zeroed when unused. */ - memset(c->data, 0, HASH_CBLOCK); + OPENSSL_memset(c->data, 0, HASH_CBLOCK); } else { - memcpy(c->data + n, data, len); + OPENSSL_memcpy(c->data + n, data, len); c->num += (unsigned)len; return 1; } @@ -209,7 +221,7 @@ int HASH_UPDATE(HASH_CTX *c, const void *data_, size_t len) { if (len != 0) { c->num = (unsigned)len; - memcpy(c->data, data, len); + OPENSSL_memcpy(c->data, data, len); } return 1; } @@ -230,11 +242,11 @@ int HASH_FINAL(uint8_t *md, HASH_CTX *c) { /* Fill the block with zeros if there isn't room for a 64-bit length. */ if (n > (HASH_CBLOCK - 8)) { - memset(c->data + n, 0, HASH_CBLOCK - n); + OPENSSL_memset(c->data + n, 0, HASH_CBLOCK - n); n = 0; HASH_BLOCK_DATA_ORDER(c->h, c->data, 1); } - memset(c->data + n, 0, HASH_CBLOCK - 8 - n); + OPENSSL_memset(c->data + n, 0, HASH_CBLOCK - 8 - n); /* Append a 64-bit length to the block and process it. */ uint8_t *p = c->data + HASH_CBLOCK - 8; @@ -248,7 +260,7 @@ int HASH_FINAL(uint8_t *md, HASH_CTX *c) { assert(p == c->data + HASH_CBLOCK); HASH_BLOCK_DATA_ORDER(c->h, c->data, 1); c->num = 0; - memset(c->data, 0, HASH_CBLOCK); + OPENSSL_memset(c->data, 0, HASH_CBLOCK); HASH_MAKE_STRING(c, md); return 1; diff --git a/Sources/BoringSSL/crypto/directory.h b/Sources/BoringSSL/crypto/directory.h deleted file mode 100644 index 29123ea9d..000000000 --- a/Sources/BoringSSL/crypto/directory.h +++ /dev/null @@ -1,66 +0,0 @@ -/* Copied from Richard Levitte's (richard@levitte.org) LP library. All - * symbol names have been changed, with permission from the author. */ - -/* $LP: LPlib/source/LPdir.h,v 1.1 2004/06/14 08:56:04 _cvs_levitte Exp $ */ -/* - * Copyright (c) 2004, Richard Levitte - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef OPENSSL_HEADER_DIRECTORY_H -#define OPENSSL_HEADER_DIRECTORY_H - -#include - -#if defined(__cplusplus) -extern "C" { -#endif - - -/* Directory functions abstract the O/S specific operations for opening and - * reading directories in the filesystem. */ - - -/* OPENSSL_dir_context_st is an opaque structure that represents an open - * directory and a position in that directory. */ -typedef struct OPENSSL_dir_context_st OPENSSL_DIR_CTX; - -/* OPENSSL_DIR_read reads a single filename from |ctx|. On the first call, - * |directory| must be given and |*ctx| must be NULL. Subsequent calls with the - * same |*ctx| will return subsequent file names until it returns NULL to - * indicate EOF. The strings returned reference a buffer internal to the - * |OPENSSL_DIR_CTX| and will be overridden by subsequent calls. */ -OPENSSL_EXPORT const char *OPENSSL_DIR_read(OPENSSL_DIR_CTX **ctx, - const char *directory); - -/* OPENSSL_DIR_end closes |*ctx|. It returns one on success and zero on - * error. */ -OPENSSL_EXPORT int OPENSSL_DIR_end(OPENSSL_DIR_CTX **ctx); - - -#if defined(__cplusplus) -} /* extern C */ -#endif - -#endif /* OPENSSL_HEADER_DIRECTORY_H */ diff --git a/Sources/BoringSSL/crypto/directory_posix.c b/Sources/BoringSSL/crypto/directory_posix.c deleted file mode 100644 index b944b6920..000000000 --- a/Sources/BoringSSL/crypto/directory_posix.c +++ /dev/null @@ -1,108 +0,0 @@ -/* $LP: LPlib/source/LPdir_unix.c,v 1.11 2004/09/23 22:07:22 _cvs_levitte Exp $ */ -/* - * Copyright (c) 2004, Richard Levitte - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - -#if !defined(_POSIX_C_SOURCE) -#define _POSIX_C_SOURCE 201409 /* for readdir_r */ -#endif - -#include "directory.h" - - -#if !defined(OPENSSL_WINDOWS) - -#include -#include -#include -#include - -#if defined(OPENSSL_PNACL) -/* pnacl doesn't include readdir_r! So we do the best we can. */ -int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result) { - errno = 0; - *result = readdir(dirp); - if (*result != NULL) { - return 0; - } - if (errno) { - return 1; - } - return 0; -} -#endif - -struct OPENSSL_dir_context_st { - DIR *dir; - struct dirent dirent; -}; - -const char *OPENSSL_DIR_read(OPENSSL_DIR_CTX **ctx, const char *directory) { - struct dirent *dirent; - - if (ctx == NULL || directory == NULL) { - errno = EINVAL; - return NULL; - } - - errno = 0; - if (*ctx == NULL) { - *ctx = malloc(sizeof(OPENSSL_DIR_CTX)); - if (*ctx == NULL) { - errno = ENOMEM; - return 0; - } - memset(*ctx, 0, sizeof(OPENSSL_DIR_CTX)); - - (*ctx)->dir = opendir(directory); - if ((*ctx)->dir == NULL) { - int save_errno = errno; /* Probably not needed, but I'm paranoid */ - free(*ctx); - *ctx = NULL; - errno = save_errno; - return 0; - } - } - - if (readdir_r((*ctx)->dir, &(*ctx)->dirent, &dirent) != 0 || - dirent == NULL) { - return 0; - } - - return (*ctx)->dirent.d_name; -} - -int OPENSSL_DIR_end(OPENSSL_DIR_CTX **ctx) { - if (ctx != NULL && *ctx != NULL) { - int r = closedir((*ctx)->dir); - free(*ctx); - *ctx = NULL; - return r == 0; - } - - errno = EINVAL; - return 0; -} - -#endif /* !OPENSSL_WINDOWS */ diff --git a/Sources/BoringSSL/crypto/directory_win.c b/Sources/BoringSSL/crypto/directory_win.c deleted file mode 100644 index 4ebacf216..000000000 --- a/Sources/BoringSSL/crypto/directory_win.c +++ /dev/null @@ -1,144 +0,0 @@ -/* $LP: LPlib/source/LPdir_win.c,v 1.10 2004/08/26 13:36:05 _cvs_levitte Exp $ */ -/* - * Copyright (c) 2004, Richard Levitte - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "directory.h" - - -#if defined(OPENSSL_WINDOWS) - -#pragma warning(push, 3) -#include -#pragma warning(pop) -#include -#include -#include - -#ifndef NAME_MAX -#define NAME_MAX 255 -#endif - -#include - - -struct OPENSSL_dir_context_st { - WIN32_FIND_DATA ctx; - HANDLE handle; - char entry_name[NAME_MAX + 1]; -}; - -const char *OPENSSL_DIR_read(OPENSSL_DIR_CTX **ctx, const char *directory) { - if (ctx == NULL || directory == NULL) { - errno = EINVAL; - return 0; - } - - errno = 0; - if (*ctx == NULL) { - *ctx = malloc(sizeof(OPENSSL_DIR_CTX)); - if (*ctx == NULL) { - errno = ENOMEM; - return 0; - } - memset(*ctx, 0, sizeof(OPENSSL_DIR_CTX)); - - if (sizeof(TCHAR) != sizeof(char)) { - TCHAR *wdir = NULL; - /* len_0 denotes string length *with* trailing 0 */ - size_t index = 0, len_0 = strlen(directory) + 1; - - wdir = (TCHAR *)malloc(len_0 * sizeof(TCHAR)); - if (wdir == NULL) { - free(*ctx); - *ctx = NULL; - errno = ENOMEM; - return 0; - } - - if (!MultiByteToWideChar(CP_ACP, 0, directory, len_0, (WCHAR *)wdir, - len_0)) { - for (index = 0; index < len_0; index++) { - wdir[index] = (TCHAR)directory[index]; - } - } - - (*ctx)->handle = FindFirstFile(wdir, &(*ctx)->ctx); - - free(wdir); - } else { - (*ctx)->handle = FindFirstFile((TCHAR *)directory, &(*ctx)->ctx); - } - - if ((*ctx)->handle == INVALID_HANDLE_VALUE) { - free(*ctx); - *ctx = NULL; - errno = EINVAL; - return 0; - } - } else { - if (FindNextFile((*ctx)->handle, &(*ctx)->ctx) == FALSE) { - return 0; - } - } - - if (sizeof(TCHAR) != sizeof(char)) { - TCHAR *wdir = (*ctx)->ctx.cFileName; - size_t index, len_0 = 0; - - while (wdir[len_0] && len_0 < (sizeof((*ctx)->entry_name) - 1)) { - len_0++; - } - len_0++; - - if (!WideCharToMultiByte(CP_ACP, 0, (WCHAR *)wdir, len_0, - (*ctx)->entry_name, sizeof((*ctx)->entry_name), - NULL, 0)) { - for (index = 0; index < len_0; index++) { - (*ctx)->entry_name[index] = (char)wdir[index]; - } - } - } else { - strncpy((*ctx)->entry_name, (const char *)(*ctx)->ctx.cFileName, - sizeof((*ctx)->entry_name) - 1); - } - - (*ctx)->entry_name[sizeof((*ctx)->entry_name) - 1] = '\0'; - - return (*ctx)->entry_name; -} - -int OPENSSL_DIR_end(OPENSSL_DIR_CTX **ctx) { - if (ctx != NULL && *ctx != NULL) { - FindClose((*ctx)->handle); - free(*ctx); - *ctx = NULL; - return 1; - } - errno = EINVAL; - return 0; -} - -#endif /* OPENSSL_WINDOWS */ diff --git a/Sources/BoringSSL/crypto/dsa/dsa.c b/Sources/BoringSSL/crypto/dsa/dsa.c index 979079d89..e2b6695e8 100644 --- a/Sources/BoringSSL/crypto/dsa/dsa.c +++ b/Sources/BoringSSL/crypto/dsa/dsa.c @@ -72,6 +72,7 @@ #include #include +#include "../bn/internal.h" #include "../internal.h" @@ -90,11 +91,11 @@ DSA *DSA_new(void) { return NULL; } - memset(dsa, 0, sizeof(DSA)); + OPENSSL_memset(dsa, 0, sizeof(DSA)); dsa->references = 1; - CRYPTO_MUTEX_init(&dsa->method_mont_p_lock); + CRYPTO_MUTEX_init(&dsa->method_mont_lock); CRYPTO_new_ex_data(&dsa->ex_data); return dsa; @@ -119,7 +120,8 @@ void DSA_free(DSA *dsa) { BN_clear_free(dsa->kinv); BN_clear_free(dsa->r); BN_MONT_CTX_free(dsa->method_mont_p); - CRYPTO_MUTEX_cleanup(&dsa->method_mont_p_lock); + BN_MONT_CTX_free(dsa->method_mont_q); + CRYPTO_MUTEX_cleanup(&dsa->method_mont_lock); OPENSSL_free(dsa); } @@ -128,6 +130,29 @@ int DSA_up_ref(DSA *dsa) { return 1; } +void DSA_get0_key(const DSA *dsa, const BIGNUM **out_pub_key, + const BIGNUM **out_priv_key) { + if (out_pub_key != NULL) { + *out_pub_key = dsa->pub_key; + } + if (out_priv_key != NULL) { + *out_priv_key = dsa->priv_key; + } +} + +void DSA_get0_pqg(const DSA *dsa, const BIGNUM **out_p, const BIGNUM **out_q, + const BIGNUM **out_g) { + if (out_p != NULL) { + *out_p = dsa->p; + } + if (out_q != NULL) { + *out_q = dsa->q; + } + if (out_g != NULL) { + *out_g = dsa->g; + } +} + int DSA_generate_parameters_ex(DSA *dsa, unsigned bits, const uint8_t *seed_in, size_t seed_len, int *out_counter, unsigned long *out_h, BN_GENCB *cb) { @@ -164,7 +189,7 @@ int DSA_generate_parameters_ex(DSA *dsa, unsigned bits, const uint8_t *seed_in, /* Only consume as much seed as is expected. */ seed_len = qsize; } - memcpy(seed, seed_in, seed_len); + OPENSSL_memcpy(seed, seed_in, seed_len); } ctx = BN_CTX_new(); @@ -208,8 +233,8 @@ int DSA_generate_parameters_ex(DSA *dsa, unsigned bits, const uint8_t *seed_in, /* If we come back through, use random seed next time. */ seed_in = NULL; } - memcpy(buf, seed, qsize); - memcpy(buf2, seed, qsize); + OPENSSL_memcpy(buf, seed, qsize); + OPENSSL_memcpy(buf2, seed, qsize); /* precompute "SEED + 1" for step 7: */ for (i = qsize - 1; i < qsize; i--) { buf[i]++; @@ -409,7 +434,6 @@ int DSA_generate_key(DSA *dsa) { int ok = 0; BN_CTX *ctx = NULL; BIGNUM *pub_key = NULL, *priv_key = NULL; - BIGNUM prk; ctx = BN_CTX_new(); if (ctx == NULL) { @@ -424,11 +448,9 @@ int DSA_generate_key(DSA *dsa) { } } - do { - if (!BN_rand_range(priv_key, dsa->q)) { - goto err; - } - } while (BN_is_zero(priv_key)); + if (!BN_rand_range_ex(priv_key, 1, dsa->q)) { + goto err; + } pub_key = dsa->pub_key; if (pub_key == NULL) { @@ -438,10 +460,10 @@ int DSA_generate_key(DSA *dsa) { } } - BN_init(&prk); - BN_with_flags(&prk, priv_key, BN_FLG_CONSTTIME); - - if (!BN_mod_exp(pub_key, dsa->g, &prk, dsa->p, ctx)) { + if (!BN_MONT_CTX_set_locked(&dsa->method_mont_p, &dsa->method_mont_lock, + dsa->p, ctx) || + !BN_mod_exp_mont_consttime(pub_key, dsa->g, priv_key, dsa->p, ctx, + dsa->method_mont_p)) { goto err; } @@ -591,7 +613,6 @@ int DSA_do_check_signature(int *out_valid, const uint8_t *digest, size_t digest_len, DSA_SIG *sig, const DSA *dsa) { BN_CTX *ctx; BIGNUM u1, u2, t1; - BN_MONT_CTX *mont = NULL; int ret = 0; unsigned i; @@ -662,15 +683,14 @@ int DSA_do_check_signature(int *out_valid, const uint8_t *digest, goto err; } - mont = BN_MONT_CTX_set_locked((BN_MONT_CTX **)&dsa->method_mont_p, - (CRYPTO_MUTEX *)&dsa->method_mont_p_lock, - dsa->p, ctx); - if (!mont) { + if (!BN_MONT_CTX_set_locked((BN_MONT_CTX **)&dsa->method_mont_p, + (CRYPTO_MUTEX *)&dsa->method_mont_lock, dsa->p, + ctx)) { goto err; } if (!BN_mod_exp2_mont(&t1, dsa->g, &u1, dsa->pub_key, &u2, dsa->p, ctx, - mont)) { + dsa->method_mont_p)) { goto err; } @@ -740,7 +760,8 @@ int DSA_check_signature(int *out_valid, const uint8_t *digest, /* Ensure that the signature uses DER and doesn't have trailing garbage. */ int der_len = i2d_DSA_SIG(s, &der); - if (der_len < 0 || (size_t)der_len != sig_len || memcmp(sig, der, sig_len)) { + if (der_len < 0 || (size_t)der_len != sig_len || + OPENSSL_memcmp(sig, der, sig_len)) { goto err; } @@ -790,7 +811,7 @@ int DSA_size(const DSA *dsa) { int DSA_sign_setup(const DSA *dsa, BN_CTX *ctx_in, BIGNUM **out_kinv, BIGNUM **out_r) { BN_CTX *ctx; - BIGNUM k, kq, *K, *kinv = NULL, *r = NULL; + BIGNUM k, kq, *kinv = NULL, *r = NULL; int ret = 0; if (!dsa->p || !dsa->q || !dsa->g) { @@ -815,17 +836,16 @@ int DSA_sign_setup(const DSA *dsa, BN_CTX *ctx_in, BIGNUM **out_kinv, } /* Get random k */ - do { - if (!BN_rand_range(&k, dsa->q)) { - goto err; - } - } while (BN_is_zero(&k)); - - BN_set_flags(&k, BN_FLG_CONSTTIME); + if (!BN_rand_range_ex(&k, 1, dsa->q)) { + goto err; + } - if (BN_MONT_CTX_set_locked((BN_MONT_CTX **)&dsa->method_mont_p, - (CRYPTO_MUTEX *)&dsa->method_mont_p_lock, dsa->p, - ctx) == NULL) { + if (!BN_MONT_CTX_set_locked((BN_MONT_CTX **)&dsa->method_mont_p, + (CRYPTO_MUTEX *)&dsa->method_mont_lock, dsa->p, + ctx) || + !BN_MONT_CTX_set_locked((BN_MONT_CTX **)&dsa->method_mont_q, + (CRYPTO_MUTEX *)&dsa->method_mont_lock, dsa->q, + ctx)) { goto err; } @@ -847,18 +867,19 @@ int DSA_sign_setup(const DSA *dsa, BN_CTX *ctx_in, BIGNUM **out_kinv, goto err; } - K = &kq; - - if (!BN_mod_exp_mont(r, dsa->g, K, dsa->p, ctx, dsa->method_mont_p)) { + if (!BN_mod_exp_mont_consttime(r, dsa->g, &kq, dsa->p, ctx, + dsa->method_mont_p)) { goto err; } if (!BN_mod(r, r, dsa->q, ctx)) { goto err; } - /* Compute part of 's = inv(k) (m + xr) mod q' */ - kinv = BN_mod_inverse(NULL, &k, dsa->q, ctx); - if (kinv == NULL) { + /* Compute part of 's = inv(k) (m + xr) mod q' using Fermat's Little + * Theorem. */ + kinv = BN_new(); + if (kinv == NULL || + !bn_mod_inverse_prime(kinv, &k, dsa->q, ctx, dsa->method_mont_q)) { goto err; } @@ -882,6 +903,7 @@ int DSA_sign_setup(const DSA *dsa, BN_CTX *ctx_in, BIGNUM **out_kinv, } BN_clear_free(&k); BN_clear_free(&kq); + BN_clear_free(kinv); return ret; } diff --git a/Sources/BoringSSL/crypto/dsa/dsa_asn1.c b/Sources/BoringSSL/crypto/dsa/dsa_asn1.c index 7615fca2b..ff5ee0039 100644 --- a/Sources/BoringSSL/crypto/dsa/dsa_asn1.c +++ b/Sources/BoringSSL/crypto/dsa/dsa_asn1.c @@ -248,6 +248,7 @@ int i2d_DSA_SIG(const DSA_SIG *in, uint8_t **outp) { CBB cbb; if (!CBB_init(&cbb, 0) || !DSA_SIG_marshal(&cbb, in)) { + CBB_cleanup(&cbb); return -1; } return CBB_finish_i2d(&cbb, outp); @@ -275,6 +276,7 @@ int i2d_DSAPublicKey(const DSA *in, uint8_t **outp) { CBB cbb; if (!CBB_init(&cbb, 0) || !DSA_marshal_public_key(&cbb, in)) { + CBB_cleanup(&cbb); return -1; } return CBB_finish_i2d(&cbb, outp); @@ -302,6 +304,7 @@ int i2d_DSAPrivateKey(const DSA *in, uint8_t **outp) { CBB cbb; if (!CBB_init(&cbb, 0) || !DSA_marshal_private_key(&cbb, in)) { + CBB_cleanup(&cbb); return -1; } return CBB_finish_i2d(&cbb, outp); @@ -329,6 +332,7 @@ int i2d_DSAparams(const DSA *in, uint8_t **outp) { CBB cbb; if (!CBB_init(&cbb, 0) || !DSA_marshal_parameters(&cbb, in)) { + CBB_cleanup(&cbb); return -1; } return CBB_finish_i2d(&cbb, outp); diff --git a/Sources/BoringSSL/crypto/ec/ec.c b/Sources/BoringSSL/crypto/ec/ec.c index ca3ce373a..96bb70370 100644 --- a/Sources/BoringSSL/crypto/ec/ec.c +++ b/Sources/BoringSSL/crypto/ec/ec.c @@ -73,7 +73,7 @@ #include #include #include -#include +#include #include "internal.h" #include "../internal.h" @@ -82,7 +82,6 @@ static const struct curve_data P224 = { "NIST P-224", 28, - 1, {/* p */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -112,7 +111,6 @@ static const struct curve_data P224 = { static const struct curve_data P256 = { "NIST P-256", 32, - 1, {/* p */ 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, @@ -141,7 +139,6 @@ static const struct curve_data P256 = { static const struct curve_data P384 = { "NIST P-384", 48, - 1, {/* p */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, @@ -176,7 +173,6 @@ static const struct curve_data P384 = { static const struct curve_data P521 = { "NIST P-521", 66, - 1, {/* p */ 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, @@ -228,30 +224,48 @@ static const struct curve_data P521 = { #endif const struct built_in_curve OPENSSL_built_in_curves[] = { - {NID_secp521r1, &P521, 0}, - {NID_secp384r1, &P384, 0}, { - NID_X9_62_prime256v1, &P256, + NID_secp521r1, + /* 1.3.132.0.35 */ + {0x2b, 0x81, 0x04, 0x00, 0x23}, 5, + &P521, + &EC_GFp_mont_method, + }, + { + NID_secp384r1, + /* 1.3.132.0.34 */ + {0x2b, 0x81, 0x04, 0x00, 0x22}, 5, + &P384, + &EC_GFp_mont_method, + }, + { + NID_X9_62_prime256v1, + /* 1.2.840.10045.3.1.7 */ + {0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07}, 8, + &P256, #if defined(BORINGSSL_USE_INT128_CODE) #if !defined(OPENSSL_NO_ASM) && defined(OPENSSL_X86_64) && \ !defined(OPENSSL_SMALL) - EC_GFp_nistz256_method, + &EC_GFp_nistz256_method, #else - EC_GFp_nistp256_method, + &EC_GFp_nistp256_method, #endif #else - 0, + &EC_GFp_mont_method, #endif }, { - NID_secp224r1, &P224, + NID_secp224r1, + /* 1.3.132.0.33 */ + {0x2b, 0x81, 0x04, 0x00, 0x21}, 5, + &P224, #if defined(BORINGSSL_USE_INT128_CODE) && !defined(OPENSSL_SMALL) - EC_GFp_nistp224_method, + &EC_GFp_nistp224_method, #else - 0, + &EC_GFp_mont_method, #endif }, - {NID_undef, 0, 0}, + {NID_undef, {0}, 0, NULL, NULL}, }; /* built_in_curve_scalar_field_monts contains Montgomery contexts for @@ -336,11 +350,10 @@ EC_GROUP *ec_group_new(const EC_METHOD *meth) { OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE); return NULL; } - memset(ret, 0, sizeof(EC_GROUP)); + OPENSSL_memset(ret, 0, sizeof(EC_GROUP)); ret->meth = meth; BN_init(&ret->order); - BN_init(&ret->cofactor); if (!meth->group_init(ret)) { OPENSSL_free(ret); @@ -350,12 +363,9 @@ EC_GROUP *ec_group_new(const EC_METHOD *meth) { return ret; } -static EC_GROUP *ec_group_new_curve_GFp(const BIGNUM *p, const BIGNUM *a, - const BIGNUM *b, BN_CTX *ctx) { - const EC_METHOD *meth = EC_GFp_mont_method(); - EC_GROUP *ret; - - ret = ec_group_new(meth); +EC_GROUP *EC_GROUP_new_curve_GFp(const BIGNUM *p, const BIGNUM *a, + const BIGNUM *b, BN_CTX *ctx) { + EC_GROUP *ret = ec_group_new(&EC_GFp_mont_method); if (ret == NULL) { return NULL; } @@ -371,38 +381,24 @@ static EC_GROUP *ec_group_new_curve_GFp(const BIGNUM *p, const BIGNUM *a, return ret; } -EC_GROUP *EC_GROUP_new_arbitrary(const BIGNUM *p, const BIGNUM *a, - const BIGNUM *b, const BIGNUM *gx, - const BIGNUM *gy, const BIGNUM *order, - const BIGNUM *cofactor) { - EC_GROUP *ret = NULL; - BN_CTX *ctx; - - ctx = BN_CTX_new(); - if (ctx == NULL) { - goto err; - } - - ret = ec_group_new_curve_GFp(p, a, b, ctx); - if (ret == NULL) { - goto err; +int EC_GROUP_set_generator(EC_GROUP *group, const EC_POINT *generator, + const BIGNUM *order, const BIGNUM *cofactor) { + if (group->curve_name != NID_undef || group->generator != NULL) { + /* |EC_GROUP_set_generator| may only be used with |EC_GROUP|s returned by + * |EC_GROUP_new_curve_GFp| and may only used once on each group. */ + return 0; } - ret->generator = EC_POINT_new(ret); - if (ret->generator == NULL || - !EC_POINT_set_affine_coordinates_GFp(ret, ret->generator, gx, gy, ctx) || - !BN_copy(&ret->order, order) || - !BN_copy(&ret->cofactor, cofactor)) { - goto err; + /* Require a cofactor of one for custom curves, which implies prime order. */ + if (!BN_is_one(cofactor)) { + OPENSSL_PUT_ERROR(EC, EC_R_INVALID_COFACTOR); + return 0; } - BN_CTX_free(ctx); - return ret; - -err: - EC_GROUP_free(ret); - BN_CTX_free(ctx); - return NULL; + group->generator = EC_POINT_new(group); + return group->generator != NULL && + EC_POINT_copy(group->generator, generator) && + BN_copy(&group->order, order); } static EC_GROUP *ec_group_new_from_data(unsigned built_in_index) { @@ -410,7 +406,6 @@ static EC_GROUP *ec_group_new_from_data(unsigned built_in_index) { EC_GROUP *group = NULL; EC_POINT *P = NULL; BIGNUM *p = NULL, *a = NULL, *b = NULL, *x = NULL, *y = NULL; - const EC_METHOD *meth; int ok = 0; BN_CTX *ctx = BN_CTX_new(); @@ -430,18 +425,11 @@ static EC_GROUP *ec_group_new_from_data(unsigned built_in_index) { goto err; } - if (curve->method != 0) { - meth = curve->method(); - if (((group = ec_group_new(meth)) == NULL) || - (!(group->meth->group_set_curve(group, p, a, b, ctx)))) { - OPENSSL_PUT_ERROR(EC, ERR_R_EC_LIB); - goto err; - } - } else { - if ((group = ec_group_new_curve_GFp(p, a, b, ctx)) == NULL) { - OPENSSL_PUT_ERROR(EC, ERR_R_EC_LIB); - goto err; - } + group = ec_group_new(curve->method); + if (group == NULL || + !group->meth->group_set_curve(group, p, a, b, ctx)) { + OPENSSL_PUT_ERROR(EC, ERR_R_EC_LIB); + goto err; } if ((P = EC_POINT_new(group)) == NULL) { @@ -459,8 +447,7 @@ static EC_GROUP *ec_group_new_from_data(unsigned built_in_index) { OPENSSL_PUT_ERROR(EC, ERR_R_EC_LIB); goto err; } - if (!BN_bin2bn(params + 5 * param_len, param_len, &group->order) || - !BN_set_word(&group->cofactor, (BN_ULONG)data->cofactor)) { + if (!BN_bin2bn(params + 5 * param_len, param_len, &group->order)) { OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB); goto err; } @@ -523,80 +510,49 @@ void EC_GROUP_free(EC_GROUP *group) { EC_POINT_free(group->generator); BN_free(&group->order); - BN_free(&group->cofactor); OPENSSL_free(group); } -int ec_group_copy(EC_GROUP *dest, const EC_GROUP *src) { - if (dest->meth->group_copy == 0) { - OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); - return 0; - } - if (dest->meth != src->meth) { - OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS); - return 0; - } - if (dest == src) { - return 1; - } - - dest->mont_data = src->mont_data; - - if (src->generator != NULL) { - if (dest->generator == NULL) { - dest->generator = EC_POINT_new(dest); - if (dest->generator == NULL) { - return 0; - } - } - if (!EC_POINT_copy(dest->generator, src->generator)) { - return 0; - } - } else { - EC_POINT_clear_free(dest->generator); - dest->generator = NULL; - } - - if (!BN_copy(&dest->order, &src->order) || - !BN_copy(&dest->cofactor, &src->cofactor)) { - return 0; - } - - dest->curve_name = src->curve_name; - - return dest->meth->group_copy(dest, src); -} - const BN_MONT_CTX *ec_group_get_mont_data(const EC_GROUP *group) { return group->mont_data; } EC_GROUP *EC_GROUP_dup(const EC_GROUP *a) { - EC_GROUP *t = NULL; - int ok = 0; - if (a == NULL) { return NULL; } - t = ec_group_new(a->meth); - if (t == NULL) { + if (a->meth->group_copy == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return NULL; + } + + EC_GROUP *ret = ec_group_new(a->meth); + if (ret == NULL) { return NULL; } - if (!ec_group_copy(t, a)) { + + ret->mont_data = a->mont_data; + ret->curve_name = a->curve_name; + + if (a->generator != NULL) { + ret->generator = EC_POINT_dup(a->generator, ret); + if (ret->generator == NULL) { + goto err; + } + } + + if (!BN_copy(&ret->order, &a->order) || + !ret->meth->group_copy(ret, a)) { goto err; } - ok = 1; + return ret; err: - if (!ok) { - EC_GROUP_free(t); - return NULL; - } else { - return t; - } + EC_GROUP_free(ret); + return NULL; } int EC_GROUP_cmp(const EC_GROUP *a, const EC_GROUP *b, BN_CTX *ignored) { @@ -623,11 +579,8 @@ int EC_GROUP_get_order(const EC_GROUP *group, BIGNUM *order, BN_CTX *ctx) { int EC_GROUP_get_cofactor(const EC_GROUP *group, BIGNUM *cofactor, BN_CTX *ctx) { - if (!BN_copy(cofactor, &group->cofactor)) { - return 0; - } - - return !BN_is_zero(&group->cofactor); + /* All |EC_GROUP|s have cofactor 1. */ + return BN_set_word(cofactor, 1); } int EC_GROUP_get_curve_GFp(const EC_GROUP *group, BIGNUM *out_p, BIGNUM *out_a, @@ -698,25 +651,18 @@ int EC_POINT_copy(EC_POINT *dest, const EC_POINT *src) { } EC_POINT *EC_POINT_dup(const EC_POINT *a, const EC_GROUP *group) { - EC_POINT *t; - int r; - if (a == NULL) { return NULL; } - t = EC_POINT_new(group); - if (t == NULL) { - OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE); + EC_POINT *ret = EC_POINT_new(group); + if (ret == NULL || + !EC_POINT_copy(ret, a)) { + EC_POINT_free(ret); return NULL; } - r = EC_POINT_copy(t, a); - if (!r) { - EC_POINT_free(t); - return NULL; - } else { - return t; - } + + return ret; } int EC_POINT_set_to_infinity(const EC_GROUP *group, EC_POINT *point) { @@ -763,9 +709,7 @@ int EC_POINT_make_affine(const EC_GROUP *group, EC_POINT *point, BN_CTX *ctx) { int EC_POINTs_make_affine(const EC_GROUP *group, size_t num, EC_POINT *points[], BN_CTX *ctx) { - size_t i; - - for (i = 0; i < num; i++) { + for (size_t i = 0; i < num; i++) { if (group->meth != points[i]->meth) { OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS); return 0; diff --git a/Sources/BoringSSL/crypto/ec/ec_asn1.c b/Sources/BoringSSL/crypto/ec/ec_asn1.c index a29a2dcfc..35c8f2771 100644 --- a/Sources/BoringSSL/crypto/ec/ec_asn1.c +++ b/Sources/BoringSSL/crypto/ec/ec_asn1.c @@ -60,10 +60,11 @@ #include #include #include -#include +#include #include "internal.h" #include "../bytestring/internal.h" +#include "../internal.h" static const uint8_t kParametersTag = @@ -207,14 +208,9 @@ int EC_KEY_marshal_private_key(CBB *cbb, const EC_KEY *key, } if (!(enc_flags & EC_PKEY_NO_PARAMETERS)) { - int curve_nid = EC_GROUP_get_curve_name(key->group); - if (curve_nid == NID_undef) { - OPENSSL_PUT_ERROR(EC, EC_R_UNKNOWN_GROUP); - return 0; - } CBB child; if (!CBB_add_asn1(&ec_private_key, &child, kParametersTag) || - !OBJ_nid2cbb(&child, curve_nid) || + !EC_KEY_marshal_curve_name(&child, key->group) || !CBB_flush(&ec_private_key)) { OPENSSL_PUT_ERROR(EC, EC_R_ENCODE_ERROR); return 0; @@ -260,6 +256,9 @@ static int is_unsigned_integer(const CBS *cbs) { return 1; } +/* kPrimeFieldOID is the encoding of 1.2.840.10045.1.1. */ +static const uint8_t kPrimeField[] = {0x2a, 0x86, 0x48, 0xce, 0x3d, 0x01, 0x01}; + static int parse_explicit_prime_curve(CBS *in, CBS *out_prime, CBS *out_a, CBS *out_b, CBS *out_base_x, CBS *out_base_y, CBS *out_order) { @@ -272,7 +271,8 @@ static int parse_explicit_prime_curve(CBS *in, CBS *out_prime, CBS *out_a, version != 1 || !CBS_get_asn1(¶ms, &field_id, CBS_ASN1_SEQUENCE) || !CBS_get_asn1(&field_id, &field_type, CBS_ASN1_OBJECT) || - OBJ_cbs2nid(&field_type) != NID_X9_62_prime_field || + CBS_len(&field_type) != sizeof(kPrimeField) || + OPENSSL_memcmp(CBS_data(&field_type), kPrimeField, sizeof(kPrimeField)) != 0 || !CBS_get_asn1(&field_id, out_prime, CBS_ASN1_INTEGER) || !is_unsigned_integer(out_prime) || CBS_len(&field_id) != 0 || @@ -324,51 +324,86 @@ static int integers_equal(const CBS *a, const uint8_t *b, size_t b_len) { return CBS_mem_equal(&a_copy, b, b_len); } -EC_GROUP *EC_KEY_parse_parameters(CBS *cbs) { - if (CBS_peek_asn1_tag(cbs, CBS_ASN1_SEQUENCE)) { - /* OpenSSL sometimes produces ECPrivateKeys with explicitly-encoded versions - * of named curves. - * - * TODO(davidben): Remove support for this. */ - CBS prime, a, b, base_x, base_y, order; - if (!parse_explicit_prime_curve(cbs, &prime, &a, &b, &base_x, &base_y, - &order)) { - return NULL; - } +EC_GROUP *EC_KEY_parse_curve_name(CBS *cbs) { + CBS named_curve; + if (!CBS_get_asn1(cbs, &named_curve, CBS_ASN1_OBJECT)) { + OPENSSL_PUT_ERROR(EC, EC_R_DECODE_ERROR); + return NULL; + } - /* Look for a matching prime curve. */ - unsigned i; - for (i = 0; OPENSSL_built_in_curves[i].nid != NID_undef; i++) { - const struct built_in_curve *curve = &OPENSSL_built_in_curves[i]; - const unsigned param_len = curve->data->param_len; - /* |curve->data->data| is ordered p, a, b, x, y, order, each component - * zero-padded up to the field length. Although SEC 1 states that the - * Field-Element-to-Octet-String conversion also pads, OpenSSL mis-encodes - * |a| and |b|, so this comparison must allow omitting leading zeros. - * (This is relevant for P-521 whose |b| has a leading 0.) */ - if (integers_equal(&prime, curve->data->data, param_len) && - integers_equal(&a, curve->data->data + param_len, param_len) && - integers_equal(&b, curve->data->data + param_len * 2, param_len) && - integers_equal(&base_x, curve->data->data + param_len * 3, - param_len) && - integers_equal(&base_y, curve->data->data + param_len * 4, - param_len) && - integers_equal(&order, curve->data->data + param_len * 5, - param_len)) { - return EC_GROUP_new_by_curve_name(curve->nid); - } + /* Look for a matching curve. */ + unsigned i; + for (i = 0; OPENSSL_built_in_curves[i].nid != NID_undef; i++) { + const struct built_in_curve *curve = &OPENSSL_built_in_curves[i]; + if (CBS_len(&named_curve) == curve->oid_len && + OPENSSL_memcmp(CBS_data(&named_curve), curve->oid, curve->oid_len) == 0) { + return EC_GROUP_new_by_curve_name(curve->nid); } + } + + OPENSSL_PUT_ERROR(EC, EC_R_UNKNOWN_GROUP); + return NULL; +} +int EC_KEY_marshal_curve_name(CBB *cbb, const EC_GROUP *group) { + int nid = EC_GROUP_get_curve_name(group); + if (nid == NID_undef) { OPENSSL_PUT_ERROR(EC, EC_R_UNKNOWN_GROUP); - return NULL; + return 0; } - CBS named_curve; - if (!CBS_get_asn1(cbs, &named_curve, CBS_ASN1_OBJECT)) { - OPENSSL_PUT_ERROR(EC, EC_R_DECODE_ERROR); + unsigned i; + for (i = 0; OPENSSL_built_in_curves[i].nid != NID_undef; i++) { + const struct built_in_curve *curve = &OPENSSL_built_in_curves[i]; + if (curve->nid == nid) { + CBB child; + return CBB_add_asn1(cbb, &child, CBS_ASN1_OBJECT) && + CBB_add_bytes(&child, curve->oid, curve->oid_len) && + CBB_flush(cbb); + } + } + + OPENSSL_PUT_ERROR(EC, EC_R_UNKNOWN_GROUP); + return 0; +} + +EC_GROUP *EC_KEY_parse_parameters(CBS *cbs) { + if (!CBS_peek_asn1_tag(cbs, CBS_ASN1_SEQUENCE)) { + return EC_KEY_parse_curve_name(cbs); + } + + /* OpenSSL sometimes produces ECPrivateKeys with explicitly-encoded versions + * of named curves. + * + * TODO(davidben): Remove support for this. */ + CBS prime, a, b, base_x, base_y, order; + if (!parse_explicit_prime_curve(cbs, &prime, &a, &b, &base_x, &base_y, + &order)) { return NULL; } - return EC_GROUP_new_by_curve_name(OBJ_cbs2nid(&named_curve)); + + /* Look for a matching prime curve. */ + unsigned i; + for (i = 0; OPENSSL_built_in_curves[i].nid != NID_undef; i++) { + const struct built_in_curve *curve = &OPENSSL_built_in_curves[i]; + const unsigned param_len = curve->data->param_len; + /* |curve->data->data| is ordered p, a, b, x, y, order, each component + * zero-padded up to the field length. Although SEC 1 states that the + * Field-Element-to-Octet-String conversion also pads, OpenSSL mis-encodes + * |a| and |b|, so this comparison must allow omitting leading zeros. (This + * is relevant for P-521 whose |b| has a leading 0.) */ + if (integers_equal(&prime, curve->data->data, param_len) && + integers_equal(&a, curve->data->data + param_len, param_len) && + integers_equal(&b, curve->data->data + param_len * 2, param_len) && + integers_equal(&base_x, curve->data->data + param_len * 3, param_len) && + integers_equal(&base_y, curve->data->data + param_len * 4, param_len) && + integers_equal(&order, curve->data->data + param_len * 5, param_len)) { + return EC_GROUP_new_by_curve_name(curve->nid); + } + } + + OPENSSL_PUT_ERROR(EC, EC_R_UNKNOWN_GROUP); + return NULL; } EC_KEY *d2i_ECPrivateKey(EC_KEY **out, const uint8_t **inp, long len) { @@ -401,6 +436,7 @@ int i2d_ECPrivateKey(const EC_KEY *key, uint8_t **outp) { CBB cbb; if (!CBB_init(&cbb, 0) || !EC_KEY_marshal_private_key(&cbb, key, EC_KEY_get_enc_flags(key))) { + CBB_cleanup(&cbb); return -1; } return CBB_finish_i2d(&cbb, outp); @@ -440,15 +476,10 @@ int i2d_ECParameters(const EC_KEY *key, uint8_t **outp) { return -1; } - int curve_nid = EC_GROUP_get_curve_name(key->group); - if (curve_nid == NID_undef) { - OPENSSL_PUT_ERROR(EC, EC_R_UNKNOWN_GROUP); - return -1; - } - CBB cbb; if (!CBB_init(&cbb, 0) || - !OBJ_nid2cbb(&cbb, curve_nid)) { + !EC_KEY_marshal_curve_name(&cbb, key->group)) { + CBB_cleanup(&cbb); return -1; } return CBB_finish_i2d(&cbb, outp); diff --git a/Sources/BoringSSL/crypto/ec/ec_key.c b/Sources/BoringSSL/crypto/ec/ec_key.c index f01bf6b4d..1a933462d 100644 --- a/Sources/BoringSSL/crypto/ec/ec_key.c +++ b/Sources/BoringSSL/crypto/ec/ec_key.c @@ -91,7 +91,7 @@ EC_KEY *EC_KEY_new_method(const ENGINE *engine) { return NULL; } - memset(ret, 0, sizeof(EC_KEY)); + OPENSSL_memset(ret, 0, sizeof(EC_KEY)); if (engine) { ret->ecdsa_meth = ENGINE_get_ECDSA_method(engine); @@ -317,14 +317,6 @@ int EC_KEY_check_key(const EC_KEY *eckey) { OPENSSL_PUT_ERROR(EC, EC_R_POINT_IS_NOT_ON_CURVE); goto err; } - /* TODO(fork): can this be skipped if the cofactor is one or if we're about - * to check the private key, below? */ - if (eckey->group->meth->check_pub_key_order != NULL && - !eckey->group->meth->check_pub_key_order(eckey->group, eckey->pub_key, - ctx)) { - OPENSSL_PUT_ERROR(EC, EC_R_WRONG_ORDER); - goto err; - } /* in case the priv_key is present : * check if generator * priv_key == pub_key */ @@ -365,15 +357,24 @@ int EC_KEY_set_public_key_affine_coordinates(EC_KEY *key, BIGNUM *x, return 0; } ctx = BN_CTX_new(); + + if (ctx == NULL) { + return 0; + } + + BN_CTX_start(ctx); point = EC_POINT_new(key->group); - if (ctx == NULL || - point == NULL) { + if (point == NULL) { goto err; } tx = BN_CTX_get(ctx); ty = BN_CTX_get(ctx); + if (tx == NULL || + ty == NULL) { + goto err; + } if (!EC_POINT_set_affine_coordinates_GFp(key->group, point, x, y, ctx) || !EC_POINT_get_affine_coordinates_GFp(key->group, point, tx, ty, ctx)) { @@ -398,6 +399,7 @@ int EC_KEY_set_public_key_affine_coordinates(EC_KEY *key, BIGNUM *x, ok = 1; err: + BN_CTX_end(ctx); BN_CTX_free(ctx); EC_POINT_free(point); return ok; @@ -423,11 +425,9 @@ int EC_KEY_generate_key(EC_KEY *eckey) { } const BIGNUM *order = EC_GROUP_get0_order(eckey->group); - do { - if (!BN_rand_range(priv_key, order)) { - goto err; - } - } while (BN_is_zero(priv_key)); + if (!BN_rand_range_ex(priv_key, 1, order)) { + goto err; + } if (eckey->pub_key == NULL) { pub_key = EC_POINT_new(eckey->group); diff --git a/Sources/BoringSSL/crypto/ec/ec_montgomery.c b/Sources/BoringSSL/crypto/ec/ec_montgomery.c index 62b0d7f6f..4643fd2c4 100644 --- a/Sources/BoringSSL/crypto/ec/ec_montgomery.c +++ b/Sources/BoringSSL/crypto/ec/ec_montgomery.c @@ -71,6 +71,7 @@ #include #include +#include "../bn/internal.h" #include "internal.h" @@ -79,23 +80,18 @@ int ec_GFp_mont_group_init(EC_GROUP *group) { ok = ec_GFp_simple_group_init(group); group->mont = NULL; - group->one = NULL; return ok; } void ec_GFp_mont_group_finish(EC_GROUP *group) { BN_MONT_CTX_free(group->mont); group->mont = NULL; - BN_free(group->one); - group->one = NULL; ec_GFp_simple_group_finish(group); } int ec_GFp_mont_group_copy(EC_GROUP *dest, const EC_GROUP *src) { BN_MONT_CTX_free(dest->mont); dest->mont = NULL; - BN_clear_free(dest->one); - dest->one = NULL; if (!ec_GFp_simple_group_copy(dest, src)) { return 0; @@ -110,12 +106,6 @@ int ec_GFp_mont_group_copy(EC_GROUP *dest, const EC_GROUP *src) { goto err; } } - if (src->one != NULL) { - dest->one = BN_dup(src->one); - if (dest->one == NULL) { - goto err; - } - } return 1; @@ -129,13 +119,10 @@ int ec_GFp_mont_group_set_curve(EC_GROUP *group, const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx) { BN_CTX *new_ctx = NULL; BN_MONT_CTX *mont = NULL; - BIGNUM *one = NULL; int ret = 0; BN_MONT_CTX_free(group->mont); group->mont = NULL; - BN_free(group->one); - group->one = NULL; if (ctx == NULL) { ctx = new_ctx = BN_CTX_new(); @@ -152,29 +139,20 @@ int ec_GFp_mont_group_set_curve(EC_GROUP *group, const BIGNUM *p, OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB); goto err; } - one = BN_new(); - if (one == NULL || !BN_to_montgomery(one, BN_value_one(), mont, ctx)) { - goto err; - } group->mont = mont; mont = NULL; - group->one = one; - one = NULL; ret = ec_GFp_simple_group_set_curve(group, p, a, b, ctx); if (!ret) { BN_MONT_CTX_free(group->mont); group->mont = NULL; - BN_free(group->one); - group->one = NULL; } err: BN_CTX_free(new_ctx); BN_MONT_CTX_free(mont); - BN_free(one); return ret; } @@ -218,54 +196,108 @@ int ec_GFp_mont_field_decode(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a, return BN_from_montgomery(r, a, group->mont, ctx); } -int ec_GFp_mont_field_set_to_one(const EC_GROUP *group, BIGNUM *r, - BN_CTX *ctx) { - if (group->one == NULL) { - OPENSSL_PUT_ERROR(EC, EC_R_NOT_INITIALIZED); +static int ec_GFp_mont_point_get_affine_coordinates(const EC_GROUP *group, + const EC_POINT *point, + BIGNUM *x, BIGNUM *y, + BN_CTX *ctx) { + if (EC_POINT_is_at_infinity(group, point)) { + OPENSSL_PUT_ERROR(EC, EC_R_POINT_AT_INFINITY); return 0; } - if (!BN_copy(r, group->one)) { - return 0; + BN_CTX *new_ctx = NULL; + if (ctx == NULL) { + ctx = new_ctx = BN_CTX_new(); + if (ctx == NULL) { + return 0; + } } - return 1; -} -static int ec_GFp_mont_check_pub_key_order(const EC_GROUP *group, - const EC_POINT* pub_key, - BN_CTX *ctx) { - EC_POINT *point = EC_POINT_new(group); int ret = 0; - if (point == NULL || - !ec_wNAF_mul(group, point, NULL, pub_key, EC_GROUP_get0_order(group), - ctx) || - !EC_POINT_is_at_infinity(group, point)) { - goto err; + BN_CTX_start(ctx); + + if (BN_cmp(&point->Z, &group->one) == 0) { + /* |point| is already affine. */ + if (x != NULL && !BN_from_montgomery(x, &point->X, group->mont, ctx)) { + goto err; + } + if (y != NULL && !BN_from_montgomery(y, &point->Y, group->mont, ctx)) { + goto err; + } + } else { + /* transform (X, Y, Z) into (x, y) := (X/Z^2, Y/Z^3) */ + + BIGNUM *Z_1 = BN_CTX_get(ctx); + BIGNUM *Z_2 = BN_CTX_get(ctx); + BIGNUM *Z_3 = BN_CTX_get(ctx); + if (Z_1 == NULL || + Z_2 == NULL || + Z_3 == NULL) { + goto err; + } + + /* The straightforward way to calculate the inverse of a Montgomery-encoded + * value where the result is Montgomery-encoded is: + * + * |BN_from_montgomery| + invert + |BN_to_montgomery|. + * + * This is equivalent, but more efficient, because |BN_from_montgomery| + * is more efficient (at least in theory) than |BN_to_montgomery|, since it + * doesn't have to do the multiplication before the reduction. + * + * Use Fermat's Little Theorem instead of |BN_mod_inverse_odd| since this + * inversion may be done as the final step of private key operations. + * Unfortunately, this is suboptimal for ECDSA verification. */ + if (!BN_from_montgomery(Z_1, &point->Z, group->mont, ctx) || + !BN_from_montgomery(Z_1, Z_1, group->mont, ctx) || + !bn_mod_inverse_prime(Z_1, Z_1, &group->field, ctx, group->mont)) { + goto err; + } + + if (!BN_mod_mul_montgomery(Z_2, Z_1, Z_1, group->mont, ctx)) { + goto err; + } + + /* Instead of using |BN_from_montgomery| to convert the |x| coordinate + * and then calling |BN_from_montgomery| again to convert the |y| + * coordinate below, convert the common factor |Z_2| once now, saving one + * reduction. */ + if (!BN_from_montgomery(Z_2, Z_2, group->mont, ctx)) { + goto err; + } + + if (x != NULL) { + if (!BN_mod_mul_montgomery(x, &point->X, Z_2, group->mont, ctx)) { + goto err; + } + } + + if (y != NULL) { + if (!BN_mod_mul_montgomery(Z_3, Z_2, Z_1, group->mont, ctx) || + !BN_mod_mul_montgomery(y, &point->Y, Z_3, group->mont, ctx)) { + goto err; + } + } } ret = 1; err: - EC_POINT_free(point); + BN_CTX_end(ctx); + BN_CTX_free(new_ctx); return ret; } -const EC_METHOD *EC_GFp_mont_method(void) { - static const EC_METHOD ret = { +const EC_METHOD EC_GFp_mont_method = { ec_GFp_mont_group_init, ec_GFp_mont_group_finish, ec_GFp_mont_group_copy, ec_GFp_mont_group_set_curve, - ec_GFp_simple_point_get_affine_coordinates, + ec_GFp_mont_point_get_affine_coordinates, ec_wNAF_mul /* XXX: Not constant time. */, - ec_GFp_mont_check_pub_key_order, ec_GFp_mont_field_mul, ec_GFp_mont_field_sqr, ec_GFp_mont_field_encode, ec_GFp_mont_field_decode, - ec_GFp_mont_field_set_to_one, - }; - - return &ret; -} +}; diff --git a/Sources/BoringSSL/crypto/ec/example_mul.c b/Sources/BoringSSL/crypto/ec/example_mul.c index ebb724faf..a2bdd5277 100644 --- a/Sources/BoringSSL/crypto/ec/example_mul.c +++ b/Sources/BoringSSL/crypto/ec/example_mul.c @@ -70,10 +70,10 @@ #include #include #include -#include +#include -int example_EC_POINT_mul(void) { +static int example_EC_POINT_mul(void) { /* This example ensures that 10×∞ + G = G, in P-256. */ EC_GROUP *group = NULL; EC_POINT *p = NULL, *result = NULL; diff --git a/Sources/BoringSSL/crypto/ec/internal.h b/Sources/BoringSSL/crypto/ec/internal.h index 2b788c1ca..b3c2a71f1 100644 --- a/Sources/BoringSSL/crypto/ec/internal.h +++ b/Sources/BoringSSL/crypto/ec/internal.h @@ -96,15 +96,6 @@ struct ec_method_st { int (*mul)(const EC_GROUP *group, EC_POINT *r, const BIGNUM *g_scalar, const EC_POINT *p, const BIGNUM *p_scalar, BN_CTX *ctx); - /* |check_pub_key_order| checks that the public key is in the proper subgroup - * by checking that |pub_key*group->order| is the point at infinity. This may - * be NULL for |EC_METHOD|s specialized for prime-order curves (i.e. with - * cofactor one), as this check is not necessary for such curves (See section - * A.3 of the NSA's "Suite B Implementer's Guide to FIPS 186-3 - * (ECDSA)"). */ - int (*check_pub_key_order)(const EC_GROUP *group, const EC_POINT *pub_key, - BN_CTX *ctx); - /* 'field_mul' and 'field_sqr' can be used by 'add' and 'dbl' so that the * same implementations of point operations can be used with different * optimized implementations of expensive field operations: */ @@ -116,16 +107,15 @@ struct ec_method_st { BN_CTX *); /* e.g. to Montgomery */ int (*field_decode)(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, BN_CTX *); /* e.g. from Montgomery */ - int (*field_set_to_one)(const EC_GROUP *, BIGNUM *r, BN_CTX *); } /* EC_METHOD */; -const EC_METHOD* EC_GFp_mont_method(void); +extern const EC_METHOD EC_GFp_mont_method; struct ec_group_st { const EC_METHOD *meth; EC_POINT *generator; - BIGNUM order, cofactor; + BIGNUM order; int curve_name; /* optional NID for named curve */ @@ -141,7 +131,8 @@ struct ec_group_st { int a_is_minus3; /* enable optimized point arithmetics for special case */ BN_MONT_CTX *mont; /* Montgomery structure. */ - BIGNUM *one; /* The value one */ + + BIGNUM one; /* The value one. */ } /* EC_GROUP */; struct ec_point_st { @@ -151,7 +142,6 @@ struct ec_point_st { BIGNUM Y; BIGNUM Z; /* Jacobian projective coordinates: * (X, Y, Z) represents (X/Z^2, Y/Z^3) if Z != 0 */ - int Z_is_one; /* enable optimized point arithmetics for special case */ } /* EC_POINT */; EC_GROUP *ec_group_new(const EC_METHOD *meth); @@ -190,9 +180,6 @@ int ec_GFp_simple_get_Jprojective_coordinates_GFp(const EC_GROUP *, int ec_GFp_simple_point_set_affine_coordinates(const EC_GROUP *, EC_POINT *, const BIGNUM *x, const BIGNUM *y, BN_CTX *); -int ec_GFp_simple_point_get_affine_coordinates(const EC_GROUP *, - const EC_POINT *, BIGNUM *x, - BIGNUM *y, BN_CTX *); int ec_GFp_simple_set_compressed_coordinates(const EC_GROUP *, EC_POINT *, const BIGNUM *x, int y_bit, BN_CTX *); @@ -227,30 +214,20 @@ int ec_GFp_mont_field_encode(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, BN_CTX *); int ec_GFp_mont_field_decode(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, BN_CTX *); -int ec_GFp_mont_field_set_to_one(const EC_GROUP *, BIGNUM *r, BN_CTX *); int ec_point_set_Jprojective_coordinates_GFp(const EC_GROUP *group, EC_POINT *point, const BIGNUM *x, const BIGNUM *y, const BIGNUM *z, BN_CTX *ctx); -void ec_GFp_nistp_points_make_affine_internal( - size_t num, void *point_array, size_t felem_size, void *tmp_felems, - void (*felem_one)(void *out), int (*felem_is_zero)(const void *in), - void (*felem_assign)(void *out, const void *in), - void (*felem_square)(void *out, const void *in), - void (*felem_mul)(void *out, const void *in1, const void *in2), - void (*felem_inv)(void *out, const void *in), - void (*felem_contract)(void *out, const void *in)); - void ec_GFp_nistp_recode_scalar_bits(uint8_t *sign, uint8_t *digit, uint8_t in); -const EC_METHOD *EC_GFp_nistp224_method(void); -const EC_METHOD *EC_GFp_nistp256_method(void); +extern const EC_METHOD EC_GFp_nistp224_method; +extern const EC_METHOD EC_GFp_nistp256_method; -/* Returns GFp methods using montgomery multiplication, with x86-64 - * optimized P256. See http://eprint.iacr.org/2013/816. */ -const EC_METHOD *EC_GFp_nistz256_method(void); +/* EC_GFp_nistz256_method is a GFp method using montgomery multiplication, with + * x86-64 optimized P256. See http://eprint.iacr.org/2013/816. */ +extern const EC_METHOD EC_GFp_nistz256_method; struct ec_key_st { EC_GROUP *group; @@ -274,9 +251,6 @@ struct curve_data { const char *comment; /* param_len is the number of bytes needed to store a field element. */ uint8_t param_len; - /* cofactor is the cofactor of the group (i.e. the number of elements in the - * group divided by the size of the main subgroup. */ - uint8_t cofactor; /* promoted to BN_ULONG */ /* data points to an array of 6*|param_len| bytes which hold the field * elements of the following (in big-endian order): prime, a, b, generator x, * generator y, order. */ @@ -285,8 +259,10 @@ struct curve_data { struct built_in_curve { int nid; + uint8_t oid[8]; + uint8_t oid_len; const struct curve_data *data; - const EC_METHOD *(*method)(void); + const EC_METHOD *method; }; /* OPENSSL_built_in_curves is terminated with an entry where |nid| is diff --git a/Sources/BoringSSL/crypto/ec/oct.c b/Sources/BoringSSL/crypto/ec/oct.c index 9e18535aa..4e8272da6 100644 --- a/Sources/BoringSSL/crypto/ec/oct.c +++ b/Sources/BoringSSL/crypto/ec/oct.c @@ -281,10 +281,15 @@ int EC_POINT_point2cbb(CBB *out, const EC_GROUP *group, const EC_POINT *point, } int ec_GFp_simple_set_compressed_coordinates(const EC_GROUP *group, - EC_POINT *point, const BIGNUM *x_, + EC_POINT *point, const BIGNUM *x, int y_bit, BN_CTX *ctx) { + if (BN_is_negative(x) || BN_cmp(x, &group->field) >= 0) { + OPENSSL_PUT_ERROR(EC, EC_R_INVALID_COMPRESSED_POINT); + return 0; + } + BN_CTX *new_ctx = NULL; - BIGNUM *tmp1, *tmp2, *x, *y; + BIGNUM *tmp1, *tmp2, *y; int ret = 0; ERR_clear_error(); @@ -301,7 +306,6 @@ int ec_GFp_simple_set_compressed_coordinates(const EC_GROUP *group, BN_CTX_start(ctx); tmp1 = BN_CTX_get(ctx); tmp2 = BN_CTX_get(ctx); - x = BN_CTX_get(ctx); y = BN_CTX_get(ctx); if (y == NULL) { goto err; @@ -312,19 +316,15 @@ int ec_GFp_simple_set_compressed_coordinates(const EC_GROUP *group, * so y is one of the square roots of x^3 + a*x + b. */ /* tmp1 := x^3 */ - if (!BN_nnmod(x, x_, &group->field, ctx)) { - goto err; - } - if (group->meth->field_decode == 0) { /* field_{sqr,mul} work on standard representation */ - if (!group->meth->field_sqr(group, tmp2, x_, ctx) || - !group->meth->field_mul(group, tmp1, tmp2, x_, ctx)) { + if (!group->meth->field_sqr(group, tmp2, x, ctx) || + !group->meth->field_mul(group, tmp1, tmp2, x, ctx)) { goto err; } } else { - if (!BN_mod_sqr(tmp2, x_, &group->field, ctx) || - !BN_mod_mul(tmp1, tmp2, x_, &group->field, ctx)) { + if (!BN_mod_sqr(tmp2, x, &group->field, ctx) || + !BN_mod_mul(tmp1, tmp2, x, &group->field, ctx)) { goto err; } } @@ -381,19 +381,7 @@ int ec_GFp_simple_set_compressed_coordinates(const EC_GROUP *group, if (y_bit != BN_is_odd(y)) { if (BN_is_zero(y)) { - int kron; - - kron = BN_kronecker(x, &group->field, ctx); - if (kron == -2) { - goto err; - } - - if (kron == 1) { - OPENSSL_PUT_ERROR(EC, EC_R_INVALID_COMPRESSION_BIT); - } else { - /* BN_mod_sqrt() should have cought this error (not a square) */ - OPENSSL_PUT_ERROR(EC, EC_R_INVALID_COMPRESSED_POINT); - } + OPENSSL_PUT_ERROR(EC, EC_R_INVALID_COMPRESSION_BIT); goto err; } if (!BN_usub(y, &group->field, y)) { diff --git a/Sources/BoringSSL/crypto/ec/p224-64.c b/Sources/BoringSSL/crypto/ec/p224-64.c index 9de6cd49d..7b2ae68c9 100644 --- a/Sources/BoringSSL/crypto/ec/p224-64.c +++ b/Sources/BoringSSL/crypto/ec/p224-64.c @@ -26,7 +26,6 @@ #include #include #include -#include #include @@ -193,8 +192,7 @@ static void bin28_to_felem(felem out, const u8 in[28]) { } static void felem_to_bin28(u8 out[28], const felem in) { - unsigned i; - for (i = 0; i < 7; ++i) { + for (size_t i = 0; i < 7; ++i) { out[i] = in[0] >> (8 * i); out[i + 7] = in[1] >> (8 * i); out[i + 14] = in[2] >> (8 * i); @@ -203,9 +201,8 @@ static void felem_to_bin28(u8 out[28], const felem in) { } /* To preserve endianness when using BN_bn2bin and BN_bin2bn */ -static void flip_endian(u8 *out, const u8 *in, unsigned len) { - unsigned i; - for (i = 0; i < len; ++i) { +static void flip_endian(u8 *out, const u8 *in, size_t len) { + for (size_t i = 0; i < len; ++i) { out[i] = in[len - 1 - i]; } } @@ -214,8 +211,8 @@ static void flip_endian(u8 *out, const u8 *in, unsigned len) { static int BN_to_felem(felem out, const BIGNUM *bn) { /* BN_bn2bin eats leading zeroes */ felem_bytearray b_out; - memset(b_out, 0, sizeof(b_out)); - unsigned num_bytes = BN_num_bytes(bn); + OPENSSL_memset(b_out, 0, sizeof(b_out)); + size_t num_bytes = BN_num_bytes(bn); if (num_bytes > sizeof(b_out) || BN_is_negative(bn)) { OPENSSL_PUT_ERROR(EC, EC_R_BIGNUM_OUT_OF_RANGE); @@ -242,13 +239,6 @@ static BIGNUM *felem_to_BN(BIGNUM *out, const felem in) { * expected to be correct in general - e.g., multiplication with a large scalar * will cause an overflow. */ -static void felem_one(felem out) { - out[0] = 1; - out[1] = 0; - out[2] = 0; - out[3] = 0; -} - static void felem_assign(felem out, const felem in) { out[0] = in[0]; out[1] = in[1]; @@ -460,18 +450,6 @@ static void felem_reduce(felem out, const widefelem in) { out[3] = output[3]; } -static void felem_square_reduce(felem out, const felem in) { - widefelem tmp; - felem_square(tmp, in); - felem_reduce(out, tmp); -} - -static void felem_mul_reduce(felem out, const felem in1, const felem in2) { - widefelem tmp; - felem_mul(tmp, in1, in2); - felem_reduce(out, tmp); -} - /* Reduce to unique minimal representation. * Requires 0 <= in < 2*p (always call felem_reduce first) */ static void felem_contract(felem out, const felem in) { @@ -539,16 +517,11 @@ static limb felem_is_zero(const felem in) { return (zero | two224m96p1 | two225m97p2); } -static limb felem_is_zero_int(const felem in) { - return (int)(felem_is_zero(in) & ((limb)1)); -} - /* Invert a field element */ /* Computation chain copied from djb's code */ static void felem_inv(felem out, const felem in) { felem ftmp, ftmp2, ftmp3, ftmp4; widefelem tmp; - unsigned i; felem_square(tmp, in); felem_reduce(ftmp, tmp); /* 2 */ @@ -568,7 +541,7 @@ static void felem_inv(felem out, const felem in) { felem_reduce(ftmp, tmp); /* 2^6 - 1 */ felem_square(tmp, ftmp); felem_reduce(ftmp2, tmp); /* 2^7 - 2 */ - for (i = 0; i < 5; ++i) { /* 2^12 - 2^6 */ + for (size_t i = 0; i < 5; ++i) { /* 2^12 - 2^6 */ felem_square(tmp, ftmp2); felem_reduce(ftmp2, tmp); } @@ -576,7 +549,7 @@ static void felem_inv(felem out, const felem in) { felem_reduce(ftmp2, tmp); /* 2^12 - 1 */ felem_square(tmp, ftmp2); felem_reduce(ftmp3, tmp); /* 2^13 - 2 */ - for (i = 0; i < 11; ++i) {/* 2^24 - 2^12 */ + for (size_t i = 0; i < 11; ++i) {/* 2^24 - 2^12 */ felem_square(tmp, ftmp3); felem_reduce(ftmp3, tmp); } @@ -584,7 +557,7 @@ static void felem_inv(felem out, const felem in) { felem_reduce(ftmp2, tmp); /* 2^24 - 1 */ felem_square(tmp, ftmp2); felem_reduce(ftmp3, tmp); /* 2^25 - 2 */ - for (i = 0; i < 23; ++i) {/* 2^48 - 2^24 */ + for (size_t i = 0; i < 23; ++i) {/* 2^48 - 2^24 */ felem_square(tmp, ftmp3); felem_reduce(ftmp3, tmp); } @@ -592,7 +565,7 @@ static void felem_inv(felem out, const felem in) { felem_reduce(ftmp3, tmp); /* 2^48 - 1 */ felem_square(tmp, ftmp3); felem_reduce(ftmp4, tmp); /* 2^49 - 2 */ - for (i = 0; i < 47; ++i) {/* 2^96 - 2^48 */ + for (size_t i = 0; i < 47; ++i) {/* 2^96 - 2^48 */ felem_square(tmp, ftmp4); felem_reduce(ftmp4, tmp); } @@ -600,13 +573,13 @@ static void felem_inv(felem out, const felem in) { felem_reduce(ftmp3, tmp); /* 2^96 - 1 */ felem_square(tmp, ftmp3); felem_reduce(ftmp4, tmp); /* 2^97 - 2 */ - for (i = 0; i < 23; ++i) {/* 2^120 - 2^24 */ + for (size_t i = 0; i < 23; ++i) {/* 2^120 - 2^24 */ felem_square(tmp, ftmp4); felem_reduce(ftmp4, tmp); } felem_mul(tmp, ftmp2, ftmp4); felem_reduce(ftmp2, tmp); /* 2^120 - 1 */ - for (i = 0; i < 6; ++i) { /* 2^126 - 2^6 */ + for (size_t i = 0; i < 6; ++i) { /* 2^126 - 2^6 */ felem_square(tmp, ftmp2); felem_reduce(ftmp2, tmp); } @@ -616,7 +589,7 @@ static void felem_inv(felem out, const felem in) { felem_reduce(ftmp, tmp); /* 2^127 - 2 */ felem_mul(tmp, ftmp, in); felem_reduce(ftmp, tmp); /* 2^127 - 1 */ - for (i = 0; i < 97; ++i) {/* 2^224 - 2^97 */ + for (size_t i = 0; i < 97; ++i) {/* 2^224 - 2^97 */ felem_square(tmp, ftmp); felem_reduce(ftmp, tmp); } @@ -628,10 +601,9 @@ static void felem_inv(felem out, const felem in) { * if icopy == 1, copy in to out, * if icopy == 0, copy out to itself. */ static void copy_conditional(felem out, const felem in, limb icopy) { - unsigned i; /* icopy is a (64-bit) 0 or 1, so copy is either all-zero or all-one */ const limb copy = -icopy; - for (i = 0; i < 4; ++i) { + for (size_t i = 0; i < 4; ++i) { const limb tmp = copy & (in[i] ^ out[i]); out[i] ^= tmp; } @@ -885,13 +857,12 @@ static void point_add(felem x3, felem y3, felem z3, const felem x1, /* select_point selects the |idx|th point from a precomputation table and * copies it to out. */ -static void select_point(const u64 idx, unsigned int size, +static void select_point(const u64 idx, size_t size, const felem pre_comp[/*size*/][3], felem out[3]) { - unsigned i, j; limb *outlimbs = &out[0][0]; - memset(outlimbs, 0, 3 * sizeof(felem)); + OPENSSL_memset(outlimbs, 0, 3 * sizeof(felem)); - for (i = 0; i < size; i++) { + for (size_t i = 0; i < size; i++) { const limb *inlimbs = &pre_comp[i][0][0]; u64 mask = i ^ idx; mask |= mask >> 4; @@ -899,14 +870,14 @@ static void select_point(const u64 idx, unsigned int size, mask |= mask >> 1; mask &= 1; mask--; - for (j = 0; j < 4 * 3; j++) { + for (size_t j = 0; j < 4 * 3; j++) { outlimbs[j] |= inlimbs[j] & mask; } } } /* get_bit returns the |i|th bit in |in| */ -static char get_bit(const felem_bytearray in, unsigned i) { +static char get_bit(const felem_bytearray in, size_t i) { if (i >= 224) { return 0; } @@ -914,36 +885,32 @@ static char get_bit(const felem_bytearray in, unsigned i) { } /* Interleaved point multiplication using precomputed point multiples: - * The small point multiples 0*P, 1*P, ..., 16*P are in pre_comp[], - * the scalars in scalars[]. If g_scalar is non-NULL, we also add this multiple + * The small point multiples 0*P, 1*P, ..., 16*P are in p_pre_comp, the scalars + * in p_scalar, if non-NULL. If g_scalar is non-NULL, we also add this multiple * of the generator, using certain (large) precomputed multiples in g_pre_comp. * Output point (X, Y, Z) is stored in x_out, y_out, z_out */ -static void batch_mul(felem x_out, felem y_out, felem z_out, - const felem_bytearray scalars[], - const unsigned num_points, const u8 *g_scalar, - const int mixed, const felem pre_comp[][17][3]) { - int i, skip; - unsigned num; - unsigned gen_mul = (g_scalar != NULL); +static void batch_mul(felem x_out, felem y_out, felem z_out, const u8 *p_scalar, + const u8 *g_scalar, const felem p_pre_comp[17][3]) { felem nq[3], tmp[4]; u64 bits; u8 sign, digit; /* set nq to the point at infinity */ - memset(nq, 0, 3 * sizeof(felem)); - - /* Loop over all scalars msb-to-lsb, interleaving additions - * of multiples of the generator (two in each of the last 28 rounds) - * and additions of other points multiples (every 5th round). */ - skip = 1; /* save two point operations in the first round */ - for (i = (num_points ? 220 : 27); i >= 0; --i) { + OPENSSL_memset(nq, 0, 3 * sizeof(felem)); + + /* Loop over both scalars msb-to-lsb, interleaving additions of multiples of + * the generator (two in each of the last 28 rounds) and additions of p (every + * 5th round). */ + int skip = 1; /* save two point operations in the first round */ + size_t i = p_scalar != NULL ? 220 : 27; + for (;;) { /* double */ if (!skip) { point_double(nq[0], nq[1], nq[2], nq[0], nq[1], nq[2]); } /* add multiples of the generator */ - if (gen_mul && (i <= 27)) { + if (g_scalar != NULL && i <= 27) { /* first, look 28 bits upwards */ bits = get_bit(g_scalar, i + 196) << 3; bits |= get_bit(g_scalar, i + 140) << 2; @@ -956,7 +923,7 @@ static void batch_mul(felem x_out, felem y_out, felem z_out, point_add(nq[0], nq[1], nq[2], nq[0], nq[1], nq[2], 1 /* mixed */, tmp[0], tmp[1], tmp[2]); } else { - memcpy(nq, tmp, 3 * sizeof(felem)); + OPENSSL_memcpy(nq, tmp, 3 * sizeof(felem)); skip = 0; } @@ -972,31 +939,33 @@ static void batch_mul(felem x_out, felem y_out, felem z_out, } /* do other additions every 5 doublings */ - if (num_points && (i % 5 == 0)) { - /* loop over all scalars */ - for (num = 0; num < num_points; ++num) { - bits = get_bit(scalars[num], i + 4) << 5; - bits |= get_bit(scalars[num], i + 3) << 4; - bits |= get_bit(scalars[num], i + 2) << 3; - bits |= get_bit(scalars[num], i + 1) << 2; - bits |= get_bit(scalars[num], i) << 1; - bits |= get_bit(scalars[num], i - 1); - ec_GFp_nistp_recode_scalar_bits(&sign, &digit, bits); - - /* select the point to add or subtract */ - select_point(digit, 17, pre_comp[num], tmp); - felem_neg(tmp[3], tmp[1]); /* (X, -Y, Z) is the negative point */ - copy_conditional(tmp[1], tmp[3], sign); - - if (!skip) { - point_add(nq[0], nq[1], nq[2], nq[0], nq[1], nq[2], mixed, tmp[0], - tmp[1], tmp[2]); - } else { - memcpy(nq, tmp, 3 * sizeof(felem)); - skip = 0; - } + if (p_scalar != NULL && i % 5 == 0) { + bits = get_bit(p_scalar, i + 4) << 5; + bits |= get_bit(p_scalar, i + 3) << 4; + bits |= get_bit(p_scalar, i + 2) << 3; + bits |= get_bit(p_scalar, i + 1) << 2; + bits |= get_bit(p_scalar, i) << 1; + bits |= get_bit(p_scalar, i - 1); + ec_GFp_nistp_recode_scalar_bits(&sign, &digit, bits); + + /* select the point to add or subtract */ + select_point(digit, 17, p_pre_comp, tmp); + felem_neg(tmp[3], tmp[1]); /* (X, -Y, Z) is the negative point */ + copy_conditional(tmp[1], tmp[3], sign); + + if (!skip) { + point_add(nq[0], nq[1], nq[2], nq[0], nq[1], nq[2], 0 /* mixed */, + tmp[0], tmp[1], tmp[2]); + } else { + OPENSSL_memcpy(nq, tmp, 3 * sizeof(felem)); + skip = 0; } } + + if (i == 0) { + break; + } + --i; } felem_assign(x_out, nq[0]); felem_assign(y_out, nq[1]); @@ -1005,10 +974,10 @@ static void batch_mul(felem x_out, felem y_out, felem z_out, /* Takes the Jacobian coordinates (X, Y, Z) of a point and returns * (X', Y') = (X/Z^2, Y/Z^3) */ -int ec_GFp_nistp224_point_get_affine_coordinates(const EC_GROUP *group, - const EC_POINT *point, - BIGNUM *x, BIGNUM *y, - BN_CTX *ctx) { +static int ec_GFp_nistp224_point_get_affine_coordinates(const EC_GROUP *group, + const EC_POINT *point, + BIGNUM *x, BIGNUM *y, + BN_CTX *ctx) { felem z1, z2, x_in, y_in, x_out, y_out; widefelem tmp; @@ -1047,46 +1016,16 @@ int ec_GFp_nistp224_point_get_affine_coordinates(const EC_GROUP *group, return 1; } -static void make_points_affine(size_t num, felem points[/*num*/][3], - felem tmp_felems[/*num+1*/]) { - /* Runs in constant time, unless an input is the point at infinity - * (which normally shouldn't happen). */ - ec_GFp_nistp_points_make_affine_internal( - num, points, sizeof(felem), tmp_felems, (void (*)(void *))felem_one, - (int (*)(const void *))felem_is_zero_int, - (void (*)(void *, const void *))felem_assign, - (void (*)(void *, const void *))felem_square_reduce, - (void (*)(void *, const void *, const void *))felem_mul_reduce, - (void (*)(void *, const void *))felem_inv, - (void (*)(void *, const void *))felem_contract); -} - -int ec_GFp_nistp224_points_mul(const EC_GROUP *group, EC_POINT *r, - const BIGNUM *g_scalar, const EC_POINT *p_, - const BIGNUM *p_scalar_, BN_CTX *ctx) { - /* TODO: This function used to take |points| and |scalars| as arrays of - * |num| elements. The code below should be simplified to work in terms of - * |p_| and |p_scalar_|. */ - size_t num = p_ != NULL ? 1 : 0; - const EC_POINT **points = p_ != NULL ? &p_ : NULL; - BIGNUM const *const *scalars = p_ != NULL ? &p_scalar_ : NULL; - +static int ec_GFp_nistp224_points_mul(const EC_GROUP *group, EC_POINT *r, + const BIGNUM *g_scalar, const EC_POINT *p, + const BIGNUM *p_scalar, BN_CTX *ctx) { int ret = 0; - int j; - unsigned i; - int mixed = 0; BN_CTX *new_ctx = NULL; BIGNUM *x, *y, *z, *tmp_scalar; - felem_bytearray g_secret; - felem_bytearray *secrets = NULL; - felem(*pre_comp)[17][3] = NULL; - felem *tmp_felems = NULL; + felem_bytearray g_secret, p_secret; + felem p_pre_comp[17][3]; felem_bytearray tmp; - unsigned num_bytes; - size_t num_points = num; felem x_in, y_in, z_in, x_out, y_out, z_out; - const EC_POINT *p = NULL; - const BIGNUM *p_scalar = NULL; if (ctx == NULL) { ctx = BN_CTX_new(); @@ -1104,87 +1043,54 @@ int ec_GFp_nistp224_points_mul(const EC_GROUP *group, EC_POINT *r, goto err; } - if (num_points > 0) { - if (num_points >= 3) { - /* unless we precompute multiples for just one or two points, - * converting those into affine form is time well spent */ - mixed = 1; - } - secrets = OPENSSL_malloc(num_points * sizeof(felem_bytearray)); - pre_comp = OPENSSL_malloc(num_points * sizeof(felem[17][3])); - if (mixed) { - tmp_felems = OPENSSL_malloc((num_points * 17 + 1) * sizeof(felem)); + if (p != NULL && p_scalar != NULL) { + /* We treat NULL scalars as 0, and NULL points as points at infinity, i.e., + * they contribute nothing to the linear combination. */ + OPENSSL_memset(&p_secret, 0, sizeof(p_secret)); + OPENSSL_memset(&p_pre_comp, 0, sizeof(p_pre_comp)); + size_t num_bytes; + /* reduce g_scalar to 0 <= g_scalar < 2^224 */ + if (BN_num_bits(p_scalar) > 224 || BN_is_negative(p_scalar)) { + /* this is an unusual input, and we don't guarantee + * constant-timeness */ + if (!BN_nnmod(tmp_scalar, p_scalar, &group->order, ctx)) { + OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB); + goto err; + } + num_bytes = BN_bn2bin(tmp_scalar, tmp); + } else { + num_bytes = BN_bn2bin(p_scalar, tmp); } - if (secrets == NULL || - pre_comp == NULL || - (mixed && tmp_felems == NULL)) { - OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE); + + flip_endian(p_secret, tmp, num_bytes); + /* precompute multiples */ + if (!BN_to_felem(x_out, &p->X) || + !BN_to_felem(y_out, &p->Y) || + !BN_to_felem(z_out, &p->Z)) { goto err; } - /* we treat NULL scalars as 0, and NULL points as points at infinity, - * i.e., they contribute nothing to the linear combination */ - memset(secrets, 0, num_points * sizeof(felem_bytearray)); - memset(pre_comp, 0, num_points * 17 * 3 * sizeof(felem)); - for (i = 0; i < num_points; ++i) { - if (i == num) { - /* the generator */ - p = EC_GROUP_get0_generator(group); - p_scalar = g_scalar; - } else { - /* the i^th point */ - p = points[i]; - p_scalar = scalars[i]; - } + felem_assign(p_pre_comp[1][0], x_out); + felem_assign(p_pre_comp[1][1], y_out); + felem_assign(p_pre_comp[1][2], z_out); - if (p_scalar != NULL && p != NULL) { - /* reduce g_scalar to 0 <= g_scalar < 2^224 */ - if (BN_num_bits(p_scalar) > 224 || BN_is_negative(p_scalar)) { - /* this is an unusual input, and we don't guarantee - * constant-timeness */ - if (!BN_nnmod(tmp_scalar, p_scalar, &group->order, ctx)) { - OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB); - goto err; - } - num_bytes = BN_bn2bin(tmp_scalar, tmp); - } else { - num_bytes = BN_bn2bin(p_scalar, tmp); - } - - flip_endian(secrets[i], tmp, num_bytes); - /* precompute multiples */ - if (!BN_to_felem(x_out, &p->X) || - !BN_to_felem(y_out, &p->Y) || - !BN_to_felem(z_out, &p->Z)) { - goto err; - } - - felem_assign(pre_comp[i][1][0], x_out); - felem_assign(pre_comp[i][1][1], y_out); - felem_assign(pre_comp[i][1][2], z_out); - - for (j = 2; j <= 16; ++j) { - if (j & 1) { - point_add(pre_comp[i][j][0], pre_comp[i][j][1], pre_comp[i][j][2], - pre_comp[i][1][0], pre_comp[i][1][1], pre_comp[i][1][2], - 0, pre_comp[i][j - 1][0], pre_comp[i][j - 1][1], - pre_comp[i][j - 1][2]); - } else { - point_double(pre_comp[i][j][0], pre_comp[i][j][1], - pre_comp[i][j][2], pre_comp[i][j / 2][0], - pre_comp[i][j / 2][1], pre_comp[i][j / 2][2]); - } - } + for (size_t j = 2; j <= 16; ++j) { + if (j & 1) { + point_add(p_pre_comp[j][0], p_pre_comp[j][1], p_pre_comp[j][2], + p_pre_comp[1][0], p_pre_comp[1][1], p_pre_comp[1][2], + 0, p_pre_comp[j - 1][0], p_pre_comp[j - 1][1], + p_pre_comp[j - 1][2]); + } else { + point_double(p_pre_comp[j][0], p_pre_comp[j][1], + p_pre_comp[j][2], p_pre_comp[j / 2][0], + p_pre_comp[j / 2][1], p_pre_comp[j / 2][2]); } } - - if (mixed) { - make_points_affine(num_points * 17, pre_comp[0], tmp_felems); - } } if (g_scalar != NULL) { - memset(g_secret, 0, sizeof(g_secret)); + OPENSSL_memset(g_secret, 0, sizeof(g_secret)); + size_t num_bytes; /* reduce g_scalar to 0 <= g_scalar < 2^224 */ if (BN_num_bits(g_scalar) > 224 || BN_is_negative(g_scalar)) { /* this is an unusual input, and we don't guarantee constant-timeness */ @@ -1199,9 +1105,9 @@ int ec_GFp_nistp224_points_mul(const EC_GROUP *group, EC_POINT *r, flip_endian(g_secret, tmp, num_bytes); } - batch_mul(x_out, y_out, z_out, (const felem_bytearray(*))secrets, - num_points, g_scalar != NULL ? g_secret : NULL, mixed, - (const felem(*)[17][3])pre_comp); + batch_mul(x_out, y_out, z_out, + (p != NULL && p_scalar != NULL) ? p_secret : NULL, + g_scalar != NULL ? g_secret : NULL, (const felem(*)[3])p_pre_comp); /* reduce the output to its unique minimal representation */ felem_contract(x_in, x_out); @@ -1218,27 +1124,20 @@ int ec_GFp_nistp224_points_mul(const EC_GROUP *group, EC_POINT *r, err: BN_CTX_end(ctx); BN_CTX_free(new_ctx); - OPENSSL_free(secrets); - OPENSSL_free(pre_comp); - OPENSSL_free(tmp_felems); return ret; } -const EC_METHOD *EC_GFp_nistp224_method(void) { - static const EC_METHOD ret = {ec_GFp_simple_group_init, - ec_GFp_simple_group_finish, - ec_GFp_simple_group_copy, - ec_GFp_simple_group_set_curve, - ec_GFp_nistp224_point_get_affine_coordinates, - ec_GFp_nistp224_points_mul, - 0 /* check_pub_key_order */, - ec_GFp_simple_field_mul, - ec_GFp_simple_field_sqr, - 0 /* field_encode */, - 0 /* field_decode */, - 0 /* field_set_to_one */}; - - return &ret; -} +const EC_METHOD EC_GFp_nistp224_method = { + ec_GFp_simple_group_init, + ec_GFp_simple_group_finish, + ec_GFp_simple_group_copy, + ec_GFp_simple_group_set_curve, + ec_GFp_nistp224_point_get_affine_coordinates, + ec_GFp_nistp224_points_mul, + ec_GFp_simple_field_mul, + ec_GFp_simple_field_sqr, + NULL /* field_encode */, + NULL /* field_decode */, +}; #endif /* 64_BIT && !WINDOWS && !SMALL */ diff --git a/Sources/BoringSSL/crypto/ec/p256-64.c b/Sources/BoringSSL/crypto/ec/p256-64.c index b94e226e7..0f32c2eec 100644 --- a/Sources/BoringSSL/crypto/ec/p256-64.c +++ b/Sources/BoringSSL/crypto/ec/p256-64.c @@ -27,7 +27,6 @@ #include #include #include -#include #include @@ -94,9 +93,8 @@ static void smallfelem_to_bin32(u8 out[32], const smallfelem in) { } /* To preserve endianness when using BN_bn2bin and BN_bin2bn. */ -static void flip_endian(u8 *out, const u8 *in, unsigned len) { - unsigned i; - for (i = 0; i < len; ++i) { +static void flip_endian(u8 *out, const u8 *in, size_t len) { + for (size_t i = 0; i < len; ++i) { out[i] = in[len - 1 - i]; } } @@ -110,8 +108,8 @@ static int BN_to_felem(felem out, const BIGNUM *bn) { felem_bytearray b_out; /* BN_bn2bin eats leading zeroes */ - memset(b_out, 0, sizeof(b_out)); - unsigned num_bytes = BN_num_bytes(bn); + OPENSSL_memset(b_out, 0, sizeof(b_out)); + size_t num_bytes = BN_num_bytes(bn); if (num_bytes > sizeof(b_out)) { OPENSSL_PUT_ERROR(EC, EC_R_BIGNUM_OUT_OF_RANGE); return 0; @@ -134,20 +132,6 @@ static BIGNUM *smallfelem_to_BN(BIGNUM *out, const smallfelem in) { /* Field operations. */ -static void smallfelem_one(smallfelem out) { - out[0] = 1; - out[1] = 0; - out[2] = 0; - out[3] = 0; -} - -static void smallfelem_assign(smallfelem out, const smallfelem in) { - out[0] = in[0]; - out[1] = in[1]; - out[2] = in[2]; - out[3] = in[3]; -} - static void felem_assign(felem out, const felem in) { out[0] = in[0]; out[1] = in[1]; @@ -191,9 +175,9 @@ static void longfelem_scalar(longfelem out, const u64 scalar) { out[7] *= scalar; } -#define two105m41m9 (((limb)1) << 105) - (((limb)1) << 41) - (((limb)1) << 9) +#define two105m41m9 ((((limb)1) << 105) - (((limb)1) << 41) - (((limb)1) << 9)) #define two105 (((limb)1) << 105) -#define two105m41p9 (((limb)1) << 105) - (((limb)1) << 41) + (((limb)1) << 9) +#define two105m41p9 ((((limb)1) << 105) - (((limb)1) << 41) + (((limb)1) << 9)) /* zero105 is 0 mod p */ static const felem zero105 = {two105m41m9, two105, two105m41p9, two105m41p9}; @@ -227,9 +211,11 @@ static void felem_diff(felem out, const felem in) { out[3] -= in[3]; } -#define two107m43m11 (((limb)1) << 107) - (((limb)1) << 43) - (((limb)1) << 11) +#define two107m43m11 \ + ((((limb)1) << 107) - (((limb)1) << 43) - (((limb)1) << 11)) #define two107 (((limb)1) << 107) -#define two107m43p11 (((limb)1) << 107) - (((limb)1) << 43) + (((limb)1) << 11) +#define two107m43p11 \ + ((((limb)1) << 107) - (((limb)1) << 43) + (((limb)1) << 11)) /* zero107 is 0 mod p */ static const felem zero107 = {two107m43m11, two107, two107m43p11, two107m43p11}; @@ -288,10 +274,10 @@ static void longfelem_diff(longfelem out, const longfelem in) { out[7] -= in[7]; } -#define two64m0 (((limb)1) << 64) - 1 -#define two110p32m0 (((limb)1) << 110) + (((limb)1) << 32) - 1 -#define two64m46 (((limb)1) << 64) - (((limb)1) << 46) -#define two64m32 (((limb)1) << 64) - (((limb)1) << 32) +#define two64m0 ((((limb)1) << 64) - 1) +#define two110p32m0 ((((limb)1) << 110) + (((limb)1) << 32) - 1) +#define two64m46 ((((limb)1) << 64) - (((limb)1) << 46)) +#define two64m32 ((((limb)1) << 64) - (((limb)1) << 32)) /* zero110 is 0 mod p. */ static const felem zero110 = {two64m0, two110p32m0, two64m46, two64m32}; @@ -343,8 +329,7 @@ static void felem_shrink(smallfelem out, const felem in) { * conditionally subtract kPrime if tmp[3] is large enough. */ high = tmp[3] >> 64; /* As tmp[3] < 2^65, high is either 1 or 0 */ - high <<= 63; - high >>= 63; + high = ~(high - 1); /* high is: * all ones if the high word of tmp[3] is 1 * all zeros if the high word of tmp[3] if 0 */ @@ -611,9 +596,9 @@ static void felem_small_mul(longfelem out, const smallfelem small1, smallfelem_mul(out, small1, small2); } -#define two100m36m4 (((limb)1) << 100) - (((limb)1) << 36) - (((limb)1) << 4) +#define two100m36m4 ((((limb)1) << 100) - (((limb)1) << 36) - (((limb)1) << 4)) #define two100 (((limb)1) << 100) -#define two100m36p4 (((limb)1) << 100) - (((limb)1) << 36) + (((limb)1) << 4) +#define two100m36p4 ((((limb)1) << 100) - (((limb)1) << 36) + (((limb)1) << 4)) /* zero100 is 0 mod p */ static const felem zero100 = {two100m36m4, two100, two100m36p4, two100m36p4}; @@ -735,8 +720,7 @@ static void felem_contract(smallfelem out, const felem in) { * each u64, from most-significant to least significant. For each one, if * all words so far have been equal (m is all ones) then a non-equal * result is the answer. Otherwise we continue. */ - unsigned i; - for (i = 3; i < 4; i--) { + for (size_t i = 3; i < 4; i--) { u64 equal; uint128_t a = ((uint128_t)kPrime[i]) - out[i]; /* if out[i] > kPrime[i] then a will underflow and the high 64-bits @@ -779,25 +763,6 @@ static void felem_contract(smallfelem out, const felem in) { subtract_u64(&out[3], &carry, result & kPrime[3]); } -static void smallfelem_square_contract(smallfelem out, const smallfelem in) { - longfelem longtmp; - felem tmp; - - smallfelem_square(longtmp, in); - felem_reduce(tmp, longtmp); - felem_contract(out, tmp); -} - -static void smallfelem_mul_contract(smallfelem out, const smallfelem in1, - const smallfelem in2) { - longfelem longtmp; - felem tmp; - - smallfelem_mul(longtmp, in1, in2); - felem_reduce(tmp, longtmp); - felem_contract(out, tmp); -} - /* felem_is_zero returns a limb with all bits set if |in| == 0 (mod p) and 0 * otherwise. * On entry: @@ -834,10 +799,6 @@ static limb smallfelem_is_zero(const smallfelem small) { return result; } -static int smallfelem_is_zero_int(const smallfelem small) { - return (int)(smallfelem_is_zero(small) & ((limb)1)); -} - /* felem_inv calculates |out| = |in|^{-1} * * Based on Fermat's Little Theorem: @@ -849,7 +810,6 @@ static void felem_inv(felem out, const felem in) { /* each e_I will hold |in|^{2^I - 1} */ felem e2, e4, e8, e16, e32, e64; longfelem tmp; - unsigned i; felem_square(tmp, in); felem_reduce(ftmp, tmp); /* 2^1 */ @@ -874,47 +834,47 @@ static void felem_inv(felem out, const felem in) { felem_mul(tmp, ftmp, e4); felem_reduce(ftmp, tmp); /* 2^8 - 2^0 */ felem_assign(e8, ftmp); - for (i = 0; i < 8; i++) { + for (size_t i = 0; i < 8; i++) { felem_square(tmp, ftmp); felem_reduce(ftmp, tmp); } /* 2^16 - 2^8 */ felem_mul(tmp, ftmp, e8); felem_reduce(ftmp, tmp); /* 2^16 - 2^0 */ felem_assign(e16, ftmp); - for (i = 0; i < 16; i++) { + for (size_t i = 0; i < 16; i++) { felem_square(tmp, ftmp); felem_reduce(ftmp, tmp); } /* 2^32 - 2^16 */ felem_mul(tmp, ftmp, e16); felem_reduce(ftmp, tmp); /* 2^32 - 2^0 */ felem_assign(e32, ftmp); - for (i = 0; i < 32; i++) { + for (size_t i = 0; i < 32; i++) { felem_square(tmp, ftmp); felem_reduce(ftmp, tmp); } /* 2^64 - 2^32 */ felem_assign(e64, ftmp); felem_mul(tmp, ftmp, in); felem_reduce(ftmp, tmp); /* 2^64 - 2^32 + 2^0 */ - for (i = 0; i < 192; i++) { + for (size_t i = 0; i < 192; i++) { felem_square(tmp, ftmp); felem_reduce(ftmp, tmp); } /* 2^256 - 2^224 + 2^192 */ felem_mul(tmp, e64, e32); felem_reduce(ftmp2, tmp); /* 2^64 - 2^0 */ - for (i = 0; i < 16; i++) { + for (size_t i = 0; i < 16; i++) { felem_square(tmp, ftmp2); felem_reduce(ftmp2, tmp); } /* 2^80 - 2^16 */ felem_mul(tmp, ftmp2, e16); felem_reduce(ftmp2, tmp); /* 2^80 - 2^0 */ - for (i = 0; i < 8; i++) { + for (size_t i = 0; i < 8; i++) { felem_square(tmp, ftmp2); felem_reduce(ftmp2, tmp); } /* 2^88 - 2^8 */ felem_mul(tmp, ftmp2, e8); felem_reduce(ftmp2, tmp); /* 2^88 - 2^0 */ - for (i = 0; i < 4; i++) { + for (size_t i = 0; i < 4; i++) { felem_square(tmp, ftmp2); felem_reduce(ftmp2, tmp); } /* 2^92 - 2^4 */ @@ -937,14 +897,6 @@ static void felem_inv(felem out, const felem in) { felem_reduce(out, tmp); /* 2^256 - 2^224 + 2^192 + 2^96 - 3 */ } -static void smallfelem_inv_contract(smallfelem out, const smallfelem in) { - felem tmp; - - smallfelem_expand(tmp, in); - felem_inv(tmp, tmp); - felem_contract(out, tmp); -} - /* Group operations * ---------------- * @@ -1055,8 +1007,7 @@ static void point_double_small(smallfelem x_out, smallfelem y_out, /* copy_conditional copies in to out iff mask is all ones. */ static void copy_conditional(felem out, const felem in, limb mask) { - unsigned i; - for (i = 0; i < NLIMBS; ++i) { + for (size_t i = 0; i < NLIMBS; ++i) { const limb tmp = mask & (in[i] ^ out[i]); out[i] ^= tmp; } @@ -1064,9 +1015,8 @@ static void copy_conditional(felem out, const felem in, limb mask) { /* copy_small_conditional copies in to out iff mask is all ones. */ static void copy_small_conditional(felem out, const smallfelem in, limb mask) { - unsigned i; const u64 mask64 = mask; - for (i = 0; i < NLIMBS; ++i) { + for (size_t i = 0; i < NLIMBS; ++i) { out[i] = ((limb)(in[i] & mask64)) | (out[i] & ~mask); } } @@ -1448,13 +1398,13 @@ static const smallfelem g_pre_comp[2][16][3] = { /* select_point selects the |idx|th point from a precomputation table and * copies it to out. */ -static void select_point(const u64 idx, unsigned int size, - const smallfelem pre_comp[16][3], smallfelem out[3]) { - unsigned i, j; +static void select_point(const u64 idx, size_t size, + const smallfelem pre_comp[/*size*/][3], + smallfelem out[3]) { u64 *outlimbs = &out[0][0]; - memset(outlimbs, 0, 3 * sizeof(smallfelem)); + OPENSSL_memset(outlimbs, 0, 3 * sizeof(smallfelem)); - for (i = 0; i < size; i++) { + for (size_t i = 0; i < size; i++) { const u64 *inlimbs = (const u64 *)&pre_comp[i][0][0]; u64 mask = i ^ idx; mask |= mask >> 4; @@ -1462,7 +1412,7 @@ static void select_point(const u64 idx, unsigned int size, mask |= mask >> 1; mask &= 1; mask--; - for (j = 0; j < NLIMBS * 3; j++) { + for (size_t j = 0; j < NLIMBS * 3; j++) { outlimbs[j] |= inlimbs[j] & mask; } } @@ -1477,38 +1427,34 @@ static char get_bit(const felem_bytearray in, int i) { } /* Interleaved point multiplication using precomputed point multiples: The - * small point multiples 0*P, 1*P, ..., 17*P are in pre_comp[], the scalars - * in scalars[]. If g_scalar is non-NULL, we also add this multiple of the - * generator, using certain (large) precomputed multiples in g_pre_comp. + * small point multiples 0*P, 1*P, ..., 17*P are in p_pre_comp, the scalar + * in p_scalar, if non-NULL. If g_scalar is non-NULL, we also add this multiple + * of the generator, using certain (large) precomputed multiples in g_pre_comp. * Output point (X, Y, Z) is stored in x_out, y_out, z_out. */ -static void batch_mul(felem x_out, felem y_out, felem z_out, - const felem_bytearray scalars[], - const unsigned num_points, const u8 *g_scalar, - const int mixed, const smallfelem pre_comp[][17][3]) { - int i, skip; - unsigned num, gen_mul = (g_scalar != NULL); +static void batch_mul(felem x_out, felem y_out, felem z_out, const u8 *p_scalar, + const u8 *g_scalar, const smallfelem p_pre_comp[17][3]) { felem nq[3], ftmp; smallfelem tmp[3]; u64 bits; u8 sign, digit; /* set nq to the point at infinity */ - memset(nq, 0, 3 * sizeof(felem)); + OPENSSL_memset(nq, 0, 3 * sizeof(felem)); - /* Loop over all scalars msb-to-lsb, interleaving additions of multiples - * of the generator (two in each of the last 32 rounds) and additions of - * other points multiples (every 5th round). */ + /* Loop over both scalars msb-to-lsb, interleaving additions of multiples + * of the generator (two in each of the last 32 rounds) and additions of p + * (every 5th round). */ - skip = 1; /* save two point operations in the first - * round */ - for (i = (num_points ? 255 : 31); i >= 0; --i) { + int skip = 1; /* save two point operations in the first round */ + size_t i = p_scalar != NULL ? 255 : 31; + for (;;) { /* double */ if (!skip) { point_double(nq[0], nq[1], nq[2], nq[0], nq[1], nq[2]); } /* add multiples of the generator */ - if (gen_mul && i <= 31) { + if (g_scalar != NULL && i <= 31) { /* first, look 32 bits upwards */ bits = get_bit(g_scalar, i + 224) << 3; bits |= get_bit(g_scalar, i + 160) << 2; @@ -1518,9 +1464,8 @@ static void batch_mul(felem x_out, felem y_out, felem z_out, select_point(bits, 16, g_pre_comp[1], tmp); if (!skip) { - /* Arg 1 below is for "mixed" */ - point_add(nq[0], nq[1], nq[2], nq[0], nq[1], nq[2], 1, tmp[0], tmp[1], - tmp[2]); + point_add(nq[0], nq[1], nq[2], nq[0], nq[1], nq[2], 1 /* mixed */, + tmp[0], tmp[1], tmp[2]); } else { smallfelem_expand(nq[0], tmp[0]); smallfelem_expand(nq[1], tmp[1]); @@ -1535,41 +1480,42 @@ static void batch_mul(felem x_out, felem y_out, felem z_out, bits |= get_bit(g_scalar, i); /* select the point to add, in constant time */ select_point(bits, 16, g_pre_comp[0], tmp); - /* Arg 1 below is for "mixed" */ - point_add(nq[0], nq[1], nq[2], nq[0], nq[1], nq[2], 1, tmp[0], tmp[1], - tmp[2]); + point_add(nq[0], nq[1], nq[2], nq[0], nq[1], nq[2], 1 /* mixed */, tmp[0], + tmp[1], tmp[2]); } /* do other additions every 5 doublings */ - if (num_points && (i % 5 == 0)) { - /* loop over all scalars */ - for (num = 0; num < num_points; ++num) { - bits = get_bit(scalars[num], i + 4) << 5; - bits |= get_bit(scalars[num], i + 3) << 4; - bits |= get_bit(scalars[num], i + 2) << 3; - bits |= get_bit(scalars[num], i + 1) << 2; - bits |= get_bit(scalars[num], i) << 1; - bits |= get_bit(scalars[num], i - 1); - ec_GFp_nistp_recode_scalar_bits(&sign, &digit, bits); - - /* select the point to add or subtract, in constant time. */ - select_point(digit, 17, pre_comp[num], tmp); - smallfelem_neg(ftmp, tmp[1]); /* (X, -Y, Z) is the negative - * point */ - copy_small_conditional(ftmp, tmp[1], (((limb)sign) - 1)); - felem_contract(tmp[1], ftmp); - - if (!skip) { - point_add(nq[0], nq[1], nq[2], nq[0], nq[1], nq[2], mixed, tmp[0], - tmp[1], tmp[2]); - } else { - smallfelem_expand(nq[0], tmp[0]); - smallfelem_expand(nq[1], tmp[1]); - smallfelem_expand(nq[2], tmp[2]); - skip = 0; - } + if (p_scalar != NULL && i % 5 == 0) { + bits = get_bit(p_scalar, i + 4) << 5; + bits |= get_bit(p_scalar, i + 3) << 4; + bits |= get_bit(p_scalar, i + 2) << 3; + bits |= get_bit(p_scalar, i + 1) << 2; + bits |= get_bit(p_scalar, i) << 1; + bits |= get_bit(p_scalar, i - 1); + ec_GFp_nistp_recode_scalar_bits(&sign, &digit, bits); + + /* select the point to add or subtract, in constant time. */ + select_point(digit, 17, p_pre_comp, tmp); + smallfelem_neg(ftmp, tmp[1]); /* (X, -Y, Z) is the negative + * point */ + copy_small_conditional(ftmp, tmp[1], (((limb)sign) - 1)); + felem_contract(tmp[1], ftmp); + + if (!skip) { + point_add(nq[0], nq[1], nq[2], nq[0], nq[1], nq[2], 0 /* mixed */, + tmp[0], tmp[1], tmp[2]); + } else { + smallfelem_expand(nq[0], tmp[0]); + smallfelem_expand(nq[1], tmp[1]); + smallfelem_expand(nq[2], tmp[2]); + skip = 0; } } + + if (i == 0) { + break; + } + --i; } felem_assign(x_out, nq[0]); felem_assign(y_out, nq[1]); @@ -1583,10 +1529,10 @@ static void batch_mul(felem x_out, felem y_out, felem z_out, /* Takes the Jacobian coordinates (X, Y, Z) of a point and returns (X', Y') = * (X/Z^2, Y/Z^3). */ -int ec_GFp_nistp256_point_get_affine_coordinates(const EC_GROUP *group, - const EC_POINT *point, - BIGNUM *x, BIGNUM *y, - BN_CTX *ctx) { +static int ec_GFp_nistp256_point_get_affine_coordinates(const EC_GROUP *group, + const EC_POINT *point, + BIGNUM *x, BIGNUM *y, + BN_CTX *ctx) { felem z1, z2, x_in, y_in; smallfelem x_out, y_out; longfelem tmp; @@ -1603,68 +1549,43 @@ int ec_GFp_nistp256_point_get_affine_coordinates(const EC_GROUP *group, felem_inv(z2, z1); felem_square(tmp, z2); felem_reduce(z1, tmp); - felem_mul(tmp, x_in, z1); - felem_reduce(x_in, tmp); - felem_contract(x_out, x_in); - if (x != NULL && !smallfelem_to_BN(x, x_out)) { - OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB); - return 0; + + if (x != NULL) { + felem_mul(tmp, x_in, z1); + felem_reduce(x_in, tmp); + felem_contract(x_out, x_in); + if (!smallfelem_to_BN(x, x_out)) { + OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB); + return 0; + } } - felem_mul(tmp, z1, z2); - felem_reduce(z1, tmp); - felem_mul(tmp, y_in, z1); - felem_reduce(y_in, tmp); - felem_contract(y_out, y_in); - if (y != NULL && !smallfelem_to_BN(y, y_out)) { - OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB); - return 0; + + if (y != NULL) { + felem_mul(tmp, z1, z2); + felem_reduce(z1, tmp); + felem_mul(tmp, y_in, z1); + felem_reduce(y_in, tmp); + felem_contract(y_out, y_in); + if (!smallfelem_to_BN(y, y_out)) { + OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB); + return 0; + } } - return 1; -} -/* points below is of size |num|, and tmp_smallfelems is of size |num+1| */ -static void make_points_affine(size_t num, smallfelem points[][3], - smallfelem tmp_smallfelems[]) { - /* Runs in constant time, unless an input is the point at infinity (which - * normally shouldn't happen). */ - ec_GFp_nistp_points_make_affine_internal( - num, points, sizeof(smallfelem), tmp_smallfelems, - (void (*)(void *))smallfelem_one, - (int (*)(const void *))smallfelem_is_zero_int, - (void (*)(void *, const void *))smallfelem_assign, - (void (*)(void *, const void *))smallfelem_square_contract, - (void (*)(void *, const void *, const void *))smallfelem_mul_contract, - (void (*)(void *, const void *))smallfelem_inv_contract, - /* nothing to contract */ - (void (*)(void *, const void *))smallfelem_assign); + return 1; } -int ec_GFp_nistp256_points_mul(const EC_GROUP *group, EC_POINT *r, - const BIGNUM *g_scalar, const EC_POINT *p_, - const BIGNUM *p_scalar_, BN_CTX *ctx) { - /* TODO: This function used to take |points| and |scalars| as arrays of - * |num| elements. The code below should be simplified to work in terms of |p| - * and |p_scalar|. */ - size_t num = p_ != NULL ? 1 : 0; - const EC_POINT **points = p_ != NULL ? &p_ : NULL; - BIGNUM const *const *scalars = p_ != NULL ? &p_scalar_ : NULL; - +static int ec_GFp_nistp256_points_mul(const EC_GROUP *group, EC_POINT *r, + const BIGNUM *g_scalar, const EC_POINT *p, + const BIGNUM *p_scalar, BN_CTX *ctx) { int ret = 0; - int j; - int mixed = 0; BN_CTX *new_ctx = NULL; BIGNUM *x, *y, *z, *tmp_scalar; - felem_bytearray g_secret; - felem_bytearray *secrets = NULL; - smallfelem(*pre_comp)[17][3] = NULL; - smallfelem *tmp_smallfelems = NULL; + felem_bytearray g_secret, p_secret; + smallfelem p_pre_comp[17][3]; felem_bytearray tmp; - unsigned i, num_bytes; - size_t num_points = num; smallfelem x_in, y_in, z_in; felem x_out, y_out, z_out; - const EC_POINT *p = NULL; - const BIGNUM *p_scalar = NULL; if (ctx == NULL) { ctx = new_ctx = BN_CTX_new(); @@ -1681,83 +1602,52 @@ int ec_GFp_nistp256_points_mul(const EC_GROUP *group, EC_POINT *r, goto err; } - if (num_points > 0) { - if (num_points >= 3) { - /* unless we precompute multiples for just one or two points, - * converting those into affine form is time well spent */ - mixed = 1; - } - secrets = OPENSSL_malloc(num_points * sizeof(felem_bytearray)); - pre_comp = OPENSSL_malloc(num_points * sizeof(smallfelem[17][3])); - if (mixed) { - tmp_smallfelems = - OPENSSL_malloc((num_points * 17 + 1) * sizeof(smallfelem)); + if (p != NULL && p_scalar != NULL) { + /* We treat NULL scalars as 0, and NULL points as points at infinity, i.e., + * they contribute nothing to the linear combination. */ + OPENSSL_memset(&p_secret, 0, sizeof(p_secret)); + OPENSSL_memset(&p_pre_comp, 0, sizeof(p_pre_comp)); + size_t num_bytes; + /* Reduce g_scalar to 0 <= g_scalar < 2^256. */ + if (BN_num_bits(p_scalar) > 256 || BN_is_negative(p_scalar)) { + /* This is an unusual input, and we don't guarantee constant-timeness. */ + if (!BN_nnmod(tmp_scalar, p_scalar, &group->order, ctx)) { + OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB); + goto err; + } + num_bytes = BN_bn2bin(tmp_scalar, tmp); + } else { + num_bytes = BN_bn2bin(p_scalar, tmp); } - if (secrets == NULL || pre_comp == NULL || - (mixed && tmp_smallfelems == NULL)) { - OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE); + flip_endian(p_secret, tmp, num_bytes); + /* Precompute multiples. */ + if (!BN_to_felem(x_out, &p->X) || + !BN_to_felem(y_out, &p->Y) || + !BN_to_felem(z_out, &p->Z)) { goto err; } - - /* we treat NULL scalars as 0, and NULL points as points at infinity, - * i.e., they contribute nothing to the linear combination. */ - memset(secrets, 0, num_points * sizeof(felem_bytearray)); - memset(pre_comp, 0, num_points * 17 * 3 * sizeof(smallfelem)); - for (i = 0; i < num_points; ++i) { - if (i == num) { - /* we didn't have a valid precomputation, so we pick the generator. */ - p = EC_GROUP_get0_generator(group); - p_scalar = g_scalar; + felem_shrink(p_pre_comp[1][0], x_out); + felem_shrink(p_pre_comp[1][1], y_out); + felem_shrink(p_pre_comp[1][2], z_out); + for (size_t j = 2; j <= 16; ++j) { + if (j & 1) { + point_add_small(p_pre_comp[j][0], p_pre_comp[j][1], + p_pre_comp[j][2], p_pre_comp[1][0], + p_pre_comp[1][1], p_pre_comp[1][2], + p_pre_comp[j - 1][0], p_pre_comp[j - 1][1], + p_pre_comp[j - 1][2]); } else { - /* the i^th point */ - p = points[i]; - p_scalar = scalars[i]; - } - if (p_scalar != NULL && p != NULL) { - /* reduce g_scalar to 0 <= g_scalar < 2^256 */ - if (BN_num_bits(p_scalar) > 256 || BN_is_negative(p_scalar)) { - /* this is an unusual input, and we don't guarantee - * constant-timeness. */ - if (!BN_nnmod(tmp_scalar, p_scalar, &group->order, ctx)) { - OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB); - goto err; - } - num_bytes = BN_bn2bin(tmp_scalar, tmp); - } else { - num_bytes = BN_bn2bin(p_scalar, tmp); - } - flip_endian(secrets[i], tmp, num_bytes); - /* precompute multiples */ - if (!BN_to_felem(x_out, &p->X) || - !BN_to_felem(y_out, &p->Y) || - !BN_to_felem(z_out, &p->Z)) { - goto err; - } - felem_shrink(pre_comp[i][1][0], x_out); - felem_shrink(pre_comp[i][1][1], y_out); - felem_shrink(pre_comp[i][1][2], z_out); - for (j = 2; j <= 16; ++j) { - if (j & 1) { - point_add_small(pre_comp[i][j][0], pre_comp[i][j][1], - pre_comp[i][j][2], pre_comp[i][1][0], - pre_comp[i][1][1], pre_comp[i][1][2], - pre_comp[i][j - 1][0], pre_comp[i][j - 1][1], - pre_comp[i][j - 1][2]); - } else { - point_double_small(pre_comp[i][j][0], pre_comp[i][j][1], - pre_comp[i][j][2], pre_comp[i][j / 2][0], - pre_comp[i][j / 2][1], pre_comp[i][j / 2][2]); - } - } + point_double_small(p_pre_comp[j][0], p_pre_comp[j][1], + p_pre_comp[j][2], p_pre_comp[j / 2][0], + p_pre_comp[j / 2][1], p_pre_comp[j / 2][2]); } } - if (mixed) { - make_points_affine(num_points * 17, pre_comp[0], tmp_smallfelems); - } } if (g_scalar != NULL) { - memset(g_secret, 0, sizeof(g_secret)); + size_t num_bytes; + + OPENSSL_memset(g_secret, 0, sizeof(g_secret)); /* reduce g_scalar to 0 <= g_scalar < 2^256 */ if (BN_num_bits(g_scalar) > 256 || BN_is_negative(g_scalar)) { /* this is an unusual input, and we don't guarantee @@ -1772,9 +1662,10 @@ int ec_GFp_nistp256_points_mul(const EC_GROUP *group, EC_POINT *r, } flip_endian(g_secret, tmp, num_bytes); } - batch_mul(x_out, y_out, z_out, (const felem_bytearray(*))secrets, - num_points, g_scalar != NULL ? g_secret : NULL, mixed, - (const smallfelem(*)[17][3])pre_comp); + batch_mul(x_out, y_out, z_out, + (p != NULL && p_scalar != NULL) ? p_secret : NULL, + g_scalar != NULL ? g_secret : NULL, + (const smallfelem(*)[3]) &p_pre_comp); /* reduce the output to its unique minimal representation */ felem_contract(x_in, x_out); @@ -1791,26 +1682,20 @@ int ec_GFp_nistp256_points_mul(const EC_GROUP *group, EC_POINT *r, err: BN_CTX_end(ctx); BN_CTX_free(new_ctx); - OPENSSL_free(secrets); - OPENSSL_free(pre_comp); - OPENSSL_free(tmp_smallfelems); return ret; } -const EC_METHOD *EC_GFp_nistp256_method(void) { - static const EC_METHOD ret = { - ec_GFp_simple_group_init, - ec_GFp_simple_group_finish, - ec_GFp_simple_group_copy, - ec_GFp_simple_group_set_curve, - ec_GFp_nistp256_point_get_affine_coordinates, - ec_GFp_nistp256_points_mul, - 0 /* check_pub_key_order */, - ec_GFp_simple_field_mul, ec_GFp_simple_field_sqr, - 0 /* field_encode */, 0 /* field_decode */, 0 /* field_set_to_one */ - }; - - return &ret; -} +const EC_METHOD EC_GFp_nistp256_method = { + ec_GFp_simple_group_init, + ec_GFp_simple_group_finish, + ec_GFp_simple_group_copy, + ec_GFp_simple_group_set_curve, + ec_GFp_nistp256_point_get_affine_coordinates, + ec_GFp_nistp256_points_mul, + ec_GFp_simple_field_mul, + ec_GFp_simple_field_sqr, + NULL /* field_encode */, + NULL /* field_decode */, +}; #endif /* 64_BIT && !WINDOWS */ diff --git a/Sources/BoringSSL/crypto/ec/p256-x86_64.c b/Sources/BoringSSL/crypto/ec/p256-x86_64.c index ca967b31e..652d10cd1 100644 --- a/Sources/BoringSSL/crypto/ec/p256-x86_64.c +++ b/Sources/BoringSSL/crypto/ec/p256-x86_64.c @@ -31,48 +31,16 @@ #include #include "../bn/internal.h" -#include "../ec/internal.h" #include "../internal.h" +#include "internal.h" +#include "p256-x86_64.h" #if !defined(OPENSSL_NO_ASM) && defined(OPENSSL_X86_64) && \ !defined(OPENSSL_SMALL) - -#define P256_LIMBS (256 / BN_BITS2) - -typedef struct { - BN_ULONG X[P256_LIMBS]; - BN_ULONG Y[P256_LIMBS]; - BN_ULONG Z[P256_LIMBS]; -} P256_POINT; - -typedef struct { - BN_ULONG X[P256_LIMBS]; - BN_ULONG Y[P256_LIMBS]; -} P256_POINT_AFFINE; - typedef P256_POINT_AFFINE PRECOMP256_ROW[64]; -/* Functions implemented in assembly */ - -/* Modular neg: res = -a mod P */ -void ecp_nistz256_neg(BN_ULONG res[P256_LIMBS], const BN_ULONG a[P256_LIMBS]); -/* Montgomery mul: res = a*b*2^-256 mod P */ -void ecp_nistz256_mul_mont(BN_ULONG res[P256_LIMBS], - const BN_ULONG a[P256_LIMBS], - const BN_ULONG b[P256_LIMBS]); -/* Montgomery sqr: res = a*a*2^-256 mod P */ -void ecp_nistz256_sqr_mont(BN_ULONG res[P256_LIMBS], - const BN_ULONG a[P256_LIMBS]); -/* Convert a number from Montgomery domain, by multiplying with 1 */ -void ecp_nistz256_from_mont(BN_ULONG res[P256_LIMBS], - const BN_ULONG in[P256_LIMBS]); -/* Functions that perform constant time access to the precomputed tables */ -void ecp_nistz256_select_w5(P256_POINT *val, const P256_POINT *in_t, int index); -void ecp_nistz256_select_w7(P256_POINT_AFFINE *val, - const P256_POINT_AFFINE *in_t, int index); - /* One converted into the Montgomery domain */ static const BN_ULONG ONE[P256_LIMBS] = { TOBN(0x00000000, 0x00000001), TOBN(0xffffffff, 0x00000000), @@ -82,7 +50,7 @@ static const BN_ULONG ONE[P256_LIMBS] = { /* Precomputed tables for the default generator */ #include "p256-x86_64-table.h" -/* Recode window to a signed digit, see ecp_nistputil.c for details */ +/* Recode window to a signed digit, see util-64.c for details */ static unsigned booth_recode_w5(unsigned in) { unsigned s, d; @@ -105,6 +73,11 @@ static unsigned booth_recode_w7(unsigned in) { return (d << 1) + (s & 1); } +/* copy_conditional copies |src| to |dst| if |move| is one and leaves it as-is + * if |move| is zero. + * + * WARNING: this breaks the usual convention of constant-time functions + * returning masks. */ static void copy_conditional(BN_ULONG dst[P256_LIMBS], const BN_ULONG src[P256_LIMBS], BN_ULONG move) { BN_ULONG mask1 = ((BN_ULONG)0) - move; @@ -122,15 +95,34 @@ static void copy_conditional(BN_ULONG dst[P256_LIMBS], } } -void ecp_nistz256_point_double(P256_POINT *r, const P256_POINT *a); -void ecp_nistz256_point_add(P256_POINT *r, const P256_POINT *a, - const P256_POINT *b); -void ecp_nistz256_point_add_affine(P256_POINT *r, const P256_POINT *a, - const P256_POINT_AFFINE *b); +/* is_not_zero returns one iff in != 0 and zero otherwise. + * + * WARNING: this breaks the usual convention of constant-time functions + * returning masks. + * + * (define-fun is_not_zero ((in (_ BitVec 64))) (_ BitVec 64) + * (bvlshr (bvor in (bvsub #x0000000000000000 in)) #x000000000000003f) + * ) + * + * (declare-fun x () (_ BitVec 64)) + * + * (assert (and (= x #x0000000000000000) (= (is_not_zero x) #x0000000000000001))) + * (check-sat) + * + * (assert (and (not (= x #x0000000000000000)) (= (is_not_zero x) #x0000000000000000))) + * (check-sat) + * */ +static BN_ULONG is_not_zero(BN_ULONG in) { + in |= (0 - in); + in >>= BN_BITS2 - 1; + return in; +} -/* r = in^-1 mod p */ -static void ecp_nistz256_mod_inverse(BN_ULONG r[P256_LIMBS], - const BN_ULONG in[P256_LIMBS]) { +/* ecp_nistz256_mod_inverse_mont sets |r| to (|in| * 2^-256)^-1 * 2^256 mod p. + * That is, |r| is the modular inverse of |in| for input and output in the + * Montgomery domain. */ +static void ecp_nistz256_mod_inverse_mont(BN_ULONG r[P256_LIMBS], + const BN_ULONG in[P256_LIMBS]) { /* The poly is ffffffff 00000001 00000000 00000000 00000000 ffffffff ffffffff ffffffff We use FLT and used poly-2 as exponent */ @@ -205,9 +197,7 @@ static void ecp_nistz256_mod_inverse(BN_ULONG r[P256_LIMBS], ecp_nistz256_sqr_mont(res, res); ecp_nistz256_sqr_mont(res, res); - ecp_nistz256_mul_mont(res, res, in); - - memcpy(r, res, sizeof(res)); + ecp_nistz256_mul_mont(r, res, in); } /* ecp_nistz256_bignum_to_field_elem copies the contents of |in| to |out| and @@ -218,8 +208,8 @@ static int ecp_nistz256_bignum_to_field_elem(BN_ULONG out[P256_LIMBS], return 0; } - memset(out, 0, sizeof(BN_ULONG) * P256_LIMBS); - memcpy(out, in->d, sizeof(BN_ULONG) * in->top); + OPENSSL_memset(out, 0, sizeof(BN_ULONG) * P256_LIMBS); + OPENSSL_memcpy(out, in->d, sizeof(BN_ULONG) * in->top); return 1; } @@ -314,7 +304,7 @@ static int ecp_nistz256_windowed_mul(const EC_GROUP *group, P256_POINT *r, ecp_nistz256_point_double(&row[10 - 1], &row[5 - 1]); ecp_nistz256_point_add(&row[15 - 1], &row[14 - 1], &row[1 - 1]); ecp_nistz256_point_add(&row[11 - 1], &row[10 - 1], &row[1 - 1]); - ecp_nistz256_point_add(&row[16 - 1], &row[15 - 1], &row[1 - 1]); + ecp_nistz256_point_double(&row[16 - 1], &row[8 - 1]); BN_ULONG tmp[P256_LIMBS]; alignas(32) P256_POINT h; @@ -390,17 +380,6 @@ static int ecp_nistz256_points_mul( BN_CTX *new_ctx = NULL; int ctx_started = 0; - /* Need 256 bits for space for all coordinates. */ - if (bn_wexpand(&r->X, P256_LIMBS) == NULL || - bn_wexpand(&r->Y, P256_LIMBS) == NULL || - bn_wexpand(&r->Z, P256_LIMBS) == NULL) { - OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE); - goto err; - } - r->X.top = P256_LIMBS; - r->Y.top = P256_LIMBS; - r->Z.top = P256_LIMBS; - if (g_scalar != NULL) { if (BN_num_bits(g_scalar) > 256 || BN_is_negative(g_scalar)) { if (ctx == NULL) { @@ -459,7 +438,11 @@ static int ecp_nistz256_points_mul( ecp_nistz256_neg(p.p.Z, p.p.Y); copy_conditional(p.p.Y, p.p.Z, wvalue & 1); - memcpy(p.p.Z, ONE, sizeof(ONE)); + /* Convert |p| from affine to Jacobian coordinates. We set Z to zero if |p| + * is infinity and |ONE| otherwise. |p| was computed from the table, so it + * is infinity iff |wvalue >> 1| is zero. */ + OPENSSL_memset(p.p.Z, 0, sizeof(p.p.Z)); + copy_conditional(p.p.Z, ONE, is_not_zero(wvalue >> 1)); for (i = 1; i < 37; i++) { unsigned off = (index - 1) / 8; @@ -494,15 +477,12 @@ static int ecp_nistz256_points_mul( } } - memcpy(r->X.d, p.p.X, sizeof(p.p.X)); - memcpy(r->Y.d, p.p.Y, sizeof(p.p.Y)); - memcpy(r->Z.d, p.p.Z, sizeof(p.p.Z)); - /* Not constant-time, but we're only operating on the public output. */ - bn_correct_top(&r->X); - bn_correct_top(&r->Y); - bn_correct_top(&r->Z); - r->Z_is_one = BN_is_one(&r->Z); + if (!bn_set_words(&r->X, p.p.X, P256_LIMBS) || + !bn_set_words(&r->Y, p.p.Y, P256_LIMBS) || + !bn_set_words(&r->Z, p.p.Z, P256_LIMBS)) { + return 0; + } ret = 1; @@ -518,8 +498,6 @@ static int ecp_nistz256_get_affine(const EC_GROUP *group, const EC_POINT *point, BIGNUM *x, BIGNUM *y, BN_CTX *ctx) { BN_ULONG z_inv2[P256_LIMBS]; BN_ULONG z_inv3[P256_LIMBS]; - BN_ULONG x_aff[P256_LIMBS]; - BN_ULONG y_aff[P256_LIMBS]; BN_ULONG point_x[P256_LIMBS], point_y[P256_LIMBS], point_z[P256_LIMBS]; if (EC_POINT_is_at_infinity(group, point)) { @@ -534,53 +512,50 @@ static int ecp_nistz256_get_affine(const EC_GROUP *group, const EC_POINT *point, return 0; } - ecp_nistz256_mod_inverse(z_inv3, point_z); + ecp_nistz256_mod_inverse_mont(z_inv3, point_z); ecp_nistz256_sqr_mont(z_inv2, z_inv3); - ecp_nistz256_mul_mont(x_aff, z_inv2, point_x); + + /* Instead of using |ecp_nistz256_from_mont| to convert the |x| coordinate + * and then calling |ecp_nistz256_from_mont| again to convert the |y| + * coordinate below, convert the common factor |z_inv2| once now, saving one + * reduction. */ + ecp_nistz256_from_mont(z_inv2, z_inv2); if (x != NULL) { - if (bn_wexpand(x, P256_LIMBS) == NULL) { + BN_ULONG x_aff[P256_LIMBS]; + ecp_nistz256_mul_mont(x_aff, z_inv2, point_x); + if (!bn_set_words(x, x_aff, P256_LIMBS)) { OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE); return 0; } - x->top = P256_LIMBS; - ecp_nistz256_from_mont(x->d, x_aff); - bn_correct_top(x); } if (y != NULL) { + BN_ULONG y_aff[P256_LIMBS]; ecp_nistz256_mul_mont(z_inv3, z_inv3, z_inv2); ecp_nistz256_mul_mont(y_aff, z_inv3, point_y); - if (bn_wexpand(y, P256_LIMBS) == NULL) { + if (!bn_set_words(y, y_aff, P256_LIMBS)) { OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE); return 0; } - y->top = P256_LIMBS; - ecp_nistz256_from_mont(y->d, y_aff); - bn_correct_top(y); } return 1; } -const EC_METHOD *EC_GFp_nistz256_method(void) { - static const EC_METHOD ret = { - ec_GFp_mont_group_init, - ec_GFp_mont_group_finish, - ec_GFp_mont_group_copy, - ec_GFp_mont_group_set_curve, - ecp_nistz256_get_affine, - ecp_nistz256_points_mul, - 0 /* check_pub_key_order */, - ec_GFp_mont_field_mul, - ec_GFp_mont_field_sqr, - ec_GFp_mont_field_encode, - ec_GFp_mont_field_decode, - ec_GFp_mont_field_set_to_one, - }; - - return &ret; -} + +const EC_METHOD EC_GFp_nistz256_method = { + ec_GFp_mont_group_init, + ec_GFp_mont_group_finish, + ec_GFp_mont_group_copy, + ec_GFp_mont_group_set_curve, + ecp_nistz256_get_affine, + ecp_nistz256_points_mul, + ec_GFp_mont_field_mul, + ec_GFp_mont_field_sqr, + ec_GFp_mont_field_encode, + ec_GFp_mont_field_decode, +}; #endif /* !defined(OPENSSL_NO_ASM) && defined(OPENSSL_X86_64) && \ !defined(OPENSSL_SMALL) */ diff --git a/Sources/BoringSSL/crypto/ec/p256-x86_64.h b/Sources/BoringSSL/crypto/ec/p256-x86_64.h new file mode 100644 index 000000000..0132348e7 --- /dev/null +++ b/Sources/BoringSSL/crypto/ec/p256-x86_64.h @@ -0,0 +1,113 @@ +/* Copyright (c) 2014, Intel Corporation. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#ifndef OPENSSL_HEADER_EC_P256_X86_64_H +#define OPENSSL_HEADER_EC_P256_X86_64_H + +#include + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +#if !defined(OPENSSL_NO_ASM) && defined(OPENSSL_X86_64) && \ + !defined(OPENSSL_SMALL) + +/* P-256 field operations. + * + * An element mod P in P-256 is represented as a little-endian array of + * |P256_LIMBS| |BN_ULONG|s, spanning the full range of values. + * + * The following functions take fully-reduced inputs mod P and give + * fully-reduced outputs. They may be used in-place. */ + +#define P256_LIMBS (256 / BN_BITS2) + +/* ecp_nistz256_neg sets |res| to -|a| mod P. */ +void ecp_nistz256_neg(BN_ULONG res[P256_LIMBS], const BN_ULONG a[P256_LIMBS]); + +/* ecp_nistz256_mul_mont sets |res| to |a| * |b| * 2^-256 mod P. */ +void ecp_nistz256_mul_mont(BN_ULONG res[P256_LIMBS], + const BN_ULONG a[P256_LIMBS], + const BN_ULONG b[P256_LIMBS]); + +/* ecp_nistz256_sqr_mont sets |res| to |a| * |a| * 2^-256 mod P. */ +void ecp_nistz256_sqr_mont(BN_ULONG res[P256_LIMBS], + const BN_ULONG a[P256_LIMBS]); + +/* ecp_nistz256_from_mont sets |res| to |in|, converted from Montgomery domain + * by multiplying with 1. */ +static inline void ecp_nistz256_from_mont(BN_ULONG res[P256_LIMBS], + const BN_ULONG in[P256_LIMBS]) { + static const BN_ULONG ONE[P256_LIMBS] = { 1 }; + ecp_nistz256_mul_mont(res, in, ONE); +} + + +/* P-256 point operations. + * + * The following functions may be used in-place. All coordinates are in the + * Montgomery domain. */ + +/* A P256_POINT represents a P-256 point in Jacobian coordinates. */ +typedef struct { + BN_ULONG X[P256_LIMBS]; + BN_ULONG Y[P256_LIMBS]; + BN_ULONG Z[P256_LIMBS]; +} P256_POINT; + +/* A P256_POINT_AFFINE represents a P-256 point in affine coordinates. Infinity + * is encoded as (0, 0). */ +typedef struct { + BN_ULONG X[P256_LIMBS]; + BN_ULONG Y[P256_LIMBS]; +} P256_POINT_AFFINE; + +/* ecp_nistz256_select_w5 sets |*val| to |in_t[index-1]| if 1 <= |index| <= 16 + * and all zeros (the point at infinity) if |index| is 0. This is done in + * constant time. */ +void ecp_nistz256_select_w5(P256_POINT *val, const P256_POINT in_t[16], + int index); + +/* ecp_nistz256_select_w7 sets |*val| to |in_t[index-1]| if 1 <= |index| <= 64 + * and all zeros (the point at infinity) if |index| is 0. This is done in + * constant time. */ +void ecp_nistz256_select_w7(P256_POINT_AFFINE *val, + const P256_POINT_AFFINE in_t[64], int index); + +/* ecp_nistz256_point_double sets |r| to |a| doubled. */ +void ecp_nistz256_point_double(P256_POINT *r, const P256_POINT *a); + +/* ecp_nistz256_point_add adds |a| to |b| and places the result in |r|. */ +void ecp_nistz256_point_add(P256_POINT *r, const P256_POINT *a, + const P256_POINT *b); + +/* ecp_nistz256_point_add_affine adds |a| to |b| and places the result in + * |r|. |a| and |b| must not represent the same point unless they are both + * infinity. */ +void ecp_nistz256_point_add_affine(P256_POINT *r, const P256_POINT *a, + const P256_POINT_AFFINE *b); + +#endif /* !defined(OPENSSL_NO_ASM) && defined(OPENSSL_X86_64) && \ + !defined(OPENSSL_SMALL) */ + + +#if defined(__cplusplus) +} /* extern C++ */ +#endif + +#endif /* OPENSSL_HEADER_EC_P256_X86_64_H */ diff --git a/Sources/BoringSSL/crypto/ec/simple.c b/Sources/BoringSSL/crypto/ec/simple.c index 4eb612eb1..880b717c1 100644 --- a/Sources/BoringSSL/crypto/ec/simple.c +++ b/Sources/BoringSSL/crypto/ec/simple.c @@ -74,6 +74,7 @@ #include #include "internal.h" +#include "../internal.h" /* Most method functions in this file are designed to work with non-trivial @@ -82,16 +83,16 @@ * field_sqr methods will be used for multiplication, and field_encode and * field_decode (if defined) will be used for converting between * representations. - - * Functions ec_GFp_simple_points_make_affine() and - * ec_GFp_simple_point_get_affine_coordinates() specifically assume that if a - * non-trivial representation is used, it is a Montgomery representation (i.e. - * 'encoding' means multiplying by some factor R). */ + * + * Functions here specifically assume that if a non-trivial representation is + * used, it is a Montgomery representation (i.e. 'encoding' means multiplying + * by some factor R). */ int ec_GFp_simple_group_init(EC_GROUP *group) { BN_init(&group->field); BN_init(&group->a); BN_init(&group->b); + BN_init(&group->one); group->a_is_minus3 = 0; return 1; } @@ -100,12 +101,14 @@ void ec_GFp_simple_group_finish(EC_GROUP *group) { BN_free(&group->field); BN_free(&group->a); BN_free(&group->b); + BN_free(&group->one); } int ec_GFp_simple_group_copy(EC_GROUP *dest, const EC_GROUP *src) { if (!BN_copy(&dest->field, &src->field) || !BN_copy(&dest->a, &src->a) || - !BN_copy(&dest->b, &src->b)) { + !BN_copy(&dest->b, &src->b) || + !BN_copy(&dest->one, &src->one)) { return 0; } @@ -172,6 +175,14 @@ int ec_GFp_simple_group_set_curve(EC_GROUP *group, const BIGNUM *p, } group->a_is_minus3 = (0 == BN_cmp(tmp_a, &group->field)); + if (group->meth->field_encode != NULL) { + if (!group->meth->field_encode(group, &group->one, BN_value_one(), ctx)) { + goto err; + } + } else if (!BN_copy(&group->one, BN_value_one())) { + goto err; + } + ret = 1; err: @@ -228,7 +239,6 @@ int ec_GFp_simple_point_init(EC_POINT *point) { BN_init(&point->X); BN_init(&point->Y); BN_init(&point->Z); - point->Z_is_one = 0; return 1; } @@ -243,7 +253,6 @@ void ec_GFp_simple_point_clear_finish(EC_POINT *point) { BN_clear_free(&point->X); BN_clear_free(&point->Y); BN_clear_free(&point->Z); - point->Z_is_one = 0; } int ec_GFp_simple_point_copy(EC_POINT *dest, const EC_POINT *src) { @@ -252,18 +261,32 @@ int ec_GFp_simple_point_copy(EC_POINT *dest, const EC_POINT *src) { !BN_copy(&dest->Z, &src->Z)) { return 0; } - dest->Z_is_one = src->Z_is_one; return 1; } int ec_GFp_simple_point_set_to_infinity(const EC_GROUP *group, EC_POINT *point) { - point->Z_is_one = 0; BN_zero(&point->Z); return 1; } +static int set_Jprojective_coordinate_GFp(const EC_GROUP *group, BIGNUM *out, + const BIGNUM *in, BN_CTX *ctx) { + if (in == NULL) { + return 1; + } + if (BN_is_negative(in) || + BN_cmp(in, &group->field) >= 0) { + OPENSSL_PUT_ERROR(EC, EC_R_COORDINATES_OUT_OF_RANGE); + return 0; + } + if (group->meth->field_encode) { + return group->meth->field_encode(group, out, in, ctx); + } + return BN_copy(out, in) != NULL; +} + int ec_GFp_simple_set_Jprojective_coordinates_GFp( const EC_GROUP *group, EC_POINT *point, const BIGNUM *x, const BIGNUM *y, const BIGNUM *z, BN_CTX *ctx) { @@ -277,43 +300,10 @@ int ec_GFp_simple_set_Jprojective_coordinates_GFp( } } - if (x != NULL) { - if (!BN_nnmod(&point->X, x, &group->field, ctx)) { - goto err; - } - if (group->meth->field_encode && - !group->meth->field_encode(group, &point->X, &point->X, ctx)) { - goto err; - } - } - - if (y != NULL) { - if (!BN_nnmod(&point->Y, y, &group->field, ctx)) { - goto err; - } - if (group->meth->field_encode && - !group->meth->field_encode(group, &point->Y, &point->Y, ctx)) { - goto err; - } - } - - if (z != NULL) { - int Z_is_one; - - if (!BN_nnmod(&point->Z, z, &group->field, ctx)) { - goto err; - } - Z_is_one = BN_is_one(&point->Z); - if (group->meth->field_encode) { - if (Z_is_one && (group->meth->field_set_to_one != 0)) { - if (!group->meth->field_set_to_one(group, &point->Z, ctx)) { - goto err; - } - } else if (!group->meth->field_encode(group, &point->Z, &point->Z, ctx)) { - goto err; - } - } - point->Z_is_one = Z_is_one; + if (!set_Jprojective_coordinate_GFp(group, &point->X, x, ctx) || + !set_Jprojective_coordinate_GFp(group, &point->Y, y, ctx) || + !set_Jprojective_coordinate_GFp(group, &point->Z, z, ctx)) { + goto err; } ret = 1; @@ -379,109 +369,6 @@ int ec_GFp_simple_point_set_affine_coordinates(const EC_GROUP *group, BN_value_one(), ctx); } -int ec_GFp_simple_point_get_affine_coordinates(const EC_GROUP *group, - const EC_POINT *point, BIGNUM *x, - BIGNUM *y, BN_CTX *ctx) { - BN_CTX *new_ctx = NULL; - BIGNUM *Z, *Z_1, *Z_2, *Z_3; - const BIGNUM *Z_; - int ret = 0; - - if (EC_POINT_is_at_infinity(group, point)) { - OPENSSL_PUT_ERROR(EC, EC_R_POINT_AT_INFINITY); - return 0; - } - - if (ctx == NULL) { - ctx = new_ctx = BN_CTX_new(); - if (ctx == NULL) { - return 0; - } - } - - BN_CTX_start(ctx); - Z = BN_CTX_get(ctx); - Z_1 = BN_CTX_get(ctx); - Z_2 = BN_CTX_get(ctx); - Z_3 = BN_CTX_get(ctx); - if (Z == NULL || Z_1 == NULL || Z_2 == NULL || Z_3 == NULL) { - goto err; - } - - /* transform (X, Y, Z) into (x, y) := (X/Z^2, Y/Z^3) */ - - if (group->meth->field_decode) { - if (!group->meth->field_decode(group, Z, &point->Z, ctx)) { - goto err; - } - Z_ = Z; - } else { - Z_ = &point->Z; - } - - if (BN_is_one(Z_)) { - if (group->meth->field_decode) { - if (x != NULL && !group->meth->field_decode(group, x, &point->X, ctx)) { - goto err; - } - if (y != NULL && !group->meth->field_decode(group, y, &point->Y, ctx)) { - goto err; - } - } else { - if (x != NULL && !BN_copy(x, &point->X)) { - goto err; - } - if (y != NULL && !BN_copy(y, &point->Y)) { - goto err; - } - } - } else { - if (!BN_mod_inverse(Z_1, Z_, &group->field, ctx)) { - OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB); - goto err; - } - - if (group->meth->field_encode == 0) { - /* field_sqr works on standard representation */ - if (!group->meth->field_sqr(group, Z_2, Z_1, ctx)) { - goto err; - } - } else if (!BN_mod_sqr(Z_2, Z_1, &group->field, ctx)) { - goto err; - } - - /* in the Montgomery case, field_mul will cancel out Montgomery factor in - * X: */ - if (x != NULL && !group->meth->field_mul(group, x, &point->X, Z_2, ctx)) { - goto err; - } - - if (y != NULL) { - if (group->meth->field_encode == 0) { - /* field_mul works on standard representation */ - if (!group->meth->field_mul(group, Z_3, Z_2, Z_1, ctx)) { - goto err; - } - } else if (!BN_mod_mul(Z_3, Z_2, Z_1, &group->field, ctx)) { - goto err; - } - - /* in the Montgomery case, field_mul will cancel out Montgomery factor in - * Y: */ - if (!group->meth->field_mul(group, y, &point->Y, Z_3, ctx)) { - goto err; - } - } - } - - ret = 1; - -err: - BN_CTX_end(ctx); - BN_CTX_free(new_ctx); - return ret; -} - int ec_GFp_simple_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, const EC_POINT *b, BN_CTX *ctx) { int (*field_mul)(const EC_GROUP *, BIGNUM *, const BIGNUM *, const BIGNUM *, @@ -531,7 +418,9 @@ int ec_GFp_simple_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, */ /* n1, n2 */ - if (b->Z_is_one) { + int b_Z_is_one = BN_cmp(&b->Z, &group->one) == 0; + + if (b_Z_is_one) { if (!BN_copy(n1, &a->X) || !BN_copy(n2, &a->Y)) { goto end; } @@ -552,7 +441,8 @@ int ec_GFp_simple_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, } /* n3, n4 */ - if (a->Z_is_one) { + int a_Z_is_one = BN_cmp(&a->Z, &group->one) == 0; + if (a_Z_is_one) { if (!BN_copy(n3, &b->X) || !BN_copy(n4, &b->Y)) { goto end; } @@ -590,7 +480,6 @@ int ec_GFp_simple_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, } else { /* a is the inverse of b */ BN_zero(&r->Z); - r->Z_is_one = 0; ret = 1; goto end; } @@ -605,16 +494,16 @@ int ec_GFp_simple_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, /* 'n8' = n2 + n4 */ /* Z_r */ - if (a->Z_is_one && b->Z_is_one) { + if (a_Z_is_one && b_Z_is_one) { if (!BN_copy(&r->Z, n5)) { goto end; } } else { - if (a->Z_is_one) { + if (a_Z_is_one) { if (!BN_copy(n0, &b->Z)) { goto end; } - } else if (b->Z_is_one) { + } else if (b_Z_is_one) { if (!BN_copy(n0, &a->Z)) { goto end; } @@ -625,7 +514,7 @@ int ec_GFp_simple_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, goto end; } } - r->Z_is_one = 0; + /* Z_r = Z_a * Z_b * n5 */ /* X_r */ @@ -685,7 +574,6 @@ int ec_GFp_simple_dbl(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, if (EC_POINT_is_at_infinity(group, a)) { BN_zero(&r->Z); - r->Z_is_one = 0; return 1; } @@ -715,7 +603,7 @@ int ec_GFp_simple_dbl(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, */ /* n1 */ - if (a->Z_is_one) { + if (BN_cmp(&a->Z, &group->one) == 0) { if (!field_sqr(group, n0, &a->X, ctx) || !BN_mod_lshift1_quick(n1, n0, p) || !BN_mod_add_quick(n0, n0, n1, p) || @@ -748,7 +636,7 @@ int ec_GFp_simple_dbl(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, } /* Z_r */ - if (a->Z_is_one) { + if (BN_cmp(&a->Z, &group->one) == 0) { if (!BN_copy(n0, &a->Y)) { goto err; } @@ -758,7 +646,6 @@ int ec_GFp_simple_dbl(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, if (!BN_mod_lshift1_quick(&r->Z, n0, p)) { goto err; } - r->Z_is_one = 0; /* Z_r = 2 * Y_a * Z_a */ /* n2 */ @@ -810,7 +697,7 @@ int ec_GFp_simple_invert(const EC_GROUP *group, EC_POINT *point, BN_CTX *ctx) { } int ec_GFp_simple_is_at_infinity(const EC_GROUP *group, const EC_POINT *point) { - return !point->Z_is_one && BN_is_zero(&point->Z); + return BN_is_zero(&point->Z); } int ec_GFp_simple_is_on_curve(const EC_GROUP *group, const EC_POINT *point, @@ -821,7 +708,7 @@ int ec_GFp_simple_is_on_curve(const EC_GROUP *group, const EC_POINT *point, const BIGNUM *p; BN_CTX *new_ctx = NULL; BIGNUM *rh, *tmp, *Z4, *Z6; - int ret = -1; + int ret = 0; if (EC_POINT_is_at_infinity(group, point)) { return 1; @@ -834,7 +721,7 @@ int ec_GFp_simple_is_on_curve(const EC_GROUP *group, const EC_POINT *point, if (ctx == NULL) { ctx = new_ctx = BN_CTX_new(); if (ctx == NULL) { - return -1; + return 0; } } @@ -862,7 +749,7 @@ int ec_GFp_simple_is_on_curve(const EC_GROUP *group, const EC_POINT *point, goto err; } - if (!point->Z_is_one) { + if (BN_cmp(&point->Z, &group->one) != 0) { if (!field_sqr(group, tmp, &point->Z, ctx) || !field_sqr(group, Z4, tmp, ctx) || !field_mul(group, Z6, Z4, tmp, ctx)) { @@ -891,8 +778,6 @@ int ec_GFp_simple_is_on_curve(const EC_GROUP *group, const EC_POINT *point, goto err; } } else { - /* point->Z_is_one */ - /* rh := (rh + a)*X */ if (!BN_mod_add_quick(rh, rh, &group->a, p) || !field_mul(group, rh, rh, &point->X, ctx)) { @@ -941,7 +826,10 @@ int ec_GFp_simple_cmp(const EC_GROUP *group, const EC_POINT *a, return 1; } - if (a->Z_is_one && b->Z_is_one) { + int a_Z_is_one = BN_cmp(&a->Z, &group->one) == 0; + int b_Z_is_one = BN_cmp(&b->Z, &group->one) == 0; + + if (a_Z_is_one && b_Z_is_one) { return ((BN_cmp(&a->X, &b->X) == 0) && BN_cmp(&a->Y, &b->Y) == 0) ? 0 : 1; } @@ -970,7 +858,7 @@ int ec_GFp_simple_cmp(const EC_GROUP *group, const EC_POINT *a, * (X_a*Z_b^2, Y_a*Z_b^3) = (X_b*Z_a^2, Y_b*Z_a^3). */ - if (!b->Z_is_one) { + if (!b_Z_is_one) { if (!field_sqr(group, Zb23, &b->Z, ctx) || !field_mul(group, tmp1, &a->X, Zb23, ctx)) { goto end; @@ -979,7 +867,7 @@ int ec_GFp_simple_cmp(const EC_GROUP *group, const EC_POINT *a, } else { tmp1_ = &a->X; } - if (!a->Z_is_one) { + if (!a_Z_is_one) { if (!field_sqr(group, Za23, &a->Z, ctx) || !field_mul(group, tmp2, &b->X, Za23, ctx)) { goto end; @@ -996,7 +884,7 @@ int ec_GFp_simple_cmp(const EC_GROUP *group, const EC_POINT *a, } - if (!b->Z_is_one) { + if (!b_Z_is_one) { if (!field_mul(group, Zb23, Zb23, &b->Z, ctx) || !field_mul(group, tmp1, &a->Y, Zb23, ctx)) { goto end; @@ -1005,7 +893,7 @@ int ec_GFp_simple_cmp(const EC_GROUP *group, const EC_POINT *a, } else { tmp1_ = &a->Y; } - if (!a->Z_is_one) { + if (!a_Z_is_one) { if (!field_mul(group, Za23, Za23, &a->Z, ctx) || !field_mul(group, tmp2, &b->Y, Za23, ctx)) { goto end; @@ -1036,7 +924,8 @@ int ec_GFp_simple_make_affine(const EC_GROUP *group, EC_POINT *point, BIGNUM *x, *y; int ret = 0; - if (point->Z_is_one || EC_POINT_is_at_infinity(group, point)) { + if (BN_cmp(&point->Z, &group->one) == 0 || + EC_POINT_is_at_infinity(group, point)) { return 1; } @@ -1058,7 +947,7 @@ int ec_GFp_simple_make_affine(const EC_GROUP *group, EC_POINT *point, !EC_POINT_set_affine_coordinates_GFp(group, point, x, y, ctx)) { goto err; } - if (!point->Z_is_one) { + if (BN_cmp(&point->Z, &group->one) != 0) { OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR); goto err; } @@ -1076,7 +965,6 @@ int ec_GFp_simple_points_make_affine(const EC_GROUP *group, size_t num, BN_CTX *new_ctx = NULL; BIGNUM *tmp, *tmp_Z; BIGNUM **prod_Z = NULL; - size_t i; int ret = 0; if (num == 0) { @@ -1101,8 +989,8 @@ int ec_GFp_simple_points_make_affine(const EC_GROUP *group, size_t num, if (prod_Z == NULL) { goto err; } - memset(prod_Z, 0, num * sizeof(prod_Z[0])); - for (i = 0; i < num; i++) { + OPENSSL_memset(prod_Z, 0, num * sizeof(prod_Z[0])); + for (size_t i = 0; i < num; i++) { prod_Z[i] = BN_new(); if (prod_Z[i] == NULL) { goto err; @@ -1117,18 +1005,12 @@ int ec_GFp_simple_points_make_affine(const EC_GROUP *group, size_t num, goto err; } } else { - if (group->meth->field_set_to_one != 0) { - if (!group->meth->field_set_to_one(group, prod_Z[0], ctx)) { - goto err; - } - } else { - if (!BN_one(prod_Z[0])) { - goto err; - } + if (BN_copy(prod_Z[0], &group->one) == NULL) { + goto err; } } - for (i = 1; i < num; i++) { + for (size_t i = 1; i < num; i++) { if (!BN_is_zero(&points[i]->Z)) { if (!group->meth->field_mul(group, prod_Z[i], prod_Z[i - 1], &points[i]->Z, ctx)) { @@ -1141,10 +1023,16 @@ int ec_GFp_simple_points_make_affine(const EC_GROUP *group, size_t num, } } - /* Now use a single explicit inversion to replace every - * non-zero points[i]->Z by its inverse. */ - - if (!BN_mod_inverse(tmp, prod_Z[num - 1], &group->field, ctx)) { + /* Now use a single explicit inversion to replace every non-zero points[i]->Z + * by its inverse. We use |BN_mod_inverse_odd| instead of doing a constant- + * time inversion using Fermat's Little Theorem because this function is + * usually only used for converting multiples of a public key point to + * affine, and a public key point isn't secret. If we were to use Fermat's + * Little Theorem then the cost of the inversion would usually be so high + * that converting the multiples to affine would be counterproductive. */ + int no_inverse; + if (!BN_mod_inverse_odd(tmp, &no_inverse, prod_Z[num - 1], &group->field, + ctx)) { OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB); goto err; } @@ -1159,7 +1047,7 @@ int ec_GFp_simple_points_make_affine(const EC_GROUP *group, size_t num, } } - for (i = num - 1; i > 0; --i) { + for (size_t i = num - 1; i > 0; --i) { /* Loop invariant: tmp is the product of the inverses of * points[0]->Z .. points[i]->Z (zero-valued inputs skipped). */ if (BN_is_zero(&points[i]->Z)) { @@ -1183,7 +1071,7 @@ int ec_GFp_simple_points_make_affine(const EC_GROUP *group, size_t num, } /* Finally, fix up the X and Y coordinates for all points. */ - for (i = 0; i < num; i++) { + for (size_t i = 0; i < num; i++) { EC_POINT *p = points[i]; if (!BN_is_zero(&p->Z)) { @@ -1195,16 +1083,9 @@ int ec_GFp_simple_points_make_affine(const EC_GROUP *group, size_t num, goto err; } - if (group->meth->field_set_to_one != NULL) { - if (!group->meth->field_set_to_one(group, &p->Z, ctx)) { - goto err; - } - } else { - if (!BN_one(&p->Z)) { - goto err; - } + if (BN_copy(&p->Z, &group->one) == NULL) { + goto err; } - p->Z_is_one = 1; } } @@ -1214,7 +1095,7 @@ int ec_GFp_simple_points_make_affine(const EC_GROUP *group, size_t num, BN_CTX_end(ctx); BN_CTX_free(new_ctx); if (prod_Z != NULL) { - for (i = 0; i < num; i++) { + for (size_t i = 0; i < num; i++) { if (prod_Z[i] == NULL) { break; } diff --git a/Sources/BoringSSL/crypto/ec/util-64.c b/Sources/BoringSSL/crypto/ec/util-64.c index 171b0631b..400627125 100644 --- a/Sources/BoringSSL/crypto/ec/util-64.c +++ b/Sources/BoringSSL/crypto/ec/util-64.c @@ -21,80 +21,6 @@ #include "internal.h" -/* Convert an array of points into affine coordinates. (If the point at - * infinity is found (Z = 0), it remains unchanged.) This function is - * essentially an equivalent to EC_POINTs_make_affine(), but works with the - * internal representation of points as used by ecp_nistp###.c rather than - * with (BIGNUM-based) EC_POINT data structures. point_array is the - * input/output buffer ('num' points in projective form, i.e. three - * coordinates each), based on an internal representation of field elements - * of size 'felem_size'. tmp_felems needs to point to a temporary array of - * 'num'+1 field elements for storage of intermediate values. */ -void ec_GFp_nistp_points_make_affine_internal( - size_t num, void *point_array, size_t felem_size, void *tmp_felems, - void (*felem_one)(void *out), int (*felem_is_zero)(const void *in), - void (*felem_assign)(void *out, const void *in), - void (*felem_square)(void *out, const void *in), - void (*felem_mul)(void *out, const void *in1, const void *in2), - void (*felem_inv)(void *out, const void *in), - void (*felem_contract)(void *out, const void *in)) { - int i = 0; - -#define tmp_felem(I) (&((char *)tmp_felems)[(I)*felem_size]) -#define X(I) (&((char *)point_array)[3 * (I)*felem_size]) -#define Y(I) (&((char *)point_array)[(3 * (I) + 1) * felem_size]) -#define Z(I) (&((char *)point_array)[(3 * (I) + 2) * felem_size]) - - if (!felem_is_zero(Z(0))) { - felem_assign(tmp_felem(0), Z(0)); - } else { - felem_one(tmp_felem(0)); - } - - for (i = 1; i < (int)num; i++) { - if (!felem_is_zero(Z(i))) { - felem_mul(tmp_felem(i), tmp_felem(i - 1), Z(i)); - } else { - felem_assign(tmp_felem(i), tmp_felem(i - 1)); - } - } - /* Now each tmp_felem(i) is the product of Z(0) .. Z(i), skipping any - * zero-valued factors: if Z(i) = 0, we essentially pretend that Z(i) = 1. */ - - felem_inv(tmp_felem(num - 1), tmp_felem(num - 1)); - for (i = num - 1; i >= 0; i--) { - if (i > 0) { - /* tmp_felem(i-1) is the product of Z(0) .. Z(i-1), tmp_felem(i) - * is the inverse of the product of Z(0) .. Z(i). */ - /* 1/Z(i) */ - felem_mul(tmp_felem(num), tmp_felem(i - 1), tmp_felem(i)); - } else { - felem_assign(tmp_felem(num), tmp_felem(0)); /* 1/Z(0) */ - } - - if (!felem_is_zero(Z(i))) { - if (i > 0) { - /* For next iteration, replace tmp_felem(i-1) by its inverse. */ - felem_mul(tmp_felem(i - 1), tmp_felem(i), Z(i)); - } - - /* Convert point (X, Y, Z) into affine form (X/(Z^2), Y/(Z^3), 1). */ - felem_square(Z(i), tmp_felem(num)); /* 1/(Z^2) */ - felem_mul(X(i), X(i), Z(i)); /* X/(Z^2) */ - felem_mul(Z(i), Z(i), tmp_felem(num)); /* 1/(Z^3) */ - felem_mul(Y(i), Y(i), Z(i)); /* Y/(Z^3) */ - felem_contract(X(i), X(i)); - felem_contract(Y(i), Y(i)); - felem_one(Z(i)); - } else { - if (i > 0) { - /* For next iteration, replace tmp_felem(i-1) by its inverse. */ - felem_assign(tmp_felem(i - 1), tmp_felem(i)); - } - } - } -} - /* This function looks at 5+1 scalar bits (5 current, 1 adjacent less * significant bit), and recodes them into a signed digit for use in fast point * multiplication: the use of signed rather than unsigned digits means that diff --git a/Sources/BoringSSL/crypto/ec/wnaf.c b/Sources/BoringSSL/crypto/ec/wnaf.c index ba2257c46..67b7f3489 100644 --- a/Sources/BoringSSL/crypto/ec/wnaf.c +++ b/Sources/BoringSSL/crypto/ec/wnaf.c @@ -90,10 +90,10 @@ * with the exception that the most significant digit may be only * w-1 zeros away from that next non-zero digit. */ -static signed char *compute_wNAF(const BIGNUM *scalar, int w, size_t *ret_len) { +static int8_t *compute_wNAF(const BIGNUM *scalar, int w, size_t *ret_len) { int window_val; int ok = 0; - signed char *r = NULL; + int8_t *r = NULL; int sign = 1; int bit, next_bit, mask; size_t len = 0, j; @@ -109,9 +109,8 @@ static signed char *compute_wNAF(const BIGNUM *scalar, int w, size_t *ret_len) { return r; } - if (w <= 0 || w > 7) /* 'signed char' can represent integers with absolute - values less than 2^7 */ - { + /* 'int8_t' can represent integers with absolute values less than 2^7. */ + if (w <= 0 || w > 7) { OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR); goto err; } @@ -129,20 +128,18 @@ static signed char *compute_wNAF(const BIGNUM *scalar, int w, size_t *ret_len) { } len = BN_num_bits(scalar); - r = OPENSSL_malloc( - len + - 1); /* modified wNAF may be one digit longer than binary representation - * (*ret_len will be set to the actual length, i.e. at most - * BN_num_bits(scalar) + 1) */ + /* The modified wNAF may be one digit longer than binary representation + * (*ret_len will be set to the actual length, i.e. at most + * BN_num_bits(scalar) + 1). */ + r = OPENSSL_malloc(len + 1); if (r == NULL) { OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE); goto err; } window_val = scalar->d[0] & mask; j = 0; - while ((window_val != 0) || - (j + w + 1 < len)) /* if j+w+1 >= len, window_val will not increase */ - { + /* If j+w+1 >= len, window_val will not increase. */ + while (window_val != 0 || j + w + 1 < len) { int digit = 0; /* 0 <= window_val <= 2^(w+1) */ @@ -174,9 +171,8 @@ static signed char *compute_wNAF(const BIGNUM *scalar, int w, size_t *ret_len) { window_val -= digit; - /* now window_val is 0 or 2^(w+1) in standard wNAF generation; - * for modified window NAFs, it may also be 2^w - */ + /* Now window_val is 0 or 2^(w+1) in standard wNAF generation; + * for modified window NAFs, it may also be 2^w. */ if (window_val != 0 && window_val != next_bit && window_val != bit) { OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR); goto err; @@ -217,28 +213,45 @@ static signed char *compute_wNAF(const BIGNUM *scalar, int w, size_t *ret_len) { * sometimes smaller windows will give better performance * (thus the boundaries should be increased) */ -#define EC_window_bits_for_scalar_size(b) \ - ((size_t)((b) >= 2000 ? 6 : (b) >= 800 ? 5 : (b) >= 300 \ - ? 4 \ - : (b) >= 70 ? 3 : (b) >= 20 \ - ? 2 \ - : 1)) +static size_t window_bits_for_scalar_size(size_t b) { + if (b >= 2000) { + return 6; + } + + if (b >= 800) { + return 5; + } + + if (b >= 300) { + return 4; + } + + if (b >= 70) { + return 3; + } + + if (b >= 20) { + return 2; + } + + return 1; +} int ec_wNAF_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *g_scalar, const EC_POINT *p, const BIGNUM *p_scalar, BN_CTX *ctx) { BN_CTX *new_ctx = NULL; const EC_POINT *generator = NULL; EC_POINT *tmp = NULL; - size_t total_num; + size_t total_num = 0; size_t i, j; int k; int r_is_inverted = 0; int r_is_at_infinity = 1; size_t *wsize = NULL; /* individual window sizes */ - signed char **wNAF = NULL; /* individual wNAFs */ + int8_t **wNAF = NULL; /* individual wNAFs */ size_t *wNAF_len = NULL; size_t max_len = 0; - size_t num_val; + size_t num_val = 0; EC_POINT **val = NULL; /* precomputation */ EC_POINT **v; EC_POINT ***val_sub = NULL; /* pointers to sub-arrays of 'val' */ @@ -271,15 +284,14 @@ int ec_wNAF_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *g_scalar, } - wsize = OPENSSL_malloc(total_num * sizeof wsize[0]); - wNAF_len = OPENSSL_malloc(total_num * sizeof wNAF_len[0]); - wNAF = OPENSSL_malloc((total_num + 1) * - sizeof wNAF[0]); /* includes space for pivot */ - val_sub = OPENSSL_malloc(total_num * sizeof val_sub[0]); + wsize = OPENSSL_malloc(total_num * sizeof(wsize[0])); + wNAF_len = OPENSSL_malloc(total_num * sizeof(wNAF_len[0])); + wNAF = OPENSSL_malloc(total_num * sizeof(wNAF[0])); + val_sub = OPENSSL_malloc(total_num * sizeof(val_sub[0])); /* Ensure wNAF is initialised in case we end up going to err. */ - if (wNAF) { - wNAF[0] = NULL; /* preliminary pivot */ + if (wNAF != NULL) { + OPENSSL_memset(wNAF, 0, total_num * sizeof(wNAF[0])); } if (!wsize || !wNAF_len || !wNAF || !val_sub) { @@ -294,9 +306,8 @@ int ec_wNAF_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *g_scalar, size_t bits; bits = i < num ? BN_num_bits(scalars[i]) : BN_num_bits(g_scalar); - wsize[i] = EC_window_bits_for_scalar_size(bits); + wsize[i] = window_bits_for_scalar_size(bits); num_val += (size_t)1 << (wsize[i] - 1); - wNAF[i + 1] = NULL; /* make sure we always have a pivot */ wNAF[i] = compute_wNAF((i < num ? scalars[i] : g_scalar), wsize[i], &wNAF_len[i]); if (wNAF[i] == NULL) { @@ -309,12 +320,12 @@ int ec_wNAF_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *g_scalar, /* All points we precompute now go into a single array 'val'. 'val_sub[i]' is * a pointer to the subarray for the i-th point. */ - val = OPENSSL_malloc((num_val + 1) * sizeof val[0]); + val = OPENSSL_malloc(num_val * sizeof(val[0])); if (val == NULL) { OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE); goto err; } - val[num_val] = NULL; /* pivot element */ + OPENSSL_memset(val, 0, num_val * sizeof(val[0])); /* allocate points for precomputation */ v = val; @@ -364,7 +375,7 @@ int ec_wNAF_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *g_scalar, } } -#if 1 /* optional; EC_window_bits_for_scalar_size assumes we do this step */ +#if 1 /* optional; window_bits_for_scalar_size assumes we do this step */ if (!EC_POINTs_make_affine(group, num_val, val, ctx)) { goto err; } @@ -429,17 +440,15 @@ int ec_wNAF_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *g_scalar, OPENSSL_free(wsize); OPENSSL_free(wNAF_len); if (wNAF != NULL) { - signed char **w; - - for (w = wNAF; *w != NULL; w++) { - OPENSSL_free(*w); + for (i = 0; i < total_num; i++) { + OPENSSL_free(wNAF[i]); } OPENSSL_free(wNAF); } if (val != NULL) { - for (v = val; *v != NULL; v++) { - EC_POINT_clear_free(*v); + for (i = 0; i < num_val; i++) { + EC_POINT_clear_free(val[i]); } OPENSSL_free(val); diff --git a/Sources/BoringSSL/crypto/ecdh/ecdh.c b/Sources/BoringSSL/crypto/ecdh/ecdh.c index 4a1964a0b..22b216ef4 100644 --- a/Sources/BoringSSL/crypto/ecdh/ecdh.c +++ b/Sources/BoringSSL/crypto/ecdh/ecdh.c @@ -66,6 +66,7 @@ #include +#include #include #include @@ -73,9 +74,11 @@ #include #include +#include "../internal.h" + int ECDH_compute_key(void *out, size_t outlen, const EC_POINT *pub_key, - EC_KEY *priv_key, + const EC_KEY *priv_key, void *(*kdf)(const void *in, size_t inlen, void *out, size_t *outlen)) { const BIGNUM *const priv = EC_KEY_get0_private_key(priv_key); @@ -139,10 +142,15 @@ int ECDH_compute_key(void *out, size_t outlen, const EC_POINT *pub_key, if (buflen < outlen) { outlen = buflen; } - memcpy(out, buf, outlen); + OPENSSL_memcpy(out, buf, outlen); + } + + if (outlen > INT_MAX) { + OPENSSL_PUT_ERROR(ECDH, ERR_R_OVERFLOW); + goto err; } - ret = outlen; + ret = (int)outlen; err: OPENSSL_free(buf); diff --git a/Sources/BoringSSL/crypto/ecdsa/ecdsa.c b/Sources/BoringSSL/crypto/ecdsa/ecdsa.c index 8ce23db79..e1a0525fc 100644 --- a/Sources/BoringSSL/crypto/ecdsa/ecdsa.c +++ b/Sources/BoringSSL/crypto/ecdsa/ecdsa.c @@ -60,13 +60,16 @@ #include #include +#include "../bn/internal.h" #include "../ec/internal.h" +#include "../internal.h" int ECDSA_sign(int type, const uint8_t *digest, size_t digest_len, uint8_t *sig, - unsigned int *sig_len, EC_KEY *eckey) { + unsigned int *sig_len, const EC_KEY *eckey) { if (eckey->ecdsa_meth && eckey->ecdsa_meth->sign) { - return eckey->ecdsa_meth->sign(digest, digest_len, sig, sig_len, eckey); + return eckey->ecdsa_meth->sign(digest, digest_len, sig, sig_len, + (EC_KEY*) eckey /* cast away const */); } return ECDSA_sign_ex(type, digest, digest_len, sig, sig_len, NULL, NULL, @@ -74,15 +77,11 @@ int ECDSA_sign(int type, const uint8_t *digest, size_t digest_len, uint8_t *sig, } int ECDSA_verify(int type, const uint8_t *digest, size_t digest_len, - const uint8_t *sig, size_t sig_len, EC_KEY *eckey) { + const uint8_t *sig, size_t sig_len, const EC_KEY *eckey) { ECDSA_SIG *s; int ret = 0; uint8_t *der = NULL; - if (eckey->ecdsa_meth && eckey->ecdsa_meth->verify) { - return eckey->ecdsa_meth->verify(digest, digest_len, sig, sig_len, eckey); - } - /* Decode the ECDSA signature. */ s = ECDSA_SIG_from_bytes(sig, sig_len); if (s == NULL) { @@ -92,7 +91,7 @@ int ECDSA_verify(int type, const uint8_t *digest, size_t digest_len, /* Defend against potential laxness in the DER parser. */ size_t der_len; if (!ECDSA_SIG_to_bytes(&der, &der_len, s) || - der_len != sig_len || memcmp(sig, der, sig_len) != 0) { + der_len != sig_len || OPENSSL_memcmp(sig, der, sig_len) != 0) { /* This should never happen. crypto/bytestring is strictly DER. */ OPENSSL_PUT_ERROR(ECDSA, ERR_R_INTERNAL_ERROR); goto err; @@ -135,12 +134,12 @@ static int digest_to_bn(BIGNUM *out, const uint8_t *digest, size_t digest_len, } ECDSA_SIG *ECDSA_do_sign(const uint8_t *digest, size_t digest_len, - EC_KEY *key) { + const EC_KEY *key) { return ECDSA_do_sign_ex(digest, digest_len, NULL, NULL, key); } int ECDSA_do_verify(const uint8_t *digest, size_t digest_len, - const ECDSA_SIG *sig, EC_KEY *eckey) { + const ECDSA_SIG *sig, const EC_KEY *eckey) { int ret = 0; BN_CTX *ctx; BIGNUM *u1, *u2, *m, *X; @@ -148,11 +147,6 @@ int ECDSA_do_verify(const uint8_t *digest, size_t digest_len, const EC_GROUP *group; const EC_POINT *pub_key; - if (eckey->ecdsa_meth && eckey->ecdsa_meth->verify) { - OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_NOT_IMPLEMENTED); - return 0; - } - /* check input values */ if ((group = EC_KEY_get0_group(eckey)) == NULL || (pub_key = EC_KEY_get0_public_key(eckey)) == NULL || @@ -185,7 +179,8 @@ int ECDSA_do_verify(const uint8_t *digest, size_t digest_len, goto err; } /* calculate tmp1 = inv(S) mod order */ - if (!BN_mod_inverse(u2, sig->s, order, ctx)) { + int no_inverse; + if (!BN_mod_inverse_odd(u2, &no_inverse, sig->s, order, ctx)) { OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB); goto err; } @@ -230,11 +225,11 @@ int ECDSA_do_verify(const uint8_t *digest, size_t digest_len, return ret; } -static int ecdsa_sign_setup(EC_KEY *eckey, BN_CTX *ctx_in, BIGNUM **kinvp, +static int ecdsa_sign_setup(const EC_KEY *eckey, BN_CTX *ctx_in, BIGNUM **kinvp, BIGNUM **rp, const uint8_t *digest, size_t digest_len) { BN_CTX *ctx = NULL; - BIGNUM *k = NULL, *r = NULL, *X = NULL; + BIGNUM *k = NULL, *r = NULL, *tmp = NULL; EC_POINT *tmp_point = NULL; const EC_GROUP *group; int ret = 0; @@ -255,8 +250,8 @@ static int ecdsa_sign_setup(EC_KEY *eckey, BN_CTX *ctx_in, BIGNUM **kinvp, k = BN_new(); /* this value is later returned in *kinvp */ r = BN_new(); /* this value is later returned in *rp */ - X = BN_new(); - if (k == NULL || r == NULL || X == NULL) { + tmp = BN_new(); + if (k == NULL || r == NULL || tmp == NULL) { OPENSSL_PUT_ERROR(ECDSA, ERR_R_MALLOC_FAILURE); goto err; } @@ -272,20 +267,18 @@ static int ecdsa_sign_setup(EC_KEY *eckey, BN_CTX *ctx_in, BIGNUM **kinvp, /* If possible, we'll include the private key and message digest in the k * generation. The |digest| argument is only empty if |ECDSA_sign_setup| is * being used. */ - do { - int ok; - - if (digest_len > 0) { - ok = BN_generate_dsa_nonce(k, order, EC_KEY_get0_private_key(eckey), - digest, digest_len, ctx); - } else { - ok = BN_rand_range(k, order); - } - if (!ok) { - OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED); - goto err; - } - } while (BN_is_zero(k)); + if (digest_len > 0) { + do { + if (!BN_generate_dsa_nonce(k, order, EC_KEY_get0_private_key(eckey), + digest, digest_len, ctx)) { + OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED); + goto err; + } + } while (BN_is_zero(k)); + } else if (!BN_rand_range_ex(k, 1, order)) { + OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED); + goto err; + } /* We do not want timing information to leak the length of k, * so we compute G*k using an equivalent scalar of fixed @@ -305,33 +298,22 @@ static int ecdsa_sign_setup(EC_KEY *eckey, BN_CTX *ctx_in, BIGNUM **kinvp, OPENSSL_PUT_ERROR(ECDSA, ERR_R_EC_LIB); goto err; } - if (!EC_POINT_get_affine_coordinates_GFp(group, tmp_point, X, NULL, ctx)) { + if (!EC_POINT_get_affine_coordinates_GFp(group, tmp_point, tmp, NULL, + ctx)) { OPENSSL_PUT_ERROR(ECDSA, ERR_R_EC_LIB); goto err; } - if (!BN_nnmod(r, X, order, ctx)) { + if (!BN_nnmod(r, tmp, order, ctx)) { OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB); goto err; } } while (BN_is_zero(r)); - /* compute the inverse of k */ - if (ec_group_get_mont_data(group) != NULL) { - /* We want inverse in constant time, therefore we use that the order must - * be prime and thus we can use Fermat's Little Theorem. */ - if (!BN_set_word(X, 2) || - !BN_sub(X, order, X)) { - OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB); - goto err; - } - BN_set_flags(X, BN_FLG_CONSTTIME); - if (!BN_mod_exp_mont_consttime(k, k, X, order, ctx, - ec_group_get_mont_data(group))) { - OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB); - goto err; - } - } else if (!BN_mod_inverse(k, k, order, ctx)) { + /* Compute the inverse of k. The order is a prime, so use Fermat's Little + * Theorem. Note |ec_group_get_mont_data| may return NULL but + * |bn_mod_inverse_prime| allows this. */ + if (!bn_mod_inverse_prime(k, k, order, ctx, ec_group_get_mont_data(group))) { OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB); goto err; } @@ -353,17 +335,18 @@ static int ecdsa_sign_setup(EC_KEY *eckey, BN_CTX *ctx_in, BIGNUM **kinvp, BN_CTX_free(ctx); } EC_POINT_free(tmp_point); - BN_clear_free(X); + BN_clear_free(tmp); return ret; } -int ECDSA_sign_setup(EC_KEY *eckey, BN_CTX *ctx, BIGNUM **kinv, BIGNUM **rp) { +int ECDSA_sign_setup(const EC_KEY *eckey, BN_CTX *ctx, BIGNUM **kinv, + BIGNUM **rp) { return ecdsa_sign_setup(eckey, ctx, kinv, rp, NULL, 0); } ECDSA_SIG *ECDSA_do_sign_ex(const uint8_t *digest, size_t digest_len, const BIGNUM *in_kinv, const BIGNUM *in_r, - EC_KEY *eckey) { + const EC_KEY *eckey) { int ok = 0; BIGNUM *kinv = NULL, *s, *m = NULL, *tmp = NULL; const BIGNUM *ckinv; @@ -460,7 +443,7 @@ ECDSA_SIG *ECDSA_do_sign_ex(const uint8_t *digest, size_t digest_len, int ECDSA_sign_ex(int type, const uint8_t *digest, size_t digest_len, uint8_t *sig, unsigned int *sig_len, const BIGNUM *kinv, - const BIGNUM *r, EC_KEY *eckey) { + const BIGNUM *r, const EC_KEY *eckey) { int ret = 0; ECDSA_SIG *s = NULL; diff --git a/Sources/BoringSSL/crypto/ecdsa/ecdsa_asn1.c b/Sources/BoringSSL/crypto/ecdsa/ecdsa_asn1.c index 3a47257a5..d41a53667 100644 --- a/Sources/BoringSSL/crypto/ecdsa/ecdsa_asn1.c +++ b/Sources/BoringSSL/crypto/ecdsa/ecdsa_asn1.c @@ -220,6 +220,7 @@ int i2d_ECDSA_SIG(const ECDSA_SIG *sig, uint8_t **outp) { CBB cbb; if (!CBB_init(&cbb, 0) || !ECDSA_SIG_marshal(&cbb, sig)) { + CBB_cleanup(&cbb); return -1; } return CBB_finish_i2d(&cbb, outp); diff --git a/Sources/BoringSSL/crypto/engine/engine.c b/Sources/BoringSSL/crypto/engine/engine.c index 25ea98de2..141ed230f 100644 --- a/Sources/BoringSSL/crypto/engine/engine.c +++ b/Sources/BoringSSL/crypto/engine/engine.c @@ -23,6 +23,8 @@ #include #include +#include "../internal.h" + struct engine_st { RSA_METHOD *rsa_method; @@ -35,7 +37,7 @@ ENGINE *ENGINE_new(void) { return NULL; } - memset(engine, 0, sizeof(ENGINE)); + OPENSSL_memset(engine, 0, sizeof(ENGINE)); return engine; } @@ -93,4 +95,4 @@ void METHOD_unref(void *method_in) { assert(method->is_static); } -OPENSSL_DECLARE_ERROR_REASON(ENGINE, OPERATION_NOT_SUPPORTED); +OPENSSL_DECLARE_ERROR_REASON(ENGINE, OPERATION_NOT_SUPPORTED) diff --git a/Sources/BoringSSL/crypto/err/err.c b/Sources/BoringSSL/crypto/err/err.c index 9221bf170..cbb1260e5 100644 --- a/Sources/BoringSSL/crypto/err/err.c +++ b/Sources/BoringSSL/crypto/err/err.c @@ -114,9 +114,9 @@ #include #if defined(OPENSSL_WINDOWS) -#pragma warning(push, 3) +OPENSSL_MSVC_PRAGMA(warning(push, 3)) #include -#pragma warning(pop) +OPENSSL_MSVC_PRAGMA(warning(pop)) #endif #include @@ -141,7 +141,7 @@ static void err_clear_data(struct err_error_st *error) { /* err_clear clears the given queued error. */ static void err_clear(struct err_error_st *error) { err_clear_data(error); - memset(error, 0, sizeof(struct err_error_st)); + OPENSSL_memset(error, 0, sizeof(struct err_error_st)); } /* global_next_library contains the next custom library value to return. */ @@ -175,7 +175,7 @@ static ERR_STATE *err_get_state(void) { if (state == NULL) { return NULL; } - memset(state, 0, sizeof(ERR_STATE)); + OPENSSL_memset(state, 0, sizeof(ERR_STATE)); if (!CRYPTO_set_thread_local(OPENSSL_THREAD_LOCAL_ERR, state, err_state_free)) { return NULL; @@ -325,7 +325,7 @@ int ERR_get_next_error_library(void) { CRYPTO_STATIC_MUTEX_lock_write(&global_next_library_mutex); ret = global_next_library++; - CRYPTO_STATIC_MUTEX_unlock(&global_next_library_mutex); + CRYPTO_STATIC_MUTEX_unlock_write(&global_next_library_mutex); return ret; } @@ -349,7 +349,7 @@ char *ERR_error_string(uint32_t packed_error, char *ret) { #if !defined(NDEBUG) /* This is aimed to help catch callers who don't provide * |ERR_ERROR_STRING_BUF_LEN| bytes of space. */ - memset(ret, 0, ERR_ERROR_STRING_BUF_LEN); + OPENSSL_memset(ret, 0, ERR_ERROR_STRING_BUF_LEN); #endif ERR_error_string_n(packed_error, ret, ERR_ERROR_STRING_BUF_LEN); @@ -407,7 +407,7 @@ void ERR_error_string_n(uint32_t packed_error, char *buf, size_t len) { * terminating 0). If we're setting this colon, then all whole of the * rest of the string must be colons in order to have the correct * number. */ - memset(last_pos, ':', num_colons - i); + OPENSSL_memset(last_pos, ':', num_colons - i); break; } @@ -675,7 +675,7 @@ static void err_add_error_vdata(unsigned num, va_list args) { buf = new_buf; } - memcpy(buf + len, substr, substr_len); + OPENSSL_memcpy(buf + len, substr, substr_len); len = new_len; } diff --git a/Sources/BoringSSL/crypto/evp/evp.c b/Sources/BoringSSL/crypto/evp/evp.c index fa8421203..f08387978 100644 --- a/Sources/BoringSSL/crypto/evp/evp.c +++ b/Sources/BoringSSL/crypto/evp/evp.c @@ -59,12 +59,11 @@ #include #include -#include #include #include #include #include -#include +#include #include #include @@ -81,7 +80,7 @@ EVP_PKEY *EVP_PKEY_new(void) { return NULL; } - memset(ret, 0, sizeof(EVP_PKEY)); + OPENSSL_memset(ret, 0, sizeof(EVP_PKEY)); ret->type = EVP_PKEY_NONE; ret->references = 1; @@ -109,9 +108,9 @@ void EVP_PKEY_free(EVP_PKEY *pkey) { OPENSSL_free(pkey); } -EVP_PKEY *EVP_PKEY_up_ref(EVP_PKEY *pkey) { +int EVP_PKEY_up_ref(EVP_PKEY *pkey) { CRYPTO_refcount_inc(&pkey->references); - return pkey; + return 1; } int EVP_PKEY_is_opaque(const EVP_PKEY *pkey) { @@ -195,8 +194,10 @@ int EVP_PKEY_id(const EVP_PKEY *pkey) { return pkey->type; } -/* TODO(fork): remove the first argument. */ -const EVP_PKEY_ASN1_METHOD *EVP_PKEY_asn1_find(ENGINE **pengine, int nid) { +/* evp_pkey_asn1_find returns the ASN.1 method table for the given |nid|, which + * should be one of the |EVP_PKEY_*| values. It returns NULL if |nid| is + * unknown. */ +static const EVP_PKEY_ASN1_METHOD *evp_pkey_asn1_find(int nid) { switch (nid) { case EVP_PKEY_RSA: return &rsa_asn1_meth; @@ -210,7 +211,7 @@ const EVP_PKEY_ASN1_METHOD *EVP_PKEY_asn1_find(ENGINE **pengine, int nid) { } int EVP_PKEY_type(int nid) { - const EVP_PKEY_ASN1_METHOD *meth = EVP_PKEY_asn1_find(NULL, nid); + const EVP_PKEY_ASN1_METHOD *meth = evp_pkey_asn1_find(nid); if (meth == NULL) { return NID_undef; } @@ -301,6 +302,8 @@ EC_KEY *EVP_PKEY_get1_EC_KEY(EVP_PKEY *pkey) { return ec_key; } +DH *EVP_PKEY_get0_DH(EVP_PKEY *pkey) { return NULL; } + int EVP_PKEY_assign(EVP_PKEY *pkey, int type, void *key) { if (!EVP_PKEY_set_type(pkey, type)) { return 0; @@ -309,21 +312,6 @@ int EVP_PKEY_assign(EVP_PKEY *pkey, int type, void *key) { return key != NULL; } -const EVP_PKEY_ASN1_METHOD *EVP_PKEY_asn1_find_str(ENGINE **pengine, - const char *name, - size_t len) { - if (len == 3 && memcmp(name, "RSA", 3) == 0) { - return &rsa_asn1_meth; - } - if (len == 2 && memcmp(name, "EC", 2) == 0) { - return &ec_asn1_meth; - } - if (len == 3 && memcmp(name, "DSA", 3) == 0) { - return &dsa_asn1_meth; - } - return NULL; -} - int EVP_PKEY_set_type(EVP_PKEY *pkey, int type) { const EVP_PKEY_ASN1_METHOD *ameth; @@ -331,10 +319,10 @@ int EVP_PKEY_set_type(EVP_PKEY *pkey, int type) { free_it(pkey); } - ameth = EVP_PKEY_asn1_find(NULL, type); + ameth = evp_pkey_asn1_find(type); if (ameth == NULL) { OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM); - ERR_add_error_dataf("algorithm %d (%s)", type, OBJ_nid2sn(type)); + ERR_add_error_dataf("algorithm %d", type); return 0; } @@ -358,41 +346,6 @@ int EVP_PKEY_cmp_parameters(const EVP_PKEY *a, const EVP_PKEY *b) { return -2; } -static int print_unsupported(BIO *out, const EVP_PKEY *pkey, int indent, - const char *kstr) { - BIO_indent(out, indent, 128); - BIO_printf(out, "%s algorithm \"%s\" unsupported\n", kstr, - OBJ_nid2ln(pkey->type)); - return 1; -} - -int EVP_PKEY_print_public(BIO *out, const EVP_PKEY *pkey, int indent, - ASN1_PCTX *pctx) { - if (pkey->ameth && pkey->ameth->pub_print) { - return pkey->ameth->pub_print(out, pkey, indent, pctx); - } - - return print_unsupported(out, pkey, indent, "Public Key"); -} - -int EVP_PKEY_print_private(BIO *out, const EVP_PKEY *pkey, int indent, - ASN1_PCTX *pctx) { - if (pkey->ameth && pkey->ameth->priv_print) { - return pkey->ameth->priv_print(out, pkey, indent, pctx); - } - - return print_unsupported(out, pkey, indent, "Private Key"); -} - -int EVP_PKEY_print_params(BIO *out, const EVP_PKEY *pkey, int indent, - ASN1_PCTX *pctx) { - if (pkey->ameth && pkey->ameth->param_print) { - return pkey->ameth->param_print(out, pkey, indent, pctx); - } - - return print_unsupported(out, pkey, indent, "Parameters"); -} - int EVP_PKEY_CTX_set_signature_md(EVP_PKEY_CTX *ctx, const EVP_MD *md) { return EVP_PKEY_CTX_ctrl(ctx, -1, EVP_PKEY_OP_TYPE_SIG, EVP_PKEY_CTRL_MD, 0, (void *)md); @@ -405,6 +358,8 @@ int EVP_PKEY_CTX_get_signature_md(EVP_PKEY_CTX *ctx, const EVP_MD **out_md) { void OpenSSL_add_all_algorithms(void) {} +void OPENSSL_add_all_algorithms_conf(void) {} + void OpenSSL_add_all_ciphers(void) {} void OpenSSL_add_all_digests(void) {} diff --git a/Sources/BoringSSL/crypto/evp/evp_asn1.c b/Sources/BoringSSL/crypto/evp/evp_asn1.c index ed7ae8b75..6c9057191 100644 --- a/Sources/BoringSSL/crypto/evp/evp_asn1.c +++ b/Sources/BoringSSL/crypto/evp/evp_asn1.c @@ -56,22 +56,51 @@ #include -#include +#include + #include +#include +#include #include -#include -#include +#include #include "internal.h" +#include "../internal.h" + + +static const EVP_PKEY_ASN1_METHOD *const kASN1Methods[] = { + &rsa_asn1_meth, + &ec_asn1_meth, + &dsa_asn1_meth, +}; + +static int parse_key_type(CBS *cbs, int *out_type) { + CBS oid; + if (!CBS_get_asn1(cbs, &oid, CBS_ASN1_OBJECT)) { + return 0; + } + + unsigned i; + for (i = 0; i < OPENSSL_ARRAY_SIZE(kASN1Methods); i++) { + const EVP_PKEY_ASN1_METHOD *method = kASN1Methods[i]; + if (CBS_len(&oid) == method->oid_len && + OPENSSL_memcmp(CBS_data(&oid), method->oid, method->oid_len) == 0) { + *out_type = method->pkey_id; + return 1; + } + } + return 0; +} EVP_PKEY *EVP_parse_public_key(CBS *cbs) { /* Parse the SubjectPublicKeyInfo. */ - CBS spki, algorithm, oid, key; + CBS spki, algorithm, key; + int type; uint8_t padding; if (!CBS_get_asn1(cbs, &spki, CBS_ASN1_SEQUENCE) || !CBS_get_asn1(&spki, &algorithm, CBS_ASN1_SEQUENCE) || - !CBS_get_asn1(&algorithm, &oid, CBS_ASN1_OBJECT) || + !parse_key_type(&algorithm, &type) || !CBS_get_asn1(&spki, &key, CBS_ASN1_BITSTRING) || CBS_len(&spki) != 0 || /* Every key type defined encodes the key as a byte string with the same @@ -85,7 +114,7 @@ EVP_PKEY *EVP_parse_public_key(CBS *cbs) { /* Set up an |EVP_PKEY| of the appropriate type. */ EVP_PKEY *ret = EVP_PKEY_new(); if (ret == NULL || - !EVP_PKEY_set_type(ret, OBJ_cbs2nid(&oid))) { + !EVP_PKEY_set_type(ret, type)) { goto err; } @@ -106,7 +135,7 @@ EVP_PKEY *EVP_parse_public_key(CBS *cbs) { } int EVP_marshal_public_key(CBB *cbb, const EVP_PKEY *key) { - if (key->ameth->pub_encode == NULL) { + if (key->ameth == NULL || key->ameth->pub_encode == NULL) { OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM); return 0; } @@ -116,13 +145,14 @@ int EVP_marshal_public_key(CBB *cbb, const EVP_PKEY *key) { EVP_PKEY *EVP_parse_private_key(CBS *cbs) { /* Parse the PrivateKeyInfo. */ - CBS pkcs8, algorithm, oid, key; + CBS pkcs8, algorithm, key; uint64_t version; + int type; if (!CBS_get_asn1(cbs, &pkcs8, CBS_ASN1_SEQUENCE) || !CBS_get_asn1_uint64(&pkcs8, &version) || version != 0 || !CBS_get_asn1(&pkcs8, &algorithm, CBS_ASN1_SEQUENCE) || - !CBS_get_asn1(&algorithm, &oid, CBS_ASN1_OBJECT) || + !parse_key_type(&algorithm, &type) || !CBS_get_asn1(&pkcs8, &key, CBS_ASN1_OCTETSTRING)) { OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); return NULL; @@ -133,7 +163,7 @@ EVP_PKEY *EVP_parse_private_key(CBS *cbs) { /* Set up an |EVP_PKEY| of the appropriate type. */ EVP_PKEY *ret = EVP_PKEY_new(); if (ret == NULL || - !EVP_PKEY_set_type(ret, OBJ_cbs2nid(&oid))) { + !EVP_PKEY_set_type(ret, type)) { goto err; } @@ -154,7 +184,7 @@ EVP_PKEY *EVP_parse_private_key(CBS *cbs) { } int EVP_marshal_private_key(CBB *cbb, const EVP_PKEY *key) { - if (key->ameth->priv_encode == NULL) { + if (key->ameth == NULL || key->ameth->priv_encode == NULL) { OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM); return 0; } @@ -162,107 +192,134 @@ int EVP_marshal_private_key(CBB *cbb, const EVP_PKEY *key) { return key->ameth->priv_encode(cbb, key); } -EVP_PKEY *d2i_PrivateKey(int type, EVP_PKEY **out, const uint8_t **inp, - long len) { - EVP_PKEY *ret; - - if (out == NULL || *out == NULL) { - ret = EVP_PKEY_new(); - if (ret == NULL) { - OPENSSL_PUT_ERROR(EVP, ERR_R_EVP_LIB); - return NULL; - } - } else { - ret = *out; - } - - if (!EVP_PKEY_set_type(ret, type)) { - OPENSSL_PUT_ERROR(EVP, EVP_R_UNKNOWN_PUBLIC_KEY_TYPE); - goto err; +static EVP_PKEY *old_priv_decode(CBS *cbs, int type) { + EVP_PKEY *ret = EVP_PKEY_new(); + if (ret == NULL) { + return NULL; } - const uint8_t *in = *inp; - /* If trying to remove |old_priv_decode|, note that some code depends on this - * function writing into |*out| and the |priv_decode| path doesn't support - * that. */ - if (!ret->ameth->old_priv_decode || - !ret->ameth->old_priv_decode(ret, &in, len)) { - if (ret->ameth->priv_decode) { - /* Reset |in| in case |old_priv_decode| advanced it on error. */ - in = *inp; - PKCS8_PRIV_KEY_INFO *p8 = d2i_PKCS8_PRIV_KEY_INFO(NULL, &in, len); - if (!p8) { + switch (type) { + case EVP_PKEY_EC: { + EC_KEY *ec_key = EC_KEY_parse_private_key(cbs, NULL); + if (ec_key == NULL || !EVP_PKEY_assign_EC_KEY(ret, ec_key)) { + EC_KEY_free(ec_key); goto err; } - EVP_PKEY_free(ret); - ret = EVP_PKCS82PKEY(p8); - PKCS8_PRIV_KEY_INFO_free(p8); - if (ret == NULL) { + return ret; + } + case EVP_PKEY_DSA: { + DSA *dsa = DSA_parse_private_key(cbs); + if (dsa == NULL || !EVP_PKEY_assign_DSA(ret, dsa)) { + DSA_free(dsa); goto err; } - } else { - OPENSSL_PUT_ERROR(EVP, ERR_R_ASN1_LIB); + return ret; + } + case EVP_PKEY_RSA: { + RSA *rsa = RSA_parse_private_key(cbs); + if (rsa == NULL || !EVP_PKEY_assign_RSA(ret, rsa)) { + RSA_free(rsa); + goto err; + } + return ret; + } + default: + OPENSSL_PUT_ERROR(EVP, EVP_R_UNKNOWN_PUBLIC_KEY_TYPE); goto err; + } + +err: + EVP_PKEY_free(ret); + return NULL; +} + +EVP_PKEY *d2i_PrivateKey(int type, EVP_PKEY **out, const uint8_t **inp, + long len) { + if (len < 0) { + OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); + return NULL; + } + + /* Parse with the legacy format. */ + CBS cbs; + CBS_init(&cbs, *inp, (size_t)len); + EVP_PKEY *ret = old_priv_decode(&cbs, type); + if (ret == NULL) { + /* Try again with PKCS#8. */ + ERR_clear_error(); + CBS_init(&cbs, *inp, (size_t)len); + ret = EVP_parse_private_key(&cbs); + if (ret == NULL) { + return NULL; + } + if (ret->type != type) { + OPENSSL_PUT_ERROR(EVP, EVP_R_DIFFERENT_KEY_TYPES); + EVP_PKEY_free(ret); + return NULL; } } if (out != NULL) { + EVP_PKEY_free(*out); *out = ret; } - *inp = in; + *inp = CBS_data(&cbs); return ret; +} -err: - if (out == NULL || *out != ret) { - EVP_PKEY_free(ret); +/* num_elements parses one SEQUENCE from |in| and returns the number of elements + * in it. On parse error, it returns zero. */ +static size_t num_elements(const uint8_t *in, size_t in_len) { + CBS cbs, sequence; + CBS_init(&cbs, in, (size_t)in_len); + + if (!CBS_get_asn1(&cbs, &sequence, CBS_ASN1_SEQUENCE)) { + return 0; } - return NULL; + + size_t count = 0; + while (CBS_len(&sequence) > 0) { + if (!CBS_get_any_asn1_element(&sequence, NULL, NULL, NULL)) { + return 0; + } + + count++; + } + + return count; } EVP_PKEY *d2i_AutoPrivateKey(EVP_PKEY **out, const uint8_t **inp, long len) { - STACK_OF(ASN1_TYPE) *inkey; - const uint8_t *p; - int keytype; - p = *inp; - - /* Dirty trick: read in the ASN1 data into out STACK_OF(ASN1_TYPE): - * by analyzing it we can determine the passed structure: this - * assumes the input is surrounded by an ASN1 SEQUENCE. */ - inkey = d2i_ASN1_SEQUENCE_ANY(NULL, &p, len); - /* Since we only need to discern "traditional format" RSA and DSA - * keys we can just count the elements. */ - if (sk_ASN1_TYPE_num(inkey) == 6) { - keytype = EVP_PKEY_DSA; - } else if (sk_ASN1_TYPE_num(inkey) == 4) { - keytype = EVP_PKEY_EC; - } else if (sk_ASN1_TYPE_num(inkey) == 3) { - /* This seems to be PKCS8, not traditional format */ - p = *inp; - PKCS8_PRIV_KEY_INFO *p8 = d2i_PKCS8_PRIV_KEY_INFO(NULL, &p, len); - EVP_PKEY *ret; - - sk_ASN1_TYPE_pop_free(inkey, ASN1_TYPE_free); - if (!p8) { - OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_PUBLIC_KEY_TYPE); - return NULL; - } - ret = EVP_PKCS82PKEY(p8); - PKCS8_PRIV_KEY_INFO_free(p8); - if (ret == NULL) { - return NULL; - } + if (len < 0) { + OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); + return NULL; + } - *inp = p; - if (out) { + /* Parse the input as a PKCS#8 PrivateKeyInfo. */ + CBS cbs; + CBS_init(&cbs, *inp, (size_t)len); + EVP_PKEY *ret = EVP_parse_private_key(&cbs); + if (ret != NULL) { + if (out != NULL) { + EVP_PKEY_free(*out); *out = ret; } + *inp = CBS_data(&cbs); return ret; - } else { - keytype = EVP_PKEY_RSA; } + ERR_clear_error(); - sk_ASN1_TYPE_pop_free(inkey, ASN1_TYPE_free); - return d2i_PrivateKey(keytype, out, inp, len); + /* Count the elements to determine the legacy key format. */ + switch (num_elements(*inp, (size_t)len)) { + case 4: + return d2i_PrivateKey(EVP_PKEY_EC, out, inp, len); + + case 6: + return d2i_PrivateKey(EVP_PKEY_DSA, out, inp, len); + + default: + return d2i_PrivateKey(EVP_PKEY_RSA, out, inp, len); + } } int i2d_PublicKey(EVP_PKEY *key, uint8_t **outp) { diff --git a/Sources/BoringSSL/crypto/evp/evp_ctx.c b/Sources/BoringSSL/crypto/evp/evp_ctx.c index b06eefd6a..a17a8ccc2 100644 --- a/Sources/BoringSSL/crypto/evp/evp_ctx.c +++ b/Sources/BoringSSL/crypto/evp/evp_ctx.c @@ -56,13 +56,12 @@ #include -#include #include #include #include -#include +#include "../internal.h" #include "internal.h" @@ -98,8 +97,7 @@ static EVP_PKEY_CTX *evp_pkey_ctx_new(EVP_PKEY *pkey, ENGINE *e, int id) { if (pmeth == NULL) { OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM); - const char *name = OBJ_nid2sn(id); - ERR_add_error_dataf("algorithm %d (%s)", id, name); + ERR_add_error_dataf("algorithm %d", id); return NULL; } @@ -108,14 +106,15 @@ static EVP_PKEY_CTX *evp_pkey_ctx_new(EVP_PKEY *pkey, ENGINE *e, int id) { OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE); return NULL; } - memset(ret, 0, sizeof(EVP_PKEY_CTX)); + OPENSSL_memset(ret, 0, sizeof(EVP_PKEY_CTX)); ret->engine = e; ret->pmeth = pmeth; ret->operation = EVP_PKEY_OP_UNDEFINED; if (pkey) { - ret->pkey = EVP_PKEY_up_ref(pkey); + EVP_PKEY_up_ref(pkey); + ret->pkey = pkey; } if (pmeth->init) { @@ -149,46 +148,40 @@ void EVP_PKEY_CTX_free(EVP_PKEY_CTX *ctx) { OPENSSL_free(ctx); } -EVP_PKEY_CTX *EVP_PKEY_CTX_dup(EVP_PKEY_CTX *pctx) { - EVP_PKEY_CTX *rctx; - - if (!pctx->pmeth || !pctx->pmeth->copy) { +EVP_PKEY_CTX *EVP_PKEY_CTX_dup(EVP_PKEY_CTX *ctx) { + if (!ctx->pmeth || !ctx->pmeth->copy) { return NULL; } - rctx = OPENSSL_malloc(sizeof(EVP_PKEY_CTX)); - if (!rctx) { + EVP_PKEY_CTX *ret = OPENSSL_malloc(sizeof(EVP_PKEY_CTX)); + if (!ret) { return NULL; } - memset(rctx, 0, sizeof(EVP_PKEY_CTX)); + OPENSSL_memset(ret, 0, sizeof(EVP_PKEY_CTX)); - rctx->pmeth = pctx->pmeth; - rctx->engine = pctx->engine; - rctx->operation = pctx->operation; + ret->pmeth = ctx->pmeth; + ret->engine = ctx->engine; + ret->operation = ctx->operation; - if (pctx->pkey) { - rctx->pkey = EVP_PKEY_up_ref(pctx->pkey); - if (rctx->pkey == NULL) { - goto err; - } + if (ctx->pkey != NULL) { + EVP_PKEY_up_ref(ctx->pkey); + ret->pkey = ctx->pkey; } - if (pctx->peerkey) { - rctx->peerkey = EVP_PKEY_up_ref(pctx->peerkey); - if (rctx->peerkey == NULL) { - goto err; - } + if (ctx->peerkey != NULL) { + EVP_PKEY_up_ref(ctx->peerkey); + ret->peerkey = ctx->peerkey; } - if (pctx->pmeth->copy(rctx, pctx) > 0) { - return rctx; + if (ctx->pmeth->copy(ret, ctx) <= 0) { + ret->pmeth = NULL; + EVP_PKEY_CTX_free(ret); + OPENSSL_PUT_ERROR(EVP, ERR_LIB_EVP); + return NULL; } -err: - EVP_PKEY_CTX_free(rctx); - OPENSSL_PUT_ERROR(EVP, ERR_LIB_EVP); - return NULL; + return ret; } EVP_PKEY *EVP_PKEY_CTX_get0_pkey(EVP_PKEY_CTX *ctx) { return ctx->pkey; } @@ -200,6 +193,7 @@ int EVP_PKEY_CTX_ctrl(EVP_PKEY_CTX *ctx, int keytype, int optype, int cmd, return 0; } if (keytype != -1 && ctx->pmeth->pkey_id != keytype) { + OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); return 0; } diff --git a/Sources/BoringSSL/crypto/evp/internal.h b/Sources/BoringSSL/crypto/evp/internal.h index 7fe707e17..0783143d3 100644 --- a/Sources/BoringSSL/crypto/evp/internal.h +++ b/Sources/BoringSSL/crypto/evp/internal.h @@ -59,36 +59,17 @@ #include +#include + #if defined(__cplusplus) extern "C" { #endif -/* These values are flags for EVP_PKEY_ASN1_METHOD.flags. */ - -/* ASN1_PKEY_SIGPARAM_NULL controls whether the default behavior of - * EVP_DigestSignAlgorithm writes an explicit NULL parameter in the - * AlgorithmIdentifier. */ -#define ASN1_PKEY_SIGPARAM_NULL 0x1 - -/* evp_digest_sign_algorithm_result_t is the return value of the - * digest_sign_algorithm function in EVP_PKEY_ASN1_METHOD. */ -typedef enum { - /* EVP_DIGEST_SIGN_ALGORITHM_ERROR signals an error. */ - EVP_DIGEST_SIGN_ALGORITHM_ERROR = 0, - /* EVP_DIGEST_SIGN_ALGORITHM_SUCCESS signals that the parameters were - * serialized in the AlgorithmIdentifier. */ - EVP_DIGEST_SIGN_ALGORITHM_SUCCESS = 1, - /* EVP_DIGEST_SIGN_ALGORITHM_DEFAULT signals that the parameters are - * serialized using the default behavior. */ - EVP_DIGEST_SIGN_ALGORITHM_DEFAULT = 2, -} evp_digest_sign_algorithm_result_t; - struct evp_pkey_asn1_method_st { int pkey_id; - unsigned long pkey_flags; - - const char *pem_str; + uint8_t oid[9]; + uint8_t oid_len; /* pub_decode decodes |params| and |key| as a SubjectPublicKeyInfo * and writes the result into |out|. It returns one on success and zero on @@ -104,7 +85,6 @@ struct evp_pkey_asn1_method_st { int (*pub_encode)(CBB *out, const EVP_PKEY *key); int (*pub_cmp)(const EVP_PKEY *a, const EVP_PKEY *b); - int (*pub_print)(BIO *out, const EVP_PKEY *pkey, int indent, ASN1_PCTX *pctx); /* priv_decode decodes |params| and |key| as a PrivateKeyInfo and writes the * result into |out|. It returns one on success and zero on error. |params| is @@ -116,9 +96,6 @@ struct evp_pkey_asn1_method_st { * |out|. It returns one on success and zero on error. */ int (*priv_encode)(CBB *out, const EVP_PKEY *key); - int (*priv_print)(BIO *out, const EVP_PKEY *pkey, int indent, - ASN1_PCTX *pctx); - /* pkey_opaque returns 1 if the |pk| is opaque. Opaque keys are backed by * custom implementations which do not expose key material and parameters.*/ int (*pkey_opaque)(const EVP_PKEY *pk); @@ -135,27 +112,8 @@ struct evp_pkey_asn1_method_st { int (*param_missing)(const EVP_PKEY *pk); int (*param_copy)(EVP_PKEY *to, const EVP_PKEY *from); int (*param_cmp)(const EVP_PKEY *a, const EVP_PKEY *b); - int (*param_print)(BIO *out, const EVP_PKEY *pkey, int indent, - ASN1_PCTX *pctx); - int (*sig_print)(BIO *out, const X509_ALGOR *sigalg, const ASN1_STRING *sig, - int indent, ASN1_PCTX *pctx); - void (*pkey_free)(EVP_PKEY *pkey); - - /* Legacy functions for old PEM */ - - int (*old_priv_decode)(EVP_PKEY *pkey, const uint8_t **pder, - int derlen); - - /* Converting parameters to/from AlgorithmIdentifier (X509_ALGOR). */ - int (*digest_verify_init_from_algorithm)(EVP_MD_CTX *ctx, - X509_ALGOR *algor, - EVP_PKEY *pkey); - evp_digest_sign_algorithm_result_t (*digest_sign_algorithm)( - EVP_MD_CTX *ctx, - X509_ALGOR *algor); - } /* EVP_PKEY_ASN1_METHOD */; diff --git a/Sources/BoringSSL/crypto/evp/p_dsa_asn1.c b/Sources/BoringSSL/crypto/evp/p_dsa_asn1.c index 09f69090b..1f022f1a8 100644 --- a/Sources/BoringSSL/crypto/evp/p_dsa_asn1.c +++ b/Sources/BoringSSL/crypto/evp/p_dsa_asn1.c @@ -55,16 +55,11 @@ #include -#include -#include #include #include #include #include #include -#include -#include -#include #include "internal.h" @@ -111,10 +106,11 @@ static int dsa_pub_encode(CBB *out, const EVP_PKEY *key) { const int has_params = dsa->p != NULL && dsa->q != NULL && dsa->g != NULL; /* See RFC 5480, section 2. */ - CBB spki, algorithm, key_bitstring; + CBB spki, algorithm, oid, key_bitstring; if (!CBB_add_asn1(out, &spki, CBS_ASN1_SEQUENCE) || !CBB_add_asn1(&spki, &algorithm, CBS_ASN1_SEQUENCE) || - !OBJ_nid2cbb(&algorithm, NID_dsa) || + !CBB_add_asn1(&algorithm, &oid, CBS_ASN1_OBJECT) || + !CBB_add_bytes(&oid, dsa_asn1_meth.oid, dsa_asn1_meth.oid_len) || (has_params && !DSA_marshal_parameters(&algorithm, dsa)) || !CBB_add_asn1(&spki, &key_bitstring, CBS_ASN1_BITSTRING) || @@ -177,11 +173,12 @@ static int dsa_priv_encode(CBB *out, const EVP_PKEY *key) { } /* See PKCS#11, v2.40, section 2.5. */ - CBB pkcs8, algorithm, private_key; + CBB pkcs8, algorithm, oid, private_key; if (!CBB_add_asn1(out, &pkcs8, CBS_ASN1_SEQUENCE) || !CBB_add_asn1_uint64(&pkcs8, 0 /* version */) || !CBB_add_asn1(&pkcs8, &algorithm, CBS_ASN1_SEQUENCE) || - !OBJ_nid2cbb(&algorithm, NID_dsa) || + !CBB_add_asn1(&algorithm, &oid, CBS_ASN1_OBJECT) || + !CBB_add_bytes(&oid, dsa_asn1_meth.oid, dsa_asn1_meth.oid_len) || !DSA_marshal_parameters(&algorithm, dsa) || !CBB_add_asn1(&pkcs8, &private_key, CBS_ASN1_OCTETSTRING) || !BN_marshal_asn1(&private_key, dsa->priv_key) || @@ -245,157 +242,17 @@ static int dsa_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b) { static void int_dsa_free(EVP_PKEY *pkey) { DSA_free(pkey->pkey.dsa); } -static void update_buflen(const BIGNUM *b, size_t *pbuflen) { - size_t i; - - if (!b) { - return; - } - i = BN_num_bytes(b); - if (*pbuflen < i) { - *pbuflen = i; - } -} - -static int do_dsa_print(BIO *bp, const DSA *x, int off, int ptype) { - uint8_t *m = NULL; - int ret = 0; - size_t buf_len = 0; - const char *ktype = NULL; - - const BIGNUM *priv_key, *pub_key; - - priv_key = NULL; - if (ptype == 2) { - priv_key = x->priv_key; - } - - pub_key = NULL; - if (ptype > 0) { - pub_key = x->pub_key; - } - - ktype = "DSA-Parameters"; - if (ptype == 2) { - ktype = "Private-Key"; - } else if (ptype == 1) { - ktype = "Public-Key"; - } - - update_buflen(x->p, &buf_len); - update_buflen(x->q, &buf_len); - update_buflen(x->g, &buf_len); - update_buflen(priv_key, &buf_len); - update_buflen(pub_key, &buf_len); - - m = OPENSSL_malloc(buf_len + 10); - if (m == NULL) { - OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE); - goto err; - } - - if (priv_key) { - if (!BIO_indent(bp, off, 128) || - BIO_printf(bp, "%s: (%d bit)\n", ktype, BN_num_bits(x->p)) <= 0) { - goto err; - } - } - - if (!ASN1_bn_print(bp, "priv:", priv_key, m, off) || - !ASN1_bn_print(bp, "pub: ", pub_key, m, off) || - !ASN1_bn_print(bp, "P: ", x->p, m, off) || - !ASN1_bn_print(bp, "Q: ", x->q, m, off) || - !ASN1_bn_print(bp, "G: ", x->g, m, off)) { - goto err; - } - ret = 1; - -err: - OPENSSL_free(m); - return ret; -} - -static int dsa_param_print(BIO *bp, const EVP_PKEY *pkey, int indent, - ASN1_PCTX *ctx) { - return do_dsa_print(bp, pkey->pkey.dsa, indent, 0); -} - -static int dsa_pub_print(BIO *bp, const EVP_PKEY *pkey, int indent, - ASN1_PCTX *ctx) { - return do_dsa_print(bp, pkey->pkey.dsa, indent, 1); -} - -static int dsa_priv_print(BIO *bp, const EVP_PKEY *pkey, int indent, - ASN1_PCTX *ctx) { - return do_dsa_print(bp, pkey->pkey.dsa, indent, 2); -} - -static int old_dsa_priv_decode(EVP_PKEY *pkey, const uint8_t **pder, - int derlen) { - DSA *dsa; - dsa = d2i_DSAPrivateKey(NULL, pder, derlen); - if (dsa == NULL) { - OPENSSL_PUT_ERROR(EVP, ERR_R_DSA_LIB); - return 0; - } - EVP_PKEY_assign_DSA(pkey, dsa); - return 1; -} - -static int dsa_sig_print(BIO *bp, const X509_ALGOR *sigalg, - const ASN1_STRING *sig, int indent, ASN1_PCTX *pctx) { - DSA_SIG *dsa_sig; - const uint8_t *p; - - if (!sig) { - return BIO_puts(bp, "\n") > 0; - } - - p = sig->data; - dsa_sig = d2i_DSA_SIG(NULL, &p, sig->length); - if (dsa_sig == NULL) { - return X509_signature_dump(bp, sig, indent); - } - - int rv = 0; - size_t buf_len = 0; - uint8_t *m = NULL; - - update_buflen(dsa_sig->r, &buf_len); - update_buflen(dsa_sig->s, &buf_len); - m = OPENSSL_malloc(buf_len + 10); - if (m == NULL) { - OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE); - goto err; - } - - if (BIO_write(bp, "\n", 1) != 1 || - !ASN1_bn_print(bp, "r: ", dsa_sig->r, m, indent) || - !ASN1_bn_print(bp, "s: ", dsa_sig->s, m, indent)) { - goto err; - } - rv = 1; - -err: - OPENSSL_free(m); - DSA_SIG_free(dsa_sig); - return rv; -} - const EVP_PKEY_ASN1_METHOD dsa_asn1_meth = { EVP_PKEY_DSA, - 0, - - "DSA", + /* 1.2.840.10040.4.1 */ + {0x2a, 0x86, 0x48, 0xce, 0x38, 0x04, 0x01}, 7, dsa_pub_decode, dsa_pub_encode, dsa_pub_cmp, - dsa_pub_print, dsa_priv_decode, dsa_priv_encode, - dsa_priv_print, NULL /* pkey_opaque */, NULL /* pkey_supports_digest */, @@ -406,12 +263,6 @@ const EVP_PKEY_ASN1_METHOD dsa_asn1_meth = { dsa_missing_parameters, dsa_copy_parameters, dsa_cmp_parameters, - dsa_param_print, - dsa_sig_print, int_dsa_free, - old_dsa_priv_decode, - - NULL /* digest_verify_init_from_algorithm */, - NULL /* digest_sign_algorithm */, }; diff --git a/Sources/BoringSSL/crypto/evp/p_ec.c b/Sources/BoringSSL/crypto/evp/p_ec.c index 495218272..dc1ea6f6d 100644 --- a/Sources/BoringSSL/crypto/evp/p_ec.c +++ b/Sources/BoringSSL/crypto/evp/p_ec.c @@ -66,10 +66,11 @@ #include #include #include -#include +#include #include "internal.h" #include "../ec/internal.h" +#include "../internal.h" typedef struct { @@ -84,7 +85,7 @@ static int pkey_ec_init(EVP_PKEY_CTX *ctx) { if (!dctx) { return 0; } - memset(dctx, 0, sizeof(EC_PKEY_CTX)); + OPENSSL_memset(dctx, 0, sizeof(EC_PKEY_CTX)); ctx->data = dctx; diff --git a/Sources/BoringSSL/crypto/evp/p_ec_asn1.c b/Sources/BoringSSL/crypto/evp/p_ec_asn1.c index 14f38396f..8d44dcdce 100644 --- a/Sources/BoringSSL/crypto/evp/p_ec_asn1.c +++ b/Sources/BoringSSL/crypto/evp/p_ec_asn1.c @@ -55,16 +55,12 @@ #include -#include #include #include #include #include #include #include -#include -#include -#include #include "internal.h" @@ -72,19 +68,15 @@ static int eckey_pub_encode(CBB *out, const EVP_PKEY *key) { const EC_KEY *ec_key = key->pkey.ec; const EC_GROUP *group = EC_KEY_get0_group(ec_key); - int curve_nid = EC_GROUP_get_curve_name(group); - if (curve_nid == NID_undef) { - OPENSSL_PUT_ERROR(EVP, EVP_R_NO_NID_FOR_CURVE); - return 0; - } const EC_POINT *public_key = EC_KEY_get0_public_key(ec_key); /* See RFC 5480, section 2. */ - CBB spki, algorithm, key_bitstring; + CBB spki, algorithm, oid, key_bitstring; if (!CBB_add_asn1(out, &spki, CBS_ASN1_SEQUENCE) || !CBB_add_asn1(&spki, &algorithm, CBS_ASN1_SEQUENCE) || - !OBJ_nid2cbb(&algorithm, NID_X9_62_id_ecPublicKey) || - !OBJ_nid2cbb(&algorithm, curve_nid) || + !CBB_add_asn1(&algorithm, &oid, CBS_ASN1_OBJECT) || + !CBB_add_bytes(&oid, ec_asn1_meth.oid, ec_asn1_meth.oid_len) || + !EC_KEY_marshal_curve_name(&algorithm, group) || !CBB_add_asn1(&spki, &key_bitstring, CBS_ASN1_BITSTRING) || !CBB_add_u8(&key_bitstring, 0 /* padding */) || !EC_POINT_point2cbb(&key_bitstring, group, public_key, @@ -101,31 +93,33 @@ static int eckey_pub_decode(EVP_PKEY *out, CBS *params, CBS *key) { /* See RFC 5480, section 2. */ /* The parameters are a named curve. */ - CBS named_curve; - if (!CBS_get_asn1(params, &named_curve, CBS_ASN1_OBJECT) || - CBS_len(params) != 0) { + EC_POINT *point = NULL; + EC_KEY *eckey = NULL; + EC_GROUP *group = EC_KEY_parse_curve_name(params); + if (group == NULL || CBS_len(params) != 0) { OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); - return 0; + goto err; } - EC_KEY *eckey = EC_KEY_new_by_curve_name(OBJ_cbs2nid(&named_curve)); - if (eckey == NULL) { - return 0; + eckey = EC_KEY_new(); + if (eckey == NULL || !EC_KEY_set_group(eckey, group)) { + goto err; } - EC_POINT *point = EC_POINT_new(EC_KEY_get0_group(eckey)); + point = EC_POINT_new(group); if (point == NULL || - !EC_POINT_oct2point(EC_KEY_get0_group(eckey), point, CBS_data(key), - CBS_len(key), NULL) || + !EC_POINT_oct2point(group, point, CBS_data(key), CBS_len(key), NULL) || !EC_KEY_set_public_key(eckey, point)) { goto err; } + EC_GROUP_free(group); EC_POINT_free(point); EVP_PKEY_assign_EC_KEY(out, eckey); return 1; err: + EC_GROUP_free(group); EC_POINT_free(point); EC_KEY_free(eckey); return 0; @@ -169,11 +163,6 @@ static int eckey_priv_decode(EVP_PKEY *out, CBS *params, CBS *key) { static int eckey_priv_encode(CBB *out, const EVP_PKEY *key) { const EC_KEY *ec_key = key->pkey.ec; - int curve_nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec_key)); - if (curve_nid == NID_undef) { - OPENSSL_PUT_ERROR(EVP, EVP_R_NO_NID_FOR_CURVE); - return 0; - } /* Omit the redundant copy of the curve name. This contradicts RFC 5915 but * aligns with PKCS #11. SEC 1 only says they may be omitted if known by other @@ -182,12 +171,13 @@ static int eckey_priv_encode(CBB *out, const EVP_PKEY *key) { unsigned enc_flags = EC_KEY_get_enc_flags(ec_key) | EC_PKEY_NO_PARAMETERS; /* See RFC 5915. */ - CBB pkcs8, algorithm, private_key; + CBB pkcs8, algorithm, oid, private_key; if (!CBB_add_asn1(out, &pkcs8, CBS_ASN1_SEQUENCE) || !CBB_add_asn1_uint64(&pkcs8, 0 /* version */) || !CBB_add_asn1(&pkcs8, &algorithm, CBS_ASN1_SEQUENCE) || - !OBJ_nid2cbb(&algorithm, NID_X9_62_id_ecPublicKey) || - !OBJ_nid2cbb(&algorithm, curve_nid) || + !CBB_add_asn1(&algorithm, &oid, CBS_ASN1_OBJECT) || + !CBB_add_bytes(&oid, ec_asn1_meth.oid, ec_asn1_meth.oid_len) || + !EC_KEY_marshal_curve_name(&algorithm, EC_KEY_get0_group(ec_key)) || !CBB_add_asn1(&pkcs8, &private_key, CBS_ASN1_OCTETSTRING) || !EC_KEY_marshal_private_key(&private_key, ec_key, enc_flags) || !CBB_flush(out)) { @@ -237,153 +227,21 @@ static int ec_cmp_parameters(const EVP_PKEY *a, const EVP_PKEY *b) { static void int_ec_free(EVP_PKEY *pkey) { EC_KEY_free(pkey->pkey.ec); } -static int do_EC_KEY_print(BIO *bp, const EC_KEY *x, int off, int ktype) { - uint8_t *buffer = NULL; - const char *ecstr; - size_t buf_len = 0, i; - int ret = 0, reason = ERR_R_BIO_LIB; - BN_CTX *ctx = NULL; - const EC_GROUP *group; - const EC_POINT *public_key; - const BIGNUM *priv_key; - uint8_t *pub_key_bytes = NULL; - size_t pub_key_bytes_len = 0; - - if (x == NULL || (group = EC_KEY_get0_group(x)) == NULL) { - reason = ERR_R_PASSED_NULL_PARAMETER; - goto err; - } - - ctx = BN_CTX_new(); - if (ctx == NULL) { - reason = ERR_R_MALLOC_FAILURE; - goto err; - } - - if (ktype > 0) { - public_key = EC_KEY_get0_public_key(x); - if (public_key != NULL) { - pub_key_bytes_len = EC_POINT_point2oct( - group, public_key, EC_KEY_get_conv_form(x), NULL, 0, ctx); - if (pub_key_bytes_len == 0) { - reason = ERR_R_MALLOC_FAILURE; - goto err; - } - pub_key_bytes = OPENSSL_malloc(pub_key_bytes_len); - if (pub_key_bytes == NULL) { - reason = ERR_R_MALLOC_FAILURE; - goto err; - } - pub_key_bytes_len = - EC_POINT_point2oct(group, public_key, EC_KEY_get_conv_form(x), - pub_key_bytes, pub_key_bytes_len, ctx); - if (pub_key_bytes_len == 0) { - reason = ERR_R_MALLOC_FAILURE; - goto err; - } - buf_len = pub_key_bytes_len; - } - } - - if (ktype == 2) { - priv_key = EC_KEY_get0_private_key(x); - if (priv_key && (i = (size_t)BN_num_bytes(priv_key)) > buf_len) { - buf_len = i; - } - } else { - priv_key = NULL; - } - - if (ktype > 0) { - buf_len += 10; - if ((buffer = OPENSSL_malloc(buf_len)) == NULL) { - reason = ERR_R_MALLOC_FAILURE; - goto err; - } - } - if (ktype == 2) { - ecstr = "Private-Key"; - } else if (ktype == 1) { - ecstr = "Public-Key"; - } else { - ecstr = "ECDSA-Parameters"; - } - - if (!BIO_indent(bp, off, 128)) { - goto err; - } - const BIGNUM *order = EC_GROUP_get0_order(group); - if (BIO_printf(bp, "%s: (%d bit)\n", ecstr, BN_num_bits(order)) <= 0) { - goto err; - } - - if ((priv_key != NULL) && - !ASN1_bn_print(bp, "priv:", priv_key, buffer, off)) { - goto err; - } - if (pub_key_bytes != NULL) { - BIO_hexdump(bp, pub_key_bytes, pub_key_bytes_len, off); - } - /* TODO(fork): implement */ - /* - if (!ECPKParameters_print(bp, group, off)) - goto err; */ - ret = 1; - -err: - if (!ret) { - OPENSSL_PUT_ERROR(EVP, reason); - } - OPENSSL_free(pub_key_bytes); - BN_CTX_free(ctx); - OPENSSL_free(buffer); - return ret; -} - -static int eckey_param_print(BIO *bp, const EVP_PKEY *pkey, int indent, - ASN1_PCTX *ctx) { - return do_EC_KEY_print(bp, pkey->pkey.ec, indent, 0); -} - -static int eckey_pub_print(BIO *bp, const EVP_PKEY *pkey, int indent, - ASN1_PCTX *ctx) { - return do_EC_KEY_print(bp, pkey->pkey.ec, indent, 1); -} - - -static int eckey_priv_print(BIO *bp, const EVP_PKEY *pkey, int indent, - ASN1_PCTX *ctx) { - return do_EC_KEY_print(bp, pkey->pkey.ec, indent, 2); -} - static int eckey_opaque(const EVP_PKEY *pkey) { return EC_KEY_is_opaque(pkey->pkey.ec); } -static int old_ec_priv_decode(EVP_PKEY *pkey, const uint8_t **pder, - int derlen) { - EC_KEY *ec; - if (!(ec = d2i_ECPrivateKey(NULL, pder, derlen))) { - OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); - return 0; - } - EVP_PKEY_assign_EC_KEY(pkey, ec); - return 1; -} - const EVP_PKEY_ASN1_METHOD ec_asn1_meth = { EVP_PKEY_EC, - 0, - "EC", + /* 1.2.840.10045.2.1 */ + {0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01}, 7, eckey_pub_decode, eckey_pub_encode, eckey_pub_cmp, - eckey_pub_print, eckey_priv_decode, eckey_priv_encode, - eckey_priv_print, eckey_opaque, 0 /* pkey_supports_digest */, @@ -394,12 +252,6 @@ const EVP_PKEY_ASN1_METHOD ec_asn1_meth = { ec_missing_parameters, ec_copy_parameters, ec_cmp_parameters, - eckey_param_print, - 0, int_ec_free, - old_ec_priv_decode, - - NULL /* digest_verify_init_from_algorithm */, - NULL /* digest_sign_algorithm */, }; diff --git a/Sources/BoringSSL/crypto/evp/p_rsa.c b/Sources/BoringSSL/crypto/evp/p_rsa.c index 629c33a62..ea2ba9987 100644 --- a/Sources/BoringSSL/crypto/evp/p_rsa.c +++ b/Sources/BoringSSL/crypto/evp/p_rsa.c @@ -64,9 +64,10 @@ #include #include #include -#include +#include #include +#include "../internal.h" #include "../rsa/internal.h" #include "internal.h" @@ -97,7 +98,7 @@ static int pkey_rsa_init(EVP_PKEY_CTX *ctx) { if (!rctx) { return 0; } - memset(rctx, 0, sizeof(RSA_PKEY_CTX)); + OPENSSL_memset(rctx, 0, sizeof(RSA_PKEY_CTX)); rctx->nbits = 2048; rctx->pad_mode = RSA_PKCS1_PADDING; @@ -231,6 +232,11 @@ static int pkey_rsa_verify(EVP_PKEY_CTX *ctx, const uint8_t *sig, return RSA_verify(EVP_MD_type(rctx->md), tbs, tbslen, sig, siglen, rsa); case RSA_PKCS1_PSS_PADDING: + if (tbslen != EVP_MD_size(rctx->md)) { + OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_DIGEST_LENGTH); + return 0; + } + if (!setup_tbuf(rctx, ctx) || !RSA_verify_raw(rsa, &rslen, rctx->tbuf, key_len, sig, siglen, RSA_NO_PADDING) || @@ -284,7 +290,7 @@ static int pkey_rsa_verify_recover(EVP_PKEY_CTX *ctx, uint8_t *out, return 0; } *out_len = ret; - memcpy(out, rctx->tbuf, *out_len); + OPENSSL_memcpy(out, rctx->tbuf, *out_len); return 1; } @@ -324,7 +330,7 @@ static int pkey_rsa_verify_recover(EVP_PKEY_CTX *ctx, uint8_t *out, } if (out != NULL) { - memcpy(out, rctx->tbuf + asn1_prefix_len, result_len); + OPENSSL_memcpy(out, rctx->tbuf + asn1_prefix_len, result_len); } *out_len = result_len; diff --git a/Sources/BoringSSL/crypto/evp/p_rsa_asn1.c b/Sources/BoringSSL/crypto/evp/p_rsa_asn1.c index 6848cc475..2c4b266d9 100644 --- a/Sources/BoringSSL/crypto/evp/p_rsa_asn1.c +++ b/Sources/BoringSSL/crypto/evp/p_rsa_asn1.c @@ -55,15 +55,12 @@ #include -#include -#include +#include #include #include #include #include -#include #include -#include #include "../rsa/internal.h" #include "internal.h" @@ -71,10 +68,11 @@ static int rsa_pub_encode(CBB *out, const EVP_PKEY *key) { /* See RFC 3279, section 2.3.1. */ - CBB spki, algorithm, null, key_bitstring; + CBB spki, algorithm, oid, null, key_bitstring; if (!CBB_add_asn1(out, &spki, CBS_ASN1_SEQUENCE) || !CBB_add_asn1(&spki, &algorithm, CBS_ASN1_SEQUENCE) || - !OBJ_nid2cbb(&algorithm, NID_rsaEncryption) || + !CBB_add_asn1(&algorithm, &oid, CBS_ASN1_OBJECT) || + !CBB_add_bytes(&oid, rsa_asn1_meth.oid, rsa_asn1_meth.oid_len) || !CBB_add_asn1(&algorithm, &null, CBS_ASN1_NULL) || !CBB_add_asn1(&spki, &key_bitstring, CBS_ASN1_BITSTRING) || !CBB_add_u8(&key_bitstring, 0 /* padding */) || @@ -122,11 +120,12 @@ static int rsa_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b) { } static int rsa_priv_encode(CBB *out, const EVP_PKEY *key) { - CBB pkcs8, algorithm, null, private_key; + CBB pkcs8, algorithm, oid, null, private_key; if (!CBB_add_asn1(out, &pkcs8, CBS_ASN1_SEQUENCE) || !CBB_add_asn1_uint64(&pkcs8, 0 /* version */) || !CBB_add_asn1(&pkcs8, &algorithm, CBS_ASN1_SEQUENCE) || - !OBJ_nid2cbb(&algorithm, NID_rsaEncryption) || + !CBB_add_asn1(&algorithm, &oid, CBS_ASN1_OBJECT) || + !CBB_add_bytes(&oid, rsa_asn1_meth.oid, rsa_asn1_meth.oid_len) || !CBB_add_asn1(&algorithm, &null, CBS_ASN1_NULL) || !CBB_add_asn1(&pkcs8, &private_key, CBS_ASN1_OCTETSTRING) || !RSA_marshal_private_key(&private_key, key->pkey.rsa) || @@ -177,548 +176,17 @@ static int rsa_bits(const EVP_PKEY *pkey) { static void int_rsa_free(EVP_PKEY *pkey) { RSA_free(pkey->pkey.rsa); } -static void update_buflen(const BIGNUM *b, size_t *pbuflen) { - size_t i; - - if (!b) { - return; - } - - i = BN_num_bytes(b); - if (*pbuflen < i) { - *pbuflen = i; - } -} - -static int do_rsa_print(BIO *out, const RSA *rsa, int off, - int include_private) { - char *str; - const char *s; - uint8_t *m = NULL; - int ret = 0, mod_len = 0; - size_t buf_len = 0; - - update_buflen(rsa->n, &buf_len); - update_buflen(rsa->e, &buf_len); - - if (include_private) { - update_buflen(rsa->d, &buf_len); - update_buflen(rsa->p, &buf_len); - update_buflen(rsa->q, &buf_len); - update_buflen(rsa->dmp1, &buf_len); - update_buflen(rsa->dmq1, &buf_len); - update_buflen(rsa->iqmp, &buf_len); - - if (rsa->additional_primes != NULL) { - size_t i; - - for (i = 0; i < sk_RSA_additional_prime_num(rsa->additional_primes); - i++) { - const RSA_additional_prime *ap = - sk_RSA_additional_prime_value(rsa->additional_primes, i); - update_buflen(ap->prime, &buf_len); - update_buflen(ap->exp, &buf_len); - update_buflen(ap->coeff, &buf_len); - } - } - } - - m = OPENSSL_malloc(buf_len + 10); - if (m == NULL) { - OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE); - goto err; - } - - if (rsa->n != NULL) { - mod_len = BN_num_bits(rsa->n); - } - - if (!BIO_indent(out, off, 128)) { - goto err; - } - - if (include_private && rsa->d) { - if (BIO_printf(out, "Private-Key: (%d bit)\n", mod_len) <= 0) { - goto err; - } - str = "modulus:"; - s = "publicExponent:"; - } else { - if (BIO_printf(out, "Public-Key: (%d bit)\n", mod_len) <= 0) { - goto err; - } - str = "Modulus:"; - s = "Exponent:"; - } - if (!ASN1_bn_print(out, str, rsa->n, m, off) || - !ASN1_bn_print(out, s, rsa->e, m, off)) { - goto err; - } - - if (include_private) { - if (!ASN1_bn_print(out, "privateExponent:", rsa->d, m, off) || - !ASN1_bn_print(out, "prime1:", rsa->p, m, off) || - !ASN1_bn_print(out, "prime2:", rsa->q, m, off) || - !ASN1_bn_print(out, "exponent1:", rsa->dmp1, m, off) || - !ASN1_bn_print(out, "exponent2:", rsa->dmq1, m, off) || - !ASN1_bn_print(out, "coefficient:", rsa->iqmp, m, off)) { - goto err; - } - - if (rsa->additional_primes != NULL && - sk_RSA_additional_prime_num(rsa->additional_primes) > 0) { - size_t i; - - if (BIO_printf(out, "otherPrimeInfos:\n") <= 0) { - goto err; - } - for (i = 0; i < sk_RSA_additional_prime_num(rsa->additional_primes); - i++) { - const RSA_additional_prime *ap = - sk_RSA_additional_prime_value(rsa->additional_primes, i); - - if (BIO_printf(out, "otherPrimeInfo (prime %u):\n", - (unsigned)(i + 3)) <= 0 || - !ASN1_bn_print(out, "prime:", ap->prime, m, off) || - !ASN1_bn_print(out, "exponent:", ap->exp, m, off) || - !ASN1_bn_print(out, "coeff:", ap->coeff, m, off)) { - goto err; - } - } - } - } - ret = 1; - -err: - OPENSSL_free(m); - return ret; -} - -static int rsa_pub_print(BIO *bp, const EVP_PKEY *pkey, int indent, - ASN1_PCTX *ctx) { - return do_rsa_print(bp, pkey->pkey.rsa, indent, 0); -} - - -static int rsa_priv_print(BIO *bp, const EVP_PKEY *pkey, int indent, - ASN1_PCTX *ctx) { - return do_rsa_print(bp, pkey->pkey.rsa, indent, 1); -} - -/* Given an MGF1 Algorithm ID decode to an Algorithm Identifier */ -static X509_ALGOR *rsa_mgf1_decode(X509_ALGOR *alg) { - const uint8_t *p; - int plen; - - if (alg == NULL || alg->parameter == NULL || - OBJ_obj2nid(alg->algorithm) != NID_mgf1 || - alg->parameter->type != V_ASN1_SEQUENCE) { - return NULL; - } - - p = alg->parameter->value.sequence->data; - plen = alg->parameter->value.sequence->length; - return d2i_X509_ALGOR(NULL, &p, plen); -} - -static RSA_PSS_PARAMS *rsa_pss_decode(const X509_ALGOR *alg, - X509_ALGOR **pmaskHash) { - const uint8_t *p; - int plen; - RSA_PSS_PARAMS *pss; - - *pmaskHash = NULL; - - if (!alg->parameter || alg->parameter->type != V_ASN1_SEQUENCE) { - return NULL; - } - p = alg->parameter->value.sequence->data; - plen = alg->parameter->value.sequence->length; - pss = d2i_RSA_PSS_PARAMS(NULL, &p, plen); - - if (!pss) { - return NULL; - } - - *pmaskHash = rsa_mgf1_decode(pss->maskGenAlgorithm); - - return pss; -} - -static int rsa_pss_param_print(BIO *bp, RSA_PSS_PARAMS *pss, - X509_ALGOR *maskHash, int indent) { - int rv = 0; - - if (!pss) { - if (BIO_puts(bp, " (INVALID PSS PARAMETERS)\n") <= 0) { - return 0; - } - return 1; - } - - if (BIO_puts(bp, "\n") <= 0 || - !BIO_indent(bp, indent, 128) || - BIO_puts(bp, "Hash Algorithm: ") <= 0) { - goto err; - } - - if (pss->hashAlgorithm) { - if (i2a_ASN1_OBJECT(bp, pss->hashAlgorithm->algorithm) <= 0) { - goto err; - } - } else if (BIO_puts(bp, "sha1 (default)") <= 0) { - goto err; - } - - if (BIO_puts(bp, "\n") <= 0 || - !BIO_indent(bp, indent, 128) || - BIO_puts(bp, "Mask Algorithm: ") <= 0) { - goto err; - } - - if (pss->maskGenAlgorithm) { - if (i2a_ASN1_OBJECT(bp, pss->maskGenAlgorithm->algorithm) <= 0 || - BIO_puts(bp, " with ") <= 0) { - goto err; - } - - if (maskHash) { - if (i2a_ASN1_OBJECT(bp, maskHash->algorithm) <= 0) { - goto err; - } - } else if (BIO_puts(bp, "INVALID") <= 0) { - goto err; - } - } else if (BIO_puts(bp, "mgf1 with sha1 (default)") <= 0) { - goto err; - } - BIO_puts(bp, "\n"); - - if (!BIO_indent(bp, indent, 128) || - BIO_puts(bp, "Salt Length: 0x") <= 0) { - goto err; - } - - if (pss->saltLength) { - if (i2a_ASN1_INTEGER(bp, pss->saltLength) <= 0) { - goto err; - } - } else if (BIO_puts(bp, "14 (default)") <= 0) { - goto err; - } - BIO_puts(bp, "\n"); - - if (!BIO_indent(bp, indent, 128) || - BIO_puts(bp, "Trailer Field: 0x") <= 0) { - goto err; - } - - if (pss->trailerField) { - if (i2a_ASN1_INTEGER(bp, pss->trailerField) <= 0) { - goto err; - } - } else if (BIO_puts(bp, "BC (default)") <= 0) { - goto err; - } - BIO_puts(bp, "\n"); - - rv = 1; - -err: - return rv; -} - -static int rsa_sig_print(BIO *bp, const X509_ALGOR *sigalg, - const ASN1_STRING *sig, int indent, ASN1_PCTX *pctx) { - if (OBJ_obj2nid(sigalg->algorithm) == NID_rsassaPss) { - int rv; - RSA_PSS_PARAMS *pss; - X509_ALGOR *maskHash; - - pss = rsa_pss_decode(sigalg, &maskHash); - rv = rsa_pss_param_print(bp, pss, maskHash, indent); - RSA_PSS_PARAMS_free(pss); - X509_ALGOR_free(maskHash); - if (!rv) { - return 0; - } - } else if (!sig && BIO_puts(bp, "\n") <= 0) { - return 0; - } - - if (sig) { - return X509_signature_dump(bp, sig, indent); - } - return 1; -} - -static int old_rsa_priv_decode(EVP_PKEY *pkey, const uint8_t **pder, - int derlen) { - RSA *rsa = d2i_RSAPrivateKey(NULL, pder, derlen); - if (rsa == NULL) { - OPENSSL_PUT_ERROR(EVP, ERR_R_RSA_LIB); - return 0; - } - EVP_PKEY_assign_RSA(pkey, rsa); - return 1; -} - -/* allocate and set algorithm ID from EVP_MD, default SHA1 */ -static int rsa_md_to_algor(X509_ALGOR **palg, const EVP_MD *md) { - if (EVP_MD_type(md) == NID_sha1) { - return 1; - } - *palg = X509_ALGOR_new(); - if (!*palg) { - return 0; - } - X509_ALGOR_set_md(*palg, md); - return 1; -} - -/* Allocate and set MGF1 algorithm ID from EVP_MD */ -static int rsa_md_to_mgf1(X509_ALGOR **palg, const EVP_MD *mgf1md) { - X509_ALGOR *algtmp = NULL; - ASN1_STRING *stmp = NULL; - *palg = NULL; - - if (EVP_MD_type(mgf1md) == NID_sha1) { - return 1; - } - /* need to embed algorithm ID inside another */ - if (!rsa_md_to_algor(&algtmp, mgf1md) || - !ASN1_item_pack(algtmp, ASN1_ITEM_rptr(X509_ALGOR), &stmp)) { - goto err; - } - *palg = X509_ALGOR_new(); - if (!*palg) { - goto err; - } - X509_ALGOR_set0(*palg, OBJ_nid2obj(NID_mgf1), V_ASN1_SEQUENCE, stmp); - stmp = NULL; - -err: - ASN1_STRING_free(stmp); - X509_ALGOR_free(algtmp); - if (*palg) { - return 1; - } - - return 0; -} - -/* convert algorithm ID to EVP_MD, default SHA1 */ -static const EVP_MD *rsa_algor_to_md(X509_ALGOR *alg) { - const EVP_MD *md; - if (!alg) { - return EVP_sha1(); - } - md = EVP_get_digestbyobj(alg->algorithm); - if (md == NULL) { - OPENSSL_PUT_ERROR(EVP, EVP_R_UNKNOWN_DIGEST); - } - return md; -} - -/* convert MGF1 algorithm ID to EVP_MD, default SHA1 */ -static const EVP_MD *rsa_mgf1_to_md(X509_ALGOR *alg, X509_ALGOR *maskHash) { - const EVP_MD *md; - if (!alg) { - return EVP_sha1(); - } - /* Check mask and lookup mask hash algorithm */ - if (OBJ_obj2nid(alg->algorithm) != NID_mgf1) { - OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_MASK_ALGORITHM); - return NULL; - } - if (!maskHash) { - OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_MASK_PARAMETER); - return NULL; - } - md = EVP_get_digestbyobj(maskHash->algorithm); - if (md == NULL) { - OPENSSL_PUT_ERROR(EVP, EVP_R_UNKNOWN_MASK_DIGEST); - return NULL; - } - return md; -} - -/* rsa_ctx_to_pss converts EVP_PKEY_CTX in PSS mode into corresponding - * algorithm parameter, suitable for setting as an AlgorithmIdentifier. */ -static ASN1_STRING *rsa_ctx_to_pss(EVP_PKEY_CTX *pkctx) { - const EVP_MD *sigmd, *mgf1md; - RSA_PSS_PARAMS *pss = NULL; - ASN1_STRING *os = NULL; - EVP_PKEY *pk = EVP_PKEY_CTX_get0_pkey(pkctx); - int saltlen, rv = 0; - - if (!EVP_PKEY_CTX_get_signature_md(pkctx, &sigmd) || - !EVP_PKEY_CTX_get_rsa_mgf1_md(pkctx, &mgf1md) || - !EVP_PKEY_CTX_get_rsa_pss_saltlen(pkctx, &saltlen)) { - goto err; - } - - if (saltlen == -1) { - saltlen = EVP_MD_size(sigmd); - } else if (saltlen == -2) { - saltlen = EVP_PKEY_size(pk) - EVP_MD_size(sigmd) - 2; - if (((EVP_PKEY_bits(pk) - 1) & 0x7) == 0) { - saltlen--; - } - } else { - goto err; - } - - pss = RSA_PSS_PARAMS_new(); - if (!pss) { - goto err; - } - - if (saltlen != 20) { - pss->saltLength = ASN1_INTEGER_new(); - if (!pss->saltLength || - !ASN1_INTEGER_set(pss->saltLength, saltlen)) { - goto err; - } - } - - if (!rsa_md_to_algor(&pss->hashAlgorithm, sigmd) || - !rsa_md_to_mgf1(&pss->maskGenAlgorithm, mgf1md)) { - goto err; - } - - /* Finally create string with pss parameter encoding. */ - if (!ASN1_item_pack(pss, ASN1_ITEM_rptr(RSA_PSS_PARAMS), &os)) { - goto err; - } - rv = 1; - -err: - if (pss) { - RSA_PSS_PARAMS_free(pss); - } - if (rv) { - return os; - } - if (os) { - ASN1_STRING_free(os); - } - return NULL; -} - -/* From PSS AlgorithmIdentifier set public key parameters. */ -static int rsa_pss_to_ctx(EVP_MD_CTX *ctx, X509_ALGOR *sigalg, EVP_PKEY *pkey) { - int ret = 0; - int saltlen; - const EVP_MD *mgf1md = NULL, *md = NULL; - RSA_PSS_PARAMS *pss; - X509_ALGOR *maskHash; - EVP_PKEY_CTX *pkctx; - - /* Sanity check: make sure it is PSS */ - if (OBJ_obj2nid(sigalg->algorithm) != NID_rsassaPss) { - OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_SIGNATURE_TYPE); - return 0; - } - /* Decode PSS parameters */ - pss = rsa_pss_decode(sigalg, &maskHash); - if (pss == NULL) { - OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PSS_PARAMETERS); - goto err; - } - - mgf1md = rsa_mgf1_to_md(pss->maskGenAlgorithm, maskHash); - if (!mgf1md) { - goto err; - } - md = rsa_algor_to_md(pss->hashAlgorithm); - if (!md) { - goto err; - } - - saltlen = 20; - if (pss->saltLength) { - saltlen = ASN1_INTEGER_get(pss->saltLength); - - /* Could perform more salt length sanity checks but the main - * RSA routines will trap other invalid values anyway. */ - if (saltlen < 0) { - OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_SALT_LENGTH); - goto err; - } - } - - /* low-level routines support only trailer field 0xbc (value 1) - * and PKCS#1 says we should reject any other value anyway. */ - if (pss->trailerField && ASN1_INTEGER_get(pss->trailerField) != 1) { - OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_TRAILER); - goto err; - } - - if (!EVP_DigestVerifyInit(ctx, &pkctx, md, NULL, pkey) || - !EVP_PKEY_CTX_set_rsa_padding(pkctx, RSA_PKCS1_PSS_PADDING) || - !EVP_PKEY_CTX_set_rsa_pss_saltlen(pkctx, saltlen) || - !EVP_PKEY_CTX_set_rsa_mgf1_md(pkctx, mgf1md)) { - goto err; - } - - ret = 1; - -err: - RSA_PSS_PARAMS_free(pss); - if (maskHash) { - X509_ALGOR_free(maskHash); - } - return ret; -} - -/* Customised RSA AlgorithmIdentifier handling. This is called when a signature - * is encountered requiring special handling. We currently only handle PSS. */ -static int rsa_digest_verify_init_from_algorithm(EVP_MD_CTX *ctx, - X509_ALGOR *sigalg, - EVP_PKEY *pkey) { - /* Sanity check: make sure it is PSS */ - if (OBJ_obj2nid(sigalg->algorithm) != NID_rsassaPss) { - OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_SIGNATURE_TYPE); - return 0; - } - return rsa_pss_to_ctx(ctx, sigalg, pkey); -} - -static evp_digest_sign_algorithm_result_t rsa_digest_sign_algorithm( - EVP_MD_CTX *ctx, X509_ALGOR *sigalg) { - int pad_mode; - EVP_PKEY_CTX *pkctx = ctx->pctx; - if (!EVP_PKEY_CTX_get_rsa_padding(pkctx, &pad_mode)) { - return EVP_DIGEST_SIGN_ALGORITHM_ERROR; - } - if (pad_mode == RSA_PKCS1_PSS_PADDING) { - ASN1_STRING *os1 = rsa_ctx_to_pss(pkctx); - if (!os1) { - return EVP_DIGEST_SIGN_ALGORITHM_ERROR; - } - X509_ALGOR_set0(sigalg, OBJ_nid2obj(NID_rsassaPss), V_ASN1_SEQUENCE, os1); - return EVP_DIGEST_SIGN_ALGORITHM_SUCCESS; - } - - /* Other padding schemes use the default behavior. */ - return EVP_DIGEST_SIGN_ALGORITHM_DEFAULT; -} - const EVP_PKEY_ASN1_METHOD rsa_asn1_meth = { EVP_PKEY_RSA, - ASN1_PKEY_SIGPARAM_NULL, - - "RSA", + /* 1.2.840.113549.1.1.1 */ + {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01}, 9, rsa_pub_decode, rsa_pub_encode, rsa_pub_cmp, - rsa_pub_print, rsa_priv_decode, rsa_priv_encode, - rsa_priv_print, rsa_opaque, rsa_supports_digest, @@ -726,13 +194,7 @@ const EVP_PKEY_ASN1_METHOD rsa_asn1_meth = { int_rsa_size, rsa_bits, - 0,0,0,0, + 0,0,0, - rsa_sig_print, int_rsa_free, - - old_rsa_priv_decode, - - rsa_digest_verify_init_from_algorithm, - rsa_digest_sign_algorithm, }; diff --git a/Sources/BoringSSL/crypto/evp/pbkdf.c b/Sources/BoringSSL/crypto/evp/pbkdf.c index b06b922b0..1792cdc81 100644 --- a/Sources/BoringSSL/crypto/evp/pbkdf.c +++ b/Sources/BoringSSL/crypto/evp/pbkdf.c @@ -59,6 +59,8 @@ #include +#include "../internal.h" + int PKCS5_PBKDF2_HMAC(const char *password, size_t password_len, const uint8_t *salt, size_t salt_len, unsigned iterations, @@ -101,7 +103,7 @@ int PKCS5_PBKDF2_HMAC(const char *password, size_t password_len, return 0; } HMAC_CTX_cleanup(&hctx); - memcpy(p, digest_tmp, cplen); + OPENSSL_memcpy(p, digest_tmp, cplen); for (j = 1; j < iterations; j++) { if (!HMAC_CTX_copy(&hctx, &hctx_tpl)) { HMAC_CTX_cleanup(&hctx_tpl); diff --git a/Sources/BoringSSL/crypto/evp/print.c b/Sources/BoringSSL/crypto/evp/print.c new file mode 100644 index 000000000..b2e350982 --- /dev/null +++ b/Sources/BoringSSL/crypto/evp/print.c @@ -0,0 +1,520 @@ +/* ==================================================================== + * Copyright (c) 2006 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "../internal.h" +#include "../rsa/internal.h" + + +static int bn_print(BIO *bp, const char *number, const BIGNUM *num, + uint8_t *buf, int off) { + if (num == NULL) { + return 1; + } + + if (!BIO_indent(bp, off, 128)) { + return 0; + } + if (BN_is_zero(num)) { + if (BIO_printf(bp, "%s 0\n", number) <= 0) { + return 0; + } + return 1; + } + + if (BN_num_bytes(num) <= sizeof(long)) { + const char *neg = BN_is_negative(num) ? "-" : ""; + if (BIO_printf(bp, "%s %s%lu (%s0x%lx)\n", number, neg, + (unsigned long)num->d[0], neg, + (unsigned long)num->d[0]) <= 0) { + return 0; + } + } else { + buf[0] = 0; + if (BIO_printf(bp, "%s%s", number, + (BN_is_negative(num)) ? " (Negative)" : "") <= 0) { + return 0; + } + int n = BN_bn2bin(num, &buf[1]); + + if (buf[1] & 0x80) { + n++; + } else { + buf++; + } + + int i; + for (i = 0; i < n; i++) { + if ((i % 15) == 0) { + if (BIO_puts(bp, "\n") <= 0 || + !BIO_indent(bp, off + 4, 128)) { + return 0; + } + } + if (BIO_printf(bp, "%02x%s", buf[i], ((i + 1) == n) ? "" : ":") <= 0) { + return 0; + } + } + if (BIO_write(bp, "\n", 1) <= 0) { + return 0; + } + } + return 1; +} + +static void update_buflen(const BIGNUM *b, size_t *pbuflen) { + if (!b) { + return; + } + + size_t len = BN_num_bytes(b); + if (*pbuflen < len) { + *pbuflen = len; + } +} + +/* RSA keys. */ + +static int do_rsa_print(BIO *out, const RSA *rsa, int off, + int include_private) { + const char *s, *str; + uint8_t *m = NULL; + int ret = 0, mod_len = 0; + size_t buf_len = 0; + + update_buflen(rsa->n, &buf_len); + update_buflen(rsa->e, &buf_len); + + if (include_private) { + update_buflen(rsa->d, &buf_len); + update_buflen(rsa->p, &buf_len); + update_buflen(rsa->q, &buf_len); + update_buflen(rsa->dmp1, &buf_len); + update_buflen(rsa->dmq1, &buf_len); + update_buflen(rsa->iqmp, &buf_len); + + if (rsa->additional_primes != NULL) { + for (size_t i = 0; + i < sk_RSA_additional_prime_num(rsa->additional_primes); i++) { + const RSA_additional_prime *ap = + sk_RSA_additional_prime_value(rsa->additional_primes, i); + update_buflen(ap->prime, &buf_len); + update_buflen(ap->exp, &buf_len); + update_buflen(ap->coeff, &buf_len); + } + } + } + + m = (uint8_t *)OPENSSL_malloc(buf_len + 10); + if (m == NULL) { + OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE); + goto err; + } + + if (rsa->n != NULL) { + mod_len = BN_num_bits(rsa->n); + } + + if (!BIO_indent(out, off, 128)) { + goto err; + } + + if (include_private && rsa->d) { + if (BIO_printf(out, "Private-Key: (%d bit)\n", mod_len) <= 0) { + goto err; + } + str = "modulus:"; + s = "publicExponent:"; + } else { + if (BIO_printf(out, "Public-Key: (%d bit)\n", mod_len) <= 0) { + goto err; + } + str = "Modulus:"; + s = "Exponent:"; + } + if (!bn_print(out, str, rsa->n, m, off) || + !bn_print(out, s, rsa->e, m, off)) { + goto err; + } + + if (include_private) { + if (!bn_print(out, "privateExponent:", rsa->d, m, off) || + !bn_print(out, "prime1:", rsa->p, m, off) || + !bn_print(out, "prime2:", rsa->q, m, off) || + !bn_print(out, "exponent1:", rsa->dmp1, m, off) || + !bn_print(out, "exponent2:", rsa->dmq1, m, off) || + !bn_print(out, "coefficient:", rsa->iqmp, m, off)) { + goto err; + } + + if (rsa->additional_primes != NULL && + sk_RSA_additional_prime_num(rsa->additional_primes) > 0) { + if (BIO_printf(out, "otherPrimeInfos:\n") <= 0) { + goto err; + } + for (size_t i = 0; + i < sk_RSA_additional_prime_num(rsa->additional_primes); i++) { + const RSA_additional_prime *ap = + sk_RSA_additional_prime_value(rsa->additional_primes, i); + + if (BIO_printf(out, "otherPrimeInfo (prime %u):\n", + (unsigned)(i + 3)) <= 0 || + !bn_print(out, "prime:", ap->prime, m, off) || + !bn_print(out, "exponent:", ap->exp, m, off) || + !bn_print(out, "coeff:", ap->coeff, m, off)) { + goto err; + } + } + } + } + ret = 1; + +err: + OPENSSL_free(m); + return ret; +} + +static int rsa_pub_print(BIO *bp, const EVP_PKEY *pkey, int indent, + ASN1_PCTX *ctx) { + return do_rsa_print(bp, pkey->pkey.rsa, indent, 0); +} + +static int rsa_priv_print(BIO *bp, const EVP_PKEY *pkey, int indent, + ASN1_PCTX *ctx) { + return do_rsa_print(bp, pkey->pkey.rsa, indent, 1); +} + + +/* DSA keys. */ + +static int do_dsa_print(BIO *bp, const DSA *x, int off, int ptype) { + uint8_t *m = NULL; + int ret = 0; + size_t buf_len = 0; + const char *ktype = NULL; + + const BIGNUM *priv_key, *pub_key; + + priv_key = NULL; + if (ptype == 2) { + priv_key = x->priv_key; + } + + pub_key = NULL; + if (ptype > 0) { + pub_key = x->pub_key; + } + + ktype = "DSA-Parameters"; + if (ptype == 2) { + ktype = "Private-Key"; + } else if (ptype == 1) { + ktype = "Public-Key"; + } + + update_buflen(x->p, &buf_len); + update_buflen(x->q, &buf_len); + update_buflen(x->g, &buf_len); + update_buflen(priv_key, &buf_len); + update_buflen(pub_key, &buf_len); + + m = (uint8_t *)OPENSSL_malloc(buf_len + 10); + if (m == NULL) { + OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE); + goto err; + } + + if (priv_key) { + if (!BIO_indent(bp, off, 128) || + BIO_printf(bp, "%s: (%d bit)\n", ktype, BN_num_bits(x->p)) <= 0) { + goto err; + } + } + + if (!bn_print(bp, "priv:", priv_key, m, off) || + !bn_print(bp, "pub: ", pub_key, m, off) || + !bn_print(bp, "P: ", x->p, m, off) || + !bn_print(bp, "Q: ", x->q, m, off) || + !bn_print(bp, "G: ", x->g, m, off)) { + goto err; + } + ret = 1; + +err: + OPENSSL_free(m); + return ret; +} + +static int dsa_param_print(BIO *bp, const EVP_PKEY *pkey, int indent, + ASN1_PCTX *ctx) { + return do_dsa_print(bp, pkey->pkey.dsa, indent, 0); +} + +static int dsa_pub_print(BIO *bp, const EVP_PKEY *pkey, int indent, + ASN1_PCTX *ctx) { + return do_dsa_print(bp, pkey->pkey.dsa, indent, 1); +} + +static int dsa_priv_print(BIO *bp, const EVP_PKEY *pkey, int indent, + ASN1_PCTX *ctx) { + return do_dsa_print(bp, pkey->pkey.dsa, indent, 2); +} + + +/* EC keys. */ + +static int do_EC_KEY_print(BIO *bp, const EC_KEY *x, int off, int ktype) { + uint8_t *buffer = NULL; + const char *ecstr; + size_t buf_len = 0, i; + int ret = 0, reason = ERR_R_BIO_LIB; + BIGNUM *order = NULL; + BN_CTX *ctx = NULL; + const EC_GROUP *group; + const EC_POINT *public_key; + const BIGNUM *priv_key; + uint8_t *pub_key_bytes = NULL; + size_t pub_key_bytes_len = 0; + + if (x == NULL || (group = EC_KEY_get0_group(x)) == NULL) { + reason = ERR_R_PASSED_NULL_PARAMETER; + goto err; + } + + ctx = BN_CTX_new(); + if (ctx == NULL) { + reason = ERR_R_MALLOC_FAILURE; + goto err; + } + + if (ktype > 0) { + public_key = EC_KEY_get0_public_key(x); + if (public_key != NULL) { + pub_key_bytes_len = EC_POINT_point2oct( + group, public_key, EC_KEY_get_conv_form(x), NULL, 0, ctx); + if (pub_key_bytes_len == 0) { + reason = ERR_R_MALLOC_FAILURE; + goto err; + } + pub_key_bytes = OPENSSL_malloc(pub_key_bytes_len); + if (pub_key_bytes == NULL) { + reason = ERR_R_MALLOC_FAILURE; + goto err; + } + pub_key_bytes_len = + EC_POINT_point2oct(group, public_key, EC_KEY_get_conv_form(x), + pub_key_bytes, pub_key_bytes_len, ctx); + if (pub_key_bytes_len == 0) { + reason = ERR_R_MALLOC_FAILURE; + goto err; + } + buf_len = pub_key_bytes_len; + } + } + + if (ktype == 2) { + priv_key = EC_KEY_get0_private_key(x); + if (priv_key && (i = (size_t)BN_num_bytes(priv_key)) > buf_len) { + buf_len = i; + } + } else { + priv_key = NULL; + } + + if (ktype > 0) { + buf_len += 10; + if ((buffer = OPENSSL_malloc(buf_len)) == NULL) { + reason = ERR_R_MALLOC_FAILURE; + goto err; + } + } + if (ktype == 2) { + ecstr = "Private-Key"; + } else if (ktype == 1) { + ecstr = "Public-Key"; + } else { + ecstr = "ECDSA-Parameters"; + } + + if (!BIO_indent(bp, off, 128)) { + goto err; + } + order = BN_new(); + if (order == NULL || !EC_GROUP_get_order(group, order, NULL) || + BIO_printf(bp, "%s: (%d bit)\n", ecstr, BN_num_bits(order)) <= 0) { + goto err; + } + + if ((priv_key != NULL) && + !bn_print(bp, "priv:", priv_key, buffer, off)) { + goto err; + } + if (pub_key_bytes != NULL) { + BIO_hexdump(bp, pub_key_bytes, pub_key_bytes_len, off); + } + /* TODO(fork): implement */ + /* + if (!ECPKParameters_print(bp, group, off)) + goto err; */ + ret = 1; + +err: + if (!ret) { + OPENSSL_PUT_ERROR(EVP, reason); + } + OPENSSL_free(pub_key_bytes); + BN_free(order); + BN_CTX_free(ctx); + OPENSSL_free(buffer); + return ret; +} + +static int eckey_param_print(BIO *bp, const EVP_PKEY *pkey, int indent, + ASN1_PCTX *ctx) { + return do_EC_KEY_print(bp, pkey->pkey.ec, indent, 0); +} + +static int eckey_pub_print(BIO *bp, const EVP_PKEY *pkey, int indent, + ASN1_PCTX *ctx) { + return do_EC_KEY_print(bp, pkey->pkey.ec, indent, 1); +} + + +static int eckey_priv_print(BIO *bp, const EVP_PKEY *pkey, int indent, + ASN1_PCTX *ctx) { + return do_EC_KEY_print(bp, pkey->pkey.ec, indent, 2); +} + + +typedef struct { + int type; + int (*pub_print)(BIO *out, const EVP_PKEY *pkey, int indent, ASN1_PCTX *pctx); + int (*priv_print)(BIO *out, const EVP_PKEY *pkey, int indent, + ASN1_PCTX *pctx); + int (*param_print)(BIO *out, const EVP_PKEY *pkey, int indent, + ASN1_PCTX *pctx); +} EVP_PKEY_PRINT_METHOD; + +static EVP_PKEY_PRINT_METHOD kPrintMethods[] = { + { + EVP_PKEY_RSA, + rsa_pub_print, + rsa_priv_print, + NULL /* param_print */, + }, + { + EVP_PKEY_DSA, + dsa_pub_print, + dsa_priv_print, + dsa_param_print, + }, + { + EVP_PKEY_EC, + eckey_pub_print, + eckey_priv_print, + eckey_param_print, + }, +}; + +static size_t kPrintMethodsLen = OPENSSL_ARRAY_SIZE(kPrintMethods); + +static EVP_PKEY_PRINT_METHOD *find_method(int type) { + for (size_t i = 0; i < kPrintMethodsLen; i++) { + if (kPrintMethods[i].type == type) { + return &kPrintMethods[i]; + } + } + return NULL; +} + +static int print_unsupported(BIO *out, const EVP_PKEY *pkey, int indent, + const char *kstr) { + BIO_indent(out, indent, 128); + BIO_printf(out, "%s algorithm unsupported\n", kstr); + return 1; +} + +int EVP_PKEY_print_public(BIO *out, const EVP_PKEY *pkey, int indent, + ASN1_PCTX *pctx) { + EVP_PKEY_PRINT_METHOD *method = find_method(pkey->type); + if (method != NULL && method->pub_print != NULL) { + return method->pub_print(out, pkey, indent, pctx); + } + return print_unsupported(out, pkey, indent, "Public Key"); +} + +int EVP_PKEY_print_private(BIO *out, const EVP_PKEY *pkey, int indent, + ASN1_PCTX *pctx) { + EVP_PKEY_PRINT_METHOD *method = find_method(pkey->type); + if (method != NULL && method->priv_print != NULL) { + return method->priv_print(out, pkey, indent, pctx); + } + return print_unsupported(out, pkey, indent, "Private Key"); +} + +int EVP_PKEY_print_params(BIO *out, const EVP_PKEY *pkey, int indent, + ASN1_PCTX *pctx) { + EVP_PKEY_PRINT_METHOD *method = find_method(pkey->type); + if (method != NULL && method->param_print != NULL) { + return method->param_print(out, pkey, indent, pctx); + } + return print_unsupported(out, pkey, indent, "Parameters"); +} diff --git a/Sources/BoringSSL/crypto/ex_data.c b/Sources/BoringSSL/crypto/ex_data.c index 8fa124029..528651331 100644 --- a/Sources/BoringSSL/crypto/ex_data.c +++ b/Sources/BoringSSL/crypto/ex_data.c @@ -163,7 +163,7 @@ int CRYPTO_get_ex_new_index(CRYPTO_EX_DATA_CLASS *ex_data_class, int *out_index, ret = 1; err: - CRYPTO_STATIC_MUTEX_unlock(&ex_data_class->lock); + CRYPTO_STATIC_MUTEX_unlock_write(&ex_data_class->lock); return ret; } @@ -217,7 +217,7 @@ static int get_func_pointers(STACK_OF(CRYPTO_EX_DATA_FUNCS) **out, if (n > 0) { *out = sk_CRYPTO_EX_DATA_FUNCS_dup(ex_data_class->meth); } - CRYPTO_STATIC_MUTEX_unlock(&ex_data_class->lock); + CRYPTO_STATIC_MUTEX_unlock_read(&ex_data_class->lock); if (n > 0 && *out == NULL) { OPENSSL_PUT_ERROR(CRYPTO, ERR_R_MALLOC_FAILURE); @@ -244,8 +244,7 @@ int CRYPTO_dup_ex_data(CRYPTO_EX_DATA_CLASS *ex_data_class, CRYPTO_EX_DATA *to, return 0; } - size_t i; - for (i = 0; i < sk_CRYPTO_EX_DATA_FUNCS_num(func_pointers); i++) { + for (size_t i = 0; i < sk_CRYPTO_EX_DATA_FUNCS_num(func_pointers); i++) { CRYPTO_EX_DATA_FUNCS *func_pointer = sk_CRYPTO_EX_DATA_FUNCS_value(func_pointers, i); void *ptr = CRYPTO_get_ex_data(from, i + ex_data_class->num_reserved); @@ -274,8 +273,7 @@ void CRYPTO_free_ex_data(CRYPTO_EX_DATA_CLASS *ex_data_class, void *obj, return; } - size_t i; - for (i = 0; i < sk_CRYPTO_EX_DATA_FUNCS_num(func_pointers); i++) { + for (size_t i = 0; i < sk_CRYPTO_EX_DATA_FUNCS_num(func_pointers); i++) { CRYPTO_EX_DATA_FUNCS *func_pointer = sk_CRYPTO_EX_DATA_FUNCS_value(func_pointers, i); if (func_pointer->free_func) { diff --git a/Sources/BoringSSL/crypto/hkdf/hkdf.c b/Sources/BoringSSL/crypto/hkdf/hkdf.c index f9cdcb0b2..ae43b69fe 100644 --- a/Sources/BoringSSL/crypto/hkdf/hkdf.c +++ b/Sources/BoringSSL/crypto/hkdf/hkdf.c @@ -20,23 +20,53 @@ #include #include +#include "../internal.h" -int HKDF(uint8_t *out_key, size_t out_len, - const EVP_MD *digest, - const uint8_t *secret, size_t secret_len, - const uint8_t *salt, size_t salt_len, - const uint8_t *info, size_t info_len) { + +int HKDF(uint8_t *out_key, size_t out_len, const EVP_MD *digest, + const uint8_t *secret, size_t secret_len, const uint8_t *salt, + size_t salt_len, const uint8_t *info, size_t info_len) { + /* https://tools.ietf.org/html/rfc5869#section-2 */ + uint8_t prk[EVP_MAX_MD_SIZE]; + size_t prk_len; + + if (!HKDF_extract(prk, &prk_len, digest, secret, secret_len, salt, + salt_len) || + !HKDF_expand(out_key, out_len, digest, prk, prk_len, info, info_len)) { + return 0; + } + + return 1; +} + +int HKDF_extract(uint8_t *out_key, size_t *out_len, const EVP_MD *digest, + const uint8_t *secret, size_t secret_len, const uint8_t *salt, + size_t salt_len) { /* https://tools.ietf.org/html/rfc5869#section-2.2 */ + + /* If salt is not given, HashLength zeros are used. However, HMAC does that + * internally already so we can ignore it.*/ + unsigned len; + if (HMAC(digest, salt, salt_len, secret, secret_len, out_key, &len) == NULL) { + OPENSSL_PUT_ERROR(HKDF, ERR_R_HMAC_LIB); + return 0; + } + *out_len = len; + assert(*out_len == EVP_MD_size(digest)); + return 1; +} + +int HKDF_expand(uint8_t *out_key, size_t out_len, const EVP_MD *digest, + const uint8_t *prk, size_t prk_len, const uint8_t *info, + size_t info_len) { + /* https://tools.ietf.org/html/rfc5869#section-2.3 */ const size_t digest_len = EVP_MD_size(digest); - uint8_t prk[EVP_MAX_MD_SIZE], previous[EVP_MAX_MD_SIZE]; + uint8_t previous[EVP_MAX_MD_SIZE]; size_t n, done = 0; - unsigned i, prk_len; + unsigned i; int ret = 0; HMAC_CTX hmac; - /* If salt is not given, HashLength zeros are used. However, HMAC does that - * internally already so we can ignore it.*/ - /* Expand key material to desired length. */ n = (out_len + digest_len - 1) / digest_len; if (out_len + digest_len < out_len || n > 255) { @@ -45,13 +75,6 @@ int HKDF(uint8_t *out_key, size_t out_len, } HMAC_CTX_init(&hmac); - - /* Extract input keying material into pseudorandom key |prk|. */ - if (HMAC(digest, salt, salt_len, secret, secret_len, prk, &prk_len) == NULL) { - goto out; - } - assert(prk_len == digest_len); - if (!HMAC_Init_ex(&hmac, prk, prk_len, digest, NULL)) { goto out; } @@ -74,7 +97,7 @@ int HKDF(uint8_t *out_key, size_t out_len, if (done + todo > out_len) { todo = out_len - done; } - memcpy(out_key + done, previous, todo); + OPENSSL_memcpy(out_key + done, previous, todo); done += todo; } diff --git a/Sources/BoringSSL/crypto/hmac/hmac.c b/Sources/BoringSSL/crypto/hmac/hmac.c index be2dccec2..a2526678e 100644 --- a/Sources/BoringSSL/crypto/hmac/hmac.c +++ b/Sources/BoringSSL/crypto/hmac/hmac.c @@ -59,8 +59,11 @@ #include #include +#include #include +#include "../internal.h" + uint8_t *HMAC(const EVP_MD *evp_md, const void *key, size_t key_len, const uint8_t *data, size_t data_len, uint8_t *out, @@ -114,9 +117,8 @@ int HMAC_Init_ex(HMAC_CTX *ctx, const void *key, size_t key_len, * exist callers which intend the latter, but the former is an awkward edge * case. Fix to API to avoid this. */ if (md != ctx->md || key != NULL) { - size_t i; - uint8_t pad[HMAC_MAX_MD_CBLOCK]; - uint8_t key_block[HMAC_MAX_MD_CBLOCK]; + uint8_t pad[EVP_MAX_MD_BLOCK_SIZE]; + uint8_t key_block[EVP_MAX_MD_BLOCK_SIZE]; unsigned key_block_len; size_t block_size = EVP_MD_block_size(md); @@ -130,15 +132,15 @@ int HMAC_Init_ex(HMAC_CTX *ctx, const void *key, size_t key_len, } } else { assert(key_len <= sizeof(key_block)); - memcpy(key_block, key, key_len); + OPENSSL_memcpy(key_block, key, key_len); key_block_len = (unsigned)key_len; } /* Keys are then padded with zeros. */ - if (key_block_len != HMAC_MAX_MD_CBLOCK) { - memset(&key_block[key_block_len], 0, sizeof(key_block) - key_block_len); + if (key_block_len != EVP_MAX_MD_BLOCK_SIZE) { + OPENSSL_memset(&key_block[key_block_len], 0, sizeof(key_block) - key_block_len); } - for (i = 0; i < HMAC_MAX_MD_CBLOCK; i++) { + for (size_t i = 0; i < EVP_MAX_MD_BLOCK_SIZE; i++) { pad[i] = 0x36 ^ key_block[i]; } if (!EVP_DigestInit_ex(&ctx->i_ctx, md, impl) || @@ -146,7 +148,7 @@ int HMAC_Init_ex(HMAC_CTX *ctx, const void *key, size_t key_len, return 0; } - for (i = 0; i < HMAC_MAX_MD_CBLOCK; i++) { + for (size_t i = 0; i < EVP_MAX_MD_BLOCK_SIZE; i++) { pad[i] = 0x5c ^ key_block[i]; } if (!EVP_DigestInit_ex(&ctx->o_ctx, md, impl) || diff --git a/Sources/BoringSSL/crypto/internal.h b/Sources/BoringSSL/crypto/internal.h index 2229e19eb..272495676 100644 --- a/Sources/BoringSSL/crypto/internal.h +++ b/Sources/BoringSSL/crypto/internal.h @@ -112,6 +112,8 @@ #include #include +#include + #if defined(_MSC_VER) #if !defined(__cplusplus) || _MSC_VER < 1900 #define alignas(x) __declspec(align(x)) @@ -121,78 +123,51 @@ #include #endif -#if defined(OPENSSL_NO_THREADS) -#elif defined(OPENSSL_WINDOWS) -#pragma warning(push, 3) -#include -#pragma warning(pop) -#else +#if !defined(OPENSSL_NO_THREADS) && \ + (!defined(OPENSSL_WINDOWS) || defined(__MINGW32__)) #include +#define OPENSSL_PTHREADS #endif -#if defined(__cplusplus) -extern "C" { -#endif - - -/* MSVC's C4701 warning about the use of *potentially*--as opposed to - * *definitely*--uninitialized values sometimes has false positives. Usually - * the false positives can and should be worked around by simplifying the - * control flow. When that is not practical, annotate the function containing - * the code that triggers the warning with - * OPENSSL_SUPPRESS_POTENTIALLY_UNINITIALIZED_WARNINGS after its parameters: - * - * void f() OPENSSL_SUPPRESS_POTENTIALLY_UNINITIALIZED_WARNINGS { - * ... - * } - * - * Note that MSVC's control flow analysis seems to operate on a whole-function - * basis, so the annotation must be placed on the entire function, not just a - * block within the function. */ -#if defined(_MSC_VER) -#define OPENSSL_SUPPRESS_POTENTIALLY_UNINITIALIZED_WARNINGS \ - __pragma(warning(suppress:4701)) -#else -#define OPENSSL_SUPPRESS_POTENTIALLY_UNINITIALIZED_WARNINGS +#if !defined(OPENSSL_NO_THREADS) && !defined(OPENSSL_PTHREADS) && \ + defined(OPENSSL_WINDOWS) +#define OPENSSL_WINDOWS_THREADS +OPENSSL_MSVC_PRAGMA(warning(push, 3)) +#include +OPENSSL_MSVC_PRAGMA(warning(pop)) #endif -/* MSVC will sometimes correctly detect unreachable code and issue a warning, - * which breaks the build since we treat errors as warnings, in some rare cases - * where we want to allow the dead code to continue to exist. In these - * situations, annotate the function containing the unreachable code with - * OPENSSL_SUPPRESS_UNREACHABLE_CODE_WARNINGS after its parameters: - * - * void f() OPENSSL_SUPPRESS_UNREACHABLE_CODE_WARNINGS { - * ... - * } - * - * Note that MSVC's reachability analysis seems to operate on a whole-function - * basis, so the annotation must be placed on the entire function, not just a - * block within the function. */ -#if defined(_MSC_VER) -#define OPENSSL_SUPPRESS_UNREACHABLE_CODE_WARNINGS \ - __pragma(warning(suppress:4702)) -#else -#define OPENSSL_SUPPRESS_UNREACHABLE_CODE_WARNINGS +#if defined(__cplusplus) +extern "C" { #endif #if defined(OPENSSL_X86) || defined(OPENSSL_X86_64) || defined(OPENSSL_ARM) || \ - defined(OPENSSL_AARCH64) -/* OPENSSL_cpuid_setup initializes OPENSSL_ia32cap_P. */ + defined(OPENSSL_AARCH64) || defined(OPENSSL_PPC64LE) +/* OPENSSL_cpuid_setup initializes the platform-specific feature cache. */ void OPENSSL_cpuid_setup(void); #endif -#if !defined(inline) -#define inline __inline -#endif - #if !defined(_MSC_VER) && defined(OPENSSL_64_BIT) typedef __int128_t int128_t; typedef __uint128_t uint128_t; #endif +#define OPENSSL_ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0])) + +/* buffers_alias returns one if |a| and |b| alias and zero otherwise. */ +static inline int buffers_alias(const uint8_t *a, size_t a_len, + const uint8_t *b, size_t b_len) { + /* Cast |a| and |b| to integers. In C, pointer comparisons between unrelated + * objects are undefined whereas pointer to integer conversions are merely + * implementation-defined. We assume the implementation defined it in a sane + * way. */ + uintptr_t a_u = (uintptr_t)a; + uintptr_t b_u = (uintptr_t)b; + return a_u + a_len > b_u && b_u + b_len > a_u; +} + /* Constant-time utility functions. * @@ -339,12 +314,14 @@ static inline int constant_time_select_int(unsigned int mask, int a, int b) { #if defined(OPENSSL_NO_THREADS) typedef uint32_t CRYPTO_once_t; #define CRYPTO_ONCE_INIT 0 -#elif defined(OPENSSL_WINDOWS) -typedef volatile LONG CRYPTO_once_t; -#define CRYPTO_ONCE_INIT 0 -#else +#elif defined(OPENSSL_WINDOWS_THREADS) +typedef INIT_ONCE CRYPTO_once_t; +#define CRYPTO_ONCE_INIT INIT_ONCE_STATIC_INIT +#elif defined(OPENSSL_PTHREADS) typedef pthread_once_t CRYPTO_once_t; #define CRYPTO_ONCE_INIT PTHREAD_ONCE_INIT +#else +#error "Unknown threading library" #endif /* CRYPTO_once calls |init| exactly once per process. This is thread-safe: if @@ -387,27 +364,26 @@ OPENSSL_EXPORT int CRYPTO_refcount_dec_and_test_zero(CRYPTO_refcount_t *count); * |CRYPTO_STATIC_MUTEX_INIT|. * * |CRYPTO_MUTEX| can appear in public structures and so is defined in - * thread.h. - * - * The global lock is a different type because there's no static initialiser - * value on Windows for locks, so global locks have to be coupled with a - * |CRYPTO_once_t| to ensure that the lock is setup before use. This is done - * automatically by |CRYPTO_STATIC_MUTEX_lock_*|. */ + * thread.h as a structure large enough to fit the real type. The global lock is + * a different type so it may be initialized with platform initializer macros.*/ #if defined(OPENSSL_NO_THREADS) -struct CRYPTO_STATIC_MUTEX {}; -#define CRYPTO_STATIC_MUTEX_INIT {} -#elif defined(OPENSSL_WINDOWS) struct CRYPTO_STATIC_MUTEX { - CRYPTO_once_t once; - CRITICAL_SECTION lock; + char padding; /* Empty structs have different sizes in C and C++. */ }; -#define CRYPTO_STATIC_MUTEX_INIT { CRYPTO_ONCE_INIT, { 0 } } -#else +#define CRYPTO_STATIC_MUTEX_INIT { 0 } +#elif defined(OPENSSL_WINDOWS_THREADS) +struct CRYPTO_STATIC_MUTEX { + SRWLOCK lock; +}; +#define CRYPTO_STATIC_MUTEX_INIT { SRWLOCK_INIT } +#elif defined(OPENSSL_PTHREADS) struct CRYPTO_STATIC_MUTEX { pthread_rwlock_t lock; }; #define CRYPTO_STATIC_MUTEX_INIT { PTHREAD_RWLOCK_INITIALIZER } +#else +#error "Unknown threading library" #endif /* CRYPTO_MUTEX_init initialises |lock|. If |lock| is a static variable, use a @@ -415,16 +391,18 @@ struct CRYPTO_STATIC_MUTEX { OPENSSL_EXPORT void CRYPTO_MUTEX_init(CRYPTO_MUTEX *lock); /* CRYPTO_MUTEX_lock_read locks |lock| such that other threads may also have a - * read lock, but none may have a write lock. (On Windows, read locks are - * actually fully exclusive.) */ + * read lock, but none may have a write lock. */ OPENSSL_EXPORT void CRYPTO_MUTEX_lock_read(CRYPTO_MUTEX *lock); /* CRYPTO_MUTEX_lock_write locks |lock| such that no other thread has any type * of lock on it. */ OPENSSL_EXPORT void CRYPTO_MUTEX_lock_write(CRYPTO_MUTEX *lock); -/* CRYPTO_MUTEX_unlock unlocks |lock|. */ -OPENSSL_EXPORT void CRYPTO_MUTEX_unlock(CRYPTO_MUTEX *lock); +/* CRYPTO_MUTEX_unlock_read unlocks |lock| for reading. */ +OPENSSL_EXPORT void CRYPTO_MUTEX_unlock_read(CRYPTO_MUTEX *lock); + +/* CRYPTO_MUTEX_unlock_write unlocks |lock| for writing. */ +OPENSSL_EXPORT void CRYPTO_MUTEX_unlock_write(CRYPTO_MUTEX *lock); /* CRYPTO_MUTEX_cleanup releases all resources held by |lock|. */ OPENSSL_EXPORT void CRYPTO_MUTEX_cleanup(CRYPTO_MUTEX *lock); @@ -443,8 +421,12 @@ OPENSSL_EXPORT void CRYPTO_STATIC_MUTEX_lock_read( OPENSSL_EXPORT void CRYPTO_STATIC_MUTEX_lock_write( struct CRYPTO_STATIC_MUTEX *lock); -/* CRYPTO_STATIC_MUTEX_unlock unlocks |lock|. */ -OPENSSL_EXPORT void CRYPTO_STATIC_MUTEX_unlock( +/* CRYPTO_STATIC_MUTEX_unlock_read unlocks |lock| for reading. */ +OPENSSL_EXPORT void CRYPTO_STATIC_MUTEX_unlock_read( + struct CRYPTO_STATIC_MUTEX *lock); + +/* CRYPTO_STATIC_MUTEX_unlock_write unlocks |lock| for writing. */ +OPENSSL_EXPORT void CRYPTO_STATIC_MUTEX_unlock_write( struct CRYPTO_STATIC_MUTEX *lock); @@ -540,6 +522,85 @@ OPENSSL_EXPORT void CRYPTO_free_ex_data(CRYPTO_EX_DATA_CLASS *ex_data_class, void *obj, CRYPTO_EX_DATA *ad); +/* Language bug workarounds. + * + * Most C standard library functions are undefined if passed NULL, even when the + * corresponding length is zero. This gives them (and, in turn, all functions + * which call them) surprising behavior on empty arrays. Some compilers will + * miscompile code due to this rule. See also + * https://www.imperialviolet.org/2016/06/26/nonnull.html + * + * These wrapper functions behave the same as the corresponding C standard + * functions, but behave as expected when passed NULL if the length is zero. + * + * Note |OPENSSL_memcmp| is a different function from |CRYPTO_memcmp|. */ + +/* C++ defines |memchr| as a const-correct overload. */ +#if defined(__cplusplus) +extern "C++" { + +static inline const void *OPENSSL_memchr(const void *s, int c, size_t n) { + if (n == 0) { + return NULL; + } + + return memchr(s, c, n); +} + +static inline void *OPENSSL_memchr(void *s, int c, size_t n) { + if (n == 0) { + return NULL; + } + + return memchr(s, c, n); +} + +} /* extern "C++" */ +#else /* __cplusplus */ + +static inline void *OPENSSL_memchr(const void *s, int c, size_t n) { + if (n == 0) { + return NULL; + } + + return memchr(s, c, n); +} + +#endif /* __cplusplus */ + +static inline int OPENSSL_memcmp(const void *s1, const void *s2, size_t n) { + if (n == 0) { + return 0; + } + + return memcmp(s1, s2, n); +} + +static inline void *OPENSSL_memcpy(void *dst, const void *src, size_t n) { + if (n == 0) { + return dst; + } + + return memcpy(dst, src, n); +} + +static inline void *OPENSSL_memmove(void *dst, const void *src, size_t n) { + if (n == 0) { + return dst; + } + + return memmove(dst, src, n); +} + +static inline void *OPENSSL_memset(void *dst, int c, size_t n) { + if (n == 0) { + return dst; + } + + return memset(dst, c, n); +} + + #if defined(__cplusplus) } /* extern C */ #endif diff --git a/Sources/BoringSSL/crypto/lhash/lhash.c b/Sources/BoringSSL/crypto/lhash/lhash.c index 257900eab..27960d98b 100644 --- a/Sources/BoringSSL/crypto/lhash/lhash.c +++ b/Sources/BoringSSL/crypto/lhash/lhash.c @@ -62,6 +62,9 @@ #include +#include "../internal.h" + + /* kMinNumBuckets is the minimum size of the buckets array in an |_LHASH|. */ static const size_t kMinNumBuckets = 16; @@ -71,13 +74,11 @@ static const size_t kMaxAverageChainLength = 2; static const size_t kMinAverageChainLength = 1; _LHASH *lh_new(lhash_hash_func hash, lhash_cmp_func comp) { - _LHASH *ret; - - ret = OPENSSL_malloc(sizeof(_LHASH)); + _LHASH *ret = OPENSSL_malloc(sizeof(_LHASH)); if (ret == NULL) { return NULL; } - memset(ret, 0, sizeof(_LHASH)); + OPENSSL_memset(ret, 0, sizeof(_LHASH)); ret->num_buckets = kMinNumBuckets; ret->buckets = OPENSSL_malloc(sizeof(LHASH_ITEM *) * ret->num_buckets); @@ -85,30 +86,21 @@ _LHASH *lh_new(lhash_hash_func hash, lhash_cmp_func comp) { OPENSSL_free(ret); return NULL; } - memset(ret->buckets, 0, sizeof(LHASH_ITEM *) * ret->num_buckets); + OPENSSL_memset(ret->buckets, 0, sizeof(LHASH_ITEM *) * ret->num_buckets); ret->comp = comp; - if (ret->comp == NULL) { - ret->comp = (lhash_cmp_func) strcmp; - } ret->hash = hash; - if (ret->hash == NULL) { - ret->hash = (lhash_hash_func) lh_strhash; - } - return ret; } void lh_free(_LHASH *lh) { - size_t i; - LHASH_ITEM *n, *next; - if (lh == NULL) { return; } - for (i = 0; i < lh->num_buckets; i++) { - for (n = lh->buckets[i]; n != NULL; n = next) { + for (size_t i = 0; i < lh->num_buckets; i++) { + LHASH_ITEM *next; + for (LHASH_ITEM *n = lh->buckets[i]; n != NULL; n = next) { next = n->next; OPENSSL_free(n); } @@ -175,7 +167,7 @@ static void lh_rebucket(_LHASH *lh, const size_t new_num_buckets) { if (new_buckets == NULL) { return; } - memset(new_buckets, 0, alloc_size); + OPENSSL_memset(new_buckets, 0, alloc_size); for (i = 0; i < lh->num_buckets; i++) { for (cur = lh->buckets[i]; cur != NULL; cur = next) { @@ -277,9 +269,6 @@ void *lh_delete(_LHASH *lh, const void *data) { static void lh_doall_internal(_LHASH *lh, void (*no_arg_func)(void *), void (*arg_func)(void *, void *), void *arg) { - size_t i; - LHASH_ITEM *cur, *next; - if (lh == NULL) { return; } @@ -289,8 +278,9 @@ static void lh_doall_internal(_LHASH *lh, void (*no_arg_func)(void *), lh->callback_depth++; } - for (i = 0; i < lh->num_buckets; i++) { - for (cur = lh->buckets[i]; cur != NULL; cur = next) { + for (size_t i = 0; i < lh->num_buckets; i++) { + LHASH_ITEM *next; + for (LHASH_ITEM *cur = lh->buckets[i]; cur != NULL; cur = next) { next = cur->next; if (arg_func) { arg_func(cur->data, arg); diff --git a/Sources/BoringSSL/crypto/md4/md4.c b/Sources/BoringSSL/crypto/md4/md4.c index 86a540b4e..0046c217f 100644 --- a/Sources/BoringSSL/crypto/md4/md4.c +++ b/Sources/BoringSSL/crypto/md4/md4.c @@ -59,11 +59,22 @@ #include #include +#include "../internal.h" + + +uint8_t *MD4(const uint8_t *data, size_t len, uint8_t *out) { + MD4_CTX ctx; + MD4_Init(&ctx); + MD4_Update(&ctx, data, len); + MD4_Final(out, &ctx); + + return out; +} /* Implemented from RFC1186 The MD4 Message-Digest Algorithm. */ int MD4_Init(MD4_CTX *md4) { - memset(md4, 0, sizeof(MD4_CTX)); + OPENSSL_memset(md4, 0, sizeof(MD4_CTX)); md4->h[0] = 0x67452301UL; md4->h[1] = 0xefcdab89UL; md4->h[2] = 0x98badcfeUL; @@ -105,23 +116,23 @@ void md4_block_data_order(uint32_t *state, const uint8_t *data, size_t num); #define ROTATE(a, n) (((a) << (n)) | ((a) >> (32 - (n)))) -#define R0(a, b, c, d, k, s, t) \ - { \ - a += ((k) + (t)+F((b), (c), (d))); \ - a = ROTATE(a, s); \ - }; - -#define R1(a, b, c, d, k, s, t) \ - { \ - a += ((k) + (t)+G((b), (c), (d))); \ - a = ROTATE(a, s); \ - }; - -#define R2(a, b, c, d, k, s, t) \ - { \ - a += ((k) + (t)+H((b), (c), (d))); \ - a = ROTATE(a, s); \ - }; +#define R0(a, b, c, d, k, s, t) \ + do { \ + (a) += ((k) + (t) + F((b), (c), (d))); \ + (a) = ROTATE(a, s); \ + } while (0) + +#define R1(a, b, c, d, k, s, t) \ + do { \ + (a) += ((k) + (t) + G((b), (c), (d))); \ + (a) = ROTATE(a, s); \ + } while (0) + +#define R2(a, b, c, d, k, s, t) \ + do { \ + (a) += ((k) + (t) + H((b), (c), (d))); \ + (a) = ROTATE(a, s); \ + } while (0) void md4_block_data_order(uint32_t *state, const uint8_t *data, size_t num) { uint32_t A, B, C, D, l; diff --git a/Sources/BoringSSL/crypto/md5/md5.c b/Sources/BoringSSL/crypto/md5/md5.c index 66483b847..7712f4757 100644 --- a/Sources/BoringSSL/crypto/md5/md5.c +++ b/Sources/BoringSSL/crypto/md5/md5.c @@ -60,6 +60,8 @@ #include +#include "../internal.h" + uint8_t *MD5(const uint8_t *data, size_t len, uint8_t *out) { MD5_CTX ctx; @@ -78,7 +80,7 @@ uint8_t *MD5(const uint8_t *data, size_t len, uint8_t *out) { } int MD5_Init(MD5_CTX *md5) { - memset(md5, 0, sizeof(MD5_CTX)); + OPENSSL_memset(md5, 0, sizeof(MD5_CTX)); md5->h[0] = 0x67452301UL; md5->h[1] = 0xefcdab89UL; md5->h[2] = 0x98badcfeUL; @@ -122,32 +124,40 @@ void md5_block_data_order(uint32_t *state, const uint8_t *data, size_t num); * simplified to the code below. Wei attributes these optimizations * to Peter Gutmann's SHS code, and he attributes it to Rich Schroeppel. */ -#define F(b,c,d) ((((c) ^ (d)) & (b)) ^ (d)) -#define G(b,c,d) ((((b) ^ (c)) & (d)) ^ (c)) -#define H(b,c,d) ((b) ^ (c) ^ (d)) -#define I(b,c,d) (((~(d)) | (b)) ^ (c)) +#define F(b, c, d) ((((c) ^ (d)) & (b)) ^ (d)) +#define G(b, c, d) ((((b) ^ (c)) & (d)) ^ (c)) +#define H(b, c, d) ((b) ^ (c) ^ (d)) +#define I(b, c, d) (((~(d)) | (b)) ^ (c)) #define ROTATE(a, n) (((a) << (n)) | ((a) >> (32 - (n)))) -#define R0(a,b,c,d,k,s,t) { \ - a+=((k)+(t)+F((b),(c),(d))); \ - a=ROTATE(a,s); \ - a+=b; };\ +#define R0(a, b, c, d, k, s, t) \ + do { \ + (a) += ((k) + (t) + F((b), (c), (d))); \ + (a) = ROTATE(a, s); \ + (a) += (b); \ + } while (0) -#define R1(a,b,c,d,k,s,t) { \ - a+=((k)+(t)+G((b),(c),(d))); \ - a=ROTATE(a,s); \ - a+=b; }; +#define R1(a, b, c, d, k, s, t) \ + do { \ + (a) += ((k) + (t) + G((b), (c), (d))); \ + (a) = ROTATE(a, s); \ + (a) += (b); \ + } while (0) -#define R2(a,b,c,d,k,s,t) { \ - a+=((k)+(t)+H((b),(c),(d))); \ - a=ROTATE(a,s); \ - a+=b; }; +#define R2(a, b, c, d, k, s, t) \ + do { \ + (a) += ((k) + (t) + H((b), (c), (d))); \ + (a) = ROTATE(a, s); \ + (a) += (b); \ + } while (0) -#define R3(a,b,c,d,k,s,t) { \ - a+=((k)+(t)+I((b),(c),(d))); \ - a=ROTATE(a,s); \ - a+=b; }; +#define R3(a, b, c, d, k, s, t) \ + do { \ + (a) += ((k) + (t) + I((b), (c), (d))); \ + (a) = ROTATE(a, s); \ + (a) += (b); \ + } while (0) #ifndef md5_block_data_order #ifdef X diff --git a/Sources/BoringSSL/crypto/mem.c b/Sources/BoringSSL/crypto/mem.c index df8e0e337..390ca2e73 100644 --- a/Sources/BoringSSL/crypto/mem.c +++ b/Sources/BoringSSL/crypto/mem.c @@ -66,17 +66,17 @@ #include #if defined(OPENSSL_WINDOWS) -#pragma warning(push, 3) +OPENSSL_MSVC_PRAGMA(warning(push, 3)) #include -#pragma warning(pop) +OPENSSL_MSVC_PRAGMA(warning(pop)) #else #include #endif +#include "internal.h" -void *OPENSSL_realloc_clean(void *ptr, size_t old_size, size_t new_size) { - void *ret = NULL; +void *OPENSSL_realloc_clean(void *ptr, size_t old_size, size_t new_size) { if (ptr == NULL) { return OPENSSL_malloc(new_size); } @@ -91,12 +91,12 @@ void *OPENSSL_realloc_clean(void *ptr, size_t old_size, size_t new_size) { return NULL; } - ret = OPENSSL_malloc(new_size); + void *ret = OPENSSL_malloc(new_size); if (ret == NULL) { return NULL; } - memcpy(ret, ptr, old_size); + OPENSSL_memcpy(ret, ptr, old_size); OPENSSL_cleanse(ptr, old_size); OPENSSL_free(ptr); return ret; @@ -106,7 +106,7 @@ void OPENSSL_cleanse(void *ptr, size_t len) { #if defined(OPENSSL_WINDOWS) SecureZeroMemory(ptr, len); #else - memset(ptr, 0, len); + OPENSSL_memset(ptr, 0, len); #if !defined(OPENSSL_NO_ASM) /* As best as we can tell, this is sufficient to break any optimisations that @@ -118,12 +118,11 @@ void OPENSSL_cleanse(void *ptr, size_t len) { } int CRYPTO_memcmp(const void *in_a, const void *in_b, size_t len) { - size_t i; const uint8_t *a = in_a; const uint8_t *b = in_b; uint8_t x = 0; - for (i = 0; i < len; i++) { + for (size_t i = 0; i < len; i++) { x |= a[i] ^ b[i]; } @@ -136,10 +135,9 @@ uint32_t OPENSSL_hash32(const void *ptr, size_t len) { static const uint32_t kOffsetBasis = 2166136261u; const uint8_t *in = ptr; - size_t i; uint32_t h = kOffsetBasis; - for (i = 0; i < len; i++) { + for (size_t i = 0; i < len; i++) { h ^= in[i]; h *= kPrime; } @@ -147,12 +145,8 @@ uint32_t OPENSSL_hash32(const void *ptr, size_t len) { return h; } -char *OPENSSL_strdup(const char *s) { return strdup(s); } - size_t OPENSSL_strnlen(const char *s, size_t len) { - size_t i; - - for (i = 0; i < len; i++) { + for (size_t i = 0; i < len; i++) { if (s[i] == 0) { return i; } @@ -163,6 +157,8 @@ size_t OPENSSL_strnlen(const char *s, size_t len) { #if defined(OPENSSL_WINDOWS) +char *OPENSSL_strdup(const char *s) { return _strdup(s); } + int OPENSSL_strcasecmp(const char *a, const char *b) { return _stricmp(a, b); } @@ -173,6 +169,8 @@ int OPENSSL_strncasecmp(const char *a, const char *b, size_t n) { #else +char *OPENSSL_strdup(const char *s) { return strdup(s); } + int OPENSSL_strcasecmp(const char *a, const char *b) { return strcasecmp(a, b); } @@ -185,12 +183,8 @@ int OPENSSL_strncasecmp(const char *a, const char *b, size_t n) { int BIO_snprintf(char *buf, size_t n, const char *format, ...) { va_list args; - int ret; - va_start(args, format); - - ret = BIO_vsnprintf(buf, n, format, args); - + int ret = BIO_vsnprintf(buf, n, format, args); va_end(args); return ret; } diff --git a/Sources/BoringSSL/crypto/modes/cbc.c b/Sources/BoringSSL/crypto/modes/cbc.c index e41f2b497..12d551ce7 100644 --- a/Sources/BoringSSL/crypto/modes/cbc.c +++ b/Sources/BoringSSL/crypto/modes/cbc.c @@ -52,10 +52,6 @@ #include "internal.h" -#ifndef STRICT_ALIGNMENT -# define STRICT_ALIGNMENT 0 -#endif - void CRYPTO_cbc128_encrypt(const uint8_t *in, uint8_t *out, size_t len, const void *key, uint8_t ivec[16], block128_f block) { @@ -107,7 +103,7 @@ void CRYPTO_cbc128_encrypt(const uint8_t *in, uint8_t *out, size_t len, out += 16; } - memcpy(ivec, iv, 16); + OPENSSL_memcpy(ivec, iv, 16); } void CRYPTO_cbc128_decrypt(const uint8_t *in, uint8_t *out, size_t len, @@ -158,7 +154,7 @@ void CRYPTO_cbc128_decrypt(const uint8_t *in, uint8_t *out, size_t len, out += 16; } } - memcpy(ivec, iv, 16); + OPENSSL_memcpy(ivec, iv, 16); } else { /* |out| is less than two blocks behind |in|. Decrypting an input block * directly to |out| would overwrite a ciphertext block before it is used as diff --git a/Sources/BoringSSL/crypto/modes/cfb.c b/Sources/BoringSSL/crypto/modes/cfb.c index c58614ba0..af15255b4 100644 --- a/Sources/BoringSSL/crypto/modes/cfb.c +++ b/Sources/BoringSSL/crypto/modes/cfb.c @@ -57,14 +57,13 @@ OPENSSL_COMPILE_ASSERT((16 % sizeof(size_t)) == 0, bad_size_t_size); void CRYPTO_cfb128_encrypt(const uint8_t *in, uint8_t *out, size_t len, - const void *key, uint8_t ivec[16], int *num, int enc, - block128_f block) { - unsigned int n; + const void *key, uint8_t ivec[16], unsigned *num, + int enc, block128_f block) { size_t l = 0; assert(in && out && key && ivec && num); - n = *num; + unsigned n = *num; if (enc) { while (n && len) { @@ -168,7 +167,7 @@ static void cfbr_encrypt_block(const uint8_t *in, uint8_t *out, unsigned nbits, } /* fill in the first half of the new IV with the current IV */ - memcpy(ovec, ivec, 16); + OPENSSL_memcpy(ovec, ivec, 16); /* construct the new IV */ (*block)(ivec, ivec, key); num = (nbits + 7) / 8; @@ -187,7 +186,7 @@ static void cfbr_encrypt_block(const uint8_t *in, uint8_t *out, unsigned nbits, rem = nbits % 8; num = nbits / 8; if (rem == 0) { - memcpy(ivec, ovec + num, 16); + OPENSSL_memcpy(ivec, ovec + num, 16); } else { for (n = 0; n < 16; ++n) { ivec[n] = ovec[n + num] << rem | ovec[n + num + 1] >> (8 - rem); @@ -199,7 +198,7 @@ static void cfbr_encrypt_block(const uint8_t *in, uint8_t *out, unsigned nbits, /* N.B. This expects the input to be packed, MS bit first */ void CRYPTO_cfb128_1_encrypt(const uint8_t *in, uint8_t *out, size_t bits, - const void *key, uint8_t ivec[16], int *num, + const void *key, uint8_t ivec[16], unsigned *num, int enc, block128_f block) { size_t n; uint8_t c[1], d[1]; @@ -217,7 +216,7 @@ void CRYPTO_cfb128_1_encrypt(const uint8_t *in, uint8_t *out, size_t bits, void CRYPTO_cfb128_8_encrypt(const unsigned char *in, unsigned char *out, size_t length, const void *key, - unsigned char ivec[16], int *num, int enc, + unsigned char ivec[16], unsigned *num, int enc, block128_f block) { size_t n; diff --git a/Sources/BoringSSL/crypto/modes/ctr.c b/Sources/BoringSSL/crypto/modes/ctr.c index 0baed5d45..c026d1541 100644 --- a/Sources/BoringSSL/crypto/modes/ctr.c +++ b/Sources/BoringSSL/crypto/modes/ctr.c @@ -59,17 +59,13 @@ /* increment counter (128-bit int) by 1 */ static void ctr128_inc(uint8_t *counter) { - uint32_t n = 16; - uint8_t c; + uint32_t n = 16, c = 1; do { --n; - c = counter[n]; - ++c; - counter[n] = c; - if (c) { - return; - } + c += counter[n]; + counter[n] = (uint8_t) c; + c >>= 8; } while (n); } @@ -104,7 +100,7 @@ void CRYPTO_ctr128_encrypt(const uint8_t *in, uint8_t *out, size_t len, } #if STRICT_ALIGNMENT - if (((size_t)in | (size_t)out | (size_t)ivec) % sizeof(size_t) != 0) { + if (((size_t)in | (size_t)out | (size_t)ecount_buf) % sizeof(size_t) != 0) { size_t l = 0; while (l < len) { if (n == 0) { @@ -124,7 +120,7 @@ void CRYPTO_ctr128_encrypt(const uint8_t *in, uint8_t *out, size_t len, while (len >= 16) { (*block)(ivec, ecount_buf, key); ctr128_inc(ivec); - for (; n < 16; n += sizeof(size_t)) { + for (n = 0; n < 16; n += sizeof(size_t)) { *(size_t *)(out + n) = *(const size_t *)(in + n) ^ *(const size_t *)(ecount_buf + n); } @@ -146,17 +142,13 @@ void CRYPTO_ctr128_encrypt(const uint8_t *in, uint8_t *out, size_t len, /* increment upper 96 bits of 128-bit counter by 1 */ static void ctr96_inc(uint8_t *counter) { - uint32_t n = 12; - uint8_t c; + uint32_t n = 12, c = 1; do { --n; - c = counter[n]; - ++c; - counter[n] = c; - if (c) { - return; - } + c += counter[n]; + counter[n] = (uint8_t) c; + c >>= 8; } while (n); } @@ -210,7 +202,7 @@ void CRYPTO_ctr128_encrypt_ctr32(const uint8_t *in, uint8_t *out, in += blocks; } if (len) { - memset(ecount_buf, 0, 16); + OPENSSL_memset(ecount_buf, 0, 16); (*func)(ecount_buf, ecount_buf, 1, key, ivec); ++ctr32; PUTU32(ivec + 12, ctr32); diff --git a/Sources/BoringSSL/crypto/modes/gcm.c b/Sources/BoringSSL/crypto/modes/gcm.c index 8cc138dc4..1330ad626 100644 --- a/Sources/BoringSSL/crypto/modes/gcm.c +++ b/Sources/BoringSSL/crypto/modes/gcm.c @@ -55,34 +55,28 @@ #include #include "internal.h" +#include "../internal.h" #if !defined(OPENSSL_NO_ASM) && \ (defined(OPENSSL_X86) || defined(OPENSSL_X86_64) || \ - defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64)) + defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64) || \ + defined(OPENSSL_PPC64LE)) #define GHASH_ASM #endif -#if defined(BSWAP4) && STRICT_ALIGNMENT == 1 -/* redefine, because alignment is ensured */ -#undef GETU32 -#define GETU32(p) BSWAP4(*(const uint32_t *)(p)) -#undef PUTU32 -#define PUTU32(p, v) *(uint32_t *)(p) = BSWAP4(v) -#endif - #define PACK(s) ((size_t)(s) << (sizeof(size_t) * 8 - 16)) -#define REDUCE1BIT(V) \ - do { \ - if (sizeof(size_t) == 8) { \ - uint64_t T = UINT64_C(0xe100000000000000) & (0 - (V.lo & 1)); \ - V.lo = (V.hi << 63) | (V.lo >> 1); \ - V.hi = (V.hi >> 1) ^ T; \ - } else { \ - uint32_t T = 0xe1000000U & (0 - (uint32_t)(V.lo & 1)); \ - V.lo = (V.hi << 63) | (V.lo >> 1); \ - V.hi = (V.hi >> 1) ^ ((uint64_t)T << 32); \ - } \ +#define REDUCE1BIT(V) \ + do { \ + if (sizeof(size_t) == 8) { \ + uint64_t T = UINT64_C(0xe100000000000000) & (0 - ((V).lo & 1)); \ + (V).lo = ((V).hi << 63) | ((V).lo >> 1); \ + (V).hi = ((V).hi >> 1) ^ T; \ + } else { \ + uint32_t T = 0xe1000000U & (0 - (uint32_t)((V).lo & 1)); \ + (V).lo = ((V).hi << 63) | ((V).lo >> 1); \ + (V).hi = ((V).hi >> 1) ^ ((uint64_t)T << 32); \ + } \ } while (0) // kSizeTWithoutLower4Bits is a mask that can be used to zero the lower four @@ -119,32 +113,15 @@ static void gcm_init_4bit(u128 Htable[16], uint64_t H[2]) { Htable[15].hi = V.hi ^ Htable[7].hi, Htable[15].lo = V.lo ^ Htable[7].lo; #if defined(GHASH_ASM) && defined(OPENSSL_ARM) - /* ARM assembler expects specific dword order in Htable. */ - { - int j; - const union { - long one; - char little; - } is_endian = {1}; - - if (is_endian.little) { - for (j = 0; j < 16; ++j) { - V = Htable[j]; - Htable[j].hi = V.lo; - Htable[j].lo = V.hi; - } - } else { - for (j = 0; j < 16; ++j) { - V = Htable[j]; - Htable[j].hi = V.lo << 32 | V.lo >> 32; - Htable[j].lo = V.hi << 32 | V.hi >> 32; - } - } + for (int j = 0; j < 16; ++j) { + V = Htable[j]; + Htable[j].hi = V.lo; + Htable[j].lo = V.hi; } #endif } -#if !defined(GHASH_ASM) || defined(OPENSSL_AARCH64) +#if !defined(GHASH_ASM) || defined(OPENSSL_AARCH64) || defined(OPENSSL_PPC64LE) static const size_t rem_4bit[16] = { PACK(0x0000), PACK(0x1C20), PACK(0x3840), PACK(0x2460), PACK(0x7080), PACK(0x6CA0), PACK(0x48C0), PACK(0x54E0), @@ -155,10 +132,6 @@ static void gcm_gmult_4bit(uint64_t Xi[2], const u128 Htable[16]) { u128 Z; int cnt = 15; size_t rem, nlo, nhi; - const union { - long one; - char little; - } is_endian = {1}; nlo = ((const uint8_t *)Xi)[15]; nhi = nlo >> 4; @@ -201,26 +174,8 @@ static void gcm_gmult_4bit(uint64_t Xi[2], const u128 Htable[16]) { Z.lo ^= Htable[nlo].lo; } - if (is_endian.little) { -#ifdef BSWAP8 - Xi[0] = BSWAP8(Z.hi); - Xi[1] = BSWAP8(Z.lo); -#else - uint8_t *p = (uint8_t *)Xi; - uint32_t v; - v = (uint32_t)(Z.hi >> 32); - PUTU32(p, v); - v = (uint32_t)(Z.hi); - PUTU32(p + 4, v); - v = (uint32_t)(Z.lo >> 32); - PUTU32(p + 8, v); - v = (uint32_t)(Z.lo); - PUTU32(p + 12, v); -#endif - } else { - Xi[0] = Z.hi; - Xi[1] = Z.lo; - } + Xi[0] = CRYPTO_bswap8(Z.hi); + Xi[1] = CRYPTO_bswap8(Z.lo); } /* Streamed gcm_mult_4bit, see CRYPTO_gcm128_[en|de]crypt for @@ -228,15 +183,11 @@ static void gcm_gmult_4bit(uint64_t Xi[2], const u128 Htable[16]) { * performance improvement, at least not on x86[_64]. It's here * mostly as reference and a placeholder for possible future * non-trivial optimization[s]... */ -static void gcm_ghash_4bit(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp, - size_t len) { +static void gcm_ghash_4bit(uint64_t Xi[2], const u128 Htable[16], + const uint8_t *inp, size_t len) { u128 Z; int cnt; size_t rem, nlo, nhi; - const union { - long one; - char little; - } is_endian = {1}; do { cnt = 15; @@ -283,26 +234,8 @@ static void gcm_ghash_4bit(uint64_t Xi[2], const u128 Htable[16], const uint8_t Z.lo ^= Htable[nlo].lo; } - if (is_endian.little) { -#ifdef BSWAP8 - Xi[0] = BSWAP8(Z.hi); - Xi[1] = BSWAP8(Z.lo); -#else - uint8_t *p = (uint8_t *)Xi; - uint32_t v; - v = (uint32_t)(Z.hi >> 32); - PUTU32(p, v); - v = (uint32_t)(Z.hi); - PUTU32(p + 4, v); - v = (uint32_t)(Z.lo >> 32); - PUTU32(p + 8, v); - v = (uint32_t)(Z.lo); - PUTU32(p + 12, v); -#endif - } else { - Xi[0] = Z.hi; - Xi[1] = Z.lo; - } + Xi[0] = CRYPTO_bswap8(Z.hi); + Xi[1] = CRYPTO_bswap8(Z.lo); } while (inp += 16, len -= 16); } #else /* GHASH_ASM */ @@ -311,7 +244,7 @@ void gcm_ghash_4bit(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp, size_t len); #endif -#define GCM_MUL(ctx, Xi) gcm_gmult_4bit(ctx->Xi.u, ctx->Htable) +#define GCM_MUL(ctx, Xi) gcm_gmult_4bit((ctx)->Xi.u, (ctx)->Htable) #if defined(GHASH_ASM) #define GHASH(ctx, in, len) gcm_ghash_4bit((ctx)->Xi.u, (ctx)->Htable, in, len) /* GHASH_CHUNK is "stride parameter" missioned to mitigate cache @@ -322,22 +255,30 @@ void gcm_ghash_4bit(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp, #if defined(GHASH_ASM) + #if defined(OPENSSL_X86) || defined(OPENSSL_X86_64) -#define GHASH_ASM_X86_OR_64 #define GCM_FUNCREF_4BIT void gcm_init_clmul(u128 Htable[16], const uint64_t Xi[2]); void gcm_gmult_clmul(uint64_t Xi[2], const u128 Htable[16]); void gcm_ghash_clmul(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp, size_t len); -#if defined(OPENSSL_X86) -#define gcm_init_avx gcm_init_clmul -#define gcm_gmult_avx gcm_gmult_clmul -#define gcm_ghash_avx gcm_ghash_clmul -#else +#if defined(OPENSSL_X86_64) +#define GHASH_ASM_X86_64 void gcm_init_avx(u128 Htable[16], const uint64_t Xi[2]); void gcm_gmult_avx(uint64_t Xi[2], const u128 Htable[16]); -void gcm_ghash_avx(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp, size_t len); +void gcm_ghash_avx(uint64_t Xi[2], const u128 Htable[16], const uint8_t *in, + size_t len); +#define AESNI_GCM +static int aesni_gcm_enabled(GCM128_CONTEXT *ctx, ctr128_f stream) { + return stream == aesni_ctr32_encrypt_blocks && + ctx->ghash == gcm_ghash_avx; +} + +size_t aesni_gcm_encrypt(const uint8_t *in, uint8_t *out, size_t len, + const void *key, uint8_t ivec[16], uint64_t *Xi); +size_t aesni_gcm_decrypt(const uint8_t *in, uint8_t *out, size_t len, + const void *key, uint8_t ivec[16], uint64_t *Xi); #endif #if defined(OPENSSL_X86) @@ -345,11 +286,8 @@ void gcm_ghash_avx(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp, si void gcm_gmult_4bit_mmx(uint64_t Xi[2], const u128 Htable[16]); void gcm_ghash_4bit_mmx(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp, size_t len); - -void gcm_gmult_4bit_x86(uint64_t Xi[2], const u128 Htable[16]); -void gcm_ghash_4bit_x86(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp, - size_t len); #endif + #elif defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64) #include #if __ARM_ARCH__ >= 7 @@ -380,122 +318,121 @@ void gcm_ghash_neon(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp, static int neon_capable(void) { return 0; } -void gcm_init_neon(u128 Htable[16], const uint64_t Xi[2]) { +static void gcm_init_neon(u128 Htable[16], const uint64_t Xi[2]) { abort(); } -void gcm_gmult_neon(uint64_t Xi[2], const u128 Htable[16]) { +static void gcm_gmult_neon(uint64_t Xi[2], const u128 Htable[16]) { abort(); } -void gcm_ghash_neon(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp, - size_t len) { +static void gcm_ghash_neon(uint64_t Xi[2], const u128 Htable[16], + const uint8_t *inp, size_t len) { abort(); } #endif #endif +#elif defined(OPENSSL_PPC64LE) +#define GHASH_ASM_PPC64LE +#define GCM_FUNCREF_4BIT +void gcm_init_p8(u128 Htable[16], const uint64_t Xi[2]); +void gcm_gmult_p8(uint64_t Xi[2], const u128 Htable[16]); +void gcm_ghash_p8(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp, + size_t len); #endif #endif #ifdef GCM_FUNCREF_4BIT #undef GCM_MUL -#define GCM_MUL(ctx, Xi) (*gcm_gmult_p)(ctx->Xi.u, ctx->Htable) +#define GCM_MUL(ctx, Xi) (*gcm_gmult_p)((ctx)->Xi.u, (ctx)->Htable) #ifdef GHASH #undef GHASH -#define GHASH(ctx, in, len) (*gcm_ghash_p)(ctx->Xi.u, ctx->Htable, in, len) +#define GHASH(ctx, in, len) (*gcm_ghash_p)((ctx)->Xi.u, (ctx)->Htable, in, len) #endif #endif -GCM128_CONTEXT *CRYPTO_gcm128_new(const void *key, block128_f block) { - GCM128_CONTEXT *ret; +void CRYPTO_ghash_init(gmult_func *out_mult, ghash_func *out_hash, + u128 *out_key, u128 out_table[16], + const uint8_t *gcm_key) { + union { + uint64_t u[2]; + uint8_t c[16]; + } H; - ret = OPENSSL_malloc(sizeof(GCM128_CONTEXT)); - if (ret != NULL) { - CRYPTO_gcm128_init(ret, key, block); - } - - return ret; -} - -void CRYPTO_gcm128_init(GCM128_CONTEXT *ctx, const void *key, - block128_f block) { - const union { - long one; - char little; - } is_endian = {1}; + OPENSSL_memcpy(H.c, gcm_key, 16); - memset(ctx, 0, sizeof(*ctx)); - ctx->block = block; + /* H is stored in host byte order */ + H.u[0] = CRYPTO_bswap8(H.u[0]); + H.u[1] = CRYPTO_bswap8(H.u[1]); - (*block)(ctx->H.c, ctx->H.c, key); + OPENSSL_memcpy(out_key, H.c, 16); - if (is_endian.little) { -/* H is stored in host byte order */ -#ifdef BSWAP8 - ctx->H.u[0] = BSWAP8(ctx->H.u[0]); - ctx->H.u[1] = BSWAP8(ctx->H.u[1]); -#else - uint8_t *p = ctx->H.c; - uint64_t hi, lo; - hi = (uint64_t)GETU32(p) << 32 | GETU32(p + 4); - lo = (uint64_t)GETU32(p + 8) << 32 | GETU32(p + 12); - ctx->H.u[0] = hi; - ctx->H.u[1] = lo; -#endif - } - -#if defined(GHASH_ASM_X86_OR_64) +#if defined(GHASH_ASM_X86_64) if (crypto_gcm_clmul_enabled()) { if (((OPENSSL_ia32cap_P[1] >> 22) & 0x41) == 0x41) { /* AVX+MOVBE */ - gcm_init_avx(ctx->Htable, ctx->H.u); - ctx->gmult = gcm_gmult_avx; - ctx->ghash = gcm_ghash_avx; - } else { - gcm_init_clmul(ctx->Htable, ctx->H.u); - ctx->gmult = gcm_gmult_clmul; - ctx->ghash = gcm_ghash_clmul; + gcm_init_avx(out_table, H.u); + *out_mult = gcm_gmult_avx; + *out_hash = gcm_ghash_avx; + return; } + gcm_init_clmul(out_table, H.u); + *out_mult = gcm_gmult_clmul; + *out_hash = gcm_ghash_clmul; return; } - gcm_init_4bit(ctx->Htable, ctx->H.u); -#if defined(GHASH_ASM_X86) /* x86 only */ - if (OPENSSL_ia32cap_P[0] & (1 << 25)) { /* check SSE bit */ - ctx->gmult = gcm_gmult_4bit_mmx; - ctx->ghash = gcm_ghash_4bit_mmx; - } else { - ctx->gmult = gcm_gmult_4bit_x86; - ctx->ghash = gcm_ghash_4bit_x86; +#elif defined(GHASH_ASM_X86) + if (crypto_gcm_clmul_enabled()) { + gcm_init_clmul(out_table, H.u); + *out_mult = gcm_gmult_clmul; + *out_hash = gcm_ghash_clmul; + return; } -#else - ctx->gmult = gcm_gmult_4bit; - ctx->ghash = gcm_ghash_4bit; -#endif #elif defined(GHASH_ASM_ARM) if (pmull_capable()) { - gcm_init_v8(ctx->Htable, ctx->H.u); - ctx->gmult = gcm_gmult_v8; - ctx->ghash = gcm_ghash_v8; - } else if (neon_capable()) { - gcm_init_neon(ctx->Htable,ctx->H.u); - ctx->gmult = gcm_gmult_neon; - ctx->ghash = gcm_ghash_neon; - } else { - gcm_init_4bit(ctx->Htable, ctx->H.u); - ctx->gmult = gcm_gmult_4bit; - ctx->ghash = gcm_ghash_4bit; + gcm_init_v8(out_table, H.u); + *out_mult = gcm_gmult_v8; + *out_hash = gcm_ghash_v8; + return; + } + + if (neon_capable()) { + gcm_init_neon(out_table, H.u); + *out_mult = gcm_gmult_neon; + *out_hash = gcm_ghash_neon; + return; + } +#elif defined(GHASH_ASM_PPC64LE) + if (CRYPTO_is_PPC64LE_vcrypto_capable()) { + gcm_init_p8(out_table, H.u); + *out_mult = gcm_gmult_p8; + *out_hash = gcm_ghash_p8; + return; } +#endif + + gcm_init_4bit(out_table, H.u); +#if defined(GHASH_ASM_X86) + *out_mult = gcm_gmult_4bit_mmx; + *out_hash = gcm_ghash_4bit_mmx; #else - gcm_init_4bit(ctx->Htable, ctx->H.u); - ctx->gmult = gcm_gmult_4bit; - ctx->ghash = gcm_ghash_4bit; + *out_mult = gcm_gmult_4bit; + *out_hash = gcm_ghash_4bit; #endif } +void CRYPTO_gcm128_init(GCM128_CONTEXT *ctx, const void *aes_key, + block128_f block) { + OPENSSL_memset(ctx, 0, sizeof(*ctx)); + ctx->block = block; + + uint8_t gcm_key[16]; + OPENSSL_memset(gcm_key, 0, sizeof(gcm_key)); + (*block)(gcm_key, gcm_key, aes_key); + + CRYPTO_ghash_init(&ctx->gmult, &ctx->ghash, &ctx->H, ctx->Htable, gcm_key); +} + void CRYPTO_gcm128_setiv(GCM128_CONTEXT *ctx, const void *key, const uint8_t *iv, size_t len) { - const union { - long one; - char little; - } is_endian = {1}; unsigned int ctr; #ifdef GCM_FUNCREF_4BIT void (*gcm_gmult_p)(uint64_t Xi[2], const u128 Htable[16]) = ctx->gmult; @@ -511,15 +448,14 @@ void CRYPTO_gcm128_setiv(GCM128_CONTEXT *ctx, const void *key, ctx->mres = 0; if (len == 12) { - memcpy(ctx->Yi.c, iv, 12); + OPENSSL_memcpy(ctx->Yi.c, iv, 12); ctx->Yi.c[15] = 1; ctr = 1; } else { - size_t i; uint64_t len0 = len; while (len >= 16) { - for (i = 0; i < 16; ++i) { + for (size_t i = 0; i < 16; ++i) { ctx->Yi.c[i] ^= iv[i]; } GCM_MUL(ctx, Yi); @@ -527,49 +463,24 @@ void CRYPTO_gcm128_setiv(GCM128_CONTEXT *ctx, const void *key, len -= 16; } if (len) { - for (i = 0; i < len; ++i) { + for (size_t i = 0; i < len; ++i) { ctx->Yi.c[i] ^= iv[i]; } GCM_MUL(ctx, Yi); } len0 <<= 3; - if (is_endian.little) { -#ifdef BSWAP8 - ctx->Yi.u[1] ^= BSWAP8(len0); -#else - ctx->Yi.c[8] ^= (uint8_t)(len0 >> 56); - ctx->Yi.c[9] ^= (uint8_t)(len0 >> 48); - ctx->Yi.c[10] ^= (uint8_t)(len0 >> 40); - ctx->Yi.c[11] ^= (uint8_t)(len0 >> 32); - ctx->Yi.c[12] ^= (uint8_t)(len0 >> 24); - ctx->Yi.c[13] ^= (uint8_t)(len0 >> 16); - ctx->Yi.c[14] ^= (uint8_t)(len0 >> 8); - ctx->Yi.c[15] ^= (uint8_t)(len0); -#endif - } else { - ctx->Yi.u[1] ^= len0; - } + ctx->Yi.u[1] ^= CRYPTO_bswap8(len0); GCM_MUL(ctx, Yi); - - if (is_endian.little) { - ctr = GETU32(ctx->Yi.c + 12); - } else { - ctr = ctx->Yi.d[3]; - } + ctr = GETU32_aligned(ctx->Yi.c + 12); } (*ctx->block)(ctx->Yi.c, ctx->EK0.c, key); ++ctr; - if (is_endian.little) { - PUTU32(ctx->Yi.c + 12, ctr); - } else { - ctx->Yi.d[3] = ctr; - } + PUTU32_aligned(ctx->Yi.c + 12, ctr); } int CRYPTO_gcm128_aad(GCM128_CONTEXT *ctx, const uint8_t *aad, size_t len) { - size_t i; unsigned int n; uint64_t alen = ctx->len.u[0]; #ifdef GCM_FUNCREF_4BIT @@ -605,16 +516,17 @@ int CRYPTO_gcm128_aad(GCM128_CONTEXT *ctx, const uint8_t *aad, size_t len) { } } + /* Process a whole number of blocks. */ #ifdef GHASH - i = len & kSizeTWithoutLower4Bits; - if (i != 0) { - GHASH(ctx, aad, i); - aad += i; - len -= i; + size_t len_blocks = len & kSizeTWithoutLower4Bits; + if (len_blocks != 0) { + GHASH(ctx, aad, len_blocks); + aad += len_blocks; + len -= len_blocks; } #else while (len >= 16) { - for (i = 0; i < 16; ++i) { + for (size_t i = 0; i < 16; ++i) { ctx->Xi.c[i] ^= aad[i]; } GCM_MUL(ctx, Xi); @@ -622,9 +534,11 @@ int CRYPTO_gcm128_aad(GCM128_CONTEXT *ctx, const uint8_t *aad, size_t len) { len -= 16; } #endif - if (len) { + + /* Process the remainder. */ + if (len != 0) { n = (unsigned int)len; - for (i = 0; i < len; ++i) { + for (size_t i = 0; i < len; ++i) { ctx->Xi.c[i] ^= aad[i]; } } @@ -636,12 +550,7 @@ int CRYPTO_gcm128_aad(GCM128_CONTEXT *ctx, const uint8_t *aad, size_t len) { int CRYPTO_gcm128_encrypt(GCM128_CONTEXT *ctx, const void *key, const unsigned char *in, unsigned char *out, size_t len) { - const union { - long one; - char little; - } is_endian = {1}; unsigned int n, ctr; - size_t i; uint64_t mlen = ctx->len.u[1]; block128_f block = ctx->block; #ifdef GCM_FUNCREF_4BIT @@ -665,11 +574,7 @@ int CRYPTO_gcm128_encrypt(GCM128_CONTEXT *ctx, const void *key, ctx->ares = 0; } - if (is_endian.little) { - ctr = GETU32(ctx->Yi.c + 12); - } else { - ctr = ctx->Yi.d[3]; - } + ctr = GETU32_aligned(ctx->Yi.c + 12); n = ctx->mres; if (n) { @@ -686,15 +591,11 @@ int CRYPTO_gcm128_encrypt(GCM128_CONTEXT *ctx, const void *key, } } if (STRICT_ALIGNMENT && ((size_t)in | (size_t)out) % sizeof(size_t) != 0) { - for (i = 0; i < len; ++i) { + for (size_t i = 0; i < len; ++i) { if (n == 0) { (*block)(ctx->Yi.c, ctx->EKi.c, key); ++ctr; - if (is_endian.little) { - PUTU32(ctx->Yi.c + 12, ctr); - } else { - ctx->Yi.d[3] = ctr; - } + PUTU32_aligned(ctx->Yi.c + 12, ctr); } ctx->Xi.c[n] ^= out[i] = in[i] ^ ctx->EKi.c[n]; n = (n + 1) % 16; @@ -716,12 +617,8 @@ int CRYPTO_gcm128_encrypt(GCM128_CONTEXT *ctx, const void *key, (*block)(ctx->Yi.c, ctx->EKi.c, key); ++ctr; - if (is_endian.little) { - PUTU32(ctx->Yi.c + 12, ctr); - } else { - ctx->Yi.d[3] = ctr; - } - for (i = 0; i < 16 / sizeof(size_t); ++i) { + PUTU32_aligned(ctx->Yi.c + 12, ctr); + for (size_t i = 0; i < 16 / sizeof(size_t); ++i) { out_t[i] = in_t[i] ^ ctx->EKi.t[i]; } out += 16; @@ -731,28 +628,23 @@ int CRYPTO_gcm128_encrypt(GCM128_CONTEXT *ctx, const void *key, GHASH(ctx, out - GHASH_CHUNK, GHASH_CHUNK); len -= GHASH_CHUNK; } - if ((i = (len & (size_t) - 16))) { - size_t j = i; - + size_t len_blocks = len & kSizeTWithoutLower4Bits; + if (len_blocks != 0) { while (len >= 16) { size_t *out_t = (size_t *)out; const size_t *in_t = (const size_t *)in; (*block)(ctx->Yi.c, ctx->EKi.c, key); ++ctr; - if (is_endian.little) { - PUTU32(ctx->Yi.c + 12, ctr); - } else { - ctx->Yi.d[3] = ctr; - } - for (i = 0; i < 16 / sizeof(size_t); ++i) { + PUTU32_aligned(ctx->Yi.c + 12, ctr); + for (size_t i = 0; i < 16 / sizeof(size_t); ++i) { out_t[i] = in_t[i] ^ ctx->EKi.t[i]; } out += 16; in += 16; len -= 16; } - GHASH(ctx, out - j, j); + GHASH(ctx, out - len_blocks, len_blocks); } #else while (len >= 16) { @@ -761,12 +653,8 @@ int CRYPTO_gcm128_encrypt(GCM128_CONTEXT *ctx, const void *key, (*block)(ctx->Yi.c, ctx->EKi.c, key); ++ctr; - if (is_endian.little) { - PUTU32(ctx->Yi.c + 12, ctr); - } else { - ctx->Yi.d[3] = ctr; - } - for (i = 0; i < 16 / sizeof(size_t); ++i) { + PUTU32_aligned(ctx->Yi.c + 12, ctr); + for (size_t i = 0; i < 16 / sizeof(size_t); ++i) { ctx->Xi.t[i] ^= out_t[i] = in_t[i] ^ ctx->EKi.t[i]; } GCM_MUL(ctx, Xi); @@ -778,11 +666,7 @@ int CRYPTO_gcm128_encrypt(GCM128_CONTEXT *ctx, const void *key, if (len) { (*block)(ctx->Yi.c, ctx->EKi.c, key); ++ctr; - if (is_endian.little) { - PUTU32(ctx->Yi.c + 12, ctr); - } else { - ctx->Yi.d[3] = ctr; - } + PUTU32_aligned(ctx->Yi.c + 12, ctr); while (len--) { ctx->Xi.c[n] ^= out[n] = in[n] ^ ctx->EKi.c[n]; ++n; @@ -796,12 +680,7 @@ int CRYPTO_gcm128_encrypt(GCM128_CONTEXT *ctx, const void *key, int CRYPTO_gcm128_decrypt(GCM128_CONTEXT *ctx, const void *key, const unsigned char *in, unsigned char *out, size_t len) { - const union { - long one; - char little; - } is_endian = {1}; unsigned int n, ctr; - size_t i; uint64_t mlen = ctx->len.u[1]; block128_f block = ctx->block; #ifdef GCM_FUNCREF_4BIT @@ -825,11 +704,7 @@ int CRYPTO_gcm128_decrypt(GCM128_CONTEXT *ctx, const void *key, ctx->ares = 0; } - if (is_endian.little) { - ctr = GETU32(ctx->Yi.c + 12); - } else { - ctr = ctx->Yi.d[3]; - } + ctr = GETU32_aligned(ctx->Yi.c + 12); n = ctx->mres; if (n) { @@ -848,16 +723,12 @@ int CRYPTO_gcm128_decrypt(GCM128_CONTEXT *ctx, const void *key, } } if (STRICT_ALIGNMENT && ((size_t)in | (size_t)out) % sizeof(size_t) != 0) { - for (i = 0; i < len; ++i) { + for (size_t i = 0; i < len; ++i) { uint8_t c; if (n == 0) { (*block)(ctx->Yi.c, ctx->EKi.c, key); ++ctr; - if (is_endian.little) { - PUTU32(ctx->Yi.c + 12, ctr); - } else { - ctx->Yi.d[3] = ctr; - } + PUTU32_aligned(ctx->Yi.c + 12, ctr); } c = in[i]; out[i] = c ^ ctx->EKi.c[n]; @@ -882,12 +753,8 @@ int CRYPTO_gcm128_decrypt(GCM128_CONTEXT *ctx, const void *key, (*block)(ctx->Yi.c, ctx->EKi.c, key); ++ctr; - if (is_endian.little) { - PUTU32(ctx->Yi.c + 12, ctr); - } else { - ctx->Yi.d[3] = ctr; - } - for (i = 0; i < 16 / sizeof(size_t); ++i) { + PUTU32_aligned(ctx->Yi.c + 12, ctr); + for (size_t i = 0; i < 16 / sizeof(size_t); ++i) { out_t[i] = in_t[i] ^ ctx->EKi.t[i]; } out += 16; @@ -896,21 +763,17 @@ int CRYPTO_gcm128_decrypt(GCM128_CONTEXT *ctx, const void *key, } len -= GHASH_CHUNK; } - i = len & kSizeTWithoutLower4Bits; - if (i != 0) { - GHASH(ctx, in, i); + size_t len_blocks = len & kSizeTWithoutLower4Bits; + if (len_blocks != 0) { + GHASH(ctx, in, len_blocks); while (len >= 16) { size_t *out_t = (size_t *)out; const size_t *in_t = (const size_t *)in; (*block)(ctx->Yi.c, ctx->EKi.c, key); ++ctr; - if (is_endian.little) { - PUTU32(ctx->Yi.c + 12, ctr); - } else { - ctx->Yi.d[3] = ctr; - } - for (i = 0; i < 16 / sizeof(size_t); ++i) { + PUTU32_aligned(ctx->Yi.c + 12, ctr); + for (size_t i = 0; i < 16 / sizeof(size_t); ++i) { out_t[i] = in_t[i] ^ ctx->EKi.t[i]; } out += 16; @@ -925,12 +788,8 @@ int CRYPTO_gcm128_decrypt(GCM128_CONTEXT *ctx, const void *key, (*block)(ctx->Yi.c, ctx->EKi.c, key); ++ctr; - if (is_endian.little) { - PUTU32(ctx->Yi.c + 12, ctr); - } else { - ctx->Yi.d[3] = ctr; - } - for (i = 0; i < 16 / sizeof(size_t); ++i) { + PUTU32_aligned(ctx->Yi.c + 12, ctr); + for (size_t i = 0; i < 16 / sizeof(size_t); ++i) { size_t c = in_t[i]; out_t[i] = c ^ ctx->EKi.t[i]; ctx->Xi.t[i] ^= c; @@ -944,11 +803,7 @@ int CRYPTO_gcm128_decrypt(GCM128_CONTEXT *ctx, const void *key, if (len) { (*block)(ctx->Yi.c, ctx->EKi.c, key); ++ctr; - if (is_endian.little) { - PUTU32(ctx->Yi.c + 12, ctr); - } else { - ctx->Yi.d[3] = ctr; - } + PUTU32_aligned(ctx->Yi.c + 12, ctr); while (len--) { uint8_t c = in[n]; ctx->Xi.c[n] ^= c; @@ -964,10 +819,6 @@ int CRYPTO_gcm128_decrypt(GCM128_CONTEXT *ctx, const void *key, int CRYPTO_gcm128_encrypt_ctr32(GCM128_CONTEXT *ctx, const void *key, const uint8_t *in, uint8_t *out, size_t len, ctr128_f stream) { - const union { - long one; - char little; - } is_endian = {1}; unsigned int n, ctr; uint64_t mlen = ctx->len.u[1]; #ifdef GCM_FUNCREF_4BIT @@ -991,12 +842,6 @@ int CRYPTO_gcm128_encrypt_ctr32(GCM128_CONTEXT *ctx, const void *key, ctx->ares = 0; } - if (is_endian.little) { - ctr = GETU32(ctx->Yi.c + 12); - } else { - ctr = ctx->Yi.d[3]; - } - n = ctx->mres; if (n) { while (n && len) { @@ -1011,15 +856,25 @@ int CRYPTO_gcm128_encrypt_ctr32(GCM128_CONTEXT *ctx, const void *key, return 1; } } + +#if defined(AESNI_GCM) + if (aesni_gcm_enabled(ctx, stream)) { + /* |aesni_gcm_encrypt| may not process all the input given to it. It may + * not process *any* of its input if it is deemed too small. */ + size_t bulk = aesni_gcm_encrypt(in, out, len, key, ctx->Yi.c, ctx->Xi.u); + in += bulk; + out += bulk; + len -= bulk; + } +#endif + + ctr = GETU32_aligned(ctx->Yi.c + 12); + #if defined(GHASH) while (len >= GHASH_CHUNK) { (*stream)(in, out, GHASH_CHUNK / 16, key, ctx->Yi.c); ctr += GHASH_CHUNK / 16; - if (is_endian.little) { - PUTU32(ctx->Yi.c + 12, ctr); - } else { - ctx->Yi.d[3] = ctr; - } + PUTU32_aligned(ctx->Yi.c + 12, ctr); GHASH(ctx, out, GHASH_CHUNK); out += GHASH_CHUNK; in += GHASH_CHUNK; @@ -1032,11 +887,7 @@ int CRYPTO_gcm128_encrypt_ctr32(GCM128_CONTEXT *ctx, const void *key, (*stream)(in, out, j, key, ctx->Yi.c); ctr += (unsigned int)j; - if (is_endian.little) { - PUTU32(ctx->Yi.c + 12, ctr); - } else { - ctx->Yi.d[3] = ctr; - } + PUTU32_aligned(ctx->Yi.c + 12, ctr); in += i; len -= i; #if defined(GHASH) @@ -1055,11 +906,7 @@ int CRYPTO_gcm128_encrypt_ctr32(GCM128_CONTEXT *ctx, const void *key, if (len) { (*ctx->block)(ctx->Yi.c, ctx->EKi.c, key); ++ctr; - if (is_endian.little) { - PUTU32(ctx->Yi.c + 12, ctr); - } else { - ctx->Yi.d[3] = ctr; - } + PUTU32_aligned(ctx->Yi.c + 12, ctr); while (len--) { ctx->Xi.c[n] ^= out[n] = in[n] ^ ctx->EKi.c[n]; ++n; @@ -1073,10 +920,6 @@ int CRYPTO_gcm128_encrypt_ctr32(GCM128_CONTEXT *ctx, const void *key, int CRYPTO_gcm128_decrypt_ctr32(GCM128_CONTEXT *ctx, const void *key, const uint8_t *in, uint8_t *out, size_t len, ctr128_f stream) { - const union { - long one; - char little; - } is_endian = {1}; unsigned int n, ctr; uint64_t mlen = ctx->len.u[1]; #ifdef GCM_FUNCREF_4BIT @@ -1100,12 +943,6 @@ int CRYPTO_gcm128_decrypt_ctr32(GCM128_CONTEXT *ctx, const void *key, ctx->ares = 0; } - if (is_endian.little) { - ctr = GETU32(ctx->Yi.c + 12); - } else { - ctr = ctx->Yi.d[3]; - } - n = ctx->mres; if (n) { while (n && len) { @@ -1122,16 +959,26 @@ int CRYPTO_gcm128_decrypt_ctr32(GCM128_CONTEXT *ctx, const void *key, return 1; } } + +#if defined(AESNI_GCM) + if (aesni_gcm_enabled(ctx, stream)) { + /* |aesni_gcm_decrypt| may not process all the input given to it. It may + * not process *any* of its input if it is deemed too small. */ + size_t bulk = aesni_gcm_decrypt(in, out, len, key, ctx->Yi.c, ctx->Xi.u); + in += bulk; + out += bulk; + len -= bulk; + } +#endif + + ctr = GETU32_aligned(ctx->Yi.c + 12); + #if defined(GHASH) while (len >= GHASH_CHUNK) { GHASH(ctx, in, GHASH_CHUNK); (*stream)(in, out, GHASH_CHUNK / 16, key, ctx->Yi.c); ctr += GHASH_CHUNK / 16; - if (is_endian.little) { - PUTU32(ctx->Yi.c + 12, ctr); - } else { - ctx->Yi.d[3] = ctr; - } + PUTU32_aligned(ctx->Yi.c + 12, ctr); out += GHASH_CHUNK; in += GHASH_CHUNK; len -= GHASH_CHUNK; @@ -1157,11 +1004,7 @@ int CRYPTO_gcm128_decrypt_ctr32(GCM128_CONTEXT *ctx, const void *key, #endif (*stream)(in, out, j, key, ctx->Yi.c); ctr += (unsigned int)j; - if (is_endian.little) { - PUTU32(ctx->Yi.c + 12, ctr); - } else { - ctx->Yi.d[3] = ctr; - } + PUTU32_aligned(ctx->Yi.c + 12, ctr); out += i; in += i; len -= i; @@ -1169,11 +1012,7 @@ int CRYPTO_gcm128_decrypt_ctr32(GCM128_CONTEXT *ctx, const void *key, if (len) { (*ctx->block)(ctx->Yi.c, ctx->EKi.c, key); ++ctr; - if (is_endian.little) { - PUTU32(ctx->Yi.c + 12, ctr); - } else { - ctx->Yi.d[3] = ctr; - } + PUTU32_aligned(ctx->Yi.c + 12, ctr); while (len--) { uint8_t c = in[n]; ctx->Xi.c[n] ^= c; @@ -1187,10 +1026,6 @@ int CRYPTO_gcm128_decrypt_ctr32(GCM128_CONTEXT *ctx, const void *key, } int CRYPTO_gcm128_finish(GCM128_CONTEXT *ctx, const uint8_t *tag, size_t len) { - const union { - long one; - char little; - } is_endian = {1}; uint64_t alen = ctx->len.u[0] << 3; uint64_t clen = ctx->len.u[1] << 3; #ifdef GCM_FUNCREF_4BIT @@ -1201,20 +1036,8 @@ int CRYPTO_gcm128_finish(GCM128_CONTEXT *ctx, const uint8_t *tag, size_t len) { GCM_MUL(ctx, Xi); } - if (is_endian.little) { -#ifdef BSWAP8 - alen = BSWAP8(alen); - clen = BSWAP8(clen); -#else - uint8_t *p = ctx->len.c; - - ctx->len.u[0] = alen; - ctx->len.u[1] = clen; - - alen = (uint64_t)GETU32(p) << 32 | GETU32(p + 4); - clen = (uint64_t)GETU32(p + 8) << 32 | GETU32(p + 12); -#endif - } + alen = CRYPTO_bswap8(alen); + clen = CRYPTO_bswap8(clen); ctx->Xi.u[0] ^= alen; ctx->Xi.u[1] ^= clen; @@ -1232,14 +1055,8 @@ int CRYPTO_gcm128_finish(GCM128_CONTEXT *ctx, const uint8_t *tag, size_t len) { void CRYPTO_gcm128_tag(GCM128_CONTEXT *ctx, unsigned char *tag, size_t len) { CRYPTO_gcm128_finish(ctx, NULL, 0); - memcpy(tag, ctx->Xi.c, len <= sizeof(ctx->Xi.c) ? len : sizeof(ctx->Xi.c)); -} - -void CRYPTO_gcm128_release(GCM128_CONTEXT *ctx) { - if (ctx) { - OPENSSL_cleanse(ctx, sizeof(*ctx)); - OPENSSL_free(ctx); - } + OPENSSL_memcpy(tag, ctx->Xi.c, + len <= sizeof(ctx->Xi.c) ? len : sizeof(ctx->Xi.c)); } #if defined(OPENSSL_X86) || defined(OPENSSL_X86_64) diff --git a/Sources/BoringSSL/crypto/modes/internal.h b/Sources/BoringSSL/crypto/modes/internal.h index 7255a7ca0..94072ecb7 100644 --- a/Sources/BoringSSL/crypto/modes/internal.h +++ b/Sources/BoringSSL/crypto/modes/internal.h @@ -51,6 +51,10 @@ #include +#include + +#include "../internal.h" + #if defined(__cplusplus) extern "C" { #endif @@ -64,90 +68,58 @@ extern "C" { #define STRICT_ALIGNMENT 0 #endif -#if !defined(PEDANTIC) && !defined(OPENSSL_NO_ASM) #if defined(__GNUC__) && __GNUC__ >= 2 -#if defined(OPENSSL_X86_64) -#define BSWAP8(x) \ - ({ \ - uint64_t ret = (x); \ - asm("bswapq %0" : "+r"(ret)); \ - ret; \ - }) -#define BSWAP4(x) \ - ({ \ - uint32_t ret = (x); \ - asm("bswapl %0" : "+r"(ret)); \ - ret; \ - }) -#elif defined(OPENSSL_X86) -#define BSWAP8(x) \ - ({ \ - uint32_t lo = (uint64_t)(x) >> 32, hi = (x); \ - asm("bswapl %0; bswapl %1" : "+r"(hi), "+r"(lo)); \ - (uint64_t) hi << 32 | lo; \ - }) -#define BSWAP4(x) \ - ({ \ - uint32_t ret = (x); \ - asm("bswapl %0" : "+r"(ret)); \ - ret; \ - }) -#elif defined(OPENSSL_AARCH64) -#define BSWAP8(x) \ - ({ \ - uint64_t ret; \ - asm("rev %0,%1" : "=r"(ret) : "r"(x)); \ - ret; \ - }) -#define BSWAP4(x) \ - ({ \ - uint32_t ret; \ - asm("rev %w0,%w1" : "=r"(ret) : "r"(x)); \ - ret; \ - }) -#elif defined(OPENSSL_ARM) && !defined(STRICT_ALIGNMENT) -#define BSWAP8(x) \ - ({ \ - uint32_t lo = (uint64_t)(x) >> 32, hi = (x); \ - asm("rev %0,%0; rev %1,%1" : "+r"(hi), "+r"(lo)); \ - (uint64_t) hi << 32 | lo; \ - }) -#define BSWAP4(x) \ - ({ \ - uint32_t ret; \ - asm("rev %0,%1" : "=r"(ret) : "r"((uint32_t)(x))); \ - ret; \ - }) -#endif +static inline uint32_t CRYPTO_bswap4(uint32_t x) { + return __builtin_bswap32(x); +} + +static inline uint64_t CRYPTO_bswap8(uint64_t x) { + return __builtin_bswap64(x); +} #elif defined(_MSC_VER) -#if _MSC_VER >= 1300 -#pragma warning(push, 3) +OPENSSL_MSVC_PRAGMA(warning(push, 3)) #include -#pragma warning(pop) +OPENSSL_MSVC_PRAGMA(warning(pop)) #pragma intrinsic(_byteswap_uint64, _byteswap_ulong) -#define BSWAP8(x) _byteswap_uint64((uint64_t)(x)) -#define BSWAP4(x) _byteswap_ulong((uint32_t)(x)) -#elif defined(OPENSSL_X86) -__inline uint32_t _bswap4(uint32_t val) { - _asm mov eax, val - _asm bswap eax +static inline uint32_t CRYPTO_bswap4(uint32_t x) { + return _byteswap_ulong(x); } -#define BSWAP4(x) _bswap4(x) -#endif -#endif -#endif -#if defined(BSWAP4) && !defined(STRICT_ALIGNMENT) -#define GETU32(p) BSWAP4(*(const uint32_t *)(p)) -#define PUTU32(p, v) *(uint32_t *)(p) = BSWAP4(v) +static inline uint64_t CRYPTO_bswap8(uint64_t x) { + return _byteswap_uint64(x); +} #else -#define GETU32(p) \ - ((uint32_t)(p)[0] << 24 | (uint32_t)(p)[1] << 16 | (uint32_t)(p)[2] << 8 | (uint32_t)(p)[3]) -#define PUTU32(p, v) \ - ((p)[0] = (uint8_t)((v) >> 24), (p)[1] = (uint8_t)((v) >> 16), \ - (p)[2] = (uint8_t)((v) >> 8), (p)[3] = (uint8_t)(v)) +static inline uint32_t CRYPTO_bswap4(uint32_t x) { + x = (x >> 16) | (x << 16); + x = ((x & 0xff00ff00) >> 8) | ((x & 0x00ff00ff) << 8); + return x; +} + +static inline uint64_t CRYPTO_bswap8(uint64_t x) { + return CRYPTO_bswap4(x >> 32) | (((uint64_t)CRYPTO_bswap4(x)) << 32); +} #endif +static inline uint32_t GETU32(const void *in) { + uint32_t v; + OPENSSL_memcpy(&v, in, sizeof(v)); + return CRYPTO_bswap4(v); +} + +static inline void PUTU32(void *out, uint32_t v) { + v = CRYPTO_bswap4(v); + OPENSSL_memcpy(out, &v, sizeof(v)); +} + +static inline uint32_t GETU32_aligned(const void *in) { + const char *alias = (const char *) in; + return CRYPTO_bswap4(*((const uint32_t *) alias)); +} + +static inline void PUTU32_aligned(void *in, uint32_t v) { + char *alias = (char *) in; + *((uint32_t *) alias) = CRYPTO_bswap4(v); +} /* block128_f is the type of a 128-bit, block cipher. */ typedef void (*block128_f)(const uint8_t in[16], uint8_t out[16], @@ -156,6 +128,16 @@ typedef void (*block128_f)(const uint8_t in[16], uint8_t out[16], /* GCM definitions */ typedef struct { uint64_t hi,lo; } u128; +/* gmult_func multiplies |Xi| by the GCM key and writes the result back to + * |Xi|. */ +typedef void (*gmult_func)(uint64_t Xi[2], const u128 Htable[16]); + +/* ghash_func repeatedly multiplies |Xi| by the GCM key and adds in blocks from + * |inp|. The result is written back to |Xi| and the |len| argument must be a + * multiple of 16. */ +typedef void (*ghash_func)(uint64_t Xi[2], const u128 Htable[16], + const uint8_t *inp, size_t len); + /* This differs from upstream's |gcm128_context| in that it does not have the * |key| pointer, in order to make it |memcpy|-friendly. Rather the key is * passed into each call that needs it. */ @@ -166,29 +148,19 @@ struct gcm128_context { uint32_t d[4]; uint8_t c[16]; size_t t[16 / sizeof(size_t)]; - } Yi, EKi, EK0, len, Xi, H; + } Yi, EKi, EK0, len, Xi; - /* Relative position of Xi, H and pre-computed Htable is used in some - * assembler modules, i.e. don't change the order! */ + /* Note that the order of |Xi|, |H| and |Htable| is fixed by the MOVBE-based, + * x86-64, GHASH assembly. */ + u128 H; u128 Htable[16]; - void (*gmult)(uint64_t Xi[2], const u128 Htable[16]); - void (*ghash)(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp, - size_t len); + gmult_func gmult; + ghash_func ghash; unsigned int mres, ares; block128_f block; }; -struct ccm128_context { - union { - uint64_t u[2]; - uint8_t c[16]; - } nonce, cmac; - uint64_t blocks; - block128_f block; - void *key; -}; - #if defined(OPENSSL_X86) || defined(OPENSSL_X86_64) /* crypto_gcm_clmul_enabled returns one if the CLMUL implementation of GCM is * used. */ @@ -210,7 +182,7 @@ typedef void (*ctr128_f)(const uint8_t *in, uint8_t *out, size_t blocks, * incremented by this function. */ void CRYPTO_ctr128_encrypt(const uint8_t *in, uint8_t *out, size_t len, const void *key, uint8_t ivec[16], - uint8_t ecount_buf[16], unsigned int *num, + uint8_t ecount_buf[16], unsigned *num, block128_f block); /* CRYPTO_ctr128_encrypt_ctr32 acts like |CRYPTO_ctr128_encrypt| but takes @@ -219,9 +191,15 @@ void CRYPTO_ctr128_encrypt(const uint8_t *in, uint8_t *out, size_t len, * function. */ void CRYPTO_ctr128_encrypt_ctr32(const uint8_t *in, uint8_t *out, size_t len, const void *key, uint8_t ivec[16], - uint8_t ecount_buf[16], unsigned int *num, + uint8_t ecount_buf[16], unsigned *num, ctr128_f ctr); +#if !defined(OPENSSL_NO_ASM) && \ + (defined(OPENSSL_X86) || defined(OPENSSL_X86_64)) +void aesni_ctr32_encrypt_blocks(const uint8_t *in, uint8_t *out, size_t blocks, + const void *key, const uint8_t *ivec); +#endif + /* GCM. * @@ -232,10 +210,12 @@ void CRYPTO_ctr128_encrypt_ctr32(const uint8_t *in, uint8_t *out, size_t len, typedef struct gcm128_context GCM128_CONTEXT; -/* CRYPTO_gcm128_new allocates a fresh |GCM128_CONTEXT| and calls - * |CRYPTO_gcm128_init|. It returns the new context, or NULL on error. */ -OPENSSL_EXPORT GCM128_CONTEXT *CRYPTO_gcm128_new(const void *key, - block128_f block); +/* CRYPTO_ghash_init writes a precomputed table of powers of |gcm_key| to + * |out_table| and sets |*out_mult| and |*out_hash| to (potentially hardware + * accelerated) functions for performing operations in the GHASH field. */ +void CRYPTO_ghash_init(gmult_func *out_mult, ghash_func *out_hash, + u128 *out_key, u128 out_table[16], + const uint8_t *gcm_key); /* CRYPTO_gcm128_init initialises |ctx| to use |block| (typically AES) with * the given key. */ @@ -297,9 +277,6 @@ OPENSSL_EXPORT int CRYPTO_gcm128_finish(GCM128_CONTEXT *ctx, const uint8_t *tag, OPENSSL_EXPORT void CRYPTO_gcm128_tag(GCM128_CONTEXT *ctx, uint8_t *tag, size_t len); -/* CRYPTO_gcm128_release clears and frees |ctx|. */ -OPENSSL_EXPORT void CRYPTO_gcm128_release(GCM128_CONTEXT *ctx); - /* CBC. */ @@ -331,7 +308,7 @@ void CRYPTO_cbc128_decrypt(const uint8_t *in, uint8_t *out, size_t len, * call. */ void CRYPTO_ofb128_encrypt(const uint8_t *in, uint8_t *out, size_t len, const void *key, uint8_t ivec[16], - int *num, block128_f block); + unsigned *num, block128_f block); /* CFB. */ @@ -341,21 +318,21 @@ void CRYPTO_ofb128_encrypt(const uint8_t *in, uint8_t *out, * |len| be a multiple of any value and any partial blocks are stored in |ivec| * and |*num|, the latter must be zero before the initial call. */ void CRYPTO_cfb128_encrypt(const uint8_t *in, uint8_t *out, size_t len, - const void *key, uint8_t ivec[16], int *num, int enc, - block128_f block); + const void *key, uint8_t ivec[16], unsigned *num, + int enc, block128_f block); /* CRYPTO_cfb128_8_encrypt encrypts (or decrypts, if |enc| is zero) |len| bytes * from |in| to |out| using |block| in CFB-8 mode. Prior to the first call * |num| should be set to zero. */ void CRYPTO_cfb128_8_encrypt(const uint8_t *in, uint8_t *out, size_t len, - const void *key, uint8_t ivec[16], int *num, + const void *key, uint8_t ivec[16], unsigned *num, int enc, block128_f block); /* CRYPTO_cfb128_1_encrypt encrypts (or decrypts, if |enc| is zero) |len| bytes * from |in| to |out| using |block| in CFB-1 mode. Prior to the first call * |num| should be set to zero. */ void CRYPTO_cfb128_1_encrypt(const uint8_t *in, uint8_t *out, size_t bits, - const void *key, uint8_t ivec[16], int *num, + const void *key, uint8_t ivec[16], unsigned *num, int enc, block128_f block); size_t CRYPTO_cts128_encrypt_block(const uint8_t *in, uint8_t *out, size_t len, @@ -363,6 +340,40 @@ size_t CRYPTO_cts128_encrypt_block(const uint8_t *in, uint8_t *out, size_t len, block128_f block); +/* POLYVAL. + * + * POLYVAL is a polynomial authenticator that operates over a field very + * similar to the one that GHASH uses. See + * https://tools.ietf.org/html/draft-irtf-cfrg-gcmsiv-02#section-3. */ + +typedef union { + uint64_t u[2]; + uint8_t c[16]; +} polyval_block; + +struct polyval_ctx { + /* Note that the order of |S|, |H| and |Htable| is fixed by the MOVBE-based, + * x86-64, GHASH assembly. */ + polyval_block S; + u128 H; + u128 Htable[16]; + gmult_func gmult; + ghash_func ghash; +}; + +/* CRYPTO_POLYVAL_init initialises |ctx| using |key|. */ +void CRYPTO_POLYVAL_init(struct polyval_ctx *ctx, const uint8_t key[16]); + +/* CRYPTO_POLYVAL_update_blocks updates the accumulator in |ctx| given the + * blocks from |in|. Only a whole number of blocks can be processed so |in_len| + * must be a multiple of 16. */ +void CRYPTO_POLYVAL_update_blocks(struct polyval_ctx *ctx, const uint8_t *in, + size_t in_len); + +/* CRYPTO_POLYVAL_finish writes the accumulator from |ctx| to |out|. */ +void CRYPTO_POLYVAL_finish(const struct polyval_ctx *ctx, uint8_t out[16]); + + #if defined(__cplusplus) } /* extern C */ #endif diff --git a/Sources/BoringSSL/crypto/modes/ofb.c b/Sources/BoringSSL/crypto/modes/ofb.c index 63c3165a8..95d15c3d4 100644 --- a/Sources/BoringSSL/crypto/modes/ofb.c +++ b/Sources/BoringSSL/crypto/modes/ofb.c @@ -49,6 +49,7 @@ #include #include +#include #include "internal.h" @@ -56,13 +57,11 @@ OPENSSL_COMPILE_ASSERT((16 % sizeof(size_t)) == 0, bad_size_t_size); void CRYPTO_ofb128_encrypt(const uint8_t *in, uint8_t *out, size_t len, - const void *key, uint8_t ivec[16], int *num, + const void *key, uint8_t ivec[16], unsigned *num, block128_f block) { - unsigned int n; - assert(in && out && key && ivec && num); - n = *num; + unsigned n = *num; while (n && len) { *(out++) = *(in++) ^ ivec[n]; @@ -70,27 +69,15 @@ void CRYPTO_ofb128_encrypt(const uint8_t *in, uint8_t *out, size_t len, n = (n + 1) % 16; } -#if STRICT_ALIGNMENT - if (((size_t)in | (size_t)out | (size_t)ivec) % sizeof(size_t) != 0) { - size_t l = 0; - while (l < len) { - if (n == 0) { - (*block)(ivec, ivec, key); - } - out[l] = in[l] ^ ivec[n]; - ++l; - n = (n + 1) % 16; - } - - *num = n; - return; - } -#endif - while (len >= 16) { (*block)(ivec, ivec, key); for (; n < 16; n += sizeof(size_t)) { - *(size_t *)(out + n) = *(size_t *)(in + n) ^ *(size_t *)(ivec + n); + size_t a, b; + OPENSSL_memcpy(&a, in + n, sizeof(size_t)); + OPENSSL_memcpy(&b, ivec + n, sizeof(size_t)); + + const size_t c = a ^ b; + OPENSSL_memcpy(out + n, &c, sizeof(size_t)); } len -= 16; out += 16; diff --git a/Sources/BoringSSL/crypto/modes/polyval.c b/Sources/BoringSSL/crypto/modes/polyval.c new file mode 100644 index 000000000..33d37eb79 --- /dev/null +++ b/Sources/BoringSSL/crypto/modes/polyval.c @@ -0,0 +1,94 @@ +/* Copyright (c) 2016, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include + +#if !defined(OPENSSL_SMALL) + +#include +#include + +#include "internal.h" +#include "../internal.h" + + +/* byte_reverse reverses the order of the bytes in |b->c|. */ +static void byte_reverse(polyval_block *b) { + const uint64_t t = CRYPTO_bswap8(b->u[0]); + b->u[0] = CRYPTO_bswap8(b->u[1]); + b->u[1] = t; +} + +/* reverse_and_mulX_ghash interprets the bytes |b->c| as a reversed element of + * the GHASH field, multiplies that by 'x' and serialises the result back into + * |b|, but with GHASH's backwards bit ordering. */ +static void reverse_and_mulX_ghash(polyval_block *b) { + uint64_t hi = b->u[0]; + uint64_t lo = b->u[1]; + const unsigned carry = constant_time_eq(hi & 1, 1); + hi >>= 1; + hi |= lo << 63; + lo >>= 1; + lo ^= ((uint64_t) constant_time_select(carry, 0xe1, 0)) << 56; + + b->u[0] = CRYPTO_bswap8(lo); + b->u[1] = CRYPTO_bswap8(hi); +} + +/* POLYVAL(H, X_1, ..., X_n) = + * ByteReverse(GHASH(mulX_GHASH(ByteReverse(H)), ByteReverse(X_1), ..., + * ByteReverse(X_n))). + * + * See https://tools.ietf.org/html/draft-irtf-cfrg-gcmsiv-02#appendix-A. */ + +void CRYPTO_POLYVAL_init(struct polyval_ctx *ctx, const uint8_t key[16]) { + polyval_block H; + OPENSSL_memcpy(H.c, key, 16); + reverse_and_mulX_ghash(&H); + + CRYPTO_ghash_init(&ctx->gmult, &ctx->ghash, &ctx->H, ctx->Htable, H.c); + OPENSSL_memset(&ctx->S, 0, sizeof(ctx->S)); +} + +void CRYPTO_POLYVAL_update_blocks(struct polyval_ctx *ctx, const uint8_t *in, + size_t in_len) { + assert((in_len & 15) == 0); + polyval_block reversed[32]; + + while (in_len > 0) { + size_t todo = in_len; + if (todo > sizeof(reversed)) { + todo = sizeof(reversed); + } + OPENSSL_memcpy(reversed, in, todo); + in += todo; + in_len -= todo; + + size_t blocks = todo / sizeof(polyval_block); + for (size_t i = 0; i < blocks; i++) { + byte_reverse(&reversed[i]); + } + + ctx->ghash(ctx->S.u, ctx->Htable, (const uint8_t *) reversed, todo); + } +} + +void CRYPTO_POLYVAL_finish(const struct polyval_ctx *ctx, uint8_t out[16]) { + polyval_block S = ctx->S; + byte_reverse(&S); + OPENSSL_memcpy(out, &S.c, sizeof(polyval_block)); +} + + +#endif /* !OPENSSL_SMALL */ diff --git a/Sources/BoringSSL/crypto/obj/obj.c b/Sources/BoringSSL/crypto/obj/obj.c index 94f739cef..173257fa7 100644 --- a/Sources/BoringSSL/crypto/obj/obj.c +++ b/Sources/BoringSSL/crypto/obj/obj.c @@ -54,8 +54,13 @@ * copied and put under another distribution licence * [including the GNU Public Licence.] */ +#if !defined(__STDC_FORMAT_MACROS) +#define __STDC_FORMAT_MACROS +#endif + #include +#include #include #include @@ -87,7 +92,7 @@ static int obj_next_nid(void) { CRYPTO_STATIC_MUTEX_lock_write(&global_next_nid_lock); ret = global_next_nid++; - CRYPTO_STATIC_MUTEX_unlock(&global_next_nid_lock); + CRYPTO_STATIC_MUTEX_unlock_write(&global_next_nid_lock); return ret; } @@ -118,7 +123,7 @@ ASN1_OBJECT *OBJ_dup(const ASN1_OBJECT *o) { goto err; } if (o->data != NULL) { - memcpy(data, o->data, o->length); + OPENSSL_memcpy(data, o->data, o->length); } /* once data is attached to an object, it remains const */ @@ -164,7 +169,7 @@ int OBJ_cmp(const ASN1_OBJECT *a, const ASN1_OBJECT *b) { if (ret) { return ret; } - return memcmp(a->data, b->data, a->length); + return OPENSSL_memcmp(a->data, b->data, a->length); } /* obj_cmp is called to search the kNIDsInOIDOrder array. The |key| argument is @@ -180,7 +185,7 @@ static int obj_cmp(const void *key, const void *element) { } else if (a->length > b->length) { return 1; } - return memcmp(a->data, b->data, a->length); + return OPENSSL_memcmp(a->data, b->data, a->length); } int OBJ_obj2nid(const ASN1_OBJECT *obj) { @@ -200,13 +205,14 @@ int OBJ_obj2nid(const ASN1_OBJECT *obj) { match = lh_ASN1_OBJECT_retrieve(global_added_by_data, obj); if (match != NULL) { - CRYPTO_STATIC_MUTEX_unlock(&global_added_lock); + CRYPTO_STATIC_MUTEX_unlock_read(&global_added_lock); return match->nid; } } - CRYPTO_STATIC_MUTEX_unlock(&global_added_lock); + CRYPTO_STATIC_MUTEX_unlock_read(&global_added_lock); - nid_ptr = bsearch(obj, kNIDsInOIDOrder, NUM_OBJ, sizeof(unsigned), obj_cmp); + nid_ptr = bsearch(obj, kNIDsInOIDOrder, OPENSSL_ARRAY_SIZE(kNIDsInOIDOrder), + sizeof(kNIDsInOIDOrder[0]), obj_cmp); if (nid_ptr == NULL) { return NID_undef; } @@ -215,10 +221,14 @@ int OBJ_obj2nid(const ASN1_OBJECT *obj) { } int OBJ_cbs2nid(const CBS *cbs) { + if (CBS_len(cbs) > INT_MAX) { + return NID_undef; + } + ASN1_OBJECT obj; - memset(&obj, 0, sizeof(obj)); + OPENSSL_memset(&obj, 0, sizeof(obj)); obj.data = CBS_data(cbs); - obj.length = CBS_len(cbs); + obj.length = (int)CBS_len(cbs); return OBJ_obj2nid(&obj); } @@ -243,13 +253,15 @@ int OBJ_sn2nid(const char *short_name) { template.sn = short_name; match = lh_ASN1_OBJECT_retrieve(global_added_by_short_name, &template); if (match != NULL) { - CRYPTO_STATIC_MUTEX_unlock(&global_added_lock); + CRYPTO_STATIC_MUTEX_unlock_read(&global_added_lock); return match->nid; } } - CRYPTO_STATIC_MUTEX_unlock(&global_added_lock); + CRYPTO_STATIC_MUTEX_unlock_read(&global_added_lock); - nid_ptr = bsearch(short_name, kNIDsInShortNameOrder, NUM_SN, sizeof(unsigned), short_name_cmp); + nid_ptr = bsearch(short_name, kNIDsInShortNameOrder, + OPENSSL_ARRAY_SIZE(kNIDsInShortNameOrder), + sizeof(kNIDsInShortNameOrder[0]), short_name_cmp); if (nid_ptr == NULL) { return NID_undef; } @@ -277,13 +289,15 @@ int OBJ_ln2nid(const char *long_name) { template.ln = long_name; match = lh_ASN1_OBJECT_retrieve(global_added_by_long_name, &template); if (match != NULL) { - CRYPTO_STATIC_MUTEX_unlock(&global_added_lock); + CRYPTO_STATIC_MUTEX_unlock_read(&global_added_lock); return match->nid; } } - CRYPTO_STATIC_MUTEX_unlock(&global_added_lock); + CRYPTO_STATIC_MUTEX_unlock_read(&global_added_lock); - nid_ptr = bsearch(long_name, kNIDsInLongNameOrder, NUM_LN, sizeof(unsigned), long_name_cmp); + nid_ptr = bsearch(long_name, kNIDsInLongNameOrder, + OPENSSL_ARRAY_SIZE(kNIDsInLongNameOrder), + sizeof(kNIDsInLongNameOrder[0]), long_name_cmp); if (nid_ptr == NULL) { return NID_undef; } @@ -330,11 +344,11 @@ const ASN1_OBJECT *OBJ_nid2obj(int nid) { template.nid = nid; match = lh_ASN1_OBJECT_retrieve(global_added_by_nid, &template); if (match != NULL) { - CRYPTO_STATIC_MUTEX_unlock(&global_added_lock); + CRYPTO_STATIC_MUTEX_unlock_read(&global_added_lock); return match; } } - CRYPTO_STATIC_MUTEX_unlock(&global_added_lock); + CRYPTO_STATIC_MUTEX_unlock_read(&global_added_lock); err: OPENSSL_PUT_ERROR(OBJ, OBJ_R_UNKNOWN_NID); @@ -405,148 +419,115 @@ ASN1_OBJECT *OBJ_txt2obj(const char *s, int dont_search_names) { return op; } -int OBJ_obj2txt(char *out, int out_len, const ASN1_OBJECT *obj, int dont_return_name) { - int i, n = 0, len, nid, first, use_bn; - BIGNUM *bl; - unsigned long l; - const unsigned char *p; - char tbuf[DECIMAL_SIZE(i) + DECIMAL_SIZE(l) + 2]; - - if (out && out_len > 0) { - out[0] = 0; - } - - if (obj == NULL || obj->data == NULL) { - return 0; +static int strlcpy_int(char *dst, const char *src, int dst_size) { + size_t ret = BUF_strlcpy(dst, src, dst_size < 0 ? 0 : (size_t)dst_size); + if (ret > INT_MAX) { + OPENSSL_PUT_ERROR(OBJ, ERR_R_OVERFLOW); + return -1; } + return (int)ret; +} - if (!dont_return_name && (nid = OBJ_obj2nid(obj)) != NID_undef) { - const char *s; - s = OBJ_nid2ln(nid); - if (s == NULL) { - s = OBJ_nid2sn(nid); +static int parse_oid_component(CBS *cbs, uint64_t *out) { + uint64_t v = 0; + uint8_t b; + do { + if (!CBS_get_u8(cbs, &b)) { + return 0; } - if (s) { - if (out) { - BUF_strlcpy(out, s, out_len); - } - return strlen(s); + if ((v >> (64 - 7)) != 0) { + /* The component is too large. */ + return 0; } - } + if (v == 0 && b == 0x80) { + /* The component must be minimally encoded. */ + return 0; + } + v = (v << 7) | (b & 0x7f); - len = obj->length; - p = obj->data; + /* Components end at an octet with the high bit cleared. */ + } while (b & 0x80); - first = 1; - bl = NULL; + *out = v; + return 1; +} - while (len > 0) { - l = 0; - use_bn = 0; - for (;;) { - unsigned char c = *p++; - len--; - if (len == 0 && (c & 0x80)) { - goto err; - } - if (use_bn) { - if (!BN_add_word(bl, c & 0x7f)) { - goto err; - } - } else { - l |= c & 0x7f; - } - if (!(c & 0x80)) { - break; - } - if (!use_bn && (l > (ULONG_MAX >> 7L))) { - if (!bl && !(bl = BN_new())) { - goto err; - } - if (!BN_set_word(bl, l)) { - goto err; - } - use_bn = 1; +static int add_decimal(CBB *out, uint64_t v) { + char buf[DECIMAL_SIZE(uint64_t) + 1]; + BIO_snprintf(buf, sizeof(buf), "%" PRIu64, v); + return CBB_add_bytes(out, (const uint8_t *)buf, strlen(buf)); +} + +int OBJ_obj2txt(char *out, int out_len, const ASN1_OBJECT *obj, + int always_return_oid) { + /* Python depends on the empty OID successfully encoding as the empty + * string. */ + if (obj == NULL || obj->length == 0) { + return strlcpy_int(out, "", out_len); + } + + if (!always_return_oid) { + int nid = OBJ_obj2nid(obj); + if (nid != NID_undef) { + const char *name = OBJ_nid2ln(nid); + if (name == NULL) { + name = OBJ_nid2sn(nid); } - if (use_bn) { - if (!BN_lshift(bl, bl, 7)) { - goto err; - } - } else { - l <<= 7L; + if (name != NULL) { + return strlcpy_int(out, name, out_len); } } + } - if (first) { - first = 0; - if (l >= 80) { - i = 2; - if (use_bn) { - if (!BN_sub_word(bl, 80)) { - goto err; - } - } else { - l -= 80; - } - } else { - i = (int)(l / 40); - l -= (long)(i * 40); - } - if (out && out_len > 1) { - *out++ = i + '0'; - *out = '0'; - out_len--; - } - n++; + CBB cbb; + if (!CBB_init(&cbb, 32)) { + goto err; + } + + CBS cbs; + CBS_init(&cbs, obj->data, obj->length); + + /* The first component is 40 * value1 + value2, where value1 is 0, 1, or 2. */ + uint64_t v; + if (!parse_oid_component(&cbs, &v)) { + goto err; + } + + if (v >= 80) { + if (!CBB_add_bytes(&cbb, (const uint8_t *)"2.", 2) || + !add_decimal(&cbb, v - 80)) { + goto err; } + } else if (!add_decimal(&cbb, v / 40) || + !CBB_add_u8(&cbb, '.') || + !add_decimal(&cbb, v % 40)) { + goto err; + } - if (use_bn) { - char *bndec; - bndec = BN_bn2dec(bl); - if (!bndec) { - goto err; - } - i = strlen(bndec); - if (out) { - if (out_len > 1) { - *out++ = '.'; - *out = 0; - out_len--; - } - BUF_strlcpy(out, bndec, out_len); - if (i > out_len) { - out += out_len; - out_len = 0; - } else { - out += i; - out_len -= i; - } - } - n++; - n += i; - OPENSSL_free(bndec); - } else { - BIO_snprintf(tbuf, sizeof(tbuf), ".%lu", l); - i = strlen(tbuf); - if (out && out_len > 0) { - BUF_strlcpy(out, tbuf, out_len); - if (i > out_len) { - out += out_len; - out_len = 0; - } else { - out += i; - out_len -= i; - } - } - n += i; + while (CBS_len(&cbs) != 0) { + if (!parse_oid_component(&cbs, &v) || + !CBB_add_u8(&cbb, '.') || + !add_decimal(&cbb, v)) { + goto err; } } - BN_free(bl); - return n; + uint8_t *txt; + size_t txt_len; + if (!CBB_add_u8(&cbb, '\0') || + !CBB_finish(&cbb, &txt, &txt_len)) { + goto err; + } + + int ret = strlcpy_int(out, (const char *)txt, out_len); + OPENSSL_free(txt); + return ret; err: - BN_free(bl); + CBB_cleanup(&cbb); + if (out_len > 0) { + out[0] = '\0'; + } return -1; } @@ -567,7 +548,7 @@ static int cmp_data(const ASN1_OBJECT *a, const ASN1_OBJECT *b) { if (i) { return i; } - return memcmp(a->data, b->data, a->length); + return OPENSSL_memcmp(a->data, b->data, a->length); } static uint32_t hash_short_name(const ASN1_OBJECT *obj) { @@ -618,7 +599,7 @@ static int obj_add_object(ASN1_OBJECT *obj) { if (obj->ln != NULL) { ok &= lh_ASN1_OBJECT_insert(global_added_by_long_name, &old_object, obj); } - CRYPTO_STATIC_MUTEX_unlock(&global_added_lock); + CRYPTO_STATIC_MUTEX_unlock_write(&global_added_lock); return ok; } diff --git a/Sources/BoringSSL/crypto/obj/obj_dat.h b/Sources/BoringSSL/crypto/obj/obj_dat.h index bf44c6d9e..4905f0d02 100644 --- a/Sources/BoringSSL/crypto/obj/obj_dat.h +++ b/Sources/BoringSSL/crypto/obj/obj_dat.h @@ -1,7 +1,3 @@ -/* THIS FILE IS GENERATED FROM objects.h by obj_dat.pl via the - * following command: - * perl obj_dat.pl ../../include/openssl/obj_mac.h obj_dat.h */ - /* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com) * All rights reserved. * @@ -58,5203 +54,6123 @@ * copied and put under another distribution licence * [including the GNU Public Licence.] */ +/* This file is generated by crypto/obj/objects.go. */ + #define NUM_NID 949 -#define NUM_SN 941 -#define NUM_LN 941 -#define NUM_OBJ 882 -static const unsigned char lvalues[6176]={ -0x2A,0x86,0x48,0x86,0xF7,0x0D, /* [ 0] OBJ_rsadsi */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01, /* [ 6] OBJ_pkcs */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x02,0x02, /* [ 13] OBJ_md2 */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x02,0x05, /* [ 21] OBJ_md5 */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x03,0x04, /* [ 29] OBJ_rc4 */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,/* [ 37] OBJ_rsaEncryption */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x02,/* [ 46] OBJ_md2WithRSAEncryption */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x04,/* [ 55] OBJ_md5WithRSAEncryption */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x05,0x01,/* [ 64] OBJ_pbeWithMD2AndDES_CBC */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x05,0x03,/* [ 73] OBJ_pbeWithMD5AndDES_CBC */ -0x55, /* [ 82] OBJ_X500 */ -0x55,0x04, /* [ 83] OBJ_X509 */ -0x55,0x04,0x03, /* [ 85] OBJ_commonName */ -0x55,0x04,0x06, /* [ 88] OBJ_countryName */ -0x55,0x04,0x07, /* [ 91] OBJ_localityName */ -0x55,0x04,0x08, /* [ 94] OBJ_stateOrProvinceName */ -0x55,0x04,0x0A, /* [ 97] OBJ_organizationName */ -0x55,0x04,0x0B, /* [100] OBJ_organizationalUnitName */ -0x55,0x08,0x01,0x01, /* [103] OBJ_rsa */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x07, /* [107] OBJ_pkcs7 */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x07,0x01,/* [115] OBJ_pkcs7_data */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x07,0x02,/* [124] OBJ_pkcs7_signed */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x07,0x03,/* [133] OBJ_pkcs7_enveloped */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x07,0x04,/* [142] OBJ_pkcs7_signedAndEnveloped */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x07,0x05,/* [151] OBJ_pkcs7_digest */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x07,0x06,/* [160] OBJ_pkcs7_encrypted */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x03, /* [169] OBJ_pkcs3 */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x03,0x01,/* [177] OBJ_dhKeyAgreement */ -0x2B,0x0E,0x03,0x02,0x06, /* [186] OBJ_des_ecb */ -0x2B,0x0E,0x03,0x02,0x09, /* [191] OBJ_des_cfb64 */ -0x2B,0x0E,0x03,0x02,0x07, /* [196] OBJ_des_cbc */ -0x2B,0x0E,0x03,0x02,0x11, /* [201] OBJ_des_ede_ecb */ -0x2B,0x06,0x01,0x04,0x01,0x81,0x3C,0x07,0x01,0x01,0x02,/* [206] OBJ_idea_cbc */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x03,0x02, /* [217] OBJ_rc2_cbc */ -0x2B,0x0E,0x03,0x02,0x12, /* [225] OBJ_sha */ -0x2B,0x0E,0x03,0x02,0x0F, /* [230] OBJ_shaWithRSAEncryption */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x03,0x07, /* [235] OBJ_des_ede3_cbc */ -0x2B,0x0E,0x03,0x02,0x08, /* [243] OBJ_des_ofb64 */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09, /* [248] OBJ_pkcs9 */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x01,/* [256] OBJ_pkcs9_emailAddress */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x02,/* [265] OBJ_pkcs9_unstructuredName */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x03,/* [274] OBJ_pkcs9_contentType */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x04,/* [283] OBJ_pkcs9_messageDigest */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x05,/* [292] OBJ_pkcs9_signingTime */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x06,/* [301] OBJ_pkcs9_countersignature */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x07,/* [310] OBJ_pkcs9_challengePassword */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x08,/* [319] OBJ_pkcs9_unstructuredAddress */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x09,/* [328] OBJ_pkcs9_extCertAttributes */ -0x60,0x86,0x48,0x01,0x86,0xF8,0x42, /* [337] OBJ_netscape */ -0x60,0x86,0x48,0x01,0x86,0xF8,0x42,0x01, /* [344] OBJ_netscape_cert_extension */ -0x60,0x86,0x48,0x01,0x86,0xF8,0x42,0x02, /* [352] OBJ_netscape_data_type */ -0x2B,0x0E,0x03,0x02,0x1A, /* [360] OBJ_sha1 */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,/* [365] OBJ_sha1WithRSAEncryption */ -0x2B,0x0E,0x03,0x02,0x0D, /* [374] OBJ_dsaWithSHA */ -0x2B,0x0E,0x03,0x02,0x0C, /* [379] OBJ_dsa_2 */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x05,0x0B,/* [384] OBJ_pbeWithSHA1AndRC2_CBC */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x05,0x0C,/* [393] OBJ_id_pbkdf2 */ -0x2B,0x0E,0x03,0x02,0x1B, /* [402] OBJ_dsaWithSHA1_2 */ -0x60,0x86,0x48,0x01,0x86,0xF8,0x42,0x01,0x01,/* [407] OBJ_netscape_cert_type */ -0x60,0x86,0x48,0x01,0x86,0xF8,0x42,0x01,0x02,/* [416] OBJ_netscape_base_url */ -0x60,0x86,0x48,0x01,0x86,0xF8,0x42,0x01,0x03,/* [425] OBJ_netscape_revocation_url */ -0x60,0x86,0x48,0x01,0x86,0xF8,0x42,0x01,0x04,/* [434] OBJ_netscape_ca_revocation_url */ -0x60,0x86,0x48,0x01,0x86,0xF8,0x42,0x01,0x07,/* [443] OBJ_netscape_renewal_url */ -0x60,0x86,0x48,0x01,0x86,0xF8,0x42,0x01,0x08,/* [452] OBJ_netscape_ca_policy_url */ -0x60,0x86,0x48,0x01,0x86,0xF8,0x42,0x01,0x0C,/* [461] OBJ_netscape_ssl_server_name */ -0x60,0x86,0x48,0x01,0x86,0xF8,0x42,0x01,0x0D,/* [470] OBJ_netscape_comment */ -0x60,0x86,0x48,0x01,0x86,0xF8,0x42,0x02,0x05,/* [479] OBJ_netscape_cert_sequence */ -0x55,0x1D, /* [488] OBJ_id_ce */ -0x55,0x1D,0x0E, /* [490] OBJ_subject_key_identifier */ -0x55,0x1D,0x0F, /* [493] OBJ_key_usage */ -0x55,0x1D,0x10, /* [496] OBJ_private_key_usage_period */ -0x55,0x1D,0x11, /* [499] OBJ_subject_alt_name */ -0x55,0x1D,0x12, /* [502] OBJ_issuer_alt_name */ -0x55,0x1D,0x13, /* [505] OBJ_basic_constraints */ -0x55,0x1D,0x14, /* [508] OBJ_crl_number */ -0x55,0x1D,0x20, /* [511] OBJ_certificate_policies */ -0x55,0x1D,0x23, /* [514] OBJ_authority_key_identifier */ -0x2B,0x06,0x01,0x04,0x01,0x97,0x55,0x01,0x02,/* [517] OBJ_bf_cbc */ -0x55,0x08,0x03,0x65, /* [526] OBJ_mdc2 */ -0x55,0x08,0x03,0x64, /* [530] OBJ_mdc2WithRSA */ -0x55,0x04,0x2A, /* [534] OBJ_givenName */ -0x55,0x04,0x04, /* [537] OBJ_surname */ -0x55,0x04,0x2B, /* [540] OBJ_initials */ -0x55,0x1D,0x1F, /* [543] OBJ_crl_distribution_points */ -0x2B,0x0E,0x03,0x02,0x03, /* [546] OBJ_md5WithRSA */ -0x55,0x04,0x05, /* [551] OBJ_serialNumber */ -0x55,0x04,0x0C, /* [554] OBJ_title */ -0x55,0x04,0x0D, /* [557] OBJ_description */ -0x2A,0x86,0x48,0x86,0xF6,0x7D,0x07,0x42,0x0A,/* [560] OBJ_cast5_cbc */ -0x2A,0x86,0x48,0x86,0xF6,0x7D,0x07,0x42,0x0C,/* [569] OBJ_pbeWithMD5AndCast5_CBC */ -0x2A,0x86,0x48,0xCE,0x38,0x04,0x03, /* [578] OBJ_dsaWithSHA1 */ -0x2B,0x0E,0x03,0x02,0x1D, /* [585] OBJ_sha1WithRSA */ -0x2A,0x86,0x48,0xCE,0x38,0x04,0x01, /* [590] OBJ_dsa */ -0x2B,0x24,0x03,0x02,0x01, /* [597] OBJ_ripemd160 */ -0x2B,0x24,0x03,0x03,0x01,0x02, /* [602] OBJ_ripemd160WithRSA */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x03,0x08, /* [608] OBJ_rc5_cbc */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x03,0x08,/* [616] OBJ_zlib_compression */ -0x55,0x1D,0x25, /* [627] OBJ_ext_key_usage */ -0x2B,0x06,0x01,0x05,0x05,0x07, /* [630] OBJ_id_pkix */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x03, /* [636] OBJ_id_kp */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x01, /* [643] OBJ_server_auth */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x02, /* [651] OBJ_client_auth */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x03, /* [659] OBJ_code_sign */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x04, /* [667] OBJ_email_protect */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x08, /* [675] OBJ_time_stamp */ -0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x02,0x01,0x15,/* [683] OBJ_ms_code_ind */ -0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x02,0x01,0x16,/* [693] OBJ_ms_code_com */ -0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x0A,0x03,0x01,/* [703] OBJ_ms_ctl_sign */ -0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x0A,0x03,0x03,/* [713] OBJ_ms_sgc */ -0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x0A,0x03,0x04,/* [723] OBJ_ms_efs */ -0x60,0x86,0x48,0x01,0x86,0xF8,0x42,0x04,0x01,/* [733] OBJ_ns_sgc */ -0x55,0x1D,0x1B, /* [742] OBJ_delta_crl */ -0x55,0x1D,0x15, /* [745] OBJ_crl_reason */ -0x55,0x1D,0x18, /* [748] OBJ_invalidity_date */ -0x2B,0x65,0x01,0x04,0x01, /* [751] OBJ_sxnet */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x0C,0x01,0x01,/* [756] OBJ_pbe_WithSHA1And128BitRC4 */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x0C,0x01,0x02,/* [766] OBJ_pbe_WithSHA1And40BitRC4 */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x0C,0x01,0x03,/* [776] OBJ_pbe_WithSHA1And3_Key_TripleDES_CBC */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x0C,0x01,0x04,/* [786] OBJ_pbe_WithSHA1And2_Key_TripleDES_CBC */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x0C,0x01,0x05,/* [796] OBJ_pbe_WithSHA1And128BitRC2_CBC */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x0C,0x01,0x06,/* [806] OBJ_pbe_WithSHA1And40BitRC2_CBC */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x0C,0x0A,0x01,0x01,/* [816] OBJ_keyBag */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x0C,0x0A,0x01,0x02,/* [827] OBJ_pkcs8ShroudedKeyBag */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x0C,0x0A,0x01,0x03,/* [838] OBJ_certBag */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x0C,0x0A,0x01,0x04,/* [849] OBJ_crlBag */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x0C,0x0A,0x01,0x05,/* [860] OBJ_secretBag */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x0C,0x0A,0x01,0x06,/* [871] OBJ_safeContentsBag */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x14,/* [882] OBJ_friendlyName */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x15,/* [891] OBJ_localKeyID */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x16,0x01,/* [900] OBJ_x509Certificate */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x16,0x02,/* [910] OBJ_sdsiCertificate */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x17,0x01,/* [920] OBJ_x509Crl */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x05,0x0D,/* [930] OBJ_pbes2 */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x05,0x0E,/* [939] OBJ_pbmac1 */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x02,0x07, /* [948] OBJ_hmacWithSHA1 */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x02,0x01, /* [956] OBJ_id_qt_cps */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x02,0x02, /* [964] OBJ_id_qt_unotice */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x0F,/* [972] OBJ_SMIMECapabilities */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x05,0x04,/* [981] OBJ_pbeWithMD2AndRC2_CBC */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x05,0x06,/* [990] OBJ_pbeWithMD5AndRC2_CBC */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x05,0x0A,/* [999] OBJ_pbeWithSHA1AndDES_CBC */ -0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x02,0x01,0x0E,/* [1008] OBJ_ms_ext_req */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x0E,/* [1018] OBJ_ext_req */ -0x55,0x04,0x29, /* [1027] OBJ_name */ -0x55,0x04,0x2E, /* [1030] OBJ_dnQualifier */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x01, /* [1033] OBJ_id_pe */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x30, /* [1040] OBJ_id_ad */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x01, /* [1047] OBJ_info_access */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x01, /* [1055] OBJ_ad_OCSP */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x02, /* [1063] OBJ_ad_ca_issuers */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x09, /* [1071] OBJ_OCSP_sign */ -0x2A, /* [1079] OBJ_member_body */ -0x2A,0x86,0x48, /* [1080] OBJ_ISO_US */ -0x2A,0x86,0x48,0xCE,0x38, /* [1083] OBJ_X9_57 */ -0x2A,0x86,0x48,0xCE,0x38,0x04, /* [1088] OBJ_X9cm */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01, /* [1094] OBJ_pkcs1 */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x05, /* [1102] OBJ_pkcs5 */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,/* [1110] OBJ_SMIME */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x00,/* [1119] OBJ_id_smime_mod */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x01,/* [1129] OBJ_id_smime_ct */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,/* [1139] OBJ_id_smime_aa */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x03,/* [1149] OBJ_id_smime_alg */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x04,/* [1159] OBJ_id_smime_cd */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x05,/* [1169] OBJ_id_smime_spq */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x06,/* [1179] OBJ_id_smime_cti */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x00,0x01,/* [1189] OBJ_id_smime_mod_cms */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x00,0x02,/* [1200] OBJ_id_smime_mod_ess */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x00,0x03,/* [1211] OBJ_id_smime_mod_oid */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x00,0x04,/* [1222] OBJ_id_smime_mod_msg_v3 */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x00,0x05,/* [1233] OBJ_id_smime_mod_ets_eSignature_88 */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x00,0x06,/* [1244] OBJ_id_smime_mod_ets_eSignature_97 */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x00,0x07,/* [1255] OBJ_id_smime_mod_ets_eSigPolicy_88 */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x00,0x08,/* [1266] OBJ_id_smime_mod_ets_eSigPolicy_97 */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x01,0x01,/* [1277] OBJ_id_smime_ct_receipt */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x01,0x02,/* [1288] OBJ_id_smime_ct_authData */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x01,0x03,/* [1299] OBJ_id_smime_ct_publishCert */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x01,0x04,/* [1310] OBJ_id_smime_ct_TSTInfo */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x01,0x05,/* [1321] OBJ_id_smime_ct_TDTInfo */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x01,0x06,/* [1332] OBJ_id_smime_ct_contentInfo */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x01,0x07,/* [1343] OBJ_id_smime_ct_DVCSRequestData */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x01,0x08,/* [1354] OBJ_id_smime_ct_DVCSResponseData */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x01,/* [1365] OBJ_id_smime_aa_receiptRequest */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x02,/* [1376] OBJ_id_smime_aa_securityLabel */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x03,/* [1387] OBJ_id_smime_aa_mlExpandHistory */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x04,/* [1398] OBJ_id_smime_aa_contentHint */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x05,/* [1409] OBJ_id_smime_aa_msgSigDigest */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x06,/* [1420] OBJ_id_smime_aa_encapContentType */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x07,/* [1431] OBJ_id_smime_aa_contentIdentifier */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x08,/* [1442] OBJ_id_smime_aa_macValue */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x09,/* [1453] OBJ_id_smime_aa_equivalentLabels */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x0A,/* [1464] OBJ_id_smime_aa_contentReference */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x0B,/* [1475] OBJ_id_smime_aa_encrypKeyPref */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x0C,/* [1486] OBJ_id_smime_aa_signingCertificate */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x0D,/* [1497] OBJ_id_smime_aa_smimeEncryptCerts */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x0E,/* [1508] OBJ_id_smime_aa_timeStampToken */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x0F,/* [1519] OBJ_id_smime_aa_ets_sigPolicyId */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x10,/* [1530] OBJ_id_smime_aa_ets_commitmentType */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x11,/* [1541] OBJ_id_smime_aa_ets_signerLocation */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x12,/* [1552] OBJ_id_smime_aa_ets_signerAttr */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x13,/* [1563] OBJ_id_smime_aa_ets_otherSigCert */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x14,/* [1574] OBJ_id_smime_aa_ets_contentTimestamp */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x15,/* [1585] OBJ_id_smime_aa_ets_CertificateRefs */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x16,/* [1596] OBJ_id_smime_aa_ets_RevocationRefs */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x17,/* [1607] OBJ_id_smime_aa_ets_certValues */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x18,/* [1618] OBJ_id_smime_aa_ets_revocationValues */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x19,/* [1629] OBJ_id_smime_aa_ets_escTimeStamp */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x1A,/* [1640] OBJ_id_smime_aa_ets_certCRLTimestamp */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x1B,/* [1651] OBJ_id_smime_aa_ets_archiveTimeStamp */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x1C,/* [1662] OBJ_id_smime_aa_signatureType */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x1D,/* [1673] OBJ_id_smime_aa_dvcs_dvc */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x03,0x01,/* [1684] OBJ_id_smime_alg_ESDHwith3DES */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x03,0x02,/* [1695] OBJ_id_smime_alg_ESDHwithRC2 */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x03,0x03,/* [1706] OBJ_id_smime_alg_3DESwrap */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x03,0x04,/* [1717] OBJ_id_smime_alg_RC2wrap */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x03,0x05,/* [1728] OBJ_id_smime_alg_ESDH */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x03,0x06,/* [1739] OBJ_id_smime_alg_CMS3DESwrap */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x03,0x07,/* [1750] OBJ_id_smime_alg_CMSRC2wrap */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x04,0x01,/* [1761] OBJ_id_smime_cd_ldap */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x05,0x01,/* [1772] OBJ_id_smime_spq_ets_sqt_uri */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x05,0x02,/* [1783] OBJ_id_smime_spq_ets_sqt_unotice */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x06,0x01,/* [1794] OBJ_id_smime_cti_ets_proofOfOrigin */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x06,0x02,/* [1805] OBJ_id_smime_cti_ets_proofOfReceipt */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x06,0x03,/* [1816] OBJ_id_smime_cti_ets_proofOfDelivery */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x06,0x04,/* [1827] OBJ_id_smime_cti_ets_proofOfSender */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x06,0x05,/* [1838] OBJ_id_smime_cti_ets_proofOfApproval */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x06,0x06,/* [1849] OBJ_id_smime_cti_ets_proofOfCreation */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x02,0x04, /* [1860] OBJ_md4 */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x00, /* [1868] OBJ_id_pkix_mod */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x02, /* [1875] OBJ_id_qt */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x04, /* [1882] OBJ_id_it */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x05, /* [1889] OBJ_id_pkip */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x06, /* [1896] OBJ_id_alg */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x07, /* [1903] OBJ_id_cmc */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x08, /* [1910] OBJ_id_on */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x09, /* [1917] OBJ_id_pda */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x0A, /* [1924] OBJ_id_aca */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x0B, /* [1931] OBJ_id_qcs */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x0C, /* [1938] OBJ_id_cct */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x00,0x01, /* [1945] OBJ_id_pkix1_explicit_88 */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x00,0x02, /* [1953] OBJ_id_pkix1_implicit_88 */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x00,0x03, /* [1961] OBJ_id_pkix1_explicit_93 */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x00,0x04, /* [1969] OBJ_id_pkix1_implicit_93 */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x00,0x05, /* [1977] OBJ_id_mod_crmf */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x00,0x06, /* [1985] OBJ_id_mod_cmc */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x00,0x07, /* [1993] OBJ_id_mod_kea_profile_88 */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x00,0x08, /* [2001] OBJ_id_mod_kea_profile_93 */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x00,0x09, /* [2009] OBJ_id_mod_cmp */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x00,0x0A, /* [2017] OBJ_id_mod_qualified_cert_88 */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x00,0x0B, /* [2025] OBJ_id_mod_qualified_cert_93 */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x00,0x0C, /* [2033] OBJ_id_mod_attribute_cert */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x00,0x0D, /* [2041] OBJ_id_mod_timestamp_protocol */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x00,0x0E, /* [2049] OBJ_id_mod_ocsp */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x00,0x0F, /* [2057] OBJ_id_mod_dvcs */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x00,0x10, /* [2065] OBJ_id_mod_cmp2000 */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x02, /* [2073] OBJ_biometricInfo */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x03, /* [2081] OBJ_qcStatements */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x04, /* [2089] OBJ_ac_auditEntity */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x05, /* [2097] OBJ_ac_targeting */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x06, /* [2105] OBJ_aaControls */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x07, /* [2113] OBJ_sbgp_ipAddrBlock */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x08, /* [2121] OBJ_sbgp_autonomousSysNum */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x09, /* [2129] OBJ_sbgp_routerIdentifier */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x02,0x03, /* [2137] OBJ_textNotice */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x05, /* [2145] OBJ_ipsecEndSystem */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x06, /* [2153] OBJ_ipsecTunnel */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x07, /* [2161] OBJ_ipsecUser */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x0A, /* [2169] OBJ_dvcs */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x04,0x01, /* [2177] OBJ_id_it_caProtEncCert */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x04,0x02, /* [2185] OBJ_id_it_signKeyPairTypes */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x04,0x03, /* [2193] OBJ_id_it_encKeyPairTypes */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x04,0x04, /* [2201] OBJ_id_it_preferredSymmAlg */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x04,0x05, /* [2209] OBJ_id_it_caKeyUpdateInfo */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x04,0x06, /* [2217] OBJ_id_it_currentCRL */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x04,0x07, /* [2225] OBJ_id_it_unsupportedOIDs */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x04,0x08, /* [2233] OBJ_id_it_subscriptionRequest */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x04,0x09, /* [2241] OBJ_id_it_subscriptionResponse */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x04,0x0A, /* [2249] OBJ_id_it_keyPairParamReq */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x04,0x0B, /* [2257] OBJ_id_it_keyPairParamRep */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x04,0x0C, /* [2265] OBJ_id_it_revPassphrase */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x04,0x0D, /* [2273] OBJ_id_it_implicitConfirm */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x04,0x0E, /* [2281] OBJ_id_it_confirmWaitTime */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x04,0x0F, /* [2289] OBJ_id_it_origPKIMessage */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x05,0x01, /* [2297] OBJ_id_regCtrl */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x05,0x02, /* [2305] OBJ_id_regInfo */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x05,0x01,0x01,/* [2313] OBJ_id_regCtrl_regToken */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x05,0x01,0x02,/* [2322] OBJ_id_regCtrl_authenticator */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x05,0x01,0x03,/* [2331] OBJ_id_regCtrl_pkiPublicationInfo */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x05,0x01,0x04,/* [2340] OBJ_id_regCtrl_pkiArchiveOptions */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x05,0x01,0x05,/* [2349] OBJ_id_regCtrl_oldCertID */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x05,0x01,0x06,/* [2358] OBJ_id_regCtrl_protocolEncrKey */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x05,0x02,0x01,/* [2367] OBJ_id_regInfo_utf8Pairs */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x05,0x02,0x02,/* [2376] OBJ_id_regInfo_certReq */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x06,0x01, /* [2385] OBJ_id_alg_des40 */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x06,0x02, /* [2393] OBJ_id_alg_noSignature */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x06,0x03, /* [2401] OBJ_id_alg_dh_sig_hmac_sha1 */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x06,0x04, /* [2409] OBJ_id_alg_dh_pop */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x07,0x01, /* [2417] OBJ_id_cmc_statusInfo */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x07,0x02, /* [2425] OBJ_id_cmc_identification */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x07,0x03, /* [2433] OBJ_id_cmc_identityProof */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x07,0x04, /* [2441] OBJ_id_cmc_dataReturn */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x07,0x05, /* [2449] OBJ_id_cmc_transactionId */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x07,0x06, /* [2457] OBJ_id_cmc_senderNonce */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x07,0x07, /* [2465] OBJ_id_cmc_recipientNonce */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x07,0x08, /* [2473] OBJ_id_cmc_addExtensions */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x07,0x09, /* [2481] OBJ_id_cmc_encryptedPOP */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x07,0x0A, /* [2489] OBJ_id_cmc_decryptedPOP */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x07,0x0B, /* [2497] OBJ_id_cmc_lraPOPWitness */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x07,0x0F, /* [2505] OBJ_id_cmc_getCert */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x07,0x10, /* [2513] OBJ_id_cmc_getCRL */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x07,0x11, /* [2521] OBJ_id_cmc_revokeRequest */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x07,0x12, /* [2529] OBJ_id_cmc_regInfo */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x07,0x13, /* [2537] OBJ_id_cmc_responseInfo */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x07,0x15, /* [2545] OBJ_id_cmc_queryPending */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x07,0x16, /* [2553] OBJ_id_cmc_popLinkRandom */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x07,0x17, /* [2561] OBJ_id_cmc_popLinkWitness */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x07,0x18, /* [2569] OBJ_id_cmc_confirmCertAcceptance */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x08,0x01, /* [2577] OBJ_id_on_personalData */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x09,0x01, /* [2585] OBJ_id_pda_dateOfBirth */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x09,0x02, /* [2593] OBJ_id_pda_placeOfBirth */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x09,0x03, /* [2601] OBJ_id_pda_gender */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x09,0x04, /* [2609] OBJ_id_pda_countryOfCitizenship */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x09,0x05, /* [2617] OBJ_id_pda_countryOfResidence */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x0A,0x01, /* [2625] OBJ_id_aca_authenticationInfo */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x0A,0x02, /* [2633] OBJ_id_aca_accessIdentity */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x0A,0x03, /* [2641] OBJ_id_aca_chargingIdentity */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x0A,0x04, /* [2649] OBJ_id_aca_group */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x0A,0x05, /* [2657] OBJ_id_aca_role */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x0B,0x01, /* [2665] OBJ_id_qcs_pkixQCSyntax_v1 */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x0C,0x01, /* [2673] OBJ_id_cct_crs */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x0C,0x02, /* [2681] OBJ_id_cct_PKIData */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x0C,0x03, /* [2689] OBJ_id_cct_PKIResponse */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x03, /* [2697] OBJ_ad_timeStamping */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x04, /* [2705] OBJ_ad_dvcs */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x01,/* [2713] OBJ_id_pkix_OCSP_basic */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x02,/* [2722] OBJ_id_pkix_OCSP_Nonce */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x03,/* [2731] OBJ_id_pkix_OCSP_CrlID */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x04,/* [2740] OBJ_id_pkix_OCSP_acceptableResponses */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x05,/* [2749] OBJ_id_pkix_OCSP_noCheck */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x06,/* [2758] OBJ_id_pkix_OCSP_archiveCutoff */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x07,/* [2767] OBJ_id_pkix_OCSP_serviceLocator */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x08,/* [2776] OBJ_id_pkix_OCSP_extendedStatus */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x09,/* [2785] OBJ_id_pkix_OCSP_valid */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x0A,/* [2794] OBJ_id_pkix_OCSP_path */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x0B,/* [2803] OBJ_id_pkix_OCSP_trustRoot */ -0x2B,0x0E,0x03,0x02, /* [2812] OBJ_algorithm */ -0x2B,0x0E,0x03,0x02,0x0B, /* [2816] OBJ_rsaSignature */ -0x55,0x08, /* [2821] OBJ_X500algorithms */ -0x2B, /* [2823] OBJ_org */ -0x2B,0x06, /* [2824] OBJ_dod */ -0x2B,0x06,0x01, /* [2826] OBJ_iana */ -0x2B,0x06,0x01,0x01, /* [2829] OBJ_Directory */ -0x2B,0x06,0x01,0x02, /* [2833] OBJ_Management */ -0x2B,0x06,0x01,0x03, /* [2837] OBJ_Experimental */ -0x2B,0x06,0x01,0x04, /* [2841] OBJ_Private */ -0x2B,0x06,0x01,0x05, /* [2845] OBJ_Security */ -0x2B,0x06,0x01,0x06, /* [2849] OBJ_SNMPv2 */ -0x2B,0x06,0x01,0x07, /* [2853] OBJ_Mail */ -0x2B,0x06,0x01,0x04,0x01, /* [2857] OBJ_Enterprises */ -0x2B,0x06,0x01,0x04,0x01,0x8B,0x3A,0x82,0x58,/* [2862] OBJ_dcObject */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x19,/* [2871] OBJ_domainComponent */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x04,0x0D,/* [2881] OBJ_Domain */ -0x55,0x01,0x05, /* [2891] OBJ_selected_attribute_types */ -0x55,0x01,0x05,0x37, /* [2894] OBJ_clearance */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x03,/* [2898] OBJ_md4WithRSAEncryption */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x0A, /* [2907] OBJ_ac_proxying */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x0B, /* [2915] OBJ_sinfo_access */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x0A,0x06, /* [2923] OBJ_id_aca_encAttrs */ -0x55,0x04,0x48, /* [2931] OBJ_role */ -0x55,0x1D,0x24, /* [2934] OBJ_policy_constraints */ -0x55,0x1D,0x37, /* [2937] OBJ_target_information */ -0x55,0x1D,0x38, /* [2940] OBJ_no_rev_avail */ -0x2A,0x86,0x48,0xCE,0x3D, /* [2943] OBJ_ansi_X9_62 */ -0x2A,0x86,0x48,0xCE,0x3D,0x01,0x01, /* [2948] OBJ_X9_62_prime_field */ -0x2A,0x86,0x48,0xCE,0x3D,0x01,0x02, /* [2955] OBJ_X9_62_characteristic_two_field */ -0x2A,0x86,0x48,0xCE,0x3D,0x02,0x01, /* [2962] OBJ_X9_62_id_ecPublicKey */ -0x2A,0x86,0x48,0xCE,0x3D,0x03,0x01,0x01, /* [2969] OBJ_X9_62_prime192v1 */ -0x2A,0x86,0x48,0xCE,0x3D,0x03,0x01,0x02, /* [2977] OBJ_X9_62_prime192v2 */ -0x2A,0x86,0x48,0xCE,0x3D,0x03,0x01,0x03, /* [2985] OBJ_X9_62_prime192v3 */ -0x2A,0x86,0x48,0xCE,0x3D,0x03,0x01,0x04, /* [2993] OBJ_X9_62_prime239v1 */ -0x2A,0x86,0x48,0xCE,0x3D,0x03,0x01,0x05, /* [3001] OBJ_X9_62_prime239v2 */ -0x2A,0x86,0x48,0xCE,0x3D,0x03,0x01,0x06, /* [3009] OBJ_X9_62_prime239v3 */ -0x2A,0x86,0x48,0xCE,0x3D,0x03,0x01,0x07, /* [3017] OBJ_X9_62_prime256v1 */ -0x2A,0x86,0x48,0xCE,0x3D,0x04,0x01, /* [3025] OBJ_ecdsa_with_SHA1 */ -0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x11,0x01,/* [3032] OBJ_ms_csp_name */ -0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x01,/* [3041] OBJ_aes_128_ecb */ -0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x02,/* [3050] OBJ_aes_128_cbc */ -0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x03,/* [3059] OBJ_aes_128_ofb128 */ -0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x04,/* [3068] OBJ_aes_128_cfb128 */ -0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x15,/* [3077] OBJ_aes_192_ecb */ -0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x16,/* [3086] OBJ_aes_192_cbc */ -0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x17,/* [3095] OBJ_aes_192_ofb128 */ -0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x18,/* [3104] OBJ_aes_192_cfb128 */ -0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x29,/* [3113] OBJ_aes_256_ecb */ -0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x2A,/* [3122] OBJ_aes_256_cbc */ -0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x2B,/* [3131] OBJ_aes_256_ofb128 */ -0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x2C,/* [3140] OBJ_aes_256_cfb128 */ -0x55,0x1D,0x17, /* [3149] OBJ_hold_instruction_code */ -0x2A,0x86,0x48,0xCE,0x38,0x02,0x01, /* [3152] OBJ_hold_instruction_none */ -0x2A,0x86,0x48,0xCE,0x38,0x02,0x02, /* [3159] OBJ_hold_instruction_call_issuer */ -0x2A,0x86,0x48,0xCE,0x38,0x02,0x03, /* [3166] OBJ_hold_instruction_reject */ -0x09, /* [3173] OBJ_data */ -0x09,0x92,0x26, /* [3174] OBJ_pss */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C, /* [3177] OBJ_ucl */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64, /* [3184] OBJ_pilot */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,/* [3192] OBJ_pilotAttributeType */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x03,/* [3201] OBJ_pilotAttributeSyntax */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x04,/* [3210] OBJ_pilotObjectClass */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x0A,/* [3219] OBJ_pilotGroups */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x03,0x04,/* [3228] OBJ_iA5StringSyntax */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x03,0x05,/* [3238] OBJ_caseIgnoreIA5StringSyntax */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x04,0x03,/* [3248] OBJ_pilotObject */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x04,0x04,/* [3258] OBJ_pilotPerson */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x04,0x05,/* [3268] OBJ_account */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x04,0x06,/* [3278] OBJ_document */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x04,0x07,/* [3288] OBJ_room */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x04,0x09,/* [3298] OBJ_documentSeries */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x04,0x0E,/* [3308] OBJ_rFC822localPart */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x04,0x0F,/* [3318] OBJ_dNSDomain */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x04,0x11,/* [3328] OBJ_domainRelatedObject */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x04,0x12,/* [3338] OBJ_friendlyCountry */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x04,0x13,/* [3348] OBJ_simpleSecurityObject */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x04,0x14,/* [3358] OBJ_pilotOrganization */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x04,0x15,/* [3368] OBJ_pilotDSA */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x04,0x16,/* [3378] OBJ_qualityLabelledData */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x01,/* [3388] OBJ_userId */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x02,/* [3398] OBJ_textEncodedORAddress */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x03,/* [3408] OBJ_rfc822Mailbox */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x04,/* [3418] OBJ_info */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x05,/* [3428] OBJ_favouriteDrink */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x06,/* [3438] OBJ_roomNumber */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x07,/* [3448] OBJ_photo */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x08,/* [3458] OBJ_userClass */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x09,/* [3468] OBJ_host */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x0A,/* [3478] OBJ_manager */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x0B,/* [3488] OBJ_documentIdentifier */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x0C,/* [3498] OBJ_documentTitle */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x0D,/* [3508] OBJ_documentVersion */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x0E,/* [3518] OBJ_documentAuthor */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x0F,/* [3528] OBJ_documentLocation */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x14,/* [3538] OBJ_homeTelephoneNumber */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x15,/* [3548] OBJ_secretary */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x16,/* [3558] OBJ_otherMailbox */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x17,/* [3568] OBJ_lastModifiedTime */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x18,/* [3578] OBJ_lastModifiedBy */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x1A,/* [3588] OBJ_aRecord */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x1B,/* [3598] OBJ_pilotAttributeType27 */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x1C,/* [3608] OBJ_mXRecord */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x1D,/* [3618] OBJ_nSRecord */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x1E,/* [3628] OBJ_sOARecord */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x1F,/* [3638] OBJ_cNAMERecord */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x25,/* [3648] OBJ_associatedDomain */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x26,/* [3658] OBJ_associatedName */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x27,/* [3668] OBJ_homePostalAddress */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x28,/* [3678] OBJ_personalTitle */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x29,/* [3688] OBJ_mobileTelephoneNumber */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x2A,/* [3698] OBJ_pagerTelephoneNumber */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x2B,/* [3708] OBJ_friendlyCountryName */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x2D,/* [3718] OBJ_organizationalStatus */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x2E,/* [3728] OBJ_janetMailbox */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x2F,/* [3738] OBJ_mailPreferenceOption */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x30,/* [3748] OBJ_buildingName */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x31,/* [3758] OBJ_dSAQuality */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x32,/* [3768] OBJ_singleLevelQuality */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x33,/* [3778] OBJ_subtreeMinimumQuality */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x34,/* [3788] OBJ_subtreeMaximumQuality */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x35,/* [3798] OBJ_personalSignature */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x36,/* [3808] OBJ_dITRedirect */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x37,/* [3818] OBJ_audio */ -0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x38,/* [3828] OBJ_documentPublisher */ -0x55,0x04,0x2D, /* [3838] OBJ_x500UniqueIdentifier */ -0x2B,0x06,0x01,0x07,0x01, /* [3841] OBJ_mime_mhs */ -0x2B,0x06,0x01,0x07,0x01,0x01, /* [3846] OBJ_mime_mhs_headings */ -0x2B,0x06,0x01,0x07,0x01,0x02, /* [3852] OBJ_mime_mhs_bodies */ -0x2B,0x06,0x01,0x07,0x01,0x01,0x01, /* [3858] OBJ_id_hex_partial_message */ -0x2B,0x06,0x01,0x07,0x01,0x01,0x02, /* [3865] OBJ_id_hex_multipart_message */ -0x55,0x04,0x2C, /* [3872] OBJ_generationQualifier */ -0x55,0x04,0x41, /* [3875] OBJ_pseudonym */ -0x67,0x2A, /* [3878] OBJ_id_set */ -0x67,0x2A,0x00, /* [3880] OBJ_set_ctype */ -0x67,0x2A,0x01, /* [3883] OBJ_set_msgExt */ -0x67,0x2A,0x03, /* [3886] OBJ_set_attr */ -0x67,0x2A,0x05, /* [3889] OBJ_set_policy */ -0x67,0x2A,0x07, /* [3892] OBJ_set_certExt */ -0x67,0x2A,0x08, /* [3895] OBJ_set_brand */ -0x67,0x2A,0x00,0x00, /* [3898] OBJ_setct_PANData */ -0x67,0x2A,0x00,0x01, /* [3902] OBJ_setct_PANToken */ -0x67,0x2A,0x00,0x02, /* [3906] OBJ_setct_PANOnly */ -0x67,0x2A,0x00,0x03, /* [3910] OBJ_setct_OIData */ -0x67,0x2A,0x00,0x04, /* [3914] OBJ_setct_PI */ -0x67,0x2A,0x00,0x05, /* [3918] OBJ_setct_PIData */ -0x67,0x2A,0x00,0x06, /* [3922] OBJ_setct_PIDataUnsigned */ -0x67,0x2A,0x00,0x07, /* [3926] OBJ_setct_HODInput */ -0x67,0x2A,0x00,0x08, /* [3930] OBJ_setct_AuthResBaggage */ -0x67,0x2A,0x00,0x09, /* [3934] OBJ_setct_AuthRevReqBaggage */ -0x67,0x2A,0x00,0x0A, /* [3938] OBJ_setct_AuthRevResBaggage */ -0x67,0x2A,0x00,0x0B, /* [3942] OBJ_setct_CapTokenSeq */ -0x67,0x2A,0x00,0x0C, /* [3946] OBJ_setct_PInitResData */ -0x67,0x2A,0x00,0x0D, /* [3950] OBJ_setct_PI_TBS */ -0x67,0x2A,0x00,0x0E, /* [3954] OBJ_setct_PResData */ -0x67,0x2A,0x00,0x10, /* [3958] OBJ_setct_AuthReqTBS */ -0x67,0x2A,0x00,0x11, /* [3962] OBJ_setct_AuthResTBS */ -0x67,0x2A,0x00,0x12, /* [3966] OBJ_setct_AuthResTBSX */ -0x67,0x2A,0x00,0x13, /* [3970] OBJ_setct_AuthTokenTBS */ -0x67,0x2A,0x00,0x14, /* [3974] OBJ_setct_CapTokenData */ -0x67,0x2A,0x00,0x15, /* [3978] OBJ_setct_CapTokenTBS */ -0x67,0x2A,0x00,0x16, /* [3982] OBJ_setct_AcqCardCodeMsg */ -0x67,0x2A,0x00,0x17, /* [3986] OBJ_setct_AuthRevReqTBS */ -0x67,0x2A,0x00,0x18, /* [3990] OBJ_setct_AuthRevResData */ -0x67,0x2A,0x00,0x19, /* [3994] OBJ_setct_AuthRevResTBS */ -0x67,0x2A,0x00,0x1A, /* [3998] OBJ_setct_CapReqTBS */ -0x67,0x2A,0x00,0x1B, /* [4002] OBJ_setct_CapReqTBSX */ -0x67,0x2A,0x00,0x1C, /* [4006] OBJ_setct_CapResData */ -0x67,0x2A,0x00,0x1D, /* [4010] OBJ_setct_CapRevReqTBS */ -0x67,0x2A,0x00,0x1E, /* [4014] OBJ_setct_CapRevReqTBSX */ -0x67,0x2A,0x00,0x1F, /* [4018] OBJ_setct_CapRevResData */ -0x67,0x2A,0x00,0x20, /* [4022] OBJ_setct_CredReqTBS */ -0x67,0x2A,0x00,0x21, /* [4026] OBJ_setct_CredReqTBSX */ -0x67,0x2A,0x00,0x22, /* [4030] OBJ_setct_CredResData */ -0x67,0x2A,0x00,0x23, /* [4034] OBJ_setct_CredRevReqTBS */ -0x67,0x2A,0x00,0x24, /* [4038] OBJ_setct_CredRevReqTBSX */ -0x67,0x2A,0x00,0x25, /* [4042] OBJ_setct_CredRevResData */ -0x67,0x2A,0x00,0x26, /* [4046] OBJ_setct_PCertReqData */ -0x67,0x2A,0x00,0x27, /* [4050] OBJ_setct_PCertResTBS */ -0x67,0x2A,0x00,0x28, /* [4054] OBJ_setct_BatchAdminReqData */ -0x67,0x2A,0x00,0x29, /* [4058] OBJ_setct_BatchAdminResData */ -0x67,0x2A,0x00,0x2A, /* [4062] OBJ_setct_CardCInitResTBS */ -0x67,0x2A,0x00,0x2B, /* [4066] OBJ_setct_MeAqCInitResTBS */ -0x67,0x2A,0x00,0x2C, /* [4070] OBJ_setct_RegFormResTBS */ -0x67,0x2A,0x00,0x2D, /* [4074] OBJ_setct_CertReqData */ -0x67,0x2A,0x00,0x2E, /* [4078] OBJ_setct_CertReqTBS */ -0x67,0x2A,0x00,0x2F, /* [4082] OBJ_setct_CertResData */ -0x67,0x2A,0x00,0x30, /* [4086] OBJ_setct_CertInqReqTBS */ -0x67,0x2A,0x00,0x31, /* [4090] OBJ_setct_ErrorTBS */ -0x67,0x2A,0x00,0x32, /* [4094] OBJ_setct_PIDualSignedTBE */ -0x67,0x2A,0x00,0x33, /* [4098] OBJ_setct_PIUnsignedTBE */ -0x67,0x2A,0x00,0x34, /* [4102] OBJ_setct_AuthReqTBE */ -0x67,0x2A,0x00,0x35, /* [4106] OBJ_setct_AuthResTBE */ -0x67,0x2A,0x00,0x36, /* [4110] OBJ_setct_AuthResTBEX */ -0x67,0x2A,0x00,0x37, /* [4114] OBJ_setct_AuthTokenTBE */ -0x67,0x2A,0x00,0x38, /* [4118] OBJ_setct_CapTokenTBE */ -0x67,0x2A,0x00,0x39, /* [4122] OBJ_setct_CapTokenTBEX */ -0x67,0x2A,0x00,0x3A, /* [4126] OBJ_setct_AcqCardCodeMsgTBE */ -0x67,0x2A,0x00,0x3B, /* [4130] OBJ_setct_AuthRevReqTBE */ -0x67,0x2A,0x00,0x3C, /* [4134] OBJ_setct_AuthRevResTBE */ -0x67,0x2A,0x00,0x3D, /* [4138] OBJ_setct_AuthRevResTBEB */ -0x67,0x2A,0x00,0x3E, /* [4142] OBJ_setct_CapReqTBE */ -0x67,0x2A,0x00,0x3F, /* [4146] OBJ_setct_CapReqTBEX */ -0x67,0x2A,0x00,0x40, /* [4150] OBJ_setct_CapResTBE */ -0x67,0x2A,0x00,0x41, /* [4154] OBJ_setct_CapRevReqTBE */ -0x67,0x2A,0x00,0x42, /* [4158] OBJ_setct_CapRevReqTBEX */ -0x67,0x2A,0x00,0x43, /* [4162] OBJ_setct_CapRevResTBE */ -0x67,0x2A,0x00,0x44, /* [4166] OBJ_setct_CredReqTBE */ -0x67,0x2A,0x00,0x45, /* [4170] OBJ_setct_CredReqTBEX */ -0x67,0x2A,0x00,0x46, /* [4174] OBJ_setct_CredResTBE */ -0x67,0x2A,0x00,0x47, /* [4178] OBJ_setct_CredRevReqTBE */ -0x67,0x2A,0x00,0x48, /* [4182] OBJ_setct_CredRevReqTBEX */ -0x67,0x2A,0x00,0x49, /* [4186] OBJ_setct_CredRevResTBE */ -0x67,0x2A,0x00,0x4A, /* [4190] OBJ_setct_BatchAdminReqTBE */ -0x67,0x2A,0x00,0x4B, /* [4194] OBJ_setct_BatchAdminResTBE */ -0x67,0x2A,0x00,0x4C, /* [4198] OBJ_setct_RegFormReqTBE */ -0x67,0x2A,0x00,0x4D, /* [4202] OBJ_setct_CertReqTBE */ -0x67,0x2A,0x00,0x4E, /* [4206] OBJ_setct_CertReqTBEX */ -0x67,0x2A,0x00,0x4F, /* [4210] OBJ_setct_CertResTBE */ -0x67,0x2A,0x00,0x50, /* [4214] OBJ_setct_CRLNotificationTBS */ -0x67,0x2A,0x00,0x51, /* [4218] OBJ_setct_CRLNotificationResTBS */ -0x67,0x2A,0x00,0x52, /* [4222] OBJ_setct_BCIDistributionTBS */ -0x67,0x2A,0x01,0x01, /* [4226] OBJ_setext_genCrypt */ -0x67,0x2A,0x01,0x03, /* [4230] OBJ_setext_miAuth */ -0x67,0x2A,0x01,0x04, /* [4234] OBJ_setext_pinSecure */ -0x67,0x2A,0x01,0x05, /* [4238] OBJ_setext_pinAny */ -0x67,0x2A,0x01,0x07, /* [4242] OBJ_setext_track2 */ -0x67,0x2A,0x01,0x08, /* [4246] OBJ_setext_cv */ -0x67,0x2A,0x05,0x00, /* [4250] OBJ_set_policy_root */ -0x67,0x2A,0x07,0x00, /* [4254] OBJ_setCext_hashedRoot */ -0x67,0x2A,0x07,0x01, /* [4258] OBJ_setCext_certType */ -0x67,0x2A,0x07,0x02, /* [4262] OBJ_setCext_merchData */ -0x67,0x2A,0x07,0x03, /* [4266] OBJ_setCext_cCertRequired */ -0x67,0x2A,0x07,0x04, /* [4270] OBJ_setCext_tunneling */ -0x67,0x2A,0x07,0x05, /* [4274] OBJ_setCext_setExt */ -0x67,0x2A,0x07,0x06, /* [4278] OBJ_setCext_setQualf */ -0x67,0x2A,0x07,0x07, /* [4282] OBJ_setCext_PGWYcapabilities */ -0x67,0x2A,0x07,0x08, /* [4286] OBJ_setCext_TokenIdentifier */ -0x67,0x2A,0x07,0x09, /* [4290] OBJ_setCext_Track2Data */ -0x67,0x2A,0x07,0x0A, /* [4294] OBJ_setCext_TokenType */ -0x67,0x2A,0x07,0x0B, /* [4298] OBJ_setCext_IssuerCapabilities */ -0x67,0x2A,0x03,0x00, /* [4302] OBJ_setAttr_Cert */ -0x67,0x2A,0x03,0x01, /* [4306] OBJ_setAttr_PGWYcap */ -0x67,0x2A,0x03,0x02, /* [4310] OBJ_setAttr_TokenType */ -0x67,0x2A,0x03,0x03, /* [4314] OBJ_setAttr_IssCap */ -0x67,0x2A,0x03,0x00,0x00, /* [4318] OBJ_set_rootKeyThumb */ -0x67,0x2A,0x03,0x00,0x01, /* [4323] OBJ_set_addPolicy */ -0x67,0x2A,0x03,0x02,0x01, /* [4328] OBJ_setAttr_Token_EMV */ -0x67,0x2A,0x03,0x02,0x02, /* [4333] OBJ_setAttr_Token_B0Prime */ -0x67,0x2A,0x03,0x03,0x03, /* [4338] OBJ_setAttr_IssCap_CVM */ -0x67,0x2A,0x03,0x03,0x04, /* [4343] OBJ_setAttr_IssCap_T2 */ -0x67,0x2A,0x03,0x03,0x05, /* [4348] OBJ_setAttr_IssCap_Sig */ -0x67,0x2A,0x03,0x03,0x03,0x01, /* [4353] OBJ_setAttr_GenCryptgrm */ -0x67,0x2A,0x03,0x03,0x04,0x01, /* [4359] OBJ_setAttr_T2Enc */ -0x67,0x2A,0x03,0x03,0x04,0x02, /* [4365] OBJ_setAttr_T2cleartxt */ -0x67,0x2A,0x03,0x03,0x05,0x01, /* [4371] OBJ_setAttr_TokICCsig */ -0x67,0x2A,0x03,0x03,0x05,0x02, /* [4377] OBJ_setAttr_SecDevSig */ -0x67,0x2A,0x08,0x01, /* [4383] OBJ_set_brand_IATA_ATA */ -0x67,0x2A,0x08,0x1E, /* [4387] OBJ_set_brand_Diners */ -0x67,0x2A,0x08,0x22, /* [4391] OBJ_set_brand_AmericanExpress */ -0x67,0x2A,0x08,0x23, /* [4395] OBJ_set_brand_JCB */ -0x67,0x2A,0x08,0x04, /* [4399] OBJ_set_brand_Visa */ -0x67,0x2A,0x08,0x05, /* [4403] OBJ_set_brand_MasterCard */ -0x67,0x2A,0x08,0xAE,0x7B, /* [4407] OBJ_set_brand_Novus */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x03,0x0A, /* [4412] OBJ_des_cdmf */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x06,/* [4420] OBJ_rsaOAEPEncryptionSET */ -0x67, /* [4429] OBJ_international_organizations */ -0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x14,0x02,0x02,/* [4430] OBJ_ms_smartcard_login */ -0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x14,0x02,0x03,/* [4440] OBJ_ms_upn */ -0x55,0x04,0x09, /* [4450] OBJ_streetAddress */ -0x55,0x04,0x11, /* [4453] OBJ_postalCode */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x15, /* [4456] OBJ_id_ppl */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x0E, /* [4463] OBJ_proxyCertInfo */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x15,0x00, /* [4471] OBJ_id_ppl_anyLanguage */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x15,0x01, /* [4479] OBJ_id_ppl_inheritAll */ -0x55,0x1D,0x1E, /* [4487] OBJ_name_constraints */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x15,0x02, /* [4490] OBJ_Independent */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,/* [4498] OBJ_sha256WithRSAEncryption */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0C,/* [4507] OBJ_sha384WithRSAEncryption */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0D,/* [4516] OBJ_sha512WithRSAEncryption */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0E,/* [4525] OBJ_sha224WithRSAEncryption */ -0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x01,/* [4534] OBJ_sha256 */ -0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x02,/* [4543] OBJ_sha384 */ -0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x03,/* [4552] OBJ_sha512 */ -0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x04,/* [4561] OBJ_sha224 */ -0x2B, /* [4570] OBJ_identified_organization */ -0x2B,0x81,0x04, /* [4571] OBJ_certicom_arc */ -0x67,0x2B, /* [4574] OBJ_wap */ -0x67,0x2B,0x01, /* [4576] OBJ_wap_wsg */ -0x2A,0x86,0x48,0xCE,0x3D,0x01,0x02,0x03, /* [4579] OBJ_X9_62_id_characteristic_two_basis */ -0x2A,0x86,0x48,0xCE,0x3D,0x01,0x02,0x03,0x01,/* [4587] OBJ_X9_62_onBasis */ -0x2A,0x86,0x48,0xCE,0x3D,0x01,0x02,0x03,0x02,/* [4596] OBJ_X9_62_tpBasis */ -0x2A,0x86,0x48,0xCE,0x3D,0x01,0x02,0x03,0x03,/* [4605] OBJ_X9_62_ppBasis */ -0x2A,0x86,0x48,0xCE,0x3D,0x03,0x00,0x01, /* [4614] OBJ_X9_62_c2pnb163v1 */ -0x2A,0x86,0x48,0xCE,0x3D,0x03,0x00,0x02, /* [4622] OBJ_X9_62_c2pnb163v2 */ -0x2A,0x86,0x48,0xCE,0x3D,0x03,0x00,0x03, /* [4630] OBJ_X9_62_c2pnb163v3 */ -0x2A,0x86,0x48,0xCE,0x3D,0x03,0x00,0x04, /* [4638] OBJ_X9_62_c2pnb176v1 */ -0x2A,0x86,0x48,0xCE,0x3D,0x03,0x00,0x05, /* [4646] OBJ_X9_62_c2tnb191v1 */ -0x2A,0x86,0x48,0xCE,0x3D,0x03,0x00,0x06, /* [4654] OBJ_X9_62_c2tnb191v2 */ -0x2A,0x86,0x48,0xCE,0x3D,0x03,0x00,0x07, /* [4662] OBJ_X9_62_c2tnb191v3 */ -0x2A,0x86,0x48,0xCE,0x3D,0x03,0x00,0x08, /* [4670] OBJ_X9_62_c2onb191v4 */ -0x2A,0x86,0x48,0xCE,0x3D,0x03,0x00,0x09, /* [4678] OBJ_X9_62_c2onb191v5 */ -0x2A,0x86,0x48,0xCE,0x3D,0x03,0x00,0x0A, /* [4686] OBJ_X9_62_c2pnb208w1 */ -0x2A,0x86,0x48,0xCE,0x3D,0x03,0x00,0x0B, /* [4694] OBJ_X9_62_c2tnb239v1 */ -0x2A,0x86,0x48,0xCE,0x3D,0x03,0x00,0x0C, /* [4702] OBJ_X9_62_c2tnb239v2 */ -0x2A,0x86,0x48,0xCE,0x3D,0x03,0x00,0x0D, /* [4710] OBJ_X9_62_c2tnb239v3 */ -0x2A,0x86,0x48,0xCE,0x3D,0x03,0x00,0x0E, /* [4718] OBJ_X9_62_c2onb239v4 */ -0x2A,0x86,0x48,0xCE,0x3D,0x03,0x00,0x0F, /* [4726] OBJ_X9_62_c2onb239v5 */ -0x2A,0x86,0x48,0xCE,0x3D,0x03,0x00,0x10, /* [4734] OBJ_X9_62_c2pnb272w1 */ -0x2A,0x86,0x48,0xCE,0x3D,0x03,0x00,0x11, /* [4742] OBJ_X9_62_c2pnb304w1 */ -0x2A,0x86,0x48,0xCE,0x3D,0x03,0x00,0x12, /* [4750] OBJ_X9_62_c2tnb359v1 */ -0x2A,0x86,0x48,0xCE,0x3D,0x03,0x00,0x13, /* [4758] OBJ_X9_62_c2pnb368w1 */ -0x2A,0x86,0x48,0xCE,0x3D,0x03,0x00,0x14, /* [4766] OBJ_X9_62_c2tnb431r1 */ -0x2B,0x81,0x04,0x00,0x06, /* [4774] OBJ_secp112r1 */ -0x2B,0x81,0x04,0x00,0x07, /* [4779] OBJ_secp112r2 */ -0x2B,0x81,0x04,0x00,0x1C, /* [4784] OBJ_secp128r1 */ -0x2B,0x81,0x04,0x00,0x1D, /* [4789] OBJ_secp128r2 */ -0x2B,0x81,0x04,0x00,0x09, /* [4794] OBJ_secp160k1 */ -0x2B,0x81,0x04,0x00,0x08, /* [4799] OBJ_secp160r1 */ -0x2B,0x81,0x04,0x00,0x1E, /* [4804] OBJ_secp160r2 */ -0x2B,0x81,0x04,0x00,0x1F, /* [4809] OBJ_secp192k1 */ -0x2B,0x81,0x04,0x00,0x20, /* [4814] OBJ_secp224k1 */ -0x2B,0x81,0x04,0x00,0x21, /* [4819] OBJ_secp224r1 */ -0x2B,0x81,0x04,0x00,0x0A, /* [4824] OBJ_secp256k1 */ -0x2B,0x81,0x04,0x00,0x22, /* [4829] OBJ_secp384r1 */ -0x2B,0x81,0x04,0x00,0x23, /* [4834] OBJ_secp521r1 */ -0x2B,0x81,0x04,0x00,0x04, /* [4839] OBJ_sect113r1 */ -0x2B,0x81,0x04,0x00,0x05, /* [4844] OBJ_sect113r2 */ -0x2B,0x81,0x04,0x00,0x16, /* [4849] OBJ_sect131r1 */ -0x2B,0x81,0x04,0x00,0x17, /* [4854] OBJ_sect131r2 */ -0x2B,0x81,0x04,0x00,0x01, /* [4859] OBJ_sect163k1 */ -0x2B,0x81,0x04,0x00,0x02, /* [4864] OBJ_sect163r1 */ -0x2B,0x81,0x04,0x00,0x0F, /* [4869] OBJ_sect163r2 */ -0x2B,0x81,0x04,0x00,0x18, /* [4874] OBJ_sect193r1 */ -0x2B,0x81,0x04,0x00,0x19, /* [4879] OBJ_sect193r2 */ -0x2B,0x81,0x04,0x00,0x1A, /* [4884] OBJ_sect233k1 */ -0x2B,0x81,0x04,0x00,0x1B, /* [4889] OBJ_sect233r1 */ -0x2B,0x81,0x04,0x00,0x03, /* [4894] OBJ_sect239k1 */ -0x2B,0x81,0x04,0x00,0x10, /* [4899] OBJ_sect283k1 */ -0x2B,0x81,0x04,0x00,0x11, /* [4904] OBJ_sect283r1 */ -0x2B,0x81,0x04,0x00,0x24, /* [4909] OBJ_sect409k1 */ -0x2B,0x81,0x04,0x00,0x25, /* [4914] OBJ_sect409r1 */ -0x2B,0x81,0x04,0x00,0x26, /* [4919] OBJ_sect571k1 */ -0x2B,0x81,0x04,0x00,0x27, /* [4924] OBJ_sect571r1 */ -0x67,0x2B,0x01,0x04,0x01, /* [4929] OBJ_wap_wsg_idm_ecid_wtls1 */ -0x67,0x2B,0x01,0x04,0x03, /* [4934] OBJ_wap_wsg_idm_ecid_wtls3 */ -0x67,0x2B,0x01,0x04,0x04, /* [4939] OBJ_wap_wsg_idm_ecid_wtls4 */ -0x67,0x2B,0x01,0x04,0x05, /* [4944] OBJ_wap_wsg_idm_ecid_wtls5 */ -0x67,0x2B,0x01,0x04,0x06, /* [4949] OBJ_wap_wsg_idm_ecid_wtls6 */ -0x67,0x2B,0x01,0x04,0x07, /* [4954] OBJ_wap_wsg_idm_ecid_wtls7 */ -0x67,0x2B,0x01,0x04,0x08, /* [4959] OBJ_wap_wsg_idm_ecid_wtls8 */ -0x67,0x2B,0x01,0x04,0x09, /* [4964] OBJ_wap_wsg_idm_ecid_wtls9 */ -0x67,0x2B,0x01,0x04,0x0A, /* [4969] OBJ_wap_wsg_idm_ecid_wtls10 */ -0x67,0x2B,0x01,0x04,0x0B, /* [4974] OBJ_wap_wsg_idm_ecid_wtls11 */ -0x67,0x2B,0x01,0x04,0x0C, /* [4979] OBJ_wap_wsg_idm_ecid_wtls12 */ -0x55,0x1D,0x20,0x00, /* [4984] OBJ_any_policy */ -0x55,0x1D,0x21, /* [4988] OBJ_policy_mappings */ -0x55,0x1D,0x36, /* [4991] OBJ_inhibit_any_policy */ -0x2A,0x83,0x08,0x8C,0x9A,0x4B,0x3D,0x01,0x01,0x01,0x02,/* [4994] OBJ_camellia_128_cbc */ -0x2A,0x83,0x08,0x8C,0x9A,0x4B,0x3D,0x01,0x01,0x01,0x03,/* [5005] OBJ_camellia_192_cbc */ -0x2A,0x83,0x08,0x8C,0x9A,0x4B,0x3D,0x01,0x01,0x01,0x04,/* [5016] OBJ_camellia_256_cbc */ -0x03,0xA2,0x31,0x05,0x03,0x01,0x09,0x01, /* [5027] OBJ_camellia_128_ecb */ -0x03,0xA2,0x31,0x05,0x03,0x01,0x09,0x15, /* [5035] OBJ_camellia_192_ecb */ -0x03,0xA2,0x31,0x05,0x03,0x01,0x09,0x29, /* [5043] OBJ_camellia_256_ecb */ -0x03,0xA2,0x31,0x05,0x03,0x01,0x09,0x04, /* [5051] OBJ_camellia_128_cfb128 */ -0x03,0xA2,0x31,0x05,0x03,0x01,0x09,0x18, /* [5059] OBJ_camellia_192_cfb128 */ -0x03,0xA2,0x31,0x05,0x03,0x01,0x09,0x2C, /* [5067] OBJ_camellia_256_cfb128 */ -0x03,0xA2,0x31,0x05,0x03,0x01,0x09,0x03, /* [5075] OBJ_camellia_128_ofb128 */ -0x03,0xA2,0x31,0x05,0x03,0x01,0x09,0x17, /* [5083] OBJ_camellia_192_ofb128 */ -0x03,0xA2,0x31,0x05,0x03,0x01,0x09,0x2B, /* [5091] OBJ_camellia_256_ofb128 */ -0x55,0x1D,0x09, /* [5099] OBJ_subject_directory_attributes */ -0x55,0x1D,0x1C, /* [5102] OBJ_issuing_distribution_point */ -0x55,0x1D,0x1D, /* [5105] OBJ_certificate_issuer */ -0x2A,0x83,0x1A,0x8C,0x9A,0x44, /* [5108] OBJ_kisa */ -0x2A,0x83,0x1A,0x8C,0x9A,0x44,0x01,0x03, /* [5114] OBJ_seed_ecb */ -0x2A,0x83,0x1A,0x8C,0x9A,0x44,0x01,0x04, /* [5122] OBJ_seed_cbc */ -0x2A,0x83,0x1A,0x8C,0x9A,0x44,0x01,0x06, /* [5130] OBJ_seed_ofb128 */ -0x2A,0x83,0x1A,0x8C,0x9A,0x44,0x01,0x05, /* [5138] OBJ_seed_cfb128 */ -0x2B,0x06,0x01,0x05,0x05,0x08,0x01,0x01, /* [5146] OBJ_hmac_md5 */ -0x2B,0x06,0x01,0x05,0x05,0x08,0x01,0x02, /* [5154] OBJ_hmac_sha1 */ -0x2A,0x86,0x48,0x86,0xF6,0x7D,0x07,0x42,0x0D,/* [5162] OBJ_id_PasswordBasedMAC */ -0x2A,0x86,0x48,0x86,0xF6,0x7D,0x07,0x42,0x1E,/* [5171] OBJ_id_DHBasedMac */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x04,0x10, /* [5180] OBJ_id_it_suppLangTags */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x05, /* [5188] OBJ_caRepository */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x01,0x09,/* [5196] OBJ_id_smime_ct_compressedData */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x01,0x1B,/* [5207] OBJ_id_ct_asciiTextWithCRLF */ -0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x05,/* [5218] OBJ_id_aes128_wrap */ -0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x19,/* [5227] OBJ_id_aes192_wrap */ -0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x2D,/* [5236] OBJ_id_aes256_wrap */ -0x2A,0x86,0x48,0xCE,0x3D,0x04,0x02, /* [5245] OBJ_ecdsa_with_Recommended */ -0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03, /* [5252] OBJ_ecdsa_with_Specified */ -0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x01, /* [5259] OBJ_ecdsa_with_SHA224 */ -0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x02, /* [5267] OBJ_ecdsa_with_SHA256 */ -0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x03, /* [5275] OBJ_ecdsa_with_SHA384 */ -0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x04, /* [5283] OBJ_ecdsa_with_SHA512 */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x02,0x06, /* [5291] OBJ_hmacWithMD5 */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x02,0x08, /* [5299] OBJ_hmacWithSHA224 */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x02,0x09, /* [5307] OBJ_hmacWithSHA256 */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x02,0x0A, /* [5315] OBJ_hmacWithSHA384 */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x02,0x0B, /* [5323] OBJ_hmacWithSHA512 */ -0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x03,0x01,/* [5331] OBJ_dsa_with_SHA224 */ -0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x03,0x02,/* [5340] OBJ_dsa_with_SHA256 */ -0x28,0xCF,0x06,0x03,0x00,0x37, /* [5349] OBJ_whirlpool */ -0x2A,0x85,0x03,0x02,0x02, /* [5355] OBJ_cryptopro */ -0x2A,0x85,0x03,0x02,0x09, /* [5360] OBJ_cryptocom */ -0x2A,0x85,0x03,0x02,0x02,0x03, /* [5365] OBJ_id_GostR3411_94_with_GostR3410_2001 */ -0x2A,0x85,0x03,0x02,0x02,0x04, /* [5371] OBJ_id_GostR3411_94_with_GostR3410_94 */ -0x2A,0x85,0x03,0x02,0x02,0x09, /* [5377] OBJ_id_GostR3411_94 */ -0x2A,0x85,0x03,0x02,0x02,0x0A, /* [5383] OBJ_id_HMACGostR3411_94 */ -0x2A,0x85,0x03,0x02,0x02,0x13, /* [5389] OBJ_id_GostR3410_2001 */ -0x2A,0x85,0x03,0x02,0x02,0x14, /* [5395] OBJ_id_GostR3410_94 */ -0x2A,0x85,0x03,0x02,0x02,0x15, /* [5401] OBJ_id_Gost28147_89 */ -0x2A,0x85,0x03,0x02,0x02,0x16, /* [5407] OBJ_id_Gost28147_89_MAC */ -0x2A,0x85,0x03,0x02,0x02,0x17, /* [5413] OBJ_id_GostR3411_94_prf */ -0x2A,0x85,0x03,0x02,0x02,0x62, /* [5419] OBJ_id_GostR3410_2001DH */ -0x2A,0x85,0x03,0x02,0x02,0x63, /* [5425] OBJ_id_GostR3410_94DH */ -0x2A,0x85,0x03,0x02,0x02,0x0E,0x01, /* [5431] OBJ_id_Gost28147_89_CryptoPro_KeyMeshing */ -0x2A,0x85,0x03,0x02,0x02,0x0E,0x00, /* [5438] OBJ_id_Gost28147_89_None_KeyMeshing */ -0x2A,0x85,0x03,0x02,0x02,0x1E,0x00, /* [5445] OBJ_id_GostR3411_94_TestParamSet */ -0x2A,0x85,0x03,0x02,0x02,0x1E,0x01, /* [5452] OBJ_id_GostR3411_94_CryptoProParamSet */ -0x2A,0x85,0x03,0x02,0x02,0x1F,0x00, /* [5459] OBJ_id_Gost28147_89_TestParamSet */ -0x2A,0x85,0x03,0x02,0x02,0x1F,0x01, /* [5466] OBJ_id_Gost28147_89_CryptoPro_A_ParamSet */ -0x2A,0x85,0x03,0x02,0x02,0x1F,0x02, /* [5473] OBJ_id_Gost28147_89_CryptoPro_B_ParamSet */ -0x2A,0x85,0x03,0x02,0x02,0x1F,0x03, /* [5480] OBJ_id_Gost28147_89_CryptoPro_C_ParamSet */ -0x2A,0x85,0x03,0x02,0x02,0x1F,0x04, /* [5487] OBJ_id_Gost28147_89_CryptoPro_D_ParamSet */ -0x2A,0x85,0x03,0x02,0x02,0x1F,0x05, /* [5494] OBJ_id_Gost28147_89_CryptoPro_Oscar_1_1_ParamSet */ -0x2A,0x85,0x03,0x02,0x02,0x1F,0x06, /* [5501] OBJ_id_Gost28147_89_CryptoPro_Oscar_1_0_ParamSet */ -0x2A,0x85,0x03,0x02,0x02,0x1F,0x07, /* [5508] OBJ_id_Gost28147_89_CryptoPro_RIC_1_ParamSet */ -0x2A,0x85,0x03,0x02,0x02,0x20,0x00, /* [5515] OBJ_id_GostR3410_94_TestParamSet */ -0x2A,0x85,0x03,0x02,0x02,0x20,0x02, /* [5522] OBJ_id_GostR3410_94_CryptoPro_A_ParamSet */ -0x2A,0x85,0x03,0x02,0x02,0x20,0x03, /* [5529] OBJ_id_GostR3410_94_CryptoPro_B_ParamSet */ -0x2A,0x85,0x03,0x02,0x02,0x20,0x04, /* [5536] OBJ_id_GostR3410_94_CryptoPro_C_ParamSet */ -0x2A,0x85,0x03,0x02,0x02,0x20,0x05, /* [5543] OBJ_id_GostR3410_94_CryptoPro_D_ParamSet */ -0x2A,0x85,0x03,0x02,0x02,0x21,0x01, /* [5550] OBJ_id_GostR3410_94_CryptoPro_XchA_ParamSet */ -0x2A,0x85,0x03,0x02,0x02,0x21,0x02, /* [5557] OBJ_id_GostR3410_94_CryptoPro_XchB_ParamSet */ -0x2A,0x85,0x03,0x02,0x02,0x21,0x03, /* [5564] OBJ_id_GostR3410_94_CryptoPro_XchC_ParamSet */ -0x2A,0x85,0x03,0x02,0x02,0x23,0x00, /* [5571] OBJ_id_GostR3410_2001_TestParamSet */ -0x2A,0x85,0x03,0x02,0x02,0x23,0x01, /* [5578] OBJ_id_GostR3410_2001_CryptoPro_A_ParamSet */ -0x2A,0x85,0x03,0x02,0x02,0x23,0x02, /* [5585] OBJ_id_GostR3410_2001_CryptoPro_B_ParamSet */ -0x2A,0x85,0x03,0x02,0x02,0x23,0x03, /* [5592] OBJ_id_GostR3410_2001_CryptoPro_C_ParamSet */ -0x2A,0x85,0x03,0x02,0x02,0x24,0x00, /* [5599] OBJ_id_GostR3410_2001_CryptoPro_XchA_ParamSet */ -0x2A,0x85,0x03,0x02,0x02,0x24,0x01, /* [5606] OBJ_id_GostR3410_2001_CryptoPro_XchB_ParamSet */ -0x2A,0x85,0x03,0x02,0x02,0x14,0x01, /* [5613] OBJ_id_GostR3410_94_a */ -0x2A,0x85,0x03,0x02,0x02,0x14,0x02, /* [5620] OBJ_id_GostR3410_94_aBis */ -0x2A,0x85,0x03,0x02,0x02,0x14,0x03, /* [5627] OBJ_id_GostR3410_94_b */ -0x2A,0x85,0x03,0x02,0x02,0x14,0x04, /* [5634] OBJ_id_GostR3410_94_bBis */ -0x2A,0x85,0x03,0x02,0x09,0x01,0x06,0x01, /* [5641] OBJ_id_Gost28147_89_cc */ -0x2A,0x85,0x03,0x02,0x09,0x01,0x05,0x03, /* [5649] OBJ_id_GostR3410_94_cc */ -0x2A,0x85,0x03,0x02,0x09,0x01,0x05,0x04, /* [5657] OBJ_id_GostR3410_2001_cc */ -0x2A,0x85,0x03,0x02,0x09,0x01,0x03,0x03, /* [5665] OBJ_id_GostR3411_94_with_GostR3410_94_cc */ -0x2A,0x85,0x03,0x02,0x09,0x01,0x03,0x04, /* [5673] OBJ_id_GostR3411_94_with_GostR3410_2001_cc */ -0x2A,0x85,0x03,0x02,0x09,0x01,0x08,0x01, /* [5681] OBJ_id_GostR3410_2001_ParamSet_cc */ -0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x11,0x02,/* [5689] OBJ_LocalKeySet */ -0x55,0x1D,0x2E, /* [5698] OBJ_freshest_crl */ -0x2B,0x06,0x01,0x05,0x05,0x07,0x08,0x03, /* [5701] OBJ_id_on_permanentIdentifier */ -0x55,0x04,0x0E, /* [5709] OBJ_searchGuide */ -0x55,0x04,0x0F, /* [5712] OBJ_businessCategory */ -0x55,0x04,0x10, /* [5715] OBJ_postalAddress */ -0x55,0x04,0x12, /* [5718] OBJ_postOfficeBox */ -0x55,0x04,0x13, /* [5721] OBJ_physicalDeliveryOfficeName */ -0x55,0x04,0x14, /* [5724] OBJ_telephoneNumber */ -0x55,0x04,0x15, /* [5727] OBJ_telexNumber */ -0x55,0x04,0x16, /* [5730] OBJ_teletexTerminalIdentifier */ -0x55,0x04,0x17, /* [5733] OBJ_facsimileTelephoneNumber */ -0x55,0x04,0x18, /* [5736] OBJ_x121Address */ -0x55,0x04,0x19, /* [5739] OBJ_internationaliSDNNumber */ -0x55,0x04,0x1A, /* [5742] OBJ_registeredAddress */ -0x55,0x04,0x1B, /* [5745] OBJ_destinationIndicator */ -0x55,0x04,0x1C, /* [5748] OBJ_preferredDeliveryMethod */ -0x55,0x04,0x1D, /* [5751] OBJ_presentationAddress */ -0x55,0x04,0x1E, /* [5754] OBJ_supportedApplicationContext */ -0x55,0x04,0x1F, /* [5757] OBJ_member */ -0x55,0x04,0x20, /* [5760] OBJ_owner */ -0x55,0x04,0x21, /* [5763] OBJ_roleOccupant */ -0x55,0x04,0x22, /* [5766] OBJ_seeAlso */ -0x55,0x04,0x23, /* [5769] OBJ_userPassword */ -0x55,0x04,0x24, /* [5772] OBJ_userCertificate */ -0x55,0x04,0x25, /* [5775] OBJ_cACertificate */ -0x55,0x04,0x26, /* [5778] OBJ_authorityRevocationList */ -0x55,0x04,0x27, /* [5781] OBJ_certificateRevocationList */ -0x55,0x04,0x28, /* [5784] OBJ_crossCertificatePair */ -0x55,0x04,0x2F, /* [5787] OBJ_enhancedSearchGuide */ -0x55,0x04,0x30, /* [5790] OBJ_protocolInformation */ -0x55,0x04,0x31, /* [5793] OBJ_distinguishedName */ -0x55,0x04,0x32, /* [5796] OBJ_uniqueMember */ -0x55,0x04,0x33, /* [5799] OBJ_houseIdentifier */ -0x55,0x04,0x34, /* [5802] OBJ_supportedAlgorithms */ -0x55,0x04,0x35, /* [5805] OBJ_deltaRevocationList */ -0x55,0x04,0x36, /* [5808] OBJ_dmdName */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x03,0x09,/* [5811] OBJ_id_alg_PWRI_KEK */ -0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x06,/* [5822] OBJ_aes_128_gcm */ -0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x07,/* [5831] OBJ_aes_128_ccm */ -0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x08,/* [5840] OBJ_id_aes128_wrap_pad */ -0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x1A,/* [5849] OBJ_aes_192_gcm */ -0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x1B,/* [5858] OBJ_aes_192_ccm */ -0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x1C,/* [5867] OBJ_id_aes192_wrap_pad */ -0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x2E,/* [5876] OBJ_aes_256_gcm */ -0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x2F,/* [5885] OBJ_aes_256_ccm */ -0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x30,/* [5894] OBJ_id_aes256_wrap_pad */ -0x2A,0x83,0x08,0x8C,0x9A,0x4B,0x3D,0x01,0x01,0x03,0x02,/* [5903] OBJ_id_camellia128_wrap */ -0x2A,0x83,0x08,0x8C,0x9A,0x4B,0x3D,0x01,0x01,0x03,0x03,/* [5914] OBJ_id_camellia192_wrap */ -0x2A,0x83,0x08,0x8C,0x9A,0x4B,0x3D,0x01,0x01,0x03,0x04,/* [5925] OBJ_id_camellia256_wrap */ -0x55,0x1D,0x25,0x00, /* [5936] OBJ_anyExtendedKeyUsage */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x08,/* [5940] OBJ_mgf1 */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0A,/* [5949] OBJ_rsassaPss */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x07,/* [5958] OBJ_rsaesOaep */ -0x2A,0x86,0x48,0xCE,0x3E,0x02,0x01, /* [5967] OBJ_dhpublicnumber */ -0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x01,/* [5974] OBJ_brainpoolP160r1 */ -0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x02,/* [5983] OBJ_brainpoolP160t1 */ -0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x03,/* [5992] OBJ_brainpoolP192r1 */ -0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x04,/* [6001] OBJ_brainpoolP192t1 */ -0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x05,/* [6010] OBJ_brainpoolP224r1 */ -0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x06,/* [6019] OBJ_brainpoolP224t1 */ -0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x07,/* [6028] OBJ_brainpoolP256r1 */ -0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x08,/* [6037] OBJ_brainpoolP256t1 */ -0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x09,/* [6046] OBJ_brainpoolP320r1 */ -0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x0A,/* [6055] OBJ_brainpoolP320t1 */ -0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x0B,/* [6064] OBJ_brainpoolP384r1 */ -0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x0C,/* [6073] OBJ_brainpoolP384t1 */ -0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x0D,/* [6082] OBJ_brainpoolP512r1 */ -0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x0E,/* [6091] OBJ_brainpoolP512t1 */ -0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x09,/* [6100] OBJ_pSpecified */ -0x2B,0x81,0x05,0x10,0x86,0x48,0x3F,0x00,0x02,/* [6109] OBJ_dhSinglePass_stdDH_sha1kdf_scheme */ -0x2B,0x81,0x04,0x01,0x0B,0x00, /* [6118] OBJ_dhSinglePass_stdDH_sha224kdf_scheme */ -0x2B,0x81,0x04,0x01,0x0B,0x01, /* [6124] OBJ_dhSinglePass_stdDH_sha256kdf_scheme */ -0x2B,0x81,0x04,0x01,0x0B,0x02, /* [6130] OBJ_dhSinglePass_stdDH_sha384kdf_scheme */ -0x2B,0x81,0x04,0x01,0x0B,0x03, /* [6136] OBJ_dhSinglePass_stdDH_sha512kdf_scheme */ -0x2B,0x81,0x05,0x10,0x86,0x48,0x3F,0x00,0x03,/* [6142] OBJ_dhSinglePass_cofactorDH_sha1kdf_scheme */ -0x2B,0x81,0x04,0x01,0x0E,0x00, /* [6151] OBJ_dhSinglePass_cofactorDH_sha224kdf_scheme */ -0x2B,0x81,0x04,0x01,0x0E,0x01, /* [6157] OBJ_dhSinglePass_cofactorDH_sha256kdf_scheme */ -0x2B,0x81,0x04,0x01,0x0E,0x02, /* [6163] OBJ_dhSinglePass_cofactorDH_sha384kdf_scheme */ -0x2B,0x81,0x04,0x01,0x0E,0x03, /* [6169] OBJ_dhSinglePass_cofactorDH_sha512kdf_scheme */ +static const uint8_t kObjectData[] = { + /* NID_rsadsi */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + /* NID_pkcs */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, + /* NID_md2 */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x02, + /* NID_md5 */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05, + /* NID_rc4 */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x03, 0x04, + /* NID_rsaEncryption */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, + /* NID_md2WithRSAEncryption */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x02, + /* NID_md5WithRSAEncryption */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x04, + /* NID_pbeWithMD2AndDES_CBC */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x05, 0x01, + /* NID_pbeWithMD5AndDES_CBC */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x05, 0x03, + /* NID_X500 */ + 0x55, + /* NID_X509 */ + 0x55, 0x04, + /* NID_commonName */ + 0x55, 0x04, 0x03, + /* NID_countryName */ + 0x55, 0x04, 0x06, + /* NID_localityName */ + 0x55, 0x04, 0x07, + /* NID_stateOrProvinceName */ + 0x55, 0x04, 0x08, + /* NID_organizationName */ + 0x55, 0x04, 0x0a, + /* NID_organizationalUnitName */ + 0x55, 0x04, 0x0b, + /* NID_rsa */ + 0x55, 0x08, 0x01, 0x01, + /* NID_pkcs7 */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, + /* NID_pkcs7_data */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, + /* NID_pkcs7_signed */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, + /* NID_pkcs7_enveloped */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x03, + /* NID_pkcs7_signedAndEnveloped */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x04, + /* NID_pkcs7_digest */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x05, + /* NID_pkcs7_encrypted */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x06, + /* NID_pkcs3 */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x03, + /* NID_dhKeyAgreement */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x03, 0x01, + /* NID_des_ecb */ + 0x2b, 0x0e, 0x03, 0x02, 0x06, + /* NID_des_cfb64 */ + 0x2b, 0x0e, 0x03, 0x02, 0x09, + /* NID_des_cbc */ + 0x2b, 0x0e, 0x03, 0x02, 0x07, + /* NID_des_ede_ecb */ + 0x2b, 0x0e, 0x03, 0x02, 0x11, + /* NID_idea_cbc */ + 0x2b, 0x06, 0x01, 0x04, 0x01, 0x81, 0x3c, 0x07, 0x01, 0x01, 0x02, + /* NID_rc2_cbc */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x03, 0x02, + /* NID_sha */ + 0x2b, 0x0e, 0x03, 0x02, 0x12, + /* NID_shaWithRSAEncryption */ + 0x2b, 0x0e, 0x03, 0x02, 0x0f, + /* NID_des_ede3_cbc */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x03, 0x07, + /* NID_des_ofb64 */ + 0x2b, 0x0e, 0x03, 0x02, 0x08, + /* NID_pkcs9 */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, + /* NID_pkcs9_emailAddress */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, + /* NID_pkcs9_unstructuredName */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x02, + /* NID_pkcs9_contentType */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x03, + /* NID_pkcs9_messageDigest */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x04, + /* NID_pkcs9_signingTime */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x05, + /* NID_pkcs9_countersignature */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x06, + /* NID_pkcs9_challengePassword */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x07, + /* NID_pkcs9_unstructuredAddress */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x08, + /* NID_pkcs9_extCertAttributes */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x09, + /* NID_netscape */ + 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, + /* NID_netscape_cert_extension */ + 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x01, + /* NID_netscape_data_type */ + 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x02, + /* NID_sha1 */ + 0x2b, 0x0e, 0x03, 0x02, 0x1a, + /* NID_sha1WithRSAEncryption */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, + /* NID_dsaWithSHA */ + 0x2b, 0x0e, 0x03, 0x02, 0x0d, + /* NID_dsa_2 */ + 0x2b, 0x0e, 0x03, 0x02, 0x0c, + /* NID_pbeWithSHA1AndRC2_CBC */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x05, 0x0b, + /* NID_id_pbkdf2 */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x05, 0x0c, + /* NID_dsaWithSHA1_2 */ + 0x2b, 0x0e, 0x03, 0x02, 0x1b, + /* NID_netscape_cert_type */ + 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x01, 0x01, + /* NID_netscape_base_url */ + 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x01, 0x02, + /* NID_netscape_revocation_url */ + 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x01, 0x03, + /* NID_netscape_ca_revocation_url */ + 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x01, 0x04, + /* NID_netscape_renewal_url */ + 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x01, 0x07, + /* NID_netscape_ca_policy_url */ + 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x01, 0x08, + /* NID_netscape_ssl_server_name */ + 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x01, 0x0c, + /* NID_netscape_comment */ + 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x01, 0x0d, + /* NID_netscape_cert_sequence */ + 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x02, 0x05, + /* NID_id_ce */ + 0x55, 0x1d, + /* NID_subject_key_identifier */ + 0x55, 0x1d, 0x0e, + /* NID_key_usage */ + 0x55, 0x1d, 0x0f, + /* NID_private_key_usage_period */ + 0x55, 0x1d, 0x10, + /* NID_subject_alt_name */ + 0x55, 0x1d, 0x11, + /* NID_issuer_alt_name */ + 0x55, 0x1d, 0x12, + /* NID_basic_constraints */ + 0x55, 0x1d, 0x13, + /* NID_crl_number */ + 0x55, 0x1d, 0x14, + /* NID_certificate_policies */ + 0x55, 0x1d, 0x20, + /* NID_authority_key_identifier */ + 0x55, 0x1d, 0x23, + /* NID_bf_cbc */ + 0x2b, 0x06, 0x01, 0x04, 0x01, 0x97, 0x55, 0x01, 0x02, + /* NID_mdc2 */ + 0x55, 0x08, 0x03, 0x65, + /* NID_mdc2WithRSA */ + 0x55, 0x08, 0x03, 0x64, + /* NID_givenName */ + 0x55, 0x04, 0x2a, + /* NID_surname */ + 0x55, 0x04, 0x04, + /* NID_initials */ + 0x55, 0x04, 0x2b, + /* NID_crl_distribution_points */ + 0x55, 0x1d, 0x1f, + /* NID_md5WithRSA */ + 0x2b, 0x0e, 0x03, 0x02, 0x03, + /* NID_serialNumber */ + 0x55, 0x04, 0x05, + /* NID_title */ + 0x55, 0x04, 0x0c, + /* NID_description */ + 0x55, 0x04, 0x0d, + /* NID_cast5_cbc */ + 0x2a, 0x86, 0x48, 0x86, 0xf6, 0x7d, 0x07, 0x42, 0x0a, + /* NID_pbeWithMD5AndCast5_CBC */ + 0x2a, 0x86, 0x48, 0x86, 0xf6, 0x7d, 0x07, 0x42, 0x0c, + /* NID_dsaWithSHA1 */ + 0x2a, 0x86, 0x48, 0xce, 0x38, 0x04, 0x03, + /* NID_sha1WithRSA */ + 0x2b, 0x0e, 0x03, 0x02, 0x1d, + /* NID_dsa */ + 0x2a, 0x86, 0x48, 0xce, 0x38, 0x04, 0x01, + /* NID_ripemd160 */ + 0x2b, 0x24, 0x03, 0x02, 0x01, + /* NID_ripemd160WithRSA */ + 0x2b, 0x24, 0x03, 0x03, 0x01, 0x02, + /* NID_rc5_cbc */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x03, 0x08, + /* NID_zlib_compression */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x03, 0x08, + /* NID_ext_key_usage */ + 0x55, 0x1d, 0x25, + /* NID_id_pkix */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, + /* NID_id_kp */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, + /* NID_server_auth */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, + /* NID_client_auth */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, + /* NID_code_sign */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x03, + /* NID_email_protect */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x04, + /* NID_time_stamp */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x08, + /* NID_ms_code_ind */ + 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x02, 0x01, 0x15, + /* NID_ms_code_com */ + 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x02, 0x01, 0x16, + /* NID_ms_ctl_sign */ + 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x0a, 0x03, 0x01, + /* NID_ms_sgc */ + 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x0a, 0x03, 0x03, + /* NID_ms_efs */ + 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x0a, 0x03, 0x04, + /* NID_ns_sgc */ + 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x04, 0x01, + /* NID_delta_crl */ + 0x55, 0x1d, 0x1b, + /* NID_crl_reason */ + 0x55, 0x1d, 0x15, + /* NID_invalidity_date */ + 0x55, 0x1d, 0x18, + /* NID_sxnet */ + 0x2b, 0x65, 0x01, 0x04, 0x01, + /* NID_pbe_WithSHA1And128BitRC4 */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x01, 0x01, + /* NID_pbe_WithSHA1And40BitRC4 */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x01, 0x02, + /* NID_pbe_WithSHA1And3_Key_TripleDES_CBC */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x01, 0x03, + /* NID_pbe_WithSHA1And2_Key_TripleDES_CBC */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x01, 0x04, + /* NID_pbe_WithSHA1And128BitRC2_CBC */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x01, 0x05, + /* NID_pbe_WithSHA1And40BitRC2_CBC */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x01, 0x06, + /* NID_keyBag */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x0a, 0x01, 0x01, + /* NID_pkcs8ShroudedKeyBag */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x0a, 0x01, 0x02, + /* NID_certBag */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x0a, 0x01, 0x03, + /* NID_crlBag */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x0a, 0x01, 0x04, + /* NID_secretBag */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x0a, 0x01, 0x05, + /* NID_safeContentsBag */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x0a, 0x01, 0x06, + /* NID_friendlyName */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x14, + /* NID_localKeyID */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x15, + /* NID_x509Certificate */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x16, 0x01, + /* NID_sdsiCertificate */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x16, 0x02, + /* NID_x509Crl */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x17, 0x01, + /* NID_pbes2 */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x05, 0x0d, + /* NID_pbmac1 */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x05, 0x0e, + /* NID_hmacWithSHA1 */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x07, + /* NID_id_qt_cps */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, + /* NID_id_qt_unotice */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x02, + /* NID_SMIMECapabilities */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x0f, + /* NID_pbeWithMD2AndRC2_CBC */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x05, 0x04, + /* NID_pbeWithMD5AndRC2_CBC */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x05, 0x06, + /* NID_pbeWithSHA1AndDES_CBC */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x05, 0x0a, + /* NID_ms_ext_req */ + 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x02, 0x01, 0x0e, + /* NID_ext_req */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x0e, + /* NID_name */ + 0x55, 0x04, 0x29, + /* NID_dnQualifier */ + 0x55, 0x04, 0x2e, + /* NID_id_pe */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, + /* NID_id_ad */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, + /* NID_info_access */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, + /* NID_ad_OCSP */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, + /* NID_ad_ca_issuers */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x02, + /* NID_OCSP_sign */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x09, + /* NID_member_body */ + 0x2a, + /* NID_ISO_US */ + 0x2a, 0x86, 0x48, + /* NID_X9_57 */ + 0x2a, 0x86, 0x48, 0xce, 0x38, + /* NID_X9cm */ + 0x2a, 0x86, 0x48, 0xce, 0x38, 0x04, + /* NID_pkcs1 */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, + /* NID_pkcs5 */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x05, + /* NID_SMIME */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, + /* NID_id_smime_mod */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x00, + /* NID_id_smime_ct */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x01, + /* NID_id_smime_aa */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x02, + /* NID_id_smime_alg */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x03, + /* NID_id_smime_cd */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x04, + /* NID_id_smime_spq */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x05, + /* NID_id_smime_cti */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x06, + /* NID_id_smime_mod_cms */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x00, 0x01, + /* NID_id_smime_mod_ess */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x00, 0x02, + /* NID_id_smime_mod_oid */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x00, 0x03, + /* NID_id_smime_mod_msg_v3 */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x00, 0x04, + /* NID_id_smime_mod_ets_eSignature_88 */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x00, 0x05, + /* NID_id_smime_mod_ets_eSignature_97 */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x00, 0x06, + /* NID_id_smime_mod_ets_eSigPolicy_88 */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x00, 0x07, + /* NID_id_smime_mod_ets_eSigPolicy_97 */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x00, 0x08, + /* NID_id_smime_ct_receipt */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x01, 0x01, + /* NID_id_smime_ct_authData */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x01, 0x02, + /* NID_id_smime_ct_publishCert */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x01, 0x03, + /* NID_id_smime_ct_TSTInfo */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x01, 0x04, + /* NID_id_smime_ct_TDTInfo */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x01, 0x05, + /* NID_id_smime_ct_contentInfo */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x01, 0x06, + /* NID_id_smime_ct_DVCSRequestData */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x01, 0x07, + /* NID_id_smime_ct_DVCSResponseData */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x01, 0x08, + /* NID_id_smime_aa_receiptRequest */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x02, 0x01, + /* NID_id_smime_aa_securityLabel */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x02, 0x02, + /* NID_id_smime_aa_mlExpandHistory */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x02, 0x03, + /* NID_id_smime_aa_contentHint */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x02, 0x04, + /* NID_id_smime_aa_msgSigDigest */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x02, 0x05, + /* NID_id_smime_aa_encapContentType */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x02, 0x06, + /* NID_id_smime_aa_contentIdentifier */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x02, 0x07, + /* NID_id_smime_aa_macValue */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x02, 0x08, + /* NID_id_smime_aa_equivalentLabels */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x02, 0x09, + /* NID_id_smime_aa_contentReference */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x02, 0x0a, + /* NID_id_smime_aa_encrypKeyPref */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x02, 0x0b, + /* NID_id_smime_aa_signingCertificate */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x02, 0x0c, + /* NID_id_smime_aa_smimeEncryptCerts */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x02, 0x0d, + /* NID_id_smime_aa_timeStampToken */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x02, 0x0e, + /* NID_id_smime_aa_ets_sigPolicyId */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x02, 0x0f, + /* NID_id_smime_aa_ets_commitmentType */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x02, 0x10, + /* NID_id_smime_aa_ets_signerLocation */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x02, 0x11, + /* NID_id_smime_aa_ets_signerAttr */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x02, 0x12, + /* NID_id_smime_aa_ets_otherSigCert */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x02, 0x13, + /* NID_id_smime_aa_ets_contentTimestamp */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x02, 0x14, + /* NID_id_smime_aa_ets_CertificateRefs */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x02, 0x15, + /* NID_id_smime_aa_ets_RevocationRefs */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x02, 0x16, + /* NID_id_smime_aa_ets_certValues */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x02, 0x17, + /* NID_id_smime_aa_ets_revocationValues */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x02, 0x18, + /* NID_id_smime_aa_ets_escTimeStamp */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x02, 0x19, + /* NID_id_smime_aa_ets_certCRLTimestamp */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x02, 0x1a, + /* NID_id_smime_aa_ets_archiveTimeStamp */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x02, 0x1b, + /* NID_id_smime_aa_signatureType */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x02, 0x1c, + /* NID_id_smime_aa_dvcs_dvc */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x02, 0x1d, + /* NID_id_smime_alg_ESDHwith3DES */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x03, 0x01, + /* NID_id_smime_alg_ESDHwithRC2 */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x03, 0x02, + /* NID_id_smime_alg_3DESwrap */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x03, 0x03, + /* NID_id_smime_alg_RC2wrap */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x03, 0x04, + /* NID_id_smime_alg_ESDH */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x03, 0x05, + /* NID_id_smime_alg_CMS3DESwrap */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x03, 0x06, + /* NID_id_smime_alg_CMSRC2wrap */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x03, 0x07, + /* NID_id_smime_cd_ldap */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x04, 0x01, + /* NID_id_smime_spq_ets_sqt_uri */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x05, 0x01, + /* NID_id_smime_spq_ets_sqt_unotice */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x05, 0x02, + /* NID_id_smime_cti_ets_proofOfOrigin */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x06, 0x01, + /* NID_id_smime_cti_ets_proofOfReceipt */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x06, 0x02, + /* NID_id_smime_cti_ets_proofOfDelivery */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x06, 0x03, + /* NID_id_smime_cti_ets_proofOfSender */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x06, 0x04, + /* NID_id_smime_cti_ets_proofOfApproval */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x06, 0x05, + /* NID_id_smime_cti_ets_proofOfCreation */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x06, 0x06, + /* NID_md4 */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x04, + /* NID_id_pkix_mod */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x00, + /* NID_id_qt */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, + /* NID_id_it */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x04, + /* NID_id_pkip */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x05, + /* NID_id_alg */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x06, + /* NID_id_cmc */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x07, + /* NID_id_on */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x08, + /* NID_id_pda */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x09, + /* NID_id_aca */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x0a, + /* NID_id_qcs */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x0b, + /* NID_id_cct */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x0c, + /* NID_id_pkix1_explicit_88 */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x00, 0x01, + /* NID_id_pkix1_implicit_88 */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x00, 0x02, + /* NID_id_pkix1_explicit_93 */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x00, 0x03, + /* NID_id_pkix1_implicit_93 */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x00, 0x04, + /* NID_id_mod_crmf */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x00, 0x05, + /* NID_id_mod_cmc */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x00, 0x06, + /* NID_id_mod_kea_profile_88 */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x00, 0x07, + /* NID_id_mod_kea_profile_93 */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x00, 0x08, + /* NID_id_mod_cmp */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x00, 0x09, + /* NID_id_mod_qualified_cert_88 */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x00, 0x0a, + /* NID_id_mod_qualified_cert_93 */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x00, 0x0b, + /* NID_id_mod_attribute_cert */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x00, 0x0c, + /* NID_id_mod_timestamp_protocol */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x00, 0x0d, + /* NID_id_mod_ocsp */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x00, 0x0e, + /* NID_id_mod_dvcs */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x00, 0x0f, + /* NID_id_mod_cmp2000 */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x00, 0x10, + /* NID_biometricInfo */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x02, + /* NID_qcStatements */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x03, + /* NID_ac_auditEntity */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x04, + /* NID_ac_targeting */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x05, + /* NID_aaControls */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x06, + /* NID_sbgp_ipAddrBlock */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x07, + /* NID_sbgp_autonomousSysNum */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x08, + /* NID_sbgp_routerIdentifier */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x09, + /* NID_textNotice */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x03, + /* NID_ipsecEndSystem */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x05, + /* NID_ipsecTunnel */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x06, + /* NID_ipsecUser */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x07, + /* NID_dvcs */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x0a, + /* NID_id_it_caProtEncCert */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x04, 0x01, + /* NID_id_it_signKeyPairTypes */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x04, 0x02, + /* NID_id_it_encKeyPairTypes */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x04, 0x03, + /* NID_id_it_preferredSymmAlg */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x04, 0x04, + /* NID_id_it_caKeyUpdateInfo */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x04, 0x05, + /* NID_id_it_currentCRL */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x04, 0x06, + /* NID_id_it_unsupportedOIDs */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x04, 0x07, + /* NID_id_it_subscriptionRequest */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x04, 0x08, + /* NID_id_it_subscriptionResponse */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x04, 0x09, + /* NID_id_it_keyPairParamReq */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x04, 0x0a, + /* NID_id_it_keyPairParamRep */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x04, 0x0b, + /* NID_id_it_revPassphrase */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x04, 0x0c, + /* NID_id_it_implicitConfirm */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x04, 0x0d, + /* NID_id_it_confirmWaitTime */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x04, 0x0e, + /* NID_id_it_origPKIMessage */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x04, 0x0f, + /* NID_id_regCtrl */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x05, 0x01, + /* NID_id_regInfo */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x05, 0x02, + /* NID_id_regCtrl_regToken */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x05, 0x01, 0x01, + /* NID_id_regCtrl_authenticator */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x05, 0x01, 0x02, + /* NID_id_regCtrl_pkiPublicationInfo */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x05, 0x01, 0x03, + /* NID_id_regCtrl_pkiArchiveOptions */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x05, 0x01, 0x04, + /* NID_id_regCtrl_oldCertID */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x05, 0x01, 0x05, + /* NID_id_regCtrl_protocolEncrKey */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x05, 0x01, 0x06, + /* NID_id_regInfo_utf8Pairs */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x05, 0x02, 0x01, + /* NID_id_regInfo_certReq */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x05, 0x02, 0x02, + /* NID_id_alg_des40 */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x06, 0x01, + /* NID_id_alg_noSignature */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x06, 0x02, + /* NID_id_alg_dh_sig_hmac_sha1 */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x06, 0x03, + /* NID_id_alg_dh_pop */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x06, 0x04, + /* NID_id_cmc_statusInfo */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x07, 0x01, + /* NID_id_cmc_identification */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x07, 0x02, + /* NID_id_cmc_identityProof */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x07, 0x03, + /* NID_id_cmc_dataReturn */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x07, 0x04, + /* NID_id_cmc_transactionId */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x07, 0x05, + /* NID_id_cmc_senderNonce */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x07, 0x06, + /* NID_id_cmc_recipientNonce */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x07, 0x07, + /* NID_id_cmc_addExtensions */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x07, 0x08, + /* NID_id_cmc_encryptedPOP */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x07, 0x09, + /* NID_id_cmc_decryptedPOP */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x07, 0x0a, + /* NID_id_cmc_lraPOPWitness */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x07, 0x0b, + /* NID_id_cmc_getCert */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x07, 0x0f, + /* NID_id_cmc_getCRL */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x07, 0x10, + /* NID_id_cmc_revokeRequest */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x07, 0x11, + /* NID_id_cmc_regInfo */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x07, 0x12, + /* NID_id_cmc_responseInfo */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x07, 0x13, + /* NID_id_cmc_queryPending */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x07, 0x15, + /* NID_id_cmc_popLinkRandom */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x07, 0x16, + /* NID_id_cmc_popLinkWitness */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x07, 0x17, + /* NID_id_cmc_confirmCertAcceptance */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x07, 0x18, + /* NID_id_on_personalData */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x08, 0x01, + /* NID_id_pda_dateOfBirth */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x09, 0x01, + /* NID_id_pda_placeOfBirth */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x09, 0x02, + /* NID_id_pda_gender */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x09, 0x03, + /* NID_id_pda_countryOfCitizenship */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x09, 0x04, + /* NID_id_pda_countryOfResidence */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x09, 0x05, + /* NID_id_aca_authenticationInfo */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x0a, 0x01, + /* NID_id_aca_accessIdentity */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x0a, 0x02, + /* NID_id_aca_chargingIdentity */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x0a, 0x03, + /* NID_id_aca_group */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x0a, 0x04, + /* NID_id_aca_role */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x0a, 0x05, + /* NID_id_qcs_pkixQCSyntax_v1 */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x0b, 0x01, + /* NID_id_cct_crs */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x0c, 0x01, + /* NID_id_cct_PKIData */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x0c, 0x02, + /* NID_id_cct_PKIResponse */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x0c, 0x03, + /* NID_ad_timeStamping */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x03, + /* NID_ad_dvcs */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x04, + /* NID_id_pkix_OCSP_basic */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x01, + /* NID_id_pkix_OCSP_Nonce */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x02, + /* NID_id_pkix_OCSP_CrlID */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x03, + /* NID_id_pkix_OCSP_acceptableResponses */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x04, + /* NID_id_pkix_OCSP_noCheck */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x05, + /* NID_id_pkix_OCSP_archiveCutoff */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x06, + /* NID_id_pkix_OCSP_serviceLocator */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x07, + /* NID_id_pkix_OCSP_extendedStatus */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x08, + /* NID_id_pkix_OCSP_valid */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x09, + /* NID_id_pkix_OCSP_path */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x0a, + /* NID_id_pkix_OCSP_trustRoot */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x0b, + /* NID_algorithm */ + 0x2b, 0x0e, 0x03, 0x02, + /* NID_rsaSignature */ + 0x2b, 0x0e, 0x03, 0x02, 0x0b, + /* NID_X500algorithms */ + 0x55, 0x08, + /* NID_org */ + 0x2b, + /* NID_dod */ + 0x2b, 0x06, + /* NID_iana */ + 0x2b, 0x06, 0x01, + /* NID_Directory */ + 0x2b, 0x06, 0x01, 0x01, + /* NID_Management */ + 0x2b, 0x06, 0x01, 0x02, + /* NID_Experimental */ + 0x2b, 0x06, 0x01, 0x03, + /* NID_Private */ + 0x2b, 0x06, 0x01, 0x04, + /* NID_Security */ + 0x2b, 0x06, 0x01, 0x05, + /* NID_SNMPv2 */ + 0x2b, 0x06, 0x01, 0x06, + /* NID_Mail */ + 0x2b, 0x06, 0x01, 0x07, + /* NID_Enterprises */ + 0x2b, 0x06, 0x01, 0x04, 0x01, + /* NID_dcObject */ + 0x2b, 0x06, 0x01, 0x04, 0x01, 0x8b, 0x3a, 0x82, 0x58, + /* NID_domainComponent */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x19, + /* NID_Domain */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x04, 0x0d, + /* NID_selected_attribute_types */ + 0x55, 0x01, 0x05, + /* NID_clearance */ + 0x55, 0x01, 0x05, 0x37, + /* NID_md4WithRSAEncryption */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x03, + /* NID_ac_proxying */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x0a, + /* NID_sinfo_access */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x0b, + /* NID_id_aca_encAttrs */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x0a, 0x06, + /* NID_role */ + 0x55, 0x04, 0x48, + /* NID_policy_constraints */ + 0x55, 0x1d, 0x24, + /* NID_target_information */ + 0x55, 0x1d, 0x37, + /* NID_no_rev_avail */ + 0x55, 0x1d, 0x38, + /* NID_ansi_X9_62 */ + 0x2a, 0x86, 0x48, 0xce, 0x3d, + /* NID_X9_62_prime_field */ + 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x01, 0x01, + /* NID_X9_62_characteristic_two_field */ + 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x01, 0x02, + /* NID_X9_62_id_ecPublicKey */ + 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, + /* NID_X9_62_prime192v1 */ + 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x01, + /* NID_X9_62_prime192v2 */ + 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x02, + /* NID_X9_62_prime192v3 */ + 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x03, + /* NID_X9_62_prime239v1 */ + 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x04, + /* NID_X9_62_prime239v2 */ + 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x05, + /* NID_X9_62_prime239v3 */ + 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x06, + /* NID_X9_62_prime256v1 */ + 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, + /* NID_ecdsa_with_SHA1 */ + 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x01, + /* NID_ms_csp_name */ + 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x11, 0x01, + /* NID_aes_128_ecb */ + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x01, + /* NID_aes_128_cbc */ + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x02, + /* NID_aes_128_ofb128 */ + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x03, + /* NID_aes_128_cfb128 */ + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x04, + /* NID_aes_192_ecb */ + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x15, + /* NID_aes_192_cbc */ + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x16, + /* NID_aes_192_ofb128 */ + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x17, + /* NID_aes_192_cfb128 */ + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x18, + /* NID_aes_256_ecb */ + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x29, + /* NID_aes_256_cbc */ + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x2a, + /* NID_aes_256_ofb128 */ + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x2b, + /* NID_aes_256_cfb128 */ + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x2c, + /* NID_hold_instruction_code */ + 0x55, 0x1d, 0x17, + /* NID_hold_instruction_none */ + 0x2a, 0x86, 0x48, 0xce, 0x38, 0x02, 0x01, + /* NID_hold_instruction_call_issuer */ + 0x2a, 0x86, 0x48, 0xce, 0x38, 0x02, 0x02, + /* NID_hold_instruction_reject */ + 0x2a, 0x86, 0x48, 0xce, 0x38, 0x02, 0x03, + /* NID_data */ + 0x09, + /* NID_pss */ + 0x09, 0x92, 0x26, + /* NID_ucl */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, + /* NID_pilot */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, + /* NID_pilotAttributeType */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, + /* NID_pilotAttributeSyntax */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x03, + /* NID_pilotObjectClass */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x04, + /* NID_pilotGroups */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x0a, + /* NID_iA5StringSyntax */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x03, 0x04, + /* NID_caseIgnoreIA5StringSyntax */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x03, 0x05, + /* NID_pilotObject */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x04, 0x03, + /* NID_pilotPerson */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x04, 0x04, + /* NID_account */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x04, 0x05, + /* NID_document */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x04, 0x06, + /* NID_room */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x04, 0x07, + /* NID_documentSeries */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x04, 0x09, + /* NID_rFC822localPart */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x04, 0x0e, + /* NID_dNSDomain */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x04, 0x0f, + /* NID_domainRelatedObject */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x04, 0x11, + /* NID_friendlyCountry */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x04, 0x12, + /* NID_simpleSecurityObject */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x04, 0x13, + /* NID_pilotOrganization */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x04, 0x14, + /* NID_pilotDSA */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x04, 0x15, + /* NID_qualityLabelledData */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x04, 0x16, + /* NID_userId */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x01, + /* NID_textEncodedORAddress */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x02, + /* NID_rfc822Mailbox */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x03, + /* NID_info */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x04, + /* NID_favouriteDrink */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x05, + /* NID_roomNumber */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x06, + /* NID_photo */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x07, + /* NID_userClass */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x08, + /* NID_host */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x09, + /* NID_manager */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x0a, + /* NID_documentIdentifier */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x0b, + /* NID_documentTitle */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x0c, + /* NID_documentVersion */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x0d, + /* NID_documentAuthor */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x0e, + /* NID_documentLocation */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x0f, + /* NID_homeTelephoneNumber */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x14, + /* NID_secretary */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x15, + /* NID_otherMailbox */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x16, + /* NID_lastModifiedTime */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x17, + /* NID_lastModifiedBy */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x18, + /* NID_aRecord */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x1a, + /* NID_pilotAttributeType27 */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x1b, + /* NID_mXRecord */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x1c, + /* NID_nSRecord */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x1d, + /* NID_sOARecord */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x1e, + /* NID_cNAMERecord */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x1f, + /* NID_associatedDomain */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x25, + /* NID_associatedName */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x26, + /* NID_homePostalAddress */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x27, + /* NID_personalTitle */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x28, + /* NID_mobileTelephoneNumber */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x29, + /* NID_pagerTelephoneNumber */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x2a, + /* NID_friendlyCountryName */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x2b, + /* NID_organizationalStatus */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x2d, + /* NID_janetMailbox */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x2e, + /* NID_mailPreferenceOption */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x2f, + /* NID_buildingName */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x30, + /* NID_dSAQuality */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x31, + /* NID_singleLevelQuality */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x32, + /* NID_subtreeMinimumQuality */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x33, + /* NID_subtreeMaximumQuality */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x34, + /* NID_personalSignature */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x35, + /* NID_dITRedirect */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x36, + /* NID_audio */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x37, + /* NID_documentPublisher */ + 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x38, + /* NID_x500UniqueIdentifier */ + 0x55, 0x04, 0x2d, + /* NID_mime_mhs */ + 0x2b, 0x06, 0x01, 0x07, 0x01, + /* NID_mime_mhs_headings */ + 0x2b, 0x06, 0x01, 0x07, 0x01, 0x01, + /* NID_mime_mhs_bodies */ + 0x2b, 0x06, 0x01, 0x07, 0x01, 0x02, + /* NID_id_hex_partial_message */ + 0x2b, 0x06, 0x01, 0x07, 0x01, 0x01, 0x01, + /* NID_id_hex_multipart_message */ + 0x2b, 0x06, 0x01, 0x07, 0x01, 0x01, 0x02, + /* NID_generationQualifier */ + 0x55, 0x04, 0x2c, + /* NID_pseudonym */ + 0x55, 0x04, 0x41, + /* NID_id_set */ + 0x67, 0x2a, + /* NID_set_ctype */ + 0x67, 0x2a, 0x00, + /* NID_set_msgExt */ + 0x67, 0x2a, 0x01, + /* NID_set_attr */ + 0x67, 0x2a, 0x03, + /* NID_set_policy */ + 0x67, 0x2a, 0x05, + /* NID_set_certExt */ + 0x67, 0x2a, 0x07, + /* NID_set_brand */ + 0x67, 0x2a, 0x08, + /* NID_setct_PANData */ + 0x67, 0x2a, 0x00, 0x00, + /* NID_setct_PANToken */ + 0x67, 0x2a, 0x00, 0x01, + /* NID_setct_PANOnly */ + 0x67, 0x2a, 0x00, 0x02, + /* NID_setct_OIData */ + 0x67, 0x2a, 0x00, 0x03, + /* NID_setct_PI */ + 0x67, 0x2a, 0x00, 0x04, + /* NID_setct_PIData */ + 0x67, 0x2a, 0x00, 0x05, + /* NID_setct_PIDataUnsigned */ + 0x67, 0x2a, 0x00, 0x06, + /* NID_setct_HODInput */ + 0x67, 0x2a, 0x00, 0x07, + /* NID_setct_AuthResBaggage */ + 0x67, 0x2a, 0x00, 0x08, + /* NID_setct_AuthRevReqBaggage */ + 0x67, 0x2a, 0x00, 0x09, + /* NID_setct_AuthRevResBaggage */ + 0x67, 0x2a, 0x00, 0x0a, + /* NID_setct_CapTokenSeq */ + 0x67, 0x2a, 0x00, 0x0b, + /* NID_setct_PInitResData */ + 0x67, 0x2a, 0x00, 0x0c, + /* NID_setct_PI_TBS */ + 0x67, 0x2a, 0x00, 0x0d, + /* NID_setct_PResData */ + 0x67, 0x2a, 0x00, 0x0e, + /* NID_setct_AuthReqTBS */ + 0x67, 0x2a, 0x00, 0x10, + /* NID_setct_AuthResTBS */ + 0x67, 0x2a, 0x00, 0x11, + /* NID_setct_AuthResTBSX */ + 0x67, 0x2a, 0x00, 0x12, + /* NID_setct_AuthTokenTBS */ + 0x67, 0x2a, 0x00, 0x13, + /* NID_setct_CapTokenData */ + 0x67, 0x2a, 0x00, 0x14, + /* NID_setct_CapTokenTBS */ + 0x67, 0x2a, 0x00, 0x15, + /* NID_setct_AcqCardCodeMsg */ + 0x67, 0x2a, 0x00, 0x16, + /* NID_setct_AuthRevReqTBS */ + 0x67, 0x2a, 0x00, 0x17, + /* NID_setct_AuthRevResData */ + 0x67, 0x2a, 0x00, 0x18, + /* NID_setct_AuthRevResTBS */ + 0x67, 0x2a, 0x00, 0x19, + /* NID_setct_CapReqTBS */ + 0x67, 0x2a, 0x00, 0x1a, + /* NID_setct_CapReqTBSX */ + 0x67, 0x2a, 0x00, 0x1b, + /* NID_setct_CapResData */ + 0x67, 0x2a, 0x00, 0x1c, + /* NID_setct_CapRevReqTBS */ + 0x67, 0x2a, 0x00, 0x1d, + /* NID_setct_CapRevReqTBSX */ + 0x67, 0x2a, 0x00, 0x1e, + /* NID_setct_CapRevResData */ + 0x67, 0x2a, 0x00, 0x1f, + /* NID_setct_CredReqTBS */ + 0x67, 0x2a, 0x00, 0x20, + /* NID_setct_CredReqTBSX */ + 0x67, 0x2a, 0x00, 0x21, + /* NID_setct_CredResData */ + 0x67, 0x2a, 0x00, 0x22, + /* NID_setct_CredRevReqTBS */ + 0x67, 0x2a, 0x00, 0x23, + /* NID_setct_CredRevReqTBSX */ + 0x67, 0x2a, 0x00, 0x24, + /* NID_setct_CredRevResData */ + 0x67, 0x2a, 0x00, 0x25, + /* NID_setct_PCertReqData */ + 0x67, 0x2a, 0x00, 0x26, + /* NID_setct_PCertResTBS */ + 0x67, 0x2a, 0x00, 0x27, + /* NID_setct_BatchAdminReqData */ + 0x67, 0x2a, 0x00, 0x28, + /* NID_setct_BatchAdminResData */ + 0x67, 0x2a, 0x00, 0x29, + /* NID_setct_CardCInitResTBS */ + 0x67, 0x2a, 0x00, 0x2a, + /* NID_setct_MeAqCInitResTBS */ + 0x67, 0x2a, 0x00, 0x2b, + /* NID_setct_RegFormResTBS */ + 0x67, 0x2a, 0x00, 0x2c, + /* NID_setct_CertReqData */ + 0x67, 0x2a, 0x00, 0x2d, + /* NID_setct_CertReqTBS */ + 0x67, 0x2a, 0x00, 0x2e, + /* NID_setct_CertResData */ + 0x67, 0x2a, 0x00, 0x2f, + /* NID_setct_CertInqReqTBS */ + 0x67, 0x2a, 0x00, 0x30, + /* NID_setct_ErrorTBS */ + 0x67, 0x2a, 0x00, 0x31, + /* NID_setct_PIDualSignedTBE */ + 0x67, 0x2a, 0x00, 0x32, + /* NID_setct_PIUnsignedTBE */ + 0x67, 0x2a, 0x00, 0x33, + /* NID_setct_AuthReqTBE */ + 0x67, 0x2a, 0x00, 0x34, + /* NID_setct_AuthResTBE */ + 0x67, 0x2a, 0x00, 0x35, + /* NID_setct_AuthResTBEX */ + 0x67, 0x2a, 0x00, 0x36, + /* NID_setct_AuthTokenTBE */ + 0x67, 0x2a, 0x00, 0x37, + /* NID_setct_CapTokenTBE */ + 0x67, 0x2a, 0x00, 0x38, + /* NID_setct_CapTokenTBEX */ + 0x67, 0x2a, 0x00, 0x39, + /* NID_setct_AcqCardCodeMsgTBE */ + 0x67, 0x2a, 0x00, 0x3a, + /* NID_setct_AuthRevReqTBE */ + 0x67, 0x2a, 0x00, 0x3b, + /* NID_setct_AuthRevResTBE */ + 0x67, 0x2a, 0x00, 0x3c, + /* NID_setct_AuthRevResTBEB */ + 0x67, 0x2a, 0x00, 0x3d, + /* NID_setct_CapReqTBE */ + 0x67, 0x2a, 0x00, 0x3e, + /* NID_setct_CapReqTBEX */ + 0x67, 0x2a, 0x00, 0x3f, + /* NID_setct_CapResTBE */ + 0x67, 0x2a, 0x00, 0x40, + /* NID_setct_CapRevReqTBE */ + 0x67, 0x2a, 0x00, 0x41, + /* NID_setct_CapRevReqTBEX */ + 0x67, 0x2a, 0x00, 0x42, + /* NID_setct_CapRevResTBE */ + 0x67, 0x2a, 0x00, 0x43, + /* NID_setct_CredReqTBE */ + 0x67, 0x2a, 0x00, 0x44, + /* NID_setct_CredReqTBEX */ + 0x67, 0x2a, 0x00, 0x45, + /* NID_setct_CredResTBE */ + 0x67, 0x2a, 0x00, 0x46, + /* NID_setct_CredRevReqTBE */ + 0x67, 0x2a, 0x00, 0x47, + /* NID_setct_CredRevReqTBEX */ + 0x67, 0x2a, 0x00, 0x48, + /* NID_setct_CredRevResTBE */ + 0x67, 0x2a, 0x00, 0x49, + /* NID_setct_BatchAdminReqTBE */ + 0x67, 0x2a, 0x00, 0x4a, + /* NID_setct_BatchAdminResTBE */ + 0x67, 0x2a, 0x00, 0x4b, + /* NID_setct_RegFormReqTBE */ + 0x67, 0x2a, 0x00, 0x4c, + /* NID_setct_CertReqTBE */ + 0x67, 0x2a, 0x00, 0x4d, + /* NID_setct_CertReqTBEX */ + 0x67, 0x2a, 0x00, 0x4e, + /* NID_setct_CertResTBE */ + 0x67, 0x2a, 0x00, 0x4f, + /* NID_setct_CRLNotificationTBS */ + 0x67, 0x2a, 0x00, 0x50, + /* NID_setct_CRLNotificationResTBS */ + 0x67, 0x2a, 0x00, 0x51, + /* NID_setct_BCIDistributionTBS */ + 0x67, 0x2a, 0x00, 0x52, + /* NID_setext_genCrypt */ + 0x67, 0x2a, 0x01, 0x01, + /* NID_setext_miAuth */ + 0x67, 0x2a, 0x01, 0x03, + /* NID_setext_pinSecure */ + 0x67, 0x2a, 0x01, 0x04, + /* NID_setext_pinAny */ + 0x67, 0x2a, 0x01, 0x05, + /* NID_setext_track2 */ + 0x67, 0x2a, 0x01, 0x07, + /* NID_setext_cv */ + 0x67, 0x2a, 0x01, 0x08, + /* NID_set_policy_root */ + 0x67, 0x2a, 0x05, 0x00, + /* NID_setCext_hashedRoot */ + 0x67, 0x2a, 0x07, 0x00, + /* NID_setCext_certType */ + 0x67, 0x2a, 0x07, 0x01, + /* NID_setCext_merchData */ + 0x67, 0x2a, 0x07, 0x02, + /* NID_setCext_cCertRequired */ + 0x67, 0x2a, 0x07, 0x03, + /* NID_setCext_tunneling */ + 0x67, 0x2a, 0x07, 0x04, + /* NID_setCext_setExt */ + 0x67, 0x2a, 0x07, 0x05, + /* NID_setCext_setQualf */ + 0x67, 0x2a, 0x07, 0x06, + /* NID_setCext_PGWYcapabilities */ + 0x67, 0x2a, 0x07, 0x07, + /* NID_setCext_TokenIdentifier */ + 0x67, 0x2a, 0x07, 0x08, + /* NID_setCext_Track2Data */ + 0x67, 0x2a, 0x07, 0x09, + /* NID_setCext_TokenType */ + 0x67, 0x2a, 0x07, 0x0a, + /* NID_setCext_IssuerCapabilities */ + 0x67, 0x2a, 0x07, 0x0b, + /* NID_setAttr_Cert */ + 0x67, 0x2a, 0x03, 0x00, + /* NID_setAttr_PGWYcap */ + 0x67, 0x2a, 0x03, 0x01, + /* NID_setAttr_TokenType */ + 0x67, 0x2a, 0x03, 0x02, + /* NID_setAttr_IssCap */ + 0x67, 0x2a, 0x03, 0x03, + /* NID_set_rootKeyThumb */ + 0x67, 0x2a, 0x03, 0x00, 0x00, + /* NID_set_addPolicy */ + 0x67, 0x2a, 0x03, 0x00, 0x01, + /* NID_setAttr_Token_EMV */ + 0x67, 0x2a, 0x03, 0x02, 0x01, + /* NID_setAttr_Token_B0Prime */ + 0x67, 0x2a, 0x03, 0x02, 0x02, + /* NID_setAttr_IssCap_CVM */ + 0x67, 0x2a, 0x03, 0x03, 0x03, + /* NID_setAttr_IssCap_T2 */ + 0x67, 0x2a, 0x03, 0x03, 0x04, + /* NID_setAttr_IssCap_Sig */ + 0x67, 0x2a, 0x03, 0x03, 0x05, + /* NID_setAttr_GenCryptgrm */ + 0x67, 0x2a, 0x03, 0x03, 0x03, 0x01, + /* NID_setAttr_T2Enc */ + 0x67, 0x2a, 0x03, 0x03, 0x04, 0x01, + /* NID_setAttr_T2cleartxt */ + 0x67, 0x2a, 0x03, 0x03, 0x04, 0x02, + /* NID_setAttr_TokICCsig */ + 0x67, 0x2a, 0x03, 0x03, 0x05, 0x01, + /* NID_setAttr_SecDevSig */ + 0x67, 0x2a, 0x03, 0x03, 0x05, 0x02, + /* NID_set_brand_IATA_ATA */ + 0x67, 0x2a, 0x08, 0x01, + /* NID_set_brand_Diners */ + 0x67, 0x2a, 0x08, 0x1e, + /* NID_set_brand_AmericanExpress */ + 0x67, 0x2a, 0x08, 0x22, + /* NID_set_brand_JCB */ + 0x67, 0x2a, 0x08, 0x23, + /* NID_set_brand_Visa */ + 0x67, 0x2a, 0x08, 0x04, + /* NID_set_brand_MasterCard */ + 0x67, 0x2a, 0x08, 0x05, + /* NID_set_brand_Novus */ + 0x67, 0x2a, 0x08, 0xae, 0x7b, + /* NID_des_cdmf */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x03, 0x0a, + /* NID_rsaOAEPEncryptionSET */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x06, + /* NID_international_organizations */ + 0x67, + /* NID_ms_smartcard_login */ + 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x14, 0x02, 0x02, + /* NID_ms_upn */ + 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x14, 0x02, 0x03, + /* NID_streetAddress */ + 0x55, 0x04, 0x09, + /* NID_postalCode */ + 0x55, 0x04, 0x11, + /* NID_id_ppl */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x15, + /* NID_proxyCertInfo */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x0e, + /* NID_id_ppl_anyLanguage */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x15, 0x00, + /* NID_id_ppl_inheritAll */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x15, 0x01, + /* NID_name_constraints */ + 0x55, 0x1d, 0x1e, + /* NID_Independent */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x15, 0x02, + /* NID_sha256WithRSAEncryption */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, + /* NID_sha384WithRSAEncryption */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0c, + /* NID_sha512WithRSAEncryption */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0d, + /* NID_sha224WithRSAEncryption */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0e, + /* NID_sha256 */ + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, + /* NID_sha384 */ + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, + /* NID_sha512 */ + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, + /* NID_sha224 */ + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, + /* NID_identified_organization */ + 0x2b, + /* NID_certicom_arc */ + 0x2b, 0x81, 0x04, + /* NID_wap */ + 0x67, 0x2b, + /* NID_wap_wsg */ + 0x67, 0x2b, 0x01, + /* NID_X9_62_id_characteristic_two_basis */ + 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x01, 0x02, 0x03, + /* NID_X9_62_onBasis */ + 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x01, 0x02, 0x03, 0x01, + /* NID_X9_62_tpBasis */ + 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x01, 0x02, 0x03, 0x02, + /* NID_X9_62_ppBasis */ + 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x01, 0x02, 0x03, 0x03, + /* NID_X9_62_c2pnb163v1 */ + 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x00, 0x01, + /* NID_X9_62_c2pnb163v2 */ + 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x00, 0x02, + /* NID_X9_62_c2pnb163v3 */ + 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x00, 0x03, + /* NID_X9_62_c2pnb176v1 */ + 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x00, 0x04, + /* NID_X9_62_c2tnb191v1 */ + 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x00, 0x05, + /* NID_X9_62_c2tnb191v2 */ + 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x00, 0x06, + /* NID_X9_62_c2tnb191v3 */ + 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x00, 0x07, + /* NID_X9_62_c2onb191v4 */ + 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x00, 0x08, + /* NID_X9_62_c2onb191v5 */ + 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x00, 0x09, + /* NID_X9_62_c2pnb208w1 */ + 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x00, 0x0a, + /* NID_X9_62_c2tnb239v1 */ + 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x00, 0x0b, + /* NID_X9_62_c2tnb239v2 */ + 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x00, 0x0c, + /* NID_X9_62_c2tnb239v3 */ + 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x00, 0x0d, + /* NID_X9_62_c2onb239v4 */ + 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x00, 0x0e, + /* NID_X9_62_c2onb239v5 */ + 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x00, 0x0f, + /* NID_X9_62_c2pnb272w1 */ + 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x00, 0x10, + /* NID_X9_62_c2pnb304w1 */ + 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x00, 0x11, + /* NID_X9_62_c2tnb359v1 */ + 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x00, 0x12, + /* NID_X9_62_c2pnb368w1 */ + 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x00, 0x13, + /* NID_X9_62_c2tnb431r1 */ + 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x00, 0x14, + /* NID_secp112r1 */ + 0x2b, 0x81, 0x04, 0x00, 0x06, + /* NID_secp112r2 */ + 0x2b, 0x81, 0x04, 0x00, 0x07, + /* NID_secp128r1 */ + 0x2b, 0x81, 0x04, 0x00, 0x1c, + /* NID_secp128r2 */ + 0x2b, 0x81, 0x04, 0x00, 0x1d, + /* NID_secp160k1 */ + 0x2b, 0x81, 0x04, 0x00, 0x09, + /* NID_secp160r1 */ + 0x2b, 0x81, 0x04, 0x00, 0x08, + /* NID_secp160r2 */ + 0x2b, 0x81, 0x04, 0x00, 0x1e, + /* NID_secp192k1 */ + 0x2b, 0x81, 0x04, 0x00, 0x1f, + /* NID_secp224k1 */ + 0x2b, 0x81, 0x04, 0x00, 0x20, + /* NID_secp224r1 */ + 0x2b, 0x81, 0x04, 0x00, 0x21, + /* NID_secp256k1 */ + 0x2b, 0x81, 0x04, 0x00, 0x0a, + /* NID_secp384r1 */ + 0x2b, 0x81, 0x04, 0x00, 0x22, + /* NID_secp521r1 */ + 0x2b, 0x81, 0x04, 0x00, 0x23, + /* NID_sect113r1 */ + 0x2b, 0x81, 0x04, 0x00, 0x04, + /* NID_sect113r2 */ + 0x2b, 0x81, 0x04, 0x00, 0x05, + /* NID_sect131r1 */ + 0x2b, 0x81, 0x04, 0x00, 0x16, + /* NID_sect131r2 */ + 0x2b, 0x81, 0x04, 0x00, 0x17, + /* NID_sect163k1 */ + 0x2b, 0x81, 0x04, 0x00, 0x01, + /* NID_sect163r1 */ + 0x2b, 0x81, 0x04, 0x00, 0x02, + /* NID_sect163r2 */ + 0x2b, 0x81, 0x04, 0x00, 0x0f, + /* NID_sect193r1 */ + 0x2b, 0x81, 0x04, 0x00, 0x18, + /* NID_sect193r2 */ + 0x2b, 0x81, 0x04, 0x00, 0x19, + /* NID_sect233k1 */ + 0x2b, 0x81, 0x04, 0x00, 0x1a, + /* NID_sect233r1 */ + 0x2b, 0x81, 0x04, 0x00, 0x1b, + /* NID_sect239k1 */ + 0x2b, 0x81, 0x04, 0x00, 0x03, + /* NID_sect283k1 */ + 0x2b, 0x81, 0x04, 0x00, 0x10, + /* NID_sect283r1 */ + 0x2b, 0x81, 0x04, 0x00, 0x11, + /* NID_sect409k1 */ + 0x2b, 0x81, 0x04, 0x00, 0x24, + /* NID_sect409r1 */ + 0x2b, 0x81, 0x04, 0x00, 0x25, + /* NID_sect571k1 */ + 0x2b, 0x81, 0x04, 0x00, 0x26, + /* NID_sect571r1 */ + 0x2b, 0x81, 0x04, 0x00, 0x27, + /* NID_wap_wsg_idm_ecid_wtls1 */ + 0x67, 0x2b, 0x01, 0x04, 0x01, + /* NID_wap_wsg_idm_ecid_wtls3 */ + 0x67, 0x2b, 0x01, 0x04, 0x03, + /* NID_wap_wsg_idm_ecid_wtls4 */ + 0x67, 0x2b, 0x01, 0x04, 0x04, + /* NID_wap_wsg_idm_ecid_wtls5 */ + 0x67, 0x2b, 0x01, 0x04, 0x05, + /* NID_wap_wsg_idm_ecid_wtls6 */ + 0x67, 0x2b, 0x01, 0x04, 0x06, + /* NID_wap_wsg_idm_ecid_wtls7 */ + 0x67, 0x2b, 0x01, 0x04, 0x07, + /* NID_wap_wsg_idm_ecid_wtls8 */ + 0x67, 0x2b, 0x01, 0x04, 0x08, + /* NID_wap_wsg_idm_ecid_wtls9 */ + 0x67, 0x2b, 0x01, 0x04, 0x09, + /* NID_wap_wsg_idm_ecid_wtls10 */ + 0x67, 0x2b, 0x01, 0x04, 0x0a, + /* NID_wap_wsg_idm_ecid_wtls11 */ + 0x67, 0x2b, 0x01, 0x04, 0x0b, + /* NID_wap_wsg_idm_ecid_wtls12 */ + 0x67, 0x2b, 0x01, 0x04, 0x0c, + /* NID_any_policy */ + 0x55, 0x1d, 0x20, 0x00, + /* NID_policy_mappings */ + 0x55, 0x1d, 0x21, + /* NID_inhibit_any_policy */ + 0x55, 0x1d, 0x36, + /* NID_camellia_128_cbc */ + 0x2a, 0x83, 0x08, 0x8c, 0x9a, 0x4b, 0x3d, 0x01, 0x01, 0x01, 0x02, + /* NID_camellia_192_cbc */ + 0x2a, 0x83, 0x08, 0x8c, 0x9a, 0x4b, 0x3d, 0x01, 0x01, 0x01, 0x03, + /* NID_camellia_256_cbc */ + 0x2a, 0x83, 0x08, 0x8c, 0x9a, 0x4b, 0x3d, 0x01, 0x01, 0x01, 0x04, + /* NID_camellia_128_ecb */ + 0x03, 0xa2, 0x31, 0x05, 0x03, 0x01, 0x09, 0x01, + /* NID_camellia_192_ecb */ + 0x03, 0xa2, 0x31, 0x05, 0x03, 0x01, 0x09, 0x15, + /* NID_camellia_256_ecb */ + 0x03, 0xa2, 0x31, 0x05, 0x03, 0x01, 0x09, 0x29, + /* NID_camellia_128_cfb128 */ + 0x03, 0xa2, 0x31, 0x05, 0x03, 0x01, 0x09, 0x04, + /* NID_camellia_192_cfb128 */ + 0x03, 0xa2, 0x31, 0x05, 0x03, 0x01, 0x09, 0x18, + /* NID_camellia_256_cfb128 */ + 0x03, 0xa2, 0x31, 0x05, 0x03, 0x01, 0x09, 0x2c, + /* NID_camellia_128_ofb128 */ + 0x03, 0xa2, 0x31, 0x05, 0x03, 0x01, 0x09, 0x03, + /* NID_camellia_192_ofb128 */ + 0x03, 0xa2, 0x31, 0x05, 0x03, 0x01, 0x09, 0x17, + /* NID_camellia_256_ofb128 */ + 0x03, 0xa2, 0x31, 0x05, 0x03, 0x01, 0x09, 0x2b, + /* NID_subject_directory_attributes */ + 0x55, 0x1d, 0x09, + /* NID_issuing_distribution_point */ + 0x55, 0x1d, 0x1c, + /* NID_certificate_issuer */ + 0x55, 0x1d, 0x1d, + /* NID_kisa */ + 0x2a, 0x83, 0x1a, 0x8c, 0x9a, 0x44, + /* NID_seed_ecb */ + 0x2a, 0x83, 0x1a, 0x8c, 0x9a, 0x44, 0x01, 0x03, + /* NID_seed_cbc */ + 0x2a, 0x83, 0x1a, 0x8c, 0x9a, 0x44, 0x01, 0x04, + /* NID_seed_ofb128 */ + 0x2a, 0x83, 0x1a, 0x8c, 0x9a, 0x44, 0x01, 0x06, + /* NID_seed_cfb128 */ + 0x2a, 0x83, 0x1a, 0x8c, 0x9a, 0x44, 0x01, 0x05, + /* NID_hmac_md5 */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x08, 0x01, 0x01, + /* NID_hmac_sha1 */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x08, 0x01, 0x02, + /* NID_id_PasswordBasedMAC */ + 0x2a, 0x86, 0x48, 0x86, 0xf6, 0x7d, 0x07, 0x42, 0x0d, + /* NID_id_DHBasedMac */ + 0x2a, 0x86, 0x48, 0x86, 0xf6, 0x7d, 0x07, 0x42, 0x1e, + /* NID_id_it_suppLangTags */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x04, 0x10, + /* NID_caRepository */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x05, + /* NID_id_smime_ct_compressedData */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x01, 0x09, + /* NID_id_ct_asciiTextWithCRLF */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x01, 0x1b, + /* NID_id_aes128_wrap */ + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x05, + /* NID_id_aes192_wrap */ + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x19, + /* NID_id_aes256_wrap */ + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x2d, + /* NID_ecdsa_with_Recommended */ + 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x02, + /* NID_ecdsa_with_Specified */ + 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, + /* NID_ecdsa_with_SHA224 */ + 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x01, + /* NID_ecdsa_with_SHA256 */ + 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, + /* NID_ecdsa_with_SHA384 */ + 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x03, + /* NID_ecdsa_with_SHA512 */ + 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x04, + /* NID_hmacWithMD5 */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x06, + /* NID_hmacWithSHA224 */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x08, + /* NID_hmacWithSHA256 */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x09, + /* NID_hmacWithSHA384 */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x0a, + /* NID_hmacWithSHA512 */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x0b, + /* NID_dsa_with_SHA224 */ + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03, 0x01, + /* NID_dsa_with_SHA256 */ + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03, 0x02, + /* NID_whirlpool */ + 0x28, 0xcf, 0x06, 0x03, 0x00, 0x37, + /* NID_cryptopro */ + 0x2a, 0x85, 0x03, 0x02, 0x02, + /* NID_cryptocom */ + 0x2a, 0x85, 0x03, 0x02, 0x09, + /* NID_id_GostR3411_94_with_GostR3410_2001 */ + 0x2a, 0x85, 0x03, 0x02, 0x02, 0x03, + /* NID_id_GostR3411_94_with_GostR3410_94 */ + 0x2a, 0x85, 0x03, 0x02, 0x02, 0x04, + /* NID_id_GostR3411_94 */ + 0x2a, 0x85, 0x03, 0x02, 0x02, 0x09, + /* NID_id_HMACGostR3411_94 */ + 0x2a, 0x85, 0x03, 0x02, 0x02, 0x0a, + /* NID_id_GostR3410_2001 */ + 0x2a, 0x85, 0x03, 0x02, 0x02, 0x13, + /* NID_id_GostR3410_94 */ + 0x2a, 0x85, 0x03, 0x02, 0x02, 0x14, + /* NID_id_Gost28147_89 */ + 0x2a, 0x85, 0x03, 0x02, 0x02, 0x15, + /* NID_id_Gost28147_89_MAC */ + 0x2a, 0x85, 0x03, 0x02, 0x02, 0x16, + /* NID_id_GostR3411_94_prf */ + 0x2a, 0x85, 0x03, 0x02, 0x02, 0x17, + /* NID_id_GostR3410_2001DH */ + 0x2a, 0x85, 0x03, 0x02, 0x02, 0x62, + /* NID_id_GostR3410_94DH */ + 0x2a, 0x85, 0x03, 0x02, 0x02, 0x63, + /* NID_id_Gost28147_89_CryptoPro_KeyMeshing */ + 0x2a, 0x85, 0x03, 0x02, 0x02, 0x0e, 0x01, + /* NID_id_Gost28147_89_None_KeyMeshing */ + 0x2a, 0x85, 0x03, 0x02, 0x02, 0x0e, 0x00, + /* NID_id_GostR3411_94_TestParamSet */ + 0x2a, 0x85, 0x03, 0x02, 0x02, 0x1e, 0x00, + /* NID_id_GostR3411_94_CryptoProParamSet */ + 0x2a, 0x85, 0x03, 0x02, 0x02, 0x1e, 0x01, + /* NID_id_Gost28147_89_TestParamSet */ + 0x2a, 0x85, 0x03, 0x02, 0x02, 0x1f, 0x00, + /* NID_id_Gost28147_89_CryptoPro_A_ParamSet */ + 0x2a, 0x85, 0x03, 0x02, 0x02, 0x1f, 0x01, + /* NID_id_Gost28147_89_CryptoPro_B_ParamSet */ + 0x2a, 0x85, 0x03, 0x02, 0x02, 0x1f, 0x02, + /* NID_id_Gost28147_89_CryptoPro_C_ParamSet */ + 0x2a, 0x85, 0x03, 0x02, 0x02, 0x1f, 0x03, + /* NID_id_Gost28147_89_CryptoPro_D_ParamSet */ + 0x2a, 0x85, 0x03, 0x02, 0x02, 0x1f, 0x04, + /* NID_id_Gost28147_89_CryptoPro_Oscar_1_1_ParamSet */ + 0x2a, 0x85, 0x03, 0x02, 0x02, 0x1f, 0x05, + /* NID_id_Gost28147_89_CryptoPro_Oscar_1_0_ParamSet */ + 0x2a, 0x85, 0x03, 0x02, 0x02, 0x1f, 0x06, + /* NID_id_Gost28147_89_CryptoPro_RIC_1_ParamSet */ + 0x2a, 0x85, 0x03, 0x02, 0x02, 0x1f, 0x07, + /* NID_id_GostR3410_94_TestParamSet */ + 0x2a, 0x85, 0x03, 0x02, 0x02, 0x20, 0x00, + /* NID_id_GostR3410_94_CryptoPro_A_ParamSet */ + 0x2a, 0x85, 0x03, 0x02, 0x02, 0x20, 0x02, + /* NID_id_GostR3410_94_CryptoPro_B_ParamSet */ + 0x2a, 0x85, 0x03, 0x02, 0x02, 0x20, 0x03, + /* NID_id_GostR3410_94_CryptoPro_C_ParamSet */ + 0x2a, 0x85, 0x03, 0x02, 0x02, 0x20, 0x04, + /* NID_id_GostR3410_94_CryptoPro_D_ParamSet */ + 0x2a, 0x85, 0x03, 0x02, 0x02, 0x20, 0x05, + /* NID_id_GostR3410_94_CryptoPro_XchA_ParamSet */ + 0x2a, 0x85, 0x03, 0x02, 0x02, 0x21, 0x01, + /* NID_id_GostR3410_94_CryptoPro_XchB_ParamSet */ + 0x2a, 0x85, 0x03, 0x02, 0x02, 0x21, 0x02, + /* NID_id_GostR3410_94_CryptoPro_XchC_ParamSet */ + 0x2a, 0x85, 0x03, 0x02, 0x02, 0x21, 0x03, + /* NID_id_GostR3410_2001_TestParamSet */ + 0x2a, 0x85, 0x03, 0x02, 0x02, 0x23, 0x00, + /* NID_id_GostR3410_2001_CryptoPro_A_ParamSet */ + 0x2a, 0x85, 0x03, 0x02, 0x02, 0x23, 0x01, + /* NID_id_GostR3410_2001_CryptoPro_B_ParamSet */ + 0x2a, 0x85, 0x03, 0x02, 0x02, 0x23, 0x02, + /* NID_id_GostR3410_2001_CryptoPro_C_ParamSet */ + 0x2a, 0x85, 0x03, 0x02, 0x02, 0x23, 0x03, + /* NID_id_GostR3410_2001_CryptoPro_XchA_ParamSet */ + 0x2a, 0x85, 0x03, 0x02, 0x02, 0x24, 0x00, + /* NID_id_GostR3410_2001_CryptoPro_XchB_ParamSet */ + 0x2a, 0x85, 0x03, 0x02, 0x02, 0x24, 0x01, + /* NID_id_GostR3410_94_a */ + 0x2a, 0x85, 0x03, 0x02, 0x02, 0x14, 0x01, + /* NID_id_GostR3410_94_aBis */ + 0x2a, 0x85, 0x03, 0x02, 0x02, 0x14, 0x02, + /* NID_id_GostR3410_94_b */ + 0x2a, 0x85, 0x03, 0x02, 0x02, 0x14, 0x03, + /* NID_id_GostR3410_94_bBis */ + 0x2a, 0x85, 0x03, 0x02, 0x02, 0x14, 0x04, + /* NID_id_Gost28147_89_cc */ + 0x2a, 0x85, 0x03, 0x02, 0x09, 0x01, 0x06, 0x01, + /* NID_id_GostR3410_94_cc */ + 0x2a, 0x85, 0x03, 0x02, 0x09, 0x01, 0x05, 0x03, + /* NID_id_GostR3410_2001_cc */ + 0x2a, 0x85, 0x03, 0x02, 0x09, 0x01, 0x05, 0x04, + /* NID_id_GostR3411_94_with_GostR3410_94_cc */ + 0x2a, 0x85, 0x03, 0x02, 0x09, 0x01, 0x03, 0x03, + /* NID_id_GostR3411_94_with_GostR3410_2001_cc */ + 0x2a, 0x85, 0x03, 0x02, 0x09, 0x01, 0x03, 0x04, + /* NID_id_GostR3410_2001_ParamSet_cc */ + 0x2a, 0x85, 0x03, 0x02, 0x09, 0x01, 0x08, 0x01, + /* NID_LocalKeySet */ + 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x11, 0x02, + /* NID_freshest_crl */ + 0x55, 0x1d, 0x2e, + /* NID_id_on_permanentIdentifier */ + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x08, 0x03, + /* NID_searchGuide */ + 0x55, 0x04, 0x0e, + /* NID_businessCategory */ + 0x55, 0x04, 0x0f, + /* NID_postalAddress */ + 0x55, 0x04, 0x10, + /* NID_postOfficeBox */ + 0x55, 0x04, 0x12, + /* NID_physicalDeliveryOfficeName */ + 0x55, 0x04, 0x13, + /* NID_telephoneNumber */ + 0x55, 0x04, 0x14, + /* NID_telexNumber */ + 0x55, 0x04, 0x15, + /* NID_teletexTerminalIdentifier */ + 0x55, 0x04, 0x16, + /* NID_facsimileTelephoneNumber */ + 0x55, 0x04, 0x17, + /* NID_x121Address */ + 0x55, 0x04, 0x18, + /* NID_internationaliSDNNumber */ + 0x55, 0x04, 0x19, + /* NID_registeredAddress */ + 0x55, 0x04, 0x1a, + /* NID_destinationIndicator */ + 0x55, 0x04, 0x1b, + /* NID_preferredDeliveryMethod */ + 0x55, 0x04, 0x1c, + /* NID_presentationAddress */ + 0x55, 0x04, 0x1d, + /* NID_supportedApplicationContext */ + 0x55, 0x04, 0x1e, + /* NID_member */ + 0x55, 0x04, 0x1f, + /* NID_owner */ + 0x55, 0x04, 0x20, + /* NID_roleOccupant */ + 0x55, 0x04, 0x21, + /* NID_seeAlso */ + 0x55, 0x04, 0x22, + /* NID_userPassword */ + 0x55, 0x04, 0x23, + /* NID_userCertificate */ + 0x55, 0x04, 0x24, + /* NID_cACertificate */ + 0x55, 0x04, 0x25, + /* NID_authorityRevocationList */ + 0x55, 0x04, 0x26, + /* NID_certificateRevocationList */ + 0x55, 0x04, 0x27, + /* NID_crossCertificatePair */ + 0x55, 0x04, 0x28, + /* NID_enhancedSearchGuide */ + 0x55, 0x04, 0x2f, + /* NID_protocolInformation */ + 0x55, 0x04, 0x30, + /* NID_distinguishedName */ + 0x55, 0x04, 0x31, + /* NID_uniqueMember */ + 0x55, 0x04, 0x32, + /* NID_houseIdentifier */ + 0x55, 0x04, 0x33, + /* NID_supportedAlgorithms */ + 0x55, 0x04, 0x34, + /* NID_deltaRevocationList */ + 0x55, 0x04, 0x35, + /* NID_dmdName */ + 0x55, 0x04, 0x36, + /* NID_id_alg_PWRI_KEK */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x03, 0x09, + /* NID_aes_128_gcm */ + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x06, + /* NID_aes_128_ccm */ + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x07, + /* NID_id_aes128_wrap_pad */ + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x08, + /* NID_aes_192_gcm */ + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x1a, + /* NID_aes_192_ccm */ + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x1b, + /* NID_id_aes192_wrap_pad */ + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x1c, + /* NID_aes_256_gcm */ + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x2e, + /* NID_aes_256_ccm */ + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x2f, + /* NID_id_aes256_wrap_pad */ + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x30, + /* NID_id_camellia128_wrap */ + 0x2a, 0x83, 0x08, 0x8c, 0x9a, 0x4b, 0x3d, 0x01, 0x01, 0x03, 0x02, + /* NID_id_camellia192_wrap */ + 0x2a, 0x83, 0x08, 0x8c, 0x9a, 0x4b, 0x3d, 0x01, 0x01, 0x03, 0x03, + /* NID_id_camellia256_wrap */ + 0x2a, 0x83, 0x08, 0x8c, 0x9a, 0x4b, 0x3d, 0x01, 0x01, 0x03, 0x04, + /* NID_anyExtendedKeyUsage */ + 0x55, 0x1d, 0x25, 0x00, + /* NID_mgf1 */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x08, + /* NID_rsassaPss */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0a, + /* NID_rsaesOaep */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x07, + /* NID_dhpublicnumber */ + 0x2a, 0x86, 0x48, 0xce, 0x3e, 0x02, 0x01, + /* NID_brainpoolP160r1 */ + 0x2b, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x01, + /* NID_brainpoolP160t1 */ + 0x2b, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x02, + /* NID_brainpoolP192r1 */ + 0x2b, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x03, + /* NID_brainpoolP192t1 */ + 0x2b, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x04, + /* NID_brainpoolP224r1 */ + 0x2b, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x05, + /* NID_brainpoolP224t1 */ + 0x2b, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x06, + /* NID_brainpoolP256r1 */ + 0x2b, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x07, + /* NID_brainpoolP256t1 */ + 0x2b, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x08, + /* NID_brainpoolP320r1 */ + 0x2b, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x09, + /* NID_brainpoolP320t1 */ + 0x2b, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0a, + /* NID_brainpoolP384r1 */ + 0x2b, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0b, + /* NID_brainpoolP384t1 */ + 0x2b, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0c, + /* NID_brainpoolP512r1 */ + 0x2b, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0d, + /* NID_brainpoolP512t1 */ + 0x2b, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0e, + /* NID_pSpecified */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x09, + /* NID_dhSinglePass_stdDH_sha1kdf_scheme */ + 0x2b, 0x81, 0x05, 0x10, 0x86, 0x48, 0x3f, 0x00, 0x02, + /* NID_dhSinglePass_stdDH_sha224kdf_scheme */ + 0x2b, 0x81, 0x04, 0x01, 0x0b, 0x00, + /* NID_dhSinglePass_stdDH_sha256kdf_scheme */ + 0x2b, 0x81, 0x04, 0x01, 0x0b, 0x01, + /* NID_dhSinglePass_stdDH_sha384kdf_scheme */ + 0x2b, 0x81, 0x04, 0x01, 0x0b, 0x02, + /* NID_dhSinglePass_stdDH_sha512kdf_scheme */ + 0x2b, 0x81, 0x04, 0x01, 0x0b, 0x03, + /* NID_dhSinglePass_cofactorDH_sha1kdf_scheme */ + 0x2b, 0x81, 0x05, 0x10, 0x86, 0x48, 0x3f, 0x00, 0x03, + /* NID_dhSinglePass_cofactorDH_sha224kdf_scheme */ + 0x2b, 0x81, 0x04, 0x01, 0x0e, 0x00, + /* NID_dhSinglePass_cofactorDH_sha256kdf_scheme */ + 0x2b, 0x81, 0x04, 0x01, 0x0e, 0x01, + /* NID_dhSinglePass_cofactorDH_sha384kdf_scheme */ + 0x2b, 0x81, 0x04, 0x01, 0x0e, 0x02, + /* NID_dhSinglePass_cofactorDH_sha512kdf_scheme */ + 0x2b, 0x81, 0x04, 0x01, 0x0e, 0x03, }; -static const ASN1_OBJECT kObjects[NUM_NID]={ -{"UNDEF","undefined",NID_undef,0,NULL,0}, -{"rsadsi","RSA Data Security, Inc.",NID_rsadsi,6,&(lvalues[0]),0}, -{"pkcs","RSA Data Security, Inc. PKCS",NID_pkcs,7,&(lvalues[6]),0}, -{"MD2","md2",NID_md2,8,&(lvalues[13]),0}, -{"MD5","md5",NID_md5,8,&(lvalues[21]),0}, -{"RC4","rc4",NID_rc4,8,&(lvalues[29]),0}, -{"rsaEncryption","rsaEncryption",NID_rsaEncryption,9,&(lvalues[37]),0}, -{"RSA-MD2","md2WithRSAEncryption",NID_md2WithRSAEncryption,9, - &(lvalues[46]),0}, -{"RSA-MD5","md5WithRSAEncryption",NID_md5WithRSAEncryption,9, - &(lvalues[55]),0}, -{"PBE-MD2-DES","pbeWithMD2AndDES-CBC",NID_pbeWithMD2AndDES_CBC,9, - &(lvalues[64]),0}, -{"PBE-MD5-DES","pbeWithMD5AndDES-CBC",NID_pbeWithMD5AndDES_CBC,9, - &(lvalues[73]),0}, -{"X500","directory services (X.500)",NID_X500,1,&(lvalues[82]),0}, -{"X509","X509",NID_X509,2,&(lvalues[83]),0}, -{"CN","commonName",NID_commonName,3,&(lvalues[85]),0}, -{"C","countryName",NID_countryName,3,&(lvalues[88]),0}, -{"L","localityName",NID_localityName,3,&(lvalues[91]),0}, -{"ST","stateOrProvinceName",NID_stateOrProvinceName,3,&(lvalues[94]),0}, -{"O","organizationName",NID_organizationName,3,&(lvalues[97]),0}, -{"OU","organizationalUnitName",NID_organizationalUnitName,3, - &(lvalues[100]),0}, -{"RSA","rsa",NID_rsa,4,&(lvalues[103]),0}, -{"pkcs7","pkcs7",NID_pkcs7,8,&(lvalues[107]),0}, -{"pkcs7-data","pkcs7-data",NID_pkcs7_data,9,&(lvalues[115]),0}, -{"pkcs7-signedData","pkcs7-signedData",NID_pkcs7_signed,9, - &(lvalues[124]),0}, -{"pkcs7-envelopedData","pkcs7-envelopedData",NID_pkcs7_enveloped,9, - &(lvalues[133]),0}, -{"pkcs7-signedAndEnvelopedData","pkcs7-signedAndEnvelopedData", - NID_pkcs7_signedAndEnveloped,9,&(lvalues[142]),0}, -{"pkcs7-digestData","pkcs7-digestData",NID_pkcs7_digest,9, - &(lvalues[151]),0}, -{"pkcs7-encryptedData","pkcs7-encryptedData",NID_pkcs7_encrypted,9, - &(lvalues[160]),0}, -{"pkcs3","pkcs3",NID_pkcs3,8,&(lvalues[169]),0}, -{"dhKeyAgreement","dhKeyAgreement",NID_dhKeyAgreement,9, - &(lvalues[177]),0}, -{"DES-ECB","des-ecb",NID_des_ecb,5,&(lvalues[186]),0}, -{"DES-CFB","des-cfb",NID_des_cfb64,5,&(lvalues[191]),0}, -{"DES-CBC","des-cbc",NID_des_cbc,5,&(lvalues[196]),0}, -{"DES-EDE","des-ede",NID_des_ede_ecb,5,&(lvalues[201]),0}, -{"DES-EDE3","des-ede3",NID_des_ede3_ecb,0,NULL,0}, -{"IDEA-CBC","idea-cbc",NID_idea_cbc,11,&(lvalues[206]),0}, -{"IDEA-CFB","idea-cfb",NID_idea_cfb64,0,NULL,0}, -{"IDEA-ECB","idea-ecb",NID_idea_ecb,0,NULL,0}, -{"RC2-CBC","rc2-cbc",NID_rc2_cbc,8,&(lvalues[217]),0}, -{"RC2-ECB","rc2-ecb",NID_rc2_ecb,0,NULL,0}, -{"RC2-CFB","rc2-cfb",NID_rc2_cfb64,0,NULL,0}, -{"RC2-OFB","rc2-ofb",NID_rc2_ofb64,0,NULL,0}, -{"SHA","sha",NID_sha,5,&(lvalues[225]),0}, -{"RSA-SHA","shaWithRSAEncryption",NID_shaWithRSAEncryption,5, - &(lvalues[230]),0}, -{"DES-EDE-CBC","des-ede-cbc",NID_des_ede_cbc,0,NULL,0}, -{"DES-EDE3-CBC","des-ede3-cbc",NID_des_ede3_cbc,8,&(lvalues[235]),0}, -{"DES-OFB","des-ofb",NID_des_ofb64,5,&(lvalues[243]),0}, -{"IDEA-OFB","idea-ofb",NID_idea_ofb64,0,NULL,0}, -{"pkcs9","pkcs9",NID_pkcs9,8,&(lvalues[248]),0}, -{"emailAddress","emailAddress",NID_pkcs9_emailAddress,9, - &(lvalues[256]),0}, -{"unstructuredName","unstructuredName",NID_pkcs9_unstructuredName,9, - &(lvalues[265]),0}, -{"contentType","contentType",NID_pkcs9_contentType,9,&(lvalues[274]),0}, -{"messageDigest","messageDigest",NID_pkcs9_messageDigest,9, - &(lvalues[283]),0}, -{"signingTime","signingTime",NID_pkcs9_signingTime,9,&(lvalues[292]),0}, -{"countersignature","countersignature",NID_pkcs9_countersignature,9, - &(lvalues[301]),0}, -{"challengePassword","challengePassword",NID_pkcs9_challengePassword, - 9,&(lvalues[310]),0}, -{"unstructuredAddress","unstructuredAddress", - NID_pkcs9_unstructuredAddress,9,&(lvalues[319]),0}, -{"extendedCertificateAttributes","extendedCertificateAttributes", - NID_pkcs9_extCertAttributes,9,&(lvalues[328]),0}, -{"Netscape","Netscape Communications Corp.",NID_netscape,7, - &(lvalues[337]),0}, -{"nsCertExt","Netscape Certificate Extension", - NID_netscape_cert_extension,8,&(lvalues[344]),0}, -{"nsDataType","Netscape Data Type",NID_netscape_data_type,8, - &(lvalues[352]),0}, -{"DES-EDE-CFB","des-ede-cfb",NID_des_ede_cfb64,0,NULL,0}, -{"DES-EDE3-CFB","des-ede3-cfb",NID_des_ede3_cfb64,0,NULL,0}, -{"DES-EDE-OFB","des-ede-ofb",NID_des_ede_ofb64,0,NULL,0}, -{"DES-EDE3-OFB","des-ede3-ofb",NID_des_ede3_ofb64,0,NULL,0}, -{"SHA1","sha1",NID_sha1,5,&(lvalues[360]),0}, -{"RSA-SHA1","sha1WithRSAEncryption",NID_sha1WithRSAEncryption,9, - &(lvalues[365]),0}, -{"DSA-SHA","dsaWithSHA",NID_dsaWithSHA,5,&(lvalues[374]),0}, -{"DSA-old","dsaEncryption-old",NID_dsa_2,5,&(lvalues[379]),0}, -{"PBE-SHA1-RC2-64","pbeWithSHA1AndRC2-CBC",NID_pbeWithSHA1AndRC2_CBC, - 9,&(lvalues[384]),0}, -{"PBKDF2","PBKDF2",NID_id_pbkdf2,9,&(lvalues[393]),0}, -{"DSA-SHA1-old","dsaWithSHA1-old",NID_dsaWithSHA1_2,5,&(lvalues[402]),0}, -{"nsCertType","Netscape Cert Type",NID_netscape_cert_type,9, - &(lvalues[407]),0}, -{"nsBaseUrl","Netscape Base Url",NID_netscape_base_url,9, - &(lvalues[416]),0}, -{"nsRevocationUrl","Netscape Revocation Url", - NID_netscape_revocation_url,9,&(lvalues[425]),0}, -{"nsCaRevocationUrl","Netscape CA Revocation Url", - NID_netscape_ca_revocation_url,9,&(lvalues[434]),0}, -{"nsRenewalUrl","Netscape Renewal Url",NID_netscape_renewal_url,9, - &(lvalues[443]),0}, -{"nsCaPolicyUrl","Netscape CA Policy Url",NID_netscape_ca_policy_url, - 9,&(lvalues[452]),0}, -{"nsSslServerName","Netscape SSL Server Name", - NID_netscape_ssl_server_name,9,&(lvalues[461]),0}, -{"nsComment","Netscape Comment",NID_netscape_comment,9,&(lvalues[470]),0}, -{"nsCertSequence","Netscape Certificate Sequence", - NID_netscape_cert_sequence,9,&(lvalues[479]),0}, -{"DESX-CBC","desx-cbc",NID_desx_cbc,0,NULL,0}, -{"id-ce","id-ce",NID_id_ce,2,&(lvalues[488]),0}, -{"subjectKeyIdentifier","X509v3 Subject Key Identifier", - NID_subject_key_identifier,3,&(lvalues[490]),0}, -{"keyUsage","X509v3 Key Usage",NID_key_usage,3,&(lvalues[493]),0}, -{"privateKeyUsagePeriod","X509v3 Private Key Usage Period", - NID_private_key_usage_period,3,&(lvalues[496]),0}, -{"subjectAltName","X509v3 Subject Alternative Name", - NID_subject_alt_name,3,&(lvalues[499]),0}, -{"issuerAltName","X509v3 Issuer Alternative Name",NID_issuer_alt_name, - 3,&(lvalues[502]),0}, -{"basicConstraints","X509v3 Basic Constraints",NID_basic_constraints, - 3,&(lvalues[505]),0}, -{"crlNumber","X509v3 CRL Number",NID_crl_number,3,&(lvalues[508]),0}, -{"certificatePolicies","X509v3 Certificate Policies", - NID_certificate_policies,3,&(lvalues[511]),0}, -{"authorityKeyIdentifier","X509v3 Authority Key Identifier", - NID_authority_key_identifier,3,&(lvalues[514]),0}, -{"BF-CBC","bf-cbc",NID_bf_cbc,9,&(lvalues[517]),0}, -{"BF-ECB","bf-ecb",NID_bf_ecb,0,NULL,0}, -{"BF-CFB","bf-cfb",NID_bf_cfb64,0,NULL,0}, -{"BF-OFB","bf-ofb",NID_bf_ofb64,0,NULL,0}, -{"MDC2","mdc2",NID_mdc2,4,&(lvalues[526]),0}, -{"RSA-MDC2","mdc2WithRSA",NID_mdc2WithRSA,4,&(lvalues[530]),0}, -{"RC4-40","rc4-40",NID_rc4_40,0,NULL,0}, -{"RC2-40-CBC","rc2-40-cbc",NID_rc2_40_cbc,0,NULL,0}, -{"GN","givenName",NID_givenName,3,&(lvalues[534]),0}, -{"SN","surname",NID_surname,3,&(lvalues[537]),0}, -{"initials","initials",NID_initials,3,&(lvalues[540]),0}, -{NULL,NULL,NID_undef,0,NULL,0}, -{"crlDistributionPoints","X509v3 CRL Distribution Points", - NID_crl_distribution_points,3,&(lvalues[543]),0}, -{"RSA-NP-MD5","md5WithRSA",NID_md5WithRSA,5,&(lvalues[546]),0}, -{"serialNumber","serialNumber",NID_serialNumber,3,&(lvalues[551]),0}, -{"title","title",NID_title,3,&(lvalues[554]),0}, -{"description","description",NID_description,3,&(lvalues[557]),0}, -{"CAST5-CBC","cast5-cbc",NID_cast5_cbc,9,&(lvalues[560]),0}, -{"CAST5-ECB","cast5-ecb",NID_cast5_ecb,0,NULL,0}, -{"CAST5-CFB","cast5-cfb",NID_cast5_cfb64,0,NULL,0}, -{"CAST5-OFB","cast5-ofb",NID_cast5_ofb64,0,NULL,0}, -{"pbeWithMD5AndCast5CBC","pbeWithMD5AndCast5CBC", - NID_pbeWithMD5AndCast5_CBC,9,&(lvalues[569]),0}, -{"DSA-SHA1","dsaWithSHA1",NID_dsaWithSHA1,7,&(lvalues[578]),0}, -{"MD5-SHA1","md5-sha1",NID_md5_sha1,0,NULL,0}, -{"RSA-SHA1-2","sha1WithRSA",NID_sha1WithRSA,5,&(lvalues[585]),0}, -{"DSA","dsaEncryption",NID_dsa,7,&(lvalues[590]),0}, -{"RIPEMD160","ripemd160",NID_ripemd160,5,&(lvalues[597]),0}, -{NULL,NULL,NID_undef,0,NULL,0}, -{"RSA-RIPEMD160","ripemd160WithRSA",NID_ripemd160WithRSA,6, - &(lvalues[602]),0}, -{"RC5-CBC","rc5-cbc",NID_rc5_cbc,8,&(lvalues[608]),0}, -{"RC5-ECB","rc5-ecb",NID_rc5_ecb,0,NULL,0}, -{"RC5-CFB","rc5-cfb",NID_rc5_cfb64,0,NULL,0}, -{"RC5-OFB","rc5-ofb",NID_rc5_ofb64,0,NULL,0}, -{NULL,NULL,NID_undef,0,NULL,0}, -{"ZLIB","zlib compression",NID_zlib_compression,11,&(lvalues[616]),0}, -{"extendedKeyUsage","X509v3 Extended Key Usage",NID_ext_key_usage,3, - &(lvalues[627]),0}, -{"PKIX","PKIX",NID_id_pkix,6,&(lvalues[630]),0}, -{"id-kp","id-kp",NID_id_kp,7,&(lvalues[636]),0}, -{"serverAuth","TLS Web Server Authentication",NID_server_auth,8, - &(lvalues[643]),0}, -{"clientAuth","TLS Web Client Authentication",NID_client_auth,8, - &(lvalues[651]),0}, -{"codeSigning","Code Signing",NID_code_sign,8,&(lvalues[659]),0}, -{"emailProtection","E-mail Protection",NID_email_protect,8, - &(lvalues[667]),0}, -{"timeStamping","Time Stamping",NID_time_stamp,8,&(lvalues[675]),0}, -{"msCodeInd","Microsoft Individual Code Signing",NID_ms_code_ind,10, - &(lvalues[683]),0}, -{"msCodeCom","Microsoft Commercial Code Signing",NID_ms_code_com,10, - &(lvalues[693]),0}, -{"msCTLSign","Microsoft Trust List Signing",NID_ms_ctl_sign,10, - &(lvalues[703]),0}, -{"msSGC","Microsoft Server Gated Crypto",NID_ms_sgc,10,&(lvalues[713]),0}, -{"msEFS","Microsoft Encrypted File System",NID_ms_efs,10, - &(lvalues[723]),0}, -{"nsSGC","Netscape Server Gated Crypto",NID_ns_sgc,9,&(lvalues[733]),0}, -{"deltaCRL","X509v3 Delta CRL Indicator",NID_delta_crl,3, - &(lvalues[742]),0}, -{"CRLReason","X509v3 CRL Reason Code",NID_crl_reason,3,&(lvalues[745]),0}, -{"invalidityDate","Invalidity Date",NID_invalidity_date,3, - &(lvalues[748]),0}, -{"SXNetID","Strong Extranet ID",NID_sxnet,5,&(lvalues[751]),0}, -{"PBE-SHA1-RC4-128","pbeWithSHA1And128BitRC4", - NID_pbe_WithSHA1And128BitRC4,10,&(lvalues[756]),0}, -{"PBE-SHA1-RC4-40","pbeWithSHA1And40BitRC4", - NID_pbe_WithSHA1And40BitRC4,10,&(lvalues[766]),0}, -{"PBE-SHA1-3DES","pbeWithSHA1And3-KeyTripleDES-CBC", - NID_pbe_WithSHA1And3_Key_TripleDES_CBC,10,&(lvalues[776]),0}, -{"PBE-SHA1-2DES","pbeWithSHA1And2-KeyTripleDES-CBC", - NID_pbe_WithSHA1And2_Key_TripleDES_CBC,10,&(lvalues[786]),0}, -{"PBE-SHA1-RC2-128","pbeWithSHA1And128BitRC2-CBC", - NID_pbe_WithSHA1And128BitRC2_CBC,10,&(lvalues[796]),0}, -{"PBE-SHA1-RC2-40","pbeWithSHA1And40BitRC2-CBC", - NID_pbe_WithSHA1And40BitRC2_CBC,10,&(lvalues[806]),0}, -{"keyBag","keyBag",NID_keyBag,11,&(lvalues[816]),0}, -{"pkcs8ShroudedKeyBag","pkcs8ShroudedKeyBag",NID_pkcs8ShroudedKeyBag, - 11,&(lvalues[827]),0}, -{"certBag","certBag",NID_certBag,11,&(lvalues[838]),0}, -{"crlBag","crlBag",NID_crlBag,11,&(lvalues[849]),0}, -{"secretBag","secretBag",NID_secretBag,11,&(lvalues[860]),0}, -{"safeContentsBag","safeContentsBag",NID_safeContentsBag,11, - &(lvalues[871]),0}, -{"friendlyName","friendlyName",NID_friendlyName,9,&(lvalues[882]),0}, -{"localKeyID","localKeyID",NID_localKeyID,9,&(lvalues[891]),0}, -{"x509Certificate","x509Certificate",NID_x509Certificate,10, - &(lvalues[900]),0}, -{"sdsiCertificate","sdsiCertificate",NID_sdsiCertificate,10, - &(lvalues[910]),0}, -{"x509Crl","x509Crl",NID_x509Crl,10,&(lvalues[920]),0}, -{"PBES2","PBES2",NID_pbes2,9,&(lvalues[930]),0}, -{"PBMAC1","PBMAC1",NID_pbmac1,9,&(lvalues[939]),0}, -{"hmacWithSHA1","hmacWithSHA1",NID_hmacWithSHA1,8,&(lvalues[948]),0}, -{"id-qt-cps","Policy Qualifier CPS",NID_id_qt_cps,8,&(lvalues[956]),0}, -{"id-qt-unotice","Policy Qualifier User Notice",NID_id_qt_unotice,8, - &(lvalues[964]),0}, -{"RC2-64-CBC","rc2-64-cbc",NID_rc2_64_cbc,0,NULL,0}, -{"SMIME-CAPS","S/MIME Capabilities",NID_SMIMECapabilities,9, - &(lvalues[972]),0}, -{"PBE-MD2-RC2-64","pbeWithMD2AndRC2-CBC",NID_pbeWithMD2AndRC2_CBC,9, - &(lvalues[981]),0}, -{"PBE-MD5-RC2-64","pbeWithMD5AndRC2-CBC",NID_pbeWithMD5AndRC2_CBC,9, - &(lvalues[990]),0}, -{"PBE-SHA1-DES","pbeWithSHA1AndDES-CBC",NID_pbeWithSHA1AndDES_CBC,9, - &(lvalues[999]),0}, -{"msExtReq","Microsoft Extension Request",NID_ms_ext_req,10, - &(lvalues[1008]),0}, -{"extReq","Extension Request",NID_ext_req,9,&(lvalues[1018]),0}, -{"name","name",NID_name,3,&(lvalues[1027]),0}, -{"dnQualifier","dnQualifier",NID_dnQualifier,3,&(lvalues[1030]),0}, -{"id-pe","id-pe",NID_id_pe,7,&(lvalues[1033]),0}, -{"id-ad","id-ad",NID_id_ad,7,&(lvalues[1040]),0}, -{"authorityInfoAccess","Authority Information Access",NID_info_access, - 8,&(lvalues[1047]),0}, -{"OCSP","OCSP",NID_ad_OCSP,8,&(lvalues[1055]),0}, -{"caIssuers","CA Issuers",NID_ad_ca_issuers,8,&(lvalues[1063]),0}, -{"OCSPSigning","OCSP Signing",NID_OCSP_sign,8,&(lvalues[1071]),0}, -{"ISO","iso",NID_iso,0,NULL,0}, -{"member-body","ISO Member Body",NID_member_body,1,&(lvalues[1079]),0}, -{"ISO-US","ISO US Member Body",NID_ISO_US,3,&(lvalues[1080]),0}, -{"X9-57","X9.57",NID_X9_57,5,&(lvalues[1083]),0}, -{"X9cm","X9.57 CM ?",NID_X9cm,6,&(lvalues[1088]),0}, -{"pkcs1","pkcs1",NID_pkcs1,8,&(lvalues[1094]),0}, -{"pkcs5","pkcs5",NID_pkcs5,8,&(lvalues[1102]),0}, -{"SMIME","S/MIME",NID_SMIME,9,&(lvalues[1110]),0}, -{"id-smime-mod","id-smime-mod",NID_id_smime_mod,10,&(lvalues[1119]),0}, -{"id-smime-ct","id-smime-ct",NID_id_smime_ct,10,&(lvalues[1129]),0}, -{"id-smime-aa","id-smime-aa",NID_id_smime_aa,10,&(lvalues[1139]),0}, -{"id-smime-alg","id-smime-alg",NID_id_smime_alg,10,&(lvalues[1149]),0}, -{"id-smime-cd","id-smime-cd",NID_id_smime_cd,10,&(lvalues[1159]),0}, -{"id-smime-spq","id-smime-spq",NID_id_smime_spq,10,&(lvalues[1169]),0}, -{"id-smime-cti","id-smime-cti",NID_id_smime_cti,10,&(lvalues[1179]),0}, -{"id-smime-mod-cms","id-smime-mod-cms",NID_id_smime_mod_cms,11, - &(lvalues[1189]),0}, -{"id-smime-mod-ess","id-smime-mod-ess",NID_id_smime_mod_ess,11, - &(lvalues[1200]),0}, -{"id-smime-mod-oid","id-smime-mod-oid",NID_id_smime_mod_oid,11, - &(lvalues[1211]),0}, -{"id-smime-mod-msg-v3","id-smime-mod-msg-v3",NID_id_smime_mod_msg_v3, - 11,&(lvalues[1222]),0}, -{"id-smime-mod-ets-eSignature-88","id-smime-mod-ets-eSignature-88", - NID_id_smime_mod_ets_eSignature_88,11,&(lvalues[1233]),0}, -{"id-smime-mod-ets-eSignature-97","id-smime-mod-ets-eSignature-97", - NID_id_smime_mod_ets_eSignature_97,11,&(lvalues[1244]),0}, -{"id-smime-mod-ets-eSigPolicy-88","id-smime-mod-ets-eSigPolicy-88", - NID_id_smime_mod_ets_eSigPolicy_88,11,&(lvalues[1255]),0}, -{"id-smime-mod-ets-eSigPolicy-97","id-smime-mod-ets-eSigPolicy-97", - NID_id_smime_mod_ets_eSigPolicy_97,11,&(lvalues[1266]),0}, -{"id-smime-ct-receipt","id-smime-ct-receipt",NID_id_smime_ct_receipt, - 11,&(lvalues[1277]),0}, -{"id-smime-ct-authData","id-smime-ct-authData", - NID_id_smime_ct_authData,11,&(lvalues[1288]),0}, -{"id-smime-ct-publishCert","id-smime-ct-publishCert", - NID_id_smime_ct_publishCert,11,&(lvalues[1299]),0}, -{"id-smime-ct-TSTInfo","id-smime-ct-TSTInfo",NID_id_smime_ct_TSTInfo, - 11,&(lvalues[1310]),0}, -{"id-smime-ct-TDTInfo","id-smime-ct-TDTInfo",NID_id_smime_ct_TDTInfo, - 11,&(lvalues[1321]),0}, -{"id-smime-ct-contentInfo","id-smime-ct-contentInfo", - NID_id_smime_ct_contentInfo,11,&(lvalues[1332]),0}, -{"id-smime-ct-DVCSRequestData","id-smime-ct-DVCSRequestData", - NID_id_smime_ct_DVCSRequestData,11,&(lvalues[1343]),0}, -{"id-smime-ct-DVCSResponseData","id-smime-ct-DVCSResponseData", - NID_id_smime_ct_DVCSResponseData,11,&(lvalues[1354]),0}, -{"id-smime-aa-receiptRequest","id-smime-aa-receiptRequest", - NID_id_smime_aa_receiptRequest,11,&(lvalues[1365]),0}, -{"id-smime-aa-securityLabel","id-smime-aa-securityLabel", - NID_id_smime_aa_securityLabel,11,&(lvalues[1376]),0}, -{"id-smime-aa-mlExpandHistory","id-smime-aa-mlExpandHistory", - NID_id_smime_aa_mlExpandHistory,11,&(lvalues[1387]),0}, -{"id-smime-aa-contentHint","id-smime-aa-contentHint", - NID_id_smime_aa_contentHint,11,&(lvalues[1398]),0}, -{"id-smime-aa-msgSigDigest","id-smime-aa-msgSigDigest", - NID_id_smime_aa_msgSigDigest,11,&(lvalues[1409]),0}, -{"id-smime-aa-encapContentType","id-smime-aa-encapContentType", - NID_id_smime_aa_encapContentType,11,&(lvalues[1420]),0}, -{"id-smime-aa-contentIdentifier","id-smime-aa-contentIdentifier", - NID_id_smime_aa_contentIdentifier,11,&(lvalues[1431]),0}, -{"id-smime-aa-macValue","id-smime-aa-macValue", - NID_id_smime_aa_macValue,11,&(lvalues[1442]),0}, -{"id-smime-aa-equivalentLabels","id-smime-aa-equivalentLabels", - NID_id_smime_aa_equivalentLabels,11,&(lvalues[1453]),0}, -{"id-smime-aa-contentReference","id-smime-aa-contentReference", - NID_id_smime_aa_contentReference,11,&(lvalues[1464]),0}, -{"id-smime-aa-encrypKeyPref","id-smime-aa-encrypKeyPref", - NID_id_smime_aa_encrypKeyPref,11,&(lvalues[1475]),0}, -{"id-smime-aa-signingCertificate","id-smime-aa-signingCertificate", - NID_id_smime_aa_signingCertificate,11,&(lvalues[1486]),0}, -{"id-smime-aa-smimeEncryptCerts","id-smime-aa-smimeEncryptCerts", - NID_id_smime_aa_smimeEncryptCerts,11,&(lvalues[1497]),0}, -{"id-smime-aa-timeStampToken","id-smime-aa-timeStampToken", - NID_id_smime_aa_timeStampToken,11,&(lvalues[1508]),0}, -{"id-smime-aa-ets-sigPolicyId","id-smime-aa-ets-sigPolicyId", - NID_id_smime_aa_ets_sigPolicyId,11,&(lvalues[1519]),0}, -{"id-smime-aa-ets-commitmentType","id-smime-aa-ets-commitmentType", - NID_id_smime_aa_ets_commitmentType,11,&(lvalues[1530]),0}, -{"id-smime-aa-ets-signerLocation","id-smime-aa-ets-signerLocation", - NID_id_smime_aa_ets_signerLocation,11,&(lvalues[1541]),0}, -{"id-smime-aa-ets-signerAttr","id-smime-aa-ets-signerAttr", - NID_id_smime_aa_ets_signerAttr,11,&(lvalues[1552]),0}, -{"id-smime-aa-ets-otherSigCert","id-smime-aa-ets-otherSigCert", - NID_id_smime_aa_ets_otherSigCert,11,&(lvalues[1563]),0}, -{"id-smime-aa-ets-contentTimestamp", - "id-smime-aa-ets-contentTimestamp", - NID_id_smime_aa_ets_contentTimestamp,11,&(lvalues[1574]),0}, -{"id-smime-aa-ets-CertificateRefs","id-smime-aa-ets-CertificateRefs", - NID_id_smime_aa_ets_CertificateRefs,11,&(lvalues[1585]),0}, -{"id-smime-aa-ets-RevocationRefs","id-smime-aa-ets-RevocationRefs", - NID_id_smime_aa_ets_RevocationRefs,11,&(lvalues[1596]),0}, -{"id-smime-aa-ets-certValues","id-smime-aa-ets-certValues", - NID_id_smime_aa_ets_certValues,11,&(lvalues[1607]),0}, -{"id-smime-aa-ets-revocationValues", - "id-smime-aa-ets-revocationValues", - NID_id_smime_aa_ets_revocationValues,11,&(lvalues[1618]),0}, -{"id-smime-aa-ets-escTimeStamp","id-smime-aa-ets-escTimeStamp", - NID_id_smime_aa_ets_escTimeStamp,11,&(lvalues[1629]),0}, -{"id-smime-aa-ets-certCRLTimestamp", - "id-smime-aa-ets-certCRLTimestamp", - NID_id_smime_aa_ets_certCRLTimestamp,11,&(lvalues[1640]),0}, -{"id-smime-aa-ets-archiveTimeStamp", - "id-smime-aa-ets-archiveTimeStamp", - NID_id_smime_aa_ets_archiveTimeStamp,11,&(lvalues[1651]),0}, -{"id-smime-aa-signatureType","id-smime-aa-signatureType", - NID_id_smime_aa_signatureType,11,&(lvalues[1662]),0}, -{"id-smime-aa-dvcs-dvc","id-smime-aa-dvcs-dvc", - NID_id_smime_aa_dvcs_dvc,11,&(lvalues[1673]),0}, -{"id-smime-alg-ESDHwith3DES","id-smime-alg-ESDHwith3DES", - NID_id_smime_alg_ESDHwith3DES,11,&(lvalues[1684]),0}, -{"id-smime-alg-ESDHwithRC2","id-smime-alg-ESDHwithRC2", - NID_id_smime_alg_ESDHwithRC2,11,&(lvalues[1695]),0}, -{"id-smime-alg-3DESwrap","id-smime-alg-3DESwrap", - NID_id_smime_alg_3DESwrap,11,&(lvalues[1706]),0}, -{"id-smime-alg-RC2wrap","id-smime-alg-RC2wrap", - NID_id_smime_alg_RC2wrap,11,&(lvalues[1717]),0}, -{"id-smime-alg-ESDH","id-smime-alg-ESDH",NID_id_smime_alg_ESDH,11, - &(lvalues[1728]),0}, -{"id-smime-alg-CMS3DESwrap","id-smime-alg-CMS3DESwrap", - NID_id_smime_alg_CMS3DESwrap,11,&(lvalues[1739]),0}, -{"id-smime-alg-CMSRC2wrap","id-smime-alg-CMSRC2wrap", - NID_id_smime_alg_CMSRC2wrap,11,&(lvalues[1750]),0}, -{"id-smime-cd-ldap","id-smime-cd-ldap",NID_id_smime_cd_ldap,11, - &(lvalues[1761]),0}, -{"id-smime-spq-ets-sqt-uri","id-smime-spq-ets-sqt-uri", - NID_id_smime_spq_ets_sqt_uri,11,&(lvalues[1772]),0}, -{"id-smime-spq-ets-sqt-unotice","id-smime-spq-ets-sqt-unotice", - NID_id_smime_spq_ets_sqt_unotice,11,&(lvalues[1783]),0}, -{"id-smime-cti-ets-proofOfOrigin","id-smime-cti-ets-proofOfOrigin", - NID_id_smime_cti_ets_proofOfOrigin,11,&(lvalues[1794]),0}, -{"id-smime-cti-ets-proofOfReceipt","id-smime-cti-ets-proofOfReceipt", - NID_id_smime_cti_ets_proofOfReceipt,11,&(lvalues[1805]),0}, -{"id-smime-cti-ets-proofOfDelivery", - "id-smime-cti-ets-proofOfDelivery", - NID_id_smime_cti_ets_proofOfDelivery,11,&(lvalues[1816]),0}, -{"id-smime-cti-ets-proofOfSender","id-smime-cti-ets-proofOfSender", - NID_id_smime_cti_ets_proofOfSender,11,&(lvalues[1827]),0}, -{"id-smime-cti-ets-proofOfApproval", - "id-smime-cti-ets-proofOfApproval", - NID_id_smime_cti_ets_proofOfApproval,11,&(lvalues[1838]),0}, -{"id-smime-cti-ets-proofOfCreation", - "id-smime-cti-ets-proofOfCreation", - NID_id_smime_cti_ets_proofOfCreation,11,&(lvalues[1849]),0}, -{"MD4","md4",NID_md4,8,&(lvalues[1860]),0}, -{"id-pkix-mod","id-pkix-mod",NID_id_pkix_mod,7,&(lvalues[1868]),0}, -{"id-qt","id-qt",NID_id_qt,7,&(lvalues[1875]),0}, -{"id-it","id-it",NID_id_it,7,&(lvalues[1882]),0}, -{"id-pkip","id-pkip",NID_id_pkip,7,&(lvalues[1889]),0}, -{"id-alg","id-alg",NID_id_alg,7,&(lvalues[1896]),0}, -{"id-cmc","id-cmc",NID_id_cmc,7,&(lvalues[1903]),0}, -{"id-on","id-on",NID_id_on,7,&(lvalues[1910]),0}, -{"id-pda","id-pda",NID_id_pda,7,&(lvalues[1917]),0}, -{"id-aca","id-aca",NID_id_aca,7,&(lvalues[1924]),0}, -{"id-qcs","id-qcs",NID_id_qcs,7,&(lvalues[1931]),0}, -{"id-cct","id-cct",NID_id_cct,7,&(lvalues[1938]),0}, -{"id-pkix1-explicit-88","id-pkix1-explicit-88", - NID_id_pkix1_explicit_88,8,&(lvalues[1945]),0}, -{"id-pkix1-implicit-88","id-pkix1-implicit-88", - NID_id_pkix1_implicit_88,8,&(lvalues[1953]),0}, -{"id-pkix1-explicit-93","id-pkix1-explicit-93", - NID_id_pkix1_explicit_93,8,&(lvalues[1961]),0}, -{"id-pkix1-implicit-93","id-pkix1-implicit-93", - NID_id_pkix1_implicit_93,8,&(lvalues[1969]),0}, -{"id-mod-crmf","id-mod-crmf",NID_id_mod_crmf,8,&(lvalues[1977]),0}, -{"id-mod-cmc","id-mod-cmc",NID_id_mod_cmc,8,&(lvalues[1985]),0}, -{"id-mod-kea-profile-88","id-mod-kea-profile-88", - NID_id_mod_kea_profile_88,8,&(lvalues[1993]),0}, -{"id-mod-kea-profile-93","id-mod-kea-profile-93", - NID_id_mod_kea_profile_93,8,&(lvalues[2001]),0}, -{"id-mod-cmp","id-mod-cmp",NID_id_mod_cmp,8,&(lvalues[2009]),0}, -{"id-mod-qualified-cert-88","id-mod-qualified-cert-88", - NID_id_mod_qualified_cert_88,8,&(lvalues[2017]),0}, -{"id-mod-qualified-cert-93","id-mod-qualified-cert-93", - NID_id_mod_qualified_cert_93,8,&(lvalues[2025]),0}, -{"id-mod-attribute-cert","id-mod-attribute-cert", - NID_id_mod_attribute_cert,8,&(lvalues[2033]),0}, -{"id-mod-timestamp-protocol","id-mod-timestamp-protocol", - NID_id_mod_timestamp_protocol,8,&(lvalues[2041]),0}, -{"id-mod-ocsp","id-mod-ocsp",NID_id_mod_ocsp,8,&(lvalues[2049]),0}, -{"id-mod-dvcs","id-mod-dvcs",NID_id_mod_dvcs,8,&(lvalues[2057]),0}, -{"id-mod-cmp2000","id-mod-cmp2000",NID_id_mod_cmp2000,8, - &(lvalues[2065]),0}, -{"biometricInfo","Biometric Info",NID_biometricInfo,8,&(lvalues[2073]),0}, -{"qcStatements","qcStatements",NID_qcStatements,8,&(lvalues[2081]),0}, -{"ac-auditEntity","ac-auditEntity",NID_ac_auditEntity,8, - &(lvalues[2089]),0}, -{"ac-targeting","ac-targeting",NID_ac_targeting,8,&(lvalues[2097]),0}, -{"aaControls","aaControls",NID_aaControls,8,&(lvalues[2105]),0}, -{"sbgp-ipAddrBlock","sbgp-ipAddrBlock",NID_sbgp_ipAddrBlock,8, - &(lvalues[2113]),0}, -{"sbgp-autonomousSysNum","sbgp-autonomousSysNum", - NID_sbgp_autonomousSysNum,8,&(lvalues[2121]),0}, -{"sbgp-routerIdentifier","sbgp-routerIdentifier", - NID_sbgp_routerIdentifier,8,&(lvalues[2129]),0}, -{"textNotice","textNotice",NID_textNotice,8,&(lvalues[2137]),0}, -{"ipsecEndSystem","IPSec End System",NID_ipsecEndSystem,8, - &(lvalues[2145]),0}, -{"ipsecTunnel","IPSec Tunnel",NID_ipsecTunnel,8,&(lvalues[2153]),0}, -{"ipsecUser","IPSec User",NID_ipsecUser,8,&(lvalues[2161]),0}, -{"DVCS","dvcs",NID_dvcs,8,&(lvalues[2169]),0}, -{"id-it-caProtEncCert","id-it-caProtEncCert",NID_id_it_caProtEncCert, - 8,&(lvalues[2177]),0}, -{"id-it-signKeyPairTypes","id-it-signKeyPairTypes", - NID_id_it_signKeyPairTypes,8,&(lvalues[2185]),0}, -{"id-it-encKeyPairTypes","id-it-encKeyPairTypes", - NID_id_it_encKeyPairTypes,8,&(lvalues[2193]),0}, -{"id-it-preferredSymmAlg","id-it-preferredSymmAlg", - NID_id_it_preferredSymmAlg,8,&(lvalues[2201]),0}, -{"id-it-caKeyUpdateInfo","id-it-caKeyUpdateInfo", - NID_id_it_caKeyUpdateInfo,8,&(lvalues[2209]),0}, -{"id-it-currentCRL","id-it-currentCRL",NID_id_it_currentCRL,8, - &(lvalues[2217]),0}, -{"id-it-unsupportedOIDs","id-it-unsupportedOIDs", - NID_id_it_unsupportedOIDs,8,&(lvalues[2225]),0}, -{"id-it-subscriptionRequest","id-it-subscriptionRequest", - NID_id_it_subscriptionRequest,8,&(lvalues[2233]),0}, -{"id-it-subscriptionResponse","id-it-subscriptionResponse", - NID_id_it_subscriptionResponse,8,&(lvalues[2241]),0}, -{"id-it-keyPairParamReq","id-it-keyPairParamReq", - NID_id_it_keyPairParamReq,8,&(lvalues[2249]),0}, -{"id-it-keyPairParamRep","id-it-keyPairParamRep", - NID_id_it_keyPairParamRep,8,&(lvalues[2257]),0}, -{"id-it-revPassphrase","id-it-revPassphrase",NID_id_it_revPassphrase, - 8,&(lvalues[2265]),0}, -{"id-it-implicitConfirm","id-it-implicitConfirm", - NID_id_it_implicitConfirm,8,&(lvalues[2273]),0}, -{"id-it-confirmWaitTime","id-it-confirmWaitTime", - NID_id_it_confirmWaitTime,8,&(lvalues[2281]),0}, -{"id-it-origPKIMessage","id-it-origPKIMessage", - NID_id_it_origPKIMessage,8,&(lvalues[2289]),0}, -{"id-regCtrl","id-regCtrl",NID_id_regCtrl,8,&(lvalues[2297]),0}, -{"id-regInfo","id-regInfo",NID_id_regInfo,8,&(lvalues[2305]),0}, -{"id-regCtrl-regToken","id-regCtrl-regToken",NID_id_regCtrl_regToken, - 9,&(lvalues[2313]),0}, -{"id-regCtrl-authenticator","id-regCtrl-authenticator", - NID_id_regCtrl_authenticator,9,&(lvalues[2322]),0}, -{"id-regCtrl-pkiPublicationInfo","id-regCtrl-pkiPublicationInfo", - NID_id_regCtrl_pkiPublicationInfo,9,&(lvalues[2331]),0}, -{"id-regCtrl-pkiArchiveOptions","id-regCtrl-pkiArchiveOptions", - NID_id_regCtrl_pkiArchiveOptions,9,&(lvalues[2340]),0}, -{"id-regCtrl-oldCertID","id-regCtrl-oldCertID", - NID_id_regCtrl_oldCertID,9,&(lvalues[2349]),0}, -{"id-regCtrl-protocolEncrKey","id-regCtrl-protocolEncrKey", - NID_id_regCtrl_protocolEncrKey,9,&(lvalues[2358]),0}, -{"id-regInfo-utf8Pairs","id-regInfo-utf8Pairs", - NID_id_regInfo_utf8Pairs,9,&(lvalues[2367]),0}, -{"id-regInfo-certReq","id-regInfo-certReq",NID_id_regInfo_certReq,9, - &(lvalues[2376]),0}, -{"id-alg-des40","id-alg-des40",NID_id_alg_des40,8,&(lvalues[2385]),0}, -{"id-alg-noSignature","id-alg-noSignature",NID_id_alg_noSignature,8, - &(lvalues[2393]),0}, -{"id-alg-dh-sig-hmac-sha1","id-alg-dh-sig-hmac-sha1", - NID_id_alg_dh_sig_hmac_sha1,8,&(lvalues[2401]),0}, -{"id-alg-dh-pop","id-alg-dh-pop",NID_id_alg_dh_pop,8,&(lvalues[2409]),0}, -{"id-cmc-statusInfo","id-cmc-statusInfo",NID_id_cmc_statusInfo,8, - &(lvalues[2417]),0}, -{"id-cmc-identification","id-cmc-identification", - NID_id_cmc_identification,8,&(lvalues[2425]),0}, -{"id-cmc-identityProof","id-cmc-identityProof", - NID_id_cmc_identityProof,8,&(lvalues[2433]),0}, -{"id-cmc-dataReturn","id-cmc-dataReturn",NID_id_cmc_dataReturn,8, - &(lvalues[2441]),0}, -{"id-cmc-transactionId","id-cmc-transactionId", - NID_id_cmc_transactionId,8,&(lvalues[2449]),0}, -{"id-cmc-senderNonce","id-cmc-senderNonce",NID_id_cmc_senderNonce,8, - &(lvalues[2457]),0}, -{"id-cmc-recipientNonce","id-cmc-recipientNonce", - NID_id_cmc_recipientNonce,8,&(lvalues[2465]),0}, -{"id-cmc-addExtensions","id-cmc-addExtensions", - NID_id_cmc_addExtensions,8,&(lvalues[2473]),0}, -{"id-cmc-encryptedPOP","id-cmc-encryptedPOP",NID_id_cmc_encryptedPOP, - 8,&(lvalues[2481]),0}, -{"id-cmc-decryptedPOP","id-cmc-decryptedPOP",NID_id_cmc_decryptedPOP, - 8,&(lvalues[2489]),0}, -{"id-cmc-lraPOPWitness","id-cmc-lraPOPWitness", - NID_id_cmc_lraPOPWitness,8,&(lvalues[2497]),0}, -{"id-cmc-getCert","id-cmc-getCert",NID_id_cmc_getCert,8, - &(lvalues[2505]),0}, -{"id-cmc-getCRL","id-cmc-getCRL",NID_id_cmc_getCRL,8,&(lvalues[2513]),0}, -{"id-cmc-revokeRequest","id-cmc-revokeRequest", - NID_id_cmc_revokeRequest,8,&(lvalues[2521]),0}, -{"id-cmc-regInfo","id-cmc-regInfo",NID_id_cmc_regInfo,8, - &(lvalues[2529]),0}, -{"id-cmc-responseInfo","id-cmc-responseInfo",NID_id_cmc_responseInfo, - 8,&(lvalues[2537]),0}, -{"id-cmc-queryPending","id-cmc-queryPending",NID_id_cmc_queryPending, - 8,&(lvalues[2545]),0}, -{"id-cmc-popLinkRandom","id-cmc-popLinkRandom", - NID_id_cmc_popLinkRandom,8,&(lvalues[2553]),0}, -{"id-cmc-popLinkWitness","id-cmc-popLinkWitness", - NID_id_cmc_popLinkWitness,8,&(lvalues[2561]),0}, -{"id-cmc-confirmCertAcceptance","id-cmc-confirmCertAcceptance", - NID_id_cmc_confirmCertAcceptance,8,&(lvalues[2569]),0}, -{"id-on-personalData","id-on-personalData",NID_id_on_personalData,8, - &(lvalues[2577]),0}, -{"id-pda-dateOfBirth","id-pda-dateOfBirth",NID_id_pda_dateOfBirth,8, - &(lvalues[2585]),0}, -{"id-pda-placeOfBirth","id-pda-placeOfBirth",NID_id_pda_placeOfBirth, - 8,&(lvalues[2593]),0}, -{NULL,NULL,NID_undef,0,NULL,0}, -{"id-pda-gender","id-pda-gender",NID_id_pda_gender,8,&(lvalues[2601]),0}, -{"id-pda-countryOfCitizenship","id-pda-countryOfCitizenship", - NID_id_pda_countryOfCitizenship,8,&(lvalues[2609]),0}, -{"id-pda-countryOfResidence","id-pda-countryOfResidence", - NID_id_pda_countryOfResidence,8,&(lvalues[2617]),0}, -{"id-aca-authenticationInfo","id-aca-authenticationInfo", - NID_id_aca_authenticationInfo,8,&(lvalues[2625]),0}, -{"id-aca-accessIdentity","id-aca-accessIdentity", - NID_id_aca_accessIdentity,8,&(lvalues[2633]),0}, -{"id-aca-chargingIdentity","id-aca-chargingIdentity", - NID_id_aca_chargingIdentity,8,&(lvalues[2641]),0}, -{"id-aca-group","id-aca-group",NID_id_aca_group,8,&(lvalues[2649]),0}, -{"id-aca-role","id-aca-role",NID_id_aca_role,8,&(lvalues[2657]),0}, -{"id-qcs-pkixQCSyntax-v1","id-qcs-pkixQCSyntax-v1", - NID_id_qcs_pkixQCSyntax_v1,8,&(lvalues[2665]),0}, -{"id-cct-crs","id-cct-crs",NID_id_cct_crs,8,&(lvalues[2673]),0}, -{"id-cct-PKIData","id-cct-PKIData",NID_id_cct_PKIData,8, - &(lvalues[2681]),0}, -{"id-cct-PKIResponse","id-cct-PKIResponse",NID_id_cct_PKIResponse,8, - &(lvalues[2689]),0}, -{"ad_timestamping","AD Time Stamping",NID_ad_timeStamping,8, - &(lvalues[2697]),0}, -{"AD_DVCS","ad dvcs",NID_ad_dvcs,8,&(lvalues[2705]),0}, -{"basicOCSPResponse","Basic OCSP Response",NID_id_pkix_OCSP_basic,9, - &(lvalues[2713]),0}, -{"Nonce","OCSP Nonce",NID_id_pkix_OCSP_Nonce,9,&(lvalues[2722]),0}, -{"CrlID","OCSP CRL ID",NID_id_pkix_OCSP_CrlID,9,&(lvalues[2731]),0}, -{"acceptableResponses","Acceptable OCSP Responses", - NID_id_pkix_OCSP_acceptableResponses,9,&(lvalues[2740]),0}, -{"noCheck","OCSP No Check",NID_id_pkix_OCSP_noCheck,9,&(lvalues[2749]),0}, -{"archiveCutoff","OCSP Archive Cutoff",NID_id_pkix_OCSP_archiveCutoff, - 9,&(lvalues[2758]),0}, -{"serviceLocator","OCSP Service Locator", - NID_id_pkix_OCSP_serviceLocator,9,&(lvalues[2767]),0}, -{"extendedStatus","Extended OCSP Status", - NID_id_pkix_OCSP_extendedStatus,9,&(lvalues[2776]),0}, -{"valid","valid",NID_id_pkix_OCSP_valid,9,&(lvalues[2785]),0}, -{"path","path",NID_id_pkix_OCSP_path,9,&(lvalues[2794]),0}, -{"trustRoot","Trust Root",NID_id_pkix_OCSP_trustRoot,9, - &(lvalues[2803]),0}, -{"algorithm","algorithm",NID_algorithm,4,&(lvalues[2812]),0}, -{"rsaSignature","rsaSignature",NID_rsaSignature,5,&(lvalues[2816]),0}, -{"X500algorithms","directory services - algorithms", - NID_X500algorithms,2,&(lvalues[2821]),0}, -{"ORG","org",NID_org,1,&(lvalues[2823]),0}, -{"DOD","dod",NID_dod,2,&(lvalues[2824]),0}, -{"IANA","iana",NID_iana,3,&(lvalues[2826]),0}, -{"directory","Directory",NID_Directory,4,&(lvalues[2829]),0}, -{"mgmt","Management",NID_Management,4,&(lvalues[2833]),0}, -{"experimental","Experimental",NID_Experimental,4,&(lvalues[2837]),0}, -{"private","Private",NID_Private,4,&(lvalues[2841]),0}, -{"security","Security",NID_Security,4,&(lvalues[2845]),0}, -{"snmpv2","SNMPv2",NID_SNMPv2,4,&(lvalues[2849]),0}, -{"Mail","Mail",NID_Mail,4,&(lvalues[2853]),0}, -{"enterprises","Enterprises",NID_Enterprises,5,&(lvalues[2857]),0}, -{"dcobject","dcObject",NID_dcObject,9,&(lvalues[2862]),0}, -{"DC","domainComponent",NID_domainComponent,10,&(lvalues[2871]),0}, -{"domain","Domain",NID_Domain,10,&(lvalues[2881]),0}, -{"NULL","NULL",NID_joint_iso_ccitt,0,NULL,0}, -{"selected-attribute-types","Selected Attribute Types", - NID_selected_attribute_types,3,&(lvalues[2891]),0}, -{"clearance","clearance",NID_clearance,4,&(lvalues[2894]),0}, -{"RSA-MD4","md4WithRSAEncryption",NID_md4WithRSAEncryption,9, - &(lvalues[2898]),0}, -{"ac-proxying","ac-proxying",NID_ac_proxying,8,&(lvalues[2907]),0}, -{"subjectInfoAccess","Subject Information Access",NID_sinfo_access,8, - &(lvalues[2915]),0}, -{"id-aca-encAttrs","id-aca-encAttrs",NID_id_aca_encAttrs,8, - &(lvalues[2923]),0}, -{"role","role",NID_role,3,&(lvalues[2931]),0}, -{"policyConstraints","X509v3 Policy Constraints", - NID_policy_constraints,3,&(lvalues[2934]),0}, -{"targetInformation","X509v3 AC Targeting",NID_target_information,3, - &(lvalues[2937]),0}, -{"noRevAvail","X509v3 No Revocation Available",NID_no_rev_avail,3, - &(lvalues[2940]),0}, -{"NULL","NULL",NID_ccitt,0,NULL,0}, -{"ansi-X9-62","ANSI X9.62",NID_ansi_X9_62,5,&(lvalues[2943]),0}, -{"prime-field","prime-field",NID_X9_62_prime_field,7,&(lvalues[2948]),0}, -{"characteristic-two-field","characteristic-two-field", - NID_X9_62_characteristic_two_field,7,&(lvalues[2955]),0}, -{"id-ecPublicKey","id-ecPublicKey",NID_X9_62_id_ecPublicKey,7, - &(lvalues[2962]),0}, -{"prime192v1","prime192v1",NID_X9_62_prime192v1,8,&(lvalues[2969]),0}, -{"prime192v2","prime192v2",NID_X9_62_prime192v2,8,&(lvalues[2977]),0}, -{"prime192v3","prime192v3",NID_X9_62_prime192v3,8,&(lvalues[2985]),0}, -{"prime239v1","prime239v1",NID_X9_62_prime239v1,8,&(lvalues[2993]),0}, -{"prime239v2","prime239v2",NID_X9_62_prime239v2,8,&(lvalues[3001]),0}, -{"prime239v3","prime239v3",NID_X9_62_prime239v3,8,&(lvalues[3009]),0}, -{"prime256v1","prime256v1",NID_X9_62_prime256v1,8,&(lvalues[3017]),0}, -{"ecdsa-with-SHA1","ecdsa-with-SHA1",NID_ecdsa_with_SHA1,7, - &(lvalues[3025]),0}, -{"CSPName","Microsoft CSP Name",NID_ms_csp_name,9,&(lvalues[3032]),0}, -{"AES-128-ECB","aes-128-ecb",NID_aes_128_ecb,9,&(lvalues[3041]),0}, -{"AES-128-CBC","aes-128-cbc",NID_aes_128_cbc,9,&(lvalues[3050]),0}, -{"AES-128-OFB","aes-128-ofb",NID_aes_128_ofb128,9,&(lvalues[3059]),0}, -{"AES-128-CFB","aes-128-cfb",NID_aes_128_cfb128,9,&(lvalues[3068]),0}, -{"AES-192-ECB","aes-192-ecb",NID_aes_192_ecb,9,&(lvalues[3077]),0}, -{"AES-192-CBC","aes-192-cbc",NID_aes_192_cbc,9,&(lvalues[3086]),0}, -{"AES-192-OFB","aes-192-ofb",NID_aes_192_ofb128,9,&(lvalues[3095]),0}, -{"AES-192-CFB","aes-192-cfb",NID_aes_192_cfb128,9,&(lvalues[3104]),0}, -{"AES-256-ECB","aes-256-ecb",NID_aes_256_ecb,9,&(lvalues[3113]),0}, -{"AES-256-CBC","aes-256-cbc",NID_aes_256_cbc,9,&(lvalues[3122]),0}, -{"AES-256-OFB","aes-256-ofb",NID_aes_256_ofb128,9,&(lvalues[3131]),0}, -{"AES-256-CFB","aes-256-cfb",NID_aes_256_cfb128,9,&(lvalues[3140]),0}, -{"holdInstructionCode","Hold Instruction Code", - NID_hold_instruction_code,3,&(lvalues[3149]),0}, -{"holdInstructionNone","Hold Instruction None", - NID_hold_instruction_none,7,&(lvalues[3152]),0}, -{"holdInstructionCallIssuer","Hold Instruction Call Issuer", - NID_hold_instruction_call_issuer,7,&(lvalues[3159]),0}, -{"holdInstructionReject","Hold Instruction Reject", - NID_hold_instruction_reject,7,&(lvalues[3166]),0}, -{"data","data",NID_data,1,&(lvalues[3173]),0}, -{"pss","pss",NID_pss,3,&(lvalues[3174]),0}, -{"ucl","ucl",NID_ucl,7,&(lvalues[3177]),0}, -{"pilot","pilot",NID_pilot,8,&(lvalues[3184]),0}, -{"pilotAttributeType","pilotAttributeType",NID_pilotAttributeType,9, - &(lvalues[3192]),0}, -{"pilotAttributeSyntax","pilotAttributeSyntax", - NID_pilotAttributeSyntax,9,&(lvalues[3201]),0}, -{"pilotObjectClass","pilotObjectClass",NID_pilotObjectClass,9, - &(lvalues[3210]),0}, -{"pilotGroups","pilotGroups",NID_pilotGroups,9,&(lvalues[3219]),0}, -{"iA5StringSyntax","iA5StringSyntax",NID_iA5StringSyntax,10, - &(lvalues[3228]),0}, -{"caseIgnoreIA5StringSyntax","caseIgnoreIA5StringSyntax", - NID_caseIgnoreIA5StringSyntax,10,&(lvalues[3238]),0}, -{"pilotObject","pilotObject",NID_pilotObject,10,&(lvalues[3248]),0}, -{"pilotPerson","pilotPerson",NID_pilotPerson,10,&(lvalues[3258]),0}, -{"account","account",NID_account,10,&(lvalues[3268]),0}, -{"document","document",NID_document,10,&(lvalues[3278]),0}, -{"room","room",NID_room,10,&(lvalues[3288]),0}, -{"documentSeries","documentSeries",NID_documentSeries,10, - &(lvalues[3298]),0}, -{"rFC822localPart","rFC822localPart",NID_rFC822localPart,10, - &(lvalues[3308]),0}, -{"dNSDomain","dNSDomain",NID_dNSDomain,10,&(lvalues[3318]),0}, -{"domainRelatedObject","domainRelatedObject",NID_domainRelatedObject, - 10,&(lvalues[3328]),0}, -{"friendlyCountry","friendlyCountry",NID_friendlyCountry,10, - &(lvalues[3338]),0}, -{"simpleSecurityObject","simpleSecurityObject", - NID_simpleSecurityObject,10,&(lvalues[3348]),0}, -{"pilotOrganization","pilotOrganization",NID_pilotOrganization,10, - &(lvalues[3358]),0}, -{"pilotDSA","pilotDSA",NID_pilotDSA,10,&(lvalues[3368]),0}, -{"qualityLabelledData","qualityLabelledData",NID_qualityLabelledData, - 10,&(lvalues[3378]),0}, -{"UID","userId",NID_userId,10,&(lvalues[3388]),0}, -{"textEncodedORAddress","textEncodedORAddress", - NID_textEncodedORAddress,10,&(lvalues[3398]),0}, -{"mail","rfc822Mailbox",NID_rfc822Mailbox,10,&(lvalues[3408]),0}, -{"info","info",NID_info,10,&(lvalues[3418]),0}, -{"favouriteDrink","favouriteDrink",NID_favouriteDrink,10, - &(lvalues[3428]),0}, -{"roomNumber","roomNumber",NID_roomNumber,10,&(lvalues[3438]),0}, -{"photo","photo",NID_photo,10,&(lvalues[3448]),0}, -{"userClass","userClass",NID_userClass,10,&(lvalues[3458]),0}, -{"host","host",NID_host,10,&(lvalues[3468]),0}, -{"manager","manager",NID_manager,10,&(lvalues[3478]),0}, -{"documentIdentifier","documentIdentifier",NID_documentIdentifier,10, - &(lvalues[3488]),0}, -{"documentTitle","documentTitle",NID_documentTitle,10,&(lvalues[3498]),0}, -{"documentVersion","documentVersion",NID_documentVersion,10, - &(lvalues[3508]),0}, -{"documentAuthor","documentAuthor",NID_documentAuthor,10, - &(lvalues[3518]),0}, -{"documentLocation","documentLocation",NID_documentLocation,10, - &(lvalues[3528]),0}, -{"homeTelephoneNumber","homeTelephoneNumber",NID_homeTelephoneNumber, - 10,&(lvalues[3538]),0}, -{"secretary","secretary",NID_secretary,10,&(lvalues[3548]),0}, -{"otherMailbox","otherMailbox",NID_otherMailbox,10,&(lvalues[3558]),0}, -{"lastModifiedTime","lastModifiedTime",NID_lastModifiedTime,10, - &(lvalues[3568]),0}, -{"lastModifiedBy","lastModifiedBy",NID_lastModifiedBy,10, - &(lvalues[3578]),0}, -{"aRecord","aRecord",NID_aRecord,10,&(lvalues[3588]),0}, -{"pilotAttributeType27","pilotAttributeType27", - NID_pilotAttributeType27,10,&(lvalues[3598]),0}, -{"mXRecord","mXRecord",NID_mXRecord,10,&(lvalues[3608]),0}, -{"nSRecord","nSRecord",NID_nSRecord,10,&(lvalues[3618]),0}, -{"sOARecord","sOARecord",NID_sOARecord,10,&(lvalues[3628]),0}, -{"cNAMERecord","cNAMERecord",NID_cNAMERecord,10,&(lvalues[3638]),0}, -{"associatedDomain","associatedDomain",NID_associatedDomain,10, - &(lvalues[3648]),0}, -{"associatedName","associatedName",NID_associatedName,10, - &(lvalues[3658]),0}, -{"homePostalAddress","homePostalAddress",NID_homePostalAddress,10, - &(lvalues[3668]),0}, -{"personalTitle","personalTitle",NID_personalTitle,10,&(lvalues[3678]),0}, -{"mobileTelephoneNumber","mobileTelephoneNumber", - NID_mobileTelephoneNumber,10,&(lvalues[3688]),0}, -{"pagerTelephoneNumber","pagerTelephoneNumber", - NID_pagerTelephoneNumber,10,&(lvalues[3698]),0}, -{"friendlyCountryName","friendlyCountryName",NID_friendlyCountryName, - 10,&(lvalues[3708]),0}, -{"organizationalStatus","organizationalStatus", - NID_organizationalStatus,10,&(lvalues[3718]),0}, -{"janetMailbox","janetMailbox",NID_janetMailbox,10,&(lvalues[3728]),0}, -{"mailPreferenceOption","mailPreferenceOption", - NID_mailPreferenceOption,10,&(lvalues[3738]),0}, -{"buildingName","buildingName",NID_buildingName,10,&(lvalues[3748]),0}, -{"dSAQuality","dSAQuality",NID_dSAQuality,10,&(lvalues[3758]),0}, -{"singleLevelQuality","singleLevelQuality",NID_singleLevelQuality,10, - &(lvalues[3768]),0}, -{"subtreeMinimumQuality","subtreeMinimumQuality", - NID_subtreeMinimumQuality,10,&(lvalues[3778]),0}, -{"subtreeMaximumQuality","subtreeMaximumQuality", - NID_subtreeMaximumQuality,10,&(lvalues[3788]),0}, -{"personalSignature","personalSignature",NID_personalSignature,10, - &(lvalues[3798]),0}, -{"dITRedirect","dITRedirect",NID_dITRedirect,10,&(lvalues[3808]),0}, -{"audio","audio",NID_audio,10,&(lvalues[3818]),0}, -{"documentPublisher","documentPublisher",NID_documentPublisher,10, - &(lvalues[3828]),0}, -{"x500UniqueIdentifier","x500UniqueIdentifier", - NID_x500UniqueIdentifier,3,&(lvalues[3838]),0}, -{"mime-mhs","MIME MHS",NID_mime_mhs,5,&(lvalues[3841]),0}, -{"mime-mhs-headings","mime-mhs-headings",NID_mime_mhs_headings,6, - &(lvalues[3846]),0}, -{"mime-mhs-bodies","mime-mhs-bodies",NID_mime_mhs_bodies,6, - &(lvalues[3852]),0}, -{"id-hex-partial-message","id-hex-partial-message", - NID_id_hex_partial_message,7,&(lvalues[3858]),0}, -{"id-hex-multipart-message","id-hex-multipart-message", - NID_id_hex_multipart_message,7,&(lvalues[3865]),0}, -{"generationQualifier","generationQualifier",NID_generationQualifier, - 3,&(lvalues[3872]),0}, -{"pseudonym","pseudonym",NID_pseudonym,3,&(lvalues[3875]),0}, -{NULL,NULL,NID_undef,0,NULL,0}, -{"id-set","Secure Electronic Transactions",NID_id_set,2, - &(lvalues[3878]),0}, -{"set-ctype","content types",NID_set_ctype,3,&(lvalues[3880]),0}, -{"set-msgExt","message extensions",NID_set_msgExt,3,&(lvalues[3883]),0}, -{"set-attr","set-attr",NID_set_attr,3,&(lvalues[3886]),0}, -{"set-policy","set-policy",NID_set_policy,3,&(lvalues[3889]),0}, -{"set-certExt","certificate extensions",NID_set_certExt,3, - &(lvalues[3892]),0}, -{"set-brand","set-brand",NID_set_brand,3,&(lvalues[3895]),0}, -{"setct-PANData","setct-PANData",NID_setct_PANData,4,&(lvalues[3898]),0}, -{"setct-PANToken","setct-PANToken",NID_setct_PANToken,4, - &(lvalues[3902]),0}, -{"setct-PANOnly","setct-PANOnly",NID_setct_PANOnly,4,&(lvalues[3906]),0}, -{"setct-OIData","setct-OIData",NID_setct_OIData,4,&(lvalues[3910]),0}, -{"setct-PI","setct-PI",NID_setct_PI,4,&(lvalues[3914]),0}, -{"setct-PIData","setct-PIData",NID_setct_PIData,4,&(lvalues[3918]),0}, -{"setct-PIDataUnsigned","setct-PIDataUnsigned", - NID_setct_PIDataUnsigned,4,&(lvalues[3922]),0}, -{"setct-HODInput","setct-HODInput",NID_setct_HODInput,4, - &(lvalues[3926]),0}, -{"setct-AuthResBaggage","setct-AuthResBaggage", - NID_setct_AuthResBaggage,4,&(lvalues[3930]),0}, -{"setct-AuthRevReqBaggage","setct-AuthRevReqBaggage", - NID_setct_AuthRevReqBaggage,4,&(lvalues[3934]),0}, -{"setct-AuthRevResBaggage","setct-AuthRevResBaggage", - NID_setct_AuthRevResBaggage,4,&(lvalues[3938]),0}, -{"setct-CapTokenSeq","setct-CapTokenSeq",NID_setct_CapTokenSeq,4, - &(lvalues[3942]),0}, -{"setct-PInitResData","setct-PInitResData",NID_setct_PInitResData,4, - &(lvalues[3946]),0}, -{"setct-PI-TBS","setct-PI-TBS",NID_setct_PI_TBS,4,&(lvalues[3950]),0}, -{"setct-PResData","setct-PResData",NID_setct_PResData,4, - &(lvalues[3954]),0}, -{"setct-AuthReqTBS","setct-AuthReqTBS",NID_setct_AuthReqTBS,4, - &(lvalues[3958]),0}, -{"setct-AuthResTBS","setct-AuthResTBS",NID_setct_AuthResTBS,4, - &(lvalues[3962]),0}, -{"setct-AuthResTBSX","setct-AuthResTBSX",NID_setct_AuthResTBSX,4, - &(lvalues[3966]),0}, -{"setct-AuthTokenTBS","setct-AuthTokenTBS",NID_setct_AuthTokenTBS,4, - &(lvalues[3970]),0}, -{"setct-CapTokenData","setct-CapTokenData",NID_setct_CapTokenData,4, - &(lvalues[3974]),0}, -{"setct-CapTokenTBS","setct-CapTokenTBS",NID_setct_CapTokenTBS,4, - &(lvalues[3978]),0}, -{"setct-AcqCardCodeMsg","setct-AcqCardCodeMsg", - NID_setct_AcqCardCodeMsg,4,&(lvalues[3982]),0}, -{"setct-AuthRevReqTBS","setct-AuthRevReqTBS",NID_setct_AuthRevReqTBS, - 4,&(lvalues[3986]),0}, -{"setct-AuthRevResData","setct-AuthRevResData", - NID_setct_AuthRevResData,4,&(lvalues[3990]),0}, -{"setct-AuthRevResTBS","setct-AuthRevResTBS",NID_setct_AuthRevResTBS, - 4,&(lvalues[3994]),0}, -{"setct-CapReqTBS","setct-CapReqTBS",NID_setct_CapReqTBS,4, - &(lvalues[3998]),0}, -{"setct-CapReqTBSX","setct-CapReqTBSX",NID_setct_CapReqTBSX,4, - &(lvalues[4002]),0}, -{"setct-CapResData","setct-CapResData",NID_setct_CapResData,4, - &(lvalues[4006]),0}, -{"setct-CapRevReqTBS","setct-CapRevReqTBS",NID_setct_CapRevReqTBS,4, - &(lvalues[4010]),0}, -{"setct-CapRevReqTBSX","setct-CapRevReqTBSX",NID_setct_CapRevReqTBSX, - 4,&(lvalues[4014]),0}, -{"setct-CapRevResData","setct-CapRevResData",NID_setct_CapRevResData, - 4,&(lvalues[4018]),0}, -{"setct-CredReqTBS","setct-CredReqTBS",NID_setct_CredReqTBS,4, - &(lvalues[4022]),0}, -{"setct-CredReqTBSX","setct-CredReqTBSX",NID_setct_CredReqTBSX,4, - &(lvalues[4026]),0}, -{"setct-CredResData","setct-CredResData",NID_setct_CredResData,4, - &(lvalues[4030]),0}, -{"setct-CredRevReqTBS","setct-CredRevReqTBS",NID_setct_CredRevReqTBS, - 4,&(lvalues[4034]),0}, -{"setct-CredRevReqTBSX","setct-CredRevReqTBSX", - NID_setct_CredRevReqTBSX,4,&(lvalues[4038]),0}, -{"setct-CredRevResData","setct-CredRevResData", - NID_setct_CredRevResData,4,&(lvalues[4042]),0}, -{"setct-PCertReqData","setct-PCertReqData",NID_setct_PCertReqData,4, - &(lvalues[4046]),0}, -{"setct-PCertResTBS","setct-PCertResTBS",NID_setct_PCertResTBS,4, - &(lvalues[4050]),0}, -{"setct-BatchAdminReqData","setct-BatchAdminReqData", - NID_setct_BatchAdminReqData,4,&(lvalues[4054]),0}, -{"setct-BatchAdminResData","setct-BatchAdminResData", - NID_setct_BatchAdminResData,4,&(lvalues[4058]),0}, -{"setct-CardCInitResTBS","setct-CardCInitResTBS", - NID_setct_CardCInitResTBS,4,&(lvalues[4062]),0}, -{"setct-MeAqCInitResTBS","setct-MeAqCInitResTBS", - NID_setct_MeAqCInitResTBS,4,&(lvalues[4066]),0}, -{"setct-RegFormResTBS","setct-RegFormResTBS",NID_setct_RegFormResTBS, - 4,&(lvalues[4070]),0}, -{"setct-CertReqData","setct-CertReqData",NID_setct_CertReqData,4, - &(lvalues[4074]),0}, -{"setct-CertReqTBS","setct-CertReqTBS",NID_setct_CertReqTBS,4, - &(lvalues[4078]),0}, -{"setct-CertResData","setct-CertResData",NID_setct_CertResData,4, - &(lvalues[4082]),0}, -{"setct-CertInqReqTBS","setct-CertInqReqTBS",NID_setct_CertInqReqTBS, - 4,&(lvalues[4086]),0}, -{"setct-ErrorTBS","setct-ErrorTBS",NID_setct_ErrorTBS,4, - &(lvalues[4090]),0}, -{"setct-PIDualSignedTBE","setct-PIDualSignedTBE", - NID_setct_PIDualSignedTBE,4,&(lvalues[4094]),0}, -{"setct-PIUnsignedTBE","setct-PIUnsignedTBE",NID_setct_PIUnsignedTBE, - 4,&(lvalues[4098]),0}, -{"setct-AuthReqTBE","setct-AuthReqTBE",NID_setct_AuthReqTBE,4, - &(lvalues[4102]),0}, -{"setct-AuthResTBE","setct-AuthResTBE",NID_setct_AuthResTBE,4, - &(lvalues[4106]),0}, -{"setct-AuthResTBEX","setct-AuthResTBEX",NID_setct_AuthResTBEX,4, - &(lvalues[4110]),0}, -{"setct-AuthTokenTBE","setct-AuthTokenTBE",NID_setct_AuthTokenTBE,4, - &(lvalues[4114]),0}, -{"setct-CapTokenTBE","setct-CapTokenTBE",NID_setct_CapTokenTBE,4, - &(lvalues[4118]),0}, -{"setct-CapTokenTBEX","setct-CapTokenTBEX",NID_setct_CapTokenTBEX,4, - &(lvalues[4122]),0}, -{"setct-AcqCardCodeMsgTBE","setct-AcqCardCodeMsgTBE", - NID_setct_AcqCardCodeMsgTBE,4,&(lvalues[4126]),0}, -{"setct-AuthRevReqTBE","setct-AuthRevReqTBE",NID_setct_AuthRevReqTBE, - 4,&(lvalues[4130]),0}, -{"setct-AuthRevResTBE","setct-AuthRevResTBE",NID_setct_AuthRevResTBE, - 4,&(lvalues[4134]),0}, -{"setct-AuthRevResTBEB","setct-AuthRevResTBEB", - NID_setct_AuthRevResTBEB,4,&(lvalues[4138]),0}, -{"setct-CapReqTBE","setct-CapReqTBE",NID_setct_CapReqTBE,4, - &(lvalues[4142]),0}, -{"setct-CapReqTBEX","setct-CapReqTBEX",NID_setct_CapReqTBEX,4, - &(lvalues[4146]),0}, -{"setct-CapResTBE","setct-CapResTBE",NID_setct_CapResTBE,4, - &(lvalues[4150]),0}, -{"setct-CapRevReqTBE","setct-CapRevReqTBE",NID_setct_CapRevReqTBE,4, - &(lvalues[4154]),0}, -{"setct-CapRevReqTBEX","setct-CapRevReqTBEX",NID_setct_CapRevReqTBEX, - 4,&(lvalues[4158]),0}, -{"setct-CapRevResTBE","setct-CapRevResTBE",NID_setct_CapRevResTBE,4, - &(lvalues[4162]),0}, -{"setct-CredReqTBE","setct-CredReqTBE",NID_setct_CredReqTBE,4, - &(lvalues[4166]),0}, -{"setct-CredReqTBEX","setct-CredReqTBEX",NID_setct_CredReqTBEX,4, - &(lvalues[4170]),0}, -{"setct-CredResTBE","setct-CredResTBE",NID_setct_CredResTBE,4, - &(lvalues[4174]),0}, -{"setct-CredRevReqTBE","setct-CredRevReqTBE",NID_setct_CredRevReqTBE, - 4,&(lvalues[4178]),0}, -{"setct-CredRevReqTBEX","setct-CredRevReqTBEX", - NID_setct_CredRevReqTBEX,4,&(lvalues[4182]),0}, -{"setct-CredRevResTBE","setct-CredRevResTBE",NID_setct_CredRevResTBE, - 4,&(lvalues[4186]),0}, -{"setct-BatchAdminReqTBE","setct-BatchAdminReqTBE", - NID_setct_BatchAdminReqTBE,4,&(lvalues[4190]),0}, -{"setct-BatchAdminResTBE","setct-BatchAdminResTBE", - NID_setct_BatchAdminResTBE,4,&(lvalues[4194]),0}, -{"setct-RegFormReqTBE","setct-RegFormReqTBE",NID_setct_RegFormReqTBE, - 4,&(lvalues[4198]),0}, -{"setct-CertReqTBE","setct-CertReqTBE",NID_setct_CertReqTBE,4, - &(lvalues[4202]),0}, -{"setct-CertReqTBEX","setct-CertReqTBEX",NID_setct_CertReqTBEX,4, - &(lvalues[4206]),0}, -{"setct-CertResTBE","setct-CertResTBE",NID_setct_CertResTBE,4, - &(lvalues[4210]),0}, -{"setct-CRLNotificationTBS","setct-CRLNotificationTBS", - NID_setct_CRLNotificationTBS,4,&(lvalues[4214]),0}, -{"setct-CRLNotificationResTBS","setct-CRLNotificationResTBS", - NID_setct_CRLNotificationResTBS,4,&(lvalues[4218]),0}, -{"setct-BCIDistributionTBS","setct-BCIDistributionTBS", - NID_setct_BCIDistributionTBS,4,&(lvalues[4222]),0}, -{"setext-genCrypt","generic cryptogram",NID_setext_genCrypt,4, - &(lvalues[4226]),0}, -{"setext-miAuth","merchant initiated auth",NID_setext_miAuth,4, - &(lvalues[4230]),0}, -{"setext-pinSecure","setext-pinSecure",NID_setext_pinSecure,4, - &(lvalues[4234]),0}, -{"setext-pinAny","setext-pinAny",NID_setext_pinAny,4,&(lvalues[4238]),0}, -{"setext-track2","setext-track2",NID_setext_track2,4,&(lvalues[4242]),0}, -{"setext-cv","additional verification",NID_setext_cv,4, - &(lvalues[4246]),0}, -{"set-policy-root","set-policy-root",NID_set_policy_root,4, - &(lvalues[4250]),0}, -{"setCext-hashedRoot","setCext-hashedRoot",NID_setCext_hashedRoot,4, - &(lvalues[4254]),0}, -{"setCext-certType","setCext-certType",NID_setCext_certType,4, - &(lvalues[4258]),0}, -{"setCext-merchData","setCext-merchData",NID_setCext_merchData,4, - &(lvalues[4262]),0}, -{"setCext-cCertRequired","setCext-cCertRequired", - NID_setCext_cCertRequired,4,&(lvalues[4266]),0}, -{"setCext-tunneling","setCext-tunneling",NID_setCext_tunneling,4, - &(lvalues[4270]),0}, -{"setCext-setExt","setCext-setExt",NID_setCext_setExt,4, - &(lvalues[4274]),0}, -{"setCext-setQualf","setCext-setQualf",NID_setCext_setQualf,4, - &(lvalues[4278]),0}, -{"setCext-PGWYcapabilities","setCext-PGWYcapabilities", - NID_setCext_PGWYcapabilities,4,&(lvalues[4282]),0}, -{"setCext-TokenIdentifier","setCext-TokenIdentifier", - NID_setCext_TokenIdentifier,4,&(lvalues[4286]),0}, -{"setCext-Track2Data","setCext-Track2Data",NID_setCext_Track2Data,4, - &(lvalues[4290]),0}, -{"setCext-TokenType","setCext-TokenType",NID_setCext_TokenType,4, - &(lvalues[4294]),0}, -{"setCext-IssuerCapabilities","setCext-IssuerCapabilities", - NID_setCext_IssuerCapabilities,4,&(lvalues[4298]),0}, -{"setAttr-Cert","setAttr-Cert",NID_setAttr_Cert,4,&(lvalues[4302]),0}, -{"setAttr-PGWYcap","payment gateway capabilities",NID_setAttr_PGWYcap, - 4,&(lvalues[4306]),0}, -{"setAttr-TokenType","setAttr-TokenType",NID_setAttr_TokenType,4, - &(lvalues[4310]),0}, -{"setAttr-IssCap","issuer capabilities",NID_setAttr_IssCap,4, - &(lvalues[4314]),0}, -{"set-rootKeyThumb","set-rootKeyThumb",NID_set_rootKeyThumb,5, - &(lvalues[4318]),0}, -{"set-addPolicy","set-addPolicy",NID_set_addPolicy,5,&(lvalues[4323]),0}, -{"setAttr-Token-EMV","setAttr-Token-EMV",NID_setAttr_Token_EMV,5, - &(lvalues[4328]),0}, -{"setAttr-Token-B0Prime","setAttr-Token-B0Prime", - NID_setAttr_Token_B0Prime,5,&(lvalues[4333]),0}, -{"setAttr-IssCap-CVM","setAttr-IssCap-CVM",NID_setAttr_IssCap_CVM,5, - &(lvalues[4338]),0}, -{"setAttr-IssCap-T2","setAttr-IssCap-T2",NID_setAttr_IssCap_T2,5, - &(lvalues[4343]),0}, -{"setAttr-IssCap-Sig","setAttr-IssCap-Sig",NID_setAttr_IssCap_Sig,5, - &(lvalues[4348]),0}, -{"setAttr-GenCryptgrm","generate cryptogram",NID_setAttr_GenCryptgrm, - 6,&(lvalues[4353]),0}, -{"setAttr-T2Enc","encrypted track 2",NID_setAttr_T2Enc,6, - &(lvalues[4359]),0}, -{"setAttr-T2cleartxt","cleartext track 2",NID_setAttr_T2cleartxt,6, - &(lvalues[4365]),0}, -{"setAttr-TokICCsig","ICC or token signature",NID_setAttr_TokICCsig,6, - &(lvalues[4371]),0}, -{"setAttr-SecDevSig","secure device signature",NID_setAttr_SecDevSig, - 6,&(lvalues[4377]),0}, -{"set-brand-IATA-ATA","set-brand-IATA-ATA",NID_set_brand_IATA_ATA,4, - &(lvalues[4383]),0}, -{"set-brand-Diners","set-brand-Diners",NID_set_brand_Diners,4, - &(lvalues[4387]),0}, -{"set-brand-AmericanExpress","set-brand-AmericanExpress", - NID_set_brand_AmericanExpress,4,&(lvalues[4391]),0}, -{"set-brand-JCB","set-brand-JCB",NID_set_brand_JCB,4,&(lvalues[4395]),0}, -{"set-brand-Visa","set-brand-Visa",NID_set_brand_Visa,4, - &(lvalues[4399]),0}, -{"set-brand-MasterCard","set-brand-MasterCard", - NID_set_brand_MasterCard,4,&(lvalues[4403]),0}, -{"set-brand-Novus","set-brand-Novus",NID_set_brand_Novus,5, - &(lvalues[4407]),0}, -{"DES-CDMF","des-cdmf",NID_des_cdmf,8,&(lvalues[4412]),0}, -{"rsaOAEPEncryptionSET","rsaOAEPEncryptionSET", - NID_rsaOAEPEncryptionSET,9,&(lvalues[4420]),0}, -{"ITU-T","itu-t",NID_itu_t,0,NULL,0}, -{"JOINT-ISO-ITU-T","joint-iso-itu-t",NID_joint_iso_itu_t,0,NULL,0}, -{"international-organizations","International Organizations", - NID_international_organizations,1,&(lvalues[4429]),0}, -{"msSmartcardLogin","Microsoft Smartcardlogin",NID_ms_smartcard_login, - 10,&(lvalues[4430]),0}, -{"msUPN","Microsoft Universal Principal Name",NID_ms_upn,10, - &(lvalues[4440]),0}, -{"AES-128-CFB1","aes-128-cfb1",NID_aes_128_cfb1,0,NULL,0}, -{"AES-192-CFB1","aes-192-cfb1",NID_aes_192_cfb1,0,NULL,0}, -{"AES-256-CFB1","aes-256-cfb1",NID_aes_256_cfb1,0,NULL,0}, -{"AES-128-CFB8","aes-128-cfb8",NID_aes_128_cfb8,0,NULL,0}, -{"AES-192-CFB8","aes-192-cfb8",NID_aes_192_cfb8,0,NULL,0}, -{"AES-256-CFB8","aes-256-cfb8",NID_aes_256_cfb8,0,NULL,0}, -{"DES-CFB1","des-cfb1",NID_des_cfb1,0,NULL,0}, -{"DES-CFB8","des-cfb8",NID_des_cfb8,0,NULL,0}, -{"DES-EDE3-CFB1","des-ede3-cfb1",NID_des_ede3_cfb1,0,NULL,0}, -{"DES-EDE3-CFB8","des-ede3-cfb8",NID_des_ede3_cfb8,0,NULL,0}, -{"street","streetAddress",NID_streetAddress,3,&(lvalues[4450]),0}, -{"postalCode","postalCode",NID_postalCode,3,&(lvalues[4453]),0}, -{"id-ppl","id-ppl",NID_id_ppl,7,&(lvalues[4456]),0}, -{"proxyCertInfo","Proxy Certificate Information",NID_proxyCertInfo,8, - &(lvalues[4463]),0}, -{"id-ppl-anyLanguage","Any language",NID_id_ppl_anyLanguage,8, - &(lvalues[4471]),0}, -{"id-ppl-inheritAll","Inherit all",NID_id_ppl_inheritAll,8, - &(lvalues[4479]),0}, -{"nameConstraints","X509v3 Name Constraints",NID_name_constraints,3, - &(lvalues[4487]),0}, -{"id-ppl-independent","Independent",NID_Independent,8,&(lvalues[4490]),0}, -{"RSA-SHA256","sha256WithRSAEncryption",NID_sha256WithRSAEncryption,9, - &(lvalues[4498]),0}, -{"RSA-SHA384","sha384WithRSAEncryption",NID_sha384WithRSAEncryption,9, - &(lvalues[4507]),0}, -{"RSA-SHA512","sha512WithRSAEncryption",NID_sha512WithRSAEncryption,9, - &(lvalues[4516]),0}, -{"RSA-SHA224","sha224WithRSAEncryption",NID_sha224WithRSAEncryption,9, - &(lvalues[4525]),0}, -{"SHA256","sha256",NID_sha256,9,&(lvalues[4534]),0}, -{"SHA384","sha384",NID_sha384,9,&(lvalues[4543]),0}, -{"SHA512","sha512",NID_sha512,9,&(lvalues[4552]),0}, -{"SHA224","sha224",NID_sha224,9,&(lvalues[4561]),0}, -{"identified-organization","identified-organization", - NID_identified_organization,1,&(lvalues[4570]),0}, -{"certicom-arc","certicom-arc",NID_certicom_arc,3,&(lvalues[4571]),0}, -{"wap","wap",NID_wap,2,&(lvalues[4574]),0}, -{"wap-wsg","wap-wsg",NID_wap_wsg,3,&(lvalues[4576]),0}, -{"id-characteristic-two-basis","id-characteristic-two-basis", - NID_X9_62_id_characteristic_two_basis,8,&(lvalues[4579]),0}, -{"onBasis","onBasis",NID_X9_62_onBasis,9,&(lvalues[4587]),0}, -{"tpBasis","tpBasis",NID_X9_62_tpBasis,9,&(lvalues[4596]),0}, -{"ppBasis","ppBasis",NID_X9_62_ppBasis,9,&(lvalues[4605]),0}, -{"c2pnb163v1","c2pnb163v1",NID_X9_62_c2pnb163v1,8,&(lvalues[4614]),0}, -{"c2pnb163v2","c2pnb163v2",NID_X9_62_c2pnb163v2,8,&(lvalues[4622]),0}, -{"c2pnb163v3","c2pnb163v3",NID_X9_62_c2pnb163v3,8,&(lvalues[4630]),0}, -{"c2pnb176v1","c2pnb176v1",NID_X9_62_c2pnb176v1,8,&(lvalues[4638]),0}, -{"c2tnb191v1","c2tnb191v1",NID_X9_62_c2tnb191v1,8,&(lvalues[4646]),0}, -{"c2tnb191v2","c2tnb191v2",NID_X9_62_c2tnb191v2,8,&(lvalues[4654]),0}, -{"c2tnb191v3","c2tnb191v3",NID_X9_62_c2tnb191v3,8,&(lvalues[4662]),0}, -{"c2onb191v4","c2onb191v4",NID_X9_62_c2onb191v4,8,&(lvalues[4670]),0}, -{"c2onb191v5","c2onb191v5",NID_X9_62_c2onb191v5,8,&(lvalues[4678]),0}, -{"c2pnb208w1","c2pnb208w1",NID_X9_62_c2pnb208w1,8,&(lvalues[4686]),0}, -{"c2tnb239v1","c2tnb239v1",NID_X9_62_c2tnb239v1,8,&(lvalues[4694]),0}, -{"c2tnb239v2","c2tnb239v2",NID_X9_62_c2tnb239v2,8,&(lvalues[4702]),0}, -{"c2tnb239v3","c2tnb239v3",NID_X9_62_c2tnb239v3,8,&(lvalues[4710]),0}, -{"c2onb239v4","c2onb239v4",NID_X9_62_c2onb239v4,8,&(lvalues[4718]),0}, -{"c2onb239v5","c2onb239v5",NID_X9_62_c2onb239v5,8,&(lvalues[4726]),0}, -{"c2pnb272w1","c2pnb272w1",NID_X9_62_c2pnb272w1,8,&(lvalues[4734]),0}, -{"c2pnb304w1","c2pnb304w1",NID_X9_62_c2pnb304w1,8,&(lvalues[4742]),0}, -{"c2tnb359v1","c2tnb359v1",NID_X9_62_c2tnb359v1,8,&(lvalues[4750]),0}, -{"c2pnb368w1","c2pnb368w1",NID_X9_62_c2pnb368w1,8,&(lvalues[4758]),0}, -{"c2tnb431r1","c2tnb431r1",NID_X9_62_c2tnb431r1,8,&(lvalues[4766]),0}, -{"secp112r1","secp112r1",NID_secp112r1,5,&(lvalues[4774]),0}, -{"secp112r2","secp112r2",NID_secp112r2,5,&(lvalues[4779]),0}, -{"secp128r1","secp128r1",NID_secp128r1,5,&(lvalues[4784]),0}, -{"secp128r2","secp128r2",NID_secp128r2,5,&(lvalues[4789]),0}, -{"secp160k1","secp160k1",NID_secp160k1,5,&(lvalues[4794]),0}, -{"secp160r1","secp160r1",NID_secp160r1,5,&(lvalues[4799]),0}, -{"secp160r2","secp160r2",NID_secp160r2,5,&(lvalues[4804]),0}, -{"secp192k1","secp192k1",NID_secp192k1,5,&(lvalues[4809]),0}, -{"secp224k1","secp224k1",NID_secp224k1,5,&(lvalues[4814]),0}, -{"secp224r1","secp224r1",NID_secp224r1,5,&(lvalues[4819]),0}, -{"secp256k1","secp256k1",NID_secp256k1,5,&(lvalues[4824]),0}, -{"secp384r1","secp384r1",NID_secp384r1,5,&(lvalues[4829]),0}, -{"secp521r1","secp521r1",NID_secp521r1,5,&(lvalues[4834]),0}, -{"sect113r1","sect113r1",NID_sect113r1,5,&(lvalues[4839]),0}, -{"sect113r2","sect113r2",NID_sect113r2,5,&(lvalues[4844]),0}, -{"sect131r1","sect131r1",NID_sect131r1,5,&(lvalues[4849]),0}, -{"sect131r2","sect131r2",NID_sect131r2,5,&(lvalues[4854]),0}, -{"sect163k1","sect163k1",NID_sect163k1,5,&(lvalues[4859]),0}, -{"sect163r1","sect163r1",NID_sect163r1,5,&(lvalues[4864]),0}, -{"sect163r2","sect163r2",NID_sect163r2,5,&(lvalues[4869]),0}, -{"sect193r1","sect193r1",NID_sect193r1,5,&(lvalues[4874]),0}, -{"sect193r2","sect193r2",NID_sect193r2,5,&(lvalues[4879]),0}, -{"sect233k1","sect233k1",NID_sect233k1,5,&(lvalues[4884]),0}, -{"sect233r1","sect233r1",NID_sect233r1,5,&(lvalues[4889]),0}, -{"sect239k1","sect239k1",NID_sect239k1,5,&(lvalues[4894]),0}, -{"sect283k1","sect283k1",NID_sect283k1,5,&(lvalues[4899]),0}, -{"sect283r1","sect283r1",NID_sect283r1,5,&(lvalues[4904]),0}, -{"sect409k1","sect409k1",NID_sect409k1,5,&(lvalues[4909]),0}, -{"sect409r1","sect409r1",NID_sect409r1,5,&(lvalues[4914]),0}, -{"sect571k1","sect571k1",NID_sect571k1,5,&(lvalues[4919]),0}, -{"sect571r1","sect571r1",NID_sect571r1,5,&(lvalues[4924]),0}, -{"wap-wsg-idm-ecid-wtls1","wap-wsg-idm-ecid-wtls1", - NID_wap_wsg_idm_ecid_wtls1,5,&(lvalues[4929]),0}, -{"wap-wsg-idm-ecid-wtls3","wap-wsg-idm-ecid-wtls3", - NID_wap_wsg_idm_ecid_wtls3,5,&(lvalues[4934]),0}, -{"wap-wsg-idm-ecid-wtls4","wap-wsg-idm-ecid-wtls4", - NID_wap_wsg_idm_ecid_wtls4,5,&(lvalues[4939]),0}, -{"wap-wsg-idm-ecid-wtls5","wap-wsg-idm-ecid-wtls5", - NID_wap_wsg_idm_ecid_wtls5,5,&(lvalues[4944]),0}, -{"wap-wsg-idm-ecid-wtls6","wap-wsg-idm-ecid-wtls6", - NID_wap_wsg_idm_ecid_wtls6,5,&(lvalues[4949]),0}, -{"wap-wsg-idm-ecid-wtls7","wap-wsg-idm-ecid-wtls7", - NID_wap_wsg_idm_ecid_wtls7,5,&(lvalues[4954]),0}, -{"wap-wsg-idm-ecid-wtls8","wap-wsg-idm-ecid-wtls8", - NID_wap_wsg_idm_ecid_wtls8,5,&(lvalues[4959]),0}, -{"wap-wsg-idm-ecid-wtls9","wap-wsg-idm-ecid-wtls9", - NID_wap_wsg_idm_ecid_wtls9,5,&(lvalues[4964]),0}, -{"wap-wsg-idm-ecid-wtls10","wap-wsg-idm-ecid-wtls10", - NID_wap_wsg_idm_ecid_wtls10,5,&(lvalues[4969]),0}, -{"wap-wsg-idm-ecid-wtls11","wap-wsg-idm-ecid-wtls11", - NID_wap_wsg_idm_ecid_wtls11,5,&(lvalues[4974]),0}, -{"wap-wsg-idm-ecid-wtls12","wap-wsg-idm-ecid-wtls12", - NID_wap_wsg_idm_ecid_wtls12,5,&(lvalues[4979]),0}, -{"anyPolicy","X509v3 Any Policy",NID_any_policy,4,&(lvalues[4984]),0}, -{"policyMappings","X509v3 Policy Mappings",NID_policy_mappings,3, - &(lvalues[4988]),0}, -{"inhibitAnyPolicy","X509v3 Inhibit Any Policy", - NID_inhibit_any_policy,3,&(lvalues[4991]),0}, -{"Oakley-EC2N-3","ipsec3",NID_ipsec3,0,NULL,0}, -{"Oakley-EC2N-4","ipsec4",NID_ipsec4,0,NULL,0}, -{"CAMELLIA-128-CBC","camellia-128-cbc",NID_camellia_128_cbc,11, - &(lvalues[4994]),0}, -{"CAMELLIA-192-CBC","camellia-192-cbc",NID_camellia_192_cbc,11, - &(lvalues[5005]),0}, -{"CAMELLIA-256-CBC","camellia-256-cbc",NID_camellia_256_cbc,11, - &(lvalues[5016]),0}, -{"CAMELLIA-128-ECB","camellia-128-ecb",NID_camellia_128_ecb,8, - &(lvalues[5027]),0}, -{"CAMELLIA-192-ECB","camellia-192-ecb",NID_camellia_192_ecb,8, - &(lvalues[5035]),0}, -{"CAMELLIA-256-ECB","camellia-256-ecb",NID_camellia_256_ecb,8, - &(lvalues[5043]),0}, -{"CAMELLIA-128-CFB","camellia-128-cfb",NID_camellia_128_cfb128,8, - &(lvalues[5051]),0}, -{"CAMELLIA-192-CFB","camellia-192-cfb",NID_camellia_192_cfb128,8, - &(lvalues[5059]),0}, -{"CAMELLIA-256-CFB","camellia-256-cfb",NID_camellia_256_cfb128,8, - &(lvalues[5067]),0}, -{"CAMELLIA-128-CFB1","camellia-128-cfb1",NID_camellia_128_cfb1,0,NULL,0}, -{"CAMELLIA-192-CFB1","camellia-192-cfb1",NID_camellia_192_cfb1,0,NULL,0}, -{"CAMELLIA-256-CFB1","camellia-256-cfb1",NID_camellia_256_cfb1,0,NULL,0}, -{"CAMELLIA-128-CFB8","camellia-128-cfb8",NID_camellia_128_cfb8,0,NULL,0}, -{"CAMELLIA-192-CFB8","camellia-192-cfb8",NID_camellia_192_cfb8,0,NULL,0}, -{"CAMELLIA-256-CFB8","camellia-256-cfb8",NID_camellia_256_cfb8,0,NULL,0}, -{"CAMELLIA-128-OFB","camellia-128-ofb",NID_camellia_128_ofb128,8, - &(lvalues[5075]),0}, -{"CAMELLIA-192-OFB","camellia-192-ofb",NID_camellia_192_ofb128,8, - &(lvalues[5083]),0}, -{"CAMELLIA-256-OFB","camellia-256-ofb",NID_camellia_256_ofb128,8, - &(lvalues[5091]),0}, -{"subjectDirectoryAttributes","X509v3 Subject Directory Attributes", - NID_subject_directory_attributes,3,&(lvalues[5099]),0}, -{"issuingDistributionPoint","X509v3 Issuing Distribution Point", - NID_issuing_distribution_point,3,&(lvalues[5102]),0}, -{"certificateIssuer","X509v3 Certificate Issuer", - NID_certificate_issuer,3,&(lvalues[5105]),0}, -{NULL,NULL,NID_undef,0,NULL,0}, -{"KISA","kisa",NID_kisa,6,&(lvalues[5108]),0}, -{NULL,NULL,NID_undef,0,NULL,0}, -{NULL,NULL,NID_undef,0,NULL,0}, -{"SEED-ECB","seed-ecb",NID_seed_ecb,8,&(lvalues[5114]),0}, -{"SEED-CBC","seed-cbc",NID_seed_cbc,8,&(lvalues[5122]),0}, -{"SEED-OFB","seed-ofb",NID_seed_ofb128,8,&(lvalues[5130]),0}, -{"SEED-CFB","seed-cfb",NID_seed_cfb128,8,&(lvalues[5138]),0}, -{"HMAC-MD5","hmac-md5",NID_hmac_md5,8,&(lvalues[5146]),0}, -{"HMAC-SHA1","hmac-sha1",NID_hmac_sha1,8,&(lvalues[5154]),0}, -{"id-PasswordBasedMAC","password based MAC",NID_id_PasswordBasedMAC,9, - &(lvalues[5162]),0}, -{"id-DHBasedMac","Diffie-Hellman based MAC",NID_id_DHBasedMac,9, - &(lvalues[5171]),0}, -{"id-it-suppLangTags","id-it-suppLangTags",NID_id_it_suppLangTags,8, - &(lvalues[5180]),0}, -{"caRepository","CA Repository",NID_caRepository,8,&(lvalues[5188]),0}, -{"id-smime-ct-compressedData","id-smime-ct-compressedData", - NID_id_smime_ct_compressedData,11,&(lvalues[5196]),0}, -{"id-ct-asciiTextWithCRLF","id-ct-asciiTextWithCRLF", - NID_id_ct_asciiTextWithCRLF,11,&(lvalues[5207]),0}, -{"id-aes128-wrap","id-aes128-wrap",NID_id_aes128_wrap,9, - &(lvalues[5218]),0}, -{"id-aes192-wrap","id-aes192-wrap",NID_id_aes192_wrap,9, - &(lvalues[5227]),0}, -{"id-aes256-wrap","id-aes256-wrap",NID_id_aes256_wrap,9, - &(lvalues[5236]),0}, -{"ecdsa-with-Recommended","ecdsa-with-Recommended", - NID_ecdsa_with_Recommended,7,&(lvalues[5245]),0}, -{"ecdsa-with-Specified","ecdsa-with-Specified", - NID_ecdsa_with_Specified,7,&(lvalues[5252]),0}, -{"ecdsa-with-SHA224","ecdsa-with-SHA224",NID_ecdsa_with_SHA224,8, - &(lvalues[5259]),0}, -{"ecdsa-with-SHA256","ecdsa-with-SHA256",NID_ecdsa_with_SHA256,8, - &(lvalues[5267]),0}, -{"ecdsa-with-SHA384","ecdsa-with-SHA384",NID_ecdsa_with_SHA384,8, - &(lvalues[5275]),0}, -{"ecdsa-with-SHA512","ecdsa-with-SHA512",NID_ecdsa_with_SHA512,8, - &(lvalues[5283]),0}, -{"hmacWithMD5","hmacWithMD5",NID_hmacWithMD5,8,&(lvalues[5291]),0}, -{"hmacWithSHA224","hmacWithSHA224",NID_hmacWithSHA224,8, - &(lvalues[5299]),0}, -{"hmacWithSHA256","hmacWithSHA256",NID_hmacWithSHA256,8, - &(lvalues[5307]),0}, -{"hmacWithSHA384","hmacWithSHA384",NID_hmacWithSHA384,8, - &(lvalues[5315]),0}, -{"hmacWithSHA512","hmacWithSHA512",NID_hmacWithSHA512,8, - &(lvalues[5323]),0}, -{"dsa_with_SHA224","dsa_with_SHA224",NID_dsa_with_SHA224,9, - &(lvalues[5331]),0}, -{"dsa_with_SHA256","dsa_with_SHA256",NID_dsa_with_SHA256,9, - &(lvalues[5340]),0}, -{"whirlpool","whirlpool",NID_whirlpool,6,&(lvalues[5349]),0}, -{"cryptopro","cryptopro",NID_cryptopro,5,&(lvalues[5355]),0}, -{"cryptocom","cryptocom",NID_cryptocom,5,&(lvalues[5360]),0}, -{"id-GostR3411-94-with-GostR3410-2001", - "GOST R 34.11-94 with GOST R 34.10-2001", - NID_id_GostR3411_94_with_GostR3410_2001,6,&(lvalues[5365]),0}, -{"id-GostR3411-94-with-GostR3410-94", - "GOST R 34.11-94 with GOST R 34.10-94", - NID_id_GostR3411_94_with_GostR3410_94,6,&(lvalues[5371]),0}, -{"md_gost94","GOST R 34.11-94",NID_id_GostR3411_94,6,&(lvalues[5377]),0}, -{"id-HMACGostR3411-94","HMAC GOST 34.11-94",NID_id_HMACGostR3411_94,6, - &(lvalues[5383]),0}, -{"gost2001","GOST R 34.10-2001",NID_id_GostR3410_2001,6, - &(lvalues[5389]),0}, -{"gost94","GOST R 34.10-94",NID_id_GostR3410_94,6,&(lvalues[5395]),0}, -{"gost89","GOST 28147-89",NID_id_Gost28147_89,6,&(lvalues[5401]),0}, -{"gost89-cnt","gost89-cnt",NID_gost89_cnt,0,NULL,0}, -{"gost-mac","GOST 28147-89 MAC",NID_id_Gost28147_89_MAC,6, - &(lvalues[5407]),0}, -{"prf-gostr3411-94","GOST R 34.11-94 PRF",NID_id_GostR3411_94_prf,6, - &(lvalues[5413]),0}, -{"id-GostR3410-2001DH","GOST R 34.10-2001 DH",NID_id_GostR3410_2001DH, - 6,&(lvalues[5419]),0}, -{"id-GostR3410-94DH","GOST R 34.10-94 DH",NID_id_GostR3410_94DH,6, - &(lvalues[5425]),0}, -{"id-Gost28147-89-CryptoPro-KeyMeshing", - "id-Gost28147-89-CryptoPro-KeyMeshing", - NID_id_Gost28147_89_CryptoPro_KeyMeshing,7,&(lvalues[5431]),0}, -{"id-Gost28147-89-None-KeyMeshing","id-Gost28147-89-None-KeyMeshing", - NID_id_Gost28147_89_None_KeyMeshing,7,&(lvalues[5438]),0}, -{"id-GostR3411-94-TestParamSet","id-GostR3411-94-TestParamSet", - NID_id_GostR3411_94_TestParamSet,7,&(lvalues[5445]),0}, -{"id-GostR3411-94-CryptoProParamSet", - "id-GostR3411-94-CryptoProParamSet", - NID_id_GostR3411_94_CryptoProParamSet,7,&(lvalues[5452]),0}, -{"id-Gost28147-89-TestParamSet","id-Gost28147-89-TestParamSet", - NID_id_Gost28147_89_TestParamSet,7,&(lvalues[5459]),0}, -{"id-Gost28147-89-CryptoPro-A-ParamSet", - "id-Gost28147-89-CryptoPro-A-ParamSet", - NID_id_Gost28147_89_CryptoPro_A_ParamSet,7,&(lvalues[5466]),0}, -{"id-Gost28147-89-CryptoPro-B-ParamSet", - "id-Gost28147-89-CryptoPro-B-ParamSet", - NID_id_Gost28147_89_CryptoPro_B_ParamSet,7,&(lvalues[5473]),0}, -{"id-Gost28147-89-CryptoPro-C-ParamSet", - "id-Gost28147-89-CryptoPro-C-ParamSet", - NID_id_Gost28147_89_CryptoPro_C_ParamSet,7,&(lvalues[5480]),0}, -{"id-Gost28147-89-CryptoPro-D-ParamSet", - "id-Gost28147-89-CryptoPro-D-ParamSet", - NID_id_Gost28147_89_CryptoPro_D_ParamSet,7,&(lvalues[5487]),0}, -{"id-Gost28147-89-CryptoPro-Oscar-1-1-ParamSet", - "id-Gost28147-89-CryptoPro-Oscar-1-1-ParamSet", - NID_id_Gost28147_89_CryptoPro_Oscar_1_1_ParamSet,7,&(lvalues[5494]), - 0}, -{"id-Gost28147-89-CryptoPro-Oscar-1-0-ParamSet", - "id-Gost28147-89-CryptoPro-Oscar-1-0-ParamSet", - NID_id_Gost28147_89_CryptoPro_Oscar_1_0_ParamSet,7,&(lvalues[5501]), - 0}, -{"id-Gost28147-89-CryptoPro-RIC-1-ParamSet", - "id-Gost28147-89-CryptoPro-RIC-1-ParamSet", - NID_id_Gost28147_89_CryptoPro_RIC_1_ParamSet,7,&(lvalues[5508]),0}, -{"id-GostR3410-94-TestParamSet","id-GostR3410-94-TestParamSet", - NID_id_GostR3410_94_TestParamSet,7,&(lvalues[5515]),0}, -{"id-GostR3410-94-CryptoPro-A-ParamSet", - "id-GostR3410-94-CryptoPro-A-ParamSet", - NID_id_GostR3410_94_CryptoPro_A_ParamSet,7,&(lvalues[5522]),0}, -{"id-GostR3410-94-CryptoPro-B-ParamSet", - "id-GostR3410-94-CryptoPro-B-ParamSet", - NID_id_GostR3410_94_CryptoPro_B_ParamSet,7,&(lvalues[5529]),0}, -{"id-GostR3410-94-CryptoPro-C-ParamSet", - "id-GostR3410-94-CryptoPro-C-ParamSet", - NID_id_GostR3410_94_CryptoPro_C_ParamSet,7,&(lvalues[5536]),0}, -{"id-GostR3410-94-CryptoPro-D-ParamSet", - "id-GostR3410-94-CryptoPro-D-ParamSet", - NID_id_GostR3410_94_CryptoPro_D_ParamSet,7,&(lvalues[5543]),0}, -{"id-GostR3410-94-CryptoPro-XchA-ParamSet", - "id-GostR3410-94-CryptoPro-XchA-ParamSet", - NID_id_GostR3410_94_CryptoPro_XchA_ParamSet,7,&(lvalues[5550]),0}, -{"id-GostR3410-94-CryptoPro-XchB-ParamSet", - "id-GostR3410-94-CryptoPro-XchB-ParamSet", - NID_id_GostR3410_94_CryptoPro_XchB_ParamSet,7,&(lvalues[5557]),0}, -{"id-GostR3410-94-CryptoPro-XchC-ParamSet", - "id-GostR3410-94-CryptoPro-XchC-ParamSet", - NID_id_GostR3410_94_CryptoPro_XchC_ParamSet,7,&(lvalues[5564]),0}, -{"id-GostR3410-2001-TestParamSet","id-GostR3410-2001-TestParamSet", - NID_id_GostR3410_2001_TestParamSet,7,&(lvalues[5571]),0}, -{"id-GostR3410-2001-CryptoPro-A-ParamSet", - "id-GostR3410-2001-CryptoPro-A-ParamSet", - NID_id_GostR3410_2001_CryptoPro_A_ParamSet,7,&(lvalues[5578]),0}, -{"id-GostR3410-2001-CryptoPro-B-ParamSet", - "id-GostR3410-2001-CryptoPro-B-ParamSet", - NID_id_GostR3410_2001_CryptoPro_B_ParamSet,7,&(lvalues[5585]),0}, -{"id-GostR3410-2001-CryptoPro-C-ParamSet", - "id-GostR3410-2001-CryptoPro-C-ParamSet", - NID_id_GostR3410_2001_CryptoPro_C_ParamSet,7,&(lvalues[5592]),0}, -{"id-GostR3410-2001-CryptoPro-XchA-ParamSet", - "id-GostR3410-2001-CryptoPro-XchA-ParamSet", - NID_id_GostR3410_2001_CryptoPro_XchA_ParamSet,7,&(lvalues[5599]),0}, - -{"id-GostR3410-2001-CryptoPro-XchB-ParamSet", - "id-GostR3410-2001-CryptoPro-XchB-ParamSet", - NID_id_GostR3410_2001_CryptoPro_XchB_ParamSet,7,&(lvalues[5606]),0}, - -{"id-GostR3410-94-a","id-GostR3410-94-a",NID_id_GostR3410_94_a,7, - &(lvalues[5613]),0}, -{"id-GostR3410-94-aBis","id-GostR3410-94-aBis", - NID_id_GostR3410_94_aBis,7,&(lvalues[5620]),0}, -{"id-GostR3410-94-b","id-GostR3410-94-b",NID_id_GostR3410_94_b,7, - &(lvalues[5627]),0}, -{"id-GostR3410-94-bBis","id-GostR3410-94-bBis", - NID_id_GostR3410_94_bBis,7,&(lvalues[5634]),0}, -{"id-Gost28147-89-cc","GOST 28147-89 Cryptocom ParamSet", - NID_id_Gost28147_89_cc,8,&(lvalues[5641]),0}, -{"gost94cc","GOST 34.10-94 Cryptocom",NID_id_GostR3410_94_cc,8, - &(lvalues[5649]),0}, -{"gost2001cc","GOST 34.10-2001 Cryptocom",NID_id_GostR3410_2001_cc,8, - &(lvalues[5657]),0}, -{"id-GostR3411-94-with-GostR3410-94-cc", - "GOST R 34.11-94 with GOST R 34.10-94 Cryptocom", - NID_id_GostR3411_94_with_GostR3410_94_cc,8,&(lvalues[5665]),0}, -{"id-GostR3411-94-with-GostR3410-2001-cc", - "GOST R 34.11-94 with GOST R 34.10-2001 Cryptocom", - NID_id_GostR3411_94_with_GostR3410_2001_cc,8,&(lvalues[5673]),0}, -{"id-GostR3410-2001-ParamSet-cc", - "GOST R 3410-2001 Parameter Set Cryptocom", - NID_id_GostR3410_2001_ParamSet_cc,8,&(lvalues[5681]),0}, -{"HMAC","hmac",NID_hmac,0,NULL,0}, -{"LocalKeySet","Microsoft Local Key set",NID_LocalKeySet,9, - &(lvalues[5689]),0}, -{"freshestCRL","X509v3 Freshest CRL",NID_freshest_crl,3, - &(lvalues[5698]),0}, -{"id-on-permanentIdentifier","Permanent Identifier", - NID_id_on_permanentIdentifier,8,&(lvalues[5701]),0}, -{"searchGuide","searchGuide",NID_searchGuide,3,&(lvalues[5709]),0}, -{"businessCategory","businessCategory",NID_businessCategory,3, - &(lvalues[5712]),0}, -{"postalAddress","postalAddress",NID_postalAddress,3,&(lvalues[5715]),0}, -{"postOfficeBox","postOfficeBox",NID_postOfficeBox,3,&(lvalues[5718]),0}, -{"physicalDeliveryOfficeName","physicalDeliveryOfficeName", - NID_physicalDeliveryOfficeName,3,&(lvalues[5721]),0}, -{"telephoneNumber","telephoneNumber",NID_telephoneNumber,3, - &(lvalues[5724]),0}, -{"telexNumber","telexNumber",NID_telexNumber,3,&(lvalues[5727]),0}, -{"teletexTerminalIdentifier","teletexTerminalIdentifier", - NID_teletexTerminalIdentifier,3,&(lvalues[5730]),0}, -{"facsimileTelephoneNumber","facsimileTelephoneNumber", - NID_facsimileTelephoneNumber,3,&(lvalues[5733]),0}, -{"x121Address","x121Address",NID_x121Address,3,&(lvalues[5736]),0}, -{"internationaliSDNNumber","internationaliSDNNumber", - NID_internationaliSDNNumber,3,&(lvalues[5739]),0}, -{"registeredAddress","registeredAddress",NID_registeredAddress,3, - &(lvalues[5742]),0}, -{"destinationIndicator","destinationIndicator", - NID_destinationIndicator,3,&(lvalues[5745]),0}, -{"preferredDeliveryMethod","preferredDeliveryMethod", - NID_preferredDeliveryMethod,3,&(lvalues[5748]),0}, -{"presentationAddress","presentationAddress",NID_presentationAddress, - 3,&(lvalues[5751]),0}, -{"supportedApplicationContext","supportedApplicationContext", - NID_supportedApplicationContext,3,&(lvalues[5754]),0}, -{"member","member",NID_member,3,&(lvalues[5757]),0}, -{"owner","owner",NID_owner,3,&(lvalues[5760]),0}, -{"roleOccupant","roleOccupant",NID_roleOccupant,3,&(lvalues[5763]),0}, -{"seeAlso","seeAlso",NID_seeAlso,3,&(lvalues[5766]),0}, -{"userPassword","userPassword",NID_userPassword,3,&(lvalues[5769]),0}, -{"userCertificate","userCertificate",NID_userCertificate,3, - &(lvalues[5772]),0}, -{"cACertificate","cACertificate",NID_cACertificate,3,&(lvalues[5775]),0}, -{"authorityRevocationList","authorityRevocationList", - NID_authorityRevocationList,3,&(lvalues[5778]),0}, -{"certificateRevocationList","certificateRevocationList", - NID_certificateRevocationList,3,&(lvalues[5781]),0}, -{"crossCertificatePair","crossCertificatePair", - NID_crossCertificatePair,3,&(lvalues[5784]),0}, -{"enhancedSearchGuide","enhancedSearchGuide",NID_enhancedSearchGuide, - 3,&(lvalues[5787]),0}, -{"protocolInformation","protocolInformation",NID_protocolInformation, - 3,&(lvalues[5790]),0}, -{"distinguishedName","distinguishedName",NID_distinguishedName,3, - &(lvalues[5793]),0}, -{"uniqueMember","uniqueMember",NID_uniqueMember,3,&(lvalues[5796]),0}, -{"houseIdentifier","houseIdentifier",NID_houseIdentifier,3, - &(lvalues[5799]),0}, -{"supportedAlgorithms","supportedAlgorithms",NID_supportedAlgorithms, - 3,&(lvalues[5802]),0}, -{"deltaRevocationList","deltaRevocationList",NID_deltaRevocationList, - 3,&(lvalues[5805]),0}, -{"dmdName","dmdName",NID_dmdName,3,&(lvalues[5808]),0}, -{"id-alg-PWRI-KEK","id-alg-PWRI-KEK",NID_id_alg_PWRI_KEK,11, - &(lvalues[5811]),0}, -{"CMAC","cmac",NID_cmac,0,NULL,0}, -{"id-aes128-GCM","aes-128-gcm",NID_aes_128_gcm,9,&(lvalues[5822]),0}, -{"id-aes128-CCM","aes-128-ccm",NID_aes_128_ccm,9,&(lvalues[5831]),0}, -{"id-aes128-wrap-pad","id-aes128-wrap-pad",NID_id_aes128_wrap_pad,9, - &(lvalues[5840]),0}, -{"id-aes192-GCM","aes-192-gcm",NID_aes_192_gcm,9,&(lvalues[5849]),0}, -{"id-aes192-CCM","aes-192-ccm",NID_aes_192_ccm,9,&(lvalues[5858]),0}, -{"id-aes192-wrap-pad","id-aes192-wrap-pad",NID_id_aes192_wrap_pad,9, - &(lvalues[5867]),0}, -{"id-aes256-GCM","aes-256-gcm",NID_aes_256_gcm,9,&(lvalues[5876]),0}, -{"id-aes256-CCM","aes-256-ccm",NID_aes_256_ccm,9,&(lvalues[5885]),0}, -{"id-aes256-wrap-pad","id-aes256-wrap-pad",NID_id_aes256_wrap_pad,9, - &(lvalues[5894]),0}, -{"AES-128-CTR","aes-128-ctr",NID_aes_128_ctr,0,NULL,0}, -{"AES-192-CTR","aes-192-ctr",NID_aes_192_ctr,0,NULL,0}, -{"AES-256-CTR","aes-256-ctr",NID_aes_256_ctr,0,NULL,0}, -{"id-camellia128-wrap","id-camellia128-wrap",NID_id_camellia128_wrap, - 11,&(lvalues[5903]),0}, -{"id-camellia192-wrap","id-camellia192-wrap",NID_id_camellia192_wrap, - 11,&(lvalues[5914]),0}, -{"id-camellia256-wrap","id-camellia256-wrap",NID_id_camellia256_wrap, - 11,&(lvalues[5925]),0}, -{"anyExtendedKeyUsage","Any Extended Key Usage", - NID_anyExtendedKeyUsage,4,&(lvalues[5936]),0}, -{"MGF1","mgf1",NID_mgf1,9,&(lvalues[5940]),0}, -{"RSASSA-PSS","rsassaPss",NID_rsassaPss,9,&(lvalues[5949]),0}, -{"AES-128-XTS","aes-128-xts",NID_aes_128_xts,0,NULL,0}, -{"AES-256-XTS","aes-256-xts",NID_aes_256_xts,0,NULL,0}, -{"RC4-HMAC-MD5","rc4-hmac-md5",NID_rc4_hmac_md5,0,NULL,0}, -{"AES-128-CBC-HMAC-SHA1","aes-128-cbc-hmac-sha1", - NID_aes_128_cbc_hmac_sha1,0,NULL,0}, -{"AES-192-CBC-HMAC-SHA1","aes-192-cbc-hmac-sha1", - NID_aes_192_cbc_hmac_sha1,0,NULL,0}, -{"AES-256-CBC-HMAC-SHA1","aes-256-cbc-hmac-sha1", - NID_aes_256_cbc_hmac_sha1,0,NULL,0}, -{"RSAES-OAEP","rsaesOaep",NID_rsaesOaep,9,&(lvalues[5958]),0}, -{"dhpublicnumber","X9.42 DH",NID_dhpublicnumber,7,&(lvalues[5967]),0}, -{"brainpoolP160r1","brainpoolP160r1",NID_brainpoolP160r1,9, - &(lvalues[5974]),0}, -{"brainpoolP160t1","brainpoolP160t1",NID_brainpoolP160t1,9, - &(lvalues[5983]),0}, -{"brainpoolP192r1","brainpoolP192r1",NID_brainpoolP192r1,9, - &(lvalues[5992]),0}, -{"brainpoolP192t1","brainpoolP192t1",NID_brainpoolP192t1,9, - &(lvalues[6001]),0}, -{"brainpoolP224r1","brainpoolP224r1",NID_brainpoolP224r1,9, - &(lvalues[6010]),0}, -{"brainpoolP224t1","brainpoolP224t1",NID_brainpoolP224t1,9, - &(lvalues[6019]),0}, -{"brainpoolP256r1","brainpoolP256r1",NID_brainpoolP256r1,9, - &(lvalues[6028]),0}, -{"brainpoolP256t1","brainpoolP256t1",NID_brainpoolP256t1,9, - &(lvalues[6037]),0}, -{"brainpoolP320r1","brainpoolP320r1",NID_brainpoolP320r1,9, - &(lvalues[6046]),0}, -{"brainpoolP320t1","brainpoolP320t1",NID_brainpoolP320t1,9, - &(lvalues[6055]),0}, -{"brainpoolP384r1","brainpoolP384r1",NID_brainpoolP384r1,9, - &(lvalues[6064]),0}, -{"brainpoolP384t1","brainpoolP384t1",NID_brainpoolP384t1,9, - &(lvalues[6073]),0}, -{"brainpoolP512r1","brainpoolP512r1",NID_brainpoolP512r1,9, - &(lvalues[6082]),0}, -{"brainpoolP512t1","brainpoolP512t1",NID_brainpoolP512t1,9, - &(lvalues[6091]),0}, -{"PSPECIFIED","pSpecified",NID_pSpecified,9,&(lvalues[6100]),0}, -{"dhSinglePass-stdDH-sha1kdf-scheme", - "dhSinglePass-stdDH-sha1kdf-scheme", - NID_dhSinglePass_stdDH_sha1kdf_scheme,9,&(lvalues[6109]),0}, -{"dhSinglePass-stdDH-sha224kdf-scheme", - "dhSinglePass-stdDH-sha224kdf-scheme", - NID_dhSinglePass_stdDH_sha224kdf_scheme,6,&(lvalues[6118]),0}, -{"dhSinglePass-stdDH-sha256kdf-scheme", - "dhSinglePass-stdDH-sha256kdf-scheme", - NID_dhSinglePass_stdDH_sha256kdf_scheme,6,&(lvalues[6124]),0}, -{"dhSinglePass-stdDH-sha384kdf-scheme", - "dhSinglePass-stdDH-sha384kdf-scheme", - NID_dhSinglePass_stdDH_sha384kdf_scheme,6,&(lvalues[6130]),0}, -{"dhSinglePass-stdDH-sha512kdf-scheme", - "dhSinglePass-stdDH-sha512kdf-scheme", - NID_dhSinglePass_stdDH_sha512kdf_scheme,6,&(lvalues[6136]),0}, -{"dhSinglePass-cofactorDH-sha1kdf-scheme", - "dhSinglePass-cofactorDH-sha1kdf-scheme", - NID_dhSinglePass_cofactorDH_sha1kdf_scheme,9,&(lvalues[6142]),0}, -{"dhSinglePass-cofactorDH-sha224kdf-scheme", - "dhSinglePass-cofactorDH-sha224kdf-scheme", - NID_dhSinglePass_cofactorDH_sha224kdf_scheme,6,&(lvalues[6151]),0}, -{"dhSinglePass-cofactorDH-sha256kdf-scheme", - "dhSinglePass-cofactorDH-sha256kdf-scheme", - NID_dhSinglePass_cofactorDH_sha256kdf_scheme,6,&(lvalues[6157]),0}, -{"dhSinglePass-cofactorDH-sha384kdf-scheme", - "dhSinglePass-cofactorDH-sha384kdf-scheme", - NID_dhSinglePass_cofactorDH_sha384kdf_scheme,6,&(lvalues[6163]),0}, -{"dhSinglePass-cofactorDH-sha512kdf-scheme", - "dhSinglePass-cofactorDH-sha512kdf-scheme", - NID_dhSinglePass_cofactorDH_sha512kdf_scheme,6,&(lvalues[6169]),0}, -{"dh-std-kdf","dh-std-kdf",NID_dh_std_kdf,0,NULL,0}, -{"dh-cofactor-kdf","dh-cofactor-kdf",NID_dh_cofactor_kdf,0,NULL,0}, -{"X25519","x25519",NID_x25519,0,NULL,0}, +static const ASN1_OBJECT kObjects[NUM_NID] = { + {"UNDEF", "undefined", NID_undef, 0, NULL, 0}, + {"rsadsi", "RSA Data Security, Inc.", NID_rsadsi, 6, &kObjectData[0], 0}, + {"pkcs", "RSA Data Security, Inc. PKCS", NID_pkcs, 7, &kObjectData[6], 0}, + {"MD2", "md2", NID_md2, 8, &kObjectData[13], 0}, + {"MD5", "md5", NID_md5, 8, &kObjectData[21], 0}, + {"RC4", "rc4", NID_rc4, 8, &kObjectData[29], 0}, + {"rsaEncryption", "rsaEncryption", NID_rsaEncryption, 9, &kObjectData[37], + 0}, + {"RSA-MD2", "md2WithRSAEncryption", NID_md2WithRSAEncryption, 9, + &kObjectData[46], 0}, + {"RSA-MD5", "md5WithRSAEncryption", NID_md5WithRSAEncryption, 9, + &kObjectData[55], 0}, + {"PBE-MD2-DES", "pbeWithMD2AndDES-CBC", NID_pbeWithMD2AndDES_CBC, 9, + &kObjectData[64], 0}, + {"PBE-MD5-DES", "pbeWithMD5AndDES-CBC", NID_pbeWithMD5AndDES_CBC, 9, + &kObjectData[73], 0}, + {"X500", "directory services (X.500)", NID_X500, 1, &kObjectData[82], 0}, + {"X509", "X509", NID_X509, 2, &kObjectData[83], 0}, + {"CN", "commonName", NID_commonName, 3, &kObjectData[85], 0}, + {"C", "countryName", NID_countryName, 3, &kObjectData[88], 0}, + {"L", "localityName", NID_localityName, 3, &kObjectData[91], 0}, + {"ST", "stateOrProvinceName", NID_stateOrProvinceName, 3, &kObjectData[94], + 0}, + {"O", "organizationName", NID_organizationName, 3, &kObjectData[97], 0}, + {"OU", "organizationalUnitName", NID_organizationalUnitName, 3, + &kObjectData[100], 0}, + {"RSA", "rsa", NID_rsa, 4, &kObjectData[103], 0}, + {"pkcs7", "pkcs7", NID_pkcs7, 8, &kObjectData[107], 0}, + {"pkcs7-data", "pkcs7-data", NID_pkcs7_data, 9, &kObjectData[115], 0}, + {"pkcs7-signedData", "pkcs7-signedData", NID_pkcs7_signed, 9, + &kObjectData[124], 0}, + {"pkcs7-envelopedData", "pkcs7-envelopedData", NID_pkcs7_enveloped, 9, + &kObjectData[133], 0}, + {"pkcs7-signedAndEnvelopedData", "pkcs7-signedAndEnvelopedData", + NID_pkcs7_signedAndEnveloped, 9, &kObjectData[142], 0}, + {"pkcs7-digestData", "pkcs7-digestData", NID_pkcs7_digest, 9, + &kObjectData[151], 0}, + {"pkcs7-encryptedData", "pkcs7-encryptedData", NID_pkcs7_encrypted, 9, + &kObjectData[160], 0}, + {"pkcs3", "pkcs3", NID_pkcs3, 8, &kObjectData[169], 0}, + {"dhKeyAgreement", "dhKeyAgreement", NID_dhKeyAgreement, 9, + &kObjectData[177], 0}, + {"DES-ECB", "des-ecb", NID_des_ecb, 5, &kObjectData[186], 0}, + {"DES-CFB", "des-cfb", NID_des_cfb64, 5, &kObjectData[191], 0}, + {"DES-CBC", "des-cbc", NID_des_cbc, 5, &kObjectData[196], 0}, + {"DES-EDE", "des-ede", NID_des_ede_ecb, 5, &kObjectData[201], 0}, + {"DES-EDE3", "des-ede3", NID_des_ede3_ecb, 0, NULL, 0}, + {"IDEA-CBC", "idea-cbc", NID_idea_cbc, 11, &kObjectData[206], 0}, + {"IDEA-CFB", "idea-cfb", NID_idea_cfb64, 0, NULL, 0}, + {"IDEA-ECB", "idea-ecb", NID_idea_ecb, 0, NULL, 0}, + {"RC2-CBC", "rc2-cbc", NID_rc2_cbc, 8, &kObjectData[217], 0}, + {"RC2-ECB", "rc2-ecb", NID_rc2_ecb, 0, NULL, 0}, + {"RC2-CFB", "rc2-cfb", NID_rc2_cfb64, 0, NULL, 0}, + {"RC2-OFB", "rc2-ofb", NID_rc2_ofb64, 0, NULL, 0}, + {"SHA", "sha", NID_sha, 5, &kObjectData[225], 0}, + {"RSA-SHA", "shaWithRSAEncryption", NID_shaWithRSAEncryption, 5, + &kObjectData[230], 0}, + {"DES-EDE-CBC", "des-ede-cbc", NID_des_ede_cbc, 0, NULL, 0}, + {"DES-EDE3-CBC", "des-ede3-cbc", NID_des_ede3_cbc, 8, &kObjectData[235], 0}, + {"DES-OFB", "des-ofb", NID_des_ofb64, 5, &kObjectData[243], 0}, + {"IDEA-OFB", "idea-ofb", NID_idea_ofb64, 0, NULL, 0}, + {"pkcs9", "pkcs9", NID_pkcs9, 8, &kObjectData[248], 0}, + {"emailAddress", "emailAddress", NID_pkcs9_emailAddress, 9, + &kObjectData[256], 0}, + {"unstructuredName", "unstructuredName", NID_pkcs9_unstructuredName, 9, + &kObjectData[265], 0}, + {"contentType", "contentType", NID_pkcs9_contentType, 9, &kObjectData[274], + 0}, + {"messageDigest", "messageDigest", NID_pkcs9_messageDigest, 9, + &kObjectData[283], 0}, + {"signingTime", "signingTime", NID_pkcs9_signingTime, 9, &kObjectData[292], + 0}, + {"countersignature", "countersignature", NID_pkcs9_countersignature, 9, + &kObjectData[301], 0}, + {"challengePassword", "challengePassword", NID_pkcs9_challengePassword, 9, + &kObjectData[310], 0}, + {"unstructuredAddress", "unstructuredAddress", + NID_pkcs9_unstructuredAddress, 9, &kObjectData[319], 0}, + {"extendedCertificateAttributes", "extendedCertificateAttributes", + NID_pkcs9_extCertAttributes, 9, &kObjectData[328], 0}, + {"Netscape", "Netscape Communications Corp.", NID_netscape, 7, + &kObjectData[337], 0}, + {"nsCertExt", "Netscape Certificate Extension", NID_netscape_cert_extension, + 8, &kObjectData[344], 0}, + {"nsDataType", "Netscape Data Type", NID_netscape_data_type, 8, + &kObjectData[352], 0}, + {"DES-EDE-CFB", "des-ede-cfb", NID_des_ede_cfb64, 0, NULL, 0}, + {"DES-EDE3-CFB", "des-ede3-cfb", NID_des_ede3_cfb64, 0, NULL, 0}, + {"DES-EDE-OFB", "des-ede-ofb", NID_des_ede_ofb64, 0, NULL, 0}, + {"DES-EDE3-OFB", "des-ede3-ofb", NID_des_ede3_ofb64, 0, NULL, 0}, + {"SHA1", "sha1", NID_sha1, 5, &kObjectData[360], 0}, + {"RSA-SHA1", "sha1WithRSAEncryption", NID_sha1WithRSAEncryption, 9, + &kObjectData[365], 0}, + {"DSA-SHA", "dsaWithSHA", NID_dsaWithSHA, 5, &kObjectData[374], 0}, + {"DSA-old", "dsaEncryption-old", NID_dsa_2, 5, &kObjectData[379], 0}, + {"PBE-SHA1-RC2-64", "pbeWithSHA1AndRC2-CBC", NID_pbeWithSHA1AndRC2_CBC, 9, + &kObjectData[384], 0}, + {"PBKDF2", "PBKDF2", NID_id_pbkdf2, 9, &kObjectData[393], 0}, + {"DSA-SHA1-old", "dsaWithSHA1-old", NID_dsaWithSHA1_2, 5, &kObjectData[402], + 0}, + {"nsCertType", "Netscape Cert Type", NID_netscape_cert_type, 9, + &kObjectData[407], 0}, + {"nsBaseUrl", "Netscape Base Url", NID_netscape_base_url, 9, + &kObjectData[416], 0}, + {"nsRevocationUrl", "Netscape Revocation Url", NID_netscape_revocation_url, + 9, &kObjectData[425], 0}, + {"nsCaRevocationUrl", "Netscape CA Revocation Url", + NID_netscape_ca_revocation_url, 9, &kObjectData[434], 0}, + {"nsRenewalUrl", "Netscape Renewal Url", NID_netscape_renewal_url, 9, + &kObjectData[443], 0}, + {"nsCaPolicyUrl", "Netscape CA Policy Url", NID_netscape_ca_policy_url, 9, + &kObjectData[452], 0}, + {"nsSslServerName", "Netscape SSL Server Name", + NID_netscape_ssl_server_name, 9, &kObjectData[461], 0}, + {"nsComment", "Netscape Comment", NID_netscape_comment, 9, + &kObjectData[470], 0}, + {"nsCertSequence", "Netscape Certificate Sequence", + NID_netscape_cert_sequence, 9, &kObjectData[479], 0}, + {"DESX-CBC", "desx-cbc", NID_desx_cbc, 0, NULL, 0}, + {"id-ce", "id-ce", NID_id_ce, 2, &kObjectData[488], 0}, + {"subjectKeyIdentifier", "X509v3 Subject Key Identifier", + NID_subject_key_identifier, 3, &kObjectData[490], 0}, + {"keyUsage", "X509v3 Key Usage", NID_key_usage, 3, &kObjectData[493], 0}, + {"privateKeyUsagePeriod", "X509v3 Private Key Usage Period", + NID_private_key_usage_period, 3, &kObjectData[496], 0}, + {"subjectAltName", "X509v3 Subject Alternative Name", NID_subject_alt_name, + 3, &kObjectData[499], 0}, + {"issuerAltName", "X509v3 Issuer Alternative Name", NID_issuer_alt_name, 3, + &kObjectData[502], 0}, + {"basicConstraints", "X509v3 Basic Constraints", NID_basic_constraints, 3, + &kObjectData[505], 0}, + {"crlNumber", "X509v3 CRL Number", NID_crl_number, 3, &kObjectData[508], 0}, + {"certificatePolicies", "X509v3 Certificate Policies", + NID_certificate_policies, 3, &kObjectData[511], 0}, + {"authorityKeyIdentifier", "X509v3 Authority Key Identifier", + NID_authority_key_identifier, 3, &kObjectData[514], 0}, + {"BF-CBC", "bf-cbc", NID_bf_cbc, 9, &kObjectData[517], 0}, + {"BF-ECB", "bf-ecb", NID_bf_ecb, 0, NULL, 0}, + {"BF-CFB", "bf-cfb", NID_bf_cfb64, 0, NULL, 0}, + {"BF-OFB", "bf-ofb", NID_bf_ofb64, 0, NULL, 0}, + {"MDC2", "mdc2", NID_mdc2, 4, &kObjectData[526], 0}, + {"RSA-MDC2", "mdc2WithRSA", NID_mdc2WithRSA, 4, &kObjectData[530], 0}, + {"RC4-40", "rc4-40", NID_rc4_40, 0, NULL, 0}, + {"RC2-40-CBC", "rc2-40-cbc", NID_rc2_40_cbc, 0, NULL, 0}, + {"GN", "givenName", NID_givenName, 3, &kObjectData[534], 0}, + {"SN", "surname", NID_surname, 3, &kObjectData[537], 0}, + {"initials", "initials", NID_initials, 3, &kObjectData[540], 0}, + {NULL, NULL, NID_undef, 0, NULL, 0}, + {"crlDistributionPoints", "X509v3 CRL Distribution Points", + NID_crl_distribution_points, 3, &kObjectData[543], 0}, + {"RSA-NP-MD5", "md5WithRSA", NID_md5WithRSA, 5, &kObjectData[546], 0}, + {"serialNumber", "serialNumber", NID_serialNumber, 3, &kObjectData[551], 0}, + {"title", "title", NID_title, 3, &kObjectData[554], 0}, + {"description", "description", NID_description, 3, &kObjectData[557], 0}, + {"CAST5-CBC", "cast5-cbc", NID_cast5_cbc, 9, &kObjectData[560], 0}, + {"CAST5-ECB", "cast5-ecb", NID_cast5_ecb, 0, NULL, 0}, + {"CAST5-CFB", "cast5-cfb", NID_cast5_cfb64, 0, NULL, 0}, + {"CAST5-OFB", "cast5-ofb", NID_cast5_ofb64, 0, NULL, 0}, + {"pbeWithMD5AndCast5CBC", "pbeWithMD5AndCast5CBC", + NID_pbeWithMD5AndCast5_CBC, 9, &kObjectData[569], 0}, + {"DSA-SHA1", "dsaWithSHA1", NID_dsaWithSHA1, 7, &kObjectData[578], 0}, + {"MD5-SHA1", "md5-sha1", NID_md5_sha1, 0, NULL, 0}, + {"RSA-SHA1-2", "sha1WithRSA", NID_sha1WithRSA, 5, &kObjectData[585], 0}, + {"DSA", "dsaEncryption", NID_dsa, 7, &kObjectData[590], 0}, + {"RIPEMD160", "ripemd160", NID_ripemd160, 5, &kObjectData[597], 0}, + {NULL, NULL, NID_undef, 0, NULL, 0}, + {"RSA-RIPEMD160", "ripemd160WithRSA", NID_ripemd160WithRSA, 6, + &kObjectData[602], 0}, + {"RC5-CBC", "rc5-cbc", NID_rc5_cbc, 8, &kObjectData[608], 0}, + {"RC5-ECB", "rc5-ecb", NID_rc5_ecb, 0, NULL, 0}, + {"RC5-CFB", "rc5-cfb", NID_rc5_cfb64, 0, NULL, 0}, + {"RC5-OFB", "rc5-ofb", NID_rc5_ofb64, 0, NULL, 0}, + {NULL, NULL, NID_undef, 0, NULL, 0}, + {"ZLIB", "zlib compression", NID_zlib_compression, 11, &kObjectData[616], + 0}, + {"extendedKeyUsage", "X509v3 Extended Key Usage", NID_ext_key_usage, 3, + &kObjectData[627], 0}, + {"PKIX", "PKIX", NID_id_pkix, 6, &kObjectData[630], 0}, + {"id-kp", "id-kp", NID_id_kp, 7, &kObjectData[636], 0}, + {"serverAuth", "TLS Web Server Authentication", NID_server_auth, 8, + &kObjectData[643], 0}, + {"clientAuth", "TLS Web Client Authentication", NID_client_auth, 8, + &kObjectData[651], 0}, + {"codeSigning", "Code Signing", NID_code_sign, 8, &kObjectData[659], 0}, + {"emailProtection", "E-mail Protection", NID_email_protect, 8, + &kObjectData[667], 0}, + {"timeStamping", "Time Stamping", NID_time_stamp, 8, &kObjectData[675], 0}, + {"msCodeInd", "Microsoft Individual Code Signing", NID_ms_code_ind, 10, + &kObjectData[683], 0}, + {"msCodeCom", "Microsoft Commercial Code Signing", NID_ms_code_com, 10, + &kObjectData[693], 0}, + {"msCTLSign", "Microsoft Trust List Signing", NID_ms_ctl_sign, 10, + &kObjectData[703], 0}, + {"msSGC", "Microsoft Server Gated Crypto", NID_ms_sgc, 10, + &kObjectData[713], 0}, + {"msEFS", "Microsoft Encrypted File System", NID_ms_efs, 10, + &kObjectData[723], 0}, + {"nsSGC", "Netscape Server Gated Crypto", NID_ns_sgc, 9, &kObjectData[733], + 0}, + {"deltaCRL", "X509v3 Delta CRL Indicator", NID_delta_crl, 3, + &kObjectData[742], 0}, + {"CRLReason", "X509v3 CRL Reason Code", NID_crl_reason, 3, + &kObjectData[745], 0}, + {"invalidityDate", "Invalidity Date", NID_invalidity_date, 3, + &kObjectData[748], 0}, + {"SXNetID", "Strong Extranet ID", NID_sxnet, 5, &kObjectData[751], 0}, + {"PBE-SHA1-RC4-128", "pbeWithSHA1And128BitRC4", + NID_pbe_WithSHA1And128BitRC4, 10, &kObjectData[756], 0}, + {"PBE-SHA1-RC4-40", "pbeWithSHA1And40BitRC4", NID_pbe_WithSHA1And40BitRC4, + 10, &kObjectData[766], 0}, + {"PBE-SHA1-3DES", "pbeWithSHA1And3-KeyTripleDES-CBC", + NID_pbe_WithSHA1And3_Key_TripleDES_CBC, 10, &kObjectData[776], 0}, + {"PBE-SHA1-2DES", "pbeWithSHA1And2-KeyTripleDES-CBC", + NID_pbe_WithSHA1And2_Key_TripleDES_CBC, 10, &kObjectData[786], 0}, + {"PBE-SHA1-RC2-128", "pbeWithSHA1And128BitRC2-CBC", + NID_pbe_WithSHA1And128BitRC2_CBC, 10, &kObjectData[796], 0}, + {"PBE-SHA1-RC2-40", "pbeWithSHA1And40BitRC2-CBC", + NID_pbe_WithSHA1And40BitRC2_CBC, 10, &kObjectData[806], 0}, + {"keyBag", "keyBag", NID_keyBag, 11, &kObjectData[816], 0}, + {"pkcs8ShroudedKeyBag", "pkcs8ShroudedKeyBag", NID_pkcs8ShroudedKeyBag, 11, + &kObjectData[827], 0}, + {"certBag", "certBag", NID_certBag, 11, &kObjectData[838], 0}, + {"crlBag", "crlBag", NID_crlBag, 11, &kObjectData[849], 0}, + {"secretBag", "secretBag", NID_secretBag, 11, &kObjectData[860], 0}, + {"safeContentsBag", "safeContentsBag", NID_safeContentsBag, 11, + &kObjectData[871], 0}, + {"friendlyName", "friendlyName", NID_friendlyName, 9, &kObjectData[882], 0}, + {"localKeyID", "localKeyID", NID_localKeyID, 9, &kObjectData[891], 0}, + {"x509Certificate", "x509Certificate", NID_x509Certificate, 10, + &kObjectData[900], 0}, + {"sdsiCertificate", "sdsiCertificate", NID_sdsiCertificate, 10, + &kObjectData[910], 0}, + {"x509Crl", "x509Crl", NID_x509Crl, 10, &kObjectData[920], 0}, + {"PBES2", "PBES2", NID_pbes2, 9, &kObjectData[930], 0}, + {"PBMAC1", "PBMAC1", NID_pbmac1, 9, &kObjectData[939], 0}, + {"hmacWithSHA1", "hmacWithSHA1", NID_hmacWithSHA1, 8, &kObjectData[948], 0}, + {"id-qt-cps", "Policy Qualifier CPS", NID_id_qt_cps, 8, &kObjectData[956], + 0}, + {"id-qt-unotice", "Policy Qualifier User Notice", NID_id_qt_unotice, 8, + &kObjectData[964], 0}, + {"RC2-64-CBC", "rc2-64-cbc", NID_rc2_64_cbc, 0, NULL, 0}, + {"SMIME-CAPS", "S/MIME Capabilities", NID_SMIMECapabilities, 9, + &kObjectData[972], 0}, + {"PBE-MD2-RC2-64", "pbeWithMD2AndRC2-CBC", NID_pbeWithMD2AndRC2_CBC, 9, + &kObjectData[981], 0}, + {"PBE-MD5-RC2-64", "pbeWithMD5AndRC2-CBC", NID_pbeWithMD5AndRC2_CBC, 9, + &kObjectData[990], 0}, + {"PBE-SHA1-DES", "pbeWithSHA1AndDES-CBC", NID_pbeWithSHA1AndDES_CBC, 9, + &kObjectData[999], 0}, + {"msExtReq", "Microsoft Extension Request", NID_ms_ext_req, 10, + &kObjectData[1008], 0}, + {"extReq", "Extension Request", NID_ext_req, 9, &kObjectData[1018], 0}, + {"name", "name", NID_name, 3, &kObjectData[1027], 0}, + {"dnQualifier", "dnQualifier", NID_dnQualifier, 3, &kObjectData[1030], 0}, + {"id-pe", "id-pe", NID_id_pe, 7, &kObjectData[1033], 0}, + {"id-ad", "id-ad", NID_id_ad, 7, &kObjectData[1040], 0}, + {"authorityInfoAccess", "Authority Information Access", NID_info_access, 8, + &kObjectData[1047], 0}, + {"OCSP", "OCSP", NID_ad_OCSP, 8, &kObjectData[1055], 0}, + {"caIssuers", "CA Issuers", NID_ad_ca_issuers, 8, &kObjectData[1063], 0}, + {"OCSPSigning", "OCSP Signing", NID_OCSP_sign, 8, &kObjectData[1071], 0}, + {"ISO", "iso", NID_iso, 0, NULL, 0}, + {"member-body", "ISO Member Body", NID_member_body, 1, &kObjectData[1079], + 0}, + {"ISO-US", "ISO US Member Body", NID_ISO_US, 3, &kObjectData[1080], 0}, + {"X9-57", "X9.57", NID_X9_57, 5, &kObjectData[1083], 0}, + {"X9cm", "X9.57 CM ?", NID_X9cm, 6, &kObjectData[1088], 0}, + {"pkcs1", "pkcs1", NID_pkcs1, 8, &kObjectData[1094], 0}, + {"pkcs5", "pkcs5", NID_pkcs5, 8, &kObjectData[1102], 0}, + {"SMIME", "S/MIME", NID_SMIME, 9, &kObjectData[1110], 0}, + {"id-smime-mod", "id-smime-mod", NID_id_smime_mod, 10, &kObjectData[1119], + 0}, + {"id-smime-ct", "id-smime-ct", NID_id_smime_ct, 10, &kObjectData[1129], 0}, + {"id-smime-aa", "id-smime-aa", NID_id_smime_aa, 10, &kObjectData[1139], 0}, + {"id-smime-alg", "id-smime-alg", NID_id_smime_alg, 10, &kObjectData[1149], + 0}, + {"id-smime-cd", "id-smime-cd", NID_id_smime_cd, 10, &kObjectData[1159], 0}, + {"id-smime-spq", "id-smime-spq", NID_id_smime_spq, 10, &kObjectData[1169], + 0}, + {"id-smime-cti", "id-smime-cti", NID_id_smime_cti, 10, &kObjectData[1179], + 0}, + {"id-smime-mod-cms", "id-smime-mod-cms", NID_id_smime_mod_cms, 11, + &kObjectData[1189], 0}, + {"id-smime-mod-ess", "id-smime-mod-ess", NID_id_smime_mod_ess, 11, + &kObjectData[1200], 0}, + {"id-smime-mod-oid", "id-smime-mod-oid", NID_id_smime_mod_oid, 11, + &kObjectData[1211], 0}, + {"id-smime-mod-msg-v3", "id-smime-mod-msg-v3", NID_id_smime_mod_msg_v3, 11, + &kObjectData[1222], 0}, + {"id-smime-mod-ets-eSignature-88", "id-smime-mod-ets-eSignature-88", + NID_id_smime_mod_ets_eSignature_88, 11, &kObjectData[1233], 0}, + {"id-smime-mod-ets-eSignature-97", "id-smime-mod-ets-eSignature-97", + NID_id_smime_mod_ets_eSignature_97, 11, &kObjectData[1244], 0}, + {"id-smime-mod-ets-eSigPolicy-88", "id-smime-mod-ets-eSigPolicy-88", + NID_id_smime_mod_ets_eSigPolicy_88, 11, &kObjectData[1255], 0}, + {"id-smime-mod-ets-eSigPolicy-97", "id-smime-mod-ets-eSigPolicy-97", + NID_id_smime_mod_ets_eSigPolicy_97, 11, &kObjectData[1266], 0}, + {"id-smime-ct-receipt", "id-smime-ct-receipt", NID_id_smime_ct_receipt, 11, + &kObjectData[1277], 0}, + {"id-smime-ct-authData", "id-smime-ct-authData", NID_id_smime_ct_authData, + 11, &kObjectData[1288], 0}, + {"id-smime-ct-publishCert", "id-smime-ct-publishCert", + NID_id_smime_ct_publishCert, 11, &kObjectData[1299], 0}, + {"id-smime-ct-TSTInfo", "id-smime-ct-TSTInfo", NID_id_smime_ct_TSTInfo, 11, + &kObjectData[1310], 0}, + {"id-smime-ct-TDTInfo", "id-smime-ct-TDTInfo", NID_id_smime_ct_TDTInfo, 11, + &kObjectData[1321], 0}, + {"id-smime-ct-contentInfo", "id-smime-ct-contentInfo", + NID_id_smime_ct_contentInfo, 11, &kObjectData[1332], 0}, + {"id-smime-ct-DVCSRequestData", "id-smime-ct-DVCSRequestData", + NID_id_smime_ct_DVCSRequestData, 11, &kObjectData[1343], 0}, + {"id-smime-ct-DVCSResponseData", "id-smime-ct-DVCSResponseData", + NID_id_smime_ct_DVCSResponseData, 11, &kObjectData[1354], 0}, + {"id-smime-aa-receiptRequest", "id-smime-aa-receiptRequest", + NID_id_smime_aa_receiptRequest, 11, &kObjectData[1365], 0}, + {"id-smime-aa-securityLabel", "id-smime-aa-securityLabel", + NID_id_smime_aa_securityLabel, 11, &kObjectData[1376], 0}, + {"id-smime-aa-mlExpandHistory", "id-smime-aa-mlExpandHistory", + NID_id_smime_aa_mlExpandHistory, 11, &kObjectData[1387], 0}, + {"id-smime-aa-contentHint", "id-smime-aa-contentHint", + NID_id_smime_aa_contentHint, 11, &kObjectData[1398], 0}, + {"id-smime-aa-msgSigDigest", "id-smime-aa-msgSigDigest", + NID_id_smime_aa_msgSigDigest, 11, &kObjectData[1409], 0}, + {"id-smime-aa-encapContentType", "id-smime-aa-encapContentType", + NID_id_smime_aa_encapContentType, 11, &kObjectData[1420], 0}, + {"id-smime-aa-contentIdentifier", "id-smime-aa-contentIdentifier", + NID_id_smime_aa_contentIdentifier, 11, &kObjectData[1431], 0}, + {"id-smime-aa-macValue", "id-smime-aa-macValue", NID_id_smime_aa_macValue, + 11, &kObjectData[1442], 0}, + {"id-smime-aa-equivalentLabels", "id-smime-aa-equivalentLabels", + NID_id_smime_aa_equivalentLabels, 11, &kObjectData[1453], 0}, + {"id-smime-aa-contentReference", "id-smime-aa-contentReference", + NID_id_smime_aa_contentReference, 11, &kObjectData[1464], 0}, + {"id-smime-aa-encrypKeyPref", "id-smime-aa-encrypKeyPref", + NID_id_smime_aa_encrypKeyPref, 11, &kObjectData[1475], 0}, + {"id-smime-aa-signingCertificate", "id-smime-aa-signingCertificate", + NID_id_smime_aa_signingCertificate, 11, &kObjectData[1486], 0}, + {"id-smime-aa-smimeEncryptCerts", "id-smime-aa-smimeEncryptCerts", + NID_id_smime_aa_smimeEncryptCerts, 11, &kObjectData[1497], 0}, + {"id-smime-aa-timeStampToken", "id-smime-aa-timeStampToken", + NID_id_smime_aa_timeStampToken, 11, &kObjectData[1508], 0}, + {"id-smime-aa-ets-sigPolicyId", "id-smime-aa-ets-sigPolicyId", + NID_id_smime_aa_ets_sigPolicyId, 11, &kObjectData[1519], 0}, + {"id-smime-aa-ets-commitmentType", "id-smime-aa-ets-commitmentType", + NID_id_smime_aa_ets_commitmentType, 11, &kObjectData[1530], 0}, + {"id-smime-aa-ets-signerLocation", "id-smime-aa-ets-signerLocation", + NID_id_smime_aa_ets_signerLocation, 11, &kObjectData[1541], 0}, + {"id-smime-aa-ets-signerAttr", "id-smime-aa-ets-signerAttr", + NID_id_smime_aa_ets_signerAttr, 11, &kObjectData[1552], 0}, + {"id-smime-aa-ets-otherSigCert", "id-smime-aa-ets-otherSigCert", + NID_id_smime_aa_ets_otherSigCert, 11, &kObjectData[1563], 0}, + {"id-smime-aa-ets-contentTimestamp", "id-smime-aa-ets-contentTimestamp", + NID_id_smime_aa_ets_contentTimestamp, 11, &kObjectData[1574], 0}, + {"id-smime-aa-ets-CertificateRefs", "id-smime-aa-ets-CertificateRefs", + NID_id_smime_aa_ets_CertificateRefs, 11, &kObjectData[1585], 0}, + {"id-smime-aa-ets-RevocationRefs", "id-smime-aa-ets-RevocationRefs", + NID_id_smime_aa_ets_RevocationRefs, 11, &kObjectData[1596], 0}, + {"id-smime-aa-ets-certValues", "id-smime-aa-ets-certValues", + NID_id_smime_aa_ets_certValues, 11, &kObjectData[1607], 0}, + {"id-smime-aa-ets-revocationValues", "id-smime-aa-ets-revocationValues", + NID_id_smime_aa_ets_revocationValues, 11, &kObjectData[1618], 0}, + {"id-smime-aa-ets-escTimeStamp", "id-smime-aa-ets-escTimeStamp", + NID_id_smime_aa_ets_escTimeStamp, 11, &kObjectData[1629], 0}, + {"id-smime-aa-ets-certCRLTimestamp", "id-smime-aa-ets-certCRLTimestamp", + NID_id_smime_aa_ets_certCRLTimestamp, 11, &kObjectData[1640], 0}, + {"id-smime-aa-ets-archiveTimeStamp", "id-smime-aa-ets-archiveTimeStamp", + NID_id_smime_aa_ets_archiveTimeStamp, 11, &kObjectData[1651], 0}, + {"id-smime-aa-signatureType", "id-smime-aa-signatureType", + NID_id_smime_aa_signatureType, 11, &kObjectData[1662], 0}, + {"id-smime-aa-dvcs-dvc", "id-smime-aa-dvcs-dvc", NID_id_smime_aa_dvcs_dvc, + 11, &kObjectData[1673], 0}, + {"id-smime-alg-ESDHwith3DES", "id-smime-alg-ESDHwith3DES", + NID_id_smime_alg_ESDHwith3DES, 11, &kObjectData[1684], 0}, + {"id-smime-alg-ESDHwithRC2", "id-smime-alg-ESDHwithRC2", + NID_id_smime_alg_ESDHwithRC2, 11, &kObjectData[1695], 0}, + {"id-smime-alg-3DESwrap", "id-smime-alg-3DESwrap", + NID_id_smime_alg_3DESwrap, 11, &kObjectData[1706], 0}, + {"id-smime-alg-RC2wrap", "id-smime-alg-RC2wrap", NID_id_smime_alg_RC2wrap, + 11, &kObjectData[1717], 0}, + {"id-smime-alg-ESDH", "id-smime-alg-ESDH", NID_id_smime_alg_ESDH, 11, + &kObjectData[1728], 0}, + {"id-smime-alg-CMS3DESwrap", "id-smime-alg-CMS3DESwrap", + NID_id_smime_alg_CMS3DESwrap, 11, &kObjectData[1739], 0}, + {"id-smime-alg-CMSRC2wrap", "id-smime-alg-CMSRC2wrap", + NID_id_smime_alg_CMSRC2wrap, 11, &kObjectData[1750], 0}, + {"id-smime-cd-ldap", "id-smime-cd-ldap", NID_id_smime_cd_ldap, 11, + &kObjectData[1761], 0}, + {"id-smime-spq-ets-sqt-uri", "id-smime-spq-ets-sqt-uri", + NID_id_smime_spq_ets_sqt_uri, 11, &kObjectData[1772], 0}, + {"id-smime-spq-ets-sqt-unotice", "id-smime-spq-ets-sqt-unotice", + NID_id_smime_spq_ets_sqt_unotice, 11, &kObjectData[1783], 0}, + {"id-smime-cti-ets-proofOfOrigin", "id-smime-cti-ets-proofOfOrigin", + NID_id_smime_cti_ets_proofOfOrigin, 11, &kObjectData[1794], 0}, + {"id-smime-cti-ets-proofOfReceipt", "id-smime-cti-ets-proofOfReceipt", + NID_id_smime_cti_ets_proofOfReceipt, 11, &kObjectData[1805], 0}, + {"id-smime-cti-ets-proofOfDelivery", "id-smime-cti-ets-proofOfDelivery", + NID_id_smime_cti_ets_proofOfDelivery, 11, &kObjectData[1816], 0}, + {"id-smime-cti-ets-proofOfSender", "id-smime-cti-ets-proofOfSender", + NID_id_smime_cti_ets_proofOfSender, 11, &kObjectData[1827], 0}, + {"id-smime-cti-ets-proofOfApproval", "id-smime-cti-ets-proofOfApproval", + NID_id_smime_cti_ets_proofOfApproval, 11, &kObjectData[1838], 0}, + {"id-smime-cti-ets-proofOfCreation", "id-smime-cti-ets-proofOfCreation", + NID_id_smime_cti_ets_proofOfCreation, 11, &kObjectData[1849], 0}, + {"MD4", "md4", NID_md4, 8, &kObjectData[1860], 0}, + {"id-pkix-mod", "id-pkix-mod", NID_id_pkix_mod, 7, &kObjectData[1868], 0}, + {"id-qt", "id-qt", NID_id_qt, 7, &kObjectData[1875], 0}, + {"id-it", "id-it", NID_id_it, 7, &kObjectData[1882], 0}, + {"id-pkip", "id-pkip", NID_id_pkip, 7, &kObjectData[1889], 0}, + {"id-alg", "id-alg", NID_id_alg, 7, &kObjectData[1896], 0}, + {"id-cmc", "id-cmc", NID_id_cmc, 7, &kObjectData[1903], 0}, + {"id-on", "id-on", NID_id_on, 7, &kObjectData[1910], 0}, + {"id-pda", "id-pda", NID_id_pda, 7, &kObjectData[1917], 0}, + {"id-aca", "id-aca", NID_id_aca, 7, &kObjectData[1924], 0}, + {"id-qcs", "id-qcs", NID_id_qcs, 7, &kObjectData[1931], 0}, + {"id-cct", "id-cct", NID_id_cct, 7, &kObjectData[1938], 0}, + {"id-pkix1-explicit-88", "id-pkix1-explicit-88", NID_id_pkix1_explicit_88, + 8, &kObjectData[1945], 0}, + {"id-pkix1-implicit-88", "id-pkix1-implicit-88", NID_id_pkix1_implicit_88, + 8, &kObjectData[1953], 0}, + {"id-pkix1-explicit-93", "id-pkix1-explicit-93", NID_id_pkix1_explicit_93, + 8, &kObjectData[1961], 0}, + {"id-pkix1-implicit-93", "id-pkix1-implicit-93", NID_id_pkix1_implicit_93, + 8, &kObjectData[1969], 0}, + {"id-mod-crmf", "id-mod-crmf", NID_id_mod_crmf, 8, &kObjectData[1977], 0}, + {"id-mod-cmc", "id-mod-cmc", NID_id_mod_cmc, 8, &kObjectData[1985], 0}, + {"id-mod-kea-profile-88", "id-mod-kea-profile-88", + NID_id_mod_kea_profile_88, 8, &kObjectData[1993], 0}, + {"id-mod-kea-profile-93", "id-mod-kea-profile-93", + NID_id_mod_kea_profile_93, 8, &kObjectData[2001], 0}, + {"id-mod-cmp", "id-mod-cmp", NID_id_mod_cmp, 8, &kObjectData[2009], 0}, + {"id-mod-qualified-cert-88", "id-mod-qualified-cert-88", + NID_id_mod_qualified_cert_88, 8, &kObjectData[2017], 0}, + {"id-mod-qualified-cert-93", "id-mod-qualified-cert-93", + NID_id_mod_qualified_cert_93, 8, &kObjectData[2025], 0}, + {"id-mod-attribute-cert", "id-mod-attribute-cert", + NID_id_mod_attribute_cert, 8, &kObjectData[2033], 0}, + {"id-mod-timestamp-protocol", "id-mod-timestamp-protocol", + NID_id_mod_timestamp_protocol, 8, &kObjectData[2041], 0}, + {"id-mod-ocsp", "id-mod-ocsp", NID_id_mod_ocsp, 8, &kObjectData[2049], 0}, + {"id-mod-dvcs", "id-mod-dvcs", NID_id_mod_dvcs, 8, &kObjectData[2057], 0}, + {"id-mod-cmp2000", "id-mod-cmp2000", NID_id_mod_cmp2000, 8, + &kObjectData[2065], 0}, + {"biometricInfo", "Biometric Info", NID_biometricInfo, 8, + &kObjectData[2073], 0}, + {"qcStatements", "qcStatements", NID_qcStatements, 8, &kObjectData[2081], + 0}, + {"ac-auditEntity", "ac-auditEntity", NID_ac_auditEntity, 8, + &kObjectData[2089], 0}, + {"ac-targeting", "ac-targeting", NID_ac_targeting, 8, &kObjectData[2097], + 0}, + {"aaControls", "aaControls", NID_aaControls, 8, &kObjectData[2105], 0}, + {"sbgp-ipAddrBlock", "sbgp-ipAddrBlock", NID_sbgp_ipAddrBlock, 8, + &kObjectData[2113], 0}, + {"sbgp-autonomousSysNum", "sbgp-autonomousSysNum", + NID_sbgp_autonomousSysNum, 8, &kObjectData[2121], 0}, + {"sbgp-routerIdentifier", "sbgp-routerIdentifier", + NID_sbgp_routerIdentifier, 8, &kObjectData[2129], 0}, + {"textNotice", "textNotice", NID_textNotice, 8, &kObjectData[2137], 0}, + {"ipsecEndSystem", "IPSec End System", NID_ipsecEndSystem, 8, + &kObjectData[2145], 0}, + {"ipsecTunnel", "IPSec Tunnel", NID_ipsecTunnel, 8, &kObjectData[2153], 0}, + {"ipsecUser", "IPSec User", NID_ipsecUser, 8, &kObjectData[2161], 0}, + {"DVCS", "dvcs", NID_dvcs, 8, &kObjectData[2169], 0}, + {"id-it-caProtEncCert", "id-it-caProtEncCert", NID_id_it_caProtEncCert, 8, + &kObjectData[2177], 0}, + {"id-it-signKeyPairTypes", "id-it-signKeyPairTypes", + NID_id_it_signKeyPairTypes, 8, &kObjectData[2185], 0}, + {"id-it-encKeyPairTypes", "id-it-encKeyPairTypes", + NID_id_it_encKeyPairTypes, 8, &kObjectData[2193], 0}, + {"id-it-preferredSymmAlg", "id-it-preferredSymmAlg", + NID_id_it_preferredSymmAlg, 8, &kObjectData[2201], 0}, + {"id-it-caKeyUpdateInfo", "id-it-caKeyUpdateInfo", + NID_id_it_caKeyUpdateInfo, 8, &kObjectData[2209], 0}, + {"id-it-currentCRL", "id-it-currentCRL", NID_id_it_currentCRL, 8, + &kObjectData[2217], 0}, + {"id-it-unsupportedOIDs", "id-it-unsupportedOIDs", + NID_id_it_unsupportedOIDs, 8, &kObjectData[2225], 0}, + {"id-it-subscriptionRequest", "id-it-subscriptionRequest", + NID_id_it_subscriptionRequest, 8, &kObjectData[2233], 0}, + {"id-it-subscriptionResponse", "id-it-subscriptionResponse", + NID_id_it_subscriptionResponse, 8, &kObjectData[2241], 0}, + {"id-it-keyPairParamReq", "id-it-keyPairParamReq", + NID_id_it_keyPairParamReq, 8, &kObjectData[2249], 0}, + {"id-it-keyPairParamRep", "id-it-keyPairParamRep", + NID_id_it_keyPairParamRep, 8, &kObjectData[2257], 0}, + {"id-it-revPassphrase", "id-it-revPassphrase", NID_id_it_revPassphrase, 8, + &kObjectData[2265], 0}, + {"id-it-implicitConfirm", "id-it-implicitConfirm", + NID_id_it_implicitConfirm, 8, &kObjectData[2273], 0}, + {"id-it-confirmWaitTime", "id-it-confirmWaitTime", + NID_id_it_confirmWaitTime, 8, &kObjectData[2281], 0}, + {"id-it-origPKIMessage", "id-it-origPKIMessage", NID_id_it_origPKIMessage, + 8, &kObjectData[2289], 0}, + {"id-regCtrl", "id-regCtrl", NID_id_regCtrl, 8, &kObjectData[2297], 0}, + {"id-regInfo", "id-regInfo", NID_id_regInfo, 8, &kObjectData[2305], 0}, + {"id-regCtrl-regToken", "id-regCtrl-regToken", NID_id_regCtrl_regToken, 9, + &kObjectData[2313], 0}, + {"id-regCtrl-authenticator", "id-regCtrl-authenticator", + NID_id_regCtrl_authenticator, 9, &kObjectData[2322], 0}, + {"id-regCtrl-pkiPublicationInfo", "id-regCtrl-pkiPublicationInfo", + NID_id_regCtrl_pkiPublicationInfo, 9, &kObjectData[2331], 0}, + {"id-regCtrl-pkiArchiveOptions", "id-regCtrl-pkiArchiveOptions", + NID_id_regCtrl_pkiArchiveOptions, 9, &kObjectData[2340], 0}, + {"id-regCtrl-oldCertID", "id-regCtrl-oldCertID", NID_id_regCtrl_oldCertID, + 9, &kObjectData[2349], 0}, + {"id-regCtrl-protocolEncrKey", "id-regCtrl-protocolEncrKey", + NID_id_regCtrl_protocolEncrKey, 9, &kObjectData[2358], 0}, + {"id-regInfo-utf8Pairs", "id-regInfo-utf8Pairs", NID_id_regInfo_utf8Pairs, + 9, &kObjectData[2367], 0}, + {"id-regInfo-certReq", "id-regInfo-certReq", NID_id_regInfo_certReq, 9, + &kObjectData[2376], 0}, + {"id-alg-des40", "id-alg-des40", NID_id_alg_des40, 8, &kObjectData[2385], + 0}, + {"id-alg-noSignature", "id-alg-noSignature", NID_id_alg_noSignature, 8, + &kObjectData[2393], 0}, + {"id-alg-dh-sig-hmac-sha1", "id-alg-dh-sig-hmac-sha1", + NID_id_alg_dh_sig_hmac_sha1, 8, &kObjectData[2401], 0}, + {"id-alg-dh-pop", "id-alg-dh-pop", NID_id_alg_dh_pop, 8, &kObjectData[2409], + 0}, + {"id-cmc-statusInfo", "id-cmc-statusInfo", NID_id_cmc_statusInfo, 8, + &kObjectData[2417], 0}, + {"id-cmc-identification", "id-cmc-identification", + NID_id_cmc_identification, 8, &kObjectData[2425], 0}, + {"id-cmc-identityProof", "id-cmc-identityProof", NID_id_cmc_identityProof, + 8, &kObjectData[2433], 0}, + {"id-cmc-dataReturn", "id-cmc-dataReturn", NID_id_cmc_dataReturn, 8, + &kObjectData[2441], 0}, + {"id-cmc-transactionId", "id-cmc-transactionId", NID_id_cmc_transactionId, + 8, &kObjectData[2449], 0}, + {"id-cmc-senderNonce", "id-cmc-senderNonce", NID_id_cmc_senderNonce, 8, + &kObjectData[2457], 0}, + {"id-cmc-recipientNonce", "id-cmc-recipientNonce", + NID_id_cmc_recipientNonce, 8, &kObjectData[2465], 0}, + {"id-cmc-addExtensions", "id-cmc-addExtensions", NID_id_cmc_addExtensions, + 8, &kObjectData[2473], 0}, + {"id-cmc-encryptedPOP", "id-cmc-encryptedPOP", NID_id_cmc_encryptedPOP, 8, + &kObjectData[2481], 0}, + {"id-cmc-decryptedPOP", "id-cmc-decryptedPOP", NID_id_cmc_decryptedPOP, 8, + &kObjectData[2489], 0}, + {"id-cmc-lraPOPWitness", "id-cmc-lraPOPWitness", NID_id_cmc_lraPOPWitness, + 8, &kObjectData[2497], 0}, + {"id-cmc-getCert", "id-cmc-getCert", NID_id_cmc_getCert, 8, + &kObjectData[2505], 0}, + {"id-cmc-getCRL", "id-cmc-getCRL", NID_id_cmc_getCRL, 8, &kObjectData[2513], + 0}, + {"id-cmc-revokeRequest", "id-cmc-revokeRequest", NID_id_cmc_revokeRequest, + 8, &kObjectData[2521], 0}, + {"id-cmc-regInfo", "id-cmc-regInfo", NID_id_cmc_regInfo, 8, + &kObjectData[2529], 0}, + {"id-cmc-responseInfo", "id-cmc-responseInfo", NID_id_cmc_responseInfo, 8, + &kObjectData[2537], 0}, + {"id-cmc-queryPending", "id-cmc-queryPending", NID_id_cmc_queryPending, 8, + &kObjectData[2545], 0}, + {"id-cmc-popLinkRandom", "id-cmc-popLinkRandom", NID_id_cmc_popLinkRandom, + 8, &kObjectData[2553], 0}, + {"id-cmc-popLinkWitness", "id-cmc-popLinkWitness", + NID_id_cmc_popLinkWitness, 8, &kObjectData[2561], 0}, + {"id-cmc-confirmCertAcceptance", "id-cmc-confirmCertAcceptance", + NID_id_cmc_confirmCertAcceptance, 8, &kObjectData[2569], 0}, + {"id-on-personalData", "id-on-personalData", NID_id_on_personalData, 8, + &kObjectData[2577], 0}, + {"id-pda-dateOfBirth", "id-pda-dateOfBirth", NID_id_pda_dateOfBirth, 8, + &kObjectData[2585], 0}, + {"id-pda-placeOfBirth", "id-pda-placeOfBirth", NID_id_pda_placeOfBirth, 8, + &kObjectData[2593], 0}, + {NULL, NULL, NID_undef, 0, NULL, 0}, + {"id-pda-gender", "id-pda-gender", NID_id_pda_gender, 8, &kObjectData[2601], + 0}, + {"id-pda-countryOfCitizenship", "id-pda-countryOfCitizenship", + NID_id_pda_countryOfCitizenship, 8, &kObjectData[2609], 0}, + {"id-pda-countryOfResidence", "id-pda-countryOfResidence", + NID_id_pda_countryOfResidence, 8, &kObjectData[2617], 0}, + {"id-aca-authenticationInfo", "id-aca-authenticationInfo", + NID_id_aca_authenticationInfo, 8, &kObjectData[2625], 0}, + {"id-aca-accessIdentity", "id-aca-accessIdentity", + NID_id_aca_accessIdentity, 8, &kObjectData[2633], 0}, + {"id-aca-chargingIdentity", "id-aca-chargingIdentity", + NID_id_aca_chargingIdentity, 8, &kObjectData[2641], 0}, + {"id-aca-group", "id-aca-group", NID_id_aca_group, 8, &kObjectData[2649], + 0}, + {"id-aca-role", "id-aca-role", NID_id_aca_role, 8, &kObjectData[2657], 0}, + {"id-qcs-pkixQCSyntax-v1", "id-qcs-pkixQCSyntax-v1", + NID_id_qcs_pkixQCSyntax_v1, 8, &kObjectData[2665], 0}, + {"id-cct-crs", "id-cct-crs", NID_id_cct_crs, 8, &kObjectData[2673], 0}, + {"id-cct-PKIData", "id-cct-PKIData", NID_id_cct_PKIData, 8, + &kObjectData[2681], 0}, + {"id-cct-PKIResponse", "id-cct-PKIResponse", NID_id_cct_PKIResponse, 8, + &kObjectData[2689], 0}, + {"ad_timestamping", "AD Time Stamping", NID_ad_timeStamping, 8, + &kObjectData[2697], 0}, + {"AD_DVCS", "ad dvcs", NID_ad_dvcs, 8, &kObjectData[2705], 0}, + {"basicOCSPResponse", "Basic OCSP Response", NID_id_pkix_OCSP_basic, 9, + &kObjectData[2713], 0}, + {"Nonce", "OCSP Nonce", NID_id_pkix_OCSP_Nonce, 9, &kObjectData[2722], 0}, + {"CrlID", "OCSP CRL ID", NID_id_pkix_OCSP_CrlID, 9, &kObjectData[2731], 0}, + {"acceptableResponses", "Acceptable OCSP Responses", + NID_id_pkix_OCSP_acceptableResponses, 9, &kObjectData[2740], 0}, + {"noCheck", "OCSP No Check", NID_id_pkix_OCSP_noCheck, 9, + &kObjectData[2749], 0}, + {"archiveCutoff", "OCSP Archive Cutoff", NID_id_pkix_OCSP_archiveCutoff, 9, + &kObjectData[2758], 0}, + {"serviceLocator", "OCSP Service Locator", NID_id_pkix_OCSP_serviceLocator, + 9, &kObjectData[2767], 0}, + {"extendedStatus", "Extended OCSP Status", NID_id_pkix_OCSP_extendedStatus, + 9, &kObjectData[2776], 0}, + {"valid", "valid", NID_id_pkix_OCSP_valid, 9, &kObjectData[2785], 0}, + {"path", "path", NID_id_pkix_OCSP_path, 9, &kObjectData[2794], 0}, + {"trustRoot", "Trust Root", NID_id_pkix_OCSP_trustRoot, 9, + &kObjectData[2803], 0}, + {"algorithm", "algorithm", NID_algorithm, 4, &kObjectData[2812], 0}, + {"rsaSignature", "rsaSignature", NID_rsaSignature, 5, &kObjectData[2816], + 0}, + {"X500algorithms", "directory services - algorithms", NID_X500algorithms, 2, + &kObjectData[2821], 0}, + {"ORG", "org", NID_org, 1, &kObjectData[2823], 0}, + {"DOD", "dod", NID_dod, 2, &kObjectData[2824], 0}, + {"IANA", "iana", NID_iana, 3, &kObjectData[2826], 0}, + {"directory", "Directory", NID_Directory, 4, &kObjectData[2829], 0}, + {"mgmt", "Management", NID_Management, 4, &kObjectData[2833], 0}, + {"experimental", "Experimental", NID_Experimental, 4, &kObjectData[2837], + 0}, + {"private", "Private", NID_Private, 4, &kObjectData[2841], 0}, + {"security", "Security", NID_Security, 4, &kObjectData[2845], 0}, + {"snmpv2", "SNMPv2", NID_SNMPv2, 4, &kObjectData[2849], 0}, + {"Mail", "Mail", NID_Mail, 4, &kObjectData[2853], 0}, + {"enterprises", "Enterprises", NID_Enterprises, 5, &kObjectData[2857], 0}, + {"dcobject", "dcObject", NID_dcObject, 9, &kObjectData[2862], 0}, + {"DC", "domainComponent", NID_domainComponent, 10, &kObjectData[2871], 0}, + {"domain", "Domain", NID_Domain, 10, &kObjectData[2881], 0}, + {NULL, NULL, NID_undef, 0, NULL, 0}, + {"selected-attribute-types", "Selected Attribute Types", + NID_selected_attribute_types, 3, &kObjectData[2891], 0}, + {"clearance", "clearance", NID_clearance, 4, &kObjectData[2894], 0}, + {"RSA-MD4", "md4WithRSAEncryption", NID_md4WithRSAEncryption, 9, + &kObjectData[2898], 0}, + {"ac-proxying", "ac-proxying", NID_ac_proxying, 8, &kObjectData[2907], 0}, + {"subjectInfoAccess", "Subject Information Access", NID_sinfo_access, 8, + &kObjectData[2915], 0}, + {"id-aca-encAttrs", "id-aca-encAttrs", NID_id_aca_encAttrs, 8, + &kObjectData[2923], 0}, + {"role", "role", NID_role, 3, &kObjectData[2931], 0}, + {"policyConstraints", "X509v3 Policy Constraints", NID_policy_constraints, + 3, &kObjectData[2934], 0}, + {"targetInformation", "X509v3 AC Targeting", NID_target_information, 3, + &kObjectData[2937], 0}, + {"noRevAvail", "X509v3 No Revocation Available", NID_no_rev_avail, 3, + &kObjectData[2940], 0}, + {NULL, NULL, NID_undef, 0, NULL, 0}, + {"ansi-X9-62", "ANSI X9.62", NID_ansi_X9_62, 5, &kObjectData[2943], 0}, + {"prime-field", "prime-field", NID_X9_62_prime_field, 7, &kObjectData[2948], + 0}, + {"characteristic-two-field", "characteristic-two-field", + NID_X9_62_characteristic_two_field, 7, &kObjectData[2955], 0}, + {"id-ecPublicKey", "id-ecPublicKey", NID_X9_62_id_ecPublicKey, 7, + &kObjectData[2962], 0}, + {"prime192v1", "prime192v1", NID_X9_62_prime192v1, 8, &kObjectData[2969], + 0}, + {"prime192v2", "prime192v2", NID_X9_62_prime192v2, 8, &kObjectData[2977], + 0}, + {"prime192v3", "prime192v3", NID_X9_62_prime192v3, 8, &kObjectData[2985], + 0}, + {"prime239v1", "prime239v1", NID_X9_62_prime239v1, 8, &kObjectData[2993], + 0}, + {"prime239v2", "prime239v2", NID_X9_62_prime239v2, 8, &kObjectData[3001], + 0}, + {"prime239v3", "prime239v3", NID_X9_62_prime239v3, 8, &kObjectData[3009], + 0}, + {"prime256v1", "prime256v1", NID_X9_62_prime256v1, 8, &kObjectData[3017], + 0}, + {"ecdsa-with-SHA1", "ecdsa-with-SHA1", NID_ecdsa_with_SHA1, 7, + &kObjectData[3025], 0}, + {"CSPName", "Microsoft CSP Name", NID_ms_csp_name, 9, &kObjectData[3032], + 0}, + {"AES-128-ECB", "aes-128-ecb", NID_aes_128_ecb, 9, &kObjectData[3041], 0}, + {"AES-128-CBC", "aes-128-cbc", NID_aes_128_cbc, 9, &kObjectData[3050], 0}, + {"AES-128-OFB", "aes-128-ofb", NID_aes_128_ofb128, 9, &kObjectData[3059], + 0}, + {"AES-128-CFB", "aes-128-cfb", NID_aes_128_cfb128, 9, &kObjectData[3068], + 0}, + {"AES-192-ECB", "aes-192-ecb", NID_aes_192_ecb, 9, &kObjectData[3077], 0}, + {"AES-192-CBC", "aes-192-cbc", NID_aes_192_cbc, 9, &kObjectData[3086], 0}, + {"AES-192-OFB", "aes-192-ofb", NID_aes_192_ofb128, 9, &kObjectData[3095], + 0}, + {"AES-192-CFB", "aes-192-cfb", NID_aes_192_cfb128, 9, &kObjectData[3104], + 0}, + {"AES-256-ECB", "aes-256-ecb", NID_aes_256_ecb, 9, &kObjectData[3113], 0}, + {"AES-256-CBC", "aes-256-cbc", NID_aes_256_cbc, 9, &kObjectData[3122], 0}, + {"AES-256-OFB", "aes-256-ofb", NID_aes_256_ofb128, 9, &kObjectData[3131], + 0}, + {"AES-256-CFB", "aes-256-cfb", NID_aes_256_cfb128, 9, &kObjectData[3140], + 0}, + {"holdInstructionCode", "Hold Instruction Code", NID_hold_instruction_code, + 3, &kObjectData[3149], 0}, + {"holdInstructionNone", "Hold Instruction None", NID_hold_instruction_none, + 7, &kObjectData[3152], 0}, + {"holdInstructionCallIssuer", "Hold Instruction Call Issuer", + NID_hold_instruction_call_issuer, 7, &kObjectData[3159], 0}, + {"holdInstructionReject", "Hold Instruction Reject", + NID_hold_instruction_reject, 7, &kObjectData[3166], 0}, + {"data", "data", NID_data, 1, &kObjectData[3173], 0}, + {"pss", "pss", NID_pss, 3, &kObjectData[3174], 0}, + {"ucl", "ucl", NID_ucl, 7, &kObjectData[3177], 0}, + {"pilot", "pilot", NID_pilot, 8, &kObjectData[3184], 0}, + {"pilotAttributeType", "pilotAttributeType", NID_pilotAttributeType, 9, + &kObjectData[3192], 0}, + {"pilotAttributeSyntax", "pilotAttributeSyntax", NID_pilotAttributeSyntax, + 9, &kObjectData[3201], 0}, + {"pilotObjectClass", "pilotObjectClass", NID_pilotObjectClass, 9, + &kObjectData[3210], 0}, + {"pilotGroups", "pilotGroups", NID_pilotGroups, 9, &kObjectData[3219], 0}, + {"iA5StringSyntax", "iA5StringSyntax", NID_iA5StringSyntax, 10, + &kObjectData[3228], 0}, + {"caseIgnoreIA5StringSyntax", "caseIgnoreIA5StringSyntax", + NID_caseIgnoreIA5StringSyntax, 10, &kObjectData[3238], 0}, + {"pilotObject", "pilotObject", NID_pilotObject, 10, &kObjectData[3248], 0}, + {"pilotPerson", "pilotPerson", NID_pilotPerson, 10, &kObjectData[3258], 0}, + {"account", "account", NID_account, 10, &kObjectData[3268], 0}, + {"document", "document", NID_document, 10, &kObjectData[3278], 0}, + {"room", "room", NID_room, 10, &kObjectData[3288], 0}, + {"documentSeries", "documentSeries", NID_documentSeries, 10, + &kObjectData[3298], 0}, + {"rFC822localPart", "rFC822localPart", NID_rFC822localPart, 10, + &kObjectData[3308], 0}, + {"dNSDomain", "dNSDomain", NID_dNSDomain, 10, &kObjectData[3318], 0}, + {"domainRelatedObject", "domainRelatedObject", NID_domainRelatedObject, 10, + &kObjectData[3328], 0}, + {"friendlyCountry", "friendlyCountry", NID_friendlyCountry, 10, + &kObjectData[3338], 0}, + {"simpleSecurityObject", "simpleSecurityObject", NID_simpleSecurityObject, + 10, &kObjectData[3348], 0}, + {"pilotOrganization", "pilotOrganization", NID_pilotOrganization, 10, + &kObjectData[3358], 0}, + {"pilotDSA", "pilotDSA", NID_pilotDSA, 10, &kObjectData[3368], 0}, + {"qualityLabelledData", "qualityLabelledData", NID_qualityLabelledData, 10, + &kObjectData[3378], 0}, + {"UID", "userId", NID_userId, 10, &kObjectData[3388], 0}, + {"textEncodedORAddress", "textEncodedORAddress", NID_textEncodedORAddress, + 10, &kObjectData[3398], 0}, + {"mail", "rfc822Mailbox", NID_rfc822Mailbox, 10, &kObjectData[3408], 0}, + {"info", "info", NID_info, 10, &kObjectData[3418], 0}, + {"favouriteDrink", "favouriteDrink", NID_favouriteDrink, 10, + &kObjectData[3428], 0}, + {"roomNumber", "roomNumber", NID_roomNumber, 10, &kObjectData[3438], 0}, + {"photo", "photo", NID_photo, 10, &kObjectData[3448], 0}, + {"userClass", "userClass", NID_userClass, 10, &kObjectData[3458], 0}, + {"host", "host", NID_host, 10, &kObjectData[3468], 0}, + {"manager", "manager", NID_manager, 10, &kObjectData[3478], 0}, + {"documentIdentifier", "documentIdentifier", NID_documentIdentifier, 10, + &kObjectData[3488], 0}, + {"documentTitle", "documentTitle", NID_documentTitle, 10, + &kObjectData[3498], 0}, + {"documentVersion", "documentVersion", NID_documentVersion, 10, + &kObjectData[3508], 0}, + {"documentAuthor", "documentAuthor", NID_documentAuthor, 10, + &kObjectData[3518], 0}, + {"documentLocation", "documentLocation", NID_documentLocation, 10, + &kObjectData[3528], 0}, + {"homeTelephoneNumber", "homeTelephoneNumber", NID_homeTelephoneNumber, 10, + &kObjectData[3538], 0}, + {"secretary", "secretary", NID_secretary, 10, &kObjectData[3548], 0}, + {"otherMailbox", "otherMailbox", NID_otherMailbox, 10, &kObjectData[3558], + 0}, + {"lastModifiedTime", "lastModifiedTime", NID_lastModifiedTime, 10, + &kObjectData[3568], 0}, + {"lastModifiedBy", "lastModifiedBy", NID_lastModifiedBy, 10, + &kObjectData[3578], 0}, + {"aRecord", "aRecord", NID_aRecord, 10, &kObjectData[3588], 0}, + {"pilotAttributeType27", "pilotAttributeType27", NID_pilotAttributeType27, + 10, &kObjectData[3598], 0}, + {"mXRecord", "mXRecord", NID_mXRecord, 10, &kObjectData[3608], 0}, + {"nSRecord", "nSRecord", NID_nSRecord, 10, &kObjectData[3618], 0}, + {"sOARecord", "sOARecord", NID_sOARecord, 10, &kObjectData[3628], 0}, + {"cNAMERecord", "cNAMERecord", NID_cNAMERecord, 10, &kObjectData[3638], 0}, + {"associatedDomain", "associatedDomain", NID_associatedDomain, 10, + &kObjectData[3648], 0}, + {"associatedName", "associatedName", NID_associatedName, 10, + &kObjectData[3658], 0}, + {"homePostalAddress", "homePostalAddress", NID_homePostalAddress, 10, + &kObjectData[3668], 0}, + {"personalTitle", "personalTitle", NID_personalTitle, 10, + &kObjectData[3678], 0}, + {"mobileTelephoneNumber", "mobileTelephoneNumber", + NID_mobileTelephoneNumber, 10, &kObjectData[3688], 0}, + {"pagerTelephoneNumber", "pagerTelephoneNumber", NID_pagerTelephoneNumber, + 10, &kObjectData[3698], 0}, + {"friendlyCountryName", "friendlyCountryName", NID_friendlyCountryName, 10, + &kObjectData[3708], 0}, + {"organizationalStatus", "organizationalStatus", NID_organizationalStatus, + 10, &kObjectData[3718], 0}, + {"janetMailbox", "janetMailbox", NID_janetMailbox, 10, &kObjectData[3728], + 0}, + {"mailPreferenceOption", "mailPreferenceOption", NID_mailPreferenceOption, + 10, &kObjectData[3738], 0}, + {"buildingName", "buildingName", NID_buildingName, 10, &kObjectData[3748], + 0}, + {"dSAQuality", "dSAQuality", NID_dSAQuality, 10, &kObjectData[3758], 0}, + {"singleLevelQuality", "singleLevelQuality", NID_singleLevelQuality, 10, + &kObjectData[3768], 0}, + {"subtreeMinimumQuality", "subtreeMinimumQuality", + NID_subtreeMinimumQuality, 10, &kObjectData[3778], 0}, + {"subtreeMaximumQuality", "subtreeMaximumQuality", + NID_subtreeMaximumQuality, 10, &kObjectData[3788], 0}, + {"personalSignature", "personalSignature", NID_personalSignature, 10, + &kObjectData[3798], 0}, + {"dITRedirect", "dITRedirect", NID_dITRedirect, 10, &kObjectData[3808], 0}, + {"audio", "audio", NID_audio, 10, &kObjectData[3818], 0}, + {"documentPublisher", "documentPublisher", NID_documentPublisher, 10, + &kObjectData[3828], 0}, + {"x500UniqueIdentifier", "x500UniqueIdentifier", NID_x500UniqueIdentifier, + 3, &kObjectData[3838], 0}, + {"mime-mhs", "MIME MHS", NID_mime_mhs, 5, &kObjectData[3841], 0}, + {"mime-mhs-headings", "mime-mhs-headings", NID_mime_mhs_headings, 6, + &kObjectData[3846], 0}, + {"mime-mhs-bodies", "mime-mhs-bodies", NID_mime_mhs_bodies, 6, + &kObjectData[3852], 0}, + {"id-hex-partial-message", "id-hex-partial-message", + NID_id_hex_partial_message, 7, &kObjectData[3858], 0}, + {"id-hex-multipart-message", "id-hex-multipart-message", + NID_id_hex_multipart_message, 7, &kObjectData[3865], 0}, + {"generationQualifier", "generationQualifier", NID_generationQualifier, 3, + &kObjectData[3872], 0}, + {"pseudonym", "pseudonym", NID_pseudonym, 3, &kObjectData[3875], 0}, + {NULL, NULL, NID_undef, 0, NULL, 0}, + {"id-set", "Secure Electronic Transactions", NID_id_set, 2, + &kObjectData[3878], 0}, + {"set-ctype", "content types", NID_set_ctype, 3, &kObjectData[3880], 0}, + {"set-msgExt", "message extensions", NID_set_msgExt, 3, &kObjectData[3883], + 0}, + {"set-attr", "set-attr", NID_set_attr, 3, &kObjectData[3886], 0}, + {"set-policy", "set-policy", NID_set_policy, 3, &kObjectData[3889], 0}, + {"set-certExt", "certificate extensions", NID_set_certExt, 3, + &kObjectData[3892], 0}, + {"set-brand", "set-brand", NID_set_brand, 3, &kObjectData[3895], 0}, + {"setct-PANData", "setct-PANData", NID_setct_PANData, 4, &kObjectData[3898], + 0}, + {"setct-PANToken", "setct-PANToken", NID_setct_PANToken, 4, + &kObjectData[3902], 0}, + {"setct-PANOnly", "setct-PANOnly", NID_setct_PANOnly, 4, &kObjectData[3906], + 0}, + {"setct-OIData", "setct-OIData", NID_setct_OIData, 4, &kObjectData[3910], + 0}, + {"setct-PI", "setct-PI", NID_setct_PI, 4, &kObjectData[3914], 0}, + {"setct-PIData", "setct-PIData", NID_setct_PIData, 4, &kObjectData[3918], + 0}, + {"setct-PIDataUnsigned", "setct-PIDataUnsigned", NID_setct_PIDataUnsigned, + 4, &kObjectData[3922], 0}, + {"setct-HODInput", "setct-HODInput", NID_setct_HODInput, 4, + &kObjectData[3926], 0}, + {"setct-AuthResBaggage", "setct-AuthResBaggage", NID_setct_AuthResBaggage, + 4, &kObjectData[3930], 0}, + {"setct-AuthRevReqBaggage", "setct-AuthRevReqBaggage", + NID_setct_AuthRevReqBaggage, 4, &kObjectData[3934], 0}, + {"setct-AuthRevResBaggage", "setct-AuthRevResBaggage", + NID_setct_AuthRevResBaggage, 4, &kObjectData[3938], 0}, + {"setct-CapTokenSeq", "setct-CapTokenSeq", NID_setct_CapTokenSeq, 4, + &kObjectData[3942], 0}, + {"setct-PInitResData", "setct-PInitResData", NID_setct_PInitResData, 4, + &kObjectData[3946], 0}, + {"setct-PI-TBS", "setct-PI-TBS", NID_setct_PI_TBS, 4, &kObjectData[3950], + 0}, + {"setct-PResData", "setct-PResData", NID_setct_PResData, 4, + &kObjectData[3954], 0}, + {"setct-AuthReqTBS", "setct-AuthReqTBS", NID_setct_AuthReqTBS, 4, + &kObjectData[3958], 0}, + {"setct-AuthResTBS", "setct-AuthResTBS", NID_setct_AuthResTBS, 4, + &kObjectData[3962], 0}, + {"setct-AuthResTBSX", "setct-AuthResTBSX", NID_setct_AuthResTBSX, 4, + &kObjectData[3966], 0}, + {"setct-AuthTokenTBS", "setct-AuthTokenTBS", NID_setct_AuthTokenTBS, 4, + &kObjectData[3970], 0}, + {"setct-CapTokenData", "setct-CapTokenData", NID_setct_CapTokenData, 4, + &kObjectData[3974], 0}, + {"setct-CapTokenTBS", "setct-CapTokenTBS", NID_setct_CapTokenTBS, 4, + &kObjectData[3978], 0}, + {"setct-AcqCardCodeMsg", "setct-AcqCardCodeMsg", NID_setct_AcqCardCodeMsg, + 4, &kObjectData[3982], 0}, + {"setct-AuthRevReqTBS", "setct-AuthRevReqTBS", NID_setct_AuthRevReqTBS, 4, + &kObjectData[3986], 0}, + {"setct-AuthRevResData", "setct-AuthRevResData", NID_setct_AuthRevResData, + 4, &kObjectData[3990], 0}, + {"setct-AuthRevResTBS", "setct-AuthRevResTBS", NID_setct_AuthRevResTBS, 4, + &kObjectData[3994], 0}, + {"setct-CapReqTBS", "setct-CapReqTBS", NID_setct_CapReqTBS, 4, + &kObjectData[3998], 0}, + {"setct-CapReqTBSX", "setct-CapReqTBSX", NID_setct_CapReqTBSX, 4, + &kObjectData[4002], 0}, + {"setct-CapResData", "setct-CapResData", NID_setct_CapResData, 4, + &kObjectData[4006], 0}, + {"setct-CapRevReqTBS", "setct-CapRevReqTBS", NID_setct_CapRevReqTBS, 4, + &kObjectData[4010], 0}, + {"setct-CapRevReqTBSX", "setct-CapRevReqTBSX", NID_setct_CapRevReqTBSX, 4, + &kObjectData[4014], 0}, + {"setct-CapRevResData", "setct-CapRevResData", NID_setct_CapRevResData, 4, + &kObjectData[4018], 0}, + {"setct-CredReqTBS", "setct-CredReqTBS", NID_setct_CredReqTBS, 4, + &kObjectData[4022], 0}, + {"setct-CredReqTBSX", "setct-CredReqTBSX", NID_setct_CredReqTBSX, 4, + &kObjectData[4026], 0}, + {"setct-CredResData", "setct-CredResData", NID_setct_CredResData, 4, + &kObjectData[4030], 0}, + {"setct-CredRevReqTBS", "setct-CredRevReqTBS", NID_setct_CredRevReqTBS, 4, + &kObjectData[4034], 0}, + {"setct-CredRevReqTBSX", "setct-CredRevReqTBSX", NID_setct_CredRevReqTBSX, + 4, &kObjectData[4038], 0}, + {"setct-CredRevResData", "setct-CredRevResData", NID_setct_CredRevResData, + 4, &kObjectData[4042], 0}, + {"setct-PCertReqData", "setct-PCertReqData", NID_setct_PCertReqData, 4, + &kObjectData[4046], 0}, + {"setct-PCertResTBS", "setct-PCertResTBS", NID_setct_PCertResTBS, 4, + &kObjectData[4050], 0}, + {"setct-BatchAdminReqData", "setct-BatchAdminReqData", + NID_setct_BatchAdminReqData, 4, &kObjectData[4054], 0}, + {"setct-BatchAdminResData", "setct-BatchAdminResData", + NID_setct_BatchAdminResData, 4, &kObjectData[4058], 0}, + {"setct-CardCInitResTBS", "setct-CardCInitResTBS", + NID_setct_CardCInitResTBS, 4, &kObjectData[4062], 0}, + {"setct-MeAqCInitResTBS", "setct-MeAqCInitResTBS", + NID_setct_MeAqCInitResTBS, 4, &kObjectData[4066], 0}, + {"setct-RegFormResTBS", "setct-RegFormResTBS", NID_setct_RegFormResTBS, 4, + &kObjectData[4070], 0}, + {"setct-CertReqData", "setct-CertReqData", NID_setct_CertReqData, 4, + &kObjectData[4074], 0}, + {"setct-CertReqTBS", "setct-CertReqTBS", NID_setct_CertReqTBS, 4, + &kObjectData[4078], 0}, + {"setct-CertResData", "setct-CertResData", NID_setct_CertResData, 4, + &kObjectData[4082], 0}, + {"setct-CertInqReqTBS", "setct-CertInqReqTBS", NID_setct_CertInqReqTBS, 4, + &kObjectData[4086], 0}, + {"setct-ErrorTBS", "setct-ErrorTBS", NID_setct_ErrorTBS, 4, + &kObjectData[4090], 0}, + {"setct-PIDualSignedTBE", "setct-PIDualSignedTBE", + NID_setct_PIDualSignedTBE, 4, &kObjectData[4094], 0}, + {"setct-PIUnsignedTBE", "setct-PIUnsignedTBE", NID_setct_PIUnsignedTBE, 4, + &kObjectData[4098], 0}, + {"setct-AuthReqTBE", "setct-AuthReqTBE", NID_setct_AuthReqTBE, 4, + &kObjectData[4102], 0}, + {"setct-AuthResTBE", "setct-AuthResTBE", NID_setct_AuthResTBE, 4, + &kObjectData[4106], 0}, + {"setct-AuthResTBEX", "setct-AuthResTBEX", NID_setct_AuthResTBEX, 4, + &kObjectData[4110], 0}, + {"setct-AuthTokenTBE", "setct-AuthTokenTBE", NID_setct_AuthTokenTBE, 4, + &kObjectData[4114], 0}, + {"setct-CapTokenTBE", "setct-CapTokenTBE", NID_setct_CapTokenTBE, 4, + &kObjectData[4118], 0}, + {"setct-CapTokenTBEX", "setct-CapTokenTBEX", NID_setct_CapTokenTBEX, 4, + &kObjectData[4122], 0}, + {"setct-AcqCardCodeMsgTBE", "setct-AcqCardCodeMsgTBE", + NID_setct_AcqCardCodeMsgTBE, 4, &kObjectData[4126], 0}, + {"setct-AuthRevReqTBE", "setct-AuthRevReqTBE", NID_setct_AuthRevReqTBE, 4, + &kObjectData[4130], 0}, + {"setct-AuthRevResTBE", "setct-AuthRevResTBE", NID_setct_AuthRevResTBE, 4, + &kObjectData[4134], 0}, + {"setct-AuthRevResTBEB", "setct-AuthRevResTBEB", NID_setct_AuthRevResTBEB, + 4, &kObjectData[4138], 0}, + {"setct-CapReqTBE", "setct-CapReqTBE", NID_setct_CapReqTBE, 4, + &kObjectData[4142], 0}, + {"setct-CapReqTBEX", "setct-CapReqTBEX", NID_setct_CapReqTBEX, 4, + &kObjectData[4146], 0}, + {"setct-CapResTBE", "setct-CapResTBE", NID_setct_CapResTBE, 4, + &kObjectData[4150], 0}, + {"setct-CapRevReqTBE", "setct-CapRevReqTBE", NID_setct_CapRevReqTBE, 4, + &kObjectData[4154], 0}, + {"setct-CapRevReqTBEX", "setct-CapRevReqTBEX", NID_setct_CapRevReqTBEX, 4, + &kObjectData[4158], 0}, + {"setct-CapRevResTBE", "setct-CapRevResTBE", NID_setct_CapRevResTBE, 4, + &kObjectData[4162], 0}, + {"setct-CredReqTBE", "setct-CredReqTBE", NID_setct_CredReqTBE, 4, + &kObjectData[4166], 0}, + {"setct-CredReqTBEX", "setct-CredReqTBEX", NID_setct_CredReqTBEX, 4, + &kObjectData[4170], 0}, + {"setct-CredResTBE", "setct-CredResTBE", NID_setct_CredResTBE, 4, + &kObjectData[4174], 0}, + {"setct-CredRevReqTBE", "setct-CredRevReqTBE", NID_setct_CredRevReqTBE, 4, + &kObjectData[4178], 0}, + {"setct-CredRevReqTBEX", "setct-CredRevReqTBEX", NID_setct_CredRevReqTBEX, + 4, &kObjectData[4182], 0}, + {"setct-CredRevResTBE", "setct-CredRevResTBE", NID_setct_CredRevResTBE, 4, + &kObjectData[4186], 0}, + {"setct-BatchAdminReqTBE", "setct-BatchAdminReqTBE", + NID_setct_BatchAdminReqTBE, 4, &kObjectData[4190], 0}, + {"setct-BatchAdminResTBE", "setct-BatchAdminResTBE", + NID_setct_BatchAdminResTBE, 4, &kObjectData[4194], 0}, + {"setct-RegFormReqTBE", "setct-RegFormReqTBE", NID_setct_RegFormReqTBE, 4, + &kObjectData[4198], 0}, + {"setct-CertReqTBE", "setct-CertReqTBE", NID_setct_CertReqTBE, 4, + &kObjectData[4202], 0}, + {"setct-CertReqTBEX", "setct-CertReqTBEX", NID_setct_CertReqTBEX, 4, + &kObjectData[4206], 0}, + {"setct-CertResTBE", "setct-CertResTBE", NID_setct_CertResTBE, 4, + &kObjectData[4210], 0}, + {"setct-CRLNotificationTBS", "setct-CRLNotificationTBS", + NID_setct_CRLNotificationTBS, 4, &kObjectData[4214], 0}, + {"setct-CRLNotificationResTBS", "setct-CRLNotificationResTBS", + NID_setct_CRLNotificationResTBS, 4, &kObjectData[4218], 0}, + {"setct-BCIDistributionTBS", "setct-BCIDistributionTBS", + NID_setct_BCIDistributionTBS, 4, &kObjectData[4222], 0}, + {"setext-genCrypt", "generic cryptogram", NID_setext_genCrypt, 4, + &kObjectData[4226], 0}, + {"setext-miAuth", "merchant initiated auth", NID_setext_miAuth, 4, + &kObjectData[4230], 0}, + {"setext-pinSecure", "setext-pinSecure", NID_setext_pinSecure, 4, + &kObjectData[4234], 0}, + {"setext-pinAny", "setext-pinAny", NID_setext_pinAny, 4, &kObjectData[4238], + 0}, + {"setext-track2", "setext-track2", NID_setext_track2, 4, &kObjectData[4242], + 0}, + {"setext-cv", "additional verification", NID_setext_cv, 4, + &kObjectData[4246], 0}, + {"set-policy-root", "set-policy-root", NID_set_policy_root, 4, + &kObjectData[4250], 0}, + {"setCext-hashedRoot", "setCext-hashedRoot", NID_setCext_hashedRoot, 4, + &kObjectData[4254], 0}, + {"setCext-certType", "setCext-certType", NID_setCext_certType, 4, + &kObjectData[4258], 0}, + {"setCext-merchData", "setCext-merchData", NID_setCext_merchData, 4, + &kObjectData[4262], 0}, + {"setCext-cCertRequired", "setCext-cCertRequired", + NID_setCext_cCertRequired, 4, &kObjectData[4266], 0}, + {"setCext-tunneling", "setCext-tunneling", NID_setCext_tunneling, 4, + &kObjectData[4270], 0}, + {"setCext-setExt", "setCext-setExt", NID_setCext_setExt, 4, + &kObjectData[4274], 0}, + {"setCext-setQualf", "setCext-setQualf", NID_setCext_setQualf, 4, + &kObjectData[4278], 0}, + {"setCext-PGWYcapabilities", "setCext-PGWYcapabilities", + NID_setCext_PGWYcapabilities, 4, &kObjectData[4282], 0}, + {"setCext-TokenIdentifier", "setCext-TokenIdentifier", + NID_setCext_TokenIdentifier, 4, &kObjectData[4286], 0}, + {"setCext-Track2Data", "setCext-Track2Data", NID_setCext_Track2Data, 4, + &kObjectData[4290], 0}, + {"setCext-TokenType", "setCext-TokenType", NID_setCext_TokenType, 4, + &kObjectData[4294], 0}, + {"setCext-IssuerCapabilities", "setCext-IssuerCapabilities", + NID_setCext_IssuerCapabilities, 4, &kObjectData[4298], 0}, + {"setAttr-Cert", "setAttr-Cert", NID_setAttr_Cert, 4, &kObjectData[4302], + 0}, + {"setAttr-PGWYcap", "payment gateway capabilities", NID_setAttr_PGWYcap, 4, + &kObjectData[4306], 0}, + {"setAttr-TokenType", "setAttr-TokenType", NID_setAttr_TokenType, 4, + &kObjectData[4310], 0}, + {"setAttr-IssCap", "issuer capabilities", NID_setAttr_IssCap, 4, + &kObjectData[4314], 0}, + {"set-rootKeyThumb", "set-rootKeyThumb", NID_set_rootKeyThumb, 5, + &kObjectData[4318], 0}, + {"set-addPolicy", "set-addPolicy", NID_set_addPolicy, 5, &kObjectData[4323], + 0}, + {"setAttr-Token-EMV", "setAttr-Token-EMV", NID_setAttr_Token_EMV, 5, + &kObjectData[4328], 0}, + {"setAttr-Token-B0Prime", "setAttr-Token-B0Prime", + NID_setAttr_Token_B0Prime, 5, &kObjectData[4333], 0}, + {"setAttr-IssCap-CVM", "setAttr-IssCap-CVM", NID_setAttr_IssCap_CVM, 5, + &kObjectData[4338], 0}, + {"setAttr-IssCap-T2", "setAttr-IssCap-T2", NID_setAttr_IssCap_T2, 5, + &kObjectData[4343], 0}, + {"setAttr-IssCap-Sig", "setAttr-IssCap-Sig", NID_setAttr_IssCap_Sig, 5, + &kObjectData[4348], 0}, + {"setAttr-GenCryptgrm", "generate cryptogram", NID_setAttr_GenCryptgrm, 6, + &kObjectData[4353], 0}, + {"setAttr-T2Enc", "encrypted track 2", NID_setAttr_T2Enc, 6, + &kObjectData[4359], 0}, + {"setAttr-T2cleartxt", "cleartext track 2", NID_setAttr_T2cleartxt, 6, + &kObjectData[4365], 0}, + {"setAttr-TokICCsig", "ICC or token signature", NID_setAttr_TokICCsig, 6, + &kObjectData[4371], 0}, + {"setAttr-SecDevSig", "secure device signature", NID_setAttr_SecDevSig, 6, + &kObjectData[4377], 0}, + {"set-brand-IATA-ATA", "set-brand-IATA-ATA", NID_set_brand_IATA_ATA, 4, + &kObjectData[4383], 0}, + {"set-brand-Diners", "set-brand-Diners", NID_set_brand_Diners, 4, + &kObjectData[4387], 0}, + {"set-brand-AmericanExpress", "set-brand-AmericanExpress", + NID_set_brand_AmericanExpress, 4, &kObjectData[4391], 0}, + {"set-brand-JCB", "set-brand-JCB", NID_set_brand_JCB, 4, &kObjectData[4395], + 0}, + {"set-brand-Visa", "set-brand-Visa", NID_set_brand_Visa, 4, + &kObjectData[4399], 0}, + {"set-brand-MasterCard", "set-brand-MasterCard", NID_set_brand_MasterCard, + 4, &kObjectData[4403], 0}, + {"set-brand-Novus", "set-brand-Novus", NID_set_brand_Novus, 5, + &kObjectData[4407], 0}, + {"DES-CDMF", "des-cdmf", NID_des_cdmf, 8, &kObjectData[4412], 0}, + {"rsaOAEPEncryptionSET", "rsaOAEPEncryptionSET", NID_rsaOAEPEncryptionSET, + 9, &kObjectData[4420], 0}, + {"ITU-T", "itu-t", NID_itu_t, 0, NULL, 0}, + {"JOINT-ISO-ITU-T", "joint-iso-itu-t", NID_joint_iso_itu_t, 0, NULL, 0}, + {"international-organizations", "International Organizations", + NID_international_organizations, 1, &kObjectData[4429], 0}, + {"msSmartcardLogin", "Microsoft Smartcardlogin", NID_ms_smartcard_login, 10, + &kObjectData[4430], 0}, + {"msUPN", "Microsoft Universal Principal Name", NID_ms_upn, 10, + &kObjectData[4440], 0}, + {"AES-128-CFB1", "aes-128-cfb1", NID_aes_128_cfb1, 0, NULL, 0}, + {"AES-192-CFB1", "aes-192-cfb1", NID_aes_192_cfb1, 0, NULL, 0}, + {"AES-256-CFB1", "aes-256-cfb1", NID_aes_256_cfb1, 0, NULL, 0}, + {"AES-128-CFB8", "aes-128-cfb8", NID_aes_128_cfb8, 0, NULL, 0}, + {"AES-192-CFB8", "aes-192-cfb8", NID_aes_192_cfb8, 0, NULL, 0}, + {"AES-256-CFB8", "aes-256-cfb8", NID_aes_256_cfb8, 0, NULL, 0}, + {"DES-CFB1", "des-cfb1", NID_des_cfb1, 0, NULL, 0}, + {"DES-CFB8", "des-cfb8", NID_des_cfb8, 0, NULL, 0}, + {"DES-EDE3-CFB1", "des-ede3-cfb1", NID_des_ede3_cfb1, 0, NULL, 0}, + {"DES-EDE3-CFB8", "des-ede3-cfb8", NID_des_ede3_cfb8, 0, NULL, 0}, + {"street", "streetAddress", NID_streetAddress, 3, &kObjectData[4450], 0}, + {"postalCode", "postalCode", NID_postalCode, 3, &kObjectData[4453], 0}, + {"id-ppl", "id-ppl", NID_id_ppl, 7, &kObjectData[4456], 0}, + {"proxyCertInfo", "Proxy Certificate Information", NID_proxyCertInfo, 8, + &kObjectData[4463], 0}, + {"id-ppl-anyLanguage", "Any language", NID_id_ppl_anyLanguage, 8, + &kObjectData[4471], 0}, + {"id-ppl-inheritAll", "Inherit all", NID_id_ppl_inheritAll, 8, + &kObjectData[4479], 0}, + {"nameConstraints", "X509v3 Name Constraints", NID_name_constraints, 3, + &kObjectData[4487], 0}, + {"id-ppl-independent", "Independent", NID_Independent, 8, + &kObjectData[4490], 0}, + {"RSA-SHA256", "sha256WithRSAEncryption", NID_sha256WithRSAEncryption, 9, + &kObjectData[4498], 0}, + {"RSA-SHA384", "sha384WithRSAEncryption", NID_sha384WithRSAEncryption, 9, + &kObjectData[4507], 0}, + {"RSA-SHA512", "sha512WithRSAEncryption", NID_sha512WithRSAEncryption, 9, + &kObjectData[4516], 0}, + {"RSA-SHA224", "sha224WithRSAEncryption", NID_sha224WithRSAEncryption, 9, + &kObjectData[4525], 0}, + {"SHA256", "sha256", NID_sha256, 9, &kObjectData[4534], 0}, + {"SHA384", "sha384", NID_sha384, 9, &kObjectData[4543], 0}, + {"SHA512", "sha512", NID_sha512, 9, &kObjectData[4552], 0}, + {"SHA224", "sha224", NID_sha224, 9, &kObjectData[4561], 0}, + {"identified-organization", "identified-organization", + NID_identified_organization, 1, &kObjectData[4570], 0}, + {"certicom-arc", "certicom-arc", NID_certicom_arc, 3, &kObjectData[4571], + 0}, + {"wap", "wap", NID_wap, 2, &kObjectData[4574], 0}, + {"wap-wsg", "wap-wsg", NID_wap_wsg, 3, &kObjectData[4576], 0}, + {"id-characteristic-two-basis", "id-characteristic-two-basis", + NID_X9_62_id_characteristic_two_basis, 8, &kObjectData[4579], 0}, + {"onBasis", "onBasis", NID_X9_62_onBasis, 9, &kObjectData[4587], 0}, + {"tpBasis", "tpBasis", NID_X9_62_tpBasis, 9, &kObjectData[4596], 0}, + {"ppBasis", "ppBasis", NID_X9_62_ppBasis, 9, &kObjectData[4605], 0}, + {"c2pnb163v1", "c2pnb163v1", NID_X9_62_c2pnb163v1, 8, &kObjectData[4614], + 0}, + {"c2pnb163v2", "c2pnb163v2", NID_X9_62_c2pnb163v2, 8, &kObjectData[4622], + 0}, + {"c2pnb163v3", "c2pnb163v3", NID_X9_62_c2pnb163v3, 8, &kObjectData[4630], + 0}, + {"c2pnb176v1", "c2pnb176v1", NID_X9_62_c2pnb176v1, 8, &kObjectData[4638], + 0}, + {"c2tnb191v1", "c2tnb191v1", NID_X9_62_c2tnb191v1, 8, &kObjectData[4646], + 0}, + {"c2tnb191v2", "c2tnb191v2", NID_X9_62_c2tnb191v2, 8, &kObjectData[4654], + 0}, + {"c2tnb191v3", "c2tnb191v3", NID_X9_62_c2tnb191v3, 8, &kObjectData[4662], + 0}, + {"c2onb191v4", "c2onb191v4", NID_X9_62_c2onb191v4, 8, &kObjectData[4670], + 0}, + {"c2onb191v5", "c2onb191v5", NID_X9_62_c2onb191v5, 8, &kObjectData[4678], + 0}, + {"c2pnb208w1", "c2pnb208w1", NID_X9_62_c2pnb208w1, 8, &kObjectData[4686], + 0}, + {"c2tnb239v1", "c2tnb239v1", NID_X9_62_c2tnb239v1, 8, &kObjectData[4694], + 0}, + {"c2tnb239v2", "c2tnb239v2", NID_X9_62_c2tnb239v2, 8, &kObjectData[4702], + 0}, + {"c2tnb239v3", "c2tnb239v3", NID_X9_62_c2tnb239v3, 8, &kObjectData[4710], + 0}, + {"c2onb239v4", "c2onb239v4", NID_X9_62_c2onb239v4, 8, &kObjectData[4718], + 0}, + {"c2onb239v5", "c2onb239v5", NID_X9_62_c2onb239v5, 8, &kObjectData[4726], + 0}, + {"c2pnb272w1", "c2pnb272w1", NID_X9_62_c2pnb272w1, 8, &kObjectData[4734], + 0}, + {"c2pnb304w1", "c2pnb304w1", NID_X9_62_c2pnb304w1, 8, &kObjectData[4742], + 0}, + {"c2tnb359v1", "c2tnb359v1", NID_X9_62_c2tnb359v1, 8, &kObjectData[4750], + 0}, + {"c2pnb368w1", "c2pnb368w1", NID_X9_62_c2pnb368w1, 8, &kObjectData[4758], + 0}, + {"c2tnb431r1", "c2tnb431r1", NID_X9_62_c2tnb431r1, 8, &kObjectData[4766], + 0}, + {"secp112r1", "secp112r1", NID_secp112r1, 5, &kObjectData[4774], 0}, + {"secp112r2", "secp112r2", NID_secp112r2, 5, &kObjectData[4779], 0}, + {"secp128r1", "secp128r1", NID_secp128r1, 5, &kObjectData[4784], 0}, + {"secp128r2", "secp128r2", NID_secp128r2, 5, &kObjectData[4789], 0}, + {"secp160k1", "secp160k1", NID_secp160k1, 5, &kObjectData[4794], 0}, + {"secp160r1", "secp160r1", NID_secp160r1, 5, &kObjectData[4799], 0}, + {"secp160r2", "secp160r2", NID_secp160r2, 5, &kObjectData[4804], 0}, + {"secp192k1", "secp192k1", NID_secp192k1, 5, &kObjectData[4809], 0}, + {"secp224k1", "secp224k1", NID_secp224k1, 5, &kObjectData[4814], 0}, + {"secp224r1", "secp224r1", NID_secp224r1, 5, &kObjectData[4819], 0}, + {"secp256k1", "secp256k1", NID_secp256k1, 5, &kObjectData[4824], 0}, + {"secp384r1", "secp384r1", NID_secp384r1, 5, &kObjectData[4829], 0}, + {"secp521r1", "secp521r1", NID_secp521r1, 5, &kObjectData[4834], 0}, + {"sect113r1", "sect113r1", NID_sect113r1, 5, &kObjectData[4839], 0}, + {"sect113r2", "sect113r2", NID_sect113r2, 5, &kObjectData[4844], 0}, + {"sect131r1", "sect131r1", NID_sect131r1, 5, &kObjectData[4849], 0}, + {"sect131r2", "sect131r2", NID_sect131r2, 5, &kObjectData[4854], 0}, + {"sect163k1", "sect163k1", NID_sect163k1, 5, &kObjectData[4859], 0}, + {"sect163r1", "sect163r1", NID_sect163r1, 5, &kObjectData[4864], 0}, + {"sect163r2", "sect163r2", NID_sect163r2, 5, &kObjectData[4869], 0}, + {"sect193r1", "sect193r1", NID_sect193r1, 5, &kObjectData[4874], 0}, + {"sect193r2", "sect193r2", NID_sect193r2, 5, &kObjectData[4879], 0}, + {"sect233k1", "sect233k1", NID_sect233k1, 5, &kObjectData[4884], 0}, + {"sect233r1", "sect233r1", NID_sect233r1, 5, &kObjectData[4889], 0}, + {"sect239k1", "sect239k1", NID_sect239k1, 5, &kObjectData[4894], 0}, + {"sect283k1", "sect283k1", NID_sect283k1, 5, &kObjectData[4899], 0}, + {"sect283r1", "sect283r1", NID_sect283r1, 5, &kObjectData[4904], 0}, + {"sect409k1", "sect409k1", NID_sect409k1, 5, &kObjectData[4909], 0}, + {"sect409r1", "sect409r1", NID_sect409r1, 5, &kObjectData[4914], 0}, + {"sect571k1", "sect571k1", NID_sect571k1, 5, &kObjectData[4919], 0}, + {"sect571r1", "sect571r1", NID_sect571r1, 5, &kObjectData[4924], 0}, + {"wap-wsg-idm-ecid-wtls1", "wap-wsg-idm-ecid-wtls1", + NID_wap_wsg_idm_ecid_wtls1, 5, &kObjectData[4929], 0}, + {"wap-wsg-idm-ecid-wtls3", "wap-wsg-idm-ecid-wtls3", + NID_wap_wsg_idm_ecid_wtls3, 5, &kObjectData[4934], 0}, + {"wap-wsg-idm-ecid-wtls4", "wap-wsg-idm-ecid-wtls4", + NID_wap_wsg_idm_ecid_wtls4, 5, &kObjectData[4939], 0}, + {"wap-wsg-idm-ecid-wtls5", "wap-wsg-idm-ecid-wtls5", + NID_wap_wsg_idm_ecid_wtls5, 5, &kObjectData[4944], 0}, + {"wap-wsg-idm-ecid-wtls6", "wap-wsg-idm-ecid-wtls6", + NID_wap_wsg_idm_ecid_wtls6, 5, &kObjectData[4949], 0}, + {"wap-wsg-idm-ecid-wtls7", "wap-wsg-idm-ecid-wtls7", + NID_wap_wsg_idm_ecid_wtls7, 5, &kObjectData[4954], 0}, + {"wap-wsg-idm-ecid-wtls8", "wap-wsg-idm-ecid-wtls8", + NID_wap_wsg_idm_ecid_wtls8, 5, &kObjectData[4959], 0}, + {"wap-wsg-idm-ecid-wtls9", "wap-wsg-idm-ecid-wtls9", + NID_wap_wsg_idm_ecid_wtls9, 5, &kObjectData[4964], 0}, + {"wap-wsg-idm-ecid-wtls10", "wap-wsg-idm-ecid-wtls10", + NID_wap_wsg_idm_ecid_wtls10, 5, &kObjectData[4969], 0}, + {"wap-wsg-idm-ecid-wtls11", "wap-wsg-idm-ecid-wtls11", + NID_wap_wsg_idm_ecid_wtls11, 5, &kObjectData[4974], 0}, + {"wap-wsg-idm-ecid-wtls12", "wap-wsg-idm-ecid-wtls12", + NID_wap_wsg_idm_ecid_wtls12, 5, &kObjectData[4979], 0}, + {"anyPolicy", "X509v3 Any Policy", NID_any_policy, 4, &kObjectData[4984], + 0}, + {"policyMappings", "X509v3 Policy Mappings", NID_policy_mappings, 3, + &kObjectData[4988], 0}, + {"inhibitAnyPolicy", "X509v3 Inhibit Any Policy", NID_inhibit_any_policy, 3, + &kObjectData[4991], 0}, + {"Oakley-EC2N-3", "ipsec3", NID_ipsec3, 0, NULL, 0}, + {"Oakley-EC2N-4", "ipsec4", NID_ipsec4, 0, NULL, 0}, + {"CAMELLIA-128-CBC", "camellia-128-cbc", NID_camellia_128_cbc, 11, + &kObjectData[4994], 0}, + {"CAMELLIA-192-CBC", "camellia-192-cbc", NID_camellia_192_cbc, 11, + &kObjectData[5005], 0}, + {"CAMELLIA-256-CBC", "camellia-256-cbc", NID_camellia_256_cbc, 11, + &kObjectData[5016], 0}, + {"CAMELLIA-128-ECB", "camellia-128-ecb", NID_camellia_128_ecb, 8, + &kObjectData[5027], 0}, + {"CAMELLIA-192-ECB", "camellia-192-ecb", NID_camellia_192_ecb, 8, + &kObjectData[5035], 0}, + {"CAMELLIA-256-ECB", "camellia-256-ecb", NID_camellia_256_ecb, 8, + &kObjectData[5043], 0}, + {"CAMELLIA-128-CFB", "camellia-128-cfb", NID_camellia_128_cfb128, 8, + &kObjectData[5051], 0}, + {"CAMELLIA-192-CFB", "camellia-192-cfb", NID_camellia_192_cfb128, 8, + &kObjectData[5059], 0}, + {"CAMELLIA-256-CFB", "camellia-256-cfb", NID_camellia_256_cfb128, 8, + &kObjectData[5067], 0}, + {"CAMELLIA-128-CFB1", "camellia-128-cfb1", NID_camellia_128_cfb1, 0, NULL, + 0}, + {"CAMELLIA-192-CFB1", "camellia-192-cfb1", NID_camellia_192_cfb1, 0, NULL, + 0}, + {"CAMELLIA-256-CFB1", "camellia-256-cfb1", NID_camellia_256_cfb1, 0, NULL, + 0}, + {"CAMELLIA-128-CFB8", "camellia-128-cfb8", NID_camellia_128_cfb8, 0, NULL, + 0}, + {"CAMELLIA-192-CFB8", "camellia-192-cfb8", NID_camellia_192_cfb8, 0, NULL, + 0}, + {"CAMELLIA-256-CFB8", "camellia-256-cfb8", NID_camellia_256_cfb8, 0, NULL, + 0}, + {"CAMELLIA-128-OFB", "camellia-128-ofb", NID_camellia_128_ofb128, 8, + &kObjectData[5075], 0}, + {"CAMELLIA-192-OFB", "camellia-192-ofb", NID_camellia_192_ofb128, 8, + &kObjectData[5083], 0}, + {"CAMELLIA-256-OFB", "camellia-256-ofb", NID_camellia_256_ofb128, 8, + &kObjectData[5091], 0}, + {"subjectDirectoryAttributes", "X509v3 Subject Directory Attributes", + NID_subject_directory_attributes, 3, &kObjectData[5099], 0}, + {"issuingDistributionPoint", "X509v3 Issuing Distribution Point", + NID_issuing_distribution_point, 3, &kObjectData[5102], 0}, + {"certificateIssuer", "X509v3 Certificate Issuer", NID_certificate_issuer, + 3, &kObjectData[5105], 0}, + {NULL, NULL, NID_undef, 0, NULL, 0}, + {"KISA", "kisa", NID_kisa, 6, &kObjectData[5108], 0}, + {NULL, NULL, NID_undef, 0, NULL, 0}, + {NULL, NULL, NID_undef, 0, NULL, 0}, + {"SEED-ECB", "seed-ecb", NID_seed_ecb, 8, &kObjectData[5114], 0}, + {"SEED-CBC", "seed-cbc", NID_seed_cbc, 8, &kObjectData[5122], 0}, + {"SEED-OFB", "seed-ofb", NID_seed_ofb128, 8, &kObjectData[5130], 0}, + {"SEED-CFB", "seed-cfb", NID_seed_cfb128, 8, &kObjectData[5138], 0}, + {"HMAC-MD5", "hmac-md5", NID_hmac_md5, 8, &kObjectData[5146], 0}, + {"HMAC-SHA1", "hmac-sha1", NID_hmac_sha1, 8, &kObjectData[5154], 0}, + {"id-PasswordBasedMAC", "password based MAC", NID_id_PasswordBasedMAC, 9, + &kObjectData[5162], 0}, + {"id-DHBasedMac", "Diffie-Hellman based MAC", NID_id_DHBasedMac, 9, + &kObjectData[5171], 0}, + {"id-it-suppLangTags", "id-it-suppLangTags", NID_id_it_suppLangTags, 8, + &kObjectData[5180], 0}, + {"caRepository", "CA Repository", NID_caRepository, 8, &kObjectData[5188], + 0}, + {"id-smime-ct-compressedData", "id-smime-ct-compressedData", + NID_id_smime_ct_compressedData, 11, &kObjectData[5196], 0}, + {"id-ct-asciiTextWithCRLF", "id-ct-asciiTextWithCRLF", + NID_id_ct_asciiTextWithCRLF, 11, &kObjectData[5207], 0}, + {"id-aes128-wrap", "id-aes128-wrap", NID_id_aes128_wrap, 9, + &kObjectData[5218], 0}, + {"id-aes192-wrap", "id-aes192-wrap", NID_id_aes192_wrap, 9, + &kObjectData[5227], 0}, + {"id-aes256-wrap", "id-aes256-wrap", NID_id_aes256_wrap, 9, + &kObjectData[5236], 0}, + {"ecdsa-with-Recommended", "ecdsa-with-Recommended", + NID_ecdsa_with_Recommended, 7, &kObjectData[5245], 0}, + {"ecdsa-with-Specified", "ecdsa-with-Specified", NID_ecdsa_with_Specified, + 7, &kObjectData[5252], 0}, + {"ecdsa-with-SHA224", "ecdsa-with-SHA224", NID_ecdsa_with_SHA224, 8, + &kObjectData[5259], 0}, + {"ecdsa-with-SHA256", "ecdsa-with-SHA256", NID_ecdsa_with_SHA256, 8, + &kObjectData[5267], 0}, + {"ecdsa-with-SHA384", "ecdsa-with-SHA384", NID_ecdsa_with_SHA384, 8, + &kObjectData[5275], 0}, + {"ecdsa-with-SHA512", "ecdsa-with-SHA512", NID_ecdsa_with_SHA512, 8, + &kObjectData[5283], 0}, + {"hmacWithMD5", "hmacWithMD5", NID_hmacWithMD5, 8, &kObjectData[5291], 0}, + {"hmacWithSHA224", "hmacWithSHA224", NID_hmacWithSHA224, 8, + &kObjectData[5299], 0}, + {"hmacWithSHA256", "hmacWithSHA256", NID_hmacWithSHA256, 8, + &kObjectData[5307], 0}, + {"hmacWithSHA384", "hmacWithSHA384", NID_hmacWithSHA384, 8, + &kObjectData[5315], 0}, + {"hmacWithSHA512", "hmacWithSHA512", NID_hmacWithSHA512, 8, + &kObjectData[5323], 0}, + {"dsa_with_SHA224", "dsa_with_SHA224", NID_dsa_with_SHA224, 9, + &kObjectData[5331], 0}, + {"dsa_with_SHA256", "dsa_with_SHA256", NID_dsa_with_SHA256, 9, + &kObjectData[5340], 0}, + {"whirlpool", "whirlpool", NID_whirlpool, 6, &kObjectData[5349], 0}, + {"cryptopro", "cryptopro", NID_cryptopro, 5, &kObjectData[5355], 0}, + {"cryptocom", "cryptocom", NID_cryptocom, 5, &kObjectData[5360], 0}, + {"id-GostR3411-94-with-GostR3410-2001", + "GOST R 34.11-94 with GOST R 34.10-2001", + NID_id_GostR3411_94_with_GostR3410_2001, 6, &kObjectData[5365], 0}, + {"id-GostR3411-94-with-GostR3410-94", + "GOST R 34.11-94 with GOST R 34.10-94", + NID_id_GostR3411_94_with_GostR3410_94, 6, &kObjectData[5371], 0}, + {"md_gost94", "GOST R 34.11-94", NID_id_GostR3411_94, 6, &kObjectData[5377], + 0}, + {"id-HMACGostR3411-94", "HMAC GOST 34.11-94", NID_id_HMACGostR3411_94, 6, + &kObjectData[5383], 0}, + {"gost2001", "GOST R 34.10-2001", NID_id_GostR3410_2001, 6, + &kObjectData[5389], 0}, + {"gost94", "GOST R 34.10-94", NID_id_GostR3410_94, 6, &kObjectData[5395], + 0}, + {"gost89", "GOST 28147-89", NID_id_Gost28147_89, 6, &kObjectData[5401], 0}, + {"gost89-cnt", "gost89-cnt", NID_gost89_cnt, 0, NULL, 0}, + {"gost-mac", "GOST 28147-89 MAC", NID_id_Gost28147_89_MAC, 6, + &kObjectData[5407], 0}, + {"prf-gostr3411-94", "GOST R 34.11-94 PRF", NID_id_GostR3411_94_prf, 6, + &kObjectData[5413], 0}, + {"id-GostR3410-2001DH", "GOST R 34.10-2001 DH", NID_id_GostR3410_2001DH, 6, + &kObjectData[5419], 0}, + {"id-GostR3410-94DH", "GOST R 34.10-94 DH", NID_id_GostR3410_94DH, 6, + &kObjectData[5425], 0}, + {"id-Gost28147-89-CryptoPro-KeyMeshing", + "id-Gost28147-89-CryptoPro-KeyMeshing", + NID_id_Gost28147_89_CryptoPro_KeyMeshing, 7, &kObjectData[5431], 0}, + {"id-Gost28147-89-None-KeyMeshing", "id-Gost28147-89-None-KeyMeshing", + NID_id_Gost28147_89_None_KeyMeshing, 7, &kObjectData[5438], 0}, + {"id-GostR3411-94-TestParamSet", "id-GostR3411-94-TestParamSet", + NID_id_GostR3411_94_TestParamSet, 7, &kObjectData[5445], 0}, + {"id-GostR3411-94-CryptoProParamSet", "id-GostR3411-94-CryptoProParamSet", + NID_id_GostR3411_94_CryptoProParamSet, 7, &kObjectData[5452], 0}, + {"id-Gost28147-89-TestParamSet", "id-Gost28147-89-TestParamSet", + NID_id_Gost28147_89_TestParamSet, 7, &kObjectData[5459], 0}, + {"id-Gost28147-89-CryptoPro-A-ParamSet", + "id-Gost28147-89-CryptoPro-A-ParamSet", + NID_id_Gost28147_89_CryptoPro_A_ParamSet, 7, &kObjectData[5466], 0}, + {"id-Gost28147-89-CryptoPro-B-ParamSet", + "id-Gost28147-89-CryptoPro-B-ParamSet", + NID_id_Gost28147_89_CryptoPro_B_ParamSet, 7, &kObjectData[5473], 0}, + {"id-Gost28147-89-CryptoPro-C-ParamSet", + "id-Gost28147-89-CryptoPro-C-ParamSet", + NID_id_Gost28147_89_CryptoPro_C_ParamSet, 7, &kObjectData[5480], 0}, + {"id-Gost28147-89-CryptoPro-D-ParamSet", + "id-Gost28147-89-CryptoPro-D-ParamSet", + NID_id_Gost28147_89_CryptoPro_D_ParamSet, 7, &kObjectData[5487], 0}, + {"id-Gost28147-89-CryptoPro-Oscar-1-1-ParamSet", + "id-Gost28147-89-CryptoPro-Oscar-1-1-ParamSet", + NID_id_Gost28147_89_CryptoPro_Oscar_1_1_ParamSet, 7, &kObjectData[5494], + 0}, + {"id-Gost28147-89-CryptoPro-Oscar-1-0-ParamSet", + "id-Gost28147-89-CryptoPro-Oscar-1-0-ParamSet", + NID_id_Gost28147_89_CryptoPro_Oscar_1_0_ParamSet, 7, &kObjectData[5501], + 0}, + {"id-Gost28147-89-CryptoPro-RIC-1-ParamSet", + "id-Gost28147-89-CryptoPro-RIC-1-ParamSet", + NID_id_Gost28147_89_CryptoPro_RIC_1_ParamSet, 7, &kObjectData[5508], 0}, + {"id-GostR3410-94-TestParamSet", "id-GostR3410-94-TestParamSet", + NID_id_GostR3410_94_TestParamSet, 7, &kObjectData[5515], 0}, + {"id-GostR3410-94-CryptoPro-A-ParamSet", + "id-GostR3410-94-CryptoPro-A-ParamSet", + NID_id_GostR3410_94_CryptoPro_A_ParamSet, 7, &kObjectData[5522], 0}, + {"id-GostR3410-94-CryptoPro-B-ParamSet", + "id-GostR3410-94-CryptoPro-B-ParamSet", + NID_id_GostR3410_94_CryptoPro_B_ParamSet, 7, &kObjectData[5529], 0}, + {"id-GostR3410-94-CryptoPro-C-ParamSet", + "id-GostR3410-94-CryptoPro-C-ParamSet", + NID_id_GostR3410_94_CryptoPro_C_ParamSet, 7, &kObjectData[5536], 0}, + {"id-GostR3410-94-CryptoPro-D-ParamSet", + "id-GostR3410-94-CryptoPro-D-ParamSet", + NID_id_GostR3410_94_CryptoPro_D_ParamSet, 7, &kObjectData[5543], 0}, + {"id-GostR3410-94-CryptoPro-XchA-ParamSet", + "id-GostR3410-94-CryptoPro-XchA-ParamSet", + NID_id_GostR3410_94_CryptoPro_XchA_ParamSet, 7, &kObjectData[5550], 0}, + {"id-GostR3410-94-CryptoPro-XchB-ParamSet", + "id-GostR3410-94-CryptoPro-XchB-ParamSet", + NID_id_GostR3410_94_CryptoPro_XchB_ParamSet, 7, &kObjectData[5557], 0}, + {"id-GostR3410-94-CryptoPro-XchC-ParamSet", + "id-GostR3410-94-CryptoPro-XchC-ParamSet", + NID_id_GostR3410_94_CryptoPro_XchC_ParamSet, 7, &kObjectData[5564], 0}, + {"id-GostR3410-2001-TestParamSet", "id-GostR3410-2001-TestParamSet", + NID_id_GostR3410_2001_TestParamSet, 7, &kObjectData[5571], 0}, + {"id-GostR3410-2001-CryptoPro-A-ParamSet", + "id-GostR3410-2001-CryptoPro-A-ParamSet", + NID_id_GostR3410_2001_CryptoPro_A_ParamSet, 7, &kObjectData[5578], 0}, + {"id-GostR3410-2001-CryptoPro-B-ParamSet", + "id-GostR3410-2001-CryptoPro-B-ParamSet", + NID_id_GostR3410_2001_CryptoPro_B_ParamSet, 7, &kObjectData[5585], 0}, + {"id-GostR3410-2001-CryptoPro-C-ParamSet", + "id-GostR3410-2001-CryptoPro-C-ParamSet", + NID_id_GostR3410_2001_CryptoPro_C_ParamSet, 7, &kObjectData[5592], 0}, + {"id-GostR3410-2001-CryptoPro-XchA-ParamSet", + "id-GostR3410-2001-CryptoPro-XchA-ParamSet", + NID_id_GostR3410_2001_CryptoPro_XchA_ParamSet, 7, &kObjectData[5599], 0}, + {"id-GostR3410-2001-CryptoPro-XchB-ParamSet", + "id-GostR3410-2001-CryptoPro-XchB-ParamSet", + NID_id_GostR3410_2001_CryptoPro_XchB_ParamSet, 7, &kObjectData[5606], 0}, + {"id-GostR3410-94-a", "id-GostR3410-94-a", NID_id_GostR3410_94_a, 7, + &kObjectData[5613], 0}, + {"id-GostR3410-94-aBis", "id-GostR3410-94-aBis", NID_id_GostR3410_94_aBis, + 7, &kObjectData[5620], 0}, + {"id-GostR3410-94-b", "id-GostR3410-94-b", NID_id_GostR3410_94_b, 7, + &kObjectData[5627], 0}, + {"id-GostR3410-94-bBis", "id-GostR3410-94-bBis", NID_id_GostR3410_94_bBis, + 7, &kObjectData[5634], 0}, + {"id-Gost28147-89-cc", "GOST 28147-89 Cryptocom ParamSet", + NID_id_Gost28147_89_cc, 8, &kObjectData[5641], 0}, + {"gost94cc", "GOST 34.10-94 Cryptocom", NID_id_GostR3410_94_cc, 8, + &kObjectData[5649], 0}, + {"gost2001cc", "GOST 34.10-2001 Cryptocom", NID_id_GostR3410_2001_cc, 8, + &kObjectData[5657], 0}, + {"id-GostR3411-94-with-GostR3410-94-cc", + "GOST R 34.11-94 with GOST R 34.10-94 Cryptocom", + NID_id_GostR3411_94_with_GostR3410_94_cc, 8, &kObjectData[5665], 0}, + {"id-GostR3411-94-with-GostR3410-2001-cc", + "GOST R 34.11-94 with GOST R 34.10-2001 Cryptocom", + NID_id_GostR3411_94_with_GostR3410_2001_cc, 8, &kObjectData[5673], 0}, + {"id-GostR3410-2001-ParamSet-cc", + "GOST R 3410-2001 Parameter Set Cryptocom", + NID_id_GostR3410_2001_ParamSet_cc, 8, &kObjectData[5681], 0}, + {"HMAC", "hmac", NID_hmac, 0, NULL, 0}, + {"LocalKeySet", "Microsoft Local Key set", NID_LocalKeySet, 9, + &kObjectData[5689], 0}, + {"freshestCRL", "X509v3 Freshest CRL", NID_freshest_crl, 3, + &kObjectData[5698], 0}, + {"id-on-permanentIdentifier", "Permanent Identifier", + NID_id_on_permanentIdentifier, 8, &kObjectData[5701], 0}, + {"searchGuide", "searchGuide", NID_searchGuide, 3, &kObjectData[5709], 0}, + {"businessCategory", "businessCategory", NID_businessCategory, 3, + &kObjectData[5712], 0}, + {"postalAddress", "postalAddress", NID_postalAddress, 3, &kObjectData[5715], + 0}, + {"postOfficeBox", "postOfficeBox", NID_postOfficeBox, 3, &kObjectData[5718], + 0}, + {"physicalDeliveryOfficeName", "physicalDeliveryOfficeName", + NID_physicalDeliveryOfficeName, 3, &kObjectData[5721], 0}, + {"telephoneNumber", "telephoneNumber", NID_telephoneNumber, 3, + &kObjectData[5724], 0}, + {"telexNumber", "telexNumber", NID_telexNumber, 3, &kObjectData[5727], 0}, + {"teletexTerminalIdentifier", "teletexTerminalIdentifier", + NID_teletexTerminalIdentifier, 3, &kObjectData[5730], 0}, + {"facsimileTelephoneNumber", "facsimileTelephoneNumber", + NID_facsimileTelephoneNumber, 3, &kObjectData[5733], 0}, + {"x121Address", "x121Address", NID_x121Address, 3, &kObjectData[5736], 0}, + {"internationaliSDNNumber", "internationaliSDNNumber", + NID_internationaliSDNNumber, 3, &kObjectData[5739], 0}, + {"registeredAddress", "registeredAddress", NID_registeredAddress, 3, + &kObjectData[5742], 0}, + {"destinationIndicator", "destinationIndicator", NID_destinationIndicator, + 3, &kObjectData[5745], 0}, + {"preferredDeliveryMethod", "preferredDeliveryMethod", + NID_preferredDeliveryMethod, 3, &kObjectData[5748], 0}, + {"presentationAddress", "presentationAddress", NID_presentationAddress, 3, + &kObjectData[5751], 0}, + {"supportedApplicationContext", "supportedApplicationContext", + NID_supportedApplicationContext, 3, &kObjectData[5754], 0}, + {"member", "member", NID_member, 3, &kObjectData[5757], 0}, + {"owner", "owner", NID_owner, 3, &kObjectData[5760], 0}, + {"roleOccupant", "roleOccupant", NID_roleOccupant, 3, &kObjectData[5763], + 0}, + {"seeAlso", "seeAlso", NID_seeAlso, 3, &kObjectData[5766], 0}, + {"userPassword", "userPassword", NID_userPassword, 3, &kObjectData[5769], + 0}, + {"userCertificate", "userCertificate", NID_userCertificate, 3, + &kObjectData[5772], 0}, + {"cACertificate", "cACertificate", NID_cACertificate, 3, &kObjectData[5775], + 0}, + {"authorityRevocationList", "authorityRevocationList", + NID_authorityRevocationList, 3, &kObjectData[5778], 0}, + {"certificateRevocationList", "certificateRevocationList", + NID_certificateRevocationList, 3, &kObjectData[5781], 0}, + {"crossCertificatePair", "crossCertificatePair", NID_crossCertificatePair, + 3, &kObjectData[5784], 0}, + {"enhancedSearchGuide", "enhancedSearchGuide", NID_enhancedSearchGuide, 3, + &kObjectData[5787], 0}, + {"protocolInformation", "protocolInformation", NID_protocolInformation, 3, + &kObjectData[5790], 0}, + {"distinguishedName", "distinguishedName", NID_distinguishedName, 3, + &kObjectData[5793], 0}, + {"uniqueMember", "uniqueMember", NID_uniqueMember, 3, &kObjectData[5796], + 0}, + {"houseIdentifier", "houseIdentifier", NID_houseIdentifier, 3, + &kObjectData[5799], 0}, + {"supportedAlgorithms", "supportedAlgorithms", NID_supportedAlgorithms, 3, + &kObjectData[5802], 0}, + {"deltaRevocationList", "deltaRevocationList", NID_deltaRevocationList, 3, + &kObjectData[5805], 0}, + {"dmdName", "dmdName", NID_dmdName, 3, &kObjectData[5808], 0}, + {"id-alg-PWRI-KEK", "id-alg-PWRI-KEK", NID_id_alg_PWRI_KEK, 11, + &kObjectData[5811], 0}, + {"CMAC", "cmac", NID_cmac, 0, NULL, 0}, + {"id-aes128-GCM", "aes-128-gcm", NID_aes_128_gcm, 9, &kObjectData[5822], 0}, + {"id-aes128-CCM", "aes-128-ccm", NID_aes_128_ccm, 9, &kObjectData[5831], 0}, + {"id-aes128-wrap-pad", "id-aes128-wrap-pad", NID_id_aes128_wrap_pad, 9, + &kObjectData[5840], 0}, + {"id-aes192-GCM", "aes-192-gcm", NID_aes_192_gcm, 9, &kObjectData[5849], 0}, + {"id-aes192-CCM", "aes-192-ccm", NID_aes_192_ccm, 9, &kObjectData[5858], 0}, + {"id-aes192-wrap-pad", "id-aes192-wrap-pad", NID_id_aes192_wrap_pad, 9, + &kObjectData[5867], 0}, + {"id-aes256-GCM", "aes-256-gcm", NID_aes_256_gcm, 9, &kObjectData[5876], 0}, + {"id-aes256-CCM", "aes-256-ccm", NID_aes_256_ccm, 9, &kObjectData[5885], 0}, + {"id-aes256-wrap-pad", "id-aes256-wrap-pad", NID_id_aes256_wrap_pad, 9, + &kObjectData[5894], 0}, + {"AES-128-CTR", "aes-128-ctr", NID_aes_128_ctr, 0, NULL, 0}, + {"AES-192-CTR", "aes-192-ctr", NID_aes_192_ctr, 0, NULL, 0}, + {"AES-256-CTR", "aes-256-ctr", NID_aes_256_ctr, 0, NULL, 0}, + {"id-camellia128-wrap", "id-camellia128-wrap", NID_id_camellia128_wrap, 11, + &kObjectData[5903], 0}, + {"id-camellia192-wrap", "id-camellia192-wrap", NID_id_camellia192_wrap, 11, + &kObjectData[5914], 0}, + {"id-camellia256-wrap", "id-camellia256-wrap", NID_id_camellia256_wrap, 11, + &kObjectData[5925], 0}, + {"anyExtendedKeyUsage", "Any Extended Key Usage", NID_anyExtendedKeyUsage, + 4, &kObjectData[5936], 0}, + {"MGF1", "mgf1", NID_mgf1, 9, &kObjectData[5940], 0}, + {"RSASSA-PSS", "rsassaPss", NID_rsassaPss, 9, &kObjectData[5949], 0}, + {"AES-128-XTS", "aes-128-xts", NID_aes_128_xts, 0, NULL, 0}, + {"AES-256-XTS", "aes-256-xts", NID_aes_256_xts, 0, NULL, 0}, + {"RC4-HMAC-MD5", "rc4-hmac-md5", NID_rc4_hmac_md5, 0, NULL, 0}, + {"AES-128-CBC-HMAC-SHA1", "aes-128-cbc-hmac-sha1", + NID_aes_128_cbc_hmac_sha1, 0, NULL, 0}, + {"AES-192-CBC-HMAC-SHA1", "aes-192-cbc-hmac-sha1", + NID_aes_192_cbc_hmac_sha1, 0, NULL, 0}, + {"AES-256-CBC-HMAC-SHA1", "aes-256-cbc-hmac-sha1", + NID_aes_256_cbc_hmac_sha1, 0, NULL, 0}, + {"RSAES-OAEP", "rsaesOaep", NID_rsaesOaep, 9, &kObjectData[5958], 0}, + {"dhpublicnumber", "X9.42 DH", NID_dhpublicnumber, 7, &kObjectData[5967], + 0}, + {"brainpoolP160r1", "brainpoolP160r1", NID_brainpoolP160r1, 9, + &kObjectData[5974], 0}, + {"brainpoolP160t1", "brainpoolP160t1", NID_brainpoolP160t1, 9, + &kObjectData[5983], 0}, + {"brainpoolP192r1", "brainpoolP192r1", NID_brainpoolP192r1, 9, + &kObjectData[5992], 0}, + {"brainpoolP192t1", "brainpoolP192t1", NID_brainpoolP192t1, 9, + &kObjectData[6001], 0}, + {"brainpoolP224r1", "brainpoolP224r1", NID_brainpoolP224r1, 9, + &kObjectData[6010], 0}, + {"brainpoolP224t1", "brainpoolP224t1", NID_brainpoolP224t1, 9, + &kObjectData[6019], 0}, + {"brainpoolP256r1", "brainpoolP256r1", NID_brainpoolP256r1, 9, + &kObjectData[6028], 0}, + {"brainpoolP256t1", "brainpoolP256t1", NID_brainpoolP256t1, 9, + &kObjectData[6037], 0}, + {"brainpoolP320r1", "brainpoolP320r1", NID_brainpoolP320r1, 9, + &kObjectData[6046], 0}, + {"brainpoolP320t1", "brainpoolP320t1", NID_brainpoolP320t1, 9, + &kObjectData[6055], 0}, + {"brainpoolP384r1", "brainpoolP384r1", NID_brainpoolP384r1, 9, + &kObjectData[6064], 0}, + {"brainpoolP384t1", "brainpoolP384t1", NID_brainpoolP384t1, 9, + &kObjectData[6073], 0}, + {"brainpoolP512r1", "brainpoolP512r1", NID_brainpoolP512r1, 9, + &kObjectData[6082], 0}, + {"brainpoolP512t1", "brainpoolP512t1", NID_brainpoolP512t1, 9, + &kObjectData[6091], 0}, + {"PSPECIFIED", "pSpecified", NID_pSpecified, 9, &kObjectData[6100], 0}, + {"dhSinglePass-stdDH-sha1kdf-scheme", "dhSinglePass-stdDH-sha1kdf-scheme", + NID_dhSinglePass_stdDH_sha1kdf_scheme, 9, &kObjectData[6109], 0}, + {"dhSinglePass-stdDH-sha224kdf-scheme", + "dhSinglePass-stdDH-sha224kdf-scheme", + NID_dhSinglePass_stdDH_sha224kdf_scheme, 6, &kObjectData[6118], 0}, + {"dhSinglePass-stdDH-sha256kdf-scheme", + "dhSinglePass-stdDH-sha256kdf-scheme", + NID_dhSinglePass_stdDH_sha256kdf_scheme, 6, &kObjectData[6124], 0}, + {"dhSinglePass-stdDH-sha384kdf-scheme", + "dhSinglePass-stdDH-sha384kdf-scheme", + NID_dhSinglePass_stdDH_sha384kdf_scheme, 6, &kObjectData[6130], 0}, + {"dhSinglePass-stdDH-sha512kdf-scheme", + "dhSinglePass-stdDH-sha512kdf-scheme", + NID_dhSinglePass_stdDH_sha512kdf_scheme, 6, &kObjectData[6136], 0}, + {"dhSinglePass-cofactorDH-sha1kdf-scheme", + "dhSinglePass-cofactorDH-sha1kdf-scheme", + NID_dhSinglePass_cofactorDH_sha1kdf_scheme, 9, &kObjectData[6142], 0}, + {"dhSinglePass-cofactorDH-sha224kdf-scheme", + "dhSinglePass-cofactorDH-sha224kdf-scheme", + NID_dhSinglePass_cofactorDH_sha224kdf_scheme, 6, &kObjectData[6151], 0}, + {"dhSinglePass-cofactorDH-sha256kdf-scheme", + "dhSinglePass-cofactorDH-sha256kdf-scheme", + NID_dhSinglePass_cofactorDH_sha256kdf_scheme, 6, &kObjectData[6157], 0}, + {"dhSinglePass-cofactorDH-sha384kdf-scheme", + "dhSinglePass-cofactorDH-sha384kdf-scheme", + NID_dhSinglePass_cofactorDH_sha384kdf_scheme, 6, &kObjectData[6163], 0}, + {"dhSinglePass-cofactorDH-sha512kdf-scheme", + "dhSinglePass-cofactorDH-sha512kdf-scheme", + NID_dhSinglePass_cofactorDH_sha512kdf_scheme, 6, &kObjectData[6169], 0}, + {"dh-std-kdf", "dh-std-kdf", NID_dh_std_kdf, 0, NULL, 0}, + {"dh-cofactor-kdf", "dh-cofactor-kdf", NID_dh_cofactor_kdf, 0, NULL, 0}, + {"X25519", "X25519", NID_X25519, 0, NULL, 0}, }; -static const unsigned int kNIDsInShortNameOrder[NUM_SN]={ -364, /* "AD_DVCS" */ -419, /* "AES-128-CBC" */ -916, /* "AES-128-CBC-HMAC-SHA1" */ -421, /* "AES-128-CFB" */ -650, /* "AES-128-CFB1" */ -653, /* "AES-128-CFB8" */ -904, /* "AES-128-CTR" */ -418, /* "AES-128-ECB" */ -420, /* "AES-128-OFB" */ -913, /* "AES-128-XTS" */ -423, /* "AES-192-CBC" */ -917, /* "AES-192-CBC-HMAC-SHA1" */ -425, /* "AES-192-CFB" */ -651, /* "AES-192-CFB1" */ -654, /* "AES-192-CFB8" */ -905, /* "AES-192-CTR" */ -422, /* "AES-192-ECB" */ -424, /* "AES-192-OFB" */ -427, /* "AES-256-CBC" */ -918, /* "AES-256-CBC-HMAC-SHA1" */ -429, /* "AES-256-CFB" */ -652, /* "AES-256-CFB1" */ -655, /* "AES-256-CFB8" */ -906, /* "AES-256-CTR" */ -426, /* "AES-256-ECB" */ -428, /* "AES-256-OFB" */ -914, /* "AES-256-XTS" */ -91, /* "BF-CBC" */ -93, /* "BF-CFB" */ -92, /* "BF-ECB" */ -94, /* "BF-OFB" */ -14, /* "C" */ -751, /* "CAMELLIA-128-CBC" */ -757, /* "CAMELLIA-128-CFB" */ -760, /* "CAMELLIA-128-CFB1" */ -763, /* "CAMELLIA-128-CFB8" */ -754, /* "CAMELLIA-128-ECB" */ -766, /* "CAMELLIA-128-OFB" */ -752, /* "CAMELLIA-192-CBC" */ -758, /* "CAMELLIA-192-CFB" */ -761, /* "CAMELLIA-192-CFB1" */ -764, /* "CAMELLIA-192-CFB8" */ -755, /* "CAMELLIA-192-ECB" */ -767, /* "CAMELLIA-192-OFB" */ -753, /* "CAMELLIA-256-CBC" */ -759, /* "CAMELLIA-256-CFB" */ -762, /* "CAMELLIA-256-CFB1" */ -765, /* "CAMELLIA-256-CFB8" */ -756, /* "CAMELLIA-256-ECB" */ -768, /* "CAMELLIA-256-OFB" */ -108, /* "CAST5-CBC" */ -110, /* "CAST5-CFB" */ -109, /* "CAST5-ECB" */ -111, /* "CAST5-OFB" */ -894, /* "CMAC" */ -13, /* "CN" */ -141, /* "CRLReason" */ -417, /* "CSPName" */ -367, /* "CrlID" */ -391, /* "DC" */ -31, /* "DES-CBC" */ -643, /* "DES-CDMF" */ -30, /* "DES-CFB" */ -656, /* "DES-CFB1" */ -657, /* "DES-CFB8" */ -29, /* "DES-ECB" */ -32, /* "DES-EDE" */ -43, /* "DES-EDE-CBC" */ -60, /* "DES-EDE-CFB" */ -62, /* "DES-EDE-OFB" */ -33, /* "DES-EDE3" */ -44, /* "DES-EDE3-CBC" */ -61, /* "DES-EDE3-CFB" */ -658, /* "DES-EDE3-CFB1" */ -659, /* "DES-EDE3-CFB8" */ -63, /* "DES-EDE3-OFB" */ -45, /* "DES-OFB" */ -80, /* "DESX-CBC" */ -380, /* "DOD" */ -116, /* "DSA" */ -66, /* "DSA-SHA" */ -113, /* "DSA-SHA1" */ -70, /* "DSA-SHA1-old" */ -67, /* "DSA-old" */ -297, /* "DVCS" */ -99, /* "GN" */ -855, /* "HMAC" */ -780, /* "HMAC-MD5" */ -781, /* "HMAC-SHA1" */ -381, /* "IANA" */ -34, /* "IDEA-CBC" */ -35, /* "IDEA-CFB" */ -36, /* "IDEA-ECB" */ -46, /* "IDEA-OFB" */ -181, /* "ISO" */ -183, /* "ISO-US" */ -645, /* "ITU-T" */ -646, /* "JOINT-ISO-ITU-T" */ -773, /* "KISA" */ -15, /* "L" */ -856, /* "LocalKeySet" */ - 3, /* "MD2" */ -257, /* "MD4" */ - 4, /* "MD5" */ -114, /* "MD5-SHA1" */ -95, /* "MDC2" */ -911, /* "MGF1" */ -388, /* "Mail" */ -393, /* "NULL" */ -404, /* "NULL" */ -57, /* "Netscape" */ -366, /* "Nonce" */ -17, /* "O" */ -178, /* "OCSP" */ -180, /* "OCSPSigning" */ -379, /* "ORG" */ -18, /* "OU" */ -749, /* "Oakley-EC2N-3" */ -750, /* "Oakley-EC2N-4" */ - 9, /* "PBE-MD2-DES" */ -168, /* "PBE-MD2-RC2-64" */ -10, /* "PBE-MD5-DES" */ -169, /* "PBE-MD5-RC2-64" */ -147, /* "PBE-SHA1-2DES" */ -146, /* "PBE-SHA1-3DES" */ -170, /* "PBE-SHA1-DES" */ -148, /* "PBE-SHA1-RC2-128" */ -149, /* "PBE-SHA1-RC2-40" */ -68, /* "PBE-SHA1-RC2-64" */ -144, /* "PBE-SHA1-RC4-128" */ -145, /* "PBE-SHA1-RC4-40" */ -161, /* "PBES2" */ -69, /* "PBKDF2" */ -162, /* "PBMAC1" */ -127, /* "PKIX" */ -935, /* "PSPECIFIED" */ -98, /* "RC2-40-CBC" */ -166, /* "RC2-64-CBC" */ -37, /* "RC2-CBC" */ -39, /* "RC2-CFB" */ -38, /* "RC2-ECB" */ -40, /* "RC2-OFB" */ - 5, /* "RC4" */ -97, /* "RC4-40" */ -915, /* "RC4-HMAC-MD5" */ -120, /* "RC5-CBC" */ -122, /* "RC5-CFB" */ -121, /* "RC5-ECB" */ -123, /* "RC5-OFB" */ -117, /* "RIPEMD160" */ -19, /* "RSA" */ - 7, /* "RSA-MD2" */ -396, /* "RSA-MD4" */ - 8, /* "RSA-MD5" */ -96, /* "RSA-MDC2" */ -104, /* "RSA-NP-MD5" */ -119, /* "RSA-RIPEMD160" */ -42, /* "RSA-SHA" */ -65, /* "RSA-SHA1" */ -115, /* "RSA-SHA1-2" */ -671, /* "RSA-SHA224" */ -668, /* "RSA-SHA256" */ -669, /* "RSA-SHA384" */ -670, /* "RSA-SHA512" */ -919, /* "RSAES-OAEP" */ -912, /* "RSASSA-PSS" */ -777, /* "SEED-CBC" */ -779, /* "SEED-CFB" */ -776, /* "SEED-ECB" */ -778, /* "SEED-OFB" */ -41, /* "SHA" */ -64, /* "SHA1" */ -675, /* "SHA224" */ -672, /* "SHA256" */ -673, /* "SHA384" */ -674, /* "SHA512" */ -188, /* "SMIME" */ -167, /* "SMIME-CAPS" */ -100, /* "SN" */ -16, /* "ST" */ -143, /* "SXNetID" */ -458, /* "UID" */ - 0, /* "UNDEF" */ -948, /* "X25519" */ -11, /* "X500" */ -378, /* "X500algorithms" */ -12, /* "X509" */ -184, /* "X9-57" */ -185, /* "X9cm" */ -125, /* "ZLIB" */ -478, /* "aRecord" */ -289, /* "aaControls" */ -287, /* "ac-auditEntity" */ -397, /* "ac-proxying" */ -288, /* "ac-targeting" */ -368, /* "acceptableResponses" */ -446, /* "account" */ -363, /* "ad_timestamping" */ -376, /* "algorithm" */ -405, /* "ansi-X9-62" */ -910, /* "anyExtendedKeyUsage" */ -746, /* "anyPolicy" */ -370, /* "archiveCutoff" */ -484, /* "associatedDomain" */ -485, /* "associatedName" */ -501, /* "audio" */ -177, /* "authorityInfoAccess" */ -90, /* "authorityKeyIdentifier" */ -882, /* "authorityRevocationList" */ -87, /* "basicConstraints" */ -365, /* "basicOCSPResponse" */ -285, /* "biometricInfo" */ -921, /* "brainpoolP160r1" */ -922, /* "brainpoolP160t1" */ -923, /* "brainpoolP192r1" */ -924, /* "brainpoolP192t1" */ -925, /* "brainpoolP224r1" */ -926, /* "brainpoolP224t1" */ -927, /* "brainpoolP256r1" */ -928, /* "brainpoolP256t1" */ -929, /* "brainpoolP320r1" */ -930, /* "brainpoolP320t1" */ -931, /* "brainpoolP384r1" */ -932, /* "brainpoolP384t1" */ -933, /* "brainpoolP512r1" */ -934, /* "brainpoolP512t1" */ -494, /* "buildingName" */ -860, /* "businessCategory" */ -691, /* "c2onb191v4" */ -692, /* "c2onb191v5" */ -697, /* "c2onb239v4" */ -698, /* "c2onb239v5" */ -684, /* "c2pnb163v1" */ -685, /* "c2pnb163v2" */ -686, /* "c2pnb163v3" */ -687, /* "c2pnb176v1" */ -693, /* "c2pnb208w1" */ -699, /* "c2pnb272w1" */ -700, /* "c2pnb304w1" */ -702, /* "c2pnb368w1" */ -688, /* "c2tnb191v1" */ -689, /* "c2tnb191v2" */ -690, /* "c2tnb191v3" */ -694, /* "c2tnb239v1" */ -695, /* "c2tnb239v2" */ -696, /* "c2tnb239v3" */ -701, /* "c2tnb359v1" */ -703, /* "c2tnb431r1" */ -881, /* "cACertificate" */ -483, /* "cNAMERecord" */ -179, /* "caIssuers" */ -785, /* "caRepository" */ -443, /* "caseIgnoreIA5StringSyntax" */ -152, /* "certBag" */ -677, /* "certicom-arc" */ -771, /* "certificateIssuer" */ -89, /* "certificatePolicies" */ -883, /* "certificateRevocationList" */ -54, /* "challengePassword" */ -407, /* "characteristic-two-field" */ -395, /* "clearance" */ -130, /* "clientAuth" */ -131, /* "codeSigning" */ -50, /* "contentType" */ -53, /* "countersignature" */ -153, /* "crlBag" */ -103, /* "crlDistributionPoints" */ -88, /* "crlNumber" */ -884, /* "crossCertificatePair" */ -806, /* "cryptocom" */ -805, /* "cryptopro" */ -500, /* "dITRedirect" */ -451, /* "dNSDomain" */ -495, /* "dSAQuality" */ -434, /* "data" */ -390, /* "dcobject" */ -140, /* "deltaCRL" */ -891, /* "deltaRevocationList" */ -107, /* "description" */ -871, /* "destinationIndicator" */ -947, /* "dh-cofactor-kdf" */ -946, /* "dh-std-kdf" */ -28, /* "dhKeyAgreement" */ -941, /* "dhSinglePass-cofactorDH-sha1kdf-scheme" */ -942, /* "dhSinglePass-cofactorDH-sha224kdf-scheme" */ -943, /* "dhSinglePass-cofactorDH-sha256kdf-scheme" */ -944, /* "dhSinglePass-cofactorDH-sha384kdf-scheme" */ -945, /* "dhSinglePass-cofactorDH-sha512kdf-scheme" */ -936, /* "dhSinglePass-stdDH-sha1kdf-scheme" */ -937, /* "dhSinglePass-stdDH-sha224kdf-scheme" */ -938, /* "dhSinglePass-stdDH-sha256kdf-scheme" */ -939, /* "dhSinglePass-stdDH-sha384kdf-scheme" */ -940, /* "dhSinglePass-stdDH-sha512kdf-scheme" */ -920, /* "dhpublicnumber" */ -382, /* "directory" */ -887, /* "distinguishedName" */ -892, /* "dmdName" */ -174, /* "dnQualifier" */ -447, /* "document" */ -471, /* "documentAuthor" */ -468, /* "documentIdentifier" */ -472, /* "documentLocation" */ -502, /* "documentPublisher" */ -449, /* "documentSeries" */ -469, /* "documentTitle" */ -470, /* "documentVersion" */ -392, /* "domain" */ -452, /* "domainRelatedObject" */ -802, /* "dsa_with_SHA224" */ -803, /* "dsa_with_SHA256" */ -791, /* "ecdsa-with-Recommended" */ -416, /* "ecdsa-with-SHA1" */ -793, /* "ecdsa-with-SHA224" */ -794, /* "ecdsa-with-SHA256" */ -795, /* "ecdsa-with-SHA384" */ -796, /* "ecdsa-with-SHA512" */ -792, /* "ecdsa-with-Specified" */ -48, /* "emailAddress" */ -132, /* "emailProtection" */ -885, /* "enhancedSearchGuide" */ -389, /* "enterprises" */ -384, /* "experimental" */ -172, /* "extReq" */ -56, /* "extendedCertificateAttributes" */ -126, /* "extendedKeyUsage" */ -372, /* "extendedStatus" */ -867, /* "facsimileTelephoneNumber" */ -462, /* "favouriteDrink" */ -857, /* "freshestCRL" */ -453, /* "friendlyCountry" */ -490, /* "friendlyCountryName" */ -156, /* "friendlyName" */ -509, /* "generationQualifier" */ -815, /* "gost-mac" */ -811, /* "gost2001" */ -851, /* "gost2001cc" */ -813, /* "gost89" */ -814, /* "gost89-cnt" */ -812, /* "gost94" */ -850, /* "gost94cc" */ -797, /* "hmacWithMD5" */ -163, /* "hmacWithSHA1" */ -798, /* "hmacWithSHA224" */ -799, /* "hmacWithSHA256" */ -800, /* "hmacWithSHA384" */ -801, /* "hmacWithSHA512" */ -432, /* "holdInstructionCallIssuer" */ -430, /* "holdInstructionCode" */ -431, /* "holdInstructionNone" */ -433, /* "holdInstructionReject" */ -486, /* "homePostalAddress" */ -473, /* "homeTelephoneNumber" */ -466, /* "host" */ -889, /* "houseIdentifier" */ -442, /* "iA5StringSyntax" */ -783, /* "id-DHBasedMac" */ -824, /* "id-Gost28147-89-CryptoPro-A-ParamSet" */ -825, /* "id-Gost28147-89-CryptoPro-B-ParamSet" */ -826, /* "id-Gost28147-89-CryptoPro-C-ParamSet" */ -827, /* "id-Gost28147-89-CryptoPro-D-ParamSet" */ -819, /* "id-Gost28147-89-CryptoPro-KeyMeshing" */ -829, /* "id-Gost28147-89-CryptoPro-Oscar-1-0-ParamSet" */ -828, /* "id-Gost28147-89-CryptoPro-Oscar-1-1-ParamSet" */ -830, /* "id-Gost28147-89-CryptoPro-RIC-1-ParamSet" */ -820, /* "id-Gost28147-89-None-KeyMeshing" */ -823, /* "id-Gost28147-89-TestParamSet" */ -849, /* "id-Gost28147-89-cc" */ -840, /* "id-GostR3410-2001-CryptoPro-A-ParamSet" */ -841, /* "id-GostR3410-2001-CryptoPro-B-ParamSet" */ -842, /* "id-GostR3410-2001-CryptoPro-C-ParamSet" */ -843, /* "id-GostR3410-2001-CryptoPro-XchA-ParamSet" */ -844, /* "id-GostR3410-2001-CryptoPro-XchB-ParamSet" */ -854, /* "id-GostR3410-2001-ParamSet-cc" */ -839, /* "id-GostR3410-2001-TestParamSet" */ -817, /* "id-GostR3410-2001DH" */ -832, /* "id-GostR3410-94-CryptoPro-A-ParamSet" */ -833, /* "id-GostR3410-94-CryptoPro-B-ParamSet" */ -834, /* "id-GostR3410-94-CryptoPro-C-ParamSet" */ -835, /* "id-GostR3410-94-CryptoPro-D-ParamSet" */ -836, /* "id-GostR3410-94-CryptoPro-XchA-ParamSet" */ -837, /* "id-GostR3410-94-CryptoPro-XchB-ParamSet" */ -838, /* "id-GostR3410-94-CryptoPro-XchC-ParamSet" */ -831, /* "id-GostR3410-94-TestParamSet" */ -845, /* "id-GostR3410-94-a" */ -846, /* "id-GostR3410-94-aBis" */ -847, /* "id-GostR3410-94-b" */ -848, /* "id-GostR3410-94-bBis" */ -818, /* "id-GostR3410-94DH" */ -822, /* "id-GostR3411-94-CryptoProParamSet" */ -821, /* "id-GostR3411-94-TestParamSet" */ -807, /* "id-GostR3411-94-with-GostR3410-2001" */ -853, /* "id-GostR3411-94-with-GostR3410-2001-cc" */ -808, /* "id-GostR3411-94-with-GostR3410-94" */ -852, /* "id-GostR3411-94-with-GostR3410-94-cc" */ -810, /* "id-HMACGostR3411-94" */ -782, /* "id-PasswordBasedMAC" */ -266, /* "id-aca" */ -355, /* "id-aca-accessIdentity" */ -354, /* "id-aca-authenticationInfo" */ -356, /* "id-aca-chargingIdentity" */ -399, /* "id-aca-encAttrs" */ -357, /* "id-aca-group" */ -358, /* "id-aca-role" */ -176, /* "id-ad" */ -896, /* "id-aes128-CCM" */ -895, /* "id-aes128-GCM" */ -788, /* "id-aes128-wrap" */ -897, /* "id-aes128-wrap-pad" */ -899, /* "id-aes192-CCM" */ -898, /* "id-aes192-GCM" */ -789, /* "id-aes192-wrap" */ -900, /* "id-aes192-wrap-pad" */ -902, /* "id-aes256-CCM" */ -901, /* "id-aes256-GCM" */ -790, /* "id-aes256-wrap" */ -903, /* "id-aes256-wrap-pad" */ -262, /* "id-alg" */ -893, /* "id-alg-PWRI-KEK" */ -323, /* "id-alg-des40" */ -326, /* "id-alg-dh-pop" */ -325, /* "id-alg-dh-sig-hmac-sha1" */ -324, /* "id-alg-noSignature" */ -907, /* "id-camellia128-wrap" */ -908, /* "id-camellia192-wrap" */ -909, /* "id-camellia256-wrap" */ -268, /* "id-cct" */ -361, /* "id-cct-PKIData" */ -362, /* "id-cct-PKIResponse" */ -360, /* "id-cct-crs" */ -81, /* "id-ce" */ -680, /* "id-characteristic-two-basis" */ -263, /* "id-cmc" */ -334, /* "id-cmc-addExtensions" */ -346, /* "id-cmc-confirmCertAcceptance" */ -330, /* "id-cmc-dataReturn" */ -336, /* "id-cmc-decryptedPOP" */ -335, /* "id-cmc-encryptedPOP" */ -339, /* "id-cmc-getCRL" */ -338, /* "id-cmc-getCert" */ -328, /* "id-cmc-identification" */ -329, /* "id-cmc-identityProof" */ -337, /* "id-cmc-lraPOPWitness" */ -344, /* "id-cmc-popLinkRandom" */ -345, /* "id-cmc-popLinkWitness" */ -343, /* "id-cmc-queryPending" */ -333, /* "id-cmc-recipientNonce" */ -341, /* "id-cmc-regInfo" */ -342, /* "id-cmc-responseInfo" */ -340, /* "id-cmc-revokeRequest" */ -332, /* "id-cmc-senderNonce" */ -327, /* "id-cmc-statusInfo" */ -331, /* "id-cmc-transactionId" */ -787, /* "id-ct-asciiTextWithCRLF" */ -408, /* "id-ecPublicKey" */ -508, /* "id-hex-multipart-message" */ -507, /* "id-hex-partial-message" */ -260, /* "id-it" */ -302, /* "id-it-caKeyUpdateInfo" */ -298, /* "id-it-caProtEncCert" */ -311, /* "id-it-confirmWaitTime" */ -303, /* "id-it-currentCRL" */ -300, /* "id-it-encKeyPairTypes" */ -310, /* "id-it-implicitConfirm" */ -308, /* "id-it-keyPairParamRep" */ -307, /* "id-it-keyPairParamReq" */ -312, /* "id-it-origPKIMessage" */ -301, /* "id-it-preferredSymmAlg" */ -309, /* "id-it-revPassphrase" */ -299, /* "id-it-signKeyPairTypes" */ -305, /* "id-it-subscriptionRequest" */ -306, /* "id-it-subscriptionResponse" */ -784, /* "id-it-suppLangTags" */ -304, /* "id-it-unsupportedOIDs" */ -128, /* "id-kp" */ -280, /* "id-mod-attribute-cert" */ -274, /* "id-mod-cmc" */ -277, /* "id-mod-cmp" */ -284, /* "id-mod-cmp2000" */ -273, /* "id-mod-crmf" */ -283, /* "id-mod-dvcs" */ -275, /* "id-mod-kea-profile-88" */ -276, /* "id-mod-kea-profile-93" */ -282, /* "id-mod-ocsp" */ -278, /* "id-mod-qualified-cert-88" */ -279, /* "id-mod-qualified-cert-93" */ -281, /* "id-mod-timestamp-protocol" */ -264, /* "id-on" */ -858, /* "id-on-permanentIdentifier" */ -347, /* "id-on-personalData" */ -265, /* "id-pda" */ -352, /* "id-pda-countryOfCitizenship" */ -353, /* "id-pda-countryOfResidence" */ -348, /* "id-pda-dateOfBirth" */ -351, /* "id-pda-gender" */ -349, /* "id-pda-placeOfBirth" */ -175, /* "id-pe" */ -261, /* "id-pkip" */ -258, /* "id-pkix-mod" */ -269, /* "id-pkix1-explicit-88" */ -271, /* "id-pkix1-explicit-93" */ -270, /* "id-pkix1-implicit-88" */ -272, /* "id-pkix1-implicit-93" */ -662, /* "id-ppl" */ -664, /* "id-ppl-anyLanguage" */ -667, /* "id-ppl-independent" */ -665, /* "id-ppl-inheritAll" */ -267, /* "id-qcs" */ -359, /* "id-qcs-pkixQCSyntax-v1" */ -259, /* "id-qt" */ -164, /* "id-qt-cps" */ -165, /* "id-qt-unotice" */ -313, /* "id-regCtrl" */ -316, /* "id-regCtrl-authenticator" */ -319, /* "id-regCtrl-oldCertID" */ -318, /* "id-regCtrl-pkiArchiveOptions" */ -317, /* "id-regCtrl-pkiPublicationInfo" */ -320, /* "id-regCtrl-protocolEncrKey" */ -315, /* "id-regCtrl-regToken" */ -314, /* "id-regInfo" */ -322, /* "id-regInfo-certReq" */ -321, /* "id-regInfo-utf8Pairs" */ -512, /* "id-set" */ -191, /* "id-smime-aa" */ -215, /* "id-smime-aa-contentHint" */ -218, /* "id-smime-aa-contentIdentifier" */ -221, /* "id-smime-aa-contentReference" */ -240, /* "id-smime-aa-dvcs-dvc" */ -217, /* "id-smime-aa-encapContentType" */ -222, /* "id-smime-aa-encrypKeyPref" */ -220, /* "id-smime-aa-equivalentLabels" */ -232, /* "id-smime-aa-ets-CertificateRefs" */ -233, /* "id-smime-aa-ets-RevocationRefs" */ -238, /* "id-smime-aa-ets-archiveTimeStamp" */ -237, /* "id-smime-aa-ets-certCRLTimestamp" */ -234, /* "id-smime-aa-ets-certValues" */ -227, /* "id-smime-aa-ets-commitmentType" */ -231, /* "id-smime-aa-ets-contentTimestamp" */ -236, /* "id-smime-aa-ets-escTimeStamp" */ -230, /* "id-smime-aa-ets-otherSigCert" */ -235, /* "id-smime-aa-ets-revocationValues" */ -226, /* "id-smime-aa-ets-sigPolicyId" */ -229, /* "id-smime-aa-ets-signerAttr" */ -228, /* "id-smime-aa-ets-signerLocation" */ -219, /* "id-smime-aa-macValue" */ -214, /* "id-smime-aa-mlExpandHistory" */ -216, /* "id-smime-aa-msgSigDigest" */ -212, /* "id-smime-aa-receiptRequest" */ -213, /* "id-smime-aa-securityLabel" */ -239, /* "id-smime-aa-signatureType" */ -223, /* "id-smime-aa-signingCertificate" */ -224, /* "id-smime-aa-smimeEncryptCerts" */ -225, /* "id-smime-aa-timeStampToken" */ -192, /* "id-smime-alg" */ -243, /* "id-smime-alg-3DESwrap" */ -246, /* "id-smime-alg-CMS3DESwrap" */ -247, /* "id-smime-alg-CMSRC2wrap" */ -245, /* "id-smime-alg-ESDH" */ -241, /* "id-smime-alg-ESDHwith3DES" */ -242, /* "id-smime-alg-ESDHwithRC2" */ -244, /* "id-smime-alg-RC2wrap" */ -193, /* "id-smime-cd" */ -248, /* "id-smime-cd-ldap" */ -190, /* "id-smime-ct" */ -210, /* "id-smime-ct-DVCSRequestData" */ -211, /* "id-smime-ct-DVCSResponseData" */ -208, /* "id-smime-ct-TDTInfo" */ -207, /* "id-smime-ct-TSTInfo" */ -205, /* "id-smime-ct-authData" */ -786, /* "id-smime-ct-compressedData" */ -209, /* "id-smime-ct-contentInfo" */ -206, /* "id-smime-ct-publishCert" */ -204, /* "id-smime-ct-receipt" */ -195, /* "id-smime-cti" */ -255, /* "id-smime-cti-ets-proofOfApproval" */ -256, /* "id-smime-cti-ets-proofOfCreation" */ -253, /* "id-smime-cti-ets-proofOfDelivery" */ -251, /* "id-smime-cti-ets-proofOfOrigin" */ -252, /* "id-smime-cti-ets-proofOfReceipt" */ -254, /* "id-smime-cti-ets-proofOfSender" */ -189, /* "id-smime-mod" */ -196, /* "id-smime-mod-cms" */ -197, /* "id-smime-mod-ess" */ -202, /* "id-smime-mod-ets-eSigPolicy-88" */ -203, /* "id-smime-mod-ets-eSigPolicy-97" */ -200, /* "id-smime-mod-ets-eSignature-88" */ -201, /* "id-smime-mod-ets-eSignature-97" */ -199, /* "id-smime-mod-msg-v3" */ -198, /* "id-smime-mod-oid" */ -194, /* "id-smime-spq" */ -250, /* "id-smime-spq-ets-sqt-unotice" */ -249, /* "id-smime-spq-ets-sqt-uri" */ -676, /* "identified-organization" */ -461, /* "info" */ -748, /* "inhibitAnyPolicy" */ -101, /* "initials" */ -647, /* "international-organizations" */ -869, /* "internationaliSDNNumber" */ -142, /* "invalidityDate" */ -294, /* "ipsecEndSystem" */ -295, /* "ipsecTunnel" */ -296, /* "ipsecUser" */ -86, /* "issuerAltName" */ -770, /* "issuingDistributionPoint" */ -492, /* "janetMailbox" */ -150, /* "keyBag" */ -83, /* "keyUsage" */ -477, /* "lastModifiedBy" */ -476, /* "lastModifiedTime" */ -157, /* "localKeyID" */ -480, /* "mXRecord" */ -460, /* "mail" */ -493, /* "mailPreferenceOption" */ -467, /* "manager" */ -809, /* "md_gost94" */ -875, /* "member" */ -182, /* "member-body" */ -51, /* "messageDigest" */ -383, /* "mgmt" */ -504, /* "mime-mhs" */ -506, /* "mime-mhs-bodies" */ -505, /* "mime-mhs-headings" */ -488, /* "mobileTelephoneNumber" */ -136, /* "msCTLSign" */ -135, /* "msCodeCom" */ -134, /* "msCodeInd" */ -138, /* "msEFS" */ -171, /* "msExtReq" */ -137, /* "msSGC" */ -648, /* "msSmartcardLogin" */ -649, /* "msUPN" */ -481, /* "nSRecord" */ -173, /* "name" */ -666, /* "nameConstraints" */ -369, /* "noCheck" */ -403, /* "noRevAvail" */ -72, /* "nsBaseUrl" */ -76, /* "nsCaPolicyUrl" */ -74, /* "nsCaRevocationUrl" */ -58, /* "nsCertExt" */ -79, /* "nsCertSequence" */ -71, /* "nsCertType" */ -78, /* "nsComment" */ -59, /* "nsDataType" */ -75, /* "nsRenewalUrl" */ -73, /* "nsRevocationUrl" */ -139, /* "nsSGC" */ -77, /* "nsSslServerName" */ -681, /* "onBasis" */ -491, /* "organizationalStatus" */ -475, /* "otherMailbox" */ -876, /* "owner" */ -489, /* "pagerTelephoneNumber" */ -374, /* "path" */ -112, /* "pbeWithMD5AndCast5CBC" */ -499, /* "personalSignature" */ -487, /* "personalTitle" */ -464, /* "photo" */ -863, /* "physicalDeliveryOfficeName" */ -437, /* "pilot" */ -439, /* "pilotAttributeSyntax" */ -438, /* "pilotAttributeType" */ -479, /* "pilotAttributeType27" */ -456, /* "pilotDSA" */ -441, /* "pilotGroups" */ -444, /* "pilotObject" */ -440, /* "pilotObjectClass" */ -455, /* "pilotOrganization" */ -445, /* "pilotPerson" */ - 2, /* "pkcs" */ -186, /* "pkcs1" */ -27, /* "pkcs3" */ -187, /* "pkcs5" */ -20, /* "pkcs7" */ -21, /* "pkcs7-data" */ -25, /* "pkcs7-digestData" */ -26, /* "pkcs7-encryptedData" */ -23, /* "pkcs7-envelopedData" */ -24, /* "pkcs7-signedAndEnvelopedData" */ -22, /* "pkcs7-signedData" */ -151, /* "pkcs8ShroudedKeyBag" */ -47, /* "pkcs9" */ -401, /* "policyConstraints" */ -747, /* "policyMappings" */ -862, /* "postOfficeBox" */ -861, /* "postalAddress" */ -661, /* "postalCode" */ -683, /* "ppBasis" */ -872, /* "preferredDeliveryMethod" */ -873, /* "presentationAddress" */ -816, /* "prf-gostr3411-94" */ -406, /* "prime-field" */ -409, /* "prime192v1" */ -410, /* "prime192v2" */ -411, /* "prime192v3" */ -412, /* "prime239v1" */ -413, /* "prime239v2" */ -414, /* "prime239v3" */ -415, /* "prime256v1" */ -385, /* "private" */ -84, /* "privateKeyUsagePeriod" */ -886, /* "protocolInformation" */ -663, /* "proxyCertInfo" */ -510, /* "pseudonym" */ -435, /* "pss" */ -286, /* "qcStatements" */ -457, /* "qualityLabelledData" */ -450, /* "rFC822localPart" */ -870, /* "registeredAddress" */ -400, /* "role" */ -877, /* "roleOccupant" */ -448, /* "room" */ -463, /* "roomNumber" */ - 6, /* "rsaEncryption" */ -644, /* "rsaOAEPEncryptionSET" */ -377, /* "rsaSignature" */ - 1, /* "rsadsi" */ -482, /* "sOARecord" */ -155, /* "safeContentsBag" */ -291, /* "sbgp-autonomousSysNum" */ -290, /* "sbgp-ipAddrBlock" */ -292, /* "sbgp-routerIdentifier" */ -159, /* "sdsiCertificate" */ -859, /* "searchGuide" */ -704, /* "secp112r1" */ -705, /* "secp112r2" */ -706, /* "secp128r1" */ -707, /* "secp128r2" */ -708, /* "secp160k1" */ -709, /* "secp160r1" */ -710, /* "secp160r2" */ -711, /* "secp192k1" */ -712, /* "secp224k1" */ -713, /* "secp224r1" */ -714, /* "secp256k1" */ -715, /* "secp384r1" */ -716, /* "secp521r1" */ -154, /* "secretBag" */ -474, /* "secretary" */ -717, /* "sect113r1" */ -718, /* "sect113r2" */ -719, /* "sect131r1" */ -720, /* "sect131r2" */ -721, /* "sect163k1" */ -722, /* "sect163r1" */ -723, /* "sect163r2" */ -724, /* "sect193r1" */ -725, /* "sect193r2" */ -726, /* "sect233k1" */ -727, /* "sect233r1" */ -728, /* "sect239k1" */ -729, /* "sect283k1" */ -730, /* "sect283r1" */ -731, /* "sect409k1" */ -732, /* "sect409r1" */ -733, /* "sect571k1" */ -734, /* "sect571r1" */ -386, /* "security" */ -878, /* "seeAlso" */ -394, /* "selected-attribute-types" */ -105, /* "serialNumber" */ -129, /* "serverAuth" */ -371, /* "serviceLocator" */ -625, /* "set-addPolicy" */ -515, /* "set-attr" */ -518, /* "set-brand" */ -638, /* "set-brand-AmericanExpress" */ -637, /* "set-brand-Diners" */ -636, /* "set-brand-IATA-ATA" */ -639, /* "set-brand-JCB" */ -641, /* "set-brand-MasterCard" */ -642, /* "set-brand-Novus" */ -640, /* "set-brand-Visa" */ -517, /* "set-certExt" */ -513, /* "set-ctype" */ -514, /* "set-msgExt" */ -516, /* "set-policy" */ -607, /* "set-policy-root" */ -624, /* "set-rootKeyThumb" */ -620, /* "setAttr-Cert" */ -631, /* "setAttr-GenCryptgrm" */ -623, /* "setAttr-IssCap" */ -628, /* "setAttr-IssCap-CVM" */ -630, /* "setAttr-IssCap-Sig" */ -629, /* "setAttr-IssCap-T2" */ -621, /* "setAttr-PGWYcap" */ -635, /* "setAttr-SecDevSig" */ -632, /* "setAttr-T2Enc" */ -633, /* "setAttr-T2cleartxt" */ -634, /* "setAttr-TokICCsig" */ -627, /* "setAttr-Token-B0Prime" */ -626, /* "setAttr-Token-EMV" */ -622, /* "setAttr-TokenType" */ -619, /* "setCext-IssuerCapabilities" */ -615, /* "setCext-PGWYcapabilities" */ -616, /* "setCext-TokenIdentifier" */ -618, /* "setCext-TokenType" */ -617, /* "setCext-Track2Data" */ -611, /* "setCext-cCertRequired" */ -609, /* "setCext-certType" */ -608, /* "setCext-hashedRoot" */ -610, /* "setCext-merchData" */ -613, /* "setCext-setExt" */ -614, /* "setCext-setQualf" */ -612, /* "setCext-tunneling" */ -540, /* "setct-AcqCardCodeMsg" */ -576, /* "setct-AcqCardCodeMsgTBE" */ -570, /* "setct-AuthReqTBE" */ -534, /* "setct-AuthReqTBS" */ -527, /* "setct-AuthResBaggage" */ -571, /* "setct-AuthResTBE" */ -572, /* "setct-AuthResTBEX" */ -535, /* "setct-AuthResTBS" */ -536, /* "setct-AuthResTBSX" */ -528, /* "setct-AuthRevReqBaggage" */ -577, /* "setct-AuthRevReqTBE" */ -541, /* "setct-AuthRevReqTBS" */ -529, /* "setct-AuthRevResBaggage" */ -542, /* "setct-AuthRevResData" */ -578, /* "setct-AuthRevResTBE" */ -579, /* "setct-AuthRevResTBEB" */ -543, /* "setct-AuthRevResTBS" */ -573, /* "setct-AuthTokenTBE" */ -537, /* "setct-AuthTokenTBS" */ -600, /* "setct-BCIDistributionTBS" */ -558, /* "setct-BatchAdminReqData" */ -592, /* "setct-BatchAdminReqTBE" */ -559, /* "setct-BatchAdminResData" */ -593, /* "setct-BatchAdminResTBE" */ -599, /* "setct-CRLNotificationResTBS" */ -598, /* "setct-CRLNotificationTBS" */ -580, /* "setct-CapReqTBE" */ -581, /* "setct-CapReqTBEX" */ -544, /* "setct-CapReqTBS" */ -545, /* "setct-CapReqTBSX" */ -546, /* "setct-CapResData" */ -582, /* "setct-CapResTBE" */ -583, /* "setct-CapRevReqTBE" */ -584, /* "setct-CapRevReqTBEX" */ -547, /* "setct-CapRevReqTBS" */ -548, /* "setct-CapRevReqTBSX" */ -549, /* "setct-CapRevResData" */ -585, /* "setct-CapRevResTBE" */ -538, /* "setct-CapTokenData" */ -530, /* "setct-CapTokenSeq" */ -574, /* "setct-CapTokenTBE" */ -575, /* "setct-CapTokenTBEX" */ -539, /* "setct-CapTokenTBS" */ -560, /* "setct-CardCInitResTBS" */ -566, /* "setct-CertInqReqTBS" */ -563, /* "setct-CertReqData" */ -595, /* "setct-CertReqTBE" */ -596, /* "setct-CertReqTBEX" */ -564, /* "setct-CertReqTBS" */ -565, /* "setct-CertResData" */ -597, /* "setct-CertResTBE" */ -586, /* "setct-CredReqTBE" */ -587, /* "setct-CredReqTBEX" */ -550, /* "setct-CredReqTBS" */ -551, /* "setct-CredReqTBSX" */ -552, /* "setct-CredResData" */ -588, /* "setct-CredResTBE" */ -589, /* "setct-CredRevReqTBE" */ -590, /* "setct-CredRevReqTBEX" */ -553, /* "setct-CredRevReqTBS" */ -554, /* "setct-CredRevReqTBSX" */ -555, /* "setct-CredRevResData" */ -591, /* "setct-CredRevResTBE" */ -567, /* "setct-ErrorTBS" */ -526, /* "setct-HODInput" */ -561, /* "setct-MeAqCInitResTBS" */ -522, /* "setct-OIData" */ -519, /* "setct-PANData" */ -521, /* "setct-PANOnly" */ -520, /* "setct-PANToken" */ -556, /* "setct-PCertReqData" */ -557, /* "setct-PCertResTBS" */ -523, /* "setct-PI" */ -532, /* "setct-PI-TBS" */ -524, /* "setct-PIData" */ -525, /* "setct-PIDataUnsigned" */ -568, /* "setct-PIDualSignedTBE" */ -569, /* "setct-PIUnsignedTBE" */ -531, /* "setct-PInitResData" */ -533, /* "setct-PResData" */ -594, /* "setct-RegFormReqTBE" */ -562, /* "setct-RegFormResTBS" */ -606, /* "setext-cv" */ -601, /* "setext-genCrypt" */ -602, /* "setext-miAuth" */ -604, /* "setext-pinAny" */ -603, /* "setext-pinSecure" */ -605, /* "setext-track2" */ -52, /* "signingTime" */ -454, /* "simpleSecurityObject" */ -496, /* "singleLevelQuality" */ -387, /* "snmpv2" */ -660, /* "street" */ -85, /* "subjectAltName" */ -769, /* "subjectDirectoryAttributes" */ -398, /* "subjectInfoAccess" */ -82, /* "subjectKeyIdentifier" */ -498, /* "subtreeMaximumQuality" */ -497, /* "subtreeMinimumQuality" */ -890, /* "supportedAlgorithms" */ -874, /* "supportedApplicationContext" */ -402, /* "targetInformation" */ -864, /* "telephoneNumber" */ -866, /* "teletexTerminalIdentifier" */ -865, /* "telexNumber" */ -459, /* "textEncodedORAddress" */ -293, /* "textNotice" */ -133, /* "timeStamping" */ -106, /* "title" */ -682, /* "tpBasis" */ -375, /* "trustRoot" */ -436, /* "ucl" */ -888, /* "uniqueMember" */ -55, /* "unstructuredAddress" */ -49, /* "unstructuredName" */ -880, /* "userCertificate" */ -465, /* "userClass" */ -879, /* "userPassword" */ -373, /* "valid" */ -678, /* "wap" */ -679, /* "wap-wsg" */ -735, /* "wap-wsg-idm-ecid-wtls1" */ -743, /* "wap-wsg-idm-ecid-wtls10" */ -744, /* "wap-wsg-idm-ecid-wtls11" */ -745, /* "wap-wsg-idm-ecid-wtls12" */ -736, /* "wap-wsg-idm-ecid-wtls3" */ -737, /* "wap-wsg-idm-ecid-wtls4" */ -738, /* "wap-wsg-idm-ecid-wtls5" */ -739, /* "wap-wsg-idm-ecid-wtls6" */ -740, /* "wap-wsg-idm-ecid-wtls7" */ -741, /* "wap-wsg-idm-ecid-wtls8" */ -742, /* "wap-wsg-idm-ecid-wtls9" */ -804, /* "whirlpool" */ -868, /* "x121Address" */ -503, /* "x500UniqueIdentifier" */ -158, /* "x509Certificate" */ -160, /* "x509Crl" */ +static const unsigned kNIDsInShortNameOrder[] = { + 364 /* AD_DVCS */, + 419 /* AES-128-CBC */, + 916 /* AES-128-CBC-HMAC-SHA1 */, + 421 /* AES-128-CFB */, + 650 /* AES-128-CFB1 */, + 653 /* AES-128-CFB8 */, + 904 /* AES-128-CTR */, + 418 /* AES-128-ECB */, + 420 /* AES-128-OFB */, + 913 /* AES-128-XTS */, + 423 /* AES-192-CBC */, + 917 /* AES-192-CBC-HMAC-SHA1 */, + 425 /* AES-192-CFB */, + 651 /* AES-192-CFB1 */, + 654 /* AES-192-CFB8 */, + 905 /* AES-192-CTR */, + 422 /* AES-192-ECB */, + 424 /* AES-192-OFB */, + 427 /* AES-256-CBC */, + 918 /* AES-256-CBC-HMAC-SHA1 */, + 429 /* AES-256-CFB */, + 652 /* AES-256-CFB1 */, + 655 /* AES-256-CFB8 */, + 906 /* AES-256-CTR */, + 426 /* AES-256-ECB */, + 428 /* AES-256-OFB */, + 914 /* AES-256-XTS */, + 91 /* BF-CBC */, + 93 /* BF-CFB */, + 92 /* BF-ECB */, + 94 /* BF-OFB */, + 14 /* C */, + 751 /* CAMELLIA-128-CBC */, + 757 /* CAMELLIA-128-CFB */, + 760 /* CAMELLIA-128-CFB1 */, + 763 /* CAMELLIA-128-CFB8 */, + 754 /* CAMELLIA-128-ECB */, + 766 /* CAMELLIA-128-OFB */, + 752 /* CAMELLIA-192-CBC */, + 758 /* CAMELLIA-192-CFB */, + 761 /* CAMELLIA-192-CFB1 */, + 764 /* CAMELLIA-192-CFB8 */, + 755 /* CAMELLIA-192-ECB */, + 767 /* CAMELLIA-192-OFB */, + 753 /* CAMELLIA-256-CBC */, + 759 /* CAMELLIA-256-CFB */, + 762 /* CAMELLIA-256-CFB1 */, + 765 /* CAMELLIA-256-CFB8 */, + 756 /* CAMELLIA-256-ECB */, + 768 /* CAMELLIA-256-OFB */, + 108 /* CAST5-CBC */, + 110 /* CAST5-CFB */, + 109 /* CAST5-ECB */, + 111 /* CAST5-OFB */, + 894 /* CMAC */, + 13 /* CN */, + 141 /* CRLReason */, + 417 /* CSPName */, + 367 /* CrlID */, + 391 /* DC */, + 31 /* DES-CBC */, + 643 /* DES-CDMF */, + 30 /* DES-CFB */, + 656 /* DES-CFB1 */, + 657 /* DES-CFB8 */, + 29 /* DES-ECB */, + 32 /* DES-EDE */, + 43 /* DES-EDE-CBC */, + 60 /* DES-EDE-CFB */, + 62 /* DES-EDE-OFB */, + 33 /* DES-EDE3 */, + 44 /* DES-EDE3-CBC */, + 61 /* DES-EDE3-CFB */, + 658 /* DES-EDE3-CFB1 */, + 659 /* DES-EDE3-CFB8 */, + 63 /* DES-EDE3-OFB */, + 45 /* DES-OFB */, + 80 /* DESX-CBC */, + 380 /* DOD */, + 116 /* DSA */, + 66 /* DSA-SHA */, + 113 /* DSA-SHA1 */, + 70 /* DSA-SHA1-old */, + 67 /* DSA-old */, + 297 /* DVCS */, + 99 /* GN */, + 855 /* HMAC */, + 780 /* HMAC-MD5 */, + 781 /* HMAC-SHA1 */, + 381 /* IANA */, + 34 /* IDEA-CBC */, + 35 /* IDEA-CFB */, + 36 /* IDEA-ECB */, + 46 /* IDEA-OFB */, + 181 /* ISO */, + 183 /* ISO-US */, + 645 /* ITU-T */, + 646 /* JOINT-ISO-ITU-T */, + 773 /* KISA */, + 15 /* L */, + 856 /* LocalKeySet */, + 3 /* MD2 */, + 257 /* MD4 */, + 4 /* MD5 */, + 114 /* MD5-SHA1 */, + 95 /* MDC2 */, + 911 /* MGF1 */, + 388 /* Mail */, + 57 /* Netscape */, + 366 /* Nonce */, + 17 /* O */, + 178 /* OCSP */, + 180 /* OCSPSigning */, + 379 /* ORG */, + 18 /* OU */, + 749 /* Oakley-EC2N-3 */, + 750 /* Oakley-EC2N-4 */, + 9 /* PBE-MD2-DES */, + 168 /* PBE-MD2-RC2-64 */, + 10 /* PBE-MD5-DES */, + 169 /* PBE-MD5-RC2-64 */, + 147 /* PBE-SHA1-2DES */, + 146 /* PBE-SHA1-3DES */, + 170 /* PBE-SHA1-DES */, + 148 /* PBE-SHA1-RC2-128 */, + 149 /* PBE-SHA1-RC2-40 */, + 68 /* PBE-SHA1-RC2-64 */, + 144 /* PBE-SHA1-RC4-128 */, + 145 /* PBE-SHA1-RC4-40 */, + 161 /* PBES2 */, + 69 /* PBKDF2 */, + 162 /* PBMAC1 */, + 127 /* PKIX */, + 935 /* PSPECIFIED */, + 98 /* RC2-40-CBC */, + 166 /* RC2-64-CBC */, + 37 /* RC2-CBC */, + 39 /* RC2-CFB */, + 38 /* RC2-ECB */, + 40 /* RC2-OFB */, + 5 /* RC4 */, + 97 /* RC4-40 */, + 915 /* RC4-HMAC-MD5 */, + 120 /* RC5-CBC */, + 122 /* RC5-CFB */, + 121 /* RC5-ECB */, + 123 /* RC5-OFB */, + 117 /* RIPEMD160 */, + 19 /* RSA */, + 7 /* RSA-MD2 */, + 396 /* RSA-MD4 */, + 8 /* RSA-MD5 */, + 96 /* RSA-MDC2 */, + 104 /* RSA-NP-MD5 */, + 119 /* RSA-RIPEMD160 */, + 42 /* RSA-SHA */, + 65 /* RSA-SHA1 */, + 115 /* RSA-SHA1-2 */, + 671 /* RSA-SHA224 */, + 668 /* RSA-SHA256 */, + 669 /* RSA-SHA384 */, + 670 /* RSA-SHA512 */, + 919 /* RSAES-OAEP */, + 912 /* RSASSA-PSS */, + 777 /* SEED-CBC */, + 779 /* SEED-CFB */, + 776 /* SEED-ECB */, + 778 /* SEED-OFB */, + 41 /* SHA */, + 64 /* SHA1 */, + 675 /* SHA224 */, + 672 /* SHA256 */, + 673 /* SHA384 */, + 674 /* SHA512 */, + 188 /* SMIME */, + 167 /* SMIME-CAPS */, + 100 /* SN */, + 16 /* ST */, + 143 /* SXNetID */, + 458 /* UID */, + 0 /* UNDEF */, + 948 /* X25519 */, + 11 /* X500 */, + 378 /* X500algorithms */, + 12 /* X509 */, + 184 /* X9-57 */, + 185 /* X9cm */, + 125 /* ZLIB */, + 478 /* aRecord */, + 289 /* aaControls */, + 287 /* ac-auditEntity */, + 397 /* ac-proxying */, + 288 /* ac-targeting */, + 368 /* acceptableResponses */, + 446 /* account */, + 363 /* ad_timestamping */, + 376 /* algorithm */, + 405 /* ansi-X9-62 */, + 910 /* anyExtendedKeyUsage */, + 746 /* anyPolicy */, + 370 /* archiveCutoff */, + 484 /* associatedDomain */, + 485 /* associatedName */, + 501 /* audio */, + 177 /* authorityInfoAccess */, + 90 /* authorityKeyIdentifier */, + 882 /* authorityRevocationList */, + 87 /* basicConstraints */, + 365 /* basicOCSPResponse */, + 285 /* biometricInfo */, + 921 /* brainpoolP160r1 */, + 922 /* brainpoolP160t1 */, + 923 /* brainpoolP192r1 */, + 924 /* brainpoolP192t1 */, + 925 /* brainpoolP224r1 */, + 926 /* brainpoolP224t1 */, + 927 /* brainpoolP256r1 */, + 928 /* brainpoolP256t1 */, + 929 /* brainpoolP320r1 */, + 930 /* brainpoolP320t1 */, + 931 /* brainpoolP384r1 */, + 932 /* brainpoolP384t1 */, + 933 /* brainpoolP512r1 */, + 934 /* brainpoolP512t1 */, + 494 /* buildingName */, + 860 /* businessCategory */, + 691 /* c2onb191v4 */, + 692 /* c2onb191v5 */, + 697 /* c2onb239v4 */, + 698 /* c2onb239v5 */, + 684 /* c2pnb163v1 */, + 685 /* c2pnb163v2 */, + 686 /* c2pnb163v3 */, + 687 /* c2pnb176v1 */, + 693 /* c2pnb208w1 */, + 699 /* c2pnb272w1 */, + 700 /* c2pnb304w1 */, + 702 /* c2pnb368w1 */, + 688 /* c2tnb191v1 */, + 689 /* c2tnb191v2 */, + 690 /* c2tnb191v3 */, + 694 /* c2tnb239v1 */, + 695 /* c2tnb239v2 */, + 696 /* c2tnb239v3 */, + 701 /* c2tnb359v1 */, + 703 /* c2tnb431r1 */, + 881 /* cACertificate */, + 483 /* cNAMERecord */, + 179 /* caIssuers */, + 785 /* caRepository */, + 443 /* caseIgnoreIA5StringSyntax */, + 152 /* certBag */, + 677 /* certicom-arc */, + 771 /* certificateIssuer */, + 89 /* certificatePolicies */, + 883 /* certificateRevocationList */, + 54 /* challengePassword */, + 407 /* characteristic-two-field */, + 395 /* clearance */, + 130 /* clientAuth */, + 131 /* codeSigning */, + 50 /* contentType */, + 53 /* countersignature */, + 153 /* crlBag */, + 103 /* crlDistributionPoints */, + 88 /* crlNumber */, + 884 /* crossCertificatePair */, + 806 /* cryptocom */, + 805 /* cryptopro */, + 500 /* dITRedirect */, + 451 /* dNSDomain */, + 495 /* dSAQuality */, + 434 /* data */, + 390 /* dcobject */, + 140 /* deltaCRL */, + 891 /* deltaRevocationList */, + 107 /* description */, + 871 /* destinationIndicator */, + 947 /* dh-cofactor-kdf */, + 946 /* dh-std-kdf */, + 28 /* dhKeyAgreement */, + 941 /* dhSinglePass-cofactorDH-sha1kdf-scheme */, + 942 /* dhSinglePass-cofactorDH-sha224kdf-scheme */, + 943 /* dhSinglePass-cofactorDH-sha256kdf-scheme */, + 944 /* dhSinglePass-cofactorDH-sha384kdf-scheme */, + 945 /* dhSinglePass-cofactorDH-sha512kdf-scheme */, + 936 /* dhSinglePass-stdDH-sha1kdf-scheme */, + 937 /* dhSinglePass-stdDH-sha224kdf-scheme */, + 938 /* dhSinglePass-stdDH-sha256kdf-scheme */, + 939 /* dhSinglePass-stdDH-sha384kdf-scheme */, + 940 /* dhSinglePass-stdDH-sha512kdf-scheme */, + 920 /* dhpublicnumber */, + 382 /* directory */, + 887 /* distinguishedName */, + 892 /* dmdName */, + 174 /* dnQualifier */, + 447 /* document */, + 471 /* documentAuthor */, + 468 /* documentIdentifier */, + 472 /* documentLocation */, + 502 /* documentPublisher */, + 449 /* documentSeries */, + 469 /* documentTitle */, + 470 /* documentVersion */, + 392 /* domain */, + 452 /* domainRelatedObject */, + 802 /* dsa_with_SHA224 */, + 803 /* dsa_with_SHA256 */, + 791 /* ecdsa-with-Recommended */, + 416 /* ecdsa-with-SHA1 */, + 793 /* ecdsa-with-SHA224 */, + 794 /* ecdsa-with-SHA256 */, + 795 /* ecdsa-with-SHA384 */, + 796 /* ecdsa-with-SHA512 */, + 792 /* ecdsa-with-Specified */, + 48 /* emailAddress */, + 132 /* emailProtection */, + 885 /* enhancedSearchGuide */, + 389 /* enterprises */, + 384 /* experimental */, + 172 /* extReq */, + 56 /* extendedCertificateAttributes */, + 126 /* extendedKeyUsage */, + 372 /* extendedStatus */, + 867 /* facsimileTelephoneNumber */, + 462 /* favouriteDrink */, + 857 /* freshestCRL */, + 453 /* friendlyCountry */, + 490 /* friendlyCountryName */, + 156 /* friendlyName */, + 509 /* generationQualifier */, + 815 /* gost-mac */, + 811 /* gost2001 */, + 851 /* gost2001cc */, + 813 /* gost89 */, + 814 /* gost89-cnt */, + 812 /* gost94 */, + 850 /* gost94cc */, + 797 /* hmacWithMD5 */, + 163 /* hmacWithSHA1 */, + 798 /* hmacWithSHA224 */, + 799 /* hmacWithSHA256 */, + 800 /* hmacWithSHA384 */, + 801 /* hmacWithSHA512 */, + 432 /* holdInstructionCallIssuer */, + 430 /* holdInstructionCode */, + 431 /* holdInstructionNone */, + 433 /* holdInstructionReject */, + 486 /* homePostalAddress */, + 473 /* homeTelephoneNumber */, + 466 /* host */, + 889 /* houseIdentifier */, + 442 /* iA5StringSyntax */, + 783 /* id-DHBasedMac */, + 824 /* id-Gost28147-89-CryptoPro-A-ParamSet */, + 825 /* id-Gost28147-89-CryptoPro-B-ParamSet */, + 826 /* id-Gost28147-89-CryptoPro-C-ParamSet */, + 827 /* id-Gost28147-89-CryptoPro-D-ParamSet */, + 819 /* id-Gost28147-89-CryptoPro-KeyMeshing */, + 829 /* id-Gost28147-89-CryptoPro-Oscar-1-0-ParamSet */, + 828 /* id-Gost28147-89-CryptoPro-Oscar-1-1-ParamSet */, + 830 /* id-Gost28147-89-CryptoPro-RIC-1-ParamSet */, + 820 /* id-Gost28147-89-None-KeyMeshing */, + 823 /* id-Gost28147-89-TestParamSet */, + 849 /* id-Gost28147-89-cc */, + 840 /* id-GostR3410-2001-CryptoPro-A-ParamSet */, + 841 /* id-GostR3410-2001-CryptoPro-B-ParamSet */, + 842 /* id-GostR3410-2001-CryptoPro-C-ParamSet */, + 843 /* id-GostR3410-2001-CryptoPro-XchA-ParamSet */, + 844 /* id-GostR3410-2001-CryptoPro-XchB-ParamSet */, + 854 /* id-GostR3410-2001-ParamSet-cc */, + 839 /* id-GostR3410-2001-TestParamSet */, + 817 /* id-GostR3410-2001DH */, + 832 /* id-GostR3410-94-CryptoPro-A-ParamSet */, + 833 /* id-GostR3410-94-CryptoPro-B-ParamSet */, + 834 /* id-GostR3410-94-CryptoPro-C-ParamSet */, + 835 /* id-GostR3410-94-CryptoPro-D-ParamSet */, + 836 /* id-GostR3410-94-CryptoPro-XchA-ParamSet */, + 837 /* id-GostR3410-94-CryptoPro-XchB-ParamSet */, + 838 /* id-GostR3410-94-CryptoPro-XchC-ParamSet */, + 831 /* id-GostR3410-94-TestParamSet */, + 845 /* id-GostR3410-94-a */, + 846 /* id-GostR3410-94-aBis */, + 847 /* id-GostR3410-94-b */, + 848 /* id-GostR3410-94-bBis */, + 818 /* id-GostR3410-94DH */, + 822 /* id-GostR3411-94-CryptoProParamSet */, + 821 /* id-GostR3411-94-TestParamSet */, + 807 /* id-GostR3411-94-with-GostR3410-2001 */, + 853 /* id-GostR3411-94-with-GostR3410-2001-cc */, + 808 /* id-GostR3411-94-with-GostR3410-94 */, + 852 /* id-GostR3411-94-with-GostR3410-94-cc */, + 810 /* id-HMACGostR3411-94 */, + 782 /* id-PasswordBasedMAC */, + 266 /* id-aca */, + 355 /* id-aca-accessIdentity */, + 354 /* id-aca-authenticationInfo */, + 356 /* id-aca-chargingIdentity */, + 399 /* id-aca-encAttrs */, + 357 /* id-aca-group */, + 358 /* id-aca-role */, + 176 /* id-ad */, + 896 /* id-aes128-CCM */, + 895 /* id-aes128-GCM */, + 788 /* id-aes128-wrap */, + 897 /* id-aes128-wrap-pad */, + 899 /* id-aes192-CCM */, + 898 /* id-aes192-GCM */, + 789 /* id-aes192-wrap */, + 900 /* id-aes192-wrap-pad */, + 902 /* id-aes256-CCM */, + 901 /* id-aes256-GCM */, + 790 /* id-aes256-wrap */, + 903 /* id-aes256-wrap-pad */, + 262 /* id-alg */, + 893 /* id-alg-PWRI-KEK */, + 323 /* id-alg-des40 */, + 326 /* id-alg-dh-pop */, + 325 /* id-alg-dh-sig-hmac-sha1 */, + 324 /* id-alg-noSignature */, + 907 /* id-camellia128-wrap */, + 908 /* id-camellia192-wrap */, + 909 /* id-camellia256-wrap */, + 268 /* id-cct */, + 361 /* id-cct-PKIData */, + 362 /* id-cct-PKIResponse */, + 360 /* id-cct-crs */, + 81 /* id-ce */, + 680 /* id-characteristic-two-basis */, + 263 /* id-cmc */, + 334 /* id-cmc-addExtensions */, + 346 /* id-cmc-confirmCertAcceptance */, + 330 /* id-cmc-dataReturn */, + 336 /* id-cmc-decryptedPOP */, + 335 /* id-cmc-encryptedPOP */, + 339 /* id-cmc-getCRL */, + 338 /* id-cmc-getCert */, + 328 /* id-cmc-identification */, + 329 /* id-cmc-identityProof */, + 337 /* id-cmc-lraPOPWitness */, + 344 /* id-cmc-popLinkRandom */, + 345 /* id-cmc-popLinkWitness */, + 343 /* id-cmc-queryPending */, + 333 /* id-cmc-recipientNonce */, + 341 /* id-cmc-regInfo */, + 342 /* id-cmc-responseInfo */, + 340 /* id-cmc-revokeRequest */, + 332 /* id-cmc-senderNonce */, + 327 /* id-cmc-statusInfo */, + 331 /* id-cmc-transactionId */, + 787 /* id-ct-asciiTextWithCRLF */, + 408 /* id-ecPublicKey */, + 508 /* id-hex-multipart-message */, + 507 /* id-hex-partial-message */, + 260 /* id-it */, + 302 /* id-it-caKeyUpdateInfo */, + 298 /* id-it-caProtEncCert */, + 311 /* id-it-confirmWaitTime */, + 303 /* id-it-currentCRL */, + 300 /* id-it-encKeyPairTypes */, + 310 /* id-it-implicitConfirm */, + 308 /* id-it-keyPairParamRep */, + 307 /* id-it-keyPairParamReq */, + 312 /* id-it-origPKIMessage */, + 301 /* id-it-preferredSymmAlg */, + 309 /* id-it-revPassphrase */, + 299 /* id-it-signKeyPairTypes */, + 305 /* id-it-subscriptionRequest */, + 306 /* id-it-subscriptionResponse */, + 784 /* id-it-suppLangTags */, + 304 /* id-it-unsupportedOIDs */, + 128 /* id-kp */, + 280 /* id-mod-attribute-cert */, + 274 /* id-mod-cmc */, + 277 /* id-mod-cmp */, + 284 /* id-mod-cmp2000 */, + 273 /* id-mod-crmf */, + 283 /* id-mod-dvcs */, + 275 /* id-mod-kea-profile-88 */, + 276 /* id-mod-kea-profile-93 */, + 282 /* id-mod-ocsp */, + 278 /* id-mod-qualified-cert-88 */, + 279 /* id-mod-qualified-cert-93 */, + 281 /* id-mod-timestamp-protocol */, + 264 /* id-on */, + 858 /* id-on-permanentIdentifier */, + 347 /* id-on-personalData */, + 265 /* id-pda */, + 352 /* id-pda-countryOfCitizenship */, + 353 /* id-pda-countryOfResidence */, + 348 /* id-pda-dateOfBirth */, + 351 /* id-pda-gender */, + 349 /* id-pda-placeOfBirth */, + 175 /* id-pe */, + 261 /* id-pkip */, + 258 /* id-pkix-mod */, + 269 /* id-pkix1-explicit-88 */, + 271 /* id-pkix1-explicit-93 */, + 270 /* id-pkix1-implicit-88 */, + 272 /* id-pkix1-implicit-93 */, + 662 /* id-ppl */, + 664 /* id-ppl-anyLanguage */, + 667 /* id-ppl-independent */, + 665 /* id-ppl-inheritAll */, + 267 /* id-qcs */, + 359 /* id-qcs-pkixQCSyntax-v1 */, + 259 /* id-qt */, + 164 /* id-qt-cps */, + 165 /* id-qt-unotice */, + 313 /* id-regCtrl */, + 316 /* id-regCtrl-authenticator */, + 319 /* id-regCtrl-oldCertID */, + 318 /* id-regCtrl-pkiArchiveOptions */, + 317 /* id-regCtrl-pkiPublicationInfo */, + 320 /* id-regCtrl-protocolEncrKey */, + 315 /* id-regCtrl-regToken */, + 314 /* id-regInfo */, + 322 /* id-regInfo-certReq */, + 321 /* id-regInfo-utf8Pairs */, + 512 /* id-set */, + 191 /* id-smime-aa */, + 215 /* id-smime-aa-contentHint */, + 218 /* id-smime-aa-contentIdentifier */, + 221 /* id-smime-aa-contentReference */, + 240 /* id-smime-aa-dvcs-dvc */, + 217 /* id-smime-aa-encapContentType */, + 222 /* id-smime-aa-encrypKeyPref */, + 220 /* id-smime-aa-equivalentLabels */, + 232 /* id-smime-aa-ets-CertificateRefs */, + 233 /* id-smime-aa-ets-RevocationRefs */, + 238 /* id-smime-aa-ets-archiveTimeStamp */, + 237 /* id-smime-aa-ets-certCRLTimestamp */, + 234 /* id-smime-aa-ets-certValues */, + 227 /* id-smime-aa-ets-commitmentType */, + 231 /* id-smime-aa-ets-contentTimestamp */, + 236 /* id-smime-aa-ets-escTimeStamp */, + 230 /* id-smime-aa-ets-otherSigCert */, + 235 /* id-smime-aa-ets-revocationValues */, + 226 /* id-smime-aa-ets-sigPolicyId */, + 229 /* id-smime-aa-ets-signerAttr */, + 228 /* id-smime-aa-ets-signerLocation */, + 219 /* id-smime-aa-macValue */, + 214 /* id-smime-aa-mlExpandHistory */, + 216 /* id-smime-aa-msgSigDigest */, + 212 /* id-smime-aa-receiptRequest */, + 213 /* id-smime-aa-securityLabel */, + 239 /* id-smime-aa-signatureType */, + 223 /* id-smime-aa-signingCertificate */, + 224 /* id-smime-aa-smimeEncryptCerts */, + 225 /* id-smime-aa-timeStampToken */, + 192 /* id-smime-alg */, + 243 /* id-smime-alg-3DESwrap */, + 246 /* id-smime-alg-CMS3DESwrap */, + 247 /* id-smime-alg-CMSRC2wrap */, + 245 /* id-smime-alg-ESDH */, + 241 /* id-smime-alg-ESDHwith3DES */, + 242 /* id-smime-alg-ESDHwithRC2 */, + 244 /* id-smime-alg-RC2wrap */, + 193 /* id-smime-cd */, + 248 /* id-smime-cd-ldap */, + 190 /* id-smime-ct */, + 210 /* id-smime-ct-DVCSRequestData */, + 211 /* id-smime-ct-DVCSResponseData */, + 208 /* id-smime-ct-TDTInfo */, + 207 /* id-smime-ct-TSTInfo */, + 205 /* id-smime-ct-authData */, + 786 /* id-smime-ct-compressedData */, + 209 /* id-smime-ct-contentInfo */, + 206 /* id-smime-ct-publishCert */, + 204 /* id-smime-ct-receipt */, + 195 /* id-smime-cti */, + 255 /* id-smime-cti-ets-proofOfApproval */, + 256 /* id-smime-cti-ets-proofOfCreation */, + 253 /* id-smime-cti-ets-proofOfDelivery */, + 251 /* id-smime-cti-ets-proofOfOrigin */, + 252 /* id-smime-cti-ets-proofOfReceipt */, + 254 /* id-smime-cti-ets-proofOfSender */, + 189 /* id-smime-mod */, + 196 /* id-smime-mod-cms */, + 197 /* id-smime-mod-ess */, + 202 /* id-smime-mod-ets-eSigPolicy-88 */, + 203 /* id-smime-mod-ets-eSigPolicy-97 */, + 200 /* id-smime-mod-ets-eSignature-88 */, + 201 /* id-smime-mod-ets-eSignature-97 */, + 199 /* id-smime-mod-msg-v3 */, + 198 /* id-smime-mod-oid */, + 194 /* id-smime-spq */, + 250 /* id-smime-spq-ets-sqt-unotice */, + 249 /* id-smime-spq-ets-sqt-uri */, + 676 /* identified-organization */, + 461 /* info */, + 748 /* inhibitAnyPolicy */, + 101 /* initials */, + 647 /* international-organizations */, + 869 /* internationaliSDNNumber */, + 142 /* invalidityDate */, + 294 /* ipsecEndSystem */, + 295 /* ipsecTunnel */, + 296 /* ipsecUser */, + 86 /* issuerAltName */, + 770 /* issuingDistributionPoint */, + 492 /* janetMailbox */, + 150 /* keyBag */, + 83 /* keyUsage */, + 477 /* lastModifiedBy */, + 476 /* lastModifiedTime */, + 157 /* localKeyID */, + 480 /* mXRecord */, + 460 /* mail */, + 493 /* mailPreferenceOption */, + 467 /* manager */, + 809 /* md_gost94 */, + 875 /* member */, + 182 /* member-body */, + 51 /* messageDigest */, + 383 /* mgmt */, + 504 /* mime-mhs */, + 506 /* mime-mhs-bodies */, + 505 /* mime-mhs-headings */, + 488 /* mobileTelephoneNumber */, + 136 /* msCTLSign */, + 135 /* msCodeCom */, + 134 /* msCodeInd */, + 138 /* msEFS */, + 171 /* msExtReq */, + 137 /* msSGC */, + 648 /* msSmartcardLogin */, + 649 /* msUPN */, + 481 /* nSRecord */, + 173 /* name */, + 666 /* nameConstraints */, + 369 /* noCheck */, + 403 /* noRevAvail */, + 72 /* nsBaseUrl */, + 76 /* nsCaPolicyUrl */, + 74 /* nsCaRevocationUrl */, + 58 /* nsCertExt */, + 79 /* nsCertSequence */, + 71 /* nsCertType */, + 78 /* nsComment */, + 59 /* nsDataType */, + 75 /* nsRenewalUrl */, + 73 /* nsRevocationUrl */, + 139 /* nsSGC */, + 77 /* nsSslServerName */, + 681 /* onBasis */, + 491 /* organizationalStatus */, + 475 /* otherMailbox */, + 876 /* owner */, + 489 /* pagerTelephoneNumber */, + 374 /* path */, + 112 /* pbeWithMD5AndCast5CBC */, + 499 /* personalSignature */, + 487 /* personalTitle */, + 464 /* photo */, + 863 /* physicalDeliveryOfficeName */, + 437 /* pilot */, + 439 /* pilotAttributeSyntax */, + 438 /* pilotAttributeType */, + 479 /* pilotAttributeType27 */, + 456 /* pilotDSA */, + 441 /* pilotGroups */, + 444 /* pilotObject */, + 440 /* pilotObjectClass */, + 455 /* pilotOrganization */, + 445 /* pilotPerson */, + 2 /* pkcs */, + 186 /* pkcs1 */, + 27 /* pkcs3 */, + 187 /* pkcs5 */, + 20 /* pkcs7 */, + 21 /* pkcs7-data */, + 25 /* pkcs7-digestData */, + 26 /* pkcs7-encryptedData */, + 23 /* pkcs7-envelopedData */, + 24 /* pkcs7-signedAndEnvelopedData */, + 22 /* pkcs7-signedData */, + 151 /* pkcs8ShroudedKeyBag */, + 47 /* pkcs9 */, + 401 /* policyConstraints */, + 747 /* policyMappings */, + 862 /* postOfficeBox */, + 861 /* postalAddress */, + 661 /* postalCode */, + 683 /* ppBasis */, + 872 /* preferredDeliveryMethod */, + 873 /* presentationAddress */, + 816 /* prf-gostr3411-94 */, + 406 /* prime-field */, + 409 /* prime192v1 */, + 410 /* prime192v2 */, + 411 /* prime192v3 */, + 412 /* prime239v1 */, + 413 /* prime239v2 */, + 414 /* prime239v3 */, + 415 /* prime256v1 */, + 385 /* private */, + 84 /* privateKeyUsagePeriod */, + 886 /* protocolInformation */, + 663 /* proxyCertInfo */, + 510 /* pseudonym */, + 435 /* pss */, + 286 /* qcStatements */, + 457 /* qualityLabelledData */, + 450 /* rFC822localPart */, + 870 /* registeredAddress */, + 400 /* role */, + 877 /* roleOccupant */, + 448 /* room */, + 463 /* roomNumber */, + 6 /* rsaEncryption */, + 644 /* rsaOAEPEncryptionSET */, + 377 /* rsaSignature */, + 1 /* rsadsi */, + 482 /* sOARecord */, + 155 /* safeContentsBag */, + 291 /* sbgp-autonomousSysNum */, + 290 /* sbgp-ipAddrBlock */, + 292 /* sbgp-routerIdentifier */, + 159 /* sdsiCertificate */, + 859 /* searchGuide */, + 704 /* secp112r1 */, + 705 /* secp112r2 */, + 706 /* secp128r1 */, + 707 /* secp128r2 */, + 708 /* secp160k1 */, + 709 /* secp160r1 */, + 710 /* secp160r2 */, + 711 /* secp192k1 */, + 712 /* secp224k1 */, + 713 /* secp224r1 */, + 714 /* secp256k1 */, + 715 /* secp384r1 */, + 716 /* secp521r1 */, + 154 /* secretBag */, + 474 /* secretary */, + 717 /* sect113r1 */, + 718 /* sect113r2 */, + 719 /* sect131r1 */, + 720 /* sect131r2 */, + 721 /* sect163k1 */, + 722 /* sect163r1 */, + 723 /* sect163r2 */, + 724 /* sect193r1 */, + 725 /* sect193r2 */, + 726 /* sect233k1 */, + 727 /* sect233r1 */, + 728 /* sect239k1 */, + 729 /* sect283k1 */, + 730 /* sect283r1 */, + 731 /* sect409k1 */, + 732 /* sect409r1 */, + 733 /* sect571k1 */, + 734 /* sect571r1 */, + 386 /* security */, + 878 /* seeAlso */, + 394 /* selected-attribute-types */, + 105 /* serialNumber */, + 129 /* serverAuth */, + 371 /* serviceLocator */, + 625 /* set-addPolicy */, + 515 /* set-attr */, + 518 /* set-brand */, + 638 /* set-brand-AmericanExpress */, + 637 /* set-brand-Diners */, + 636 /* set-brand-IATA-ATA */, + 639 /* set-brand-JCB */, + 641 /* set-brand-MasterCard */, + 642 /* set-brand-Novus */, + 640 /* set-brand-Visa */, + 517 /* set-certExt */, + 513 /* set-ctype */, + 514 /* set-msgExt */, + 516 /* set-policy */, + 607 /* set-policy-root */, + 624 /* set-rootKeyThumb */, + 620 /* setAttr-Cert */, + 631 /* setAttr-GenCryptgrm */, + 623 /* setAttr-IssCap */, + 628 /* setAttr-IssCap-CVM */, + 630 /* setAttr-IssCap-Sig */, + 629 /* setAttr-IssCap-T2 */, + 621 /* setAttr-PGWYcap */, + 635 /* setAttr-SecDevSig */, + 632 /* setAttr-T2Enc */, + 633 /* setAttr-T2cleartxt */, + 634 /* setAttr-TokICCsig */, + 627 /* setAttr-Token-B0Prime */, + 626 /* setAttr-Token-EMV */, + 622 /* setAttr-TokenType */, + 619 /* setCext-IssuerCapabilities */, + 615 /* setCext-PGWYcapabilities */, + 616 /* setCext-TokenIdentifier */, + 618 /* setCext-TokenType */, + 617 /* setCext-Track2Data */, + 611 /* setCext-cCertRequired */, + 609 /* setCext-certType */, + 608 /* setCext-hashedRoot */, + 610 /* setCext-merchData */, + 613 /* setCext-setExt */, + 614 /* setCext-setQualf */, + 612 /* setCext-tunneling */, + 540 /* setct-AcqCardCodeMsg */, + 576 /* setct-AcqCardCodeMsgTBE */, + 570 /* setct-AuthReqTBE */, + 534 /* setct-AuthReqTBS */, + 527 /* setct-AuthResBaggage */, + 571 /* setct-AuthResTBE */, + 572 /* setct-AuthResTBEX */, + 535 /* setct-AuthResTBS */, + 536 /* setct-AuthResTBSX */, + 528 /* setct-AuthRevReqBaggage */, + 577 /* setct-AuthRevReqTBE */, + 541 /* setct-AuthRevReqTBS */, + 529 /* setct-AuthRevResBaggage */, + 542 /* setct-AuthRevResData */, + 578 /* setct-AuthRevResTBE */, + 579 /* setct-AuthRevResTBEB */, + 543 /* setct-AuthRevResTBS */, + 573 /* setct-AuthTokenTBE */, + 537 /* setct-AuthTokenTBS */, + 600 /* setct-BCIDistributionTBS */, + 558 /* setct-BatchAdminReqData */, + 592 /* setct-BatchAdminReqTBE */, + 559 /* setct-BatchAdminResData */, + 593 /* setct-BatchAdminResTBE */, + 599 /* setct-CRLNotificationResTBS */, + 598 /* setct-CRLNotificationTBS */, + 580 /* setct-CapReqTBE */, + 581 /* setct-CapReqTBEX */, + 544 /* setct-CapReqTBS */, + 545 /* setct-CapReqTBSX */, + 546 /* setct-CapResData */, + 582 /* setct-CapResTBE */, + 583 /* setct-CapRevReqTBE */, + 584 /* setct-CapRevReqTBEX */, + 547 /* setct-CapRevReqTBS */, + 548 /* setct-CapRevReqTBSX */, + 549 /* setct-CapRevResData */, + 585 /* setct-CapRevResTBE */, + 538 /* setct-CapTokenData */, + 530 /* setct-CapTokenSeq */, + 574 /* setct-CapTokenTBE */, + 575 /* setct-CapTokenTBEX */, + 539 /* setct-CapTokenTBS */, + 560 /* setct-CardCInitResTBS */, + 566 /* setct-CertInqReqTBS */, + 563 /* setct-CertReqData */, + 595 /* setct-CertReqTBE */, + 596 /* setct-CertReqTBEX */, + 564 /* setct-CertReqTBS */, + 565 /* setct-CertResData */, + 597 /* setct-CertResTBE */, + 586 /* setct-CredReqTBE */, + 587 /* setct-CredReqTBEX */, + 550 /* setct-CredReqTBS */, + 551 /* setct-CredReqTBSX */, + 552 /* setct-CredResData */, + 588 /* setct-CredResTBE */, + 589 /* setct-CredRevReqTBE */, + 590 /* setct-CredRevReqTBEX */, + 553 /* setct-CredRevReqTBS */, + 554 /* setct-CredRevReqTBSX */, + 555 /* setct-CredRevResData */, + 591 /* setct-CredRevResTBE */, + 567 /* setct-ErrorTBS */, + 526 /* setct-HODInput */, + 561 /* setct-MeAqCInitResTBS */, + 522 /* setct-OIData */, + 519 /* setct-PANData */, + 521 /* setct-PANOnly */, + 520 /* setct-PANToken */, + 556 /* setct-PCertReqData */, + 557 /* setct-PCertResTBS */, + 523 /* setct-PI */, + 532 /* setct-PI-TBS */, + 524 /* setct-PIData */, + 525 /* setct-PIDataUnsigned */, + 568 /* setct-PIDualSignedTBE */, + 569 /* setct-PIUnsignedTBE */, + 531 /* setct-PInitResData */, + 533 /* setct-PResData */, + 594 /* setct-RegFormReqTBE */, + 562 /* setct-RegFormResTBS */, + 606 /* setext-cv */, + 601 /* setext-genCrypt */, + 602 /* setext-miAuth */, + 604 /* setext-pinAny */, + 603 /* setext-pinSecure */, + 605 /* setext-track2 */, + 52 /* signingTime */, + 454 /* simpleSecurityObject */, + 496 /* singleLevelQuality */, + 387 /* snmpv2 */, + 660 /* street */, + 85 /* subjectAltName */, + 769 /* subjectDirectoryAttributes */, + 398 /* subjectInfoAccess */, + 82 /* subjectKeyIdentifier */, + 498 /* subtreeMaximumQuality */, + 497 /* subtreeMinimumQuality */, + 890 /* supportedAlgorithms */, + 874 /* supportedApplicationContext */, + 402 /* targetInformation */, + 864 /* telephoneNumber */, + 866 /* teletexTerminalIdentifier */, + 865 /* telexNumber */, + 459 /* textEncodedORAddress */, + 293 /* textNotice */, + 133 /* timeStamping */, + 106 /* title */, + 682 /* tpBasis */, + 375 /* trustRoot */, + 436 /* ucl */, + 888 /* uniqueMember */, + 55 /* unstructuredAddress */, + 49 /* unstructuredName */, + 880 /* userCertificate */, + 465 /* userClass */, + 879 /* userPassword */, + 373 /* valid */, + 678 /* wap */, + 679 /* wap-wsg */, + 735 /* wap-wsg-idm-ecid-wtls1 */, + 743 /* wap-wsg-idm-ecid-wtls10 */, + 744 /* wap-wsg-idm-ecid-wtls11 */, + 745 /* wap-wsg-idm-ecid-wtls12 */, + 736 /* wap-wsg-idm-ecid-wtls3 */, + 737 /* wap-wsg-idm-ecid-wtls4 */, + 738 /* wap-wsg-idm-ecid-wtls5 */, + 739 /* wap-wsg-idm-ecid-wtls6 */, + 740 /* wap-wsg-idm-ecid-wtls7 */, + 741 /* wap-wsg-idm-ecid-wtls8 */, + 742 /* wap-wsg-idm-ecid-wtls9 */, + 804 /* whirlpool */, + 868 /* x121Address */, + 503 /* x500UniqueIdentifier */, + 158 /* x509Certificate */, + 160 /* x509Crl */, }; -static const unsigned int kNIDsInLongNameOrder[NUM_LN]={ -363, /* "AD Time Stamping" */ -405, /* "ANSI X9.62" */ -368, /* "Acceptable OCSP Responses" */ -910, /* "Any Extended Key Usage" */ -664, /* "Any language" */ -177, /* "Authority Information Access" */ -365, /* "Basic OCSP Response" */ -285, /* "Biometric Info" */ -179, /* "CA Issuers" */ -785, /* "CA Repository" */ -131, /* "Code Signing" */ -783, /* "Diffie-Hellman based MAC" */ -382, /* "Directory" */ -392, /* "Domain" */ -132, /* "E-mail Protection" */ -389, /* "Enterprises" */ -384, /* "Experimental" */ -372, /* "Extended OCSP Status" */ -172, /* "Extension Request" */ -813, /* "GOST 28147-89" */ -849, /* "GOST 28147-89 Cryptocom ParamSet" */ -815, /* "GOST 28147-89 MAC" */ -851, /* "GOST 34.10-2001 Cryptocom" */ -850, /* "GOST 34.10-94 Cryptocom" */ -811, /* "GOST R 34.10-2001" */ -817, /* "GOST R 34.10-2001 DH" */ -812, /* "GOST R 34.10-94" */ -818, /* "GOST R 34.10-94 DH" */ -809, /* "GOST R 34.11-94" */ -816, /* "GOST R 34.11-94 PRF" */ -807, /* "GOST R 34.11-94 with GOST R 34.10-2001" */ -853, /* "GOST R 34.11-94 with GOST R 34.10-2001 Cryptocom" */ -808, /* "GOST R 34.11-94 with GOST R 34.10-94" */ -852, /* "GOST R 34.11-94 with GOST R 34.10-94 Cryptocom" */ -854, /* "GOST R 3410-2001 Parameter Set Cryptocom" */ -810, /* "HMAC GOST 34.11-94" */ -432, /* "Hold Instruction Call Issuer" */ -430, /* "Hold Instruction Code" */ -431, /* "Hold Instruction None" */ -433, /* "Hold Instruction Reject" */ -634, /* "ICC or token signature" */ -294, /* "IPSec End System" */ -295, /* "IPSec Tunnel" */ -296, /* "IPSec User" */ -182, /* "ISO Member Body" */ -183, /* "ISO US Member Body" */ -667, /* "Independent" */ -665, /* "Inherit all" */ -647, /* "International Organizations" */ -142, /* "Invalidity Date" */ -504, /* "MIME MHS" */ -388, /* "Mail" */ -383, /* "Management" */ -417, /* "Microsoft CSP Name" */ -135, /* "Microsoft Commercial Code Signing" */ -138, /* "Microsoft Encrypted File System" */ -171, /* "Microsoft Extension Request" */ -134, /* "Microsoft Individual Code Signing" */ -856, /* "Microsoft Local Key set" */ -137, /* "Microsoft Server Gated Crypto" */ -648, /* "Microsoft Smartcardlogin" */ -136, /* "Microsoft Trust List Signing" */ -649, /* "Microsoft Universal Principal Name" */ -393, /* "NULL" */ -404, /* "NULL" */ -72, /* "Netscape Base Url" */ -76, /* "Netscape CA Policy Url" */ -74, /* "Netscape CA Revocation Url" */ -71, /* "Netscape Cert Type" */ -58, /* "Netscape Certificate Extension" */ -79, /* "Netscape Certificate Sequence" */ -78, /* "Netscape Comment" */ -57, /* "Netscape Communications Corp." */ -59, /* "Netscape Data Type" */ -75, /* "Netscape Renewal Url" */ -73, /* "Netscape Revocation Url" */ -77, /* "Netscape SSL Server Name" */ -139, /* "Netscape Server Gated Crypto" */ -178, /* "OCSP" */ -370, /* "OCSP Archive Cutoff" */ -367, /* "OCSP CRL ID" */ -369, /* "OCSP No Check" */ -366, /* "OCSP Nonce" */ -371, /* "OCSP Service Locator" */ -180, /* "OCSP Signing" */ -161, /* "PBES2" */ -69, /* "PBKDF2" */ -162, /* "PBMAC1" */ -127, /* "PKIX" */ -858, /* "Permanent Identifier" */ -164, /* "Policy Qualifier CPS" */ -165, /* "Policy Qualifier User Notice" */ -385, /* "Private" */ -663, /* "Proxy Certificate Information" */ - 1, /* "RSA Data Security, Inc." */ - 2, /* "RSA Data Security, Inc. PKCS" */ -188, /* "S/MIME" */ -167, /* "S/MIME Capabilities" */ -387, /* "SNMPv2" */ -512, /* "Secure Electronic Transactions" */ -386, /* "Security" */ -394, /* "Selected Attribute Types" */ -143, /* "Strong Extranet ID" */ -398, /* "Subject Information Access" */ -130, /* "TLS Web Client Authentication" */ -129, /* "TLS Web Server Authentication" */ -133, /* "Time Stamping" */ -375, /* "Trust Root" */ -12, /* "X509" */ -402, /* "X509v3 AC Targeting" */ -746, /* "X509v3 Any Policy" */ -90, /* "X509v3 Authority Key Identifier" */ -87, /* "X509v3 Basic Constraints" */ -103, /* "X509v3 CRL Distribution Points" */ -88, /* "X509v3 CRL Number" */ -141, /* "X509v3 CRL Reason Code" */ -771, /* "X509v3 Certificate Issuer" */ -89, /* "X509v3 Certificate Policies" */ -140, /* "X509v3 Delta CRL Indicator" */ -126, /* "X509v3 Extended Key Usage" */ -857, /* "X509v3 Freshest CRL" */ -748, /* "X509v3 Inhibit Any Policy" */ -86, /* "X509v3 Issuer Alternative Name" */ -770, /* "X509v3 Issuing Distribution Point" */ -83, /* "X509v3 Key Usage" */ -666, /* "X509v3 Name Constraints" */ -403, /* "X509v3 No Revocation Available" */ -401, /* "X509v3 Policy Constraints" */ -747, /* "X509v3 Policy Mappings" */ -84, /* "X509v3 Private Key Usage Period" */ -85, /* "X509v3 Subject Alternative Name" */ -769, /* "X509v3 Subject Directory Attributes" */ -82, /* "X509v3 Subject Key Identifier" */ -920, /* "X9.42 DH" */ -184, /* "X9.57" */ -185, /* "X9.57 CM ?" */ -478, /* "aRecord" */ -289, /* "aaControls" */ -287, /* "ac-auditEntity" */ -397, /* "ac-proxying" */ -288, /* "ac-targeting" */ -446, /* "account" */ -364, /* "ad dvcs" */ -606, /* "additional verification" */ -419, /* "aes-128-cbc" */ -916, /* "aes-128-cbc-hmac-sha1" */ -896, /* "aes-128-ccm" */ -421, /* "aes-128-cfb" */ -650, /* "aes-128-cfb1" */ -653, /* "aes-128-cfb8" */ -904, /* "aes-128-ctr" */ -418, /* "aes-128-ecb" */ -895, /* "aes-128-gcm" */ -420, /* "aes-128-ofb" */ -913, /* "aes-128-xts" */ -423, /* "aes-192-cbc" */ -917, /* "aes-192-cbc-hmac-sha1" */ -899, /* "aes-192-ccm" */ -425, /* "aes-192-cfb" */ -651, /* "aes-192-cfb1" */ -654, /* "aes-192-cfb8" */ -905, /* "aes-192-ctr" */ -422, /* "aes-192-ecb" */ -898, /* "aes-192-gcm" */ -424, /* "aes-192-ofb" */ -427, /* "aes-256-cbc" */ -918, /* "aes-256-cbc-hmac-sha1" */ -902, /* "aes-256-ccm" */ -429, /* "aes-256-cfb" */ -652, /* "aes-256-cfb1" */ -655, /* "aes-256-cfb8" */ -906, /* "aes-256-ctr" */ -426, /* "aes-256-ecb" */ -901, /* "aes-256-gcm" */ -428, /* "aes-256-ofb" */ -914, /* "aes-256-xts" */ -376, /* "algorithm" */ -484, /* "associatedDomain" */ -485, /* "associatedName" */ -501, /* "audio" */ -882, /* "authorityRevocationList" */ -91, /* "bf-cbc" */ -93, /* "bf-cfb" */ -92, /* "bf-ecb" */ -94, /* "bf-ofb" */ -921, /* "brainpoolP160r1" */ -922, /* "brainpoolP160t1" */ -923, /* "brainpoolP192r1" */ -924, /* "brainpoolP192t1" */ -925, /* "brainpoolP224r1" */ -926, /* "brainpoolP224t1" */ -927, /* "brainpoolP256r1" */ -928, /* "brainpoolP256t1" */ -929, /* "brainpoolP320r1" */ -930, /* "brainpoolP320t1" */ -931, /* "brainpoolP384r1" */ -932, /* "brainpoolP384t1" */ -933, /* "brainpoolP512r1" */ -934, /* "brainpoolP512t1" */ -494, /* "buildingName" */ -860, /* "businessCategory" */ -691, /* "c2onb191v4" */ -692, /* "c2onb191v5" */ -697, /* "c2onb239v4" */ -698, /* "c2onb239v5" */ -684, /* "c2pnb163v1" */ -685, /* "c2pnb163v2" */ -686, /* "c2pnb163v3" */ -687, /* "c2pnb176v1" */ -693, /* "c2pnb208w1" */ -699, /* "c2pnb272w1" */ -700, /* "c2pnb304w1" */ -702, /* "c2pnb368w1" */ -688, /* "c2tnb191v1" */ -689, /* "c2tnb191v2" */ -690, /* "c2tnb191v3" */ -694, /* "c2tnb239v1" */ -695, /* "c2tnb239v2" */ -696, /* "c2tnb239v3" */ -701, /* "c2tnb359v1" */ -703, /* "c2tnb431r1" */ -881, /* "cACertificate" */ -483, /* "cNAMERecord" */ -751, /* "camellia-128-cbc" */ -757, /* "camellia-128-cfb" */ -760, /* "camellia-128-cfb1" */ -763, /* "camellia-128-cfb8" */ -754, /* "camellia-128-ecb" */ -766, /* "camellia-128-ofb" */ -752, /* "camellia-192-cbc" */ -758, /* "camellia-192-cfb" */ -761, /* "camellia-192-cfb1" */ -764, /* "camellia-192-cfb8" */ -755, /* "camellia-192-ecb" */ -767, /* "camellia-192-ofb" */ -753, /* "camellia-256-cbc" */ -759, /* "camellia-256-cfb" */ -762, /* "camellia-256-cfb1" */ -765, /* "camellia-256-cfb8" */ -756, /* "camellia-256-ecb" */ -768, /* "camellia-256-ofb" */ -443, /* "caseIgnoreIA5StringSyntax" */ -108, /* "cast5-cbc" */ -110, /* "cast5-cfb" */ -109, /* "cast5-ecb" */ -111, /* "cast5-ofb" */ -152, /* "certBag" */ -677, /* "certicom-arc" */ -517, /* "certificate extensions" */ -883, /* "certificateRevocationList" */ -54, /* "challengePassword" */ -407, /* "characteristic-two-field" */ -395, /* "clearance" */ -633, /* "cleartext track 2" */ -894, /* "cmac" */ -13, /* "commonName" */ -513, /* "content types" */ -50, /* "contentType" */ -53, /* "countersignature" */ -14, /* "countryName" */ -153, /* "crlBag" */ -884, /* "crossCertificatePair" */ -806, /* "cryptocom" */ -805, /* "cryptopro" */ -500, /* "dITRedirect" */ -451, /* "dNSDomain" */ -495, /* "dSAQuality" */ -434, /* "data" */ -390, /* "dcObject" */ -891, /* "deltaRevocationList" */ -31, /* "des-cbc" */ -643, /* "des-cdmf" */ -30, /* "des-cfb" */ -656, /* "des-cfb1" */ -657, /* "des-cfb8" */ -29, /* "des-ecb" */ -32, /* "des-ede" */ -43, /* "des-ede-cbc" */ -60, /* "des-ede-cfb" */ -62, /* "des-ede-ofb" */ -33, /* "des-ede3" */ -44, /* "des-ede3-cbc" */ -61, /* "des-ede3-cfb" */ -658, /* "des-ede3-cfb1" */ -659, /* "des-ede3-cfb8" */ -63, /* "des-ede3-ofb" */ -45, /* "des-ofb" */ -107, /* "description" */ -871, /* "destinationIndicator" */ -80, /* "desx-cbc" */ -947, /* "dh-cofactor-kdf" */ -946, /* "dh-std-kdf" */ -28, /* "dhKeyAgreement" */ -941, /* "dhSinglePass-cofactorDH-sha1kdf-scheme" */ -942, /* "dhSinglePass-cofactorDH-sha224kdf-scheme" */ -943, /* "dhSinglePass-cofactorDH-sha256kdf-scheme" */ -944, /* "dhSinglePass-cofactorDH-sha384kdf-scheme" */ -945, /* "dhSinglePass-cofactorDH-sha512kdf-scheme" */ -936, /* "dhSinglePass-stdDH-sha1kdf-scheme" */ -937, /* "dhSinglePass-stdDH-sha224kdf-scheme" */ -938, /* "dhSinglePass-stdDH-sha256kdf-scheme" */ -939, /* "dhSinglePass-stdDH-sha384kdf-scheme" */ -940, /* "dhSinglePass-stdDH-sha512kdf-scheme" */ -11, /* "directory services (X.500)" */ -378, /* "directory services - algorithms" */ -887, /* "distinguishedName" */ -892, /* "dmdName" */ -174, /* "dnQualifier" */ -447, /* "document" */ -471, /* "documentAuthor" */ -468, /* "documentIdentifier" */ -472, /* "documentLocation" */ -502, /* "documentPublisher" */ -449, /* "documentSeries" */ -469, /* "documentTitle" */ -470, /* "documentVersion" */ -380, /* "dod" */ -391, /* "domainComponent" */ -452, /* "domainRelatedObject" */ -116, /* "dsaEncryption" */ -67, /* "dsaEncryption-old" */ -66, /* "dsaWithSHA" */ -113, /* "dsaWithSHA1" */ -70, /* "dsaWithSHA1-old" */ -802, /* "dsa_with_SHA224" */ -803, /* "dsa_with_SHA256" */ -297, /* "dvcs" */ -791, /* "ecdsa-with-Recommended" */ -416, /* "ecdsa-with-SHA1" */ -793, /* "ecdsa-with-SHA224" */ -794, /* "ecdsa-with-SHA256" */ -795, /* "ecdsa-with-SHA384" */ -796, /* "ecdsa-with-SHA512" */ -792, /* "ecdsa-with-Specified" */ -48, /* "emailAddress" */ -632, /* "encrypted track 2" */ -885, /* "enhancedSearchGuide" */ -56, /* "extendedCertificateAttributes" */ -867, /* "facsimileTelephoneNumber" */ -462, /* "favouriteDrink" */ -453, /* "friendlyCountry" */ -490, /* "friendlyCountryName" */ -156, /* "friendlyName" */ -631, /* "generate cryptogram" */ -509, /* "generationQualifier" */ -601, /* "generic cryptogram" */ -99, /* "givenName" */ -814, /* "gost89-cnt" */ -855, /* "hmac" */ -780, /* "hmac-md5" */ -781, /* "hmac-sha1" */ -797, /* "hmacWithMD5" */ -163, /* "hmacWithSHA1" */ -798, /* "hmacWithSHA224" */ -799, /* "hmacWithSHA256" */ -800, /* "hmacWithSHA384" */ -801, /* "hmacWithSHA512" */ -486, /* "homePostalAddress" */ -473, /* "homeTelephoneNumber" */ -466, /* "host" */ -889, /* "houseIdentifier" */ -442, /* "iA5StringSyntax" */ -381, /* "iana" */ -824, /* "id-Gost28147-89-CryptoPro-A-ParamSet" */ -825, /* "id-Gost28147-89-CryptoPro-B-ParamSet" */ -826, /* "id-Gost28147-89-CryptoPro-C-ParamSet" */ -827, /* "id-Gost28147-89-CryptoPro-D-ParamSet" */ -819, /* "id-Gost28147-89-CryptoPro-KeyMeshing" */ -829, /* "id-Gost28147-89-CryptoPro-Oscar-1-0-ParamSet" */ -828, /* "id-Gost28147-89-CryptoPro-Oscar-1-1-ParamSet" */ -830, /* "id-Gost28147-89-CryptoPro-RIC-1-ParamSet" */ -820, /* "id-Gost28147-89-None-KeyMeshing" */ -823, /* "id-Gost28147-89-TestParamSet" */ -840, /* "id-GostR3410-2001-CryptoPro-A-ParamSet" */ -841, /* "id-GostR3410-2001-CryptoPro-B-ParamSet" */ -842, /* "id-GostR3410-2001-CryptoPro-C-ParamSet" */ -843, /* "id-GostR3410-2001-CryptoPro-XchA-ParamSet" */ -844, /* "id-GostR3410-2001-CryptoPro-XchB-ParamSet" */ -839, /* "id-GostR3410-2001-TestParamSet" */ -832, /* "id-GostR3410-94-CryptoPro-A-ParamSet" */ -833, /* "id-GostR3410-94-CryptoPro-B-ParamSet" */ -834, /* "id-GostR3410-94-CryptoPro-C-ParamSet" */ -835, /* "id-GostR3410-94-CryptoPro-D-ParamSet" */ -836, /* "id-GostR3410-94-CryptoPro-XchA-ParamSet" */ -837, /* "id-GostR3410-94-CryptoPro-XchB-ParamSet" */ -838, /* "id-GostR3410-94-CryptoPro-XchC-ParamSet" */ -831, /* "id-GostR3410-94-TestParamSet" */ -845, /* "id-GostR3410-94-a" */ -846, /* "id-GostR3410-94-aBis" */ -847, /* "id-GostR3410-94-b" */ -848, /* "id-GostR3410-94-bBis" */ -822, /* "id-GostR3411-94-CryptoProParamSet" */ -821, /* "id-GostR3411-94-TestParamSet" */ -266, /* "id-aca" */ -355, /* "id-aca-accessIdentity" */ -354, /* "id-aca-authenticationInfo" */ -356, /* "id-aca-chargingIdentity" */ -399, /* "id-aca-encAttrs" */ -357, /* "id-aca-group" */ -358, /* "id-aca-role" */ -176, /* "id-ad" */ -788, /* "id-aes128-wrap" */ -897, /* "id-aes128-wrap-pad" */ -789, /* "id-aes192-wrap" */ -900, /* "id-aes192-wrap-pad" */ -790, /* "id-aes256-wrap" */ -903, /* "id-aes256-wrap-pad" */ -262, /* "id-alg" */ -893, /* "id-alg-PWRI-KEK" */ -323, /* "id-alg-des40" */ -326, /* "id-alg-dh-pop" */ -325, /* "id-alg-dh-sig-hmac-sha1" */ -324, /* "id-alg-noSignature" */ -907, /* "id-camellia128-wrap" */ -908, /* "id-camellia192-wrap" */ -909, /* "id-camellia256-wrap" */ -268, /* "id-cct" */ -361, /* "id-cct-PKIData" */ -362, /* "id-cct-PKIResponse" */ -360, /* "id-cct-crs" */ -81, /* "id-ce" */ -680, /* "id-characteristic-two-basis" */ -263, /* "id-cmc" */ -334, /* "id-cmc-addExtensions" */ -346, /* "id-cmc-confirmCertAcceptance" */ -330, /* "id-cmc-dataReturn" */ -336, /* "id-cmc-decryptedPOP" */ -335, /* "id-cmc-encryptedPOP" */ -339, /* "id-cmc-getCRL" */ -338, /* "id-cmc-getCert" */ -328, /* "id-cmc-identification" */ -329, /* "id-cmc-identityProof" */ -337, /* "id-cmc-lraPOPWitness" */ -344, /* "id-cmc-popLinkRandom" */ -345, /* "id-cmc-popLinkWitness" */ -343, /* "id-cmc-queryPending" */ -333, /* "id-cmc-recipientNonce" */ -341, /* "id-cmc-regInfo" */ -342, /* "id-cmc-responseInfo" */ -340, /* "id-cmc-revokeRequest" */ -332, /* "id-cmc-senderNonce" */ -327, /* "id-cmc-statusInfo" */ -331, /* "id-cmc-transactionId" */ -787, /* "id-ct-asciiTextWithCRLF" */ -408, /* "id-ecPublicKey" */ -508, /* "id-hex-multipart-message" */ -507, /* "id-hex-partial-message" */ -260, /* "id-it" */ -302, /* "id-it-caKeyUpdateInfo" */ -298, /* "id-it-caProtEncCert" */ -311, /* "id-it-confirmWaitTime" */ -303, /* "id-it-currentCRL" */ -300, /* "id-it-encKeyPairTypes" */ -310, /* "id-it-implicitConfirm" */ -308, /* "id-it-keyPairParamRep" */ -307, /* "id-it-keyPairParamReq" */ -312, /* "id-it-origPKIMessage" */ -301, /* "id-it-preferredSymmAlg" */ -309, /* "id-it-revPassphrase" */ -299, /* "id-it-signKeyPairTypes" */ -305, /* "id-it-subscriptionRequest" */ -306, /* "id-it-subscriptionResponse" */ -784, /* "id-it-suppLangTags" */ -304, /* "id-it-unsupportedOIDs" */ -128, /* "id-kp" */ -280, /* "id-mod-attribute-cert" */ -274, /* "id-mod-cmc" */ -277, /* "id-mod-cmp" */ -284, /* "id-mod-cmp2000" */ -273, /* "id-mod-crmf" */ -283, /* "id-mod-dvcs" */ -275, /* "id-mod-kea-profile-88" */ -276, /* "id-mod-kea-profile-93" */ -282, /* "id-mod-ocsp" */ -278, /* "id-mod-qualified-cert-88" */ -279, /* "id-mod-qualified-cert-93" */ -281, /* "id-mod-timestamp-protocol" */ -264, /* "id-on" */ -347, /* "id-on-personalData" */ -265, /* "id-pda" */ -352, /* "id-pda-countryOfCitizenship" */ -353, /* "id-pda-countryOfResidence" */ -348, /* "id-pda-dateOfBirth" */ -351, /* "id-pda-gender" */ -349, /* "id-pda-placeOfBirth" */ -175, /* "id-pe" */ -261, /* "id-pkip" */ -258, /* "id-pkix-mod" */ -269, /* "id-pkix1-explicit-88" */ -271, /* "id-pkix1-explicit-93" */ -270, /* "id-pkix1-implicit-88" */ -272, /* "id-pkix1-implicit-93" */ -662, /* "id-ppl" */ -267, /* "id-qcs" */ -359, /* "id-qcs-pkixQCSyntax-v1" */ -259, /* "id-qt" */ -313, /* "id-regCtrl" */ -316, /* "id-regCtrl-authenticator" */ -319, /* "id-regCtrl-oldCertID" */ -318, /* "id-regCtrl-pkiArchiveOptions" */ -317, /* "id-regCtrl-pkiPublicationInfo" */ -320, /* "id-regCtrl-protocolEncrKey" */ -315, /* "id-regCtrl-regToken" */ -314, /* "id-regInfo" */ -322, /* "id-regInfo-certReq" */ -321, /* "id-regInfo-utf8Pairs" */ -191, /* "id-smime-aa" */ -215, /* "id-smime-aa-contentHint" */ -218, /* "id-smime-aa-contentIdentifier" */ -221, /* "id-smime-aa-contentReference" */ -240, /* "id-smime-aa-dvcs-dvc" */ -217, /* "id-smime-aa-encapContentType" */ -222, /* "id-smime-aa-encrypKeyPref" */ -220, /* "id-smime-aa-equivalentLabels" */ -232, /* "id-smime-aa-ets-CertificateRefs" */ -233, /* "id-smime-aa-ets-RevocationRefs" */ -238, /* "id-smime-aa-ets-archiveTimeStamp" */ -237, /* "id-smime-aa-ets-certCRLTimestamp" */ -234, /* "id-smime-aa-ets-certValues" */ -227, /* "id-smime-aa-ets-commitmentType" */ -231, /* "id-smime-aa-ets-contentTimestamp" */ -236, /* "id-smime-aa-ets-escTimeStamp" */ -230, /* "id-smime-aa-ets-otherSigCert" */ -235, /* "id-smime-aa-ets-revocationValues" */ -226, /* "id-smime-aa-ets-sigPolicyId" */ -229, /* "id-smime-aa-ets-signerAttr" */ -228, /* "id-smime-aa-ets-signerLocation" */ -219, /* "id-smime-aa-macValue" */ -214, /* "id-smime-aa-mlExpandHistory" */ -216, /* "id-smime-aa-msgSigDigest" */ -212, /* "id-smime-aa-receiptRequest" */ -213, /* "id-smime-aa-securityLabel" */ -239, /* "id-smime-aa-signatureType" */ -223, /* "id-smime-aa-signingCertificate" */ -224, /* "id-smime-aa-smimeEncryptCerts" */ -225, /* "id-smime-aa-timeStampToken" */ -192, /* "id-smime-alg" */ -243, /* "id-smime-alg-3DESwrap" */ -246, /* "id-smime-alg-CMS3DESwrap" */ -247, /* "id-smime-alg-CMSRC2wrap" */ -245, /* "id-smime-alg-ESDH" */ -241, /* "id-smime-alg-ESDHwith3DES" */ -242, /* "id-smime-alg-ESDHwithRC2" */ -244, /* "id-smime-alg-RC2wrap" */ -193, /* "id-smime-cd" */ -248, /* "id-smime-cd-ldap" */ -190, /* "id-smime-ct" */ -210, /* "id-smime-ct-DVCSRequestData" */ -211, /* "id-smime-ct-DVCSResponseData" */ -208, /* "id-smime-ct-TDTInfo" */ -207, /* "id-smime-ct-TSTInfo" */ -205, /* "id-smime-ct-authData" */ -786, /* "id-smime-ct-compressedData" */ -209, /* "id-smime-ct-contentInfo" */ -206, /* "id-smime-ct-publishCert" */ -204, /* "id-smime-ct-receipt" */ -195, /* "id-smime-cti" */ -255, /* "id-smime-cti-ets-proofOfApproval" */ -256, /* "id-smime-cti-ets-proofOfCreation" */ -253, /* "id-smime-cti-ets-proofOfDelivery" */ -251, /* "id-smime-cti-ets-proofOfOrigin" */ -252, /* "id-smime-cti-ets-proofOfReceipt" */ -254, /* "id-smime-cti-ets-proofOfSender" */ -189, /* "id-smime-mod" */ -196, /* "id-smime-mod-cms" */ -197, /* "id-smime-mod-ess" */ -202, /* "id-smime-mod-ets-eSigPolicy-88" */ -203, /* "id-smime-mod-ets-eSigPolicy-97" */ -200, /* "id-smime-mod-ets-eSignature-88" */ -201, /* "id-smime-mod-ets-eSignature-97" */ -199, /* "id-smime-mod-msg-v3" */ -198, /* "id-smime-mod-oid" */ -194, /* "id-smime-spq" */ -250, /* "id-smime-spq-ets-sqt-unotice" */ -249, /* "id-smime-spq-ets-sqt-uri" */ -34, /* "idea-cbc" */ -35, /* "idea-cfb" */ -36, /* "idea-ecb" */ -46, /* "idea-ofb" */ -676, /* "identified-organization" */ -461, /* "info" */ -101, /* "initials" */ -869, /* "internationaliSDNNumber" */ -749, /* "ipsec3" */ -750, /* "ipsec4" */ -181, /* "iso" */ -623, /* "issuer capabilities" */ -645, /* "itu-t" */ -492, /* "janetMailbox" */ -646, /* "joint-iso-itu-t" */ -150, /* "keyBag" */ -773, /* "kisa" */ -477, /* "lastModifiedBy" */ -476, /* "lastModifiedTime" */ -157, /* "localKeyID" */ -15, /* "localityName" */ -480, /* "mXRecord" */ -493, /* "mailPreferenceOption" */ -467, /* "manager" */ - 3, /* "md2" */ - 7, /* "md2WithRSAEncryption" */ -257, /* "md4" */ -396, /* "md4WithRSAEncryption" */ - 4, /* "md5" */ -114, /* "md5-sha1" */ -104, /* "md5WithRSA" */ - 8, /* "md5WithRSAEncryption" */ -95, /* "mdc2" */ -96, /* "mdc2WithRSA" */ -875, /* "member" */ -602, /* "merchant initiated auth" */ -514, /* "message extensions" */ -51, /* "messageDigest" */ -911, /* "mgf1" */ -506, /* "mime-mhs-bodies" */ -505, /* "mime-mhs-headings" */ -488, /* "mobileTelephoneNumber" */ -481, /* "nSRecord" */ -173, /* "name" */ -681, /* "onBasis" */ -379, /* "org" */ -17, /* "organizationName" */ -491, /* "organizationalStatus" */ -18, /* "organizationalUnitName" */ -475, /* "otherMailbox" */ -876, /* "owner" */ -935, /* "pSpecified" */ -489, /* "pagerTelephoneNumber" */ -782, /* "password based MAC" */ -374, /* "path" */ -621, /* "payment gateway capabilities" */ - 9, /* "pbeWithMD2AndDES-CBC" */ -168, /* "pbeWithMD2AndRC2-CBC" */ -112, /* "pbeWithMD5AndCast5CBC" */ -10, /* "pbeWithMD5AndDES-CBC" */ -169, /* "pbeWithMD5AndRC2-CBC" */ -148, /* "pbeWithSHA1And128BitRC2-CBC" */ -144, /* "pbeWithSHA1And128BitRC4" */ -147, /* "pbeWithSHA1And2-KeyTripleDES-CBC" */ -146, /* "pbeWithSHA1And3-KeyTripleDES-CBC" */ -149, /* "pbeWithSHA1And40BitRC2-CBC" */ -145, /* "pbeWithSHA1And40BitRC4" */ -170, /* "pbeWithSHA1AndDES-CBC" */ -68, /* "pbeWithSHA1AndRC2-CBC" */ -499, /* "personalSignature" */ -487, /* "personalTitle" */ -464, /* "photo" */ -863, /* "physicalDeliveryOfficeName" */ -437, /* "pilot" */ -439, /* "pilotAttributeSyntax" */ -438, /* "pilotAttributeType" */ -479, /* "pilotAttributeType27" */ -456, /* "pilotDSA" */ -441, /* "pilotGroups" */ -444, /* "pilotObject" */ -440, /* "pilotObjectClass" */ -455, /* "pilotOrganization" */ -445, /* "pilotPerson" */ -186, /* "pkcs1" */ -27, /* "pkcs3" */ -187, /* "pkcs5" */ -20, /* "pkcs7" */ -21, /* "pkcs7-data" */ -25, /* "pkcs7-digestData" */ -26, /* "pkcs7-encryptedData" */ -23, /* "pkcs7-envelopedData" */ -24, /* "pkcs7-signedAndEnvelopedData" */ -22, /* "pkcs7-signedData" */ -151, /* "pkcs8ShroudedKeyBag" */ -47, /* "pkcs9" */ -862, /* "postOfficeBox" */ -861, /* "postalAddress" */ -661, /* "postalCode" */ -683, /* "ppBasis" */ -872, /* "preferredDeliveryMethod" */ -873, /* "presentationAddress" */ -406, /* "prime-field" */ -409, /* "prime192v1" */ -410, /* "prime192v2" */ -411, /* "prime192v3" */ -412, /* "prime239v1" */ -413, /* "prime239v2" */ -414, /* "prime239v3" */ -415, /* "prime256v1" */ -886, /* "protocolInformation" */ -510, /* "pseudonym" */ -435, /* "pss" */ -286, /* "qcStatements" */ -457, /* "qualityLabelledData" */ -450, /* "rFC822localPart" */ -98, /* "rc2-40-cbc" */ -166, /* "rc2-64-cbc" */ -37, /* "rc2-cbc" */ -39, /* "rc2-cfb" */ -38, /* "rc2-ecb" */ -40, /* "rc2-ofb" */ - 5, /* "rc4" */ -97, /* "rc4-40" */ -915, /* "rc4-hmac-md5" */ -120, /* "rc5-cbc" */ -122, /* "rc5-cfb" */ -121, /* "rc5-ecb" */ -123, /* "rc5-ofb" */ -870, /* "registeredAddress" */ -460, /* "rfc822Mailbox" */ -117, /* "ripemd160" */ -119, /* "ripemd160WithRSA" */ -400, /* "role" */ -877, /* "roleOccupant" */ -448, /* "room" */ -463, /* "roomNumber" */ -19, /* "rsa" */ - 6, /* "rsaEncryption" */ -644, /* "rsaOAEPEncryptionSET" */ -377, /* "rsaSignature" */ -919, /* "rsaesOaep" */ -912, /* "rsassaPss" */ -482, /* "sOARecord" */ -155, /* "safeContentsBag" */ -291, /* "sbgp-autonomousSysNum" */ -290, /* "sbgp-ipAddrBlock" */ -292, /* "sbgp-routerIdentifier" */ -159, /* "sdsiCertificate" */ -859, /* "searchGuide" */ -704, /* "secp112r1" */ -705, /* "secp112r2" */ -706, /* "secp128r1" */ -707, /* "secp128r2" */ -708, /* "secp160k1" */ -709, /* "secp160r1" */ -710, /* "secp160r2" */ -711, /* "secp192k1" */ -712, /* "secp224k1" */ -713, /* "secp224r1" */ -714, /* "secp256k1" */ -715, /* "secp384r1" */ -716, /* "secp521r1" */ -154, /* "secretBag" */ -474, /* "secretary" */ -717, /* "sect113r1" */ -718, /* "sect113r2" */ -719, /* "sect131r1" */ -720, /* "sect131r2" */ -721, /* "sect163k1" */ -722, /* "sect163r1" */ -723, /* "sect163r2" */ -724, /* "sect193r1" */ -725, /* "sect193r2" */ -726, /* "sect233k1" */ -727, /* "sect233r1" */ -728, /* "sect239k1" */ -729, /* "sect283k1" */ -730, /* "sect283r1" */ -731, /* "sect409k1" */ -732, /* "sect409r1" */ -733, /* "sect571k1" */ -734, /* "sect571r1" */ -635, /* "secure device signature" */ -878, /* "seeAlso" */ -777, /* "seed-cbc" */ -779, /* "seed-cfb" */ -776, /* "seed-ecb" */ -778, /* "seed-ofb" */ -105, /* "serialNumber" */ -625, /* "set-addPolicy" */ -515, /* "set-attr" */ -518, /* "set-brand" */ -638, /* "set-brand-AmericanExpress" */ -637, /* "set-brand-Diners" */ -636, /* "set-brand-IATA-ATA" */ -639, /* "set-brand-JCB" */ -641, /* "set-brand-MasterCard" */ -642, /* "set-brand-Novus" */ -640, /* "set-brand-Visa" */ -516, /* "set-policy" */ -607, /* "set-policy-root" */ -624, /* "set-rootKeyThumb" */ -620, /* "setAttr-Cert" */ -628, /* "setAttr-IssCap-CVM" */ -630, /* "setAttr-IssCap-Sig" */ -629, /* "setAttr-IssCap-T2" */ -627, /* "setAttr-Token-B0Prime" */ -626, /* "setAttr-Token-EMV" */ -622, /* "setAttr-TokenType" */ -619, /* "setCext-IssuerCapabilities" */ -615, /* "setCext-PGWYcapabilities" */ -616, /* "setCext-TokenIdentifier" */ -618, /* "setCext-TokenType" */ -617, /* "setCext-Track2Data" */ -611, /* "setCext-cCertRequired" */ -609, /* "setCext-certType" */ -608, /* "setCext-hashedRoot" */ -610, /* "setCext-merchData" */ -613, /* "setCext-setExt" */ -614, /* "setCext-setQualf" */ -612, /* "setCext-tunneling" */ -540, /* "setct-AcqCardCodeMsg" */ -576, /* "setct-AcqCardCodeMsgTBE" */ -570, /* "setct-AuthReqTBE" */ -534, /* "setct-AuthReqTBS" */ -527, /* "setct-AuthResBaggage" */ -571, /* "setct-AuthResTBE" */ -572, /* "setct-AuthResTBEX" */ -535, /* "setct-AuthResTBS" */ -536, /* "setct-AuthResTBSX" */ -528, /* "setct-AuthRevReqBaggage" */ -577, /* "setct-AuthRevReqTBE" */ -541, /* "setct-AuthRevReqTBS" */ -529, /* "setct-AuthRevResBaggage" */ -542, /* "setct-AuthRevResData" */ -578, /* "setct-AuthRevResTBE" */ -579, /* "setct-AuthRevResTBEB" */ -543, /* "setct-AuthRevResTBS" */ -573, /* "setct-AuthTokenTBE" */ -537, /* "setct-AuthTokenTBS" */ -600, /* "setct-BCIDistributionTBS" */ -558, /* "setct-BatchAdminReqData" */ -592, /* "setct-BatchAdminReqTBE" */ -559, /* "setct-BatchAdminResData" */ -593, /* "setct-BatchAdminResTBE" */ -599, /* "setct-CRLNotificationResTBS" */ -598, /* "setct-CRLNotificationTBS" */ -580, /* "setct-CapReqTBE" */ -581, /* "setct-CapReqTBEX" */ -544, /* "setct-CapReqTBS" */ -545, /* "setct-CapReqTBSX" */ -546, /* "setct-CapResData" */ -582, /* "setct-CapResTBE" */ -583, /* "setct-CapRevReqTBE" */ -584, /* "setct-CapRevReqTBEX" */ -547, /* "setct-CapRevReqTBS" */ -548, /* "setct-CapRevReqTBSX" */ -549, /* "setct-CapRevResData" */ -585, /* "setct-CapRevResTBE" */ -538, /* "setct-CapTokenData" */ -530, /* "setct-CapTokenSeq" */ -574, /* "setct-CapTokenTBE" */ -575, /* "setct-CapTokenTBEX" */ -539, /* "setct-CapTokenTBS" */ -560, /* "setct-CardCInitResTBS" */ -566, /* "setct-CertInqReqTBS" */ -563, /* "setct-CertReqData" */ -595, /* "setct-CertReqTBE" */ -596, /* "setct-CertReqTBEX" */ -564, /* "setct-CertReqTBS" */ -565, /* "setct-CertResData" */ -597, /* "setct-CertResTBE" */ -586, /* "setct-CredReqTBE" */ -587, /* "setct-CredReqTBEX" */ -550, /* "setct-CredReqTBS" */ -551, /* "setct-CredReqTBSX" */ -552, /* "setct-CredResData" */ -588, /* "setct-CredResTBE" */ -589, /* "setct-CredRevReqTBE" */ -590, /* "setct-CredRevReqTBEX" */ -553, /* "setct-CredRevReqTBS" */ -554, /* "setct-CredRevReqTBSX" */ -555, /* "setct-CredRevResData" */ -591, /* "setct-CredRevResTBE" */ -567, /* "setct-ErrorTBS" */ -526, /* "setct-HODInput" */ -561, /* "setct-MeAqCInitResTBS" */ -522, /* "setct-OIData" */ -519, /* "setct-PANData" */ -521, /* "setct-PANOnly" */ -520, /* "setct-PANToken" */ -556, /* "setct-PCertReqData" */ -557, /* "setct-PCertResTBS" */ -523, /* "setct-PI" */ -532, /* "setct-PI-TBS" */ -524, /* "setct-PIData" */ -525, /* "setct-PIDataUnsigned" */ -568, /* "setct-PIDualSignedTBE" */ -569, /* "setct-PIUnsignedTBE" */ -531, /* "setct-PInitResData" */ -533, /* "setct-PResData" */ -594, /* "setct-RegFormReqTBE" */ -562, /* "setct-RegFormResTBS" */ -604, /* "setext-pinAny" */ -603, /* "setext-pinSecure" */ -605, /* "setext-track2" */ -41, /* "sha" */ -64, /* "sha1" */ -115, /* "sha1WithRSA" */ -65, /* "sha1WithRSAEncryption" */ -675, /* "sha224" */ -671, /* "sha224WithRSAEncryption" */ -672, /* "sha256" */ -668, /* "sha256WithRSAEncryption" */ -673, /* "sha384" */ -669, /* "sha384WithRSAEncryption" */ -674, /* "sha512" */ -670, /* "sha512WithRSAEncryption" */ -42, /* "shaWithRSAEncryption" */ -52, /* "signingTime" */ -454, /* "simpleSecurityObject" */ -496, /* "singleLevelQuality" */ -16, /* "stateOrProvinceName" */ -660, /* "streetAddress" */ -498, /* "subtreeMaximumQuality" */ -497, /* "subtreeMinimumQuality" */ -890, /* "supportedAlgorithms" */ -874, /* "supportedApplicationContext" */ -100, /* "surname" */ -864, /* "telephoneNumber" */ -866, /* "teletexTerminalIdentifier" */ -865, /* "telexNumber" */ -459, /* "textEncodedORAddress" */ -293, /* "textNotice" */ -106, /* "title" */ -682, /* "tpBasis" */ -436, /* "ucl" */ - 0, /* "undefined" */ -888, /* "uniqueMember" */ -55, /* "unstructuredAddress" */ -49, /* "unstructuredName" */ -880, /* "userCertificate" */ -465, /* "userClass" */ -458, /* "userId" */ -879, /* "userPassword" */ -373, /* "valid" */ -678, /* "wap" */ -679, /* "wap-wsg" */ -735, /* "wap-wsg-idm-ecid-wtls1" */ -743, /* "wap-wsg-idm-ecid-wtls10" */ -744, /* "wap-wsg-idm-ecid-wtls11" */ -745, /* "wap-wsg-idm-ecid-wtls12" */ -736, /* "wap-wsg-idm-ecid-wtls3" */ -737, /* "wap-wsg-idm-ecid-wtls4" */ -738, /* "wap-wsg-idm-ecid-wtls5" */ -739, /* "wap-wsg-idm-ecid-wtls6" */ -740, /* "wap-wsg-idm-ecid-wtls7" */ -741, /* "wap-wsg-idm-ecid-wtls8" */ -742, /* "wap-wsg-idm-ecid-wtls9" */ -804, /* "whirlpool" */ -868, /* "x121Address" */ -948, /* "x25519" */ -503, /* "x500UniqueIdentifier" */ -158, /* "x509Certificate" */ -160, /* "x509Crl" */ -125, /* "zlib compression" */ +static const unsigned kNIDsInLongNameOrder[] = { + 363 /* AD Time Stamping */, + 405 /* ANSI X9.62 */, + 368 /* Acceptable OCSP Responses */, + 910 /* Any Extended Key Usage */, + 664 /* Any language */, + 177 /* Authority Information Access */, + 365 /* Basic OCSP Response */, + 285 /* Biometric Info */, + 179 /* CA Issuers */, + 785 /* CA Repository */, + 131 /* Code Signing */, + 783 /* Diffie-Hellman based MAC */, + 382 /* Directory */, + 392 /* Domain */, + 132 /* E-mail Protection */, + 389 /* Enterprises */, + 384 /* Experimental */, + 372 /* Extended OCSP Status */, + 172 /* Extension Request */, + 813 /* GOST 28147-89 */, + 849 /* GOST 28147-89 Cryptocom ParamSet */, + 815 /* GOST 28147-89 MAC */, + 851 /* GOST 34.10-2001 Cryptocom */, + 850 /* GOST 34.10-94 Cryptocom */, + 811 /* GOST R 34.10-2001 */, + 817 /* GOST R 34.10-2001 DH */, + 812 /* GOST R 34.10-94 */, + 818 /* GOST R 34.10-94 DH */, + 809 /* GOST R 34.11-94 */, + 816 /* GOST R 34.11-94 PRF */, + 807 /* GOST R 34.11-94 with GOST R 34.10-2001 */, + 853 /* GOST R 34.11-94 with GOST R 34.10-2001 Cryptocom */, + 808 /* GOST R 34.11-94 with GOST R 34.10-94 */, + 852 /* GOST R 34.11-94 with GOST R 34.10-94 Cryptocom */, + 854 /* GOST R 3410-2001 Parameter Set Cryptocom */, + 810 /* HMAC GOST 34.11-94 */, + 432 /* Hold Instruction Call Issuer */, + 430 /* Hold Instruction Code */, + 431 /* Hold Instruction None */, + 433 /* Hold Instruction Reject */, + 634 /* ICC or token signature */, + 294 /* IPSec End System */, + 295 /* IPSec Tunnel */, + 296 /* IPSec User */, + 182 /* ISO Member Body */, + 183 /* ISO US Member Body */, + 667 /* Independent */, + 665 /* Inherit all */, + 647 /* International Organizations */, + 142 /* Invalidity Date */, + 504 /* MIME MHS */, + 388 /* Mail */, + 383 /* Management */, + 417 /* Microsoft CSP Name */, + 135 /* Microsoft Commercial Code Signing */, + 138 /* Microsoft Encrypted File System */, + 171 /* Microsoft Extension Request */, + 134 /* Microsoft Individual Code Signing */, + 856 /* Microsoft Local Key set */, + 137 /* Microsoft Server Gated Crypto */, + 648 /* Microsoft Smartcardlogin */, + 136 /* Microsoft Trust List Signing */, + 649 /* Microsoft Universal Principal Name */, + 72 /* Netscape Base Url */, + 76 /* Netscape CA Policy Url */, + 74 /* Netscape CA Revocation Url */, + 71 /* Netscape Cert Type */, + 58 /* Netscape Certificate Extension */, + 79 /* Netscape Certificate Sequence */, + 78 /* Netscape Comment */, + 57 /* Netscape Communications Corp. */, + 59 /* Netscape Data Type */, + 75 /* Netscape Renewal Url */, + 73 /* Netscape Revocation Url */, + 77 /* Netscape SSL Server Name */, + 139 /* Netscape Server Gated Crypto */, + 178 /* OCSP */, + 370 /* OCSP Archive Cutoff */, + 367 /* OCSP CRL ID */, + 369 /* OCSP No Check */, + 366 /* OCSP Nonce */, + 371 /* OCSP Service Locator */, + 180 /* OCSP Signing */, + 161 /* PBES2 */, + 69 /* PBKDF2 */, + 162 /* PBMAC1 */, + 127 /* PKIX */, + 858 /* Permanent Identifier */, + 164 /* Policy Qualifier CPS */, + 165 /* Policy Qualifier User Notice */, + 385 /* Private */, + 663 /* Proxy Certificate Information */, + 1 /* RSA Data Security, Inc. */, + 2 /* RSA Data Security, Inc. PKCS */, + 188 /* S/MIME */, + 167 /* S/MIME Capabilities */, + 387 /* SNMPv2 */, + 512 /* Secure Electronic Transactions */, + 386 /* Security */, + 394 /* Selected Attribute Types */, + 143 /* Strong Extranet ID */, + 398 /* Subject Information Access */, + 130 /* TLS Web Client Authentication */, + 129 /* TLS Web Server Authentication */, + 133 /* Time Stamping */, + 375 /* Trust Root */, + 948 /* X25519 */, + 12 /* X509 */, + 402 /* X509v3 AC Targeting */, + 746 /* X509v3 Any Policy */, + 90 /* X509v3 Authority Key Identifier */, + 87 /* X509v3 Basic Constraints */, + 103 /* X509v3 CRL Distribution Points */, + 88 /* X509v3 CRL Number */, + 141 /* X509v3 CRL Reason Code */, + 771 /* X509v3 Certificate Issuer */, + 89 /* X509v3 Certificate Policies */, + 140 /* X509v3 Delta CRL Indicator */, + 126 /* X509v3 Extended Key Usage */, + 857 /* X509v3 Freshest CRL */, + 748 /* X509v3 Inhibit Any Policy */, + 86 /* X509v3 Issuer Alternative Name */, + 770 /* X509v3 Issuing Distribution Point */, + 83 /* X509v3 Key Usage */, + 666 /* X509v3 Name Constraints */, + 403 /* X509v3 No Revocation Available */, + 401 /* X509v3 Policy Constraints */, + 747 /* X509v3 Policy Mappings */, + 84 /* X509v3 Private Key Usage Period */, + 85 /* X509v3 Subject Alternative Name */, + 769 /* X509v3 Subject Directory Attributes */, + 82 /* X509v3 Subject Key Identifier */, + 920 /* X9.42 DH */, + 184 /* X9.57 */, + 185 /* X9.57 CM ? */, + 478 /* aRecord */, + 289 /* aaControls */, + 287 /* ac-auditEntity */, + 397 /* ac-proxying */, + 288 /* ac-targeting */, + 446 /* account */, + 364 /* ad dvcs */, + 606 /* additional verification */, + 419 /* aes-128-cbc */, + 916 /* aes-128-cbc-hmac-sha1 */, + 896 /* aes-128-ccm */, + 421 /* aes-128-cfb */, + 650 /* aes-128-cfb1 */, + 653 /* aes-128-cfb8 */, + 904 /* aes-128-ctr */, + 418 /* aes-128-ecb */, + 895 /* aes-128-gcm */, + 420 /* aes-128-ofb */, + 913 /* aes-128-xts */, + 423 /* aes-192-cbc */, + 917 /* aes-192-cbc-hmac-sha1 */, + 899 /* aes-192-ccm */, + 425 /* aes-192-cfb */, + 651 /* aes-192-cfb1 */, + 654 /* aes-192-cfb8 */, + 905 /* aes-192-ctr */, + 422 /* aes-192-ecb */, + 898 /* aes-192-gcm */, + 424 /* aes-192-ofb */, + 427 /* aes-256-cbc */, + 918 /* aes-256-cbc-hmac-sha1 */, + 902 /* aes-256-ccm */, + 429 /* aes-256-cfb */, + 652 /* aes-256-cfb1 */, + 655 /* aes-256-cfb8 */, + 906 /* aes-256-ctr */, + 426 /* aes-256-ecb */, + 901 /* aes-256-gcm */, + 428 /* aes-256-ofb */, + 914 /* aes-256-xts */, + 376 /* algorithm */, + 484 /* associatedDomain */, + 485 /* associatedName */, + 501 /* audio */, + 882 /* authorityRevocationList */, + 91 /* bf-cbc */, + 93 /* bf-cfb */, + 92 /* bf-ecb */, + 94 /* bf-ofb */, + 921 /* brainpoolP160r1 */, + 922 /* brainpoolP160t1 */, + 923 /* brainpoolP192r1 */, + 924 /* brainpoolP192t1 */, + 925 /* brainpoolP224r1 */, + 926 /* brainpoolP224t1 */, + 927 /* brainpoolP256r1 */, + 928 /* brainpoolP256t1 */, + 929 /* brainpoolP320r1 */, + 930 /* brainpoolP320t1 */, + 931 /* brainpoolP384r1 */, + 932 /* brainpoolP384t1 */, + 933 /* brainpoolP512r1 */, + 934 /* brainpoolP512t1 */, + 494 /* buildingName */, + 860 /* businessCategory */, + 691 /* c2onb191v4 */, + 692 /* c2onb191v5 */, + 697 /* c2onb239v4 */, + 698 /* c2onb239v5 */, + 684 /* c2pnb163v1 */, + 685 /* c2pnb163v2 */, + 686 /* c2pnb163v3 */, + 687 /* c2pnb176v1 */, + 693 /* c2pnb208w1 */, + 699 /* c2pnb272w1 */, + 700 /* c2pnb304w1 */, + 702 /* c2pnb368w1 */, + 688 /* c2tnb191v1 */, + 689 /* c2tnb191v2 */, + 690 /* c2tnb191v3 */, + 694 /* c2tnb239v1 */, + 695 /* c2tnb239v2 */, + 696 /* c2tnb239v3 */, + 701 /* c2tnb359v1 */, + 703 /* c2tnb431r1 */, + 881 /* cACertificate */, + 483 /* cNAMERecord */, + 751 /* camellia-128-cbc */, + 757 /* camellia-128-cfb */, + 760 /* camellia-128-cfb1 */, + 763 /* camellia-128-cfb8 */, + 754 /* camellia-128-ecb */, + 766 /* camellia-128-ofb */, + 752 /* camellia-192-cbc */, + 758 /* camellia-192-cfb */, + 761 /* camellia-192-cfb1 */, + 764 /* camellia-192-cfb8 */, + 755 /* camellia-192-ecb */, + 767 /* camellia-192-ofb */, + 753 /* camellia-256-cbc */, + 759 /* camellia-256-cfb */, + 762 /* camellia-256-cfb1 */, + 765 /* camellia-256-cfb8 */, + 756 /* camellia-256-ecb */, + 768 /* camellia-256-ofb */, + 443 /* caseIgnoreIA5StringSyntax */, + 108 /* cast5-cbc */, + 110 /* cast5-cfb */, + 109 /* cast5-ecb */, + 111 /* cast5-ofb */, + 152 /* certBag */, + 677 /* certicom-arc */, + 517 /* certificate extensions */, + 883 /* certificateRevocationList */, + 54 /* challengePassword */, + 407 /* characteristic-two-field */, + 395 /* clearance */, + 633 /* cleartext track 2 */, + 894 /* cmac */, + 13 /* commonName */, + 513 /* content types */, + 50 /* contentType */, + 53 /* countersignature */, + 14 /* countryName */, + 153 /* crlBag */, + 884 /* crossCertificatePair */, + 806 /* cryptocom */, + 805 /* cryptopro */, + 500 /* dITRedirect */, + 451 /* dNSDomain */, + 495 /* dSAQuality */, + 434 /* data */, + 390 /* dcObject */, + 891 /* deltaRevocationList */, + 31 /* des-cbc */, + 643 /* des-cdmf */, + 30 /* des-cfb */, + 656 /* des-cfb1 */, + 657 /* des-cfb8 */, + 29 /* des-ecb */, + 32 /* des-ede */, + 43 /* des-ede-cbc */, + 60 /* des-ede-cfb */, + 62 /* des-ede-ofb */, + 33 /* des-ede3 */, + 44 /* des-ede3-cbc */, + 61 /* des-ede3-cfb */, + 658 /* des-ede3-cfb1 */, + 659 /* des-ede3-cfb8 */, + 63 /* des-ede3-ofb */, + 45 /* des-ofb */, + 107 /* description */, + 871 /* destinationIndicator */, + 80 /* desx-cbc */, + 947 /* dh-cofactor-kdf */, + 946 /* dh-std-kdf */, + 28 /* dhKeyAgreement */, + 941 /* dhSinglePass-cofactorDH-sha1kdf-scheme */, + 942 /* dhSinglePass-cofactorDH-sha224kdf-scheme */, + 943 /* dhSinglePass-cofactorDH-sha256kdf-scheme */, + 944 /* dhSinglePass-cofactorDH-sha384kdf-scheme */, + 945 /* dhSinglePass-cofactorDH-sha512kdf-scheme */, + 936 /* dhSinglePass-stdDH-sha1kdf-scheme */, + 937 /* dhSinglePass-stdDH-sha224kdf-scheme */, + 938 /* dhSinglePass-stdDH-sha256kdf-scheme */, + 939 /* dhSinglePass-stdDH-sha384kdf-scheme */, + 940 /* dhSinglePass-stdDH-sha512kdf-scheme */, + 11 /* directory services (X.500) */, + 378 /* directory services - algorithms */, + 887 /* distinguishedName */, + 892 /* dmdName */, + 174 /* dnQualifier */, + 447 /* document */, + 471 /* documentAuthor */, + 468 /* documentIdentifier */, + 472 /* documentLocation */, + 502 /* documentPublisher */, + 449 /* documentSeries */, + 469 /* documentTitle */, + 470 /* documentVersion */, + 380 /* dod */, + 391 /* domainComponent */, + 452 /* domainRelatedObject */, + 116 /* dsaEncryption */, + 67 /* dsaEncryption-old */, + 66 /* dsaWithSHA */, + 113 /* dsaWithSHA1 */, + 70 /* dsaWithSHA1-old */, + 802 /* dsa_with_SHA224 */, + 803 /* dsa_with_SHA256 */, + 297 /* dvcs */, + 791 /* ecdsa-with-Recommended */, + 416 /* ecdsa-with-SHA1 */, + 793 /* ecdsa-with-SHA224 */, + 794 /* ecdsa-with-SHA256 */, + 795 /* ecdsa-with-SHA384 */, + 796 /* ecdsa-with-SHA512 */, + 792 /* ecdsa-with-Specified */, + 48 /* emailAddress */, + 632 /* encrypted track 2 */, + 885 /* enhancedSearchGuide */, + 56 /* extendedCertificateAttributes */, + 867 /* facsimileTelephoneNumber */, + 462 /* favouriteDrink */, + 453 /* friendlyCountry */, + 490 /* friendlyCountryName */, + 156 /* friendlyName */, + 631 /* generate cryptogram */, + 509 /* generationQualifier */, + 601 /* generic cryptogram */, + 99 /* givenName */, + 814 /* gost89-cnt */, + 855 /* hmac */, + 780 /* hmac-md5 */, + 781 /* hmac-sha1 */, + 797 /* hmacWithMD5 */, + 163 /* hmacWithSHA1 */, + 798 /* hmacWithSHA224 */, + 799 /* hmacWithSHA256 */, + 800 /* hmacWithSHA384 */, + 801 /* hmacWithSHA512 */, + 486 /* homePostalAddress */, + 473 /* homeTelephoneNumber */, + 466 /* host */, + 889 /* houseIdentifier */, + 442 /* iA5StringSyntax */, + 381 /* iana */, + 824 /* id-Gost28147-89-CryptoPro-A-ParamSet */, + 825 /* id-Gost28147-89-CryptoPro-B-ParamSet */, + 826 /* id-Gost28147-89-CryptoPro-C-ParamSet */, + 827 /* id-Gost28147-89-CryptoPro-D-ParamSet */, + 819 /* id-Gost28147-89-CryptoPro-KeyMeshing */, + 829 /* id-Gost28147-89-CryptoPro-Oscar-1-0-ParamSet */, + 828 /* id-Gost28147-89-CryptoPro-Oscar-1-1-ParamSet */, + 830 /* id-Gost28147-89-CryptoPro-RIC-1-ParamSet */, + 820 /* id-Gost28147-89-None-KeyMeshing */, + 823 /* id-Gost28147-89-TestParamSet */, + 840 /* id-GostR3410-2001-CryptoPro-A-ParamSet */, + 841 /* id-GostR3410-2001-CryptoPro-B-ParamSet */, + 842 /* id-GostR3410-2001-CryptoPro-C-ParamSet */, + 843 /* id-GostR3410-2001-CryptoPro-XchA-ParamSet */, + 844 /* id-GostR3410-2001-CryptoPro-XchB-ParamSet */, + 839 /* id-GostR3410-2001-TestParamSet */, + 832 /* id-GostR3410-94-CryptoPro-A-ParamSet */, + 833 /* id-GostR3410-94-CryptoPro-B-ParamSet */, + 834 /* id-GostR3410-94-CryptoPro-C-ParamSet */, + 835 /* id-GostR3410-94-CryptoPro-D-ParamSet */, + 836 /* id-GostR3410-94-CryptoPro-XchA-ParamSet */, + 837 /* id-GostR3410-94-CryptoPro-XchB-ParamSet */, + 838 /* id-GostR3410-94-CryptoPro-XchC-ParamSet */, + 831 /* id-GostR3410-94-TestParamSet */, + 845 /* id-GostR3410-94-a */, + 846 /* id-GostR3410-94-aBis */, + 847 /* id-GostR3410-94-b */, + 848 /* id-GostR3410-94-bBis */, + 822 /* id-GostR3411-94-CryptoProParamSet */, + 821 /* id-GostR3411-94-TestParamSet */, + 266 /* id-aca */, + 355 /* id-aca-accessIdentity */, + 354 /* id-aca-authenticationInfo */, + 356 /* id-aca-chargingIdentity */, + 399 /* id-aca-encAttrs */, + 357 /* id-aca-group */, + 358 /* id-aca-role */, + 176 /* id-ad */, + 788 /* id-aes128-wrap */, + 897 /* id-aes128-wrap-pad */, + 789 /* id-aes192-wrap */, + 900 /* id-aes192-wrap-pad */, + 790 /* id-aes256-wrap */, + 903 /* id-aes256-wrap-pad */, + 262 /* id-alg */, + 893 /* id-alg-PWRI-KEK */, + 323 /* id-alg-des40 */, + 326 /* id-alg-dh-pop */, + 325 /* id-alg-dh-sig-hmac-sha1 */, + 324 /* id-alg-noSignature */, + 907 /* id-camellia128-wrap */, + 908 /* id-camellia192-wrap */, + 909 /* id-camellia256-wrap */, + 268 /* id-cct */, + 361 /* id-cct-PKIData */, + 362 /* id-cct-PKIResponse */, + 360 /* id-cct-crs */, + 81 /* id-ce */, + 680 /* id-characteristic-two-basis */, + 263 /* id-cmc */, + 334 /* id-cmc-addExtensions */, + 346 /* id-cmc-confirmCertAcceptance */, + 330 /* id-cmc-dataReturn */, + 336 /* id-cmc-decryptedPOP */, + 335 /* id-cmc-encryptedPOP */, + 339 /* id-cmc-getCRL */, + 338 /* id-cmc-getCert */, + 328 /* id-cmc-identification */, + 329 /* id-cmc-identityProof */, + 337 /* id-cmc-lraPOPWitness */, + 344 /* id-cmc-popLinkRandom */, + 345 /* id-cmc-popLinkWitness */, + 343 /* id-cmc-queryPending */, + 333 /* id-cmc-recipientNonce */, + 341 /* id-cmc-regInfo */, + 342 /* id-cmc-responseInfo */, + 340 /* id-cmc-revokeRequest */, + 332 /* id-cmc-senderNonce */, + 327 /* id-cmc-statusInfo */, + 331 /* id-cmc-transactionId */, + 787 /* id-ct-asciiTextWithCRLF */, + 408 /* id-ecPublicKey */, + 508 /* id-hex-multipart-message */, + 507 /* id-hex-partial-message */, + 260 /* id-it */, + 302 /* id-it-caKeyUpdateInfo */, + 298 /* id-it-caProtEncCert */, + 311 /* id-it-confirmWaitTime */, + 303 /* id-it-currentCRL */, + 300 /* id-it-encKeyPairTypes */, + 310 /* id-it-implicitConfirm */, + 308 /* id-it-keyPairParamRep */, + 307 /* id-it-keyPairParamReq */, + 312 /* id-it-origPKIMessage */, + 301 /* id-it-preferredSymmAlg */, + 309 /* id-it-revPassphrase */, + 299 /* id-it-signKeyPairTypes */, + 305 /* id-it-subscriptionRequest */, + 306 /* id-it-subscriptionResponse */, + 784 /* id-it-suppLangTags */, + 304 /* id-it-unsupportedOIDs */, + 128 /* id-kp */, + 280 /* id-mod-attribute-cert */, + 274 /* id-mod-cmc */, + 277 /* id-mod-cmp */, + 284 /* id-mod-cmp2000 */, + 273 /* id-mod-crmf */, + 283 /* id-mod-dvcs */, + 275 /* id-mod-kea-profile-88 */, + 276 /* id-mod-kea-profile-93 */, + 282 /* id-mod-ocsp */, + 278 /* id-mod-qualified-cert-88 */, + 279 /* id-mod-qualified-cert-93 */, + 281 /* id-mod-timestamp-protocol */, + 264 /* id-on */, + 347 /* id-on-personalData */, + 265 /* id-pda */, + 352 /* id-pda-countryOfCitizenship */, + 353 /* id-pda-countryOfResidence */, + 348 /* id-pda-dateOfBirth */, + 351 /* id-pda-gender */, + 349 /* id-pda-placeOfBirth */, + 175 /* id-pe */, + 261 /* id-pkip */, + 258 /* id-pkix-mod */, + 269 /* id-pkix1-explicit-88 */, + 271 /* id-pkix1-explicit-93 */, + 270 /* id-pkix1-implicit-88 */, + 272 /* id-pkix1-implicit-93 */, + 662 /* id-ppl */, + 267 /* id-qcs */, + 359 /* id-qcs-pkixQCSyntax-v1 */, + 259 /* id-qt */, + 313 /* id-regCtrl */, + 316 /* id-regCtrl-authenticator */, + 319 /* id-regCtrl-oldCertID */, + 318 /* id-regCtrl-pkiArchiveOptions */, + 317 /* id-regCtrl-pkiPublicationInfo */, + 320 /* id-regCtrl-protocolEncrKey */, + 315 /* id-regCtrl-regToken */, + 314 /* id-regInfo */, + 322 /* id-regInfo-certReq */, + 321 /* id-regInfo-utf8Pairs */, + 191 /* id-smime-aa */, + 215 /* id-smime-aa-contentHint */, + 218 /* id-smime-aa-contentIdentifier */, + 221 /* id-smime-aa-contentReference */, + 240 /* id-smime-aa-dvcs-dvc */, + 217 /* id-smime-aa-encapContentType */, + 222 /* id-smime-aa-encrypKeyPref */, + 220 /* id-smime-aa-equivalentLabels */, + 232 /* id-smime-aa-ets-CertificateRefs */, + 233 /* id-smime-aa-ets-RevocationRefs */, + 238 /* id-smime-aa-ets-archiveTimeStamp */, + 237 /* id-smime-aa-ets-certCRLTimestamp */, + 234 /* id-smime-aa-ets-certValues */, + 227 /* id-smime-aa-ets-commitmentType */, + 231 /* id-smime-aa-ets-contentTimestamp */, + 236 /* id-smime-aa-ets-escTimeStamp */, + 230 /* id-smime-aa-ets-otherSigCert */, + 235 /* id-smime-aa-ets-revocationValues */, + 226 /* id-smime-aa-ets-sigPolicyId */, + 229 /* id-smime-aa-ets-signerAttr */, + 228 /* id-smime-aa-ets-signerLocation */, + 219 /* id-smime-aa-macValue */, + 214 /* id-smime-aa-mlExpandHistory */, + 216 /* id-smime-aa-msgSigDigest */, + 212 /* id-smime-aa-receiptRequest */, + 213 /* id-smime-aa-securityLabel */, + 239 /* id-smime-aa-signatureType */, + 223 /* id-smime-aa-signingCertificate */, + 224 /* id-smime-aa-smimeEncryptCerts */, + 225 /* id-smime-aa-timeStampToken */, + 192 /* id-smime-alg */, + 243 /* id-smime-alg-3DESwrap */, + 246 /* id-smime-alg-CMS3DESwrap */, + 247 /* id-smime-alg-CMSRC2wrap */, + 245 /* id-smime-alg-ESDH */, + 241 /* id-smime-alg-ESDHwith3DES */, + 242 /* id-smime-alg-ESDHwithRC2 */, + 244 /* id-smime-alg-RC2wrap */, + 193 /* id-smime-cd */, + 248 /* id-smime-cd-ldap */, + 190 /* id-smime-ct */, + 210 /* id-smime-ct-DVCSRequestData */, + 211 /* id-smime-ct-DVCSResponseData */, + 208 /* id-smime-ct-TDTInfo */, + 207 /* id-smime-ct-TSTInfo */, + 205 /* id-smime-ct-authData */, + 786 /* id-smime-ct-compressedData */, + 209 /* id-smime-ct-contentInfo */, + 206 /* id-smime-ct-publishCert */, + 204 /* id-smime-ct-receipt */, + 195 /* id-smime-cti */, + 255 /* id-smime-cti-ets-proofOfApproval */, + 256 /* id-smime-cti-ets-proofOfCreation */, + 253 /* id-smime-cti-ets-proofOfDelivery */, + 251 /* id-smime-cti-ets-proofOfOrigin */, + 252 /* id-smime-cti-ets-proofOfReceipt */, + 254 /* id-smime-cti-ets-proofOfSender */, + 189 /* id-smime-mod */, + 196 /* id-smime-mod-cms */, + 197 /* id-smime-mod-ess */, + 202 /* id-smime-mod-ets-eSigPolicy-88 */, + 203 /* id-smime-mod-ets-eSigPolicy-97 */, + 200 /* id-smime-mod-ets-eSignature-88 */, + 201 /* id-smime-mod-ets-eSignature-97 */, + 199 /* id-smime-mod-msg-v3 */, + 198 /* id-smime-mod-oid */, + 194 /* id-smime-spq */, + 250 /* id-smime-spq-ets-sqt-unotice */, + 249 /* id-smime-spq-ets-sqt-uri */, + 34 /* idea-cbc */, + 35 /* idea-cfb */, + 36 /* idea-ecb */, + 46 /* idea-ofb */, + 676 /* identified-organization */, + 461 /* info */, + 101 /* initials */, + 869 /* internationaliSDNNumber */, + 749 /* ipsec3 */, + 750 /* ipsec4 */, + 181 /* iso */, + 623 /* issuer capabilities */, + 645 /* itu-t */, + 492 /* janetMailbox */, + 646 /* joint-iso-itu-t */, + 150 /* keyBag */, + 773 /* kisa */, + 477 /* lastModifiedBy */, + 476 /* lastModifiedTime */, + 157 /* localKeyID */, + 15 /* localityName */, + 480 /* mXRecord */, + 493 /* mailPreferenceOption */, + 467 /* manager */, + 3 /* md2 */, + 7 /* md2WithRSAEncryption */, + 257 /* md4 */, + 396 /* md4WithRSAEncryption */, + 4 /* md5 */, + 114 /* md5-sha1 */, + 104 /* md5WithRSA */, + 8 /* md5WithRSAEncryption */, + 95 /* mdc2 */, + 96 /* mdc2WithRSA */, + 875 /* member */, + 602 /* merchant initiated auth */, + 514 /* message extensions */, + 51 /* messageDigest */, + 911 /* mgf1 */, + 506 /* mime-mhs-bodies */, + 505 /* mime-mhs-headings */, + 488 /* mobileTelephoneNumber */, + 481 /* nSRecord */, + 173 /* name */, + 681 /* onBasis */, + 379 /* org */, + 17 /* organizationName */, + 491 /* organizationalStatus */, + 18 /* organizationalUnitName */, + 475 /* otherMailbox */, + 876 /* owner */, + 935 /* pSpecified */, + 489 /* pagerTelephoneNumber */, + 782 /* password based MAC */, + 374 /* path */, + 621 /* payment gateway capabilities */, + 9 /* pbeWithMD2AndDES-CBC */, + 168 /* pbeWithMD2AndRC2-CBC */, + 112 /* pbeWithMD5AndCast5CBC */, + 10 /* pbeWithMD5AndDES-CBC */, + 169 /* pbeWithMD5AndRC2-CBC */, + 148 /* pbeWithSHA1And128BitRC2-CBC */, + 144 /* pbeWithSHA1And128BitRC4 */, + 147 /* pbeWithSHA1And2-KeyTripleDES-CBC */, + 146 /* pbeWithSHA1And3-KeyTripleDES-CBC */, + 149 /* pbeWithSHA1And40BitRC2-CBC */, + 145 /* pbeWithSHA1And40BitRC4 */, + 170 /* pbeWithSHA1AndDES-CBC */, + 68 /* pbeWithSHA1AndRC2-CBC */, + 499 /* personalSignature */, + 487 /* personalTitle */, + 464 /* photo */, + 863 /* physicalDeliveryOfficeName */, + 437 /* pilot */, + 439 /* pilotAttributeSyntax */, + 438 /* pilotAttributeType */, + 479 /* pilotAttributeType27 */, + 456 /* pilotDSA */, + 441 /* pilotGroups */, + 444 /* pilotObject */, + 440 /* pilotObjectClass */, + 455 /* pilotOrganization */, + 445 /* pilotPerson */, + 186 /* pkcs1 */, + 27 /* pkcs3 */, + 187 /* pkcs5 */, + 20 /* pkcs7 */, + 21 /* pkcs7-data */, + 25 /* pkcs7-digestData */, + 26 /* pkcs7-encryptedData */, + 23 /* pkcs7-envelopedData */, + 24 /* pkcs7-signedAndEnvelopedData */, + 22 /* pkcs7-signedData */, + 151 /* pkcs8ShroudedKeyBag */, + 47 /* pkcs9 */, + 862 /* postOfficeBox */, + 861 /* postalAddress */, + 661 /* postalCode */, + 683 /* ppBasis */, + 872 /* preferredDeliveryMethod */, + 873 /* presentationAddress */, + 406 /* prime-field */, + 409 /* prime192v1 */, + 410 /* prime192v2 */, + 411 /* prime192v3 */, + 412 /* prime239v1 */, + 413 /* prime239v2 */, + 414 /* prime239v3 */, + 415 /* prime256v1 */, + 886 /* protocolInformation */, + 510 /* pseudonym */, + 435 /* pss */, + 286 /* qcStatements */, + 457 /* qualityLabelledData */, + 450 /* rFC822localPart */, + 98 /* rc2-40-cbc */, + 166 /* rc2-64-cbc */, + 37 /* rc2-cbc */, + 39 /* rc2-cfb */, + 38 /* rc2-ecb */, + 40 /* rc2-ofb */, + 5 /* rc4 */, + 97 /* rc4-40 */, + 915 /* rc4-hmac-md5 */, + 120 /* rc5-cbc */, + 122 /* rc5-cfb */, + 121 /* rc5-ecb */, + 123 /* rc5-ofb */, + 870 /* registeredAddress */, + 460 /* rfc822Mailbox */, + 117 /* ripemd160 */, + 119 /* ripemd160WithRSA */, + 400 /* role */, + 877 /* roleOccupant */, + 448 /* room */, + 463 /* roomNumber */, + 19 /* rsa */, + 6 /* rsaEncryption */, + 644 /* rsaOAEPEncryptionSET */, + 377 /* rsaSignature */, + 919 /* rsaesOaep */, + 912 /* rsassaPss */, + 482 /* sOARecord */, + 155 /* safeContentsBag */, + 291 /* sbgp-autonomousSysNum */, + 290 /* sbgp-ipAddrBlock */, + 292 /* sbgp-routerIdentifier */, + 159 /* sdsiCertificate */, + 859 /* searchGuide */, + 704 /* secp112r1 */, + 705 /* secp112r2 */, + 706 /* secp128r1 */, + 707 /* secp128r2 */, + 708 /* secp160k1 */, + 709 /* secp160r1 */, + 710 /* secp160r2 */, + 711 /* secp192k1 */, + 712 /* secp224k1 */, + 713 /* secp224r1 */, + 714 /* secp256k1 */, + 715 /* secp384r1 */, + 716 /* secp521r1 */, + 154 /* secretBag */, + 474 /* secretary */, + 717 /* sect113r1 */, + 718 /* sect113r2 */, + 719 /* sect131r1 */, + 720 /* sect131r2 */, + 721 /* sect163k1 */, + 722 /* sect163r1 */, + 723 /* sect163r2 */, + 724 /* sect193r1 */, + 725 /* sect193r2 */, + 726 /* sect233k1 */, + 727 /* sect233r1 */, + 728 /* sect239k1 */, + 729 /* sect283k1 */, + 730 /* sect283r1 */, + 731 /* sect409k1 */, + 732 /* sect409r1 */, + 733 /* sect571k1 */, + 734 /* sect571r1 */, + 635 /* secure device signature */, + 878 /* seeAlso */, + 777 /* seed-cbc */, + 779 /* seed-cfb */, + 776 /* seed-ecb */, + 778 /* seed-ofb */, + 105 /* serialNumber */, + 625 /* set-addPolicy */, + 515 /* set-attr */, + 518 /* set-brand */, + 638 /* set-brand-AmericanExpress */, + 637 /* set-brand-Diners */, + 636 /* set-brand-IATA-ATA */, + 639 /* set-brand-JCB */, + 641 /* set-brand-MasterCard */, + 642 /* set-brand-Novus */, + 640 /* set-brand-Visa */, + 516 /* set-policy */, + 607 /* set-policy-root */, + 624 /* set-rootKeyThumb */, + 620 /* setAttr-Cert */, + 628 /* setAttr-IssCap-CVM */, + 630 /* setAttr-IssCap-Sig */, + 629 /* setAttr-IssCap-T2 */, + 627 /* setAttr-Token-B0Prime */, + 626 /* setAttr-Token-EMV */, + 622 /* setAttr-TokenType */, + 619 /* setCext-IssuerCapabilities */, + 615 /* setCext-PGWYcapabilities */, + 616 /* setCext-TokenIdentifier */, + 618 /* setCext-TokenType */, + 617 /* setCext-Track2Data */, + 611 /* setCext-cCertRequired */, + 609 /* setCext-certType */, + 608 /* setCext-hashedRoot */, + 610 /* setCext-merchData */, + 613 /* setCext-setExt */, + 614 /* setCext-setQualf */, + 612 /* setCext-tunneling */, + 540 /* setct-AcqCardCodeMsg */, + 576 /* setct-AcqCardCodeMsgTBE */, + 570 /* setct-AuthReqTBE */, + 534 /* setct-AuthReqTBS */, + 527 /* setct-AuthResBaggage */, + 571 /* setct-AuthResTBE */, + 572 /* setct-AuthResTBEX */, + 535 /* setct-AuthResTBS */, + 536 /* setct-AuthResTBSX */, + 528 /* setct-AuthRevReqBaggage */, + 577 /* setct-AuthRevReqTBE */, + 541 /* setct-AuthRevReqTBS */, + 529 /* setct-AuthRevResBaggage */, + 542 /* setct-AuthRevResData */, + 578 /* setct-AuthRevResTBE */, + 579 /* setct-AuthRevResTBEB */, + 543 /* setct-AuthRevResTBS */, + 573 /* setct-AuthTokenTBE */, + 537 /* setct-AuthTokenTBS */, + 600 /* setct-BCIDistributionTBS */, + 558 /* setct-BatchAdminReqData */, + 592 /* setct-BatchAdminReqTBE */, + 559 /* setct-BatchAdminResData */, + 593 /* setct-BatchAdminResTBE */, + 599 /* setct-CRLNotificationResTBS */, + 598 /* setct-CRLNotificationTBS */, + 580 /* setct-CapReqTBE */, + 581 /* setct-CapReqTBEX */, + 544 /* setct-CapReqTBS */, + 545 /* setct-CapReqTBSX */, + 546 /* setct-CapResData */, + 582 /* setct-CapResTBE */, + 583 /* setct-CapRevReqTBE */, + 584 /* setct-CapRevReqTBEX */, + 547 /* setct-CapRevReqTBS */, + 548 /* setct-CapRevReqTBSX */, + 549 /* setct-CapRevResData */, + 585 /* setct-CapRevResTBE */, + 538 /* setct-CapTokenData */, + 530 /* setct-CapTokenSeq */, + 574 /* setct-CapTokenTBE */, + 575 /* setct-CapTokenTBEX */, + 539 /* setct-CapTokenTBS */, + 560 /* setct-CardCInitResTBS */, + 566 /* setct-CertInqReqTBS */, + 563 /* setct-CertReqData */, + 595 /* setct-CertReqTBE */, + 596 /* setct-CertReqTBEX */, + 564 /* setct-CertReqTBS */, + 565 /* setct-CertResData */, + 597 /* setct-CertResTBE */, + 586 /* setct-CredReqTBE */, + 587 /* setct-CredReqTBEX */, + 550 /* setct-CredReqTBS */, + 551 /* setct-CredReqTBSX */, + 552 /* setct-CredResData */, + 588 /* setct-CredResTBE */, + 589 /* setct-CredRevReqTBE */, + 590 /* setct-CredRevReqTBEX */, + 553 /* setct-CredRevReqTBS */, + 554 /* setct-CredRevReqTBSX */, + 555 /* setct-CredRevResData */, + 591 /* setct-CredRevResTBE */, + 567 /* setct-ErrorTBS */, + 526 /* setct-HODInput */, + 561 /* setct-MeAqCInitResTBS */, + 522 /* setct-OIData */, + 519 /* setct-PANData */, + 521 /* setct-PANOnly */, + 520 /* setct-PANToken */, + 556 /* setct-PCertReqData */, + 557 /* setct-PCertResTBS */, + 523 /* setct-PI */, + 532 /* setct-PI-TBS */, + 524 /* setct-PIData */, + 525 /* setct-PIDataUnsigned */, + 568 /* setct-PIDualSignedTBE */, + 569 /* setct-PIUnsignedTBE */, + 531 /* setct-PInitResData */, + 533 /* setct-PResData */, + 594 /* setct-RegFormReqTBE */, + 562 /* setct-RegFormResTBS */, + 604 /* setext-pinAny */, + 603 /* setext-pinSecure */, + 605 /* setext-track2 */, + 41 /* sha */, + 64 /* sha1 */, + 115 /* sha1WithRSA */, + 65 /* sha1WithRSAEncryption */, + 675 /* sha224 */, + 671 /* sha224WithRSAEncryption */, + 672 /* sha256 */, + 668 /* sha256WithRSAEncryption */, + 673 /* sha384 */, + 669 /* sha384WithRSAEncryption */, + 674 /* sha512 */, + 670 /* sha512WithRSAEncryption */, + 42 /* shaWithRSAEncryption */, + 52 /* signingTime */, + 454 /* simpleSecurityObject */, + 496 /* singleLevelQuality */, + 16 /* stateOrProvinceName */, + 660 /* streetAddress */, + 498 /* subtreeMaximumQuality */, + 497 /* subtreeMinimumQuality */, + 890 /* supportedAlgorithms */, + 874 /* supportedApplicationContext */, + 100 /* surname */, + 864 /* telephoneNumber */, + 866 /* teletexTerminalIdentifier */, + 865 /* telexNumber */, + 459 /* textEncodedORAddress */, + 293 /* textNotice */, + 106 /* title */, + 682 /* tpBasis */, + 436 /* ucl */, + 0 /* undefined */, + 888 /* uniqueMember */, + 55 /* unstructuredAddress */, + 49 /* unstructuredName */, + 880 /* userCertificate */, + 465 /* userClass */, + 458 /* userId */, + 879 /* userPassword */, + 373 /* valid */, + 678 /* wap */, + 679 /* wap-wsg */, + 735 /* wap-wsg-idm-ecid-wtls1 */, + 743 /* wap-wsg-idm-ecid-wtls10 */, + 744 /* wap-wsg-idm-ecid-wtls11 */, + 745 /* wap-wsg-idm-ecid-wtls12 */, + 736 /* wap-wsg-idm-ecid-wtls3 */, + 737 /* wap-wsg-idm-ecid-wtls4 */, + 738 /* wap-wsg-idm-ecid-wtls5 */, + 739 /* wap-wsg-idm-ecid-wtls6 */, + 740 /* wap-wsg-idm-ecid-wtls7 */, + 741 /* wap-wsg-idm-ecid-wtls8 */, + 742 /* wap-wsg-idm-ecid-wtls9 */, + 804 /* whirlpool */, + 868 /* x121Address */, + 503 /* x500UniqueIdentifier */, + 158 /* x509Certificate */, + 160 /* x509Crl */, + 125 /* zlib compression */, }; -static const unsigned int kNIDsInOIDOrder[NUM_OBJ]={ - 0, /* OBJ_undef 0 */ -181, /* OBJ_iso 1 */ -393, /* OBJ_joint_iso_ccitt OBJ_joint_iso_itu_t */ -404, /* OBJ_ccitt OBJ_itu_t */ -645, /* OBJ_itu_t 0 */ -646, /* OBJ_joint_iso_itu_t 2 */ -434, /* OBJ_data 0 9 */ -182, /* OBJ_member_body 1 2 */ -379, /* OBJ_org 1 3 */ -676, /* OBJ_identified_organization 1 3 */ -11, /* OBJ_X500 2 5 */ -647, /* OBJ_international_organizations 2 23 */ -380, /* OBJ_dod 1 3 6 */ -12, /* OBJ_X509 2 5 4 */ -378, /* OBJ_X500algorithms 2 5 8 */ -81, /* OBJ_id_ce 2 5 29 */ -512, /* OBJ_id_set 2 23 42 */ -678, /* OBJ_wap 2 23 43 */ -435, /* OBJ_pss 0 9 2342 */ -183, /* OBJ_ISO_US 1 2 840 */ -381, /* OBJ_iana 1 3 6 1 */ -677, /* OBJ_certicom_arc 1 3 132 */ -394, /* OBJ_selected_attribute_types 2 5 1 5 */ -13, /* OBJ_commonName 2 5 4 3 */ -100, /* OBJ_surname 2 5 4 4 */ -105, /* OBJ_serialNumber 2 5 4 5 */ -14, /* OBJ_countryName 2 5 4 6 */ -15, /* OBJ_localityName 2 5 4 7 */ -16, /* OBJ_stateOrProvinceName 2 5 4 8 */ -660, /* OBJ_streetAddress 2 5 4 9 */ -17, /* OBJ_organizationName 2 5 4 10 */ -18, /* OBJ_organizationalUnitName 2 5 4 11 */ -106, /* OBJ_title 2 5 4 12 */ -107, /* OBJ_description 2 5 4 13 */ -859, /* OBJ_searchGuide 2 5 4 14 */ -860, /* OBJ_businessCategory 2 5 4 15 */ -861, /* OBJ_postalAddress 2 5 4 16 */ -661, /* OBJ_postalCode 2 5 4 17 */ -862, /* OBJ_postOfficeBox 2 5 4 18 */ -863, /* OBJ_physicalDeliveryOfficeName 2 5 4 19 */ -864, /* OBJ_telephoneNumber 2 5 4 20 */ -865, /* OBJ_telexNumber 2 5 4 21 */ -866, /* OBJ_teletexTerminalIdentifier 2 5 4 22 */ -867, /* OBJ_facsimileTelephoneNumber 2 5 4 23 */ -868, /* OBJ_x121Address 2 5 4 24 */ -869, /* OBJ_internationaliSDNNumber 2 5 4 25 */ -870, /* OBJ_registeredAddress 2 5 4 26 */ -871, /* OBJ_destinationIndicator 2 5 4 27 */ -872, /* OBJ_preferredDeliveryMethod 2 5 4 28 */ -873, /* OBJ_presentationAddress 2 5 4 29 */ -874, /* OBJ_supportedApplicationContext 2 5 4 30 */ -875, /* OBJ_member 2 5 4 31 */ -876, /* OBJ_owner 2 5 4 32 */ -877, /* OBJ_roleOccupant 2 5 4 33 */ -878, /* OBJ_seeAlso 2 5 4 34 */ -879, /* OBJ_userPassword 2 5 4 35 */ -880, /* OBJ_userCertificate 2 5 4 36 */ -881, /* OBJ_cACertificate 2 5 4 37 */ -882, /* OBJ_authorityRevocationList 2 5 4 38 */ -883, /* OBJ_certificateRevocationList 2 5 4 39 */ -884, /* OBJ_crossCertificatePair 2 5 4 40 */ -173, /* OBJ_name 2 5 4 41 */ -99, /* OBJ_givenName 2 5 4 42 */ -101, /* OBJ_initials 2 5 4 43 */ -509, /* OBJ_generationQualifier 2 5 4 44 */ -503, /* OBJ_x500UniqueIdentifier 2 5 4 45 */ -174, /* OBJ_dnQualifier 2 5 4 46 */ -885, /* OBJ_enhancedSearchGuide 2 5 4 47 */ -886, /* OBJ_protocolInformation 2 5 4 48 */ -887, /* OBJ_distinguishedName 2 5 4 49 */ -888, /* OBJ_uniqueMember 2 5 4 50 */ -889, /* OBJ_houseIdentifier 2 5 4 51 */ -890, /* OBJ_supportedAlgorithms 2 5 4 52 */ -891, /* OBJ_deltaRevocationList 2 5 4 53 */ -892, /* OBJ_dmdName 2 5 4 54 */ -510, /* OBJ_pseudonym 2 5 4 65 */ -400, /* OBJ_role 2 5 4 72 */ -769, /* OBJ_subject_directory_attributes 2 5 29 9 */ -82, /* OBJ_subject_key_identifier 2 5 29 14 */ -83, /* OBJ_key_usage 2 5 29 15 */ -84, /* OBJ_private_key_usage_period 2 5 29 16 */ -85, /* OBJ_subject_alt_name 2 5 29 17 */ -86, /* OBJ_issuer_alt_name 2 5 29 18 */ -87, /* OBJ_basic_constraints 2 5 29 19 */ -88, /* OBJ_crl_number 2 5 29 20 */ -141, /* OBJ_crl_reason 2 5 29 21 */ -430, /* OBJ_hold_instruction_code 2 5 29 23 */ -142, /* OBJ_invalidity_date 2 5 29 24 */ -140, /* OBJ_delta_crl 2 5 29 27 */ -770, /* OBJ_issuing_distribution_point 2 5 29 28 */ -771, /* OBJ_certificate_issuer 2 5 29 29 */ -666, /* OBJ_name_constraints 2 5 29 30 */ -103, /* OBJ_crl_distribution_points 2 5 29 31 */ -89, /* OBJ_certificate_policies 2 5 29 32 */ -747, /* OBJ_policy_mappings 2 5 29 33 */ -90, /* OBJ_authority_key_identifier 2 5 29 35 */ -401, /* OBJ_policy_constraints 2 5 29 36 */ -126, /* OBJ_ext_key_usage 2 5 29 37 */ -857, /* OBJ_freshest_crl 2 5 29 46 */ -748, /* OBJ_inhibit_any_policy 2 5 29 54 */ -402, /* OBJ_target_information 2 5 29 55 */ -403, /* OBJ_no_rev_avail 2 5 29 56 */ -513, /* OBJ_set_ctype 2 23 42 0 */ -514, /* OBJ_set_msgExt 2 23 42 1 */ -515, /* OBJ_set_attr 2 23 42 3 */ -516, /* OBJ_set_policy 2 23 42 5 */ -517, /* OBJ_set_certExt 2 23 42 7 */ -518, /* OBJ_set_brand 2 23 42 8 */ -679, /* OBJ_wap_wsg 2 23 43 1 */ -382, /* OBJ_Directory 1 3 6 1 1 */ -383, /* OBJ_Management 1 3 6 1 2 */ -384, /* OBJ_Experimental 1 3 6 1 3 */ -385, /* OBJ_Private 1 3 6 1 4 */ -386, /* OBJ_Security 1 3 6 1 5 */ -387, /* OBJ_SNMPv2 1 3 6 1 6 */ -388, /* OBJ_Mail 1 3 6 1 7 */ -376, /* OBJ_algorithm 1 3 14 3 2 */ -395, /* OBJ_clearance 2 5 1 5 55 */ -19, /* OBJ_rsa 2 5 8 1 1 */ -96, /* OBJ_mdc2WithRSA 2 5 8 3 100 */ -95, /* OBJ_mdc2 2 5 8 3 101 */ -746, /* OBJ_any_policy 2 5 29 32 0 */ -910, /* OBJ_anyExtendedKeyUsage 2 5 29 37 0 */ -519, /* OBJ_setct_PANData 2 23 42 0 0 */ -520, /* OBJ_setct_PANToken 2 23 42 0 1 */ -521, /* OBJ_setct_PANOnly 2 23 42 0 2 */ -522, /* OBJ_setct_OIData 2 23 42 0 3 */ -523, /* OBJ_setct_PI 2 23 42 0 4 */ -524, /* OBJ_setct_PIData 2 23 42 0 5 */ -525, /* OBJ_setct_PIDataUnsigned 2 23 42 0 6 */ -526, /* OBJ_setct_HODInput 2 23 42 0 7 */ -527, /* OBJ_setct_AuthResBaggage 2 23 42 0 8 */ -528, /* OBJ_setct_AuthRevReqBaggage 2 23 42 0 9 */ -529, /* OBJ_setct_AuthRevResBaggage 2 23 42 0 10 */ -530, /* OBJ_setct_CapTokenSeq 2 23 42 0 11 */ -531, /* OBJ_setct_PInitResData 2 23 42 0 12 */ -532, /* OBJ_setct_PI_TBS 2 23 42 0 13 */ -533, /* OBJ_setct_PResData 2 23 42 0 14 */ -534, /* OBJ_setct_AuthReqTBS 2 23 42 0 16 */ -535, /* OBJ_setct_AuthResTBS 2 23 42 0 17 */ -536, /* OBJ_setct_AuthResTBSX 2 23 42 0 18 */ -537, /* OBJ_setct_AuthTokenTBS 2 23 42 0 19 */ -538, /* OBJ_setct_CapTokenData 2 23 42 0 20 */ -539, /* OBJ_setct_CapTokenTBS 2 23 42 0 21 */ -540, /* OBJ_setct_AcqCardCodeMsg 2 23 42 0 22 */ -541, /* OBJ_setct_AuthRevReqTBS 2 23 42 0 23 */ -542, /* OBJ_setct_AuthRevResData 2 23 42 0 24 */ -543, /* OBJ_setct_AuthRevResTBS 2 23 42 0 25 */ -544, /* OBJ_setct_CapReqTBS 2 23 42 0 26 */ -545, /* OBJ_setct_CapReqTBSX 2 23 42 0 27 */ -546, /* OBJ_setct_CapResData 2 23 42 0 28 */ -547, /* OBJ_setct_CapRevReqTBS 2 23 42 0 29 */ -548, /* OBJ_setct_CapRevReqTBSX 2 23 42 0 30 */ -549, /* OBJ_setct_CapRevResData 2 23 42 0 31 */ -550, /* OBJ_setct_CredReqTBS 2 23 42 0 32 */ -551, /* OBJ_setct_CredReqTBSX 2 23 42 0 33 */ -552, /* OBJ_setct_CredResData 2 23 42 0 34 */ -553, /* OBJ_setct_CredRevReqTBS 2 23 42 0 35 */ -554, /* OBJ_setct_CredRevReqTBSX 2 23 42 0 36 */ -555, /* OBJ_setct_CredRevResData 2 23 42 0 37 */ -556, /* OBJ_setct_PCertReqData 2 23 42 0 38 */ -557, /* OBJ_setct_PCertResTBS 2 23 42 0 39 */ -558, /* OBJ_setct_BatchAdminReqData 2 23 42 0 40 */ -559, /* OBJ_setct_BatchAdminResData 2 23 42 0 41 */ -560, /* OBJ_setct_CardCInitResTBS 2 23 42 0 42 */ -561, /* OBJ_setct_MeAqCInitResTBS 2 23 42 0 43 */ -562, /* OBJ_setct_RegFormResTBS 2 23 42 0 44 */ -563, /* OBJ_setct_CertReqData 2 23 42 0 45 */ -564, /* OBJ_setct_CertReqTBS 2 23 42 0 46 */ -565, /* OBJ_setct_CertResData 2 23 42 0 47 */ -566, /* OBJ_setct_CertInqReqTBS 2 23 42 0 48 */ -567, /* OBJ_setct_ErrorTBS 2 23 42 0 49 */ -568, /* OBJ_setct_PIDualSignedTBE 2 23 42 0 50 */ -569, /* OBJ_setct_PIUnsignedTBE 2 23 42 0 51 */ -570, /* OBJ_setct_AuthReqTBE 2 23 42 0 52 */ -571, /* OBJ_setct_AuthResTBE 2 23 42 0 53 */ -572, /* OBJ_setct_AuthResTBEX 2 23 42 0 54 */ -573, /* OBJ_setct_AuthTokenTBE 2 23 42 0 55 */ -574, /* OBJ_setct_CapTokenTBE 2 23 42 0 56 */ -575, /* OBJ_setct_CapTokenTBEX 2 23 42 0 57 */ -576, /* OBJ_setct_AcqCardCodeMsgTBE 2 23 42 0 58 */ -577, /* OBJ_setct_AuthRevReqTBE 2 23 42 0 59 */ -578, /* OBJ_setct_AuthRevResTBE 2 23 42 0 60 */ -579, /* OBJ_setct_AuthRevResTBEB 2 23 42 0 61 */ -580, /* OBJ_setct_CapReqTBE 2 23 42 0 62 */ -581, /* OBJ_setct_CapReqTBEX 2 23 42 0 63 */ -582, /* OBJ_setct_CapResTBE 2 23 42 0 64 */ -583, /* OBJ_setct_CapRevReqTBE 2 23 42 0 65 */ -584, /* OBJ_setct_CapRevReqTBEX 2 23 42 0 66 */ -585, /* OBJ_setct_CapRevResTBE 2 23 42 0 67 */ -586, /* OBJ_setct_CredReqTBE 2 23 42 0 68 */ -587, /* OBJ_setct_CredReqTBEX 2 23 42 0 69 */ -588, /* OBJ_setct_CredResTBE 2 23 42 0 70 */ -589, /* OBJ_setct_CredRevReqTBE 2 23 42 0 71 */ -590, /* OBJ_setct_CredRevReqTBEX 2 23 42 0 72 */ -591, /* OBJ_setct_CredRevResTBE 2 23 42 0 73 */ -592, /* OBJ_setct_BatchAdminReqTBE 2 23 42 0 74 */ -593, /* OBJ_setct_BatchAdminResTBE 2 23 42 0 75 */ -594, /* OBJ_setct_RegFormReqTBE 2 23 42 0 76 */ -595, /* OBJ_setct_CertReqTBE 2 23 42 0 77 */ -596, /* OBJ_setct_CertReqTBEX 2 23 42 0 78 */ -597, /* OBJ_setct_CertResTBE 2 23 42 0 79 */ -598, /* OBJ_setct_CRLNotificationTBS 2 23 42 0 80 */ -599, /* OBJ_setct_CRLNotificationResTBS 2 23 42 0 81 */ -600, /* OBJ_setct_BCIDistributionTBS 2 23 42 0 82 */ -601, /* OBJ_setext_genCrypt 2 23 42 1 1 */ -602, /* OBJ_setext_miAuth 2 23 42 1 3 */ -603, /* OBJ_setext_pinSecure 2 23 42 1 4 */ -604, /* OBJ_setext_pinAny 2 23 42 1 5 */ -605, /* OBJ_setext_track2 2 23 42 1 7 */ -606, /* OBJ_setext_cv 2 23 42 1 8 */ -620, /* OBJ_setAttr_Cert 2 23 42 3 0 */ -621, /* OBJ_setAttr_PGWYcap 2 23 42 3 1 */ -622, /* OBJ_setAttr_TokenType 2 23 42 3 2 */ -623, /* OBJ_setAttr_IssCap 2 23 42 3 3 */ -607, /* OBJ_set_policy_root 2 23 42 5 0 */ -608, /* OBJ_setCext_hashedRoot 2 23 42 7 0 */ -609, /* OBJ_setCext_certType 2 23 42 7 1 */ -610, /* OBJ_setCext_merchData 2 23 42 7 2 */ -611, /* OBJ_setCext_cCertRequired 2 23 42 7 3 */ -612, /* OBJ_setCext_tunneling 2 23 42 7 4 */ -613, /* OBJ_setCext_setExt 2 23 42 7 5 */ -614, /* OBJ_setCext_setQualf 2 23 42 7 6 */ -615, /* OBJ_setCext_PGWYcapabilities 2 23 42 7 7 */ -616, /* OBJ_setCext_TokenIdentifier 2 23 42 7 8 */ -617, /* OBJ_setCext_Track2Data 2 23 42 7 9 */ -618, /* OBJ_setCext_TokenType 2 23 42 7 10 */ -619, /* OBJ_setCext_IssuerCapabilities 2 23 42 7 11 */ -636, /* OBJ_set_brand_IATA_ATA 2 23 42 8 1 */ -640, /* OBJ_set_brand_Visa 2 23 42 8 4 */ -641, /* OBJ_set_brand_MasterCard 2 23 42 8 5 */ -637, /* OBJ_set_brand_Diners 2 23 42 8 30 */ -638, /* OBJ_set_brand_AmericanExpress 2 23 42 8 34 */ -639, /* OBJ_set_brand_JCB 2 23 42 8 35 */ -805, /* OBJ_cryptopro 1 2 643 2 2 */ -806, /* OBJ_cryptocom 1 2 643 2 9 */ -184, /* OBJ_X9_57 1 2 840 10040 */ -405, /* OBJ_ansi_X9_62 1 2 840 10045 */ -389, /* OBJ_Enterprises 1 3 6 1 4 1 */ -504, /* OBJ_mime_mhs 1 3 6 1 7 1 */ -104, /* OBJ_md5WithRSA 1 3 14 3 2 3 */ -29, /* OBJ_des_ecb 1 3 14 3 2 6 */ -31, /* OBJ_des_cbc 1 3 14 3 2 7 */ -45, /* OBJ_des_ofb64 1 3 14 3 2 8 */ -30, /* OBJ_des_cfb64 1 3 14 3 2 9 */ -377, /* OBJ_rsaSignature 1 3 14 3 2 11 */ -67, /* OBJ_dsa_2 1 3 14 3 2 12 */ -66, /* OBJ_dsaWithSHA 1 3 14 3 2 13 */ -42, /* OBJ_shaWithRSAEncryption 1 3 14 3 2 15 */ -32, /* OBJ_des_ede_ecb 1 3 14 3 2 17 */ -41, /* OBJ_sha 1 3 14 3 2 18 */ -64, /* OBJ_sha1 1 3 14 3 2 26 */ -70, /* OBJ_dsaWithSHA1_2 1 3 14 3 2 27 */ -115, /* OBJ_sha1WithRSA 1 3 14 3 2 29 */ -117, /* OBJ_ripemd160 1 3 36 3 2 1 */ -143, /* OBJ_sxnet 1 3 101 1 4 1 */ -721, /* OBJ_sect163k1 1 3 132 0 1 */ -722, /* OBJ_sect163r1 1 3 132 0 2 */ -728, /* OBJ_sect239k1 1 3 132 0 3 */ -717, /* OBJ_sect113r1 1 3 132 0 4 */ -718, /* OBJ_sect113r2 1 3 132 0 5 */ -704, /* OBJ_secp112r1 1 3 132 0 6 */ -705, /* OBJ_secp112r2 1 3 132 0 7 */ -709, /* OBJ_secp160r1 1 3 132 0 8 */ -708, /* OBJ_secp160k1 1 3 132 0 9 */ -714, /* OBJ_secp256k1 1 3 132 0 10 */ -723, /* OBJ_sect163r2 1 3 132 0 15 */ -729, /* OBJ_sect283k1 1 3 132 0 16 */ -730, /* OBJ_sect283r1 1 3 132 0 17 */ -719, /* OBJ_sect131r1 1 3 132 0 22 */ -720, /* OBJ_sect131r2 1 3 132 0 23 */ -724, /* OBJ_sect193r1 1 3 132 0 24 */ -725, /* OBJ_sect193r2 1 3 132 0 25 */ -726, /* OBJ_sect233k1 1 3 132 0 26 */ -727, /* OBJ_sect233r1 1 3 132 0 27 */ -706, /* OBJ_secp128r1 1 3 132 0 28 */ -707, /* OBJ_secp128r2 1 3 132 0 29 */ -710, /* OBJ_secp160r2 1 3 132 0 30 */ -711, /* OBJ_secp192k1 1 3 132 0 31 */ -712, /* OBJ_secp224k1 1 3 132 0 32 */ -713, /* OBJ_secp224r1 1 3 132 0 33 */ -715, /* OBJ_secp384r1 1 3 132 0 34 */ -716, /* OBJ_secp521r1 1 3 132 0 35 */ -731, /* OBJ_sect409k1 1 3 132 0 36 */ -732, /* OBJ_sect409r1 1 3 132 0 37 */ -733, /* OBJ_sect571k1 1 3 132 0 38 */ -734, /* OBJ_sect571r1 1 3 132 0 39 */ -624, /* OBJ_set_rootKeyThumb 2 23 42 3 0 0 */ -625, /* OBJ_set_addPolicy 2 23 42 3 0 1 */ -626, /* OBJ_setAttr_Token_EMV 2 23 42 3 2 1 */ -627, /* OBJ_setAttr_Token_B0Prime 2 23 42 3 2 2 */ -628, /* OBJ_setAttr_IssCap_CVM 2 23 42 3 3 3 */ -629, /* OBJ_setAttr_IssCap_T2 2 23 42 3 3 4 */ -630, /* OBJ_setAttr_IssCap_Sig 2 23 42 3 3 5 */ -642, /* OBJ_set_brand_Novus 2 23 42 8 6011 */ -735, /* OBJ_wap_wsg_idm_ecid_wtls1 2 23 43 1 4 1 */ -736, /* OBJ_wap_wsg_idm_ecid_wtls3 2 23 43 1 4 3 */ -737, /* OBJ_wap_wsg_idm_ecid_wtls4 2 23 43 1 4 4 */ -738, /* OBJ_wap_wsg_idm_ecid_wtls5 2 23 43 1 4 5 */ -739, /* OBJ_wap_wsg_idm_ecid_wtls6 2 23 43 1 4 6 */ -740, /* OBJ_wap_wsg_idm_ecid_wtls7 2 23 43 1 4 7 */ -741, /* OBJ_wap_wsg_idm_ecid_wtls8 2 23 43 1 4 8 */ -742, /* OBJ_wap_wsg_idm_ecid_wtls9 2 23 43 1 4 9 */ -743, /* OBJ_wap_wsg_idm_ecid_wtls10 2 23 43 1 4 10 */ -744, /* OBJ_wap_wsg_idm_ecid_wtls11 2 23 43 1 4 11 */ -745, /* OBJ_wap_wsg_idm_ecid_wtls12 2 23 43 1 4 12 */ -804, /* OBJ_whirlpool 1 0 10118 3 0 55 */ -773, /* OBJ_kisa 1 2 410 200004 */ -807, /* OBJ_id_GostR3411_94_with_GostR3410_2001 1 2 643 2 2 3 */ -808, /* OBJ_id_GostR3411_94_with_GostR3410_94 1 2 643 2 2 4 */ -809, /* OBJ_id_GostR3411_94 1 2 643 2 2 9 */ -810, /* OBJ_id_HMACGostR3411_94 1 2 643 2 2 10 */ -811, /* OBJ_id_GostR3410_2001 1 2 643 2 2 19 */ -812, /* OBJ_id_GostR3410_94 1 2 643 2 2 20 */ -813, /* OBJ_id_Gost28147_89 1 2 643 2 2 21 */ -815, /* OBJ_id_Gost28147_89_MAC 1 2 643 2 2 22 */ -816, /* OBJ_id_GostR3411_94_prf 1 2 643 2 2 23 */ -817, /* OBJ_id_GostR3410_2001DH 1 2 643 2 2 98 */ -818, /* OBJ_id_GostR3410_94DH 1 2 643 2 2 99 */ - 1, /* OBJ_rsadsi 1 2 840 113549 */ -185, /* OBJ_X9cm 1 2 840 10040 4 */ -127, /* OBJ_id_pkix 1 3 6 1 5 5 7 */ -505, /* OBJ_mime_mhs_headings 1 3 6 1 7 1 1 */ -506, /* OBJ_mime_mhs_bodies 1 3 6 1 7 1 2 */ -119, /* OBJ_ripemd160WithRSA 1 3 36 3 3 1 2 */ -937, /* OBJ_dhSinglePass_stdDH_sha224kdf_scheme 1 3 132 1 11 0 */ -938, /* OBJ_dhSinglePass_stdDH_sha256kdf_scheme 1 3 132 1 11 1 */ -939, /* OBJ_dhSinglePass_stdDH_sha384kdf_scheme 1 3 132 1 11 2 */ -940, /* OBJ_dhSinglePass_stdDH_sha512kdf_scheme 1 3 132 1 11 3 */ -942, /* OBJ_dhSinglePass_cofactorDH_sha224kdf_scheme 1 3 132 1 14 0 */ -943, /* OBJ_dhSinglePass_cofactorDH_sha256kdf_scheme 1 3 132 1 14 1 */ -944, /* OBJ_dhSinglePass_cofactorDH_sha384kdf_scheme 1 3 132 1 14 2 */ -945, /* OBJ_dhSinglePass_cofactorDH_sha512kdf_scheme 1 3 132 1 14 3 */ -631, /* OBJ_setAttr_GenCryptgrm 2 23 42 3 3 3 1 */ -632, /* OBJ_setAttr_T2Enc 2 23 42 3 3 4 1 */ -633, /* OBJ_setAttr_T2cleartxt 2 23 42 3 3 4 2 */ -634, /* OBJ_setAttr_TokICCsig 2 23 42 3 3 5 1 */ -635, /* OBJ_setAttr_SecDevSig 2 23 42 3 3 5 2 */ -436, /* OBJ_ucl 0 9 2342 19200300 */ -820, /* OBJ_id_Gost28147_89_None_KeyMeshing 1 2 643 2 2 14 0 */ -819, /* OBJ_id_Gost28147_89_CryptoPro_KeyMeshing 1 2 643 2 2 14 1 */ -845, /* OBJ_id_GostR3410_94_a 1 2 643 2 2 20 1 */ -846, /* OBJ_id_GostR3410_94_aBis 1 2 643 2 2 20 2 */ -847, /* OBJ_id_GostR3410_94_b 1 2 643 2 2 20 3 */ -848, /* OBJ_id_GostR3410_94_bBis 1 2 643 2 2 20 4 */ -821, /* OBJ_id_GostR3411_94_TestParamSet 1 2 643 2 2 30 0 */ -822, /* OBJ_id_GostR3411_94_CryptoProParamSet 1 2 643 2 2 30 1 */ -823, /* OBJ_id_Gost28147_89_TestParamSet 1 2 643 2 2 31 0 */ -824, /* OBJ_id_Gost28147_89_CryptoPro_A_ParamSet 1 2 643 2 2 31 1 */ -825, /* OBJ_id_Gost28147_89_CryptoPro_B_ParamSet 1 2 643 2 2 31 2 */ -826, /* OBJ_id_Gost28147_89_CryptoPro_C_ParamSet 1 2 643 2 2 31 3 */ -827, /* OBJ_id_Gost28147_89_CryptoPro_D_ParamSet 1 2 643 2 2 31 4 */ -828, /* OBJ_id_Gost28147_89_CryptoPro_Oscar_1_1_ParamSet 1 2 643 2 2 31 5 */ -829, /* OBJ_id_Gost28147_89_CryptoPro_Oscar_1_0_ParamSet 1 2 643 2 2 31 6 */ -830, /* OBJ_id_Gost28147_89_CryptoPro_RIC_1_ParamSet 1 2 643 2 2 31 7 */ -831, /* OBJ_id_GostR3410_94_TestParamSet 1 2 643 2 2 32 0 */ -832, /* OBJ_id_GostR3410_94_CryptoPro_A_ParamSet 1 2 643 2 2 32 2 */ -833, /* OBJ_id_GostR3410_94_CryptoPro_B_ParamSet 1 2 643 2 2 32 3 */ -834, /* OBJ_id_GostR3410_94_CryptoPro_C_ParamSet 1 2 643 2 2 32 4 */ -835, /* OBJ_id_GostR3410_94_CryptoPro_D_ParamSet 1 2 643 2 2 32 5 */ -836, /* OBJ_id_GostR3410_94_CryptoPro_XchA_ParamSet 1 2 643 2 2 33 1 */ -837, /* OBJ_id_GostR3410_94_CryptoPro_XchB_ParamSet 1 2 643 2 2 33 2 */ -838, /* OBJ_id_GostR3410_94_CryptoPro_XchC_ParamSet 1 2 643 2 2 33 3 */ -839, /* OBJ_id_GostR3410_2001_TestParamSet 1 2 643 2 2 35 0 */ -840, /* OBJ_id_GostR3410_2001_CryptoPro_A_ParamSet 1 2 643 2 2 35 1 */ -841, /* OBJ_id_GostR3410_2001_CryptoPro_B_ParamSet 1 2 643 2 2 35 2 */ -842, /* OBJ_id_GostR3410_2001_CryptoPro_C_ParamSet 1 2 643 2 2 35 3 */ -843, /* OBJ_id_GostR3410_2001_CryptoPro_XchA_ParamSet 1 2 643 2 2 36 0 */ -844, /* OBJ_id_GostR3410_2001_CryptoPro_XchB_ParamSet 1 2 643 2 2 36 1 */ - 2, /* OBJ_pkcs 1 2 840 113549 1 */ -431, /* OBJ_hold_instruction_none 1 2 840 10040 2 1 */ -432, /* OBJ_hold_instruction_call_issuer 1 2 840 10040 2 2 */ -433, /* OBJ_hold_instruction_reject 1 2 840 10040 2 3 */ -116, /* OBJ_dsa 1 2 840 10040 4 1 */ -113, /* OBJ_dsaWithSHA1 1 2 840 10040 4 3 */ -406, /* OBJ_X9_62_prime_field 1 2 840 10045 1 1 */ -407, /* OBJ_X9_62_characteristic_two_field 1 2 840 10045 1 2 */ -408, /* OBJ_X9_62_id_ecPublicKey 1 2 840 10045 2 1 */ -416, /* OBJ_ecdsa_with_SHA1 1 2 840 10045 4 1 */ -791, /* OBJ_ecdsa_with_Recommended 1 2 840 10045 4 2 */ -792, /* OBJ_ecdsa_with_Specified 1 2 840 10045 4 3 */ -920, /* OBJ_dhpublicnumber 1 2 840 10046 2 1 */ -258, /* OBJ_id_pkix_mod 1 3 6 1 5 5 7 0 */ -175, /* OBJ_id_pe 1 3 6 1 5 5 7 1 */ -259, /* OBJ_id_qt 1 3 6 1 5 5 7 2 */ -128, /* OBJ_id_kp 1 3 6 1 5 5 7 3 */ -260, /* OBJ_id_it 1 3 6 1 5 5 7 4 */ -261, /* OBJ_id_pkip 1 3 6 1 5 5 7 5 */ -262, /* OBJ_id_alg 1 3 6 1 5 5 7 6 */ -263, /* OBJ_id_cmc 1 3 6 1 5 5 7 7 */ -264, /* OBJ_id_on 1 3 6 1 5 5 7 8 */ -265, /* OBJ_id_pda 1 3 6 1 5 5 7 9 */ -266, /* OBJ_id_aca 1 3 6 1 5 5 7 10 */ -267, /* OBJ_id_qcs 1 3 6 1 5 5 7 11 */ -268, /* OBJ_id_cct 1 3 6 1 5 5 7 12 */ -662, /* OBJ_id_ppl 1 3 6 1 5 5 7 21 */ -176, /* OBJ_id_ad 1 3 6 1 5 5 7 48 */ -507, /* OBJ_id_hex_partial_message 1 3 6 1 7 1 1 1 */ -508, /* OBJ_id_hex_multipart_message 1 3 6 1 7 1 1 2 */ -57, /* OBJ_netscape 2 16 840 1 113730 */ -754, /* OBJ_camellia_128_ecb 0 3 4401 5 3 1 9 1 */ -766, /* OBJ_camellia_128_ofb128 0 3 4401 5 3 1 9 3 */ -757, /* OBJ_camellia_128_cfb128 0 3 4401 5 3 1 9 4 */ -755, /* OBJ_camellia_192_ecb 0 3 4401 5 3 1 9 21 */ -767, /* OBJ_camellia_192_ofb128 0 3 4401 5 3 1 9 23 */ -758, /* OBJ_camellia_192_cfb128 0 3 4401 5 3 1 9 24 */ -756, /* OBJ_camellia_256_ecb 0 3 4401 5 3 1 9 41 */ -768, /* OBJ_camellia_256_ofb128 0 3 4401 5 3 1 9 43 */ -759, /* OBJ_camellia_256_cfb128 0 3 4401 5 3 1 9 44 */ -437, /* OBJ_pilot 0 9 2342 19200300 100 */ -776, /* OBJ_seed_ecb 1 2 410 200004 1 3 */ -777, /* OBJ_seed_cbc 1 2 410 200004 1 4 */ -779, /* OBJ_seed_cfb128 1 2 410 200004 1 5 */ -778, /* OBJ_seed_ofb128 1 2 410 200004 1 6 */ -852, /* OBJ_id_GostR3411_94_with_GostR3410_94_cc 1 2 643 2 9 1 3 3 */ -853, /* OBJ_id_GostR3411_94_with_GostR3410_2001_cc 1 2 643 2 9 1 3 4 */ -850, /* OBJ_id_GostR3410_94_cc 1 2 643 2 9 1 5 3 */ -851, /* OBJ_id_GostR3410_2001_cc 1 2 643 2 9 1 5 4 */ -849, /* OBJ_id_Gost28147_89_cc 1 2 643 2 9 1 6 1 */ -854, /* OBJ_id_GostR3410_2001_ParamSet_cc 1 2 643 2 9 1 8 1 */ -186, /* OBJ_pkcs1 1 2 840 113549 1 1 */ -27, /* OBJ_pkcs3 1 2 840 113549 1 3 */ -187, /* OBJ_pkcs5 1 2 840 113549 1 5 */ -20, /* OBJ_pkcs7 1 2 840 113549 1 7 */ -47, /* OBJ_pkcs9 1 2 840 113549 1 9 */ - 3, /* OBJ_md2 1 2 840 113549 2 2 */ -257, /* OBJ_md4 1 2 840 113549 2 4 */ - 4, /* OBJ_md5 1 2 840 113549 2 5 */ -797, /* OBJ_hmacWithMD5 1 2 840 113549 2 6 */ -163, /* OBJ_hmacWithSHA1 1 2 840 113549 2 7 */ -798, /* OBJ_hmacWithSHA224 1 2 840 113549 2 8 */ -799, /* OBJ_hmacWithSHA256 1 2 840 113549 2 9 */ -800, /* OBJ_hmacWithSHA384 1 2 840 113549 2 10 */ -801, /* OBJ_hmacWithSHA512 1 2 840 113549 2 11 */ -37, /* OBJ_rc2_cbc 1 2 840 113549 3 2 */ - 5, /* OBJ_rc4 1 2 840 113549 3 4 */ -44, /* OBJ_des_ede3_cbc 1 2 840 113549 3 7 */ -120, /* OBJ_rc5_cbc 1 2 840 113549 3 8 */ -643, /* OBJ_des_cdmf 1 2 840 113549 3 10 */ -680, /* OBJ_X9_62_id_characteristic_two_basis 1 2 840 10045 1 2 3 */ -684, /* OBJ_X9_62_c2pnb163v1 1 2 840 10045 3 0 1 */ -685, /* OBJ_X9_62_c2pnb163v2 1 2 840 10045 3 0 2 */ -686, /* OBJ_X9_62_c2pnb163v3 1 2 840 10045 3 0 3 */ -687, /* OBJ_X9_62_c2pnb176v1 1 2 840 10045 3 0 4 */ -688, /* OBJ_X9_62_c2tnb191v1 1 2 840 10045 3 0 5 */ -689, /* OBJ_X9_62_c2tnb191v2 1 2 840 10045 3 0 6 */ -690, /* OBJ_X9_62_c2tnb191v3 1 2 840 10045 3 0 7 */ -691, /* OBJ_X9_62_c2onb191v4 1 2 840 10045 3 0 8 */ -692, /* OBJ_X9_62_c2onb191v5 1 2 840 10045 3 0 9 */ -693, /* OBJ_X9_62_c2pnb208w1 1 2 840 10045 3 0 10 */ -694, /* OBJ_X9_62_c2tnb239v1 1 2 840 10045 3 0 11 */ -695, /* OBJ_X9_62_c2tnb239v2 1 2 840 10045 3 0 12 */ -696, /* OBJ_X9_62_c2tnb239v3 1 2 840 10045 3 0 13 */ -697, /* OBJ_X9_62_c2onb239v4 1 2 840 10045 3 0 14 */ -698, /* OBJ_X9_62_c2onb239v5 1 2 840 10045 3 0 15 */ -699, /* OBJ_X9_62_c2pnb272w1 1 2 840 10045 3 0 16 */ -700, /* OBJ_X9_62_c2pnb304w1 1 2 840 10045 3 0 17 */ -701, /* OBJ_X9_62_c2tnb359v1 1 2 840 10045 3 0 18 */ -702, /* OBJ_X9_62_c2pnb368w1 1 2 840 10045 3 0 19 */ -703, /* OBJ_X9_62_c2tnb431r1 1 2 840 10045 3 0 20 */ -409, /* OBJ_X9_62_prime192v1 1 2 840 10045 3 1 1 */ -410, /* OBJ_X9_62_prime192v2 1 2 840 10045 3 1 2 */ -411, /* OBJ_X9_62_prime192v3 1 2 840 10045 3 1 3 */ -412, /* OBJ_X9_62_prime239v1 1 2 840 10045 3 1 4 */ -413, /* OBJ_X9_62_prime239v2 1 2 840 10045 3 1 5 */ -414, /* OBJ_X9_62_prime239v3 1 2 840 10045 3 1 6 */ -415, /* OBJ_X9_62_prime256v1 1 2 840 10045 3 1 7 */ -793, /* OBJ_ecdsa_with_SHA224 1 2 840 10045 4 3 1 */ -794, /* OBJ_ecdsa_with_SHA256 1 2 840 10045 4 3 2 */ -795, /* OBJ_ecdsa_with_SHA384 1 2 840 10045 4 3 3 */ -796, /* OBJ_ecdsa_with_SHA512 1 2 840 10045 4 3 4 */ -269, /* OBJ_id_pkix1_explicit_88 1 3 6 1 5 5 7 0 1 */ -270, /* OBJ_id_pkix1_implicit_88 1 3 6 1 5 5 7 0 2 */ -271, /* OBJ_id_pkix1_explicit_93 1 3 6 1 5 5 7 0 3 */ -272, /* OBJ_id_pkix1_implicit_93 1 3 6 1 5 5 7 0 4 */ -273, /* OBJ_id_mod_crmf 1 3 6 1 5 5 7 0 5 */ -274, /* OBJ_id_mod_cmc 1 3 6 1 5 5 7 0 6 */ -275, /* OBJ_id_mod_kea_profile_88 1 3 6 1 5 5 7 0 7 */ -276, /* OBJ_id_mod_kea_profile_93 1 3 6 1 5 5 7 0 8 */ -277, /* OBJ_id_mod_cmp 1 3 6 1 5 5 7 0 9 */ -278, /* OBJ_id_mod_qualified_cert_88 1 3 6 1 5 5 7 0 10 */ -279, /* OBJ_id_mod_qualified_cert_93 1 3 6 1 5 5 7 0 11 */ -280, /* OBJ_id_mod_attribute_cert 1 3 6 1 5 5 7 0 12 */ -281, /* OBJ_id_mod_timestamp_protocol 1 3 6 1 5 5 7 0 13 */ -282, /* OBJ_id_mod_ocsp 1 3 6 1 5 5 7 0 14 */ -283, /* OBJ_id_mod_dvcs 1 3 6 1 5 5 7 0 15 */ -284, /* OBJ_id_mod_cmp2000 1 3 6 1 5 5 7 0 16 */ -177, /* OBJ_info_access 1 3 6 1 5 5 7 1 1 */ -285, /* OBJ_biometricInfo 1 3 6 1 5 5 7 1 2 */ -286, /* OBJ_qcStatements 1 3 6 1 5 5 7 1 3 */ -287, /* OBJ_ac_auditEntity 1 3 6 1 5 5 7 1 4 */ -288, /* OBJ_ac_targeting 1 3 6 1 5 5 7 1 5 */ -289, /* OBJ_aaControls 1 3 6 1 5 5 7 1 6 */ -290, /* OBJ_sbgp_ipAddrBlock 1 3 6 1 5 5 7 1 7 */ -291, /* OBJ_sbgp_autonomousSysNum 1 3 6 1 5 5 7 1 8 */ -292, /* OBJ_sbgp_routerIdentifier 1 3 6 1 5 5 7 1 9 */ -397, /* OBJ_ac_proxying 1 3 6 1 5 5 7 1 10 */ -398, /* OBJ_sinfo_access 1 3 6 1 5 5 7 1 11 */ -663, /* OBJ_proxyCertInfo 1 3 6 1 5 5 7 1 14 */ -164, /* OBJ_id_qt_cps 1 3 6 1 5 5 7 2 1 */ -165, /* OBJ_id_qt_unotice 1 3 6 1 5 5 7 2 2 */ -293, /* OBJ_textNotice 1 3 6 1 5 5 7 2 3 */ -129, /* OBJ_server_auth 1 3 6 1 5 5 7 3 1 */ -130, /* OBJ_client_auth 1 3 6 1 5 5 7 3 2 */ -131, /* OBJ_code_sign 1 3 6 1 5 5 7 3 3 */ -132, /* OBJ_email_protect 1 3 6 1 5 5 7 3 4 */ -294, /* OBJ_ipsecEndSystem 1 3 6 1 5 5 7 3 5 */ -295, /* OBJ_ipsecTunnel 1 3 6 1 5 5 7 3 6 */ -296, /* OBJ_ipsecUser 1 3 6 1 5 5 7 3 7 */ -133, /* OBJ_time_stamp 1 3 6 1 5 5 7 3 8 */ -180, /* OBJ_OCSP_sign 1 3 6 1 5 5 7 3 9 */ -297, /* OBJ_dvcs 1 3 6 1 5 5 7 3 10 */ -298, /* OBJ_id_it_caProtEncCert 1 3 6 1 5 5 7 4 1 */ -299, /* OBJ_id_it_signKeyPairTypes 1 3 6 1 5 5 7 4 2 */ -300, /* OBJ_id_it_encKeyPairTypes 1 3 6 1 5 5 7 4 3 */ -301, /* OBJ_id_it_preferredSymmAlg 1 3 6 1 5 5 7 4 4 */ -302, /* OBJ_id_it_caKeyUpdateInfo 1 3 6 1 5 5 7 4 5 */ -303, /* OBJ_id_it_currentCRL 1 3 6 1 5 5 7 4 6 */ -304, /* OBJ_id_it_unsupportedOIDs 1 3 6 1 5 5 7 4 7 */ -305, /* OBJ_id_it_subscriptionRequest 1 3 6 1 5 5 7 4 8 */ -306, /* OBJ_id_it_subscriptionResponse 1 3 6 1 5 5 7 4 9 */ -307, /* OBJ_id_it_keyPairParamReq 1 3 6 1 5 5 7 4 10 */ -308, /* OBJ_id_it_keyPairParamRep 1 3 6 1 5 5 7 4 11 */ -309, /* OBJ_id_it_revPassphrase 1 3 6 1 5 5 7 4 12 */ -310, /* OBJ_id_it_implicitConfirm 1 3 6 1 5 5 7 4 13 */ -311, /* OBJ_id_it_confirmWaitTime 1 3 6 1 5 5 7 4 14 */ -312, /* OBJ_id_it_origPKIMessage 1 3 6 1 5 5 7 4 15 */ -784, /* OBJ_id_it_suppLangTags 1 3 6 1 5 5 7 4 16 */ -313, /* OBJ_id_regCtrl 1 3 6 1 5 5 7 5 1 */ -314, /* OBJ_id_regInfo 1 3 6 1 5 5 7 5 2 */ -323, /* OBJ_id_alg_des40 1 3 6 1 5 5 7 6 1 */ -324, /* OBJ_id_alg_noSignature 1 3 6 1 5 5 7 6 2 */ -325, /* OBJ_id_alg_dh_sig_hmac_sha1 1 3 6 1 5 5 7 6 3 */ -326, /* OBJ_id_alg_dh_pop 1 3 6 1 5 5 7 6 4 */ -327, /* OBJ_id_cmc_statusInfo 1 3 6 1 5 5 7 7 1 */ -328, /* OBJ_id_cmc_identification 1 3 6 1 5 5 7 7 2 */ -329, /* OBJ_id_cmc_identityProof 1 3 6 1 5 5 7 7 3 */ -330, /* OBJ_id_cmc_dataReturn 1 3 6 1 5 5 7 7 4 */ -331, /* OBJ_id_cmc_transactionId 1 3 6 1 5 5 7 7 5 */ -332, /* OBJ_id_cmc_senderNonce 1 3 6 1 5 5 7 7 6 */ -333, /* OBJ_id_cmc_recipientNonce 1 3 6 1 5 5 7 7 7 */ -334, /* OBJ_id_cmc_addExtensions 1 3 6 1 5 5 7 7 8 */ -335, /* OBJ_id_cmc_encryptedPOP 1 3 6 1 5 5 7 7 9 */ -336, /* OBJ_id_cmc_decryptedPOP 1 3 6 1 5 5 7 7 10 */ -337, /* OBJ_id_cmc_lraPOPWitness 1 3 6 1 5 5 7 7 11 */ -338, /* OBJ_id_cmc_getCert 1 3 6 1 5 5 7 7 15 */ -339, /* OBJ_id_cmc_getCRL 1 3 6 1 5 5 7 7 16 */ -340, /* OBJ_id_cmc_revokeRequest 1 3 6 1 5 5 7 7 17 */ -341, /* OBJ_id_cmc_regInfo 1 3 6 1 5 5 7 7 18 */ -342, /* OBJ_id_cmc_responseInfo 1 3 6 1 5 5 7 7 19 */ -343, /* OBJ_id_cmc_queryPending 1 3 6 1 5 5 7 7 21 */ -344, /* OBJ_id_cmc_popLinkRandom 1 3 6 1 5 5 7 7 22 */ -345, /* OBJ_id_cmc_popLinkWitness 1 3 6 1 5 5 7 7 23 */ -346, /* OBJ_id_cmc_confirmCertAcceptance 1 3 6 1 5 5 7 7 24 */ -347, /* OBJ_id_on_personalData 1 3 6 1 5 5 7 8 1 */ -858, /* OBJ_id_on_permanentIdentifier 1 3 6 1 5 5 7 8 3 */ -348, /* OBJ_id_pda_dateOfBirth 1 3 6 1 5 5 7 9 1 */ -349, /* OBJ_id_pda_placeOfBirth 1 3 6 1 5 5 7 9 2 */ -351, /* OBJ_id_pda_gender 1 3 6 1 5 5 7 9 3 */ -352, /* OBJ_id_pda_countryOfCitizenship 1 3 6 1 5 5 7 9 4 */ -353, /* OBJ_id_pda_countryOfResidence 1 3 6 1 5 5 7 9 5 */ -354, /* OBJ_id_aca_authenticationInfo 1 3 6 1 5 5 7 10 1 */ -355, /* OBJ_id_aca_accessIdentity 1 3 6 1 5 5 7 10 2 */ -356, /* OBJ_id_aca_chargingIdentity 1 3 6 1 5 5 7 10 3 */ -357, /* OBJ_id_aca_group 1 3 6 1 5 5 7 10 4 */ -358, /* OBJ_id_aca_role 1 3 6 1 5 5 7 10 5 */ -399, /* OBJ_id_aca_encAttrs 1 3 6 1 5 5 7 10 6 */ -359, /* OBJ_id_qcs_pkixQCSyntax_v1 1 3 6 1 5 5 7 11 1 */ -360, /* OBJ_id_cct_crs 1 3 6 1 5 5 7 12 1 */ -361, /* OBJ_id_cct_PKIData 1 3 6 1 5 5 7 12 2 */ -362, /* OBJ_id_cct_PKIResponse 1 3 6 1 5 5 7 12 3 */ -664, /* OBJ_id_ppl_anyLanguage 1 3 6 1 5 5 7 21 0 */ -665, /* OBJ_id_ppl_inheritAll 1 3 6 1 5 5 7 21 1 */ -667, /* OBJ_Independent 1 3 6 1 5 5 7 21 2 */ -178, /* OBJ_ad_OCSP 1 3 6 1 5 5 7 48 1 */ -179, /* OBJ_ad_ca_issuers 1 3 6 1 5 5 7 48 2 */ -363, /* OBJ_ad_timeStamping 1 3 6 1 5 5 7 48 3 */ -364, /* OBJ_ad_dvcs 1 3 6 1 5 5 7 48 4 */ -785, /* OBJ_caRepository 1 3 6 1 5 5 7 48 5 */ -780, /* OBJ_hmac_md5 1 3 6 1 5 5 8 1 1 */ -781, /* OBJ_hmac_sha1 1 3 6 1 5 5 8 1 2 */ -58, /* OBJ_netscape_cert_extension 2 16 840 1 113730 1 */ -59, /* OBJ_netscape_data_type 2 16 840 1 113730 2 */ -438, /* OBJ_pilotAttributeType 0 9 2342 19200300 100 1 */ -439, /* OBJ_pilotAttributeSyntax 0 9 2342 19200300 100 3 */ -440, /* OBJ_pilotObjectClass 0 9 2342 19200300 100 4 */ -441, /* OBJ_pilotGroups 0 9 2342 19200300 100 10 */ -108, /* OBJ_cast5_cbc 1 2 840 113533 7 66 10 */ -112, /* OBJ_pbeWithMD5AndCast5_CBC 1 2 840 113533 7 66 12 */ -782, /* OBJ_id_PasswordBasedMAC 1 2 840 113533 7 66 13 */ -783, /* OBJ_id_DHBasedMac 1 2 840 113533 7 66 30 */ - 6, /* OBJ_rsaEncryption 1 2 840 113549 1 1 1 */ - 7, /* OBJ_md2WithRSAEncryption 1 2 840 113549 1 1 2 */ -396, /* OBJ_md4WithRSAEncryption 1 2 840 113549 1 1 3 */ - 8, /* OBJ_md5WithRSAEncryption 1 2 840 113549 1 1 4 */ -65, /* OBJ_sha1WithRSAEncryption 1 2 840 113549 1 1 5 */ -644, /* OBJ_rsaOAEPEncryptionSET 1 2 840 113549 1 1 6 */ -919, /* OBJ_rsaesOaep 1 2 840 113549 1 1 7 */ -911, /* OBJ_mgf1 1 2 840 113549 1 1 8 */ -935, /* OBJ_pSpecified 1 2 840 113549 1 1 9 */ -912, /* OBJ_rsassaPss 1 2 840 113549 1 1 10 */ -668, /* OBJ_sha256WithRSAEncryption 1 2 840 113549 1 1 11 */ -669, /* OBJ_sha384WithRSAEncryption 1 2 840 113549 1 1 12 */ -670, /* OBJ_sha512WithRSAEncryption 1 2 840 113549 1 1 13 */ -671, /* OBJ_sha224WithRSAEncryption 1 2 840 113549 1 1 14 */ -28, /* OBJ_dhKeyAgreement 1 2 840 113549 1 3 1 */ - 9, /* OBJ_pbeWithMD2AndDES_CBC 1 2 840 113549 1 5 1 */ -10, /* OBJ_pbeWithMD5AndDES_CBC 1 2 840 113549 1 5 3 */ -168, /* OBJ_pbeWithMD2AndRC2_CBC 1 2 840 113549 1 5 4 */ -169, /* OBJ_pbeWithMD5AndRC2_CBC 1 2 840 113549 1 5 6 */ -170, /* OBJ_pbeWithSHA1AndDES_CBC 1 2 840 113549 1 5 10 */ -68, /* OBJ_pbeWithSHA1AndRC2_CBC 1 2 840 113549 1 5 11 */ -69, /* OBJ_id_pbkdf2 1 2 840 113549 1 5 12 */ -161, /* OBJ_pbes2 1 2 840 113549 1 5 13 */ -162, /* OBJ_pbmac1 1 2 840 113549 1 5 14 */ -21, /* OBJ_pkcs7_data 1 2 840 113549 1 7 1 */ -22, /* OBJ_pkcs7_signed 1 2 840 113549 1 7 2 */ -23, /* OBJ_pkcs7_enveloped 1 2 840 113549 1 7 3 */ -24, /* OBJ_pkcs7_signedAndEnveloped 1 2 840 113549 1 7 4 */ -25, /* OBJ_pkcs7_digest 1 2 840 113549 1 7 5 */ -26, /* OBJ_pkcs7_encrypted 1 2 840 113549 1 7 6 */ -48, /* OBJ_pkcs9_emailAddress 1 2 840 113549 1 9 1 */ -49, /* OBJ_pkcs9_unstructuredName 1 2 840 113549 1 9 2 */ -50, /* OBJ_pkcs9_contentType 1 2 840 113549 1 9 3 */ -51, /* OBJ_pkcs9_messageDigest 1 2 840 113549 1 9 4 */ -52, /* OBJ_pkcs9_signingTime 1 2 840 113549 1 9 5 */ -53, /* OBJ_pkcs9_countersignature 1 2 840 113549 1 9 6 */ -54, /* OBJ_pkcs9_challengePassword 1 2 840 113549 1 9 7 */ -55, /* OBJ_pkcs9_unstructuredAddress 1 2 840 113549 1 9 8 */ -56, /* OBJ_pkcs9_extCertAttributes 1 2 840 113549 1 9 9 */ -172, /* OBJ_ext_req 1 2 840 113549 1 9 14 */ -167, /* OBJ_SMIMECapabilities 1 2 840 113549 1 9 15 */ -188, /* OBJ_SMIME 1 2 840 113549 1 9 16 */ -156, /* OBJ_friendlyName 1 2 840 113549 1 9 20 */ -157, /* OBJ_localKeyID 1 2 840 113549 1 9 21 */ -681, /* OBJ_X9_62_onBasis 1 2 840 10045 1 2 3 1 */ -682, /* OBJ_X9_62_tpBasis 1 2 840 10045 1 2 3 2 */ -683, /* OBJ_X9_62_ppBasis 1 2 840 10045 1 2 3 3 */ -417, /* OBJ_ms_csp_name 1 3 6 1 4 1 311 17 1 */ -856, /* OBJ_LocalKeySet 1 3 6 1 4 1 311 17 2 */ -390, /* OBJ_dcObject 1 3 6 1 4 1 1466 344 */ -91, /* OBJ_bf_cbc 1 3 6 1 4 1 3029 1 2 */ -315, /* OBJ_id_regCtrl_regToken 1 3 6 1 5 5 7 5 1 1 */ -316, /* OBJ_id_regCtrl_authenticator 1 3 6 1 5 5 7 5 1 2 */ -317, /* OBJ_id_regCtrl_pkiPublicationInfo 1 3 6 1 5 5 7 5 1 3 */ -318, /* OBJ_id_regCtrl_pkiArchiveOptions 1 3 6 1 5 5 7 5 1 4 */ -319, /* OBJ_id_regCtrl_oldCertID 1 3 6 1 5 5 7 5 1 5 */ -320, /* OBJ_id_regCtrl_protocolEncrKey 1 3 6 1 5 5 7 5 1 6 */ -321, /* OBJ_id_regInfo_utf8Pairs 1 3 6 1 5 5 7 5 2 1 */ -322, /* OBJ_id_regInfo_certReq 1 3 6 1 5 5 7 5 2 2 */ -365, /* OBJ_id_pkix_OCSP_basic 1 3 6 1 5 5 7 48 1 1 */ -366, /* OBJ_id_pkix_OCSP_Nonce 1 3 6 1 5 5 7 48 1 2 */ -367, /* OBJ_id_pkix_OCSP_CrlID 1 3 6 1 5 5 7 48 1 3 */ -368, /* OBJ_id_pkix_OCSP_acceptableResponses 1 3 6 1 5 5 7 48 1 4 */ -369, /* OBJ_id_pkix_OCSP_noCheck 1 3 6 1 5 5 7 48 1 5 */ -370, /* OBJ_id_pkix_OCSP_archiveCutoff 1 3 6 1 5 5 7 48 1 6 */ -371, /* OBJ_id_pkix_OCSP_serviceLocator 1 3 6 1 5 5 7 48 1 7 */ -372, /* OBJ_id_pkix_OCSP_extendedStatus 1 3 6 1 5 5 7 48 1 8 */ -373, /* OBJ_id_pkix_OCSP_valid 1 3 6 1 5 5 7 48 1 9 */ -374, /* OBJ_id_pkix_OCSP_path 1 3 6 1 5 5 7 48 1 10 */ -375, /* OBJ_id_pkix_OCSP_trustRoot 1 3 6 1 5 5 7 48 1 11 */ -921, /* OBJ_brainpoolP160r1 1 3 36 3 3 2 8 1 1 1 */ -922, /* OBJ_brainpoolP160t1 1 3 36 3 3 2 8 1 1 2 */ -923, /* OBJ_brainpoolP192r1 1 3 36 3 3 2 8 1 1 3 */ -924, /* OBJ_brainpoolP192t1 1 3 36 3 3 2 8 1 1 4 */ -925, /* OBJ_brainpoolP224r1 1 3 36 3 3 2 8 1 1 5 */ -926, /* OBJ_brainpoolP224t1 1 3 36 3 3 2 8 1 1 6 */ -927, /* OBJ_brainpoolP256r1 1 3 36 3 3 2 8 1 1 7 */ -928, /* OBJ_brainpoolP256t1 1 3 36 3 3 2 8 1 1 8 */ -929, /* OBJ_brainpoolP320r1 1 3 36 3 3 2 8 1 1 9 */ -930, /* OBJ_brainpoolP320t1 1 3 36 3 3 2 8 1 1 10 */ -931, /* OBJ_brainpoolP384r1 1 3 36 3 3 2 8 1 1 11 */ -932, /* OBJ_brainpoolP384t1 1 3 36 3 3 2 8 1 1 12 */ -933, /* OBJ_brainpoolP512r1 1 3 36 3 3 2 8 1 1 13 */ -934, /* OBJ_brainpoolP512t1 1 3 36 3 3 2 8 1 1 14 */ -936, /* OBJ_dhSinglePass_stdDH_sha1kdf_scheme 1 3 133 16 840 63 0 2 */ -941, /* OBJ_dhSinglePass_cofactorDH_sha1kdf_scheme 1 3 133 16 840 63 0 3 */ -418, /* OBJ_aes_128_ecb 2 16 840 1 101 3 4 1 1 */ -419, /* OBJ_aes_128_cbc 2 16 840 1 101 3 4 1 2 */ -420, /* OBJ_aes_128_ofb128 2 16 840 1 101 3 4 1 3 */ -421, /* OBJ_aes_128_cfb128 2 16 840 1 101 3 4 1 4 */ -788, /* OBJ_id_aes128_wrap 2 16 840 1 101 3 4 1 5 */ -895, /* OBJ_aes_128_gcm 2 16 840 1 101 3 4 1 6 */ -896, /* OBJ_aes_128_ccm 2 16 840 1 101 3 4 1 7 */ -897, /* OBJ_id_aes128_wrap_pad 2 16 840 1 101 3 4 1 8 */ -422, /* OBJ_aes_192_ecb 2 16 840 1 101 3 4 1 21 */ -423, /* OBJ_aes_192_cbc 2 16 840 1 101 3 4 1 22 */ -424, /* OBJ_aes_192_ofb128 2 16 840 1 101 3 4 1 23 */ -425, /* OBJ_aes_192_cfb128 2 16 840 1 101 3 4 1 24 */ -789, /* OBJ_id_aes192_wrap 2 16 840 1 101 3 4 1 25 */ -898, /* OBJ_aes_192_gcm 2 16 840 1 101 3 4 1 26 */ -899, /* OBJ_aes_192_ccm 2 16 840 1 101 3 4 1 27 */ -900, /* OBJ_id_aes192_wrap_pad 2 16 840 1 101 3 4 1 28 */ -426, /* OBJ_aes_256_ecb 2 16 840 1 101 3 4 1 41 */ -427, /* OBJ_aes_256_cbc 2 16 840 1 101 3 4 1 42 */ -428, /* OBJ_aes_256_ofb128 2 16 840 1 101 3 4 1 43 */ -429, /* OBJ_aes_256_cfb128 2 16 840 1 101 3 4 1 44 */ -790, /* OBJ_id_aes256_wrap 2 16 840 1 101 3 4 1 45 */ -901, /* OBJ_aes_256_gcm 2 16 840 1 101 3 4 1 46 */ -902, /* OBJ_aes_256_ccm 2 16 840 1 101 3 4 1 47 */ -903, /* OBJ_id_aes256_wrap_pad 2 16 840 1 101 3 4 1 48 */ -672, /* OBJ_sha256 2 16 840 1 101 3 4 2 1 */ -673, /* OBJ_sha384 2 16 840 1 101 3 4 2 2 */ -674, /* OBJ_sha512 2 16 840 1 101 3 4 2 3 */ -675, /* OBJ_sha224 2 16 840 1 101 3 4 2 4 */ -802, /* OBJ_dsa_with_SHA224 2 16 840 1 101 3 4 3 1 */ -803, /* OBJ_dsa_with_SHA256 2 16 840 1 101 3 4 3 2 */ -71, /* OBJ_netscape_cert_type 2 16 840 1 113730 1 1 */ -72, /* OBJ_netscape_base_url 2 16 840 1 113730 1 2 */ -73, /* OBJ_netscape_revocation_url 2 16 840 1 113730 1 3 */ -74, /* OBJ_netscape_ca_revocation_url 2 16 840 1 113730 1 4 */ -75, /* OBJ_netscape_renewal_url 2 16 840 1 113730 1 7 */ -76, /* OBJ_netscape_ca_policy_url 2 16 840 1 113730 1 8 */ -77, /* OBJ_netscape_ssl_server_name 2 16 840 1 113730 1 12 */ -78, /* OBJ_netscape_comment 2 16 840 1 113730 1 13 */ -79, /* OBJ_netscape_cert_sequence 2 16 840 1 113730 2 5 */ -139, /* OBJ_ns_sgc 2 16 840 1 113730 4 1 */ -458, /* OBJ_userId 0 9 2342 19200300 100 1 1 */ -459, /* OBJ_textEncodedORAddress 0 9 2342 19200300 100 1 2 */ -460, /* OBJ_rfc822Mailbox 0 9 2342 19200300 100 1 3 */ -461, /* OBJ_info 0 9 2342 19200300 100 1 4 */ -462, /* OBJ_favouriteDrink 0 9 2342 19200300 100 1 5 */ -463, /* OBJ_roomNumber 0 9 2342 19200300 100 1 6 */ -464, /* OBJ_photo 0 9 2342 19200300 100 1 7 */ -465, /* OBJ_userClass 0 9 2342 19200300 100 1 8 */ -466, /* OBJ_host 0 9 2342 19200300 100 1 9 */ -467, /* OBJ_manager 0 9 2342 19200300 100 1 10 */ -468, /* OBJ_documentIdentifier 0 9 2342 19200300 100 1 11 */ -469, /* OBJ_documentTitle 0 9 2342 19200300 100 1 12 */ -470, /* OBJ_documentVersion 0 9 2342 19200300 100 1 13 */ -471, /* OBJ_documentAuthor 0 9 2342 19200300 100 1 14 */ -472, /* OBJ_documentLocation 0 9 2342 19200300 100 1 15 */ -473, /* OBJ_homeTelephoneNumber 0 9 2342 19200300 100 1 20 */ -474, /* OBJ_secretary 0 9 2342 19200300 100 1 21 */ -475, /* OBJ_otherMailbox 0 9 2342 19200300 100 1 22 */ -476, /* OBJ_lastModifiedTime 0 9 2342 19200300 100 1 23 */ -477, /* OBJ_lastModifiedBy 0 9 2342 19200300 100 1 24 */ -391, /* OBJ_domainComponent 0 9 2342 19200300 100 1 25 */ -478, /* OBJ_aRecord 0 9 2342 19200300 100 1 26 */ -479, /* OBJ_pilotAttributeType27 0 9 2342 19200300 100 1 27 */ -480, /* OBJ_mXRecord 0 9 2342 19200300 100 1 28 */ -481, /* OBJ_nSRecord 0 9 2342 19200300 100 1 29 */ -482, /* OBJ_sOARecord 0 9 2342 19200300 100 1 30 */ -483, /* OBJ_cNAMERecord 0 9 2342 19200300 100 1 31 */ -484, /* OBJ_associatedDomain 0 9 2342 19200300 100 1 37 */ -485, /* OBJ_associatedName 0 9 2342 19200300 100 1 38 */ -486, /* OBJ_homePostalAddress 0 9 2342 19200300 100 1 39 */ -487, /* OBJ_personalTitle 0 9 2342 19200300 100 1 40 */ -488, /* OBJ_mobileTelephoneNumber 0 9 2342 19200300 100 1 41 */ -489, /* OBJ_pagerTelephoneNumber 0 9 2342 19200300 100 1 42 */ -490, /* OBJ_friendlyCountryName 0 9 2342 19200300 100 1 43 */ -491, /* OBJ_organizationalStatus 0 9 2342 19200300 100 1 45 */ -492, /* OBJ_janetMailbox 0 9 2342 19200300 100 1 46 */ -493, /* OBJ_mailPreferenceOption 0 9 2342 19200300 100 1 47 */ -494, /* OBJ_buildingName 0 9 2342 19200300 100 1 48 */ -495, /* OBJ_dSAQuality 0 9 2342 19200300 100 1 49 */ -496, /* OBJ_singleLevelQuality 0 9 2342 19200300 100 1 50 */ -497, /* OBJ_subtreeMinimumQuality 0 9 2342 19200300 100 1 51 */ -498, /* OBJ_subtreeMaximumQuality 0 9 2342 19200300 100 1 52 */ -499, /* OBJ_personalSignature 0 9 2342 19200300 100 1 53 */ -500, /* OBJ_dITRedirect 0 9 2342 19200300 100 1 54 */ -501, /* OBJ_audio 0 9 2342 19200300 100 1 55 */ -502, /* OBJ_documentPublisher 0 9 2342 19200300 100 1 56 */ -442, /* OBJ_iA5StringSyntax 0 9 2342 19200300 100 3 4 */ -443, /* OBJ_caseIgnoreIA5StringSyntax 0 9 2342 19200300 100 3 5 */ -444, /* OBJ_pilotObject 0 9 2342 19200300 100 4 3 */ -445, /* OBJ_pilotPerson 0 9 2342 19200300 100 4 4 */ -446, /* OBJ_account 0 9 2342 19200300 100 4 5 */ -447, /* OBJ_document 0 9 2342 19200300 100 4 6 */ -448, /* OBJ_room 0 9 2342 19200300 100 4 7 */ -449, /* OBJ_documentSeries 0 9 2342 19200300 100 4 9 */ -392, /* OBJ_Domain 0 9 2342 19200300 100 4 13 */ -450, /* OBJ_rFC822localPart 0 9 2342 19200300 100 4 14 */ -451, /* OBJ_dNSDomain 0 9 2342 19200300 100 4 15 */ -452, /* OBJ_domainRelatedObject 0 9 2342 19200300 100 4 17 */ -453, /* OBJ_friendlyCountry 0 9 2342 19200300 100 4 18 */ -454, /* OBJ_simpleSecurityObject 0 9 2342 19200300 100 4 19 */ -455, /* OBJ_pilotOrganization 0 9 2342 19200300 100 4 20 */ -456, /* OBJ_pilotDSA 0 9 2342 19200300 100 4 21 */ -457, /* OBJ_qualityLabelledData 0 9 2342 19200300 100 4 22 */ -189, /* OBJ_id_smime_mod 1 2 840 113549 1 9 16 0 */ -190, /* OBJ_id_smime_ct 1 2 840 113549 1 9 16 1 */ -191, /* OBJ_id_smime_aa 1 2 840 113549 1 9 16 2 */ -192, /* OBJ_id_smime_alg 1 2 840 113549 1 9 16 3 */ -193, /* OBJ_id_smime_cd 1 2 840 113549 1 9 16 4 */ -194, /* OBJ_id_smime_spq 1 2 840 113549 1 9 16 5 */ -195, /* OBJ_id_smime_cti 1 2 840 113549 1 9 16 6 */ -158, /* OBJ_x509Certificate 1 2 840 113549 1 9 22 1 */ -159, /* OBJ_sdsiCertificate 1 2 840 113549 1 9 22 2 */ -160, /* OBJ_x509Crl 1 2 840 113549 1 9 23 1 */ -144, /* OBJ_pbe_WithSHA1And128BitRC4 1 2 840 113549 1 12 1 1 */ -145, /* OBJ_pbe_WithSHA1And40BitRC4 1 2 840 113549 1 12 1 2 */ -146, /* OBJ_pbe_WithSHA1And3_Key_TripleDES_CBC 1 2 840 113549 1 12 1 3 */ -147, /* OBJ_pbe_WithSHA1And2_Key_TripleDES_CBC 1 2 840 113549 1 12 1 4 */ -148, /* OBJ_pbe_WithSHA1And128BitRC2_CBC 1 2 840 113549 1 12 1 5 */ -149, /* OBJ_pbe_WithSHA1And40BitRC2_CBC 1 2 840 113549 1 12 1 6 */ -171, /* OBJ_ms_ext_req 1 3 6 1 4 1 311 2 1 14 */ -134, /* OBJ_ms_code_ind 1 3 6 1 4 1 311 2 1 21 */ -135, /* OBJ_ms_code_com 1 3 6 1 4 1 311 2 1 22 */ -136, /* OBJ_ms_ctl_sign 1 3 6 1 4 1 311 10 3 1 */ -137, /* OBJ_ms_sgc 1 3 6 1 4 1 311 10 3 3 */ -138, /* OBJ_ms_efs 1 3 6 1 4 1 311 10 3 4 */ -648, /* OBJ_ms_smartcard_login 1 3 6 1 4 1 311 20 2 2 */ -649, /* OBJ_ms_upn 1 3 6 1 4 1 311 20 2 3 */ -751, /* OBJ_camellia_128_cbc 1 2 392 200011 61 1 1 1 2 */ -752, /* OBJ_camellia_192_cbc 1 2 392 200011 61 1 1 1 3 */ -753, /* OBJ_camellia_256_cbc 1 2 392 200011 61 1 1 1 4 */ -907, /* OBJ_id_camellia128_wrap 1 2 392 200011 61 1 1 3 2 */ -908, /* OBJ_id_camellia192_wrap 1 2 392 200011 61 1 1 3 3 */ -909, /* OBJ_id_camellia256_wrap 1 2 392 200011 61 1 1 3 4 */ -196, /* OBJ_id_smime_mod_cms 1 2 840 113549 1 9 16 0 1 */ -197, /* OBJ_id_smime_mod_ess 1 2 840 113549 1 9 16 0 2 */ -198, /* OBJ_id_smime_mod_oid 1 2 840 113549 1 9 16 0 3 */ -199, /* OBJ_id_smime_mod_msg_v3 1 2 840 113549 1 9 16 0 4 */ -200, /* OBJ_id_smime_mod_ets_eSignature_88 1 2 840 113549 1 9 16 0 5 */ -201, /* OBJ_id_smime_mod_ets_eSignature_97 1 2 840 113549 1 9 16 0 6 */ -202, /* OBJ_id_smime_mod_ets_eSigPolicy_88 1 2 840 113549 1 9 16 0 7 */ -203, /* OBJ_id_smime_mod_ets_eSigPolicy_97 1 2 840 113549 1 9 16 0 8 */ -204, /* OBJ_id_smime_ct_receipt 1 2 840 113549 1 9 16 1 1 */ -205, /* OBJ_id_smime_ct_authData 1 2 840 113549 1 9 16 1 2 */ -206, /* OBJ_id_smime_ct_publishCert 1 2 840 113549 1 9 16 1 3 */ -207, /* OBJ_id_smime_ct_TSTInfo 1 2 840 113549 1 9 16 1 4 */ -208, /* OBJ_id_smime_ct_TDTInfo 1 2 840 113549 1 9 16 1 5 */ -209, /* OBJ_id_smime_ct_contentInfo 1 2 840 113549 1 9 16 1 6 */ -210, /* OBJ_id_smime_ct_DVCSRequestData 1 2 840 113549 1 9 16 1 7 */ -211, /* OBJ_id_smime_ct_DVCSResponseData 1 2 840 113549 1 9 16 1 8 */ -786, /* OBJ_id_smime_ct_compressedData 1 2 840 113549 1 9 16 1 9 */ -787, /* OBJ_id_ct_asciiTextWithCRLF 1 2 840 113549 1 9 16 1 27 */ -212, /* OBJ_id_smime_aa_receiptRequest 1 2 840 113549 1 9 16 2 1 */ -213, /* OBJ_id_smime_aa_securityLabel 1 2 840 113549 1 9 16 2 2 */ -214, /* OBJ_id_smime_aa_mlExpandHistory 1 2 840 113549 1 9 16 2 3 */ -215, /* OBJ_id_smime_aa_contentHint 1 2 840 113549 1 9 16 2 4 */ -216, /* OBJ_id_smime_aa_msgSigDigest 1 2 840 113549 1 9 16 2 5 */ -217, /* OBJ_id_smime_aa_encapContentType 1 2 840 113549 1 9 16 2 6 */ -218, /* OBJ_id_smime_aa_contentIdentifier 1 2 840 113549 1 9 16 2 7 */ -219, /* OBJ_id_smime_aa_macValue 1 2 840 113549 1 9 16 2 8 */ -220, /* OBJ_id_smime_aa_equivalentLabels 1 2 840 113549 1 9 16 2 9 */ -221, /* OBJ_id_smime_aa_contentReference 1 2 840 113549 1 9 16 2 10 */ -222, /* OBJ_id_smime_aa_encrypKeyPref 1 2 840 113549 1 9 16 2 11 */ -223, /* OBJ_id_smime_aa_signingCertificate 1 2 840 113549 1 9 16 2 12 */ -224, /* OBJ_id_smime_aa_smimeEncryptCerts 1 2 840 113549 1 9 16 2 13 */ -225, /* OBJ_id_smime_aa_timeStampToken 1 2 840 113549 1 9 16 2 14 */ -226, /* OBJ_id_smime_aa_ets_sigPolicyId 1 2 840 113549 1 9 16 2 15 */ -227, /* OBJ_id_smime_aa_ets_commitmentType 1 2 840 113549 1 9 16 2 16 */ -228, /* OBJ_id_smime_aa_ets_signerLocation 1 2 840 113549 1 9 16 2 17 */ -229, /* OBJ_id_smime_aa_ets_signerAttr 1 2 840 113549 1 9 16 2 18 */ -230, /* OBJ_id_smime_aa_ets_otherSigCert 1 2 840 113549 1 9 16 2 19 */ -231, /* OBJ_id_smime_aa_ets_contentTimestamp 1 2 840 113549 1 9 16 2 20 */ -232, /* OBJ_id_smime_aa_ets_CertificateRefs 1 2 840 113549 1 9 16 2 21 */ -233, /* OBJ_id_smime_aa_ets_RevocationRefs 1 2 840 113549 1 9 16 2 22 */ -234, /* OBJ_id_smime_aa_ets_certValues 1 2 840 113549 1 9 16 2 23 */ -235, /* OBJ_id_smime_aa_ets_revocationValues 1 2 840 113549 1 9 16 2 24 */ -236, /* OBJ_id_smime_aa_ets_escTimeStamp 1 2 840 113549 1 9 16 2 25 */ -237, /* OBJ_id_smime_aa_ets_certCRLTimestamp 1 2 840 113549 1 9 16 2 26 */ -238, /* OBJ_id_smime_aa_ets_archiveTimeStamp 1 2 840 113549 1 9 16 2 27 */ -239, /* OBJ_id_smime_aa_signatureType 1 2 840 113549 1 9 16 2 28 */ -240, /* OBJ_id_smime_aa_dvcs_dvc 1 2 840 113549 1 9 16 2 29 */ -241, /* OBJ_id_smime_alg_ESDHwith3DES 1 2 840 113549 1 9 16 3 1 */ -242, /* OBJ_id_smime_alg_ESDHwithRC2 1 2 840 113549 1 9 16 3 2 */ -243, /* OBJ_id_smime_alg_3DESwrap 1 2 840 113549 1 9 16 3 3 */ -244, /* OBJ_id_smime_alg_RC2wrap 1 2 840 113549 1 9 16 3 4 */ -245, /* OBJ_id_smime_alg_ESDH 1 2 840 113549 1 9 16 3 5 */ -246, /* OBJ_id_smime_alg_CMS3DESwrap 1 2 840 113549 1 9 16 3 6 */ -247, /* OBJ_id_smime_alg_CMSRC2wrap 1 2 840 113549 1 9 16 3 7 */ -125, /* OBJ_zlib_compression 1 2 840 113549 1 9 16 3 8 */ -893, /* OBJ_id_alg_PWRI_KEK 1 2 840 113549 1 9 16 3 9 */ -248, /* OBJ_id_smime_cd_ldap 1 2 840 113549 1 9 16 4 1 */ -249, /* OBJ_id_smime_spq_ets_sqt_uri 1 2 840 113549 1 9 16 5 1 */ -250, /* OBJ_id_smime_spq_ets_sqt_unotice 1 2 840 113549 1 9 16 5 2 */ -251, /* OBJ_id_smime_cti_ets_proofOfOrigin 1 2 840 113549 1 9 16 6 1 */ -252, /* OBJ_id_smime_cti_ets_proofOfReceipt 1 2 840 113549 1 9 16 6 2 */ -253, /* OBJ_id_smime_cti_ets_proofOfDelivery 1 2 840 113549 1 9 16 6 3 */ -254, /* OBJ_id_smime_cti_ets_proofOfSender 1 2 840 113549 1 9 16 6 4 */ -255, /* OBJ_id_smime_cti_ets_proofOfApproval 1 2 840 113549 1 9 16 6 5 */ -256, /* OBJ_id_smime_cti_ets_proofOfCreation 1 2 840 113549 1 9 16 6 6 */ -150, /* OBJ_keyBag 1 2 840 113549 1 12 10 1 1 */ -151, /* OBJ_pkcs8ShroudedKeyBag 1 2 840 113549 1 12 10 1 2 */ -152, /* OBJ_certBag 1 2 840 113549 1 12 10 1 3 */ -153, /* OBJ_crlBag 1 2 840 113549 1 12 10 1 4 */ -154, /* OBJ_secretBag 1 2 840 113549 1 12 10 1 5 */ -155, /* OBJ_safeContentsBag 1 2 840 113549 1 12 10 1 6 */ -34, /* OBJ_idea_cbc 1 3 6 1 4 1 188 7 1 1 2 */ +static const unsigned kNIDsInOIDOrder[] = { + 434 /* 0.9 (OBJ_data) */, 182 /* 1.2 (OBJ_member_body) */, + 379 /* 1.3 (OBJ_org) */, 676 /* 1.3 (OBJ_identified_organization) */, + 11 /* 2.5 (OBJ_X500) */, 647 /* 2.23 (OBJ_international_organizations) */, + 380 /* 1.3.6 (OBJ_dod) */, 12 /* 2.5.4 (OBJ_X509) */, + 378 /* 2.5.8 (OBJ_X500algorithms) */, 81 /* 2.5.29 (OBJ_id_ce) */, + 512 /* 2.23.42 (OBJ_id_set) */, 678 /* 2.23.43 (OBJ_wap) */, + 435 /* 0.9.2342 (OBJ_pss) */, 183 /* 1.2.840 (OBJ_ISO_US) */, + 381 /* 1.3.6.1 (OBJ_iana) */, 677 /* 1.3.132 (OBJ_certicom_arc) */, + 394 /* 2.5.1.5 (OBJ_selected_attribute_types) */, + 13 /* 2.5.4.3 (OBJ_commonName) */, 100 /* 2.5.4.4 (OBJ_surname) */, + 105 /* 2.5.4.5 (OBJ_serialNumber) */, 14 /* 2.5.4.6 (OBJ_countryName) */, + 15 /* 2.5.4.7 (OBJ_localityName) */, + 16 /* 2.5.4.8 (OBJ_stateOrProvinceName) */, + 660 /* 2.5.4.9 (OBJ_streetAddress) */, + 17 /* 2.5.4.10 (OBJ_organizationName) */, + 18 /* 2.5.4.11 (OBJ_organizationalUnitName) */, + 106 /* 2.5.4.12 (OBJ_title) */, 107 /* 2.5.4.13 (OBJ_description) */, + 859 /* 2.5.4.14 (OBJ_searchGuide) */, + 860 /* 2.5.4.15 (OBJ_businessCategory) */, + 861 /* 2.5.4.16 (OBJ_postalAddress) */, 661 /* 2.5.4.17 (OBJ_postalCode) */, + 862 /* 2.5.4.18 (OBJ_postOfficeBox) */, + 863 /* 2.5.4.19 (OBJ_physicalDeliveryOfficeName) */, + 864 /* 2.5.4.20 (OBJ_telephoneNumber) */, + 865 /* 2.5.4.21 (OBJ_telexNumber) */, + 866 /* 2.5.4.22 (OBJ_teletexTerminalIdentifier) */, + 867 /* 2.5.4.23 (OBJ_facsimileTelephoneNumber) */, + 868 /* 2.5.4.24 (OBJ_x121Address) */, + 869 /* 2.5.4.25 (OBJ_internationaliSDNNumber) */, + 870 /* 2.5.4.26 (OBJ_registeredAddress) */, + 871 /* 2.5.4.27 (OBJ_destinationIndicator) */, + 872 /* 2.5.4.28 (OBJ_preferredDeliveryMethod) */, + 873 /* 2.5.4.29 (OBJ_presentationAddress) */, + 874 /* 2.5.4.30 (OBJ_supportedApplicationContext) */, + 875 /* 2.5.4.31 (OBJ_member) */, 876 /* 2.5.4.32 (OBJ_owner) */, + 877 /* 2.5.4.33 (OBJ_roleOccupant) */, 878 /* 2.5.4.34 (OBJ_seeAlso) */, + 879 /* 2.5.4.35 (OBJ_userPassword) */, + 880 /* 2.5.4.36 (OBJ_userCertificate) */, + 881 /* 2.5.4.37 (OBJ_cACertificate) */, + 882 /* 2.5.4.38 (OBJ_authorityRevocationList) */, + 883 /* 2.5.4.39 (OBJ_certificateRevocationList) */, + 884 /* 2.5.4.40 (OBJ_crossCertificatePair) */, + 173 /* 2.5.4.41 (OBJ_name) */, 99 /* 2.5.4.42 (OBJ_givenName) */, + 101 /* 2.5.4.43 (OBJ_initials) */, + 509 /* 2.5.4.44 (OBJ_generationQualifier) */, + 503 /* 2.5.4.45 (OBJ_x500UniqueIdentifier) */, + 174 /* 2.5.4.46 (OBJ_dnQualifier) */, + 885 /* 2.5.4.47 (OBJ_enhancedSearchGuide) */, + 886 /* 2.5.4.48 (OBJ_protocolInformation) */, + 887 /* 2.5.4.49 (OBJ_distinguishedName) */, + 888 /* 2.5.4.50 (OBJ_uniqueMember) */, + 889 /* 2.5.4.51 (OBJ_houseIdentifier) */, + 890 /* 2.5.4.52 (OBJ_supportedAlgorithms) */, + 891 /* 2.5.4.53 (OBJ_deltaRevocationList) */, + 892 /* 2.5.4.54 (OBJ_dmdName) */, 510 /* 2.5.4.65 (OBJ_pseudonym) */, + 400 /* 2.5.4.72 (OBJ_role) */, + 769 /* 2.5.29.9 (OBJ_subject_directory_attributes) */, + 82 /* 2.5.29.14 (OBJ_subject_key_identifier) */, + 83 /* 2.5.29.15 (OBJ_key_usage) */, + 84 /* 2.5.29.16 (OBJ_private_key_usage_period) */, + 85 /* 2.5.29.17 (OBJ_subject_alt_name) */, + 86 /* 2.5.29.18 (OBJ_issuer_alt_name) */, + 87 /* 2.5.29.19 (OBJ_basic_constraints) */, + 88 /* 2.5.29.20 (OBJ_crl_number) */, 141 /* 2.5.29.21 (OBJ_crl_reason) */, + 430 /* 2.5.29.23 (OBJ_hold_instruction_code) */, + 142 /* 2.5.29.24 (OBJ_invalidity_date) */, + 140 /* 2.5.29.27 (OBJ_delta_crl) */, + 770 /* 2.5.29.28 (OBJ_issuing_distribution_point) */, + 771 /* 2.5.29.29 (OBJ_certificate_issuer) */, + 666 /* 2.5.29.30 (OBJ_name_constraints) */, + 103 /* 2.5.29.31 (OBJ_crl_distribution_points) */, + 89 /* 2.5.29.32 (OBJ_certificate_policies) */, + 747 /* 2.5.29.33 (OBJ_policy_mappings) */, + 90 /* 2.5.29.35 (OBJ_authority_key_identifier) */, + 401 /* 2.5.29.36 (OBJ_policy_constraints) */, + 126 /* 2.5.29.37 (OBJ_ext_key_usage) */, + 857 /* 2.5.29.46 (OBJ_freshest_crl) */, + 748 /* 2.5.29.54 (OBJ_inhibit_any_policy) */, + 402 /* 2.5.29.55 (OBJ_target_information) */, + 403 /* 2.5.29.56 (OBJ_no_rev_avail) */, 513 /* 2.23.42.0 (OBJ_set_ctype) */, + 514 /* 2.23.42.1 (OBJ_set_msgExt) */, 515 /* 2.23.42.3 (OBJ_set_attr) */, + 516 /* 2.23.42.5 (OBJ_set_policy) */, 517 /* 2.23.42.7 (OBJ_set_certExt) */, + 518 /* 2.23.42.8 (OBJ_set_brand) */, 679 /* 2.23.43.1 (OBJ_wap_wsg) */, + 382 /* 1.3.6.1.1 (OBJ_Directory) */, 383 /* 1.3.6.1.2 (OBJ_Management) */, + 384 /* 1.3.6.1.3 (OBJ_Experimental) */, 385 /* 1.3.6.1.4 (OBJ_Private) */, + 386 /* 1.3.6.1.5 (OBJ_Security) */, 387 /* 1.3.6.1.6 (OBJ_SNMPv2) */, + 388 /* 1.3.6.1.7 (OBJ_Mail) */, 376 /* 1.3.14.3.2 (OBJ_algorithm) */, + 395 /* 2.5.1.5.55 (OBJ_clearance) */, 19 /* 2.5.8.1.1 (OBJ_rsa) */, + 96 /* 2.5.8.3.100 (OBJ_mdc2WithRSA) */, 95 /* 2.5.8.3.101 (OBJ_mdc2) */, + 746 /* 2.5.29.32.0 (OBJ_any_policy) */, + 910 /* 2.5.29.37.0 (OBJ_anyExtendedKeyUsage) */, + 519 /* 2.23.42.0.0 (OBJ_setct_PANData) */, + 520 /* 2.23.42.0.1 (OBJ_setct_PANToken) */, + 521 /* 2.23.42.0.2 (OBJ_setct_PANOnly) */, + 522 /* 2.23.42.0.3 (OBJ_setct_OIData) */, + 523 /* 2.23.42.0.4 (OBJ_setct_PI) */, + 524 /* 2.23.42.0.5 (OBJ_setct_PIData) */, + 525 /* 2.23.42.0.6 (OBJ_setct_PIDataUnsigned) */, + 526 /* 2.23.42.0.7 (OBJ_setct_HODInput) */, + 527 /* 2.23.42.0.8 (OBJ_setct_AuthResBaggage) */, + 528 /* 2.23.42.0.9 (OBJ_setct_AuthRevReqBaggage) */, + 529 /* 2.23.42.0.10 (OBJ_setct_AuthRevResBaggage) */, + 530 /* 2.23.42.0.11 (OBJ_setct_CapTokenSeq) */, + 531 /* 2.23.42.0.12 (OBJ_setct_PInitResData) */, + 532 /* 2.23.42.0.13 (OBJ_setct_PI_TBS) */, + 533 /* 2.23.42.0.14 (OBJ_setct_PResData) */, + 534 /* 2.23.42.0.16 (OBJ_setct_AuthReqTBS) */, + 535 /* 2.23.42.0.17 (OBJ_setct_AuthResTBS) */, + 536 /* 2.23.42.0.18 (OBJ_setct_AuthResTBSX) */, + 537 /* 2.23.42.0.19 (OBJ_setct_AuthTokenTBS) */, + 538 /* 2.23.42.0.20 (OBJ_setct_CapTokenData) */, + 539 /* 2.23.42.0.21 (OBJ_setct_CapTokenTBS) */, + 540 /* 2.23.42.0.22 (OBJ_setct_AcqCardCodeMsg) */, + 541 /* 2.23.42.0.23 (OBJ_setct_AuthRevReqTBS) */, + 542 /* 2.23.42.0.24 (OBJ_setct_AuthRevResData) */, + 543 /* 2.23.42.0.25 (OBJ_setct_AuthRevResTBS) */, + 544 /* 2.23.42.0.26 (OBJ_setct_CapReqTBS) */, + 545 /* 2.23.42.0.27 (OBJ_setct_CapReqTBSX) */, + 546 /* 2.23.42.0.28 (OBJ_setct_CapResData) */, + 547 /* 2.23.42.0.29 (OBJ_setct_CapRevReqTBS) */, + 548 /* 2.23.42.0.30 (OBJ_setct_CapRevReqTBSX) */, + 549 /* 2.23.42.0.31 (OBJ_setct_CapRevResData) */, + 550 /* 2.23.42.0.32 (OBJ_setct_CredReqTBS) */, + 551 /* 2.23.42.0.33 (OBJ_setct_CredReqTBSX) */, + 552 /* 2.23.42.0.34 (OBJ_setct_CredResData) */, + 553 /* 2.23.42.0.35 (OBJ_setct_CredRevReqTBS) */, + 554 /* 2.23.42.0.36 (OBJ_setct_CredRevReqTBSX) */, + 555 /* 2.23.42.0.37 (OBJ_setct_CredRevResData) */, + 556 /* 2.23.42.0.38 (OBJ_setct_PCertReqData) */, + 557 /* 2.23.42.0.39 (OBJ_setct_PCertResTBS) */, + 558 /* 2.23.42.0.40 (OBJ_setct_BatchAdminReqData) */, + 559 /* 2.23.42.0.41 (OBJ_setct_BatchAdminResData) */, + 560 /* 2.23.42.0.42 (OBJ_setct_CardCInitResTBS) */, + 561 /* 2.23.42.0.43 (OBJ_setct_MeAqCInitResTBS) */, + 562 /* 2.23.42.0.44 (OBJ_setct_RegFormResTBS) */, + 563 /* 2.23.42.0.45 (OBJ_setct_CertReqData) */, + 564 /* 2.23.42.0.46 (OBJ_setct_CertReqTBS) */, + 565 /* 2.23.42.0.47 (OBJ_setct_CertResData) */, + 566 /* 2.23.42.0.48 (OBJ_setct_CertInqReqTBS) */, + 567 /* 2.23.42.0.49 (OBJ_setct_ErrorTBS) */, + 568 /* 2.23.42.0.50 (OBJ_setct_PIDualSignedTBE) */, + 569 /* 2.23.42.0.51 (OBJ_setct_PIUnsignedTBE) */, + 570 /* 2.23.42.0.52 (OBJ_setct_AuthReqTBE) */, + 571 /* 2.23.42.0.53 (OBJ_setct_AuthResTBE) */, + 572 /* 2.23.42.0.54 (OBJ_setct_AuthResTBEX) */, + 573 /* 2.23.42.0.55 (OBJ_setct_AuthTokenTBE) */, + 574 /* 2.23.42.0.56 (OBJ_setct_CapTokenTBE) */, + 575 /* 2.23.42.0.57 (OBJ_setct_CapTokenTBEX) */, + 576 /* 2.23.42.0.58 (OBJ_setct_AcqCardCodeMsgTBE) */, + 577 /* 2.23.42.0.59 (OBJ_setct_AuthRevReqTBE) */, + 578 /* 2.23.42.0.60 (OBJ_setct_AuthRevResTBE) */, + 579 /* 2.23.42.0.61 (OBJ_setct_AuthRevResTBEB) */, + 580 /* 2.23.42.0.62 (OBJ_setct_CapReqTBE) */, + 581 /* 2.23.42.0.63 (OBJ_setct_CapReqTBEX) */, + 582 /* 2.23.42.0.64 (OBJ_setct_CapResTBE) */, + 583 /* 2.23.42.0.65 (OBJ_setct_CapRevReqTBE) */, + 584 /* 2.23.42.0.66 (OBJ_setct_CapRevReqTBEX) */, + 585 /* 2.23.42.0.67 (OBJ_setct_CapRevResTBE) */, + 586 /* 2.23.42.0.68 (OBJ_setct_CredReqTBE) */, + 587 /* 2.23.42.0.69 (OBJ_setct_CredReqTBEX) */, + 588 /* 2.23.42.0.70 (OBJ_setct_CredResTBE) */, + 589 /* 2.23.42.0.71 (OBJ_setct_CredRevReqTBE) */, + 590 /* 2.23.42.0.72 (OBJ_setct_CredRevReqTBEX) */, + 591 /* 2.23.42.0.73 (OBJ_setct_CredRevResTBE) */, + 592 /* 2.23.42.0.74 (OBJ_setct_BatchAdminReqTBE) */, + 593 /* 2.23.42.0.75 (OBJ_setct_BatchAdminResTBE) */, + 594 /* 2.23.42.0.76 (OBJ_setct_RegFormReqTBE) */, + 595 /* 2.23.42.0.77 (OBJ_setct_CertReqTBE) */, + 596 /* 2.23.42.0.78 (OBJ_setct_CertReqTBEX) */, + 597 /* 2.23.42.0.79 (OBJ_setct_CertResTBE) */, + 598 /* 2.23.42.0.80 (OBJ_setct_CRLNotificationTBS) */, + 599 /* 2.23.42.0.81 (OBJ_setct_CRLNotificationResTBS) */, + 600 /* 2.23.42.0.82 (OBJ_setct_BCIDistributionTBS) */, + 601 /* 2.23.42.1.1 (OBJ_setext_genCrypt) */, + 602 /* 2.23.42.1.3 (OBJ_setext_miAuth) */, + 603 /* 2.23.42.1.4 (OBJ_setext_pinSecure) */, + 604 /* 2.23.42.1.5 (OBJ_setext_pinAny) */, + 605 /* 2.23.42.1.7 (OBJ_setext_track2) */, + 606 /* 2.23.42.1.8 (OBJ_setext_cv) */, + 620 /* 2.23.42.3.0 (OBJ_setAttr_Cert) */, + 621 /* 2.23.42.3.1 (OBJ_setAttr_PGWYcap) */, + 622 /* 2.23.42.3.2 (OBJ_setAttr_TokenType) */, + 623 /* 2.23.42.3.3 (OBJ_setAttr_IssCap) */, + 607 /* 2.23.42.5.0 (OBJ_set_policy_root) */, + 608 /* 2.23.42.7.0 (OBJ_setCext_hashedRoot) */, + 609 /* 2.23.42.7.1 (OBJ_setCext_certType) */, + 610 /* 2.23.42.7.2 (OBJ_setCext_merchData) */, + 611 /* 2.23.42.7.3 (OBJ_setCext_cCertRequired) */, + 612 /* 2.23.42.7.4 (OBJ_setCext_tunneling) */, + 613 /* 2.23.42.7.5 (OBJ_setCext_setExt) */, + 614 /* 2.23.42.7.6 (OBJ_setCext_setQualf) */, + 615 /* 2.23.42.7.7 (OBJ_setCext_PGWYcapabilities) */, + 616 /* 2.23.42.7.8 (OBJ_setCext_TokenIdentifier) */, + 617 /* 2.23.42.7.9 (OBJ_setCext_Track2Data) */, + 618 /* 2.23.42.7.10 (OBJ_setCext_TokenType) */, + 619 /* 2.23.42.7.11 (OBJ_setCext_IssuerCapabilities) */, + 636 /* 2.23.42.8.1 (OBJ_set_brand_IATA_ATA) */, + 640 /* 2.23.42.8.4 (OBJ_set_brand_Visa) */, + 641 /* 2.23.42.8.5 (OBJ_set_brand_MasterCard) */, + 637 /* 2.23.42.8.30 (OBJ_set_brand_Diners) */, + 638 /* 2.23.42.8.34 (OBJ_set_brand_AmericanExpress) */, + 639 /* 2.23.42.8.35 (OBJ_set_brand_JCB) */, + 805 /* 1.2.643.2.2 (OBJ_cryptopro) */, + 806 /* 1.2.643.2.9 (OBJ_cryptocom) */, 184 /* 1.2.840.10040 (OBJ_X9_57) */, + 405 /* 1.2.840.10045 (OBJ_ansi_X9_62) */, + 389 /* 1.3.6.1.4.1 (OBJ_Enterprises) */, + 504 /* 1.3.6.1.7.1 (OBJ_mime_mhs) */, + 104 /* 1.3.14.3.2.3 (OBJ_md5WithRSA) */, + 29 /* 1.3.14.3.2.6 (OBJ_des_ecb) */, 31 /* 1.3.14.3.2.7 (OBJ_des_cbc) */, + 45 /* 1.3.14.3.2.8 (OBJ_des_ofb64) */, + 30 /* 1.3.14.3.2.9 (OBJ_des_cfb64) */, + 377 /* 1.3.14.3.2.11 (OBJ_rsaSignature) */, + 67 /* 1.3.14.3.2.12 (OBJ_dsa_2) */, 66 /* 1.3.14.3.2.13 (OBJ_dsaWithSHA) */, + 42 /* 1.3.14.3.2.15 (OBJ_shaWithRSAEncryption) */, + 32 /* 1.3.14.3.2.17 (OBJ_des_ede_ecb) */, 41 /* 1.3.14.3.2.18 (OBJ_sha) */, + 64 /* 1.3.14.3.2.26 (OBJ_sha1) */, + 70 /* 1.3.14.3.2.27 (OBJ_dsaWithSHA1_2) */, + 115 /* 1.3.14.3.2.29 (OBJ_sha1WithRSA) */, + 117 /* 1.3.36.3.2.1 (OBJ_ripemd160) */, 143 /* 1.3.101.1.4.1 (OBJ_sxnet) */, + 721 /* 1.3.132.0.1 (OBJ_sect163k1) */, + 722 /* 1.3.132.0.2 (OBJ_sect163r1) */, + 728 /* 1.3.132.0.3 (OBJ_sect239k1) */, + 717 /* 1.3.132.0.4 (OBJ_sect113r1) */, + 718 /* 1.3.132.0.5 (OBJ_sect113r2) */, + 704 /* 1.3.132.0.6 (OBJ_secp112r1) */, + 705 /* 1.3.132.0.7 (OBJ_secp112r2) */, + 709 /* 1.3.132.0.8 (OBJ_secp160r1) */, + 708 /* 1.3.132.0.9 (OBJ_secp160k1) */, + 714 /* 1.3.132.0.10 (OBJ_secp256k1) */, + 723 /* 1.3.132.0.15 (OBJ_sect163r2) */, + 729 /* 1.3.132.0.16 (OBJ_sect283k1) */, + 730 /* 1.3.132.0.17 (OBJ_sect283r1) */, + 719 /* 1.3.132.0.22 (OBJ_sect131r1) */, + 720 /* 1.3.132.0.23 (OBJ_sect131r2) */, + 724 /* 1.3.132.0.24 (OBJ_sect193r1) */, + 725 /* 1.3.132.0.25 (OBJ_sect193r2) */, + 726 /* 1.3.132.0.26 (OBJ_sect233k1) */, + 727 /* 1.3.132.0.27 (OBJ_sect233r1) */, + 706 /* 1.3.132.0.28 (OBJ_secp128r1) */, + 707 /* 1.3.132.0.29 (OBJ_secp128r2) */, + 710 /* 1.3.132.0.30 (OBJ_secp160r2) */, + 711 /* 1.3.132.0.31 (OBJ_secp192k1) */, + 712 /* 1.3.132.0.32 (OBJ_secp224k1) */, + 713 /* 1.3.132.0.33 (OBJ_secp224r1) */, + 715 /* 1.3.132.0.34 (OBJ_secp384r1) */, + 716 /* 1.3.132.0.35 (OBJ_secp521r1) */, + 731 /* 1.3.132.0.36 (OBJ_sect409k1) */, + 732 /* 1.3.132.0.37 (OBJ_sect409r1) */, + 733 /* 1.3.132.0.38 (OBJ_sect571k1) */, + 734 /* 1.3.132.0.39 (OBJ_sect571r1) */, + 624 /* 2.23.42.3.0.0 (OBJ_set_rootKeyThumb) */, + 625 /* 2.23.42.3.0.1 (OBJ_set_addPolicy) */, + 626 /* 2.23.42.3.2.1 (OBJ_setAttr_Token_EMV) */, + 627 /* 2.23.42.3.2.2 (OBJ_setAttr_Token_B0Prime) */, + 628 /* 2.23.42.3.3.3 (OBJ_setAttr_IssCap_CVM) */, + 629 /* 2.23.42.3.3.4 (OBJ_setAttr_IssCap_T2) */, + 630 /* 2.23.42.3.3.5 (OBJ_setAttr_IssCap_Sig) */, + 642 /* 2.23.42.8.6011 (OBJ_set_brand_Novus) */, + 735 /* 2.23.43.1.4.1 (OBJ_wap_wsg_idm_ecid_wtls1) */, + 736 /* 2.23.43.1.4.3 (OBJ_wap_wsg_idm_ecid_wtls3) */, + 737 /* 2.23.43.1.4.4 (OBJ_wap_wsg_idm_ecid_wtls4) */, + 738 /* 2.23.43.1.4.5 (OBJ_wap_wsg_idm_ecid_wtls5) */, + 739 /* 2.23.43.1.4.6 (OBJ_wap_wsg_idm_ecid_wtls6) */, + 740 /* 2.23.43.1.4.7 (OBJ_wap_wsg_idm_ecid_wtls7) */, + 741 /* 2.23.43.1.4.8 (OBJ_wap_wsg_idm_ecid_wtls8) */, + 742 /* 2.23.43.1.4.9 (OBJ_wap_wsg_idm_ecid_wtls9) */, + 743 /* 2.23.43.1.4.10 (OBJ_wap_wsg_idm_ecid_wtls10) */, + 744 /* 2.23.43.1.4.11 (OBJ_wap_wsg_idm_ecid_wtls11) */, + 745 /* 2.23.43.1.4.12 (OBJ_wap_wsg_idm_ecid_wtls12) */, + 804 /* 1.0.10118.3.0.55 (OBJ_whirlpool) */, + 773 /* 1.2.410.200004 (OBJ_kisa) */, + 807 /* 1.2.643.2.2.3 (OBJ_id_GostR3411_94_with_GostR3410_2001) */, + 808 /* 1.2.643.2.2.4 (OBJ_id_GostR3411_94_with_GostR3410_94) */, + 809 /* 1.2.643.2.2.9 (OBJ_id_GostR3411_94) */, + 810 /* 1.2.643.2.2.10 (OBJ_id_HMACGostR3411_94) */, + 811 /* 1.2.643.2.2.19 (OBJ_id_GostR3410_2001) */, + 812 /* 1.2.643.2.2.20 (OBJ_id_GostR3410_94) */, + 813 /* 1.2.643.2.2.21 (OBJ_id_Gost28147_89) */, + 815 /* 1.2.643.2.2.22 (OBJ_id_Gost28147_89_MAC) */, + 816 /* 1.2.643.2.2.23 (OBJ_id_GostR3411_94_prf) */, + 817 /* 1.2.643.2.2.98 (OBJ_id_GostR3410_2001DH) */, + 818 /* 1.2.643.2.2.99 (OBJ_id_GostR3410_94DH) */, + 1 /* 1.2.840.113549 (OBJ_rsadsi) */, 185 /* 1.2.840.10040.4 (OBJ_X9cm) */, + 127 /* 1.3.6.1.5.5.7 (OBJ_id_pkix) */, + 505 /* 1.3.6.1.7.1.1 (OBJ_mime_mhs_headings) */, + 506 /* 1.3.6.1.7.1.2 (OBJ_mime_mhs_bodies) */, + 119 /* 1.3.36.3.3.1.2 (OBJ_ripemd160WithRSA) */, + 937 /* 1.3.132.1.11.0 (OBJ_dhSinglePass_stdDH_sha224kdf_scheme) */, + 938 /* 1.3.132.1.11.1 (OBJ_dhSinglePass_stdDH_sha256kdf_scheme) */, + 939 /* 1.3.132.1.11.2 (OBJ_dhSinglePass_stdDH_sha384kdf_scheme) */, + 940 /* 1.3.132.1.11.3 (OBJ_dhSinglePass_stdDH_sha512kdf_scheme) */, + 942 /* 1.3.132.1.14.0 (OBJ_dhSinglePass_cofactorDH_sha224kdf_scheme) */, + 943 /* 1.3.132.1.14.1 (OBJ_dhSinglePass_cofactorDH_sha256kdf_scheme) */, + 944 /* 1.3.132.1.14.2 (OBJ_dhSinglePass_cofactorDH_sha384kdf_scheme) */, + 945 /* 1.3.132.1.14.3 (OBJ_dhSinglePass_cofactorDH_sha512kdf_scheme) */, + 631 /* 2.23.42.3.3.3.1 (OBJ_setAttr_GenCryptgrm) */, + 632 /* 2.23.42.3.3.4.1 (OBJ_setAttr_T2Enc) */, + 633 /* 2.23.42.3.3.4.2 (OBJ_setAttr_T2cleartxt) */, + 634 /* 2.23.42.3.3.5.1 (OBJ_setAttr_TokICCsig) */, + 635 /* 2.23.42.3.3.5.2 (OBJ_setAttr_SecDevSig) */, + 436 /* 0.9.2342.19200300 (OBJ_ucl) */, + 820 /* 1.2.643.2.2.14.0 (OBJ_id_Gost28147_89_None_KeyMeshing) */, + 819 /* 1.2.643.2.2.14.1 (OBJ_id_Gost28147_89_CryptoPro_KeyMeshing) */, + 845 /* 1.2.643.2.2.20.1 (OBJ_id_GostR3410_94_a) */, + 846 /* 1.2.643.2.2.20.2 (OBJ_id_GostR3410_94_aBis) */, + 847 /* 1.2.643.2.2.20.3 (OBJ_id_GostR3410_94_b) */, + 848 /* 1.2.643.2.2.20.4 (OBJ_id_GostR3410_94_bBis) */, + 821 /* 1.2.643.2.2.30.0 (OBJ_id_GostR3411_94_TestParamSet) */, + 822 /* 1.2.643.2.2.30.1 (OBJ_id_GostR3411_94_CryptoProParamSet) */, + 823 /* 1.2.643.2.2.31.0 (OBJ_id_Gost28147_89_TestParamSet) */, + 824 /* 1.2.643.2.2.31.1 (OBJ_id_Gost28147_89_CryptoPro_A_ParamSet) */, + 825 /* 1.2.643.2.2.31.2 (OBJ_id_Gost28147_89_CryptoPro_B_ParamSet) */, + 826 /* 1.2.643.2.2.31.3 (OBJ_id_Gost28147_89_CryptoPro_C_ParamSet) */, + 827 /* 1.2.643.2.2.31.4 (OBJ_id_Gost28147_89_CryptoPro_D_ParamSet) */, + 828 /* 1.2.643.2.2.31.5 (OBJ_id_Gost28147_89_CryptoPro_Oscar_1_1_ParamSet) */ + , + 829 /* 1.2.643.2.2.31.6 (OBJ_id_Gost28147_89_CryptoPro_Oscar_1_0_ParamSet) */ + , + 830 /* 1.2.643.2.2.31.7 (OBJ_id_Gost28147_89_CryptoPro_RIC_1_ParamSet) */, + 831 /* 1.2.643.2.2.32.0 (OBJ_id_GostR3410_94_TestParamSet) */, + 832 /* 1.2.643.2.2.32.2 (OBJ_id_GostR3410_94_CryptoPro_A_ParamSet) */, + 833 /* 1.2.643.2.2.32.3 (OBJ_id_GostR3410_94_CryptoPro_B_ParamSet) */, + 834 /* 1.2.643.2.2.32.4 (OBJ_id_GostR3410_94_CryptoPro_C_ParamSet) */, + 835 /* 1.2.643.2.2.32.5 (OBJ_id_GostR3410_94_CryptoPro_D_ParamSet) */, + 836 /* 1.2.643.2.2.33.1 (OBJ_id_GostR3410_94_CryptoPro_XchA_ParamSet) */, + 837 /* 1.2.643.2.2.33.2 (OBJ_id_GostR3410_94_CryptoPro_XchB_ParamSet) */, + 838 /* 1.2.643.2.2.33.3 (OBJ_id_GostR3410_94_CryptoPro_XchC_ParamSet) */, + 839 /* 1.2.643.2.2.35.0 (OBJ_id_GostR3410_2001_TestParamSet) */, + 840 /* 1.2.643.2.2.35.1 (OBJ_id_GostR3410_2001_CryptoPro_A_ParamSet) */, + 841 /* 1.2.643.2.2.35.2 (OBJ_id_GostR3410_2001_CryptoPro_B_ParamSet) */, + 842 /* 1.2.643.2.2.35.3 (OBJ_id_GostR3410_2001_CryptoPro_C_ParamSet) */, + 843 /* 1.2.643.2.2.36.0 (OBJ_id_GostR3410_2001_CryptoPro_XchA_ParamSet) */, + 844 /* 1.2.643.2.2.36.1 (OBJ_id_GostR3410_2001_CryptoPro_XchB_ParamSet) */, + 2 /* 1.2.840.113549.1 (OBJ_pkcs) */, + 431 /* 1.2.840.10040.2.1 (OBJ_hold_instruction_none) */, + 432 /* 1.2.840.10040.2.2 (OBJ_hold_instruction_call_issuer) */, + 433 /* 1.2.840.10040.2.3 (OBJ_hold_instruction_reject) */, + 116 /* 1.2.840.10040.4.1 (OBJ_dsa) */, + 113 /* 1.2.840.10040.4.3 (OBJ_dsaWithSHA1) */, + 406 /* 1.2.840.10045.1.1 (OBJ_X9_62_prime_field) */, + 407 /* 1.2.840.10045.1.2 (OBJ_X9_62_characteristic_two_field) */, + 408 /* 1.2.840.10045.2.1 (OBJ_X9_62_id_ecPublicKey) */, + 416 /* 1.2.840.10045.4.1 (OBJ_ecdsa_with_SHA1) */, + 791 /* 1.2.840.10045.4.2 (OBJ_ecdsa_with_Recommended) */, + 792 /* 1.2.840.10045.4.3 (OBJ_ecdsa_with_Specified) */, + 920 /* 1.2.840.10046.2.1 (OBJ_dhpublicnumber) */, + 258 /* 1.3.6.1.5.5.7.0 (OBJ_id_pkix_mod) */, + 175 /* 1.3.6.1.5.5.7.1 (OBJ_id_pe) */, + 259 /* 1.3.6.1.5.5.7.2 (OBJ_id_qt) */, + 128 /* 1.3.6.1.5.5.7.3 (OBJ_id_kp) */, + 260 /* 1.3.6.1.5.5.7.4 (OBJ_id_it) */, + 261 /* 1.3.6.1.5.5.7.5 (OBJ_id_pkip) */, + 262 /* 1.3.6.1.5.5.7.6 (OBJ_id_alg) */, + 263 /* 1.3.6.1.5.5.7.7 (OBJ_id_cmc) */, + 264 /* 1.3.6.1.5.5.7.8 (OBJ_id_on) */, + 265 /* 1.3.6.1.5.5.7.9 (OBJ_id_pda) */, + 266 /* 1.3.6.1.5.5.7.10 (OBJ_id_aca) */, + 267 /* 1.3.6.1.5.5.7.11 (OBJ_id_qcs) */, + 268 /* 1.3.6.1.5.5.7.12 (OBJ_id_cct) */, + 662 /* 1.3.6.1.5.5.7.21 (OBJ_id_ppl) */, + 176 /* 1.3.6.1.5.5.7.48 (OBJ_id_ad) */, + 507 /* 1.3.6.1.7.1.1.1 (OBJ_id_hex_partial_message) */, + 508 /* 1.3.6.1.7.1.1.2 (OBJ_id_hex_multipart_message) */, + 57 /* 2.16.840.1.113730 (OBJ_netscape) */, + 754 /* 0.3.4401.5.3.1.9.1 (OBJ_camellia_128_ecb) */, + 766 /* 0.3.4401.5.3.1.9.3 (OBJ_camellia_128_ofb128) */, + 757 /* 0.3.4401.5.3.1.9.4 (OBJ_camellia_128_cfb128) */, + 755 /* 0.3.4401.5.3.1.9.21 (OBJ_camellia_192_ecb) */, + 767 /* 0.3.4401.5.3.1.9.23 (OBJ_camellia_192_ofb128) */, + 758 /* 0.3.4401.5.3.1.9.24 (OBJ_camellia_192_cfb128) */, + 756 /* 0.3.4401.5.3.1.9.41 (OBJ_camellia_256_ecb) */, + 768 /* 0.3.4401.5.3.1.9.43 (OBJ_camellia_256_ofb128) */, + 759 /* 0.3.4401.5.3.1.9.44 (OBJ_camellia_256_cfb128) */, + 437 /* 0.9.2342.19200300.100 (OBJ_pilot) */, + 776 /* 1.2.410.200004.1.3 (OBJ_seed_ecb) */, + 777 /* 1.2.410.200004.1.4 (OBJ_seed_cbc) */, + 779 /* 1.2.410.200004.1.5 (OBJ_seed_cfb128) */, + 778 /* 1.2.410.200004.1.6 (OBJ_seed_ofb128) */, + 852 /* 1.2.643.2.9.1.3.3 (OBJ_id_GostR3411_94_with_GostR3410_94_cc) */, + 853 /* 1.2.643.2.9.1.3.4 (OBJ_id_GostR3411_94_with_GostR3410_2001_cc) */, + 850 /* 1.2.643.2.9.1.5.3 (OBJ_id_GostR3410_94_cc) */, + 851 /* 1.2.643.2.9.1.5.4 (OBJ_id_GostR3410_2001_cc) */, + 849 /* 1.2.643.2.9.1.6.1 (OBJ_id_Gost28147_89_cc) */, + 854 /* 1.2.643.2.9.1.8.1 (OBJ_id_GostR3410_2001_ParamSet_cc) */, + 186 /* 1.2.840.113549.1.1 (OBJ_pkcs1) */, + 27 /* 1.2.840.113549.1.3 (OBJ_pkcs3) */, + 187 /* 1.2.840.113549.1.5 (OBJ_pkcs5) */, + 20 /* 1.2.840.113549.1.7 (OBJ_pkcs7) */, + 47 /* 1.2.840.113549.1.9 (OBJ_pkcs9) */, + 3 /* 1.2.840.113549.2.2 (OBJ_md2) */, + 257 /* 1.2.840.113549.2.4 (OBJ_md4) */, + 4 /* 1.2.840.113549.2.5 (OBJ_md5) */, + 797 /* 1.2.840.113549.2.6 (OBJ_hmacWithMD5) */, + 163 /* 1.2.840.113549.2.7 (OBJ_hmacWithSHA1) */, + 798 /* 1.2.840.113549.2.8 (OBJ_hmacWithSHA224) */, + 799 /* 1.2.840.113549.2.9 (OBJ_hmacWithSHA256) */, + 800 /* 1.2.840.113549.2.10 (OBJ_hmacWithSHA384) */, + 801 /* 1.2.840.113549.2.11 (OBJ_hmacWithSHA512) */, + 37 /* 1.2.840.113549.3.2 (OBJ_rc2_cbc) */, + 5 /* 1.2.840.113549.3.4 (OBJ_rc4) */, + 44 /* 1.2.840.113549.3.7 (OBJ_des_ede3_cbc) */, + 120 /* 1.2.840.113549.3.8 (OBJ_rc5_cbc) */, + 643 /* 1.2.840.113549.3.10 (OBJ_des_cdmf) */, + 680 /* 1.2.840.10045.1.2.3 (OBJ_X9_62_id_characteristic_two_basis) */, + 684 /* 1.2.840.10045.3.0.1 (OBJ_X9_62_c2pnb163v1) */, + 685 /* 1.2.840.10045.3.0.2 (OBJ_X9_62_c2pnb163v2) */, + 686 /* 1.2.840.10045.3.0.3 (OBJ_X9_62_c2pnb163v3) */, + 687 /* 1.2.840.10045.3.0.4 (OBJ_X9_62_c2pnb176v1) */, + 688 /* 1.2.840.10045.3.0.5 (OBJ_X9_62_c2tnb191v1) */, + 689 /* 1.2.840.10045.3.0.6 (OBJ_X9_62_c2tnb191v2) */, + 690 /* 1.2.840.10045.3.0.7 (OBJ_X9_62_c2tnb191v3) */, + 691 /* 1.2.840.10045.3.0.8 (OBJ_X9_62_c2onb191v4) */, + 692 /* 1.2.840.10045.3.0.9 (OBJ_X9_62_c2onb191v5) */, + 693 /* 1.2.840.10045.3.0.10 (OBJ_X9_62_c2pnb208w1) */, + 694 /* 1.2.840.10045.3.0.11 (OBJ_X9_62_c2tnb239v1) */, + 695 /* 1.2.840.10045.3.0.12 (OBJ_X9_62_c2tnb239v2) */, + 696 /* 1.2.840.10045.3.0.13 (OBJ_X9_62_c2tnb239v3) */, + 697 /* 1.2.840.10045.3.0.14 (OBJ_X9_62_c2onb239v4) */, + 698 /* 1.2.840.10045.3.0.15 (OBJ_X9_62_c2onb239v5) */, + 699 /* 1.2.840.10045.3.0.16 (OBJ_X9_62_c2pnb272w1) */, + 700 /* 1.2.840.10045.3.0.17 (OBJ_X9_62_c2pnb304w1) */, + 701 /* 1.2.840.10045.3.0.18 (OBJ_X9_62_c2tnb359v1) */, + 702 /* 1.2.840.10045.3.0.19 (OBJ_X9_62_c2pnb368w1) */, + 703 /* 1.2.840.10045.3.0.20 (OBJ_X9_62_c2tnb431r1) */, + 409 /* 1.2.840.10045.3.1.1 (OBJ_X9_62_prime192v1) */, + 410 /* 1.2.840.10045.3.1.2 (OBJ_X9_62_prime192v2) */, + 411 /* 1.2.840.10045.3.1.3 (OBJ_X9_62_prime192v3) */, + 412 /* 1.2.840.10045.3.1.4 (OBJ_X9_62_prime239v1) */, + 413 /* 1.2.840.10045.3.1.5 (OBJ_X9_62_prime239v2) */, + 414 /* 1.2.840.10045.3.1.6 (OBJ_X9_62_prime239v3) */, + 415 /* 1.2.840.10045.3.1.7 (OBJ_X9_62_prime256v1) */, + 793 /* 1.2.840.10045.4.3.1 (OBJ_ecdsa_with_SHA224) */, + 794 /* 1.2.840.10045.4.3.2 (OBJ_ecdsa_with_SHA256) */, + 795 /* 1.2.840.10045.4.3.3 (OBJ_ecdsa_with_SHA384) */, + 796 /* 1.2.840.10045.4.3.4 (OBJ_ecdsa_with_SHA512) */, + 269 /* 1.3.6.1.5.5.7.0.1 (OBJ_id_pkix1_explicit_88) */, + 270 /* 1.3.6.1.5.5.7.0.2 (OBJ_id_pkix1_implicit_88) */, + 271 /* 1.3.6.1.5.5.7.0.3 (OBJ_id_pkix1_explicit_93) */, + 272 /* 1.3.6.1.5.5.7.0.4 (OBJ_id_pkix1_implicit_93) */, + 273 /* 1.3.6.1.5.5.7.0.5 (OBJ_id_mod_crmf) */, + 274 /* 1.3.6.1.5.5.7.0.6 (OBJ_id_mod_cmc) */, + 275 /* 1.3.6.1.5.5.7.0.7 (OBJ_id_mod_kea_profile_88) */, + 276 /* 1.3.6.1.5.5.7.0.8 (OBJ_id_mod_kea_profile_93) */, + 277 /* 1.3.6.1.5.5.7.0.9 (OBJ_id_mod_cmp) */, + 278 /* 1.3.6.1.5.5.7.0.10 (OBJ_id_mod_qualified_cert_88) */, + 279 /* 1.3.6.1.5.5.7.0.11 (OBJ_id_mod_qualified_cert_93) */, + 280 /* 1.3.6.1.5.5.7.0.12 (OBJ_id_mod_attribute_cert) */, + 281 /* 1.3.6.1.5.5.7.0.13 (OBJ_id_mod_timestamp_protocol) */, + 282 /* 1.3.6.1.5.5.7.0.14 (OBJ_id_mod_ocsp) */, + 283 /* 1.3.6.1.5.5.7.0.15 (OBJ_id_mod_dvcs) */, + 284 /* 1.3.6.1.5.5.7.0.16 (OBJ_id_mod_cmp2000) */, + 177 /* 1.3.6.1.5.5.7.1.1 (OBJ_info_access) */, + 285 /* 1.3.6.1.5.5.7.1.2 (OBJ_biometricInfo) */, + 286 /* 1.3.6.1.5.5.7.1.3 (OBJ_qcStatements) */, + 287 /* 1.3.6.1.5.5.7.1.4 (OBJ_ac_auditEntity) */, + 288 /* 1.3.6.1.5.5.7.1.5 (OBJ_ac_targeting) */, + 289 /* 1.3.6.1.5.5.7.1.6 (OBJ_aaControls) */, + 290 /* 1.3.6.1.5.5.7.1.7 (OBJ_sbgp_ipAddrBlock) */, + 291 /* 1.3.6.1.5.5.7.1.8 (OBJ_sbgp_autonomousSysNum) */, + 292 /* 1.3.6.1.5.5.7.1.9 (OBJ_sbgp_routerIdentifier) */, + 397 /* 1.3.6.1.5.5.7.1.10 (OBJ_ac_proxying) */, + 398 /* 1.3.6.1.5.5.7.1.11 (OBJ_sinfo_access) */, + 663 /* 1.3.6.1.5.5.7.1.14 (OBJ_proxyCertInfo) */, + 164 /* 1.3.6.1.5.5.7.2.1 (OBJ_id_qt_cps) */, + 165 /* 1.3.6.1.5.5.7.2.2 (OBJ_id_qt_unotice) */, + 293 /* 1.3.6.1.5.5.7.2.3 (OBJ_textNotice) */, + 129 /* 1.3.6.1.5.5.7.3.1 (OBJ_server_auth) */, + 130 /* 1.3.6.1.5.5.7.3.2 (OBJ_client_auth) */, + 131 /* 1.3.6.1.5.5.7.3.3 (OBJ_code_sign) */, + 132 /* 1.3.6.1.5.5.7.3.4 (OBJ_email_protect) */, + 294 /* 1.3.6.1.5.5.7.3.5 (OBJ_ipsecEndSystem) */, + 295 /* 1.3.6.1.5.5.7.3.6 (OBJ_ipsecTunnel) */, + 296 /* 1.3.6.1.5.5.7.3.7 (OBJ_ipsecUser) */, + 133 /* 1.3.6.1.5.5.7.3.8 (OBJ_time_stamp) */, + 180 /* 1.3.6.1.5.5.7.3.9 (OBJ_OCSP_sign) */, + 297 /* 1.3.6.1.5.5.7.3.10 (OBJ_dvcs) */, + 298 /* 1.3.6.1.5.5.7.4.1 (OBJ_id_it_caProtEncCert) */, + 299 /* 1.3.6.1.5.5.7.4.2 (OBJ_id_it_signKeyPairTypes) */, + 300 /* 1.3.6.1.5.5.7.4.3 (OBJ_id_it_encKeyPairTypes) */, + 301 /* 1.3.6.1.5.5.7.4.4 (OBJ_id_it_preferredSymmAlg) */, + 302 /* 1.3.6.1.5.5.7.4.5 (OBJ_id_it_caKeyUpdateInfo) */, + 303 /* 1.3.6.1.5.5.7.4.6 (OBJ_id_it_currentCRL) */, + 304 /* 1.3.6.1.5.5.7.4.7 (OBJ_id_it_unsupportedOIDs) */, + 305 /* 1.3.6.1.5.5.7.4.8 (OBJ_id_it_subscriptionRequest) */, + 306 /* 1.3.6.1.5.5.7.4.9 (OBJ_id_it_subscriptionResponse) */, + 307 /* 1.3.6.1.5.5.7.4.10 (OBJ_id_it_keyPairParamReq) */, + 308 /* 1.3.6.1.5.5.7.4.11 (OBJ_id_it_keyPairParamRep) */, + 309 /* 1.3.6.1.5.5.7.4.12 (OBJ_id_it_revPassphrase) */, + 310 /* 1.3.6.1.5.5.7.4.13 (OBJ_id_it_implicitConfirm) */, + 311 /* 1.3.6.1.5.5.7.4.14 (OBJ_id_it_confirmWaitTime) */, + 312 /* 1.3.6.1.5.5.7.4.15 (OBJ_id_it_origPKIMessage) */, + 784 /* 1.3.6.1.5.5.7.4.16 (OBJ_id_it_suppLangTags) */, + 313 /* 1.3.6.1.5.5.7.5.1 (OBJ_id_regCtrl) */, + 314 /* 1.3.6.1.5.5.7.5.2 (OBJ_id_regInfo) */, + 323 /* 1.3.6.1.5.5.7.6.1 (OBJ_id_alg_des40) */, + 324 /* 1.3.6.1.5.5.7.6.2 (OBJ_id_alg_noSignature) */, + 325 /* 1.3.6.1.5.5.7.6.3 (OBJ_id_alg_dh_sig_hmac_sha1) */, + 326 /* 1.3.6.1.5.5.7.6.4 (OBJ_id_alg_dh_pop) */, + 327 /* 1.3.6.1.5.5.7.7.1 (OBJ_id_cmc_statusInfo) */, + 328 /* 1.3.6.1.5.5.7.7.2 (OBJ_id_cmc_identification) */, + 329 /* 1.3.6.1.5.5.7.7.3 (OBJ_id_cmc_identityProof) */, + 330 /* 1.3.6.1.5.5.7.7.4 (OBJ_id_cmc_dataReturn) */, + 331 /* 1.3.6.1.5.5.7.7.5 (OBJ_id_cmc_transactionId) */, + 332 /* 1.3.6.1.5.5.7.7.6 (OBJ_id_cmc_senderNonce) */, + 333 /* 1.3.6.1.5.5.7.7.7 (OBJ_id_cmc_recipientNonce) */, + 334 /* 1.3.6.1.5.5.7.7.8 (OBJ_id_cmc_addExtensions) */, + 335 /* 1.3.6.1.5.5.7.7.9 (OBJ_id_cmc_encryptedPOP) */, + 336 /* 1.3.6.1.5.5.7.7.10 (OBJ_id_cmc_decryptedPOP) */, + 337 /* 1.3.6.1.5.5.7.7.11 (OBJ_id_cmc_lraPOPWitness) */, + 338 /* 1.3.6.1.5.5.7.7.15 (OBJ_id_cmc_getCert) */, + 339 /* 1.3.6.1.5.5.7.7.16 (OBJ_id_cmc_getCRL) */, + 340 /* 1.3.6.1.5.5.7.7.17 (OBJ_id_cmc_revokeRequest) */, + 341 /* 1.3.6.1.5.5.7.7.18 (OBJ_id_cmc_regInfo) */, + 342 /* 1.3.6.1.5.5.7.7.19 (OBJ_id_cmc_responseInfo) */, + 343 /* 1.3.6.1.5.5.7.7.21 (OBJ_id_cmc_queryPending) */, + 344 /* 1.3.6.1.5.5.7.7.22 (OBJ_id_cmc_popLinkRandom) */, + 345 /* 1.3.6.1.5.5.7.7.23 (OBJ_id_cmc_popLinkWitness) */, + 346 /* 1.3.6.1.5.5.7.7.24 (OBJ_id_cmc_confirmCertAcceptance) */, + 347 /* 1.3.6.1.5.5.7.8.1 (OBJ_id_on_personalData) */, + 858 /* 1.3.6.1.5.5.7.8.3 (OBJ_id_on_permanentIdentifier) */, + 348 /* 1.3.6.1.5.5.7.9.1 (OBJ_id_pda_dateOfBirth) */, + 349 /* 1.3.6.1.5.5.7.9.2 (OBJ_id_pda_placeOfBirth) */, + 351 /* 1.3.6.1.5.5.7.9.3 (OBJ_id_pda_gender) */, + 352 /* 1.3.6.1.5.5.7.9.4 (OBJ_id_pda_countryOfCitizenship) */, + 353 /* 1.3.6.1.5.5.7.9.5 (OBJ_id_pda_countryOfResidence) */, + 354 /* 1.3.6.1.5.5.7.10.1 (OBJ_id_aca_authenticationInfo) */, + 355 /* 1.3.6.1.5.5.7.10.2 (OBJ_id_aca_accessIdentity) */, + 356 /* 1.3.6.1.5.5.7.10.3 (OBJ_id_aca_chargingIdentity) */, + 357 /* 1.3.6.1.5.5.7.10.4 (OBJ_id_aca_group) */, + 358 /* 1.3.6.1.5.5.7.10.5 (OBJ_id_aca_role) */, + 399 /* 1.3.6.1.5.5.7.10.6 (OBJ_id_aca_encAttrs) */, + 359 /* 1.3.6.1.5.5.7.11.1 (OBJ_id_qcs_pkixQCSyntax_v1) */, + 360 /* 1.3.6.1.5.5.7.12.1 (OBJ_id_cct_crs) */, + 361 /* 1.3.6.1.5.5.7.12.2 (OBJ_id_cct_PKIData) */, + 362 /* 1.3.6.1.5.5.7.12.3 (OBJ_id_cct_PKIResponse) */, + 664 /* 1.3.6.1.5.5.7.21.0 (OBJ_id_ppl_anyLanguage) */, + 665 /* 1.3.6.1.5.5.7.21.1 (OBJ_id_ppl_inheritAll) */, + 667 /* 1.3.6.1.5.5.7.21.2 (OBJ_Independent) */, + 178 /* 1.3.6.1.5.5.7.48.1 (OBJ_ad_OCSP) */, + 179 /* 1.3.6.1.5.5.7.48.2 (OBJ_ad_ca_issuers) */, + 363 /* 1.3.6.1.5.5.7.48.3 (OBJ_ad_timeStamping) */, + 364 /* 1.3.6.1.5.5.7.48.4 (OBJ_ad_dvcs) */, + 785 /* 1.3.6.1.5.5.7.48.5 (OBJ_caRepository) */, + 780 /* 1.3.6.1.5.5.8.1.1 (OBJ_hmac_md5) */, + 781 /* 1.3.6.1.5.5.8.1.2 (OBJ_hmac_sha1) */, + 58 /* 2.16.840.1.113730.1 (OBJ_netscape_cert_extension) */, + 59 /* 2.16.840.1.113730.2 (OBJ_netscape_data_type) */, + 438 /* 0.9.2342.19200300.100.1 (OBJ_pilotAttributeType) */, + 439 /* 0.9.2342.19200300.100.3 (OBJ_pilotAttributeSyntax) */, + 440 /* 0.9.2342.19200300.100.4 (OBJ_pilotObjectClass) */, + 441 /* 0.9.2342.19200300.100.10 (OBJ_pilotGroups) */, + 108 /* 1.2.840.113533.7.66.10 (OBJ_cast5_cbc) */, + 112 /* 1.2.840.113533.7.66.12 (OBJ_pbeWithMD5AndCast5_CBC) */, + 782 /* 1.2.840.113533.7.66.13 (OBJ_id_PasswordBasedMAC) */, + 783 /* 1.2.840.113533.7.66.30 (OBJ_id_DHBasedMac) */, + 6 /* 1.2.840.113549.1.1.1 (OBJ_rsaEncryption) */, + 7 /* 1.2.840.113549.1.1.2 (OBJ_md2WithRSAEncryption) */, + 396 /* 1.2.840.113549.1.1.3 (OBJ_md4WithRSAEncryption) */, + 8 /* 1.2.840.113549.1.1.4 (OBJ_md5WithRSAEncryption) */, + 65 /* 1.2.840.113549.1.1.5 (OBJ_sha1WithRSAEncryption) */, + 644 /* 1.2.840.113549.1.1.6 (OBJ_rsaOAEPEncryptionSET) */, + 919 /* 1.2.840.113549.1.1.7 (OBJ_rsaesOaep) */, + 911 /* 1.2.840.113549.1.1.8 (OBJ_mgf1) */, + 935 /* 1.2.840.113549.1.1.9 (OBJ_pSpecified) */, + 912 /* 1.2.840.113549.1.1.10 (OBJ_rsassaPss) */, + 668 /* 1.2.840.113549.1.1.11 (OBJ_sha256WithRSAEncryption) */, + 669 /* 1.2.840.113549.1.1.12 (OBJ_sha384WithRSAEncryption) */, + 670 /* 1.2.840.113549.1.1.13 (OBJ_sha512WithRSAEncryption) */, + 671 /* 1.2.840.113549.1.1.14 (OBJ_sha224WithRSAEncryption) */, + 28 /* 1.2.840.113549.1.3.1 (OBJ_dhKeyAgreement) */, + 9 /* 1.2.840.113549.1.5.1 (OBJ_pbeWithMD2AndDES_CBC) */, + 10 /* 1.2.840.113549.1.5.3 (OBJ_pbeWithMD5AndDES_CBC) */, + 168 /* 1.2.840.113549.1.5.4 (OBJ_pbeWithMD2AndRC2_CBC) */, + 169 /* 1.2.840.113549.1.5.6 (OBJ_pbeWithMD5AndRC2_CBC) */, + 170 /* 1.2.840.113549.1.5.10 (OBJ_pbeWithSHA1AndDES_CBC) */, + 68 /* 1.2.840.113549.1.5.11 (OBJ_pbeWithSHA1AndRC2_CBC) */, + 69 /* 1.2.840.113549.1.5.12 (OBJ_id_pbkdf2) */, + 161 /* 1.2.840.113549.1.5.13 (OBJ_pbes2) */, + 162 /* 1.2.840.113549.1.5.14 (OBJ_pbmac1) */, + 21 /* 1.2.840.113549.1.7.1 (OBJ_pkcs7_data) */, + 22 /* 1.2.840.113549.1.7.2 (OBJ_pkcs7_signed) */, + 23 /* 1.2.840.113549.1.7.3 (OBJ_pkcs7_enveloped) */, + 24 /* 1.2.840.113549.1.7.4 (OBJ_pkcs7_signedAndEnveloped) */, + 25 /* 1.2.840.113549.1.7.5 (OBJ_pkcs7_digest) */, + 26 /* 1.2.840.113549.1.7.6 (OBJ_pkcs7_encrypted) */, + 48 /* 1.2.840.113549.1.9.1 (OBJ_pkcs9_emailAddress) */, + 49 /* 1.2.840.113549.1.9.2 (OBJ_pkcs9_unstructuredName) */, + 50 /* 1.2.840.113549.1.9.3 (OBJ_pkcs9_contentType) */, + 51 /* 1.2.840.113549.1.9.4 (OBJ_pkcs9_messageDigest) */, + 52 /* 1.2.840.113549.1.9.5 (OBJ_pkcs9_signingTime) */, + 53 /* 1.2.840.113549.1.9.6 (OBJ_pkcs9_countersignature) */, + 54 /* 1.2.840.113549.1.9.7 (OBJ_pkcs9_challengePassword) */, + 55 /* 1.2.840.113549.1.9.8 (OBJ_pkcs9_unstructuredAddress) */, + 56 /* 1.2.840.113549.1.9.9 (OBJ_pkcs9_extCertAttributes) */, + 172 /* 1.2.840.113549.1.9.14 (OBJ_ext_req) */, + 167 /* 1.2.840.113549.1.9.15 (OBJ_SMIMECapabilities) */, + 188 /* 1.2.840.113549.1.9.16 (OBJ_SMIME) */, + 156 /* 1.2.840.113549.1.9.20 (OBJ_friendlyName) */, + 157 /* 1.2.840.113549.1.9.21 (OBJ_localKeyID) */, + 681 /* 1.2.840.10045.1.2.3.1 (OBJ_X9_62_onBasis) */, + 682 /* 1.2.840.10045.1.2.3.2 (OBJ_X9_62_tpBasis) */, + 683 /* 1.2.840.10045.1.2.3.3 (OBJ_X9_62_ppBasis) */, + 417 /* 1.3.6.1.4.1.311.17.1 (OBJ_ms_csp_name) */, + 856 /* 1.3.6.1.4.1.311.17.2 (OBJ_LocalKeySet) */, + 390 /* 1.3.6.1.4.1.1466.344 (OBJ_dcObject) */, + 91 /* 1.3.6.1.4.1.3029.1.2 (OBJ_bf_cbc) */, + 315 /* 1.3.6.1.5.5.7.5.1.1 (OBJ_id_regCtrl_regToken) */, + 316 /* 1.3.6.1.5.5.7.5.1.2 (OBJ_id_regCtrl_authenticator) */, + 317 /* 1.3.6.1.5.5.7.5.1.3 (OBJ_id_regCtrl_pkiPublicationInfo) */, + 318 /* 1.3.6.1.5.5.7.5.1.4 (OBJ_id_regCtrl_pkiArchiveOptions) */, + 319 /* 1.3.6.1.5.5.7.5.1.5 (OBJ_id_regCtrl_oldCertID) */, + 320 /* 1.3.6.1.5.5.7.5.1.6 (OBJ_id_regCtrl_protocolEncrKey) */, + 321 /* 1.3.6.1.5.5.7.5.2.1 (OBJ_id_regInfo_utf8Pairs) */, + 322 /* 1.3.6.1.5.5.7.5.2.2 (OBJ_id_regInfo_certReq) */, + 365 /* 1.3.6.1.5.5.7.48.1.1 (OBJ_id_pkix_OCSP_basic) */, + 366 /* 1.3.6.1.5.5.7.48.1.2 (OBJ_id_pkix_OCSP_Nonce) */, + 367 /* 1.3.6.1.5.5.7.48.1.3 (OBJ_id_pkix_OCSP_CrlID) */, + 368 /* 1.3.6.1.5.5.7.48.1.4 (OBJ_id_pkix_OCSP_acceptableResponses) */, + 369 /* 1.3.6.1.5.5.7.48.1.5 (OBJ_id_pkix_OCSP_noCheck) */, + 370 /* 1.3.6.1.5.5.7.48.1.6 (OBJ_id_pkix_OCSP_archiveCutoff) */, + 371 /* 1.3.6.1.5.5.7.48.1.7 (OBJ_id_pkix_OCSP_serviceLocator) */, + 372 /* 1.3.6.1.5.5.7.48.1.8 (OBJ_id_pkix_OCSP_extendedStatus) */, + 373 /* 1.3.6.1.5.5.7.48.1.9 (OBJ_id_pkix_OCSP_valid) */, + 374 /* 1.3.6.1.5.5.7.48.1.10 (OBJ_id_pkix_OCSP_path) */, + 375 /* 1.3.6.1.5.5.7.48.1.11 (OBJ_id_pkix_OCSP_trustRoot) */, + 921 /* 1.3.36.3.3.2.8.1.1.1 (OBJ_brainpoolP160r1) */, + 922 /* 1.3.36.3.3.2.8.1.1.2 (OBJ_brainpoolP160t1) */, + 923 /* 1.3.36.3.3.2.8.1.1.3 (OBJ_brainpoolP192r1) */, + 924 /* 1.3.36.3.3.2.8.1.1.4 (OBJ_brainpoolP192t1) */, + 925 /* 1.3.36.3.3.2.8.1.1.5 (OBJ_brainpoolP224r1) */, + 926 /* 1.3.36.3.3.2.8.1.1.6 (OBJ_brainpoolP224t1) */, + 927 /* 1.3.36.3.3.2.8.1.1.7 (OBJ_brainpoolP256r1) */, + 928 /* 1.3.36.3.3.2.8.1.1.8 (OBJ_brainpoolP256t1) */, + 929 /* 1.3.36.3.3.2.8.1.1.9 (OBJ_brainpoolP320r1) */, + 930 /* 1.3.36.3.3.2.8.1.1.10 (OBJ_brainpoolP320t1) */, + 931 /* 1.3.36.3.3.2.8.1.1.11 (OBJ_brainpoolP384r1) */, + 932 /* 1.3.36.3.3.2.8.1.1.12 (OBJ_brainpoolP384t1) */, + 933 /* 1.3.36.3.3.2.8.1.1.13 (OBJ_brainpoolP512r1) */, + 934 /* 1.3.36.3.3.2.8.1.1.14 (OBJ_brainpoolP512t1) */, + 936 /* 1.3.133.16.840.63.0.2 (OBJ_dhSinglePass_stdDH_sha1kdf_scheme) */, + 941 /* 1.3.133.16.840.63.0.3 (OBJ_dhSinglePass_cofactorDH_sha1kdf_scheme) */ + , + 418 /* 2.16.840.1.101.3.4.1.1 (OBJ_aes_128_ecb) */, + 419 /* 2.16.840.1.101.3.4.1.2 (OBJ_aes_128_cbc) */, + 420 /* 2.16.840.1.101.3.4.1.3 (OBJ_aes_128_ofb128) */, + 421 /* 2.16.840.1.101.3.4.1.4 (OBJ_aes_128_cfb128) */, + 788 /* 2.16.840.1.101.3.4.1.5 (OBJ_id_aes128_wrap) */, + 895 /* 2.16.840.1.101.3.4.1.6 (OBJ_aes_128_gcm) */, + 896 /* 2.16.840.1.101.3.4.1.7 (OBJ_aes_128_ccm) */, + 897 /* 2.16.840.1.101.3.4.1.8 (OBJ_id_aes128_wrap_pad) */, + 422 /* 2.16.840.1.101.3.4.1.21 (OBJ_aes_192_ecb) */, + 423 /* 2.16.840.1.101.3.4.1.22 (OBJ_aes_192_cbc) */, + 424 /* 2.16.840.1.101.3.4.1.23 (OBJ_aes_192_ofb128) */, + 425 /* 2.16.840.1.101.3.4.1.24 (OBJ_aes_192_cfb128) */, + 789 /* 2.16.840.1.101.3.4.1.25 (OBJ_id_aes192_wrap) */, + 898 /* 2.16.840.1.101.3.4.1.26 (OBJ_aes_192_gcm) */, + 899 /* 2.16.840.1.101.3.4.1.27 (OBJ_aes_192_ccm) */, + 900 /* 2.16.840.1.101.3.4.1.28 (OBJ_id_aes192_wrap_pad) */, + 426 /* 2.16.840.1.101.3.4.1.41 (OBJ_aes_256_ecb) */, + 427 /* 2.16.840.1.101.3.4.1.42 (OBJ_aes_256_cbc) */, + 428 /* 2.16.840.1.101.3.4.1.43 (OBJ_aes_256_ofb128) */, + 429 /* 2.16.840.1.101.3.4.1.44 (OBJ_aes_256_cfb128) */, + 790 /* 2.16.840.1.101.3.4.1.45 (OBJ_id_aes256_wrap) */, + 901 /* 2.16.840.1.101.3.4.1.46 (OBJ_aes_256_gcm) */, + 902 /* 2.16.840.1.101.3.4.1.47 (OBJ_aes_256_ccm) */, + 903 /* 2.16.840.1.101.3.4.1.48 (OBJ_id_aes256_wrap_pad) */, + 672 /* 2.16.840.1.101.3.4.2.1 (OBJ_sha256) */, + 673 /* 2.16.840.1.101.3.4.2.2 (OBJ_sha384) */, + 674 /* 2.16.840.1.101.3.4.2.3 (OBJ_sha512) */, + 675 /* 2.16.840.1.101.3.4.2.4 (OBJ_sha224) */, + 802 /* 2.16.840.1.101.3.4.3.1 (OBJ_dsa_with_SHA224) */, + 803 /* 2.16.840.1.101.3.4.3.2 (OBJ_dsa_with_SHA256) */, + 71 /* 2.16.840.1.113730.1.1 (OBJ_netscape_cert_type) */, + 72 /* 2.16.840.1.113730.1.2 (OBJ_netscape_base_url) */, + 73 /* 2.16.840.1.113730.1.3 (OBJ_netscape_revocation_url) */, + 74 /* 2.16.840.1.113730.1.4 (OBJ_netscape_ca_revocation_url) */, + 75 /* 2.16.840.1.113730.1.7 (OBJ_netscape_renewal_url) */, + 76 /* 2.16.840.1.113730.1.8 (OBJ_netscape_ca_policy_url) */, + 77 /* 2.16.840.1.113730.1.12 (OBJ_netscape_ssl_server_name) */, + 78 /* 2.16.840.1.113730.1.13 (OBJ_netscape_comment) */, + 79 /* 2.16.840.1.113730.2.5 (OBJ_netscape_cert_sequence) */, + 139 /* 2.16.840.1.113730.4.1 (OBJ_ns_sgc) */, + 458 /* 0.9.2342.19200300.100.1.1 (OBJ_userId) */, + 459 /* 0.9.2342.19200300.100.1.2 (OBJ_textEncodedORAddress) */, + 460 /* 0.9.2342.19200300.100.1.3 (OBJ_rfc822Mailbox) */, + 461 /* 0.9.2342.19200300.100.1.4 (OBJ_info) */, + 462 /* 0.9.2342.19200300.100.1.5 (OBJ_favouriteDrink) */, + 463 /* 0.9.2342.19200300.100.1.6 (OBJ_roomNumber) */, + 464 /* 0.9.2342.19200300.100.1.7 (OBJ_photo) */, + 465 /* 0.9.2342.19200300.100.1.8 (OBJ_userClass) */, + 466 /* 0.9.2342.19200300.100.1.9 (OBJ_host) */, + 467 /* 0.9.2342.19200300.100.1.10 (OBJ_manager) */, + 468 /* 0.9.2342.19200300.100.1.11 (OBJ_documentIdentifier) */, + 469 /* 0.9.2342.19200300.100.1.12 (OBJ_documentTitle) */, + 470 /* 0.9.2342.19200300.100.1.13 (OBJ_documentVersion) */, + 471 /* 0.9.2342.19200300.100.1.14 (OBJ_documentAuthor) */, + 472 /* 0.9.2342.19200300.100.1.15 (OBJ_documentLocation) */, + 473 /* 0.9.2342.19200300.100.1.20 (OBJ_homeTelephoneNumber) */, + 474 /* 0.9.2342.19200300.100.1.21 (OBJ_secretary) */, + 475 /* 0.9.2342.19200300.100.1.22 (OBJ_otherMailbox) */, + 476 /* 0.9.2342.19200300.100.1.23 (OBJ_lastModifiedTime) */, + 477 /* 0.9.2342.19200300.100.1.24 (OBJ_lastModifiedBy) */, + 391 /* 0.9.2342.19200300.100.1.25 (OBJ_domainComponent) */, + 478 /* 0.9.2342.19200300.100.1.26 (OBJ_aRecord) */, + 479 /* 0.9.2342.19200300.100.1.27 (OBJ_pilotAttributeType27) */, + 480 /* 0.9.2342.19200300.100.1.28 (OBJ_mXRecord) */, + 481 /* 0.9.2342.19200300.100.1.29 (OBJ_nSRecord) */, + 482 /* 0.9.2342.19200300.100.1.30 (OBJ_sOARecord) */, + 483 /* 0.9.2342.19200300.100.1.31 (OBJ_cNAMERecord) */, + 484 /* 0.9.2342.19200300.100.1.37 (OBJ_associatedDomain) */, + 485 /* 0.9.2342.19200300.100.1.38 (OBJ_associatedName) */, + 486 /* 0.9.2342.19200300.100.1.39 (OBJ_homePostalAddress) */, + 487 /* 0.9.2342.19200300.100.1.40 (OBJ_personalTitle) */, + 488 /* 0.9.2342.19200300.100.1.41 (OBJ_mobileTelephoneNumber) */, + 489 /* 0.9.2342.19200300.100.1.42 (OBJ_pagerTelephoneNumber) */, + 490 /* 0.9.2342.19200300.100.1.43 (OBJ_friendlyCountryName) */, + 491 /* 0.9.2342.19200300.100.1.45 (OBJ_organizationalStatus) */, + 492 /* 0.9.2342.19200300.100.1.46 (OBJ_janetMailbox) */, + 493 /* 0.9.2342.19200300.100.1.47 (OBJ_mailPreferenceOption) */, + 494 /* 0.9.2342.19200300.100.1.48 (OBJ_buildingName) */, + 495 /* 0.9.2342.19200300.100.1.49 (OBJ_dSAQuality) */, + 496 /* 0.9.2342.19200300.100.1.50 (OBJ_singleLevelQuality) */, + 497 /* 0.9.2342.19200300.100.1.51 (OBJ_subtreeMinimumQuality) */, + 498 /* 0.9.2342.19200300.100.1.52 (OBJ_subtreeMaximumQuality) */, + 499 /* 0.9.2342.19200300.100.1.53 (OBJ_personalSignature) */, + 500 /* 0.9.2342.19200300.100.1.54 (OBJ_dITRedirect) */, + 501 /* 0.9.2342.19200300.100.1.55 (OBJ_audio) */, + 502 /* 0.9.2342.19200300.100.1.56 (OBJ_documentPublisher) */, + 442 /* 0.9.2342.19200300.100.3.4 (OBJ_iA5StringSyntax) */, + 443 /* 0.9.2342.19200300.100.3.5 (OBJ_caseIgnoreIA5StringSyntax) */, + 444 /* 0.9.2342.19200300.100.4.3 (OBJ_pilotObject) */, + 445 /* 0.9.2342.19200300.100.4.4 (OBJ_pilotPerson) */, + 446 /* 0.9.2342.19200300.100.4.5 (OBJ_account) */, + 447 /* 0.9.2342.19200300.100.4.6 (OBJ_document) */, + 448 /* 0.9.2342.19200300.100.4.7 (OBJ_room) */, + 449 /* 0.9.2342.19200300.100.4.9 (OBJ_documentSeries) */, + 392 /* 0.9.2342.19200300.100.4.13 (OBJ_Domain) */, + 450 /* 0.9.2342.19200300.100.4.14 (OBJ_rFC822localPart) */, + 451 /* 0.9.2342.19200300.100.4.15 (OBJ_dNSDomain) */, + 452 /* 0.9.2342.19200300.100.4.17 (OBJ_domainRelatedObject) */, + 453 /* 0.9.2342.19200300.100.4.18 (OBJ_friendlyCountry) */, + 454 /* 0.9.2342.19200300.100.4.19 (OBJ_simpleSecurityObject) */, + 455 /* 0.9.2342.19200300.100.4.20 (OBJ_pilotOrganization) */, + 456 /* 0.9.2342.19200300.100.4.21 (OBJ_pilotDSA) */, + 457 /* 0.9.2342.19200300.100.4.22 (OBJ_qualityLabelledData) */, + 189 /* 1.2.840.113549.1.9.16.0 (OBJ_id_smime_mod) */, + 190 /* 1.2.840.113549.1.9.16.1 (OBJ_id_smime_ct) */, + 191 /* 1.2.840.113549.1.9.16.2 (OBJ_id_smime_aa) */, + 192 /* 1.2.840.113549.1.9.16.3 (OBJ_id_smime_alg) */, + 193 /* 1.2.840.113549.1.9.16.4 (OBJ_id_smime_cd) */, + 194 /* 1.2.840.113549.1.9.16.5 (OBJ_id_smime_spq) */, + 195 /* 1.2.840.113549.1.9.16.6 (OBJ_id_smime_cti) */, + 158 /* 1.2.840.113549.1.9.22.1 (OBJ_x509Certificate) */, + 159 /* 1.2.840.113549.1.9.22.2 (OBJ_sdsiCertificate) */, + 160 /* 1.2.840.113549.1.9.23.1 (OBJ_x509Crl) */, + 144 /* 1.2.840.113549.1.12.1.1 (OBJ_pbe_WithSHA1And128BitRC4) */, + 145 /* 1.2.840.113549.1.12.1.2 (OBJ_pbe_WithSHA1And40BitRC4) */, + 146 /* 1.2.840.113549.1.12.1.3 (OBJ_pbe_WithSHA1And3_Key_TripleDES_CBC) */, + 147 /* 1.2.840.113549.1.12.1.4 (OBJ_pbe_WithSHA1And2_Key_TripleDES_CBC) */, + 148 /* 1.2.840.113549.1.12.1.5 (OBJ_pbe_WithSHA1And128BitRC2_CBC) */, + 149 /* 1.2.840.113549.1.12.1.6 (OBJ_pbe_WithSHA1And40BitRC2_CBC) */, + 171 /* 1.3.6.1.4.1.311.2.1.14 (OBJ_ms_ext_req) */, + 134 /* 1.3.6.1.4.1.311.2.1.21 (OBJ_ms_code_ind) */, + 135 /* 1.3.6.1.4.1.311.2.1.22 (OBJ_ms_code_com) */, + 136 /* 1.3.6.1.4.1.311.10.3.1 (OBJ_ms_ctl_sign) */, + 137 /* 1.3.6.1.4.1.311.10.3.3 (OBJ_ms_sgc) */, + 138 /* 1.3.6.1.4.1.311.10.3.4 (OBJ_ms_efs) */, + 648 /* 1.3.6.1.4.1.311.20.2.2 (OBJ_ms_smartcard_login) */, + 649 /* 1.3.6.1.4.1.311.20.2.3 (OBJ_ms_upn) */, + 751 /* 1.2.392.200011.61.1.1.1.2 (OBJ_camellia_128_cbc) */, + 752 /* 1.2.392.200011.61.1.1.1.3 (OBJ_camellia_192_cbc) */, + 753 /* 1.2.392.200011.61.1.1.1.4 (OBJ_camellia_256_cbc) */, + 907 /* 1.2.392.200011.61.1.1.3.2 (OBJ_id_camellia128_wrap) */, + 908 /* 1.2.392.200011.61.1.1.3.3 (OBJ_id_camellia192_wrap) */, + 909 /* 1.2.392.200011.61.1.1.3.4 (OBJ_id_camellia256_wrap) */, + 196 /* 1.2.840.113549.1.9.16.0.1 (OBJ_id_smime_mod_cms) */, + 197 /* 1.2.840.113549.1.9.16.0.2 (OBJ_id_smime_mod_ess) */, + 198 /* 1.2.840.113549.1.9.16.0.3 (OBJ_id_smime_mod_oid) */, + 199 /* 1.2.840.113549.1.9.16.0.4 (OBJ_id_smime_mod_msg_v3) */, + 200 /* 1.2.840.113549.1.9.16.0.5 (OBJ_id_smime_mod_ets_eSignature_88) */, + 201 /* 1.2.840.113549.1.9.16.0.6 (OBJ_id_smime_mod_ets_eSignature_97) */, + 202 /* 1.2.840.113549.1.9.16.0.7 (OBJ_id_smime_mod_ets_eSigPolicy_88) */, + 203 /* 1.2.840.113549.1.9.16.0.8 (OBJ_id_smime_mod_ets_eSigPolicy_97) */, + 204 /* 1.2.840.113549.1.9.16.1.1 (OBJ_id_smime_ct_receipt) */, + 205 /* 1.2.840.113549.1.9.16.1.2 (OBJ_id_smime_ct_authData) */, + 206 /* 1.2.840.113549.1.9.16.1.3 (OBJ_id_smime_ct_publishCert) */, + 207 /* 1.2.840.113549.1.9.16.1.4 (OBJ_id_smime_ct_TSTInfo) */, + 208 /* 1.2.840.113549.1.9.16.1.5 (OBJ_id_smime_ct_TDTInfo) */, + 209 /* 1.2.840.113549.1.9.16.1.6 (OBJ_id_smime_ct_contentInfo) */, + 210 /* 1.2.840.113549.1.9.16.1.7 (OBJ_id_smime_ct_DVCSRequestData) */, + 211 /* 1.2.840.113549.1.9.16.1.8 (OBJ_id_smime_ct_DVCSResponseData) */, + 786 /* 1.2.840.113549.1.9.16.1.9 (OBJ_id_smime_ct_compressedData) */, + 787 /* 1.2.840.113549.1.9.16.1.27 (OBJ_id_ct_asciiTextWithCRLF) */, + 212 /* 1.2.840.113549.1.9.16.2.1 (OBJ_id_smime_aa_receiptRequest) */, + 213 /* 1.2.840.113549.1.9.16.2.2 (OBJ_id_smime_aa_securityLabel) */, + 214 /* 1.2.840.113549.1.9.16.2.3 (OBJ_id_smime_aa_mlExpandHistory) */, + 215 /* 1.2.840.113549.1.9.16.2.4 (OBJ_id_smime_aa_contentHint) */, + 216 /* 1.2.840.113549.1.9.16.2.5 (OBJ_id_smime_aa_msgSigDigest) */, + 217 /* 1.2.840.113549.1.9.16.2.6 (OBJ_id_smime_aa_encapContentType) */, + 218 /* 1.2.840.113549.1.9.16.2.7 (OBJ_id_smime_aa_contentIdentifier) */, + 219 /* 1.2.840.113549.1.9.16.2.8 (OBJ_id_smime_aa_macValue) */, + 220 /* 1.2.840.113549.1.9.16.2.9 (OBJ_id_smime_aa_equivalentLabels) */, + 221 /* 1.2.840.113549.1.9.16.2.10 (OBJ_id_smime_aa_contentReference) */, + 222 /* 1.2.840.113549.1.9.16.2.11 (OBJ_id_smime_aa_encrypKeyPref) */, + 223 /* 1.2.840.113549.1.9.16.2.12 (OBJ_id_smime_aa_signingCertificate) */, + 224 /* 1.2.840.113549.1.9.16.2.13 (OBJ_id_smime_aa_smimeEncryptCerts) */, + 225 /* 1.2.840.113549.1.9.16.2.14 (OBJ_id_smime_aa_timeStampToken) */, + 226 /* 1.2.840.113549.1.9.16.2.15 (OBJ_id_smime_aa_ets_sigPolicyId) */, + 227 /* 1.2.840.113549.1.9.16.2.16 (OBJ_id_smime_aa_ets_commitmentType) */, + 228 /* 1.2.840.113549.1.9.16.2.17 (OBJ_id_smime_aa_ets_signerLocation) */, + 229 /* 1.2.840.113549.1.9.16.2.18 (OBJ_id_smime_aa_ets_signerAttr) */, + 230 /* 1.2.840.113549.1.9.16.2.19 (OBJ_id_smime_aa_ets_otherSigCert) */, + 231 /* 1.2.840.113549.1.9.16.2.20 (OBJ_id_smime_aa_ets_contentTimestamp) */, + 232 /* 1.2.840.113549.1.9.16.2.21 (OBJ_id_smime_aa_ets_CertificateRefs) */, + 233 /* 1.2.840.113549.1.9.16.2.22 (OBJ_id_smime_aa_ets_RevocationRefs) */, + 234 /* 1.2.840.113549.1.9.16.2.23 (OBJ_id_smime_aa_ets_certValues) */, + 235 /* 1.2.840.113549.1.9.16.2.24 (OBJ_id_smime_aa_ets_revocationValues) */, + 236 /* 1.2.840.113549.1.9.16.2.25 (OBJ_id_smime_aa_ets_escTimeStamp) */, + 237 /* 1.2.840.113549.1.9.16.2.26 (OBJ_id_smime_aa_ets_certCRLTimestamp) */, + 238 /* 1.2.840.113549.1.9.16.2.27 (OBJ_id_smime_aa_ets_archiveTimeStamp) */, + 239 /* 1.2.840.113549.1.9.16.2.28 (OBJ_id_smime_aa_signatureType) */, + 240 /* 1.2.840.113549.1.9.16.2.29 (OBJ_id_smime_aa_dvcs_dvc) */, + 241 /* 1.2.840.113549.1.9.16.3.1 (OBJ_id_smime_alg_ESDHwith3DES) */, + 242 /* 1.2.840.113549.1.9.16.3.2 (OBJ_id_smime_alg_ESDHwithRC2) */, + 243 /* 1.2.840.113549.1.9.16.3.3 (OBJ_id_smime_alg_3DESwrap) */, + 244 /* 1.2.840.113549.1.9.16.3.4 (OBJ_id_smime_alg_RC2wrap) */, + 245 /* 1.2.840.113549.1.9.16.3.5 (OBJ_id_smime_alg_ESDH) */, + 246 /* 1.2.840.113549.1.9.16.3.6 (OBJ_id_smime_alg_CMS3DESwrap) */, + 247 /* 1.2.840.113549.1.9.16.3.7 (OBJ_id_smime_alg_CMSRC2wrap) */, + 125 /* 1.2.840.113549.1.9.16.3.8 (OBJ_zlib_compression) */, + 893 /* 1.2.840.113549.1.9.16.3.9 (OBJ_id_alg_PWRI_KEK) */, + 248 /* 1.2.840.113549.1.9.16.4.1 (OBJ_id_smime_cd_ldap) */, + 249 /* 1.2.840.113549.1.9.16.5.1 (OBJ_id_smime_spq_ets_sqt_uri) */, + 250 /* 1.2.840.113549.1.9.16.5.2 (OBJ_id_smime_spq_ets_sqt_unotice) */, + 251 /* 1.2.840.113549.1.9.16.6.1 (OBJ_id_smime_cti_ets_proofOfOrigin) */, + 252 /* 1.2.840.113549.1.9.16.6.2 (OBJ_id_smime_cti_ets_proofOfReceipt) */, + 253 /* 1.2.840.113549.1.9.16.6.3 (OBJ_id_smime_cti_ets_proofOfDelivery) */, + 254 /* 1.2.840.113549.1.9.16.6.4 (OBJ_id_smime_cti_ets_proofOfSender) */, + 255 /* 1.2.840.113549.1.9.16.6.5 (OBJ_id_smime_cti_ets_proofOfApproval) */, + 256 /* 1.2.840.113549.1.9.16.6.6 (OBJ_id_smime_cti_ets_proofOfCreation) */, + 150 /* 1.2.840.113549.1.12.10.1.1 (OBJ_keyBag) */, + 151 /* 1.2.840.113549.1.12.10.1.2 (OBJ_pkcs8ShroudedKeyBag) */, + 152 /* 1.2.840.113549.1.12.10.1.3 (OBJ_certBag) */, + 153 /* 1.2.840.113549.1.12.10.1.4 (OBJ_crlBag) */, + 154 /* 1.2.840.113549.1.12.10.1.5 (OBJ_secretBag) */, + 155 /* 1.2.840.113549.1.12.10.1.6 (OBJ_safeContentsBag) */, + 34 /* 1.3.6.1.4.1.188.7.1.1.2 (OBJ_idea_cbc) */, }; - diff --git a/Sources/BoringSSL/crypto/obj/obj_xref.c b/Sources/BoringSSL/crypto/obj/obj_xref.c index 70babea84..7b4ff12ee 100644 --- a/Sources/BoringSSL/crypto/obj/obj_xref.c +++ b/Sources/BoringSSL/crypto/obj/obj_xref.c @@ -56,69 +56,67 @@ #include -#include - -#include "obj_xref.h" - - -static int nid_triple_cmp_by_sign_id(const void *in_a, const void *in_b) { - const nid_triple *a = in_a; - const nid_triple *b = in_b; - - return a->sign_id - b->sign_id; -} +#include "../internal.h" + + +typedef struct { + int sign_nid; + int digest_nid; + int pkey_nid; +} nid_triple; + +static const nid_triple kTriples[] = { + /* RSA PKCS#1. */ + {NID_md4WithRSAEncryption, NID_md4, NID_rsaEncryption}, + {NID_md5WithRSAEncryption, NID_md5, NID_rsaEncryption}, + {NID_sha1WithRSAEncryption, NID_sha1, NID_rsaEncryption}, + {NID_sha224WithRSAEncryption, NID_sha224, NID_rsaEncryption}, + {NID_sha256WithRSAEncryption, NID_sha256, NID_rsaEncryption}, + {NID_sha384WithRSAEncryption, NID_sha384, NID_rsaEncryption}, + {NID_sha512WithRSAEncryption, NID_sha512, NID_rsaEncryption}, + /* DSA. */ + {NID_dsaWithSHA1, NID_sha1, NID_dsa}, + {NID_dsaWithSHA1_2, NID_sha1, NID_dsa_2}, + {NID_dsa_with_SHA224, NID_sha224, NID_dsa}, + {NID_dsa_with_SHA256, NID_sha256, NID_dsa}, + /* ECDSA. */ + {NID_ecdsa_with_SHA1, NID_sha1, NID_X9_62_id_ecPublicKey}, + {NID_ecdsa_with_SHA224, NID_sha224, NID_X9_62_id_ecPublicKey}, + {NID_ecdsa_with_SHA256, NID_sha256, NID_X9_62_id_ecPublicKey}, + {NID_ecdsa_with_SHA384, NID_sha384, NID_X9_62_id_ecPublicKey}, + {NID_ecdsa_with_SHA512, NID_sha512, NID_X9_62_id_ecPublicKey}, + /* For PSS the digest algorithm can vary and depends on the included + * AlgorithmIdentifier. The digest "undef" indicates the public key method + * should handle this explicitly. */ + {NID_rsassaPss, NID_undef, NID_rsaEncryption}, +}; int OBJ_find_sigid_algs(int sign_nid, int *out_digest_nid, int *out_pkey_nid) { - nid_triple key; - const nid_triple *triple; - - key.sign_id = sign_nid; - - triple = bsearch(&key, sigoid_srt, sizeof(sigoid_srt) / sizeof(nid_triple), - sizeof(nid_triple), nid_triple_cmp_by_sign_id); - - if (triple == NULL) { - return 0; - } - if (out_digest_nid) { - *out_digest_nid = triple->hash_id; - } - if (out_pkey_nid) { - *out_pkey_nid = triple->pkey_id; + for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(kTriples); i++) { + if (kTriples[i].sign_nid == sign_nid) { + if (out_digest_nid != NULL) { + *out_digest_nid = kTriples[i].digest_nid; + } + if (out_pkey_nid != NULL) { + *out_pkey_nid = kTriples[i].pkey_nid; + } + return 1; + } } - return 1; -} - -static int nid_triple_cmp_by_digest_and_hash(const void *in_a, - const void *in_b) { - const nid_triple *a = *((nid_triple**) in_a); - const nid_triple *b = *((nid_triple**) in_b); - - int ret = a->hash_id - b->hash_id; - if (ret) { - return ret; - } - return a->pkey_id - b->pkey_id; + return 0; } int OBJ_find_sigid_by_algs(int *out_sign_nid, int digest_nid, int pkey_nid) { - nid_triple key, *pkey; - const nid_triple **triple; - - key.hash_id = digest_nid; - key.pkey_id = pkey_nid; - pkey = &key; - - triple = bsearch(&pkey, sigoid_srt_xref, - sizeof(sigoid_srt_xref) / sizeof(nid_triple *), - sizeof(nid_triple *), nid_triple_cmp_by_digest_and_hash); - - if (triple == NULL) { - return 0; + for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(kTriples); i++) { + if (kTriples[i].digest_nid == digest_nid && + kTriples[i].pkey_nid == pkey_nid) { + if (out_sign_nid != NULL) { + *out_sign_nid = kTriples[i].sign_nid; + } + return 1; + } } - if (out_sign_nid) { - *out_sign_nid = (*triple)->sign_id; - } - return 1; + + return 0; } diff --git a/Sources/BoringSSL/crypto/obj/obj_xref.h b/Sources/BoringSSL/crypto/obj/obj_xref.h deleted file mode 100644 index b2082f55b..000000000 --- a/Sources/BoringSSL/crypto/obj/obj_xref.h +++ /dev/null @@ -1,96 +0,0 @@ -/* THIS FILE IS GENERATED FROM obj_xref.txt by obj_xref.pl via the - * following command: - * perl obj_xref.pl obj_mac.num obj_xref.txt > obj_xref.h */ - -typedef struct - { - int sign_id; - int hash_id; - int pkey_id; - } nid_triple; - -static const nid_triple sigoid_srt[] = - { - {NID_md2WithRSAEncryption, NID_md2, NID_rsaEncryption}, - {NID_md5WithRSAEncryption, NID_md5, NID_rsaEncryption}, - {NID_shaWithRSAEncryption, NID_sha, NID_rsaEncryption}, - {NID_sha1WithRSAEncryption, NID_sha1, NID_rsaEncryption}, - {NID_dsaWithSHA, NID_sha, NID_dsa}, - {NID_dsaWithSHA1_2, NID_sha1, NID_dsa_2}, - {NID_mdc2WithRSA, NID_mdc2, NID_rsaEncryption}, - {NID_md5WithRSA, NID_md5, NID_rsa}, - {NID_dsaWithSHA1, NID_sha1, NID_dsa}, - {NID_sha1WithRSA, NID_sha1, NID_rsa}, - {NID_ripemd160WithRSA, NID_ripemd160, NID_rsaEncryption}, - {NID_md4WithRSAEncryption, NID_md4, NID_rsaEncryption}, - {NID_ecdsa_with_SHA1, NID_sha1, NID_X9_62_id_ecPublicKey}, - {NID_sha256WithRSAEncryption, NID_sha256, NID_rsaEncryption}, - {NID_sha384WithRSAEncryption, NID_sha384, NID_rsaEncryption}, - {NID_sha512WithRSAEncryption, NID_sha512, NID_rsaEncryption}, - {NID_sha224WithRSAEncryption, NID_sha224, NID_rsaEncryption}, - {NID_ecdsa_with_Recommended, NID_undef, NID_X9_62_id_ecPublicKey}, - {NID_ecdsa_with_Specified, NID_undef, NID_X9_62_id_ecPublicKey}, - {NID_ecdsa_with_SHA224, NID_sha224, NID_X9_62_id_ecPublicKey}, - {NID_ecdsa_with_SHA256, NID_sha256, NID_X9_62_id_ecPublicKey}, - {NID_ecdsa_with_SHA384, NID_sha384, NID_X9_62_id_ecPublicKey}, - {NID_ecdsa_with_SHA512, NID_sha512, NID_X9_62_id_ecPublicKey}, - {NID_dsa_with_SHA224, NID_sha224, NID_dsa}, - {NID_dsa_with_SHA256, NID_sha256, NID_dsa}, - {NID_id_GostR3411_94_with_GostR3410_2001, NID_id_GostR3411_94, NID_id_GostR3410_2001}, - {NID_id_GostR3411_94_with_GostR3410_94, NID_id_GostR3411_94, NID_id_GostR3410_94}, - {NID_id_GostR3411_94_with_GostR3410_94_cc, NID_id_GostR3411_94, NID_id_GostR3410_94_cc}, - {NID_id_GostR3411_94_with_GostR3410_2001_cc, NID_id_GostR3411_94, NID_id_GostR3410_2001_cc}, - {NID_rsassaPss, NID_undef, NID_rsaEncryption}, - {NID_dhSinglePass_stdDH_sha1kdf_scheme, NID_sha1, NID_dh_std_kdf}, - {NID_dhSinglePass_stdDH_sha224kdf_scheme, NID_sha224, NID_dh_std_kdf}, - {NID_dhSinglePass_stdDH_sha256kdf_scheme, NID_sha256, NID_dh_std_kdf}, - {NID_dhSinglePass_stdDH_sha384kdf_scheme, NID_sha384, NID_dh_std_kdf}, - {NID_dhSinglePass_stdDH_sha512kdf_scheme, NID_sha512, NID_dh_std_kdf}, - {NID_dhSinglePass_cofactorDH_sha1kdf_scheme, NID_sha1, NID_dh_cofactor_kdf}, - {NID_dhSinglePass_cofactorDH_sha224kdf_scheme, NID_sha224, NID_dh_cofactor_kdf}, - {NID_dhSinglePass_cofactorDH_sha256kdf_scheme, NID_sha256, NID_dh_cofactor_kdf}, - {NID_dhSinglePass_cofactorDH_sha384kdf_scheme, NID_sha384, NID_dh_cofactor_kdf}, - {NID_dhSinglePass_cofactorDH_sha512kdf_scheme, NID_sha512, NID_dh_cofactor_kdf}, - }; - -static const nid_triple * const sigoid_srt_xref[] = - { - &sigoid_srt[0], - &sigoid_srt[1], - &sigoid_srt[7], - &sigoid_srt[2], - &sigoid_srt[4], - &sigoid_srt[3], - &sigoid_srt[9], - &sigoid_srt[5], - &sigoid_srt[8], - &sigoid_srt[12], - &sigoid_srt[30], - &sigoid_srt[35], - &sigoid_srt[6], - &sigoid_srt[10], - &sigoid_srt[11], - &sigoid_srt[13], - &sigoid_srt[24], - &sigoid_srt[20], - &sigoid_srt[32], - &sigoid_srt[37], - &sigoid_srt[14], - &sigoid_srt[21], - &sigoid_srt[33], - &sigoid_srt[38], - &sigoid_srt[15], - &sigoid_srt[22], - &sigoid_srt[34], - &sigoid_srt[39], - &sigoid_srt[16], - &sigoid_srt[23], - &sigoid_srt[19], - &sigoid_srt[31], - &sigoid_srt[36], - &sigoid_srt[25], - &sigoid_srt[26], - &sigoid_srt[27], - &sigoid_srt[28], - }; - diff --git a/Sources/BoringSSL/crypto/pem/pem_lib.c b/Sources/BoringSSL/crypto/pem/pem_lib.c index deaf26abb..8b7932e46 100644 --- a/Sources/BoringSSL/crypto/pem/pem_lib.c +++ b/Sources/BoringSSL/crypto/pem/pem_lib.c @@ -71,13 +71,13 @@ #include #include -#include "../evp/internal.h" +#include "../internal.h" + #define MIN_LENGTH 4 static int load_iv(char **fromp, unsigned char *to, int num); static int check_pem(const char *nm, const char *name); -int pem_check_suffix(const char *pem_str, const char *suffix); void PEM_proc_type(char *buf, int type) { @@ -144,23 +144,11 @@ static int check_pem(const char *nm, const char *name) /* Make PEM_STRING_EVP_PKEY match any private key */ if (!strcmp(name, PEM_STRING_EVP_PKEY)) { - int slen; - const EVP_PKEY_ASN1_METHOD *ameth; - if (!strcmp(nm, PEM_STRING_PKCS8)) - return 1; - if (!strcmp(nm, PEM_STRING_PKCS8INF)) - return 1; - slen = pem_check_suffix(nm, "PRIVATE KEY"); - if (slen > 0) { - /* - * NB: ENGINE implementations wont contain a deprecated old - * private key decode function so don't look for them. - */ - ameth = EVP_PKEY_asn1_find_str(NULL, nm, slen); - if (ameth && ameth->old_priv_decode) - return 1; - } - return 0; + return !strcmp(nm, PEM_STRING_PKCS8) || + !strcmp(nm, PEM_STRING_PKCS8INF) || + !strcmp(nm, PEM_STRING_RSA) || + !strcmp(nm, PEM_STRING_EC) || + !strcmp(nm, PEM_STRING_DSA); } /* Permit older strings */ @@ -277,7 +265,7 @@ int PEM_ASN1_write_bio(i2d_of_void *i2d, const char *name, BIO *bp, if (enc != NULL) { objstr = OBJ_nid2sn(EVP_CIPHER_nid(enc)); - if (objstr == NULL) { + if (objstr == NULL || EVP_CIPHER_iv_length(enc) == 0) { OPENSSL_PUT_ERROR(PEM, PEM_R_UNSUPPORTED_CIPHER); goto err; } @@ -653,7 +641,7 @@ int PEM_read_bio(BIO *bp, char **name, char **header, unsigned char **data, OPENSSL_PUT_ERROR(PEM, ERR_R_MALLOC_FAILURE); goto err; } - memcpy(nameB->data, &(buf[11]), i - 6); + OPENSSL_memcpy(nameB->data, &(buf[11]), i - 6); nameB->data[i - 6] = '\0'; break; } @@ -684,7 +672,7 @@ int PEM_read_bio(BIO *bp, char **name, char **header, unsigned char **data, nohead = 1; break; } - memcpy(&(headerB->data[hl]), buf, i); + OPENSSL_memcpy(&(headerB->data[hl]), buf, i); headerB->data[hl + i] = '\0'; hl += i; } @@ -716,7 +704,7 @@ int PEM_read_bio(BIO *bp, char **name, char **header, unsigned char **data, OPENSSL_PUT_ERROR(PEM, ERR_R_MALLOC_FAILURE); goto err; } - memcpy(&(dataB->data[bl]), buf, i); + OPENSSL_memcpy(&(dataB->data[bl]), buf, i); dataB->data[bl + i] = '\0'; bl += i; if (end) { @@ -779,28 +767,6 @@ int PEM_read_bio(BIO *bp, char **name, char **header, unsigned char **data, return (0); } -/* - * Check pem string and return prefix length. If for example the pem_str == - * "RSA PRIVATE KEY" and suffix = "PRIVATE KEY" the return value is 3 for the - * string "RSA". - */ - -int pem_check_suffix(const char *pem_str, const char *suffix) -{ - int pem_len = strlen(pem_str); - int suffix_len = strlen(suffix); - const char *p; - if (suffix_len + 1 >= pem_len) - return 0; - p = pem_str + pem_len - suffix_len; - if (strcmp(p, suffix)) - return 0; - p--; - if (*p != ' ') - return 0; - return p - pem_str; -} - int PEM_def_callback(char *buf, int size, int rwflag, void *userdata) { if (!buf || !userdata) { diff --git a/Sources/BoringSSL/crypto/pem/pem_pkey.c b/Sources/BoringSSL/crypto/pem/pem_pkey.c index 4cac7c288..058c03112 100644 --- a/Sources/BoringSSL/crypto/pem/pem_pkey.c +++ b/Sources/BoringSSL/crypto/pem/pem_pkey.c @@ -69,10 +69,6 @@ #include #include -#include "../evp/internal.h" - -int pem_check_suffix(const char *pem_str, const char *suffix); - EVP_PKEY *PEM_read_bio_PrivateKey(BIO *bp, EVP_PKEY **x, pem_password_cb *cb, void *u) { @@ -80,7 +76,6 @@ EVP_PKEY *PEM_read_bio_PrivateKey(BIO *bp, EVP_PKEY **x, pem_password_cb *cb, const unsigned char *p = NULL; unsigned char *data = NULL; long len; - int slen; EVP_PKEY *ret = NULL; if (!PEM_bytes_read_bio(&data, &len, &nm, PEM_STRING_EVP_PKEY, bp, cb, u)) @@ -128,12 +123,15 @@ EVP_PKEY *PEM_read_bio_PrivateKey(BIO *bp, EVP_PKEY **x, pem_password_cb *cb, *x = ret; } PKCS8_PRIV_KEY_INFO_free(p8inf); - } else if ((slen = pem_check_suffix(nm, "PRIVATE KEY")) > 0) { - const EVP_PKEY_ASN1_METHOD *ameth; - ameth = EVP_PKEY_asn1_find_str(NULL, nm, slen); - if (!ameth || !ameth->old_priv_decode) - goto p8err; - ret = d2i_PrivateKey(ameth->pkey_id, x, &p, len); + } else if (strcmp(nm, PEM_STRING_RSA) == 0) { + /* TODO(davidben): d2i_PrivateKey parses PKCS#8 along with the + * standalone format. This and the cases below probably should not + * accept PKCS#8. */ + ret = d2i_PrivateKey(EVP_PKEY_RSA, x, &p, len); + } else if (strcmp(nm, PEM_STRING_EC) == 0) { + ret = d2i_PrivateKey(EVP_PKEY_EC, x, &p, len); + } else if (strcmp(nm, PEM_STRING_DSA) == 0) { + ret = d2i_PrivateKey(EVP_PKEY_DSA, x, &p, len); } p8err: if (ret == NULL) @@ -150,14 +148,7 @@ int PEM_write_bio_PrivateKey(BIO *bp, EVP_PKEY *x, const EVP_CIPHER *enc, unsigned char *kstr, int klen, pem_password_cb *cb, void *u) { - char pem_str[80]; - if (!x->ameth || x->ameth->priv_encode) - return PEM_write_bio_PKCS8PrivateKey(bp, x, enc, - (char *)kstr, klen, cb, u); - - BIO_snprintf(pem_str, 80, "%s PRIVATE KEY", x->ameth->pem_str); - return PEM_ASN1_write_bio((i2d_of_void *)i2d_PrivateKey, - pem_str, bp, x, enc, kstr, klen, cb, u); + return PEM_write_bio_PKCS8PrivateKey(bp, x, enc, (char *)kstr, klen, cb, u); } #ifndef OPENSSL_NO_FP_API diff --git a/Sources/BoringSSL/crypto/pkcs8/internal.h b/Sources/BoringSSL/crypto/pkcs8/internal.h index 7995e7874..9cebe2962 100644 --- a/Sources/BoringSSL/crypto/pkcs8/internal.h +++ b/Sources/BoringSSL/crypto/pkcs8/internal.h @@ -63,17 +63,36 @@ extern "C" { #endif +#define PBE_UCS2_CONVERT_PASSWORD 0x1 + +struct pbe_suite { + int pbe_nid; + const EVP_CIPHER *(*cipher_func)(void); + const EVP_MD *(*md_func)(void); + /* decrypt_init initialize |ctx| for decrypting. The password is specified by + * |pass_raw| and |pass_raw_len|. |param| contains the serialized parameters + * field of the AlgorithmIdentifier. + * + * It returns one on success and zero on error. */ + int (*decrypt_init)(const struct pbe_suite *suite, EVP_CIPHER_CTX *ctx, + const uint8_t *pass_raw, size_t pass_raw_len, CBS *param); + int flags; +}; + #define PKCS5_DEFAULT_ITERATIONS 2048 #define PKCS5_SALT_LEN 8 -/* PKCS5_v2_PBE_keyivgen intializes the supplied |ctx| for PBKDF v2, which must - * be specified by |param|. The password is specified by |pass_raw| and - * |pass_raw_len|. |cipher| and |md| are ignored. - * - * It returns one on success and zero on error. */ -int PKCS5_v2_PBE_keyivgen(EVP_CIPHER_CTX *ctx, const uint8_t *pass_raw, - size_t pass_raw_len, ASN1_TYPE *param, - const EVP_CIPHER *cipher, const EVP_MD *md, int enc); +int PKCS5_pbe2_decrypt_init(const struct pbe_suite *suite, EVP_CIPHER_CTX *ctx, + const uint8_t *pass_raw, size_t pass_raw_len, + CBS *param); + +/* PKCS5_pbe2_encrypt_init configures |ctx| for encrypting with PKCS #5 PBES2, + * as defined in RFC 2998, with the specified parameters. It writes the + * corresponding AlgorithmIdentifier to |out|. */ +int PKCS5_pbe2_encrypt_init(CBB *out, EVP_CIPHER_CTX *ctx, + const EVP_CIPHER *cipher, unsigned iterations, + const uint8_t *pass_raw, size_t pass_raw_len, + const uint8_t *salt, size_t salt_len); #if defined(__cplusplus) diff --git a/Sources/BoringSSL/crypto/pkcs8/p5_pbe.c b/Sources/BoringSSL/crypto/pkcs8/p5_pbe.c deleted file mode 100644 index 653cabf37..000000000 --- a/Sources/BoringSSL/crypto/pkcs8/p5_pbe.c +++ /dev/null @@ -1,150 +0,0 @@ -/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL - * project 1999. - */ -/* ==================================================================== - * Copyright (c) 1999 The OpenSSL Project. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the OpenSSL Project - * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" - * - * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to - * endorse or promote products derived from this software without - * prior written permission. For written permission, please contact - * licensing@OpenSSL.org. - * - * 5. Products derived from this software may not be called "OpenSSL" - * nor may "OpenSSL" appear in their names without prior written - * permission of the OpenSSL Project. - * - * 6. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the OpenSSL Project - * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" - * - * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This product includes cryptographic software written by Eric Young - * (eay@cryptsoft.com). This product includes software written by Tim - * Hudson (tjh@cryptsoft.com). */ - -#include - -#include -#include -#include -#include -#include - -#include "internal.h" - - -/* PKCS#5 password based encryption structure */ - -ASN1_SEQUENCE(PBEPARAM) = { - ASN1_SIMPLE(PBEPARAM, salt, ASN1_OCTET_STRING), - ASN1_SIMPLE(PBEPARAM, iter, ASN1_INTEGER) -} ASN1_SEQUENCE_END(PBEPARAM) - -IMPLEMENT_ASN1_FUNCTIONS(PBEPARAM) - - -/* Set an algorithm identifier for a PKCS#5 PBE algorithm */ - -int PKCS5_pbe_set0_algor(X509_ALGOR *algor, int alg, int iter, - const unsigned char *salt, int saltlen) - { - PBEPARAM *pbe=NULL; - ASN1_STRING *pbe_str=NULL; - unsigned char *sstr; - - pbe = PBEPARAM_new(); - if (!pbe) - { - OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE); - goto err; - } - if(iter <= 0) - iter = PKCS5_DEFAULT_ITERATIONS; - if (!ASN1_INTEGER_set(pbe->iter, iter)) - { - OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE); - goto err; - } - if (!saltlen) - saltlen = PKCS5_SALT_LEN; - if (!ASN1_STRING_set(pbe->salt, NULL, saltlen)) - { - OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE); - goto err; - } - sstr = ASN1_STRING_data(pbe->salt); - if (salt) - memcpy(sstr, salt, saltlen); - else if (!RAND_bytes(sstr, saltlen)) - goto err; - - if(!ASN1_item_pack(pbe, ASN1_ITEM_rptr(PBEPARAM), &pbe_str)) - { - OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE); - goto err; - } - - PBEPARAM_free(pbe); - pbe = NULL; - - if (X509_ALGOR_set0(algor, OBJ_nid2obj(alg), V_ASN1_SEQUENCE, pbe_str)) - return 1; - -err: - if (pbe != NULL) - PBEPARAM_free(pbe); - if (pbe_str != NULL) - ASN1_STRING_free(pbe_str); - return 0; - } - -/* Return an algorithm identifier for a PKCS#5 PBE algorithm */ - -X509_ALGOR *PKCS5_pbe_set(int alg, int iter, - const unsigned char *salt, int saltlen) - { - X509_ALGOR *ret; - ret = X509_ALGOR_new(); - if (!ret) - { - OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE); - return NULL; - } - - if (PKCS5_pbe_set0_algor(ret, alg, iter, salt, saltlen)) - return ret; - - X509_ALGOR_free(ret); - return NULL; - } diff --git a/Sources/BoringSSL/crypto/pkcs8/p5_pbev2.c b/Sources/BoringSSL/crypto/pkcs8/p5_pbev2.c index fec0d86d2..59e206771 100644 --- a/Sources/BoringSSL/crypto/pkcs8/p5_pbev2.c +++ b/Sources/BoringSSL/crypto/pkcs8/p5_pbev2.c @@ -53,388 +53,174 @@ * (eay@cryptsoft.com). This product includes software written by Tim * Hudson (tjh@cryptsoft.com). */ -#include +#include + #include #include -#include +#include #include #include #include -#include +#include #include -#include #include "internal.h" +#include "../internal.h" -/* PKCS#5 v2.0 password based encryption structures */ - -ASN1_SEQUENCE(PBE2PARAM) = { - ASN1_SIMPLE(PBE2PARAM, keyfunc, X509_ALGOR), - ASN1_SIMPLE(PBE2PARAM, encryption, X509_ALGOR) -} ASN1_SEQUENCE_END(PBE2PARAM) - -IMPLEMENT_ASN1_FUNCTIONS(PBE2PARAM) - -ASN1_SEQUENCE(PBKDF2PARAM) = { - ASN1_SIMPLE(PBKDF2PARAM, salt, ASN1_ANY), - ASN1_SIMPLE(PBKDF2PARAM, iter, ASN1_INTEGER), - ASN1_OPT(PBKDF2PARAM, keylength, ASN1_INTEGER), - ASN1_OPT(PBKDF2PARAM, prf, X509_ALGOR) -} ASN1_SEQUENCE_END(PBKDF2PARAM) - -IMPLEMENT_ASN1_FUNCTIONS(PBKDF2PARAM); - -static int ASN1_TYPE_set_octetstring(ASN1_TYPE *a, unsigned char *data, int len) - { - ASN1_STRING *os; - - if ((os=M_ASN1_OCTET_STRING_new()) == NULL) return(0); - if (!M_ASN1_OCTET_STRING_set(os,data,len)) - { - M_ASN1_OCTET_STRING_free(os); - return 0; - } - ASN1_TYPE_set(a,V_ASN1_OCTET_STRING,os); - return(1); - } - -static int param_to_asn1(EVP_CIPHER_CTX *c, ASN1_TYPE *type) - { - unsigned iv_len; - - iv_len = EVP_CIPHER_CTX_iv_length(c); - return ASN1_TYPE_set_octetstring(type, c->oiv, iv_len); - } - -/* Return an algorithm identifier for a PKCS#5 v2.0 PBE algorithm: - * yes I know this is horrible! - * - * Extended version to allow application supplied PRF NID and IV. */ - -X509_ALGOR *PKCS5_pbe2_set_iv(const EVP_CIPHER *cipher, int iter, - unsigned char *salt, int saltlen, - unsigned char *aiv, int prf_nid) -{ - X509_ALGOR *scheme = NULL, *kalg = NULL, *ret = NULL; - int alg_nid, keylen; - EVP_CIPHER_CTX ctx; - unsigned char iv[EVP_MAX_IV_LENGTH]; - PBE2PARAM *pbe2 = NULL; - const ASN1_OBJECT *obj; - - alg_nid = EVP_CIPHER_nid(cipher); - if(alg_nid == NID_undef) { - OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER); - goto err; - } - obj = OBJ_nid2obj(alg_nid); - - if(!(pbe2 = PBE2PARAM_new())) goto merr; - - /* Setup the AlgorithmIdentifier for the encryption scheme */ - scheme = pbe2->encryption; - - scheme->algorithm = (ASN1_OBJECT*) obj; - if(!(scheme->parameter = ASN1_TYPE_new())) goto merr; - - /* Create random IV */ - if (EVP_CIPHER_iv_length(cipher)) - { - if (aiv) - memcpy(iv, aiv, EVP_CIPHER_iv_length(cipher)); - else if (!RAND_bytes(iv, EVP_CIPHER_iv_length(cipher))) - goto err; - } - - EVP_CIPHER_CTX_init(&ctx); - - /* Dummy cipherinit to just setup the IV, and PRF */ - if (!EVP_CipherInit_ex(&ctx, cipher, NULL, NULL, iv, 0)) - goto err; - if(param_to_asn1(&ctx, scheme->parameter) < 0) { - OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_ERROR_SETTING_CIPHER_PARAMS); - EVP_CIPHER_CTX_cleanup(&ctx); - goto err; - } - /* If prf NID unspecified see if cipher has a preference. - * An error is OK here: just means use default PRF. - */ - if ((prf_nid == -1) && - EVP_CIPHER_CTX_ctrl(&ctx, EVP_CTRL_PBE_PRF_NID, 0, &prf_nid) <= 0) - { - ERR_clear_error(); - prf_nid = NID_hmacWithSHA1; - } - EVP_CIPHER_CTX_cleanup(&ctx); - - /* If its RC2 then we'd better setup the key length */ - - if(alg_nid == NID_rc2_cbc) - keylen = EVP_CIPHER_key_length(cipher); - else - keylen = -1; - - /* Setup keyfunc */ - - X509_ALGOR_free(pbe2->keyfunc); - - pbe2->keyfunc = PKCS5_pbkdf2_set(iter, salt, saltlen, prf_nid, keylen); - - if (!pbe2->keyfunc) - goto merr; - - /* Now set up top level AlgorithmIdentifier */ - - if(!(ret = X509_ALGOR_new())) goto merr; - if(!(ret->parameter = ASN1_TYPE_new())) goto merr; - - ret->algorithm = (ASN1_OBJECT*) OBJ_nid2obj(NID_pbes2); - - /* Encode PBE2PARAM into parameter */ - - if(!ASN1_item_pack(pbe2, ASN1_ITEM_rptr(PBE2PARAM), - &ret->parameter->value.sequence)) goto merr; - ret->parameter->type = V_ASN1_SEQUENCE; - - PBE2PARAM_free(pbe2); - pbe2 = NULL; - - return ret; - - merr: - OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE); - - err: - PBE2PARAM_free(pbe2); - /* Note 'scheme' is freed as part of pbe2 */ - X509_ALGOR_free(kalg); - X509_ALGOR_free(ret); - - return NULL; - -} - -X509_ALGOR *PKCS5_pbe2_set(const EVP_CIPHER *cipher, int iter, - unsigned char *salt, int saltlen) - { - return PKCS5_pbe2_set_iv(cipher, iter, salt, saltlen, NULL, -1); - } - -X509_ALGOR *PKCS5_pbkdf2_set(int iter, unsigned char *salt, int saltlen, - int prf_nid, int keylen) - { - X509_ALGOR *keyfunc = NULL; - PBKDF2PARAM *kdf = NULL; - ASN1_OCTET_STRING *osalt = NULL; - - if(!(kdf = PBKDF2PARAM_new())) - goto merr; - if(!(osalt = M_ASN1_OCTET_STRING_new())) - goto merr; - - kdf->salt->value.octet_string = osalt; - kdf->salt->type = V_ASN1_OCTET_STRING; - - if (!saltlen) - saltlen = PKCS5_SALT_LEN; - if (!(osalt->data = OPENSSL_malloc (saltlen))) - goto merr; - - osalt->length = saltlen; - - if (salt) - memcpy (osalt->data, salt, saltlen); - else if (!RAND_bytes(osalt->data, saltlen)) - goto merr; - - if(iter <= 0) - iter = PKCS5_DEFAULT_ITERATIONS; - - if(!ASN1_INTEGER_set(kdf->iter, iter)) - goto merr; - - /* If have a key len set it up */ - - if(keylen > 0) - { - if(!(kdf->keylength = M_ASN1_INTEGER_new())) - goto merr; - if(!ASN1_INTEGER_set (kdf->keylength, keylen)) - goto merr; - } - - /* prf can stay NULL if we are using hmacWithSHA1 */ - if (prf_nid > 0 && prf_nid != NID_hmacWithSHA1) - { - kdf->prf = X509_ALGOR_new(); - if (!kdf->prf) - goto merr; - X509_ALGOR_set0(kdf->prf, OBJ_nid2obj(prf_nid), - V_ASN1_NULL, NULL); - } - - /* Finally setup the keyfunc structure */ - - keyfunc = X509_ALGOR_new(); - if (!keyfunc) - goto merr; - - keyfunc->algorithm = (ASN1_OBJECT*) OBJ_nid2obj(NID_id_pbkdf2); - - /* Encode PBKDF2PARAM into parameter of pbe2 */ - - if(!(keyfunc->parameter = ASN1_TYPE_new())) - goto merr; - - if(!ASN1_item_pack(kdf, ASN1_ITEM_rptr(PBKDF2PARAM), - &keyfunc->parameter->value.sequence)) - goto merr; - keyfunc->parameter->type = V_ASN1_SEQUENCE; - - PBKDF2PARAM_free(kdf); - return keyfunc; - - merr: - OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE); - PBKDF2PARAM_free(kdf); - X509_ALGOR_free(keyfunc); - return NULL; - } - -static int PKCS5_v2_PBKDF2_keyivgen(EVP_CIPHER_CTX *ctx, - const uint8_t *pass_raw, - size_t pass_raw_len, const ASN1_TYPE *param, - const ASN1_TYPE *iv, int enc) { - int rv = 0; - PBKDF2PARAM *pbkdf2param = NULL; - - if (EVP_CIPHER_CTX_cipher(ctx) == NULL) { - OPENSSL_PUT_ERROR(PKCS8, CIPHER_R_NO_CIPHER_SET); - goto err; - } - - /* Decode parameters. */ - if (param == NULL || param->type != V_ASN1_SEQUENCE) { - OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR); - goto err; - } - - const uint8_t *pbuf = param->value.sequence->data; - int plen = param->value.sequence->length; - pbkdf2param = d2i_PBKDF2PARAM(NULL, &pbuf, plen); - if (pbkdf2param == NULL || pbuf != param->value.sequence->data + plen) { - OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR); - goto err; - } - - /* Now check the parameters. */ - uint8_t key[EVP_MAX_KEY_LENGTH]; - const size_t key_len = EVP_CIPHER_CTX_key_length(ctx); - assert(key_len <= sizeof(key)); - - if (pbkdf2param->keylength != NULL && - ASN1_INTEGER_get(pbkdf2param->keylength) != (int) key_len) { - OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_UNSUPPORTED_KEYLENGTH); - goto err; - } - - if (pbkdf2param->prf != NULL && - OBJ_obj2nid(pbkdf2param->prf->algorithm) != NID_hmacWithSHA1) { - OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_UNSUPPORTED_PRF); - goto err; - } - - if (pbkdf2param->salt->type != V_ASN1_OCTET_STRING) { - OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_UNSUPPORTED_SALT_TYPE); - goto err; - } - - if (pbkdf2param->iter->type != V_ASN1_INTEGER) { - OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_ITERATION_COUNT); - goto err; - } - long iterations = ASN1_INTEGER_get(pbkdf2param->iter); - if (iterations <= 0 || - (sizeof(long) > sizeof(unsigned) && iterations > (long)UINT_MAX)) { - OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_ITERATION_COUNT); - goto err; - } - - if (iv->type != V_ASN1_OCTET_STRING || iv->value.octet_string == NULL) { - OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_ERROR_SETTING_CIPHER_PARAMS); - goto err; - } - - const size_t iv_len = EVP_CIPHER_CTX_iv_length(ctx); - if ((size_t) iv->value.octet_string->length != iv_len) { +static int pkcs5_pbe2_cipher_init(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, + unsigned iterations, const uint8_t *pass_raw, + size_t pass_raw_len, const uint8_t *salt, + size_t salt_len, const uint8_t *iv, + size_t iv_len, int enc) { + if (iv_len != EVP_CIPHER_iv_length(cipher)) { OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_ERROR_SETTING_CIPHER_PARAMS); - goto err; + return 0; } - if (!PKCS5_PBKDF2_HMAC_SHA1((const char *) pass_raw, pass_raw_len, - pbkdf2param->salt->value.octet_string->data, - pbkdf2param->salt->value.octet_string->length, - iterations, key_len, key)) { - goto err; - } - - rv = EVP_CipherInit_ex(ctx, NULL /* cipher */, NULL /* engine */, key, - iv->value.octet_string->data, enc); - - err: - PBKDF2PARAM_free(pbkdf2param); - return rv; + uint8_t key[EVP_MAX_KEY_LENGTH]; + int ret = PKCS5_PBKDF2_HMAC_SHA1((const char *)pass_raw, pass_raw_len, salt, + salt_len, iterations, + EVP_CIPHER_key_length(cipher), key) && + EVP_CipherInit_ex(ctx, cipher, NULL /* engine */, key, iv, enc); + OPENSSL_cleanse(key, EVP_MAX_KEY_LENGTH); + return ret; } -int PKCS5_v2_PBE_keyivgen(EVP_CIPHER_CTX *ctx, const uint8_t *pass_raw, - size_t pass_raw_len, ASN1_TYPE *param, - const EVP_CIPHER *unused, const EVP_MD *unused2, - int enc) { - PBE2PARAM *pbe2param = NULL; - int rv = 0; - - if (param == NULL || - param->type != V_ASN1_SEQUENCE || - param->value.sequence == NULL) { - OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR); - goto err; - } +int PKCS5_pbe2_encrypt_init(CBB *out, EVP_CIPHER_CTX *ctx, + const EVP_CIPHER *cipher, unsigned iterations, + const uint8_t *pass_raw, size_t pass_raw_len, + const uint8_t *salt, size_t salt_len) { + int cipher_nid = EVP_CIPHER_nid(cipher); + if (cipher_nid == NID_undef) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER); + return 0; + } + + /* Generate a random IV. */ + uint8_t iv[EVP_MAX_IV_LENGTH]; + if (!RAND_bytes(iv, EVP_CIPHER_iv_length(cipher))) { + return 0; + } + + /* See RFC 2898, appendix A. */ + CBB algorithm, param, kdf, kdf_param, salt_cbb, cipher_cbb, iv_cbb; + if (!CBB_add_asn1(out, &algorithm, CBS_ASN1_SEQUENCE) || + !OBJ_nid2cbb(&algorithm, NID_pbes2) || + !CBB_add_asn1(&algorithm, ¶m, CBS_ASN1_SEQUENCE) || + !CBB_add_asn1(¶m, &kdf, CBS_ASN1_SEQUENCE) || + !OBJ_nid2cbb(&kdf, NID_id_pbkdf2) || + !CBB_add_asn1(&kdf, &kdf_param, CBS_ASN1_SEQUENCE) || + !CBB_add_asn1(&kdf_param, &salt_cbb, CBS_ASN1_OCTETSTRING) || + !CBB_add_bytes(&salt_cbb, salt, salt_len) || + !CBB_add_asn1_uint64(&kdf_param, iterations) || + /* Specify a key length for RC2. */ + (cipher_nid == NID_rc2_cbc && + !CBB_add_asn1_uint64(&kdf_param, EVP_CIPHER_key_length(cipher))) || + /* Omit the PRF. We use the default hmacWithSHA1. */ + !CBB_add_asn1(¶m, &cipher_cbb, CBS_ASN1_SEQUENCE) || + !OBJ_nid2cbb(&cipher_cbb, cipher_nid) || + /* RFC 2898 says RC2-CBC and RC5-CBC-Pad use a SEQUENCE with version and + * IV, but OpenSSL always uses an OCTET STRING IV, so we do the same. */ + !CBB_add_asn1(&cipher_cbb, &iv_cbb, CBS_ASN1_OCTETSTRING) || + !CBB_add_bytes(&iv_cbb, iv, EVP_CIPHER_iv_length(cipher)) || + !CBB_flush(out)) { + return 0; + } + + return pkcs5_pbe2_cipher_init(ctx, cipher, iterations, pass_raw, pass_raw_len, + salt, salt_len, iv, + EVP_CIPHER_iv_length(cipher), 1 /* encrypt */); +} - const uint8_t *pbuf = param->value.sequence->data; - int plen = param->value.sequence->length; - pbe2param = d2i_PBE2PARAM(NULL, &pbuf, plen); - if (pbe2param == NULL || pbuf != param->value.sequence->data + plen) { +int PKCS5_pbe2_decrypt_init(const struct pbe_suite *suite, EVP_CIPHER_CTX *ctx, + const uint8_t *pass_raw, size_t pass_raw_len, + CBS *param) { + CBS pbe_param, kdf, kdf_obj, enc_scheme, enc_obj; + if (!CBS_get_asn1(param, &pbe_param, CBS_ASN1_SEQUENCE) || + CBS_len(param) != 0 || + !CBS_get_asn1(&pbe_param, &kdf, CBS_ASN1_SEQUENCE) || + !CBS_get_asn1(&pbe_param, &enc_scheme, CBS_ASN1_SEQUENCE) || + CBS_len(&pbe_param) != 0 || + !CBS_get_asn1(&kdf, &kdf_obj, CBS_ASN1_OBJECT) || + !CBS_get_asn1(&enc_scheme, &enc_obj, CBS_ASN1_OBJECT)) { OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR); - goto err; + return 0; } /* Check that the key derivation function is PBKDF2. */ - if (OBJ_obj2nid(pbe2param->keyfunc->algorithm) != NID_id_pbkdf2) { + if (OBJ_cbs2nid(&kdf_obj) != NID_id_pbkdf2) { OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_UNSUPPORTED_KEY_DERIVATION_FUNCTION); - goto err; + return 0; } /* See if we recognise the encryption algorithm. */ - const EVP_CIPHER *cipher = - EVP_get_cipherbynid(OBJ_obj2nid(pbe2param->encryption->algorithm)); + const EVP_CIPHER *cipher = EVP_get_cipherbynid(OBJ_cbs2nid(&enc_obj)); if (cipher == NULL) { OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_UNSUPPORTED_CIPHER); - goto err; + return 0; } - /* Fixup cipher based on AlgorithmIdentifier. */ - if (!EVP_CipherInit_ex(ctx, cipher, NULL /* engine */, NULL /* key */, - NULL /* iv */, enc)) { - goto err; + /* Parse the KDF parameters. */ + CBS pbkdf2_params, salt; + uint64_t iterations; + if (!CBS_get_asn1(&kdf, &pbkdf2_params, CBS_ASN1_SEQUENCE) || + CBS_len(&kdf) != 0 || + !CBS_get_asn1(&pbkdf2_params, &salt, CBS_ASN1_OCTETSTRING) || + !CBS_get_asn1_uint64(&pbkdf2_params, &iterations)) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR); + return 0; } - rv = PKCS5_v2_PBKDF2_keyivgen(ctx, pass_raw, pass_raw_len, - pbe2param->keyfunc->parameter, - pbe2param->encryption->parameter, enc); + if (iterations == 0 || iterations > UINT_MAX) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_ITERATION_COUNT); + return 0; + } + + /* The optional keyLength parameter, if present, must match the key length of + * the cipher. */ + if (CBS_peek_asn1_tag(&pbkdf2_params, CBS_ASN1_INTEGER)) { + uint64_t key_len; + if (!CBS_get_asn1_uint64(&pbkdf2_params, &key_len)) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR); + return 0; + } + + if (key_len != EVP_CIPHER_key_length(cipher)) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_UNSUPPORTED_KEYLENGTH); + return 0; + } + } + + if (CBS_len(&pbkdf2_params) != 0) { + CBS prf; + if (!CBS_get_asn1(&pbkdf2_params, &prf, CBS_ASN1_OBJECT) || + CBS_len(&pbkdf2_params) != 0) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR); + return 0; + } + + /* We only support hmacWithSHA1. It is the DEFAULT, so DER requires it be + * omitted, but we match OpenSSL in tolerating it being present. */ + if (OBJ_cbs2nid(&prf) != NID_hmacWithSHA1) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_UNSUPPORTED_PRF); + return 0; + } + } + + /* Parse the encryption scheme parameters. Note OpenSSL does not match the + * specification. Per RFC 2898, this should depend on the encryption scheme. + * In particular, RC2-CBC and RC5-CBC-Pad use a SEQUENCE with version and IV. + * We align with OpenSSL. */ + CBS iv; + if (!CBS_get_asn1(&enc_scheme, &iv, CBS_ASN1_OCTETSTRING) || + CBS_len(&enc_scheme) != 0) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_UNSUPPORTED_PRF); + return 0; + } - err: - PBE2PARAM_free(pbe2param); - return rv; + return pkcs5_pbe2_cipher_init(ctx, cipher, (unsigned)iterations, pass_raw, + pass_raw_len, CBS_data(&salt), CBS_len(&salt), + CBS_data(&iv), CBS_len(&iv), 0 /* decrypt */); } diff --git a/Sources/BoringSSL/crypto/pkcs8/p8_pkey.c b/Sources/BoringSSL/crypto/pkcs8/p8_pkey.c index c69d0face..69a7e293a 100644 --- a/Sources/BoringSSL/crypto/pkcs8/p8_pkey.c +++ b/Sources/BoringSSL/crypto/pkcs8/p8_pkey.c @@ -80,6 +80,6 @@ ASN1_SEQUENCE_cb(PKCS8_PRIV_KEY_INFO, pkey_cb) = { ASN1_SIMPLE(PKCS8_PRIV_KEY_INFO, pkeyalg, X509_ALGOR), ASN1_SIMPLE(PKCS8_PRIV_KEY_INFO, pkey, ASN1_ANY), ASN1_IMP_SET_OF_OPT(PKCS8_PRIV_KEY_INFO, attributes, X509_ATTRIBUTE, 0) -} ASN1_SEQUENCE_END_cb(PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO); +} ASN1_SEQUENCE_END_cb(PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO) -IMPLEMENT_ASN1_FUNCTIONS(PKCS8_PRIV_KEY_INFO); +IMPLEMENT_ASN1_FUNCTIONS(PKCS8_PRIV_KEY_INFO) diff --git a/Sources/BoringSSL/crypto/pkcs8/pkcs8.c b/Sources/BoringSSL/crypto/pkcs8/pkcs8.c index 175a88552..64a2d0212 100644 --- a/Sources/BoringSSL/crypto/pkcs8/pkcs8.c +++ b/Sources/BoringSSL/crypto/pkcs8/pkcs8.c @@ -60,7 +60,6 @@ #include #include -#include #include #include #include @@ -68,9 +67,12 @@ #include #include #include +#include +#include #include #include "internal.h" +#include "../internal.h" #include "../bytestring/internal.h" @@ -80,23 +82,21 @@ static int ascii_to_ucs2(const char *ascii, size_t ascii_len, uint8_t **out, size_t *out_len) { - uint8_t *unitmp; - size_t ulen, i; - - ulen = ascii_len * 2 + 2; - if (ulen < ascii_len) { + size_t ulen = ascii_len * 2 + 2; + if (ascii_len * 2 < ascii_len || ulen < ascii_len * 2) { return 0; } - unitmp = OPENSSL_malloc(ulen); + + uint8_t *unitmp = OPENSSL_malloc(ulen); if (unitmp == NULL) { return 0; } - for (i = 0; i < ulen - 2; i += 2) { + for (size_t i = 0; i < ulen - 2; i += 2) { unitmp[i] = 0; unitmp[i + 1] = ascii[i >> 1]; } - /* Make result double null terminated */ + /* Terminate the result with a UCS-2 NUL. */ unitmp[ulen - 2] = 0; unitmp[ulen - 1] = 0; *out_len = ulen; @@ -106,201 +106,197 @@ static int ascii_to_ucs2(const char *ascii, size_t ascii_len, static int pkcs12_key_gen_raw(const uint8_t *pass_raw, size_t pass_raw_len, const uint8_t *salt, size_t salt_len, - int id, int iterations, + uint8_t id, unsigned iterations, size_t out_len, uint8_t *out, - const EVP_MD *md_type) { - uint8_t *B, *D, *I, *p, *Ai; - int Slen, Plen, Ilen, Ijlen; - int i, j, v; - size_t u; - int ret = 0; - BIGNUM *Ij, *Bpl1; /* These hold Ij and B + 1 */ - EVP_MD_CTX ctx; + const EVP_MD *md) { + /* See https://tools.ietf.org/html/rfc7292#appendix-B. Quoted parts of the + * specification have errata applied and other typos fixed. */ - EVP_MD_CTX_init(&ctx); - v = EVP_MD_block_size(md_type); - u = EVP_MD_size(md_type); - D = OPENSSL_malloc(v); - Ai = OPENSSL_malloc(u); - B = OPENSSL_malloc(v + 1); - Slen = v * ((salt_len + v - 1) / v); - if (pass_raw_len) { - Plen = v * ((pass_raw_len + v - 1) / v); - } else { - Plen = 0; + if (iterations < 1) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_ITERATION_COUNT); + return 0; } - Ilen = Slen + Plen; - I = OPENSSL_malloc(Ilen); - Ij = BN_new(); - Bpl1 = BN_new(); - if (!D || !Ai || !B || !I || !Ij || !Bpl1) { - goto err; + + /* In the spec, |block_size| is called "v", but measured in bits. */ + size_t block_size = EVP_MD_block_size(md); + + /* 1. Construct a string, D (the "diversifier"), by concatenating v/8 copies + * of ID. */ + uint8_t D[EVP_MAX_MD_BLOCK_SIZE]; + OPENSSL_memset(D, id, block_size); + + /* 2. Concatenate copies of the salt together to create a string S of length + * v(ceiling(s/v)) bits (the final copy of the salt may be truncated to + * create S). Note that if the salt is the empty string, then so is S. + * + * 3. Concatenate copies of the password together to create a string P of + * length v(ceiling(p/v)) bits (the final copy of the password may be + * truncated to create P). Note that if the password is the empty string, + * then so is P. + * + * 4. Set I=S||P to be the concatenation of S and P. */ + if (salt_len + block_size - 1 < salt_len || + pass_raw_len + block_size - 1 < pass_raw_len) { + OPENSSL_PUT_ERROR(PKCS8, ERR_R_OVERFLOW); + return 0; } - for (i = 0; i < v; i++) { - D[i] = id; + size_t S_len = block_size * ((salt_len + block_size - 1) / block_size); + size_t P_len = block_size * ((pass_raw_len + block_size - 1) / block_size); + size_t I_len = S_len + P_len; + if (I_len < S_len) { + OPENSSL_PUT_ERROR(PKCS8, ERR_R_OVERFLOW); + return 0; } - p = I; - for (i = 0; i < Slen; i++) { - *p++ = salt[i % salt_len]; + + uint8_t *I = OPENSSL_malloc(I_len); + if (I_len != 0 && I == NULL) { + OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE); + return 0; + } + + for (size_t i = 0; i < S_len; i++) { + I[i] = salt[i % salt_len]; } - for (i = 0; i < Plen; i++) { - *p++ = pass_raw[i % pass_raw_len]; + for (size_t i = 0; i < P_len; i++) { + I[i + S_len] = pass_raw[i % pass_raw_len]; } - for (;;) { - if (!EVP_DigestInit_ex(&ctx, md_type, NULL) || - !EVP_DigestUpdate(&ctx, D, v) || - !EVP_DigestUpdate(&ctx, I, Ilen) || - !EVP_DigestFinal_ex(&ctx, Ai, NULL)) { + + int ret = 0; + EVP_MD_CTX ctx; + EVP_MD_CTX_init(&ctx); + + while (out_len != 0) { + /* A. Set A_i=H^r(D||I). (i.e., the r-th hash of D||I, + * H(H(H(... H(D||I)))) */ + uint8_t A[EVP_MAX_MD_SIZE]; + unsigned A_len; + if (!EVP_DigestInit_ex(&ctx, md, NULL) || + !EVP_DigestUpdate(&ctx, D, block_size) || + !EVP_DigestUpdate(&ctx, I, I_len) || + !EVP_DigestFinal_ex(&ctx, A, &A_len)) { goto err; } - for (j = 1; j < iterations; j++) { - if (!EVP_DigestInit_ex(&ctx, md_type, NULL) || - !EVP_DigestUpdate(&ctx, Ai, u) || - !EVP_DigestFinal_ex(&ctx, Ai, NULL)) { + for (unsigned iter = 1; iter < iterations; iter++) { + if (!EVP_DigestInit_ex(&ctx, md, NULL) || + !EVP_DigestUpdate(&ctx, A, A_len) || + !EVP_DigestFinal_ex(&ctx, A, &A_len)) { goto err; } } - memcpy(out, Ai, out_len < u ? out_len : u); - if (u >= out_len) { - ret = 1; - goto end; - } - out_len -= u; - out += u; - for (j = 0; j < v; j++) { - B[j] = Ai[j % u]; + + size_t todo = out_len < A_len ? out_len : A_len; + OPENSSL_memcpy(out, A, todo); + out += todo; + out_len -= todo; + if (out_len == 0) { + break; } - /* Work out B + 1 first then can use B as tmp space */ - if (!BN_bin2bn(B, v, Bpl1) || - !BN_add_word(Bpl1, 1)) { - goto err; + + /* B. Concatenate copies of A_i to create a string B of length v bits (the + * final copy of A_i may be truncated to create B). */ + uint8_t B[EVP_MAX_MD_BLOCK_SIZE]; + for (size_t i = 0; i < block_size; i++) { + B[i] = A[i % A_len]; } - for (j = 0; j < Ilen; j += v) { - if (!BN_bin2bn(I + j, v, Ij) || - !BN_add(Ij, Ij, Bpl1) || - !BN_bn2bin(Ij, B)) { - goto err; - } - Ijlen = BN_num_bytes(Ij); - /* If more than 2^(v*8) - 1 cut off MSB */ - if (Ijlen > v) { - if (!BN_bn2bin(Ij, B)) { - goto err; - } - memcpy(I + j, B + 1, v); - /* If less than v bytes pad with zeroes */ - } else if (Ijlen < v) { - memset(I + j, 0, v - Ijlen); - if (!BN_bn2bin(Ij, I + j + v - Ijlen)) { - goto err; - } - } else if (!BN_bn2bin(Ij, I + j)) { - goto err; + + /* C. Treating I as a concatenation I_0, I_1, ..., I_(k-1) of v-bit blocks, + * where k=ceiling(s/v)+ceiling(p/v), modify I by setting I_j=(I_j+B+1) mod + * 2^v for each j. */ + assert(I_len % block_size == 0); + for (size_t i = 0; i < I_len; i += block_size) { + unsigned carry = 1; + for (size_t j = block_size - 1; j < block_size; j--) { + carry += I[i + j] + B[j]; + I[i + j] = (uint8_t)carry; + carry >>= 8; } } } -err: - OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE); + ret = 1; -end: - OPENSSL_free(Ai); - OPENSSL_free(B); - OPENSSL_free(D); +err: + OPENSSL_cleanse(I, I_len); OPENSSL_free(I); - BN_free(Ij); - BN_free(Bpl1); EVP_MD_CTX_cleanup(&ctx); - return ret; } -static int pkcs12_pbe_keyivgen(EVP_CIPHER_CTX *ctx, const uint8_t *pass_raw, - size_t pass_raw_len, ASN1_TYPE *param, - const EVP_CIPHER *cipher, const EVP_MD *md, - int is_encrypt) { - PBEPARAM *pbe; - int salt_len, iterations, ret; - uint8_t *salt; - const uint8_t *pbuf; - uint8_t key[EVP_MAX_KEY_LENGTH], iv[EVP_MAX_IV_LENGTH]; - - /* Extract useful info from parameter */ - if (param == NULL || param->type != V_ASN1_SEQUENCE || - param->value.sequence == NULL) { - OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR); - return 0; - } - - pbuf = param->value.sequence->data; - pbe = d2i_PBEPARAM(NULL, &pbuf, param->value.sequence->length); - if (pbe == NULL) { - OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR); - return 0; - } - - if (!pbe->iter) { - iterations = 1; - } else { - iterations = ASN1_INTEGER_get(pbe->iter); - } - salt = pbe->salt->data; - salt_len = pbe->salt->length; - if (!pkcs12_key_gen_raw(pass_raw, pass_raw_len, salt, salt_len, PKCS12_KEY_ID, - iterations, EVP_CIPHER_key_length(cipher), key, md)) { +static int pkcs12_pbe_cipher_init(const struct pbe_suite *suite, + EVP_CIPHER_CTX *ctx, unsigned iterations, + const uint8_t *pass_raw, size_t pass_raw_len, + const uint8_t *salt, size_t salt_len, + int is_encrypt) { + const EVP_CIPHER *cipher = suite->cipher_func(); + const EVP_MD *md = suite->md_func(); + + uint8_t key[EVP_MAX_KEY_LENGTH]; + if (!pkcs12_key_gen_raw(pass_raw, pass_raw_len, salt, + salt_len, PKCS12_KEY_ID, iterations, + EVP_CIPHER_key_length(cipher), key, md)) { OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_KEY_GEN_ERROR); - PBEPARAM_free(pbe); return 0; } - if (!pkcs12_key_gen_raw(pass_raw, pass_raw_len, salt, salt_len, PKCS12_IV_ID, - iterations, EVP_CIPHER_iv_length(cipher), iv, md)) { + + uint8_t iv[EVP_MAX_IV_LENGTH]; + if (!pkcs12_key_gen_raw(pass_raw, pass_raw_len, salt, + salt_len, PKCS12_IV_ID, iterations, + EVP_CIPHER_iv_length(cipher), iv, md)) { OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_KEY_GEN_ERROR); - PBEPARAM_free(pbe); return 0; } - PBEPARAM_free(pbe); - ret = EVP_CipherInit_ex(ctx, cipher, NULL, key, iv, is_encrypt); + + int ret = EVP_CipherInit_ex(ctx, cipher, NULL, key, iv, is_encrypt); OPENSSL_cleanse(key, EVP_MAX_KEY_LENGTH); OPENSSL_cleanse(iv, EVP_MAX_IV_LENGTH); return ret; } -typedef int (*keygen_func)(EVP_CIPHER_CTX *ctx, const uint8_t *pass_raw, - size_t pass_raw_len, ASN1_TYPE *param, - const EVP_CIPHER *cipher, const EVP_MD *md, - int is_encrypt); - -struct pbe_suite { - int pbe_nid; - const EVP_CIPHER* (*cipher_func)(void); - const EVP_MD* (*md_func)(void); - keygen_func keygen; - int flags; -}; +static int pkcs12_pbe_decrypt_init(const struct pbe_suite *suite, + EVP_CIPHER_CTX *ctx, const uint8_t *pass_raw, + size_t pass_raw_len, CBS *param) { + CBS pbe_param, salt; + uint64_t iterations; + if (!CBS_get_asn1(param, &pbe_param, CBS_ASN1_SEQUENCE) || + !CBS_get_asn1(&pbe_param, &salt, CBS_ASN1_OCTETSTRING) || + !CBS_get_asn1_uint64(&pbe_param, &iterations) || + CBS_len(&pbe_param) != 0 || + CBS_len(param) != 0) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR); + return 0; + } + + if (iterations == 0 || iterations > UINT_MAX) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_ITERATION_COUNT); + return 0; + } -#define PBE_UCS2_CONVERT_PASSWORD 0x1 + return pkcs12_pbe_cipher_init(suite, ctx, (unsigned)iterations, pass_raw, + pass_raw_len, CBS_data(&salt), CBS_len(&salt), + 0 /* decrypt */); +} static const struct pbe_suite kBuiltinPBE[] = { { - NID_pbe_WithSHA1And40BitRC2_CBC, EVP_rc2_40_cbc, EVP_sha1, - pkcs12_pbe_keyivgen, PBE_UCS2_CONVERT_PASSWORD + NID_pbe_WithSHA1And40BitRC2_CBC, EVP_rc2_40_cbc, EVP_sha1, + pkcs12_pbe_decrypt_init, PBE_UCS2_CONVERT_PASSWORD, }, { - NID_pbe_WithSHA1And128BitRC4, EVP_rc4, EVP_sha1, pkcs12_pbe_keyivgen, - PBE_UCS2_CONVERT_PASSWORD + NID_pbe_WithSHA1And128BitRC4, EVP_rc4, EVP_sha1, + pkcs12_pbe_decrypt_init, PBE_UCS2_CONVERT_PASSWORD, }, { - NID_pbe_WithSHA1And3_Key_TripleDES_CBC, EVP_des_ede3_cbc, EVP_sha1, - pkcs12_pbe_keyivgen, PBE_UCS2_CONVERT_PASSWORD + NID_pbe_WithSHA1And3_Key_TripleDES_CBC, EVP_des_ede3_cbc, EVP_sha1, + pkcs12_pbe_decrypt_init, PBE_UCS2_CONVERT_PASSWORD, }, { - NID_pbes2, NULL, NULL, PKCS5_v2_PBE_keyivgen, 0 + NID_pbes2, NULL, NULL, PKCS5_pbe2_decrypt_init, 0, }, }; static const struct pbe_suite *get_pbe_suite(int pbe_nid) { unsigned i; - for (i = 0; i < sizeof(kBuiltinPBE) / sizeof(kBuiltinPBE[0]); i++) { + for (i = 0; i < OPENSSL_ARRAY_SIZE(kBuiltinPBE); i++) { if (kBuiltinPBE[i].pbe_nid == pbe_nid) { return &kBuiltinPBE[i]; } @@ -351,126 +347,133 @@ static int pass_to_pass_raw(int pbe_nid, const char *pass, int pass_len, return 1; } -static int pbe_cipher_init(ASN1_OBJECT *pbe_obj, - const uint8_t *pass_raw, size_t pass_raw_len, - ASN1_TYPE *param, - EVP_CIPHER_CTX *ctx, int is_encrypt) { - const EVP_CIPHER *cipher; - const EVP_MD *md; - - const struct pbe_suite *suite = get_pbe_suite(OBJ_obj2nid(pbe_obj)); +static int pkcs12_pbe_encrypt_init(CBB *out, EVP_CIPHER_CTX *ctx, int alg, + unsigned iterations, const uint8_t *pass_raw, + size_t pass_raw_len, const uint8_t *salt, + size_t salt_len) { + const struct pbe_suite *suite = get_pbe_suite(alg); if (suite == NULL) { - char obj_str[80]; OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_UNKNOWN_ALGORITHM); - if (!pbe_obj) { - strncpy(obj_str, "NULL", sizeof(obj_str)); - } else { - i2t_ASN1_OBJECT(obj_str, sizeof(obj_str), pbe_obj); - } - ERR_add_error_data(2, "TYPE=", obj_str); return 0; } - if (suite->cipher_func == NULL) { - cipher = NULL; - } else { - cipher = suite->cipher_func(); - if (!cipher) { - OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_UNKNOWN_CIPHER); - return 0; - } - } - - if (suite->md_func == NULL) { - md = NULL; - } else { - md = suite->md_func(); - if (!md) { - OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_UNKNOWN_DIGEST); - return 0; - } - } - - if (!suite->keygen(ctx, pass_raw, pass_raw_len, param, cipher, md, - is_encrypt)) { - OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_KEYGEN_FAILURE); + /* See RFC 2898, appendix A.3. */ + CBB algorithm, param, salt_cbb; + if (!CBB_add_asn1(out, &algorithm, CBS_ASN1_SEQUENCE) || + !OBJ_nid2cbb(&algorithm, alg) || + !CBB_add_asn1(&algorithm, ¶m, CBS_ASN1_SEQUENCE) || + !CBB_add_asn1(¶m, &salt_cbb, CBS_ASN1_OCTETSTRING) || + !CBB_add_bytes(&salt_cbb, salt, salt_len) || + !CBB_add_asn1_uint64(¶m, iterations) || + !CBB_flush(out)) { return 0; } - return 1; + return pkcs12_pbe_cipher_init(suite, ctx, iterations, pass_raw, pass_raw_len, + salt, salt_len, 1 /* encrypt */); } -static int pbe_crypt(const X509_ALGOR *algor, - const uint8_t *pass_raw, size_t pass_raw_len, - const uint8_t *in, size_t in_len, - uint8_t **out, size_t *out_len, - int is_encrypt) { - uint8_t *buf; - int n, ret = 0; +static int pbe_decrypt(uint8_t **out, size_t *out_len, CBS *algorithm, + const uint8_t *pass_raw, size_t pass_raw_len, + const uint8_t *in, size_t in_len) { + int ret = 0; + uint8_t *buf = NULL;; EVP_CIPHER_CTX ctx; - unsigned block_size; - EVP_CIPHER_CTX_init(&ctx); - if (!pbe_cipher_init(algor->algorithm, pass_raw, pass_raw_len, - algor->parameter, &ctx, is_encrypt)) { - OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_UNKNOWN_CIPHER_ALGORITHM); - return 0; + CBS obj; + if (!CBS_get_asn1(algorithm, &obj, CBS_ASN1_OBJECT)) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR); + goto err; } - block_size = EVP_CIPHER_CTX_block_size(&ctx); - if (in_len + block_size < in_len) { - OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_TOO_LONG); + const struct pbe_suite *suite = get_pbe_suite(OBJ_cbs2nid(&obj)); + if (suite == NULL) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_UNKNOWN_ALGORITHM); + goto err; + } + + if (!suite->decrypt_init(suite, &ctx, pass_raw, pass_raw_len, algorithm)) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_KEYGEN_FAILURE); goto err; } - buf = OPENSSL_malloc(in_len + block_size); + buf = OPENSSL_malloc(in_len); if (buf == NULL) { OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE); goto err; } - if (!EVP_CipherUpdate(&ctx, buf, &n, in, in_len)) { - OPENSSL_free(buf); - OPENSSL_PUT_ERROR(PKCS8, ERR_R_EVP_LIB); + if (in_len > INT_MAX) { + OPENSSL_PUT_ERROR(PKCS8, ERR_R_OVERFLOW); goto err; } - *out_len = n; - if (!EVP_CipherFinal_ex(&ctx, buf + n, &n)) { - OPENSSL_free(buf); - OPENSSL_PUT_ERROR(PKCS8, ERR_R_EVP_LIB); + int n1, n2; + if (!EVP_DecryptUpdate(&ctx, buf, &n1, in, (int)in_len) || + !EVP_DecryptFinal_ex(&ctx, buf + n1, &n2)) { goto err; } - *out_len += n; + *out = buf; + *out_len = n1 + n2; ret = 1; + buf = NULL; err: + OPENSSL_free(buf); EVP_CIPHER_CTX_cleanup(&ctx); return ret; } -static void *pkcs12_item_decrypt_d2i(X509_ALGOR *algor, const ASN1_ITEM *it, - const uint8_t *pass_raw, - size_t pass_raw_len, - ASN1_OCTET_STRING *oct) { - uint8_t *out; - const uint8_t *p; - void *ret; - size_t out_len; +static PKCS8_PRIV_KEY_INFO *pkcs8_decrypt_raw(X509_SIG *pkcs8, + const uint8_t *pass_raw, + size_t pass_raw_len) { + PKCS8_PRIV_KEY_INFO *ret = NULL; + uint8_t *in = NULL, *out = NULL; + size_t out_len = 0; - if (!pbe_crypt(algor, pass_raw, pass_raw_len, oct->data, oct->length, - &out, &out_len, 0 /* decrypt */)) { - OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_CRYPT_ERROR); - return NULL; + /* Convert the legacy ASN.1 object to a byte string. */ + int in_len = i2d_X509_SIG(pkcs8, &in); + if (in_len < 0) { + goto err; + } + + /* See RFC 5208, section 6. */ + CBS cbs, epki, algorithm, ciphertext; + CBS_init(&cbs, in, in_len); + if (!CBS_get_asn1(&cbs, &epki, CBS_ASN1_SEQUENCE) || + !CBS_get_asn1(&epki, &algorithm, CBS_ASN1_SEQUENCE) || + !CBS_get_asn1(&epki, &ciphertext, CBS_ASN1_OCTETSTRING) || + CBS_len(&epki) != 0 || + CBS_len(&cbs) != 0) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR); + goto err; + } + + if (!pbe_decrypt(&out, &out_len, &algorithm, pass_raw, pass_raw_len, + CBS_data(&ciphertext), CBS_len(&ciphertext))) { + goto err; + } + + if (out_len > LONG_MAX) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR); + goto err; } - p = out; - ret = ASN1_item_d2i(NULL, &p, out_len, it); + + /* Convert back to legacy ASN.1 objects. */ + const uint8_t *ptr = out; + ret = d2i_PKCS8_PRIV_KEY_INFO(NULL, &ptr, (long)out_len); OPENSSL_cleanse(out, out_len); - if (!ret) { + if (ret == NULL || ptr != out + out_len) { OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR); + PKCS8_PRIV_KEY_INFO_free(ret); + ret = NULL; } + +err: + OPENSSL_free(in); + OPENSSL_cleanse(out, out_len); OPENSSL_free(out); return ret; } @@ -484,7 +487,7 @@ PKCS8_PRIV_KEY_INFO *PKCS8_decrypt(X509_SIG *pkcs8, const char *pass, return NULL; } - PKCS8_PRIV_KEY_INFO *ret = PKCS8_decrypt_pbe(pkcs8, pass_raw, pass_raw_len); + PKCS8_PRIV_KEY_INFO *ret = pkcs8_decrypt_raw(pkcs8, pass_raw, pass_raw_len); if (pass_raw) { OPENSSL_cleanse(pass_raw, pass_raw_len); @@ -493,101 +496,118 @@ PKCS8_PRIV_KEY_INFO *PKCS8_decrypt(X509_SIG *pkcs8, const char *pass, return ret; } -PKCS8_PRIV_KEY_INFO *PKCS8_decrypt_pbe(X509_SIG *pkcs8, const uint8_t *pass_raw, - size_t pass_raw_len) { - return pkcs12_item_decrypt_d2i(pkcs8->algor, - ASN1_ITEM_rptr(PKCS8_PRIV_KEY_INFO), pass_raw, - pass_raw_len, pkcs8->digest); -} +static X509_SIG *pkcs8_encrypt_raw(int pbe_nid, const EVP_CIPHER *cipher, + const uint8_t *pass_raw, size_t pass_raw_len, + const uint8_t *salt, size_t salt_len, + int iterations, PKCS8_PRIV_KEY_INFO *p8inf) { + X509_SIG *ret = NULL; + uint8_t *plaintext = NULL, *salt_buf = NULL, *der = NULL; + int plaintext_len = -1; + size_t der_len; + CBB cbb; + CBB_zero(&cbb); + EVP_CIPHER_CTX ctx; + EVP_CIPHER_CTX_init(&ctx); -static ASN1_OCTET_STRING *pkcs12_item_i2d_encrypt(X509_ALGOR *algor, - const ASN1_ITEM *it, - const uint8_t *pass_raw, - size_t pass_raw_len, void *obj) { - ASN1_OCTET_STRING *oct; - uint8_t *in = NULL; - int in_len; - size_t crypt_len; - - oct = M_ASN1_OCTET_STRING_new(); - if (oct == NULL) { - OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE); - return NULL; - } - in_len = ASN1_item_i2d(obj, &in, it); - if (!in) { - OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_ENCODE_ERROR); - return NULL; - } - if (!pbe_crypt(algor, pass_raw, pass_raw_len, in, in_len, &oct->data, &crypt_len, - 1 /* encrypt */)) { - OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_ENCRYPT_ERROR); - OPENSSL_free(in); - return NULL; - } - oct->length = crypt_len; - OPENSSL_cleanse(in, in_len); - OPENSSL_free(in); - return oct; -} + /* Generate a random salt if necessary. */ + if (salt == NULL) { + if (salt_len == 0) { + salt_len = PKCS5_SALT_LEN; + } -X509_SIG *PKCS8_encrypt(int pbe_nid, const EVP_CIPHER *cipher, const char *pass, - int pass_len, uint8_t *salt, size_t salt_len, - int iterations, PKCS8_PRIV_KEY_INFO *p8inf) { - uint8_t *pass_raw = NULL; - size_t pass_raw_len = 0; - if (!pass_to_pass_raw(pbe_nid, pass, pass_len, &pass_raw, &pass_raw_len)) { - return NULL; - } + salt_buf = OPENSSL_malloc(salt_len); + if (salt_buf == NULL || + !RAND_bytes(salt_buf, salt_len)) { + goto err; + } - X509_SIG *ret = PKCS8_encrypt_pbe(pbe_nid, cipher, pass_raw, pass_raw_len, - salt, salt_len, iterations, p8inf); + salt = salt_buf; + } - if (pass_raw) { - OPENSSL_cleanse(pass_raw, pass_raw_len); - OPENSSL_free(pass_raw); + if (iterations <= 0) { + iterations = PKCS5_DEFAULT_ITERATIONS; } - return ret; -} -X509_SIG *PKCS8_encrypt_pbe(int pbe_nid, const EVP_CIPHER *cipher, - const uint8_t *pass_raw, size_t pass_raw_len, - uint8_t *salt, size_t salt_len, - int iterations, PKCS8_PRIV_KEY_INFO *p8inf) { - X509_SIG *pkcs8 = NULL; - X509_ALGOR *pbe; + /* Convert the input from the legacy ASN.1 format. */ + plaintext_len = i2d_PKCS8_PRIV_KEY_INFO(p8inf, &plaintext); + if (plaintext_len < 0) { + goto err; + } - pkcs8 = X509_SIG_new(); - if (pkcs8 == NULL) { - OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE); + CBB epki; + if (!CBB_init(&cbb, 128) || + !CBB_add_asn1(&cbb, &epki, CBS_ASN1_SEQUENCE)) { goto err; } + int alg_ok; if (pbe_nid == -1) { - pbe = PKCS5_pbe2_set(cipher, iterations, salt, salt_len); + alg_ok = PKCS5_pbe2_encrypt_init(&epki, &ctx, cipher, (unsigned)iterations, + pass_raw, pass_raw_len, salt, salt_len); } else { - pbe = PKCS5_pbe_set(pbe_nid, iterations, salt, salt_len); + alg_ok = pkcs12_pbe_encrypt_init(&epki, &ctx, pbe_nid, (unsigned)iterations, + pass_raw, pass_raw_len, salt, salt_len); + } + if (!alg_ok) { + goto err; } - if (!pbe) { - OPENSSL_PUT_ERROR(PKCS8, ERR_R_ASN1_LIB); + + size_t max_out = (size_t)plaintext_len + EVP_CIPHER_CTX_block_size(&ctx); + if (max_out < (size_t)plaintext_len) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_TOO_LONG); goto err; } - X509_ALGOR_free(pkcs8->algor); - pkcs8->algor = pbe; - M_ASN1_OCTET_STRING_free(pkcs8->digest); - pkcs8->digest = pkcs12_item_i2d_encrypt( - pbe, ASN1_ITEM_rptr(PKCS8_PRIV_KEY_INFO), pass_raw, pass_raw_len, p8inf); - if (!pkcs8->digest) { - OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_ENCRYPT_ERROR); + CBB ciphertext; + uint8_t *out; + int n1, n2; + if (!CBB_add_asn1(&epki, &ciphertext, CBS_ASN1_OCTETSTRING) || + !CBB_reserve(&ciphertext, &out, max_out) || + !EVP_CipherUpdate(&ctx, out, &n1, plaintext, plaintext_len) || + !EVP_CipherFinal_ex(&ctx, out + n1, &n2) || + !CBB_did_write(&ciphertext, n1 + n2) || + !CBB_finish(&cbb, &der, &der_len)) { goto err; } - return pkcs8; + /* Convert back to legacy ASN.1 objects. */ + const uint8_t *ptr = der; + ret = d2i_X509_SIG(NULL, &ptr, der_len); + if (ret == NULL || ptr != der + der_len) { + OPENSSL_PUT_ERROR(PKCS8, ERR_R_INTERNAL_ERROR); + X509_SIG_free(ret); + ret = NULL; + } err: - X509_SIG_free(pkcs8); - return NULL; + if (plaintext_len > 0) { + OPENSSL_cleanse(plaintext, plaintext_len); + } + OPENSSL_free(plaintext); + OPENSSL_free(salt_buf); + OPENSSL_free(der); + CBB_cleanup(&cbb); + EVP_CIPHER_CTX_cleanup(&ctx); + return ret; +} + +X509_SIG *PKCS8_encrypt(int pbe_nid, const EVP_CIPHER *cipher, const char *pass, + int pass_len, const uint8_t *salt, size_t salt_len, + int iterations, PKCS8_PRIV_KEY_INFO *p8inf) { + uint8_t *pass_raw = NULL; + size_t pass_raw_len = 0; + if (!pass_to_pass_raw(pbe_nid, pass, pass_len, &pass_raw, &pass_raw_len)) { + return NULL; + } + + X509_SIG *ret = pkcs8_encrypt_raw(pbe_nid, cipher, pass_raw, pass_raw_len, + salt, salt_len, iterations, p8inf); + + if (pass_raw) { + OPENSSL_cleanse(pass_raw, pass_raw_len); + OPENSSL_free(pass_raw); + } + return ret; } EVP_PKEY *EVP_PKCS82PKEY(PKCS8_PRIV_KEY_INFO *p8) { @@ -647,32 +667,21 @@ struct pkcs12_context { size_t password_len; }; -static int PKCS12_handle_content_info(CBS *content_info, unsigned depth, - struct pkcs12_context *ctx); - -/* PKCS12_handle_content_infos parses a series of PKCS#7 ContentInfos in a - * SEQUENCE. */ -static int PKCS12_handle_content_infos(CBS *content_infos, - unsigned depth, - struct pkcs12_context *ctx) { +/* PKCS12_handle_sequence parses a BER-encoded SEQUENCE of elements in a PKCS#12 + * structure. */ +static int PKCS12_handle_sequence( + CBS *sequence, struct pkcs12_context *ctx, + int (*handle_element)(CBS *cbs, struct pkcs12_context *ctx)) { uint8_t *der_bytes = NULL; size_t der_len; CBS in; int ret = 0; - /* Generally we only expect depths 0 (the top level, with a - * pkcs7-encryptedData and a pkcs7-data) and depth 1 (the various PKCS#12 - * bags). */ - if (depth > 3) { - OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_PKCS12_TOO_DEEPLY_NESTED); - return 0; - } - /* Although a BER->DER conversion is done at the beginning of |PKCS12_parse|, * the ASN.1 data gets wrapped in OCTETSTRINGs and/or encrypted and the * conversion cannot see through those wrappings. So each time we step * through one we need to convert to DER again. */ - if (!CBS_asn1_ber_to_der(content_infos, &der_bytes, &der_len)) { + if (!CBS_asn1_ber_to_der(sequence, &der_bytes, &der_len)) { OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); return 0; } @@ -680,30 +689,28 @@ static int PKCS12_handle_content_infos(CBS *content_infos, if (der_bytes != NULL) { CBS_init(&in, der_bytes, der_len); } else { - CBS_init(&in, CBS_data(content_infos), CBS_len(content_infos)); + CBS_init(&in, CBS_data(sequence), CBS_len(sequence)); } - if (!CBS_get_asn1(&in, &in, CBS_ASN1_SEQUENCE)) { + CBS child; + if (!CBS_get_asn1(&in, &child, CBS_ASN1_SEQUENCE) || + CBS_len(&in) != 0) { OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); goto err; } - while (CBS_len(&in) > 0) { - CBS content_info; - if (!CBS_get_asn1(&in, &content_info, CBS_ASN1_SEQUENCE)) { + while (CBS_len(&child) > 0) { + CBS element; + if (!CBS_get_asn1(&child, &element, CBS_ASN1_SEQUENCE)) { OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); goto err; } - if (!PKCS12_handle_content_info(&content_info, depth + 1, ctx)) { + if (!handle_element(&element, ctx)) { goto err; } } - /* NSS includes additional data after the SEQUENCE, but it's an (unwrapped) - * copy of the same encrypted private key (with the same IV and - * ciphertext)! */ - ret = 1; err: @@ -711,17 +718,116 @@ static int PKCS12_handle_content_infos(CBS *content_infos, return ret; } +/* PKCS12_handle_safe_bag parses a single SafeBag element in a PKCS#12 + * structure. */ +static int PKCS12_handle_safe_bag(CBS *safe_bag, struct pkcs12_context *ctx) { + CBS bag_id, wrapped_value; + if (!CBS_get_asn1(safe_bag, &bag_id, CBS_ASN1_OBJECT) || + !CBS_get_asn1(safe_bag, &wrapped_value, + CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0) + /* Ignore the bagAttributes field. */) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); + return 0; + } + + int nid = OBJ_cbs2nid(&bag_id); + if (nid == NID_pkcs8ShroudedKeyBag) { + /* See RFC 7292, section 4.2.2. */ + if (*ctx->out_key) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_MULTIPLE_PRIVATE_KEYS_IN_PKCS12); + return 0; + } + + if (CBS_len(&wrapped_value) > LONG_MAX) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); + return 0; + } + + /* |encrypted| isn't actually an X.509 signature, but it has the same + * structure as one and so |X509_SIG| is reused to store it. */ + const uint8_t *inp = CBS_data(&wrapped_value); + X509_SIG *encrypted = + d2i_X509_SIG(NULL, &inp, (long)CBS_len(&wrapped_value)); + if (encrypted == NULL) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); + return 0; + } + if (inp != CBS_data(&wrapped_value) + CBS_len(&wrapped_value)) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); + X509_SIG_free(encrypted); + return 0; + } + + PKCS8_PRIV_KEY_INFO *pki = + pkcs8_decrypt_raw(encrypted, ctx->password, ctx->password_len); + X509_SIG_free(encrypted); + if (pki == NULL) { + return 0; + } + + *ctx->out_key = EVP_PKCS82PKEY(pki); + PKCS8_PRIV_KEY_INFO_free(pki); + return ctx->out_key != NULL; + } + + if (nid == NID_certBag) { + /* See RFC 7292, section 4.2.3. */ + CBS cert_bag, cert_type, wrapped_cert, cert; + if (!CBS_get_asn1(&wrapped_value, &cert_bag, CBS_ASN1_SEQUENCE) || + !CBS_get_asn1(&cert_bag, &cert_type, CBS_ASN1_OBJECT) || + !CBS_get_asn1(&cert_bag, &wrapped_cert, + CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0) || + !CBS_get_asn1(&wrapped_cert, &cert, CBS_ASN1_OCTETSTRING)) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); + return 0; + } + + if (OBJ_cbs2nid(&cert_type) != NID_x509Certificate) { + return 1; + } + + if (CBS_len(&cert) > LONG_MAX) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); + return 0; + } + + const uint8_t *inp = CBS_data(&cert); + X509 *x509 = d2i_X509(NULL, &inp, (long)CBS_len(&cert)); + if (!x509) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); + return 0; + } + + if (inp != CBS_data(&cert) + CBS_len(&cert)) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); + X509_free(x509); + return 0; + } + + if (0 == sk_X509_push(ctx->out_certs, x509)) { + X509_free(x509); + return 0; + } + + return 1; + } + + /* Unknown element type - ignore it. */ + return 1; +} + /* PKCS12_handle_content_info parses a single PKCS#7 ContentInfo element in a * PKCS#12 structure. */ -static int PKCS12_handle_content_info(CBS *content_info, unsigned depth, +static int PKCS12_handle_content_info(CBS *content_info, struct pkcs12_context *ctx) { - CBS content_type, wrapped_contents, contents, content_infos; + CBS content_type, wrapped_contents, contents; int nid, ret = 0; uint8_t *storage = NULL; if (!CBS_get_asn1(content_info, &content_type, CBS_ASN1_OBJECT) || !CBS_get_asn1(content_info, &wrapped_contents, - CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0)) { + CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0) || + CBS_len(content_info) != 0) { OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); goto err; } @@ -734,8 +840,6 @@ static int PKCS12_handle_content_info(CBS *content_info, unsigned depth, * encrypted certificate bag and it's generally encrypted with 40-bit * RC2-CBC. */ CBS version_bytes, eci, contents_type, ai, encrypted_contents; - X509_ALGOR *algor = NULL; - const uint8_t *inp; uint8_t *out; size_t out_len; @@ -747,7 +851,7 @@ static int PKCS12_handle_content_info(CBS *content_info, unsigned depth, !CBS_get_asn1(&eci, &contents_type, CBS_ASN1_OBJECT) || /* AlgorithmIdentifier, see * https://tools.ietf.org/html/rfc5280#section-4.1.1.2 */ - !CBS_get_asn1_element(&eci, &ai, CBS_ASN1_SEQUENCE) || + !CBS_get_asn1(&eci, &ai, CBS_ASN1_SEQUENCE) || !CBS_get_asn1_implicit_string( &eci, &encrypted_contents, &storage, CBS_ASN1_CONTEXT_SPECIFIC | 0, CBS_ASN1_OCTETSTRING)) { @@ -755,122 +859,32 @@ static int PKCS12_handle_content_info(CBS *content_info, unsigned depth, goto err; } - if (OBJ_cbs2nid(&contents_type) != NID_pkcs7_data || - CBS_len(&ai) > LONG_MAX) { - OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); - goto err; - } - - inp = CBS_data(&ai); - algor = d2i_X509_ALGOR(NULL, &inp, (long)CBS_len(&ai)); - if (algor == NULL) { - goto err; - } - if (inp != CBS_data(&ai) + CBS_len(&ai)) { - X509_ALGOR_free(algor); + if (OBJ_cbs2nid(&contents_type) != NID_pkcs7_data) { OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); goto err; } - if (!pbe_crypt(algor, ctx->password, ctx->password_len, - CBS_data(&encrypted_contents), CBS_len(&encrypted_contents), - &out, &out_len, 0 /* decrypt */)) { - X509_ALGOR_free(algor); + if (!pbe_decrypt(&out, &out_len, &ai, ctx->password, ctx->password_len, + CBS_data(&encrypted_contents), + CBS_len(&encrypted_contents))) { goto err; } - X509_ALGOR_free(algor); - CBS_init(&content_infos, out, out_len); - ret = PKCS12_handle_content_infos(&content_infos, depth + 1, ctx); + CBS safe_contents; + CBS_init(&safe_contents, out, out_len); + ret = PKCS12_handle_sequence(&safe_contents, ctx, PKCS12_handle_safe_bag); OPENSSL_free(out); } else if (nid == NID_pkcs7_data) { CBS octet_string_contents; if (!CBS_get_asn1(&wrapped_contents, &octet_string_contents, - CBS_ASN1_OCTETSTRING)) { + CBS_ASN1_OCTETSTRING)) { OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); goto err; } - ret = PKCS12_handle_content_infos(&octet_string_contents, depth + 1, ctx); - } else if (nid == NID_pkcs8ShroudedKeyBag) { - /* See ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-12/pkcs-12v1.pdf, section - * 4.2.2. */ - const uint8_t *inp = CBS_data(&wrapped_contents); - PKCS8_PRIV_KEY_INFO *pki = NULL; - X509_SIG *encrypted = NULL; - - if (*ctx->out_key) { - OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_MULTIPLE_PRIVATE_KEYS_IN_PKCS12); - goto err; - } - - if (CBS_len(&wrapped_contents) > LONG_MAX) { - OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); - goto err; - } - - /* encrypted isn't actually an X.509 signature, but it has the same - * structure as one and so |X509_SIG| is reused to store it. */ - encrypted = d2i_X509_SIG(NULL, &inp, (long)CBS_len(&wrapped_contents)); - if (encrypted == NULL) { - OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); - goto err; - } - if (inp != CBS_data(&wrapped_contents) + CBS_len(&wrapped_contents)) { - OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); - X509_SIG_free(encrypted); - goto err; - } - - pki = PKCS8_decrypt_pbe(encrypted, ctx->password, ctx->password_len); - X509_SIG_free(encrypted); - if (pki == NULL) { - goto err; - } - - *ctx->out_key = EVP_PKCS82PKEY(pki); - PKCS8_PRIV_KEY_INFO_free(pki); - - if (ctx->out_key == NULL) { - goto err; - } - ret = 1; - } else if (nid == NID_certBag) { - CBS cert_bag, cert_type, wrapped_cert, cert; - - if (!CBS_get_asn1(&wrapped_contents, &cert_bag, CBS_ASN1_SEQUENCE) || - !CBS_get_asn1(&cert_bag, &cert_type, CBS_ASN1_OBJECT) || - !CBS_get_asn1(&cert_bag, &wrapped_cert, - CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0) || - !CBS_get_asn1(&wrapped_cert, &cert, CBS_ASN1_OCTETSTRING)) { - OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); - goto err; - } - - if (OBJ_cbs2nid(&cert_type) == NID_x509Certificate) { - if (CBS_len(&cert) > LONG_MAX) { - OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); - goto err; - } - const uint8_t *inp = CBS_data(&cert); - X509 *x509 = d2i_X509(NULL, &inp, (long)CBS_len(&cert)); - if (!x509) { - OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); - goto err; - } - if (inp != CBS_data(&cert) + CBS_len(&cert)) { - OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); - X509_free(x509); - goto err; - } - - if (0 == sk_X509_push(ctx->out_certs, x509)) { - X509_free(x509); - goto err; - } - } - ret = 1; + ret = PKCS12_handle_sequence(&octet_string_contents, ctx, + PKCS12_handle_safe_bag); } else { /* Unknown element type - ignore it. */ ret = 1; @@ -903,7 +917,7 @@ int PKCS12_get_key_and_certs(EVP_PKEY **out_key, STACK_OF(X509) *out_certs, } *out_key = NULL; - memset(&ctx, 0, sizeof(ctx)); + OPENSSL_memset(&ctx, 0, sizeof(ctx)); /* See ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-12/pkcs-12v1.pdf, section * four. */ @@ -987,7 +1001,7 @@ int PKCS12_get_key_and_certs(EVP_PKEY **out_key, STACK_OF(X509) *out_certs, iterations = 1; if (CBS_len(&mac_data) > 0) { if (!CBS_get_asn1_uint64(&mac_data, &iterations) || - iterations > INT_MAX) { + iterations > UINT_MAX) { OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); goto err; } @@ -1018,7 +1032,7 @@ int PKCS12_get_key_and_certs(EVP_PKEY **out_key, STACK_OF(X509) *out_certs, } /* authsafes contains a series of PKCS#7 ContentInfos. */ - if (!PKCS12_handle_content_infos(&authsafes, 0, &ctx)) { + if (!PKCS12_handle_sequence(&authsafes, &ctx, PKCS12_handle_content_info)) { goto err; } @@ -1046,7 +1060,8 @@ struct pkcs12_st { size_t ber_len; }; -PKCS12* d2i_PKCS12(PKCS12 **out_p12, const uint8_t **ber_bytes, size_t ber_len) { +PKCS12 *d2i_PKCS12(PKCS12 **out_p12, const uint8_t **ber_bytes, + size_t ber_len) { PKCS12 *p12; p12 = OPENSSL_malloc(sizeof(PKCS12)); @@ -1060,7 +1075,7 @@ PKCS12* d2i_PKCS12(PKCS12 **out_p12, const uint8_t **ber_bytes, size_t ber_len) return NULL; } - memcpy(p12->ber_bytes, *ber_bytes, ber_len); + OPENSSL_memcpy(p12->ber_bytes, *ber_bytes, ber_len); p12->ber_len = ber_len; *ber_bytes += ber_len; @@ -1185,7 +1200,7 @@ int PKCS12_verify_mac(const PKCS12 *p12, const char *password, } } else if (password_len != -1 && (password[password_len] != 0 || - memchr(password, 0, password_len) != NULL)) { + OPENSSL_memchr(password, 0, password_len) != NULL)) { return 0; } diff --git a/Sources/BoringSSL/crypto/poly1305/internal.h b/Sources/BoringSSL/crypto/poly1305/internal.h new file mode 100644 index 000000000..df6769ea4 --- /dev/null +++ b/Sources/BoringSSL/crypto/poly1305/internal.h @@ -0,0 +1,40 @@ +/* Copyright (c) 2016, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#ifndef OPENSSL_HEADER_POLY1305_INTERNAL_H +#define OPENSSL_HEADER_POLY1305_INTERNAL_H + +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +#if defined(OPENSSL_ARM) && !defined(OPENSSL_NO_ASM) +void CRYPTO_poly1305_init_neon(poly1305_state *state, const uint8_t key[32]); + +void CRYPTO_poly1305_update_neon(poly1305_state *state, const uint8_t *in, + size_t in_len); + +void CRYPTO_poly1305_finish_neon(poly1305_state *state, uint8_t mac[16]); +#endif + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_POLY1305_INTERNAL_H */ diff --git a/Sources/BoringSSL/crypto/poly1305/poly1305.c b/Sources/BoringSSL/crypto/poly1305/poly1305.c index 5a49e2df9..77e8046c5 100644 --- a/Sources/BoringSSL/crypto/poly1305/poly1305.c +++ b/Sources/BoringSSL/crypto/poly1305/poly1305.c @@ -22,40 +22,22 @@ #include +#include "internal.h" +#include "../internal.h" + #if defined(OPENSSL_WINDOWS) || !defined(OPENSSL_X86_64) -#if defined(OPENSSL_X86) || defined(OPENSSL_X86_64) || defined(OPENSSL_ARM) /* We can assume little-endian. */ static uint32_t U8TO32_LE(const uint8_t *m) { uint32_t r; - memcpy(&r, m, sizeof(r)); + OPENSSL_memcpy(&r, m, sizeof(r)); return r; } -static void U32TO8_LE(uint8_t *m, uint32_t v) { memcpy(m, &v, sizeof(v)); } -#else -static uint32_t U8TO32_LE(const uint8_t *m) { - return (uint32_t)m[0] | (uint32_t)m[1] << 8 | (uint32_t)m[2] << 16 | - (uint32_t)m[3] << 24; -} - static void U32TO8_LE(uint8_t *m, uint32_t v) { - m[0] = v; - m[1] = v >> 8; - m[2] = v >> 16; - m[3] = v >> 24; + OPENSSL_memcpy(m, &v, sizeof(v)); } -#endif - -#if defined(OPENSSL_ARM) && !defined(OPENSSL_NO_ASM) -void CRYPTO_poly1305_init_neon(poly1305_state *state, const uint8_t key[32]); - -void CRYPTO_poly1305_update_neon(poly1305_state *state, const uint8_t *in, - size_t in_len); - -void CRYPTO_poly1305_finish_neon(poly1305_state *state, uint8_t mac[16]); -#endif static uint64_t mul32x32_64(uint32_t a, uint32_t b) { return (uint64_t)a * b; } @@ -68,6 +50,11 @@ struct poly1305_state_st { uint8_t key[16]; }; +static inline struct poly1305_state_st *poly1305_aligned_state( + poly1305_state *state) { + return (struct poly1305_state_st *)(((uintptr_t)state + 63) & ~63); +} + /* poly1305_blocks updates |state| given some amount of input data. This * function may only be called with a |len| that is not a multiple of 16 at the * end of the data. Otherwise the input must be buffered into 16 byte blocks. */ @@ -166,11 +153,11 @@ static void poly1305_update(struct poly1305_state_st *state, const uint8_t *in, } void CRYPTO_poly1305_init(poly1305_state *statep, const uint8_t key[32]) { - struct poly1305_state_st *state = (struct poly1305_state_st *)statep; + struct poly1305_state_st *state = poly1305_aligned_state(statep); uint32_t t0, t1, t2, t3; #if defined(OPENSSL_ARM) && !defined(OPENSSL_NO_ASM) - if (CRYPTO_is_NEON_functional()) { + if (CRYPTO_is_NEON_capable()) { CRYPTO_poly1305_init_neon(statep, key); return; } @@ -208,25 +195,25 @@ void CRYPTO_poly1305_init(poly1305_state *statep, const uint8_t key[32]) { state->h4 = 0; state->buf_used = 0; - memcpy(state->key, key + 16, sizeof(state->key)); + OPENSSL_memcpy(state->key, key + 16, sizeof(state->key)); } void CRYPTO_poly1305_update(poly1305_state *statep, const uint8_t *in, size_t in_len) { unsigned int i; - struct poly1305_state_st *state = (struct poly1305_state_st *)statep; + struct poly1305_state_st *state = poly1305_aligned_state(statep); #if defined(OPENSSL_ARM) && !defined(OPENSSL_NO_ASM) - if (CRYPTO_is_NEON_functional()) { + if (CRYPTO_is_NEON_capable()) { CRYPTO_poly1305_update_neon(statep, in, in_len); return; } #endif if (state->buf_used) { - unsigned int todo = 16 - state->buf_used; + unsigned todo = 16 - state->buf_used; if (todo > in_len) { - todo = in_len; + todo = (unsigned)in_len; } for (i = 0; i < todo; i++) { state->buf[state->buf_used + i] = in[i]; @@ -252,18 +239,18 @@ void CRYPTO_poly1305_update(poly1305_state *statep, const uint8_t *in, for (i = 0; i < in_len; i++) { state->buf[i] = in[i]; } - state->buf_used = in_len; + state->buf_used = (unsigned)in_len; } } void CRYPTO_poly1305_finish(poly1305_state *statep, uint8_t mac[16]) { - struct poly1305_state_st *state = (struct poly1305_state_st *)statep; + struct poly1305_state_st *state = poly1305_aligned_state(statep); uint64_t f0, f1, f2, f3; uint32_t g0, g1, g2, g3, g4; uint32_t b, nb; #if defined(OPENSSL_ARM) && !defined(OPENSSL_NO_ASM) - if (CRYPTO_is_NEON_functional()) { + if (CRYPTO_is_NEON_capable()) { CRYPTO_poly1305_finish_neon(statep, mac); return; } diff --git a/Sources/BoringSSL/crypto/poly1305/poly1305_arm.c b/Sources/BoringSSL/crypto/poly1305/poly1305_arm.c index 82876e18c..444413b8b 100644 --- a/Sources/BoringSSL/crypto/poly1305/poly1305_arm.c +++ b/Sources/BoringSSL/crypto/poly1305/poly1305_arm.c @@ -22,6 +22,7 @@ #include #include "../internal.h" +#include "internal.h" typedef struct { @@ -128,7 +129,7 @@ static void fe1305x2_tobytearray(uint8_t *r, fe1305x2 *x) { * fe1305x2_frombytearray. */ static uint32_t load32(uint8_t *t) { uint32_t tmp; - memcpy(&tmp, t, sizeof(tmp)); + OPENSSL_memcpy(&tmp, t, sizeof(tmp)); return tmp; } @@ -202,7 +203,7 @@ void CRYPTO_poly1305_init_neon(poly1305_state *state, const uint8_t key[32]) { addmulmod(precomp, r, r, &zero); /* precompute r^2 */ addmulmod(precomp + 1, precomp, precomp, &zero); /* precompute r^4 */ - memcpy(st->key, key + 16, 16); + OPENSSL_memcpy(st->key, key + 16, 16); st->buf_used = 0; } diff --git a/Sources/BoringSSL/crypto/poly1305/poly1305_vec.c b/Sources/BoringSSL/crypto/poly1305/poly1305_vec.c index 59aab1997..3045a2f1b 100644 --- a/Sources/BoringSSL/crypto/poly1305/poly1305_vec.c +++ b/Sources/BoringSSL/crypto/poly1305/poly1305_vec.c @@ -701,9 +701,9 @@ static size_t poly1305_combine(poly1305_state_internal *st, const uint8_t *m, t0 &= 0x3ffffff; t1 = t1 + c; - st->HH[0] = ((t0) | (t1 << 26)) & 0xfffffffffffull; - st->HH[1] = ((t1 >> 18) | (t2 << 8) | (t3 << 34)) & 0xfffffffffffull; - st->HH[2] = ((t3 >> 10) | (t4 << 16)) & 0x3ffffffffffull; + st->HH[0] = ((t0) | (t1 << 26)) & UINT64_C(0xfffffffffff); + st->HH[1] = ((t1 >> 18) | (t2 << 8) | (t3 << 34)) & UINT64_C(0xfffffffffff); + st->HH[2] = ((t3 >> 10) | (t4 << 16)) & UINT64_C(0x3ffffffffff); return consumed; } diff --git a/Sources/BoringSSL/crypto/pool/internal.h b/Sources/BoringSSL/crypto/pool/internal.h new file mode 100644 index 000000000..3ec2ec2eb --- /dev/null +++ b/Sources/BoringSSL/crypto/pool/internal.h @@ -0,0 +1,45 @@ +/* Copyright (c) 2016, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#ifndef OPENSSL_HEADER_POOL_INTERNAL_H +#define OPENSSL_HEADER_POOL_INTERNAL_H + +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +DECLARE_LHASH_OF(CRYPTO_BUFFER); + +struct crypto_buffer_st { + CRYPTO_BUFFER_POOL *pool; + uint8_t *data; + size_t len; + CRYPTO_refcount_t references; +}; + +struct crypto_buffer_pool_st { + LHASH_OF(CRYPTO_BUFFER) *bufs; + CRYPTO_MUTEX lock; +}; + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_POOL_INTERNAL_H */ diff --git a/Sources/BoringSSL/crypto/pool/pool.c b/Sources/BoringSSL/crypto/pool/pool.c new file mode 100644 index 000000000..44d10af62 --- /dev/null +++ b/Sources/BoringSSL/crypto/pool/pool.c @@ -0,0 +1,200 @@ +/* Copyright (c) 2016, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include + +#include +#include + +#include +#include +#include +#include + +#include "../internal.h" +#include "internal.h" + + +static uint32_t CRYPTO_BUFFER_hash(const CRYPTO_BUFFER *buf) { + return OPENSSL_hash32(buf->data, buf->len); +} + +static int CRYPTO_BUFFER_cmp(const CRYPTO_BUFFER *a, const CRYPTO_BUFFER *b) { + if (a->len != b->len) { + return 1; + } + return OPENSSL_memcmp(a->data, b->data, a->len); +} + +CRYPTO_BUFFER_POOL* CRYPTO_BUFFER_POOL_new(void) { + CRYPTO_BUFFER_POOL *pool = OPENSSL_malloc(sizeof(CRYPTO_BUFFER_POOL)); + if (pool == NULL) { + return NULL; + } + + OPENSSL_memset(pool, 0, sizeof(CRYPTO_BUFFER_POOL)); + pool->bufs = lh_CRYPTO_BUFFER_new(CRYPTO_BUFFER_hash, CRYPTO_BUFFER_cmp); + if (pool->bufs == NULL) { + OPENSSL_free(pool); + return NULL; + } + + CRYPTO_MUTEX_init(&pool->lock); + + return pool; +} + +void CRYPTO_BUFFER_POOL_free(CRYPTO_BUFFER_POOL *pool) { + if (pool == NULL) { + return; + } + +#if !defined(NDEBUG) + CRYPTO_MUTEX_lock_write(&pool->lock); + assert(lh_CRYPTO_BUFFER_num_items(pool->bufs) == 0); + CRYPTO_MUTEX_unlock_write(&pool->lock); +#endif + + lh_CRYPTO_BUFFER_free(pool->bufs); + CRYPTO_MUTEX_cleanup(&pool->lock); + OPENSSL_free(pool); +} + +CRYPTO_BUFFER *CRYPTO_BUFFER_new(const uint8_t *data, size_t len, + CRYPTO_BUFFER_POOL *pool) { + if (pool != NULL) { + CRYPTO_BUFFER tmp; + tmp.data = (uint8_t *) data; + tmp.len = len; + + CRYPTO_MUTEX_lock_read(&pool->lock); + CRYPTO_BUFFER *const duplicate = + lh_CRYPTO_BUFFER_retrieve(pool->bufs, &tmp); + if (duplicate != NULL) { + CRYPTO_refcount_inc(&duplicate->references); + } + CRYPTO_MUTEX_unlock_read(&pool->lock); + + if (duplicate != NULL) { + return duplicate; + } + } + + CRYPTO_BUFFER *const buf = OPENSSL_malloc(sizeof(CRYPTO_BUFFER)); + if (buf == NULL) { + return NULL; + } + OPENSSL_memset(buf, 0, sizeof(CRYPTO_BUFFER)); + + buf->data = BUF_memdup(data, len); + if (len != 0 && buf->data == NULL) { + OPENSSL_free(buf); + return NULL; + } + + buf->len = len; + buf->references = 1; + + if (pool == NULL) { + return buf; + } + + buf->pool = pool; + + CRYPTO_MUTEX_lock_write(&pool->lock); + CRYPTO_BUFFER *duplicate = lh_CRYPTO_BUFFER_retrieve(pool->bufs, buf); + int inserted = 0; + if (duplicate == NULL) { + CRYPTO_BUFFER *old = NULL; + inserted = lh_CRYPTO_BUFFER_insert(pool->bufs, &old, buf); + assert(old == NULL); + } else { + CRYPTO_refcount_inc(&duplicate->references); + } + CRYPTO_MUTEX_unlock_write(&pool->lock); + + if (!inserted) { + /* We raced to insert |buf| into the pool and lost, or else there was an + * error inserting. */ + OPENSSL_free(buf->data); + OPENSSL_free(buf); + return duplicate; + } + + return buf; +} + +CRYPTO_BUFFER* CRYPTO_BUFFER_new_from_CBS(CBS *cbs, CRYPTO_BUFFER_POOL *pool) { + return CRYPTO_BUFFER_new(CBS_data(cbs), CBS_len(cbs), pool); +} + +void CRYPTO_BUFFER_free(CRYPTO_BUFFER *buf) { + if (buf == NULL) { + return; + } + + CRYPTO_BUFFER_POOL *const pool = buf->pool; + if (pool == NULL) { + if (CRYPTO_refcount_dec_and_test_zero(&buf->references)) { + /* If a reference count of zero is observed, there cannot be a reference + * from any pool to this buffer and thus we are able to free this + * buffer. */ + OPENSSL_free(buf->data); + OPENSSL_free(buf); + } + + return; + } + + CRYPTO_MUTEX_lock_write(&pool->lock); + if (!CRYPTO_refcount_dec_and_test_zero(&buf->references)) { + CRYPTO_MUTEX_unlock_write(&buf->pool->lock); + return; + } + + /* We have an exclusive lock on the pool, therefore no concurrent lookups can + * find this buffer and increment the reference count. Thus, if the count is + * zero there are and can never be any more references and thus we can free + * this buffer. */ + void *found = lh_CRYPTO_BUFFER_delete(pool->bufs, buf); + assert(found != NULL); + assert(found == buf); + (void)found; + CRYPTO_MUTEX_unlock_write(&buf->pool->lock); + OPENSSL_free(buf->data); + OPENSSL_free(buf); +} + +int CRYPTO_BUFFER_up_ref(CRYPTO_BUFFER *buf) { + /* This is safe in the case that |buf->pool| is NULL because it's just + * standard reference counting in that case. + * + * This is also safe if |buf->pool| is non-NULL because, if it were racing + * with |CRYPTO_BUFFER_free| then the two callers must have independent + * references already and so the reference count will never hit zero. */ + CRYPTO_refcount_inc(&buf->references); + return 1; +} + +const uint8_t *CRYPTO_BUFFER_data(const CRYPTO_BUFFER *buf) { + return buf->data; +} + +size_t CRYPTO_BUFFER_len(const CRYPTO_BUFFER *buf) { + return buf->len; +} + +void CRYPTO_BUFFER_init_CBS(const CRYPTO_BUFFER *buf, CBS *out) { + CBS_init(out, buf->data, buf->len); +} diff --git a/Sources/BoringSSL/crypto/rand/deterministic.c b/Sources/BoringSSL/crypto/rand/deterministic.c new file mode 100644 index 000000000..d96a50534 --- /dev/null +++ b/Sources/BoringSSL/crypto/rand/deterministic.c @@ -0,0 +1,48 @@ +/* Copyright (c) 2016, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include + +#if defined(BORINGSSL_UNSAFE_DETERMINISTIC_MODE) + +#include + +#include + +#include "internal.h" +#include "../internal.h" + + +/* g_num_calls is the number of calls to |CRYPTO_sysrand| that have occured. + * + * TODO(davidben): This is intentionally not thread-safe. If the fuzzer mode is + * ever used in a multi-threaded program, replace this with a thread-local. (A + * mutex would not be deterministic.) */ +static uint64_t g_num_calls = 0; + +void RAND_reset_for_fuzzing(void) { g_num_calls = 0; } + +void CRYPTO_sysrand(uint8_t *out, size_t requested) { + static const uint8_t kZeroKey[32]; + + uint8_t nonce[12]; + OPENSSL_memset(nonce, 0, sizeof(nonce)); + OPENSSL_memcpy(nonce, &g_num_calls, sizeof(g_num_calls)); + + OPENSSL_memset(out, 0, requested); + CRYPTO_chacha_20(out, out, requested, kZeroKey, nonce, 0); + g_num_calls++; +} + +#endif /* BORINGSSL_UNSAFE_DETERMINISTIC_MODE */ diff --git a/Sources/BoringSSL/crypto/rand/fuchsia.c b/Sources/BoringSSL/crypto/rand/fuchsia.c new file mode 100644 index 000000000..2e138d0ab --- /dev/null +++ b/Sources/BoringSSL/crypto/rand/fuchsia.c @@ -0,0 +1,43 @@ +/* Copyright (c) 2017, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include + +#if defined(OPENSSL_FUCHSIA) && !defined(BORINGSSL_UNSAFE_DETERMINISTIC_MODE) + +#include +#include + +#include + +#include "internal.h" + +void CRYPTO_sysrand(uint8_t *out, size_t requested) { + while (requested > 0) { + size_t output_bytes_this_pass = MX_CPRNG_DRAW_MAX_LEN; + if (requested < output_bytes_this_pass) { + output_bytes_this_pass = requested; + } + size_t bytes_drawn; + mx_status_t status = + mx_cprng_draw(out, output_bytes_this_pass, &bytes_drawn); + if (status != NO_ERROR) { + abort(); + } + requested -= bytes_drawn; + out += bytes_drawn; + } +} + +#endif /* OPENSSL_FUCHSIA && !BORINGSSL_UNSAFE_DETERMINISTIC_MODE */ diff --git a/Sources/BoringSSL/crypto/rand/rand.c b/Sources/BoringSSL/crypto/rand/rand.c index 82087ba26..51da6ba27 100644 --- a/Sources/BoringSSL/crypto/rand/rand.c +++ b/Sources/BoringSSL/crypto/rand/rand.c @@ -72,7 +72,8 @@ static void rand_thread_state_free(void *state) { OPENSSL_free(state); } -#if defined(OPENSSL_X86_64) && !defined(OPENSSL_NO_ASM) +#if defined(OPENSSL_X86_64) && !defined(OPENSSL_NO_ASM) && \ + !defined(BORINGSSL_UNSAFE_DETERMINISTIC_MODE) /* These functions are defined in asm/rdrand-x86_64.pl */ extern int CRYPTO_rdrand(uint8_t out[8]); @@ -100,7 +101,7 @@ static int hwrand(uint8_t *buf, size_t len) { if (!CRYPTO_rdrand(rand_buf)) { return 0; } - memcpy(buf + len_multiple8, rand_buf, len); + OPENSSL_memcpy(buf + len_multiple8, rand_buf, len); } return 1; @@ -137,7 +138,7 @@ int RAND_bytes(uint8_t *buf, size_t len) { return 1; } - memset(state->partial_block, 0, sizeof(state->partial_block)); + OPENSSL_memset(state->partial_block, 0, sizeof(state->partial_block)); state->calls_used = kMaxCallsPerRefresh; } @@ -160,8 +161,8 @@ int RAND_bytes(uint8_t *buf, size_t len) { todo = kMaxBytesPerCall; } uint8_t nonce[12]; - memset(nonce, 0, 4); - memcpy(nonce + 4, &state->calls_used, sizeof(state->calls_used)); + OPENSSL_memset(nonce, 0, 4); + OPENSSL_memcpy(nonce + 4, &state->calls_used, sizeof(state->calls_used)); CRYPTO_chacha_20(buf, buf, todo, state->key, nonce, 0); buf += todo; remaining -= todo; @@ -170,8 +171,8 @@ int RAND_bytes(uint8_t *buf, size_t len) { } else { if (sizeof(state->partial_block) - state->partial_block_used < len) { uint8_t nonce[12]; - memset(nonce, 0, 4); - memcpy(nonce + 4, &state->calls_used, sizeof(state->calls_used)); + OPENSSL_memset(nonce, 0, 4); + OPENSSL_memcpy(nonce + 4, &state->calls_used, sizeof(state->calls_used)); CRYPTO_chacha_20(state->partial_block, state->partial_block, sizeof(state->partial_block), state->key, nonce, 0); state->partial_block_used = 0; @@ -239,3 +240,5 @@ RAND_METHOD *RAND_SSLeay(void) { } void RAND_set_rand_method(const RAND_METHOD *method) {} + +void RAND_cleanup(void) {} diff --git a/Sources/BoringSSL/crypto/rand/urandom.c b/Sources/BoringSSL/crypto/rand/urandom.c index 5bf5c739e..23bdcf487 100644 --- a/Sources/BoringSSL/crypto/rand/urandom.c +++ b/Sources/BoringSSL/crypto/rand/urandom.c @@ -12,16 +12,26 @@ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#if !defined(_GNU_SOURCE) +#define _GNU_SOURCE /* needed for syscall() on Linux. */ +#endif + #include -#if !defined(OPENSSL_WINDOWS) +#if !defined(OPENSSL_WINDOWS) && !defined(OPENSSL_FUCHSIA) && \ + !defined(BORINGSSL_UNSAFE_DETERMINISTIC_MODE) #include #include #include +#include #include #include +#if defined(OPENSSL_LINUX) +#include +#endif + #include #include @@ -29,6 +39,43 @@ #include "../internal.h" +#if defined(OPENSSL_LINUX) + +#if defined(OPENSSL_X86_64) +#define EXPECTED_SYS_getrandom 318 +#elif defined(OPENSSL_X86) +#define EXPECTED_SYS_getrandom 355 +#elif defined(OPENSSL_AARCH64) +#define EXPECTED_SYS_getrandom 278 +#elif defined(OPENSSL_ARM) +#define EXPECTED_SYS_getrandom 384 +#elif defined(OPENSSL_PPC64LE) +#define EXPECTED_SYS_getrandom 359 +#endif + +#if defined(EXPECTED_SYS_getrandom) +#define USE_SYS_getrandom + +#if defined(SYS_getrandom) + +#if SYS_getrandom != EXPECTED_SYS_getrandom +#error "system call number for getrandom is not the expected value" +#endif + +#else /* SYS_getrandom */ + +#define SYS_getrandom EXPECTED_SYS_getrandom + +#endif /* SYS_getrandom */ + +#endif /* EXPECTED_SYS_getrandom */ + +#if !defined(GRND_NONBLOCK) +#define GRND_NONBLOCK 1 +#endif + +#endif /* OPENSSL_LINUX */ + /* This file implements a PRNG by reading from /dev/urandom, optionally with a * buffer, which is unsafe across |fork|. */ @@ -44,12 +91,16 @@ struct rand_buffer { /* requested_lock is used to protect the |*_requested| variables. */ static struct CRYPTO_STATIC_MUTEX requested_lock = CRYPTO_STATIC_MUTEX_INIT; -/* urandom_fd_requested is set by |RAND_set_urandom_fd|. It's protected by +/* The following constants are magic values of |urandom_fd|. */ +static const int kUnset = -2; +static const int kHaveGetrandom = -3; + +/* urandom_fd_requested is set by |RAND_set_urandom_fd|. It's protected by * |requested_lock|. */ -static int urandom_fd_requested = -2; +static int urandom_fd_requested = -2 /* kUnset */; /* urandom_fd is a file descriptor to /dev/urandom. It's protected by |once|. */ -static int urandom_fd = -2; +static int urandom_fd = -2 /* kUnset */; /* urandom_buffering_requested is set by |RAND_enable_fork_unsafe_buffering|. * It's protected by |requested_lock|. */ @@ -69,9 +120,34 @@ static void init_once(void) { CRYPTO_STATIC_MUTEX_lock_read(&requested_lock); urandom_buffering = urandom_buffering_requested; int fd = urandom_fd_requested; - CRYPTO_STATIC_MUTEX_unlock(&requested_lock); + CRYPTO_STATIC_MUTEX_unlock_read(&requested_lock); - if (fd == -2) { +#if defined(USE_SYS_getrandom) + uint8_t dummy; + long getrandom_ret = + syscall(SYS_getrandom, &dummy, sizeof(dummy), GRND_NONBLOCK); + + if (getrandom_ret == 1) { + urandom_fd = kHaveGetrandom; + return; + } else if (getrandom_ret == -1 && errno == EAGAIN) { + fprintf(stderr, + "getrandom indicates that the entropy pool has not been " + "initialized. Rather than continue with poor entropy, this process " + "will block until entropy is available.\n"); + do { + getrandom_ret = + syscall(SYS_getrandom, &dummy, sizeof(dummy), 0 /* no flags */); + } while (getrandom_ret == -1 && errno == EINTR); + + if (getrandom_ret == 1) { + urandom_fd = kHaveGetrandom; + return; + } + } +#endif /* USE_SYS_getrandom */ + + if (fd == kUnset) { do { fd = open("/dev/urandom", O_RDONLY); } while (fd == -1 && errno == EINTR); @@ -96,8 +172,6 @@ static void init_once(void) { urandom_fd = fd; } -void RAND_cleanup(void) {} - void RAND_set_urandom_fd(int fd) { fd = dup(fd); if (fd < 0) { @@ -106,10 +180,12 @@ void RAND_set_urandom_fd(int fd) { CRYPTO_STATIC_MUTEX_lock_write(&requested_lock); urandom_fd_requested = fd; - CRYPTO_STATIC_MUTEX_unlock(&requested_lock); + CRYPTO_STATIC_MUTEX_unlock_write(&requested_lock); CRYPTO_once(&once, init_once); - if (urandom_fd != fd) { + if (urandom_fd == kHaveGetrandom) { + close(fd); + } else if (urandom_fd != fd) { abort(); // Already initialized. } } @@ -121,17 +197,25 @@ void RAND_enable_fork_unsafe_buffering(int fd) { abort(); } } else { - fd = -2; + fd = kUnset; } CRYPTO_STATIC_MUTEX_lock_write(&requested_lock); urandom_buffering_requested = 1; urandom_fd_requested = fd; - CRYPTO_STATIC_MUTEX_unlock(&requested_lock); + CRYPTO_STATIC_MUTEX_unlock_write(&requested_lock); CRYPTO_once(&once, init_once); - if (urandom_buffering != 1 || (fd >= 0 && urandom_fd != fd)) { - abort(); // Already initialized. + if (urandom_buffering != 1) { + abort(); // Already initialized + } + + if (fd >= 0) { + if (urandom_fd == kHaveGetrandom) { + close(fd); + } else if (urandom_fd != fd) { + abort(); // Already initialized. + } } } @@ -146,7 +230,7 @@ static struct rand_buffer *get_thread_local_buffer(void) { if (buf == NULL) { return NULL; } - buf->used = BUF_SIZE; /* To trigger a |read_full| on first use. */ + buf->used = BUF_SIZE; /* To trigger a |fill_with_entropy| on first use. */ if (!CRYPTO_set_thread_local(OPENSSL_THREAD_LOCAL_URANDOM_BUF, buf, OPENSSL_free)) { OPENSSL_free(buf); @@ -156,15 +240,42 @@ static struct rand_buffer *get_thread_local_buffer(void) { return buf; } -/* read_full reads exactly |len| bytes from |fd| into |out| and returns 1. In - * the case of an error it returns 0. */ -static char read_full(int fd, uint8_t *out, size_t len) { - ssize_t r; +#if defined(USE_SYS_getrandom) && defined(__has_feature) +#if __has_feature(memory_sanitizer) +void __msan_unpoison(void *, size_t); +#endif +#endif +/* fill_with_entropy writes |len| bytes of entropy into |out|. It returns one + * on success and zero on error. */ +static char fill_with_entropy(uint8_t *out, size_t len) { while (len > 0) { - do { - r = read(fd, out, len); - } while (r == -1 && errno == EINTR); + ssize_t r; + + if (urandom_fd == kHaveGetrandom) { +#if defined(USE_SYS_getrandom) + do { + r = syscall(SYS_getrandom, out, len, 0 /* no flags */); + } while (r == -1 && errno == EINTR); + +#if defined(__has_feature) +#if __has_feature(memory_sanitizer) + if (r > 0) { + /* MSAN doesn't recognise |syscall| and thus doesn't notice that we + * have initialised the output buffer. */ + __msan_unpoison(out, r); + } +#endif /* memory_sanitizer */ +#endif /*__has_feature */ + +#else /* USE_SYS_getrandom */ + abort(); +#endif + } else { + do { + r = read(urandom_fd, out, len); + } while (r == -1 && errno == EINTR); + } if (r <= 0) { return 0; @@ -183,12 +294,12 @@ static void read_from_buffer(struct rand_buffer *buf, size_t remaining = BUF_SIZE - buf->used; while (requested > remaining) { - memcpy(out, &buf->rand[buf->used], remaining); + OPENSSL_memcpy(out, &buf->rand[buf->used], remaining); buf->used += remaining; out += remaining; requested -= remaining; - if (!read_full(urandom_fd, buf->rand, BUF_SIZE)) { + if (!fill_with_entropy(buf->rand, BUF_SIZE)) { abort(); return; } @@ -196,7 +307,7 @@ static void read_from_buffer(struct rand_buffer *buf, remaining = BUF_SIZE; } - memcpy(out, &buf->rand[buf->used], requested); + OPENSSL_memcpy(out, &buf->rand[buf->used], requested); buf->used += requested; } @@ -215,9 +326,10 @@ void CRYPTO_sysrand(uint8_t *out, size_t requested) { } } - if (!read_full(urandom_fd, out, requested)) { + if (!fill_with_entropy(out, requested)) { abort(); } } -#endif /* !OPENSSL_WINDOWS */ +#endif /* !OPENSSL_WINDOWS && !defined(OPENSSL_FUCHSIA) && \ + !BORINGSSL_UNSAFE_DETERMINISTIC_MODE */ diff --git a/Sources/BoringSSL/crypto/rand/windows.c b/Sources/BoringSSL/crypto/rand/windows.c index 1a0cb8b09..f47182d90 100644 --- a/Sources/BoringSSL/crypto/rand/windows.c +++ b/Sources/BoringSSL/crypto/rand/windows.c @@ -14,12 +14,12 @@ #include -#if defined(OPENSSL_WINDOWS) +#if defined(OPENSSL_WINDOWS) && !defined(BORINGSSL_UNSAFE_DETERMINISTIC_MODE) #include #include -#pragma warning(push, 3) +OPENSSL_MSVC_PRAGMA(warning(push, 3)) #include @@ -30,19 +30,16 @@ #include #undef SystemFunction036 -#pragma warning(pop) +OPENSSL_MSVC_PRAGMA(warning(pop)) #include "internal.h" -void RAND_cleanup(void) { -} - void CRYPTO_sysrand(uint8_t *out, size_t requested) { while (requested > 0) { ULONG output_bytes_this_pass = ULONG_MAX; if (requested < output_bytes_this_pass) { - output_bytes_this_pass = requested; + output_bytes_this_pass = (ULONG)requested; } if (RtlGenRandom(out, output_bytes_this_pass) == FALSE) { abort(); @@ -53,4 +50,4 @@ void CRYPTO_sysrand(uint8_t *out, size_t requested) { return; } -#endif /* OPENSSL_WINDOWS */ +#endif /* OPENSSL_WINDOWS && !BORINGSSL_UNSAFE_DETERMINISTIC_MODE */ diff --git a/Sources/BoringSSL/crypto/rc4/rc4.c b/Sources/BoringSSL/crypto/rc4/rc4.c index b8e1d9f0d..a27a657f2 100644 --- a/Sources/BoringSSL/crypto/rc4/rc4.c +++ b/Sources/BoringSSL/crypto/rc4/rc4.c @@ -56,228 +56,43 @@ #include -#if defined(OPENSSL_NO_ASM) || \ - (!defined(OPENSSL_X86_64) && !defined(OPENSSL_X86)) - -#if defined(OPENSSL_64_BIT) -#define RC4_CHUNK uint64_t -#elif defined(OPENSSL_32_BIT) -#define RC4_CHUNK uint32_t -#else -#error "Unknown word size" -#endif - - -/* RC4 as implemented from a posting from - * Newsgroups: sci.crypt - * From: sterndark@netcom.com (David Sterndark) - * Subject: RC4 Algorithm revealed. - * Message-ID: - * Date: Wed, 14 Sep 1994 06:35:31 GMT */ void RC4(RC4_KEY *key, size_t len, const uint8_t *in, uint8_t *out) { - uint32_t *d; - uint32_t x, y, tx, ty; - size_t i; - - x = key->x; - y = key->y; - d = key->data; - -#define RC4_STEP \ - (x = (x + 1) & 0xff, tx = d[x], y = (tx + y) & 0xff, ty = d[y], d[y] = tx, \ - d[x] = ty, (RC4_CHUNK)d[(tx + ty) & 0xff]) - - if ((((size_t)in & (sizeof(RC4_CHUNK) - 1)) | - ((size_t)out & (sizeof(RC4_CHUNK) - 1))) == 0) { - RC4_CHUNK ichunk, otp; - const union { - long one; - char little; - } is_endian = {1}; - - /* I reckon we can afford to implement both endian - * cases and to decide which way to take at run-time - * because the machine code appears to be very compact - * and redundant 1-2KB is perfectly tolerable (i.e. - * in case the compiler fails to eliminate it:-). By - * suggestion from Terrel Larson - * who also stands for the is_endian union:-) - * - * Special notes. - * - * - is_endian is declared automatic as doing otherwise - * (declaring static) prevents gcc from eliminating - * the redundant code; - * - compilers (those I've tried) don't seem to have - * problems eliminating either the operators guarded - * by "if (sizeof(RC4_CHUNK)==8)" or the condition - * expressions themselves so I've got 'em to replace - * corresponding #ifdefs from the previous version; - * - I chose to let the redundant switch cases when - * sizeof(RC4_CHUNK)!=8 be (were also #ifdefed - * before); - * - in case you wonder "&(sizeof(RC4_CHUNK)*8-1)" in - * [LB]ESHFT guards against "shift is out of range" - * warnings when sizeof(RC4_CHUNK)!=8 - * - * */ - if (!is_endian.little) { /* BIG-ENDIAN CASE */ -#define BESHFT(c) \ - (((sizeof(RC4_CHUNK) - (c) - 1) * 8) & (sizeof(RC4_CHUNK) * 8 - 1)) - for (; len & (0 - sizeof(RC4_CHUNK)); len -= sizeof(RC4_CHUNK)) { - ichunk = *(RC4_CHUNK *)in; - otp = RC4_STEP << BESHFT(0); - otp |= RC4_STEP << BESHFT(1); - otp |= RC4_STEP << BESHFT(2); - otp |= RC4_STEP << BESHFT(3); -#if defined(OPENSSL_64_BIT) - otp |= RC4_STEP << BESHFT(4); - otp |= RC4_STEP << BESHFT(5); - otp |= RC4_STEP << BESHFT(6); - otp |= RC4_STEP << BESHFT(7); -#endif - *(RC4_CHUNK *)out = otp ^ ichunk; - in += sizeof(RC4_CHUNK); - out += sizeof(RC4_CHUNK); - } - } else { /* LITTLE-ENDIAN CASE */ -#define LESHFT(c) (((c) * 8) & (sizeof(RC4_CHUNK) * 8 - 1)) - for (; len & (0 - sizeof(RC4_CHUNK)); len -= sizeof(RC4_CHUNK)) { - ichunk = *(RC4_CHUNK *)in; - otp = RC4_STEP; - otp |= RC4_STEP << 8; - otp |= RC4_STEP << 16; - otp |= RC4_STEP << 24; -#if defined(OPENSSL_64_BIT) - otp |= RC4_STEP << LESHFT(4); - otp |= RC4_STEP << LESHFT(5); - otp |= RC4_STEP << LESHFT(6); - otp |= RC4_STEP << LESHFT(7); -#endif - *(RC4_CHUNK *)out = otp ^ ichunk; - in += sizeof(RC4_CHUNK); - out += sizeof(RC4_CHUNK); - } - } + uint32_t x = key->x; + uint32_t y = key->y; + uint32_t *d = key->data; + + for (size_t i = 0; i < len; i++) { + x = (x + 1) & 0xff; + uint32_t tx = d[x]; + y = (tx + y) & 0xff; + uint32_t ty = d[y]; + d[x] = ty; + d[y] = tx; + out[i] = d[(tx + ty) & 0xff] ^ in[i]; } -#define LOOP(in, out) \ - x = ((x + 1) & 0xff); \ - tx = d[x]; \ - y = (tx + y) & 0xff; \ - d[x] = ty = d[y]; \ - d[y] = tx; \ - (out) = d[(tx + ty) & 0xff] ^ (in); - -#ifndef RC4_INDEX -#define RC4_LOOP(a, b, i) LOOP(*((a)++), *((b)++)) -#else -#define RC4_LOOP(a, b, i) LOOP(a[i], b[i]) -#endif - i = len >> 3; - if (i) { - for (;;) { - RC4_LOOP(in, out, 0); - RC4_LOOP(in, out, 1); - RC4_LOOP(in, out, 2); - RC4_LOOP(in, out, 3); - RC4_LOOP(in, out, 4); - RC4_LOOP(in, out, 5); - RC4_LOOP(in, out, 6); - RC4_LOOP(in, out, 7); -#ifdef RC4_INDEX - in += 8; - out += 8; -#endif - if (--i == 0) { - break; - } - } - } - i = len & 0x07; - if (i) { - for (;;) { - RC4_LOOP(in, out, 0); - if (--i == 0) { - break; - } - RC4_LOOP(in, out, 1); - if (--i == 0) { - break; - } - RC4_LOOP(in, out, 2); - if (--i == 0) { - break; - } - RC4_LOOP(in, out, 3); - if (--i == 0) { - break; - } - RC4_LOOP(in, out, 4); - if (--i == 0) { - break; - } - RC4_LOOP(in, out, 5); - if (--i == 0) { - break; - } - RC4_LOOP(in, out, 6); - if (--i == 0) { - break; - } - } - } key->x = x; key->y = y; } void RC4_set_key(RC4_KEY *rc4key, unsigned len, const uint8_t *key) { - uint32_t tmp; - unsigned i, id1, id2; - uint32_t *d; - - d = &rc4key->data[0]; + uint32_t *d = &rc4key->data[0]; rc4key->x = 0; rc4key->y = 0; - id1 = id2 = 0; -#define SK_LOOP(d, n) \ - { \ - tmp = d[(n)]; \ - id2 = (key[id1] + tmp + id2) & 0xff; \ - if (++id1 == len) \ - id1 = 0; \ - d[(n)] = d[id2]; \ - d[id2] = tmp; \ - } - - for (i = 0; i < 256; i++) { + for (unsigned i = 0; i < 256; i++) { d[i] = i; } - for (i = 0; i < 256; i += 4) { - SK_LOOP(d, i + 0); - SK_LOOP(d, i + 1); - SK_LOOP(d, i + 2); - SK_LOOP(d, i + 3); - } -} -#else - -/* In this case several functions are provided by asm code. However, one cannot - * control asm symbol visibility with command line flags and such so they are - * always hidden and wrapped by these C functions, which can be so - * controlled. */ - -void asm_RC4(RC4_KEY *key, size_t len, const uint8_t *in, uint8_t *out); -void RC4(RC4_KEY *key, size_t len, const uint8_t *in, uint8_t *out) { - asm_RC4(key, len, in, out); -} - -void asm_RC4_set_key(RC4_KEY *rc4key, unsigned len, const uint8_t *key); -void RC4_set_key(RC4_KEY *rc4key, unsigned len, const uint8_t *key) { - asm_RC4_set_key(rc4key, len, key); + unsigned id1 = 0, id2 = 0; + for (unsigned i = 0; i < 256; i++) { + uint32_t tmp = d[i]; + id2 = (key[id1] + tmp + id2) & 0xff; + if (++id1 == len) { + id1 = 0; + } + d[i] = d[id2]; + d[id2] = tmp; + } } - -#endif /* OPENSSL_NO_ASM || (!OPENSSL_X86_64 && !OPENSSL_X86) */ diff --git a/Sources/BoringSSL/crypto/refcount_lock.c b/Sources/BoringSSL/crypto/refcount_lock.c index bb8ef86b9..ea6a06d39 100644 --- a/Sources/BoringSSL/crypto/refcount_lock.c +++ b/Sources/BoringSSL/crypto/refcount_lock.c @@ -31,7 +31,7 @@ void CRYPTO_refcount_inc(CRYPTO_refcount_t *count) { if (*count < CRYPTO_REFCOUNT_MAX) { (*count)++; } - CRYPTO_STATIC_MUTEX_unlock(&g_refcount_lock); + CRYPTO_STATIC_MUTEX_unlock_write(&g_refcount_lock); } int CRYPTO_refcount_dec_and_test_zero(CRYPTO_refcount_t *count) { @@ -45,7 +45,7 @@ int CRYPTO_refcount_dec_and_test_zero(CRYPTO_refcount_t *count) { (*count)--; } ret = (*count == 0); - CRYPTO_STATIC_MUTEX_unlock(&g_refcount_lock); + CRYPTO_STATIC_MUTEX_unlock_write(&g_refcount_lock); return ret; } diff --git a/Sources/BoringSSL/crypto/rsa/blinding.c b/Sources/BoringSSL/crypto/rsa/blinding.c index e6b987d93..693dced3f 100644 --- a/Sources/BoringSSL/crypto/rsa/blinding.c +++ b/Sources/BoringSSL/crypto/rsa/blinding.c @@ -115,58 +115,41 @@ #include #include "internal.h" +#include "../internal.h" #define BN_BLINDING_COUNTER 32 struct bn_blinding_st { - BIGNUM *A; - BIGNUM *Ai; - BIGNUM *e; - BIGNUM *mod; - int counter; - /* mont is the Montgomery context used for this |BN_BLINDING|. It is not - * owned and must outlive this structure. */ - const BN_MONT_CTX *mont; - int (*bn_mod_exp)(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, - const BIGNUM *m, BN_CTX *ctx, const BN_MONT_CTX *mont); + BIGNUM *A; /* The base blinding factor, Montgomery-encoded. */ + BIGNUM *Ai; /* The inverse of the blinding factor, Montgomery-encoded. */ + unsigned counter; }; -BN_BLINDING *BN_BLINDING_new(const BIGNUM *A, const BIGNUM *Ai, BIGNUM *mod) { - BN_BLINDING *ret = NULL; +static int bn_blinding_create_param(BN_BLINDING *b, const BIGNUM *e, + const BN_MONT_CTX *mont, BN_CTX *ctx); - ret = (BN_BLINDING*) OPENSSL_malloc(sizeof(BN_BLINDING)); +BN_BLINDING *BN_BLINDING_new(void) { + BN_BLINDING *ret = OPENSSL_malloc(sizeof(BN_BLINDING)); if (ret == NULL) { OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE); return NULL; } - memset(ret, 0, sizeof(BN_BLINDING)); - if (A != NULL) { - ret->A = BN_dup(A); - if (ret->A == NULL) { - goto err; - } - } - if (Ai != NULL) { - ret->Ai = BN_dup(Ai); - if (ret->Ai == NULL) { - goto err; - } - } + OPENSSL_memset(ret, 0, sizeof(BN_BLINDING)); - /* save a copy of mod in the BN_BLINDING structure */ - ret->mod = BN_dup(mod); - if (ret->mod == NULL) { + ret->A = BN_new(); + if (ret->A == NULL) { goto err; } - if (BN_get_flags(mod, BN_FLG_CONSTTIME) != 0) { - BN_set_flags(ret->mod, BN_FLG_CONSTTIME); + + ret->Ai = BN_new(); + if (ret->Ai == NULL) { + goto err; } - /* Set the counter to the special value -1 - * to indicate that this is never-used fresh blinding - * that does not need updating before first use. */ - ret->counter = -1; + /* The blinding values need to be created before this blinding can be used. */ + ret->counter = BN_BLINDING_COUNTER - 1; + return ret; err: @@ -181,242 +164,102 @@ void BN_BLINDING_free(BN_BLINDING *r) { BN_free(r->A); BN_free(r->Ai); - BN_free(r->e); - BN_free(r->mod); OPENSSL_free(r); } -int BN_BLINDING_update(BN_BLINDING *b, BN_CTX *ctx) { - int ret = 0; - - if (b->A == NULL || b->Ai == NULL) { - OPENSSL_PUT_ERROR(RSA, RSA_R_BN_NOT_INITIALIZED); - goto err; - } - - if (b->counter == -1) { - b->counter = 0; - } - - if (++b->counter == BN_BLINDING_COUNTER && b->e != NULL) { +static int bn_blinding_update(BN_BLINDING *b, const BIGNUM *e, + const BN_MONT_CTX *mont, BN_CTX *ctx) { + if (++b->counter == BN_BLINDING_COUNTER) { /* re-create blinding parameters */ - if (!BN_BLINDING_create_param(b, NULL, NULL, ctx, NULL, NULL)) { + if (!bn_blinding_create_param(b, e, mont, ctx)) { goto err; } + b->counter = 0; } else { - if (!BN_mod_mul(b->A, b->A, b->A, b->mod, ctx)) { - goto err; - } - if (!BN_mod_mul(b->Ai, b->Ai, b->Ai, b->mod, ctx)) { + if (!BN_mod_mul_montgomery(b->A, b->A, b->A, mont, ctx) || + !BN_mod_mul_montgomery(b->Ai, b->Ai, b->Ai, mont, ctx)) { goto err; } } - ret = 1; + return 1; err: - if (b->counter == BN_BLINDING_COUNTER) { - b->counter = 0; - } - return ret; -} + /* |A| and |Ai| may be in an inconsistent state so they both need to be + * replaced the next time this blinding is used. Note that this is only + * sufficient because support for |BN_BLINDING_NO_UPDATE| and + * |BN_BLINDING_NO_RECREATE| was previously dropped. */ + b->counter = BN_BLINDING_COUNTER - 1; -int BN_BLINDING_convert(BIGNUM *n, BN_BLINDING *b, BN_CTX *ctx) { - int ret = 1; - - if (b->A == NULL || b->Ai == NULL) { - OPENSSL_PUT_ERROR(RSA, RSA_R_BN_NOT_INITIALIZED); - return 0; - } + return 0; +} - if (b->counter == -1) { - /* Fresh blinding, doesn't need updating. */ - b->counter = 0; - } else if (!BN_BLINDING_update(b, ctx)) { +int BN_BLINDING_convert(BIGNUM *n, BN_BLINDING *b, const BIGNUM *e, + const BN_MONT_CTX *mont, BN_CTX *ctx) { + /* |n| is not Montgomery-encoded and |b->A| is. |BN_mod_mul_montgomery| + * cancels one Montgomery factor, so the resulting value of |n| is unencoded. + */ + if (!bn_blinding_update(b, e, mont, ctx) || + !BN_mod_mul_montgomery(n, n, b->A, mont, ctx)) { return 0; } - if (!BN_mod_mul(n, n, b->A, b->mod, ctx)) { - ret = 0; - } - - return ret; + return 1; } -int BN_BLINDING_invert(BIGNUM *n, const BN_BLINDING *b, BN_CTX *ctx) { - if (b->Ai == NULL) { - OPENSSL_PUT_ERROR(RSA, RSA_R_BN_NOT_INITIALIZED); - return 0; - } - return BN_mod_mul(n, n, b->Ai, b->mod, ctx); +int BN_BLINDING_invert(BIGNUM *n, const BN_BLINDING *b, BN_MONT_CTX *mont, + BN_CTX *ctx) { + /* |n| is not Montgomery-encoded and |b->A| is. |BN_mod_mul_montgomery| + * cancels one Montgomery factor, so the resulting value of |n| is unencoded. + */ + return BN_mod_mul_montgomery(n, n, b->Ai, mont, ctx); } -BN_BLINDING *BN_BLINDING_create_param( - BN_BLINDING *b, const BIGNUM *e, BIGNUM *m, BN_CTX *ctx, - int (*bn_mod_exp)(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, - const BIGNUM *m, BN_CTX *ctx, const BN_MONT_CTX *mont), - const BN_MONT_CTX *mont) { +static int bn_blinding_create_param(BN_BLINDING *b, const BIGNUM *e, + const BN_MONT_CTX *mont, BN_CTX *ctx) { int retry_counter = 32; - BN_BLINDING *ret = NULL; - - if (b == NULL) { - ret = BN_BLINDING_new(NULL, NULL, m); - } else { - ret = b; - } - - if (ret == NULL) { - goto err; - } - - if (ret->A == NULL && (ret->A = BN_new()) == NULL) { - goto err; - } - if (ret->Ai == NULL && (ret->Ai = BN_new()) == NULL) { - goto err; - } - - if (e != NULL) { - BN_free(ret->e); - ret->e = BN_dup(e); - } - if (ret->e == NULL) { - goto err; - } - - if (bn_mod_exp != NULL) { - ret->bn_mod_exp = bn_mod_exp; - } - if (mont != NULL) { - ret->mont = mont; - } do { - if (!BN_rand_range(ret->A, ret->mod)) { - goto err; + if (!BN_rand_range_ex(b->A, 1, &mont->N)) { + OPENSSL_PUT_ERROR(RSA, ERR_R_INTERNAL_ERROR); + return 0; } - int no_inverse; - if (BN_mod_inverse_ex(ret->Ai, &no_inverse, ret->A, ret->mod, ctx) == NULL) { - /* this should almost never happen for good RSA keys */ - if (no_inverse) { - if (retry_counter-- == 0) { - OPENSSL_PUT_ERROR(RSA, RSA_R_TOO_MANY_ITERATIONS); - goto err; - } - ERR_clear_error(); - } else { - goto err; - } - } else { - break; + /* |BN_from_montgomery| + |BN_mod_inverse_blinded| is equivalent to, but + * more efficient than, |BN_mod_inverse_blinded| + |BN_to_montgomery|. */ + if (!BN_from_montgomery(b->Ai, b->A, mont, ctx)) { + OPENSSL_PUT_ERROR(RSA, ERR_R_INTERNAL_ERROR); + return 0; } - } while (1); - if (ret->bn_mod_exp != NULL && ret->mont != NULL) { - if (!ret->bn_mod_exp(ret->A, ret->A, ret->e, ret->mod, ctx, ret->mont)) { - goto err; - } - } else { - if (!BN_mod_exp(ret->A, ret->A, ret->e, ret->mod, ctx)) { - goto err; + int no_inverse; + if (BN_mod_inverse_blinded(b->Ai, &no_inverse, b->Ai, mont, ctx)) { + break; } - } - - return ret; - -err: - if (b == NULL) { - BN_BLINDING_free(ret); - ret = NULL; - } - - return ret; -} - -static BIGNUM *rsa_get_public_exp(const BIGNUM *d, const BIGNUM *p, - const BIGNUM *q, BN_CTX *ctx) { - BIGNUM *ret = NULL, *r0, *r1, *r2; - - if (d == NULL || p == NULL || q == NULL) { - return NULL; - } - - BN_CTX_start(ctx); - r0 = BN_CTX_get(ctx); - r1 = BN_CTX_get(ctx); - r2 = BN_CTX_get(ctx); - if (r2 == NULL) { - goto err; - } - - if (!BN_sub(r1, p, BN_value_one())) { - goto err; - } - if (!BN_sub(r2, q, BN_value_one())) { - goto err; - } - if (!BN_mul(r0, r1, r2, ctx)) { - goto err; - } - - ret = BN_mod_inverse(NULL, d, r0, ctx); - -err: - BN_CTX_end(ctx); - return ret; -} - -BN_BLINDING *rsa_setup_blinding(RSA *rsa, BN_CTX *in_ctx) { - BIGNUM local_n; - BIGNUM *e, *n; - BN_CTX *ctx; - BN_BLINDING *ret = NULL; - BN_MONT_CTX *mont_ctx = NULL; - if (in_ctx == NULL) { - ctx = BN_CTX_new(); - if (ctx == NULL) { + if (!no_inverse) { + OPENSSL_PUT_ERROR(RSA, ERR_R_INTERNAL_ERROR); return 0; } - } else { - ctx = in_ctx; - } - - if (rsa->e == NULL) { - e = rsa_get_public_exp(rsa->d, rsa->p, rsa->q, ctx); - if (e == NULL) { - OPENSSL_PUT_ERROR(RSA, RSA_R_NO_PUBLIC_EXPONENT); - goto err; - } - } else { - e = rsa->e; - } - n = &local_n; - BN_with_flags(n, rsa->n, BN_FLG_CONSTTIME); - - if (rsa->flags & RSA_FLAG_CACHE_PUBLIC) { - mont_ctx = BN_MONT_CTX_set_locked(&rsa->mont_n, &rsa->lock, rsa->n, ctx); - if (mont_ctx == NULL) { - goto err; + /* For reasonably-sized RSA keys, it should almost never be the case that a + * random value doesn't have an inverse. */ + if (retry_counter-- == 0) { + OPENSSL_PUT_ERROR(RSA, RSA_R_TOO_MANY_ITERATIONS); + return 0; } - } + ERR_clear_error(); + } while (1); - ret = BN_BLINDING_create_param(NULL, e, n, ctx, rsa->meth->bn_mod_exp, - mont_ctx); - if (ret == NULL) { - OPENSSL_PUT_ERROR(RSA, ERR_R_BN_LIB); - goto err; + if (!BN_mod_exp_mont(b->A, b->A, e, &mont->N, ctx, mont)) { + OPENSSL_PUT_ERROR(RSA, ERR_R_INTERNAL_ERROR); + return 0; } -err: - if (in_ctx == NULL) { - BN_CTX_free(ctx); - } - if (rsa->e == NULL) { - BN_free(e); + if (!BN_to_montgomery(b->A, b->A, mont, ctx)) { + OPENSSL_PUT_ERROR(RSA, ERR_R_INTERNAL_ERROR); + return 0; } - return ret; + return 1; } diff --git a/Sources/BoringSSL/crypto/rsa/internal.h b/Sources/BoringSSL/crypto/rsa/internal.h index 4d27344e9..c6ea97f09 100644 --- a/Sources/BoringSSL/crypto/rsa/internal.h +++ b/Sources/BoringSSL/crypto/rsa/internal.h @@ -77,9 +77,6 @@ int rsa_default_sign_raw(RSA *rsa, size_t *out_len, uint8_t *out, int padding); int rsa_default_decrypt(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out, const uint8_t *in, size_t in_len, int padding); -int rsa_default_verify_raw(RSA *rsa, size_t *out_len, uint8_t *out, - size_t max_out, const uint8_t *in, size_t in_len, - int padding); int rsa_default_private_transform(RSA *rsa, uint8_t *out, const uint8_t *in, size_t len); int rsa_default_multi_prime_keygen(RSA *rsa, int bits, int num_primes, @@ -90,17 +87,12 @@ int rsa_default_keygen(RSA *rsa, int bits, BIGNUM *e_value, BN_GENCB *cb); #define RSA_PKCS1_PADDING_SIZE 11 -BN_BLINDING *BN_BLINDING_new(const BIGNUM *A, const BIGNUM *Ai, BIGNUM *mod); +BN_BLINDING *BN_BLINDING_new(void); void BN_BLINDING_free(BN_BLINDING *b); -int BN_BLINDING_update(BN_BLINDING *b, BN_CTX *ctx); -int BN_BLINDING_convert(BIGNUM *n, BN_BLINDING *b, BN_CTX *ctx); -int BN_BLINDING_invert(BIGNUM *n, const BN_BLINDING *b, BN_CTX *ctx); -BN_BLINDING *BN_BLINDING_create_param( - BN_BLINDING *b, const BIGNUM *e, BIGNUM *m, BN_CTX *ctx, - int (*bn_mod_exp)(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, - const BIGNUM *m, BN_CTX *ctx, const BN_MONT_CTX *mont), - const BN_MONT_CTX *mont); -BN_BLINDING *rsa_setup_blinding(RSA *rsa, BN_CTX *in_ctx); +int BN_BLINDING_convert(BIGNUM *n, BN_BLINDING *b, const BIGNUM *e, + const BN_MONT_CTX *mont_ctx, BN_CTX *ctx); +int BN_BLINDING_invert(BIGNUM *n, const BN_BLINDING *b, BN_MONT_CTX *mont_ctx, + BN_CTX *ctx); int RSA_padding_add_PKCS1_type_1(uint8_t *to, unsigned to_len, diff --git a/Sources/BoringSSL/crypto/rsa/padding.c b/Sources/BoringSSL/crypto/rsa/padding.c index 128950aea..3ed19adc1 100644 --- a/Sources/BoringSSL/crypto/rsa/padding.c +++ b/Sources/BoringSSL/crypto/rsa/padding.c @@ -59,6 +59,7 @@ #include #include +#include #include #include #include @@ -73,7 +74,6 @@ int RSA_padding_add_PKCS1_type_1(uint8_t *to, unsigned to_len, const uint8_t *from, unsigned from_len) { unsigned j; - uint8_t *p; if (to_len < RSA_PKCS1_PADDING_SIZE) { OPENSSL_PUT_ERROR(RSA, RSA_R_KEY_SIZE_TOO_SMALL); @@ -85,17 +85,17 @@ int RSA_padding_add_PKCS1_type_1(uint8_t *to, unsigned to_len, return 0; } - p = (uint8_t *)to; + uint8_t *p = to; *(p++) = 0; *(p++) = 1; /* Private Key BT (Block Type) */ /* pad out with 0xff data */ j = to_len - 3 - from_len; - memset(p, 0xff, j); + OPENSSL_memset(p, 0xff, j); p += j; *(p++) = 0; - memcpy(p, from, from_len); + OPENSSL_memcpy(p, from, from_len); return 1; } @@ -146,7 +146,7 @@ int RSA_padding_check_PKCS1_type_1(uint8_t *to, unsigned to_len, OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE); return -1; } - memcpy(to, p, j); + OPENSSL_memcpy(to, p, j); return j; } @@ -154,7 +154,6 @@ int RSA_padding_check_PKCS1_type_1(uint8_t *to, unsigned to_len, int RSA_padding_add_PKCS1_type_2(uint8_t *to, unsigned to_len, const uint8_t *from, unsigned from_len) { unsigned i, j; - uint8_t *p; if (to_len < RSA_PKCS1_PADDING_SIZE) { OPENSSL_PUT_ERROR(RSA, RSA_R_KEY_SIZE_TOO_SMALL); @@ -166,7 +165,7 @@ int RSA_padding_add_PKCS1_type_2(uint8_t *to, unsigned to_len, return 0; } - p = (unsigned char *)to; + uint8_t *p = to; *(p++) = 0; *(p++) = 2; /* Public Key BT (Block Type) */ @@ -189,7 +188,7 @@ int RSA_padding_add_PKCS1_type_2(uint8_t *to, unsigned to_len, *(p++) = 0; - memcpy(p, from, from_len); + OPENSSL_memcpy(p, from, from_len); return 1; } @@ -255,7 +254,7 @@ int RSA_padding_check_PKCS1_type_2(uint8_t *to, unsigned to_len, return -1; } - memcpy(to, &from[zero_index], msg_len); + OPENSSL_memcpy(to, &from[zero_index], msg_len); return (int)msg_len; } @@ -271,51 +270,50 @@ int RSA_padding_add_none(uint8_t *to, unsigned to_len, const uint8_t *from, return 0; } - memcpy(to, from, from_len); + OPENSSL_memcpy(to, from, from_len); return 1; } -int PKCS1_MGF1(uint8_t *mask, unsigned len, const uint8_t *seed, - unsigned seedlen, const EVP_MD *dgst) { - unsigned outlen = 0; - uint32_t i; - uint8_t cnt[4]; - EVP_MD_CTX c; - uint8_t md[EVP_MAX_MD_SIZE]; - unsigned mdlen; - int ret = -1; - - EVP_MD_CTX_init(&c); - mdlen = EVP_MD_size(dgst); - - for (i = 0; outlen < len; i++) { - cnt[0] = (uint8_t)((i >> 24) & 255); - cnt[1] = (uint8_t)((i >> 16) & 255); - cnt[2] = (uint8_t)((i >> 8)) & 255; - cnt[3] = (uint8_t)(i & 255); - if (!EVP_DigestInit_ex(&c, dgst, NULL) || - !EVP_DigestUpdate(&c, seed, seedlen) || - !EVP_DigestUpdate(&c, cnt, 4)) { +static int PKCS1_MGF1(uint8_t *out, size_t len, const uint8_t *seed, + size_t seed_len, const EVP_MD *md) { + int ret = 0; + EVP_MD_CTX ctx; + EVP_MD_CTX_init(&ctx); + + size_t md_len = EVP_MD_size(md); + + for (uint32_t i = 0; len > 0; i++) { + uint8_t counter[4]; + counter[0] = (uint8_t)(i >> 24); + counter[1] = (uint8_t)(i >> 16); + counter[2] = (uint8_t)(i >> 8); + counter[3] = (uint8_t)i; + if (!EVP_DigestInit_ex(&ctx, md, NULL) || + !EVP_DigestUpdate(&ctx, seed, seed_len) || + !EVP_DigestUpdate(&ctx, counter, sizeof(counter))) { goto err; } - if (outlen + mdlen <= len) { - if (!EVP_DigestFinal_ex(&c, mask + outlen, NULL)) { + if (md_len <= len) { + if (!EVP_DigestFinal_ex(&ctx, out, NULL)) { goto err; } - outlen += mdlen; + out += md_len; + len -= md_len; } else { - if (!EVP_DigestFinal_ex(&c, md, NULL)) { + uint8_t digest[EVP_MAX_MD_SIZE]; + if (!EVP_DigestFinal_ex(&ctx, digest, NULL)) { goto err; } - memcpy(mask + outlen, md, len - outlen); - outlen = len; + OPENSSL_memcpy(out, digest, len); + len = 0; } } - ret = 0; + + ret = 1; err: - EVP_MD_CTX_cleanup(&c); + EVP_MD_CTX_cleanup(&ctx); return ret; } @@ -357,12 +355,12 @@ int RSA_padding_add_PKCS1_OAEP_mgf1(uint8_t *to, unsigned to_len, seed = to + 1; db = to + mdlen + 1; - if (!EVP_Digest((void *)param, param_len, db, NULL, md, NULL)) { + if (!EVP_Digest(param, param_len, db, NULL, md, NULL)) { return 0; } - memset(db + mdlen, 0, emlen - from_len - 2 * mdlen - 1); + OPENSSL_memset(db + mdlen, 0, emlen - from_len - 2 * mdlen - 1); db[emlen - from_len - mdlen - 1] = 0x01; - memcpy(db + emlen - from_len - mdlen, from, from_len); + OPENSSL_memcpy(db + emlen - from_len - mdlen, from, from_len); if (!RAND_bytes(seed, mdlen)) { return 0; } @@ -373,14 +371,14 @@ int RSA_padding_add_PKCS1_OAEP_mgf1(uint8_t *to, unsigned to_len, return 0; } - if (PKCS1_MGF1(dbmask, emlen - mdlen, seed, mdlen, mgf1md) < 0) { + if (!PKCS1_MGF1(dbmask, emlen - mdlen, seed, mdlen, mgf1md)) { goto out; } for (i = 0; i < emlen - mdlen; i++) { db[i] ^= dbmask[i]; } - if (PKCS1_MGF1(seedmask, mdlen, db, emlen - mdlen, mgf1md) < 0) { + if (!PKCS1_MGF1(seedmask, mdlen, db, emlen - mdlen, mgf1md)) { goto out; } for (i = 0; i < mdlen; i++) { @@ -429,21 +427,21 @@ int RSA_padding_check_PKCS1_OAEP_mgf1(uint8_t *to, unsigned to_len, maskedseed = from + 1; maskeddb = from + 1 + mdlen; - if (PKCS1_MGF1(seed, mdlen, maskeddb, dblen, mgf1md)) { + if (!PKCS1_MGF1(seed, mdlen, maskeddb, dblen, mgf1md)) { goto err; } for (i = 0; i < mdlen; i++) { seed[i] ^= maskedseed[i]; } - if (PKCS1_MGF1(db, dblen, seed, mdlen, mgf1md)) { + if (!PKCS1_MGF1(db, dblen, seed, mdlen, mgf1md)) { goto err; } for (i = 0; i < dblen; i++) { db[i] ^= maskeddb[i]; } - if (!EVP_Digest((void *)param, param_len, phash, NULL, md, NULL)) { + if (!EVP_Digest(param, param_len, phash, NULL, md, NULL)) { goto err; } @@ -473,7 +471,7 @@ int RSA_padding_check_PKCS1_OAEP_mgf1(uint8_t *to, unsigned to_len, OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE); mlen = -1; } else { - memcpy(to, db + one_index, mlen); + OPENSSL_memcpy(to, db + one_index, mlen); } OPENSSL_free(db); @@ -548,7 +546,7 @@ int RSA_verify_PKCS1_PSS_mgf1(RSA *rsa, const uint8_t *mHash, OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE); goto err; } - if (PKCS1_MGF1(DB, maskedDBLen, H, hLen, mgf1Hash) < 0) { + if (!PKCS1_MGF1(DB, maskedDBLen, H, hLen, mgf1Hash)) { goto err; } for (i = 0; i < maskedDBLen; i++) { @@ -581,7 +579,7 @@ int RSA_verify_PKCS1_PSS_mgf1(RSA *rsa, const uint8_t *mHash, if (!EVP_DigestFinal_ex(&ctx, H_, NULL)) { goto err; } - if (memcmp(H_, H, hLen)) { + if (OPENSSL_memcmp(H_, H, hLen)) { OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_SIGNATURE); ret = 0; } else { @@ -598,8 +596,7 @@ int RSA_verify_PKCS1_PSS_mgf1(RSA *rsa, const uint8_t *mHash, int RSA_padding_add_PKCS1_PSS_mgf1(RSA *rsa, unsigned char *EM, const unsigned char *mHash, const EVP_MD *Hash, const EVP_MD *mgf1Hash, - int sLen) { - int i; + int sLenRequested) { int ret = 0; size_t maskedDBLen, MSBits, emLen; size_t hLen; @@ -612,19 +609,6 @@ int RSA_padding_add_PKCS1_PSS_mgf1(RSA *rsa, unsigned char *EM, hLen = EVP_MD_size(Hash); - /* Negative sLen has special meanings: - * -1 sLen == hLen - * -2 salt length is maximized - * -N reserved */ - if (sLen == -1) { - sLen = hLen; - } else if (sLen == -2) { - sLen = -2; - } else if (sLen < -2) { - OPENSSL_PUT_ERROR(RSA, RSA_R_SLEN_CHECK_FAILED); - goto err; - } - if (BN_is_zero(rsa->n)) { OPENSSL_PUT_ERROR(RSA, RSA_R_EMPTY_PUBLIC_KEY); goto err; @@ -637,16 +621,33 @@ int RSA_padding_add_PKCS1_PSS_mgf1(RSA *rsa, unsigned char *EM, *EM++ = 0; emLen--; } - if (sLen == -2) { - if (emLen < hLen + 2) { - OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE); - goto err; - } + + if (emLen < hLen + 2) { + OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE); + goto err; + } + + /* Negative sLenRequested has special meanings: + * -1 sLen == hLen + * -2 salt length is maximized + * -N reserved */ + size_t sLen; + if (sLenRequested == -1) { + sLen = hLen; + } else if (sLenRequested == -2) { sLen = emLen - hLen - 2; - } else if (emLen < hLen + sLen + 2) { + } else if (sLenRequested < 0) { + OPENSSL_PUT_ERROR(RSA, RSA_R_SLEN_CHECK_FAILED); + goto err; + } else { + sLen = (size_t)sLenRequested; + } + + if (emLen - hLen - 2 < sLen) { OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE); goto err; } + if (sLen > 0) { salt = OPENSSL_malloc(sLen); if (!salt) { @@ -674,7 +675,7 @@ int RSA_padding_add_PKCS1_PSS_mgf1(RSA *rsa, unsigned char *EM, EVP_MD_CTX_cleanup(&ctx); /* Generate dbMask in place then perform XOR on it */ - if (PKCS1_MGF1(EM, maskedDBLen, H, hLen, mgf1Hash)) { + if (!PKCS1_MGF1(EM, maskedDBLen, H, hLen, mgf1Hash)) { goto err; } @@ -686,7 +687,7 @@ int RSA_padding_add_PKCS1_PSS_mgf1(RSA *rsa, unsigned char *EM, p += emLen - sLen - hLen - 2; *p++ ^= 0x1; if (sLen > 0) { - for (i = 0; i < sLen; i++) { + for (size_t i = 0; i < sLen; i++) { *p++ ^= salt[i]; } } diff --git a/Sources/BoringSSL/crypto/rsa/rsa.c b/Sources/BoringSSL/crypto/rsa/rsa.c index 9ffea1f2a..731293f84 100644 --- a/Sources/BoringSSL/crypto/rsa/rsa.c +++ b/Sources/BoringSSL/crypto/rsa/rsa.c @@ -64,7 +64,7 @@ #include #include #include -#include +#include #include #include "internal.h" @@ -82,7 +82,7 @@ RSA *RSA_new_method(const ENGINE *engine) { return NULL; } - memset(rsa, 0, sizeof(RSA)); + OPENSSL_memset(rsa, 0, sizeof(RSA)); if (engine) { rsa->meth = ENGINE_get_RSA_method(engine); @@ -169,6 +169,42 @@ int RSA_up_ref(RSA *rsa) { return 1; } +void RSA_get0_key(const RSA *rsa, const BIGNUM **out_n, const BIGNUM **out_e, + const BIGNUM **out_d) { + if (out_n != NULL) { + *out_n = rsa->n; + } + if (out_e != NULL) { + *out_e = rsa->e; + } + if (out_d != NULL) { + *out_d = rsa->d; + } +} + +void RSA_get0_factors(const RSA *rsa, const BIGNUM **out_p, + const BIGNUM **out_q) { + if (out_p != NULL) { + *out_p = rsa->p; + } + if (out_q != NULL) { + *out_q = rsa->q; + } +} + +void RSA_get0_crt_params(const RSA *rsa, const BIGNUM **out_dmp1, + const BIGNUM **out_dmq1, const BIGNUM **out_iqmp) { + if (out_dmp1 != NULL) { + *out_dmp1 = rsa->dmp1; + } + if (out_dmq1 != NULL) { + *out_dmq1 = rsa->dmq1; + } + if (out_iqmp != NULL) { + *out_iqmp = rsa->iqmp; + } +} + int RSA_generate_key_ex(RSA *rsa, int bits, BIGNUM *e_value, BN_GENCB *cb) { if (rsa->meth->keygen) { return rsa->meth->keygen(rsa, bits, e_value, cb); @@ -258,16 +294,6 @@ int RSA_private_decrypt(size_t flen, const uint8_t *from, uint8_t *to, RSA *rsa, return out_len; } -int RSA_verify_raw(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out, - const uint8_t *in, size_t in_len, int padding) { - if (rsa->meth->verify_raw) { - return rsa->meth->verify_raw(rsa, out_len, out, max_out, in, in_len, padding); - } - - return rsa_default_verify_raw(rsa, out_len, out, max_out, in, in_len, - padding); -} - int RSA_public_decrypt(size_t flen, const uint8_t *from, uint8_t *to, RSA *rsa, int padding) { size_t out_len; @@ -420,8 +446,8 @@ int RSA_add_pkcs1_prefix(uint8_t **out_msg, size_t *out_msg_len, return 0; } - memcpy(signed_msg, prefix, prefix_len); - memcpy(signed_msg + prefix_len, msg, msg_len); + OPENSSL_memcpy(signed_msg, prefix, prefix_len); + OPENSSL_memcpy(signed_msg + prefix_len, msg, msg_len); *out_msg = signed_msg; *out_msg_len = signed_msg_len; @@ -473,6 +499,11 @@ int RSA_sign(int hash_nid, const uint8_t *in, unsigned in_len, uint8_t *out, int RSA_verify(int hash_nid, const uint8_t *msg, size_t msg_len, const uint8_t *sig, size_t sig_len, RSA *rsa) { + if (rsa->n == NULL || rsa->e == NULL) { + OPENSSL_PUT_ERROR(RSA, RSA_R_VALUE_MISSING); + return 0; + } + const size_t rsa_size = RSA_size(rsa); uint8_t *buf = NULL; int ret = 0; @@ -480,15 +511,6 @@ int RSA_verify(int hash_nid, const uint8_t *msg, size_t msg_len, size_t signed_msg_len, len; int signed_msg_is_alloced = 0; - if (rsa->meth->verify) { - return rsa->meth->verify(hash_nid, msg, msg_len, sig, sig_len, rsa); - } - - if (sig_len != rsa_size) { - OPENSSL_PUT_ERROR(RSA, RSA_R_WRONG_SIGNATURE_LENGTH); - return 0; - } - if (hash_nid == NID_md5_sha1 && msg_len != SSL_SIG_LENGTH) { OPENSSL_PUT_ERROR(RSA, RSA_R_INVALID_MESSAGE_LENGTH); return 0; @@ -510,7 +532,7 @@ int RSA_verify(int hash_nid, const uint8_t *msg, size_t msg_len, goto out; } - if (len != signed_msg_len || CRYPTO_memcmp(buf, signed_msg, len) != 0) { + if (len != signed_msg_len || OPENSSL_memcmp(buf, signed_msg, len) != 0) { OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_SIGNATURE); goto out; } @@ -531,7 +553,7 @@ static void bn_free_and_null(BIGNUM **bn) { } int RSA_check_key(const RSA *key) { - BIGNUM n, pm1, qm1, lcm, gcd, de, dmp1, dmq1, iqmp; + BIGNUM n, pm1, qm1, lcm, gcd, de, dmp1, dmq1, iqmp_times_q; BN_CTX *ctx; int ok = 0, has_crt_values; @@ -570,7 +592,7 @@ int RSA_check_key(const RSA *key) { BN_init(&de); BN_init(&dmp1); BN_init(&dmq1); - BN_init(&iqmp); + BN_init(&iqmp_times_q); if (!BN_mul(&n, key->p, key->q, ctx) || /* lcm = lcm(prime-1, for all primes) */ @@ -587,8 +609,7 @@ int RSA_check_key(const RSA *key) { num_additional_primes = sk_RSA_additional_prime_num(key->additional_primes); } - size_t i; - for (i = 0; i < num_additional_primes; i++) { + for (size_t i = 0; i < num_additional_primes; i++) { const RSA_additional_prime *ap = sk_RSA_additional_prime_value(key->additional_primes, i); if (!BN_mul(&n, &n, ap->prime, ctx) || @@ -631,14 +652,15 @@ int RSA_check_key(const RSA *key) { /* dmq1 = d mod (q-1) */ !BN_mod(&dmq1, key->d, &qm1, ctx) || /* iqmp = q^-1 mod p */ - !BN_mod_inverse(&iqmp, key->q, key->p, ctx)) { + !BN_mod_mul(&iqmp_times_q, key->iqmp, key->q, key->p, ctx)) { OPENSSL_PUT_ERROR(RSA, ERR_LIB_BN); goto out; } if (BN_cmp(&dmp1, key->dmp1) != 0 || BN_cmp(&dmq1, key->dmq1) != 0 || - BN_cmp(&iqmp, key->iqmp) != 0) { + BN_cmp(key->iqmp, key->p) >= 0 || + !BN_is_one(&iqmp_times_q)) { OPENSSL_PUT_ERROR(RSA, RSA_R_CRT_VALUES_INCORRECT); goto out; } @@ -655,7 +677,7 @@ int RSA_check_key(const RSA *key) { BN_free(&de); BN_free(&dmp1); BN_free(&dmq1); - BN_free(&iqmp); + BN_free(&iqmp_times_q); BN_CTX_free(ctx); return ok; diff --git a/Sources/BoringSSL/crypto/rsa/rsa_asn1.c b/Sources/BoringSSL/crypto/rsa/rsa_asn1.c index 1f3d6a244..88b1dfb32 100644 --- a/Sources/BoringSSL/crypto/rsa/rsa_asn1.c +++ b/Sources/BoringSSL/crypto/rsa/rsa_asn1.c @@ -59,8 +59,6 @@ #include #include -#include -#include #include #include #include @@ -68,6 +66,7 @@ #include "internal.h" #include "../bytestring/internal.h" +#include "../internal.h" static int parse_integer_buggy(CBS *cbs, BIGNUM **out, int buggy) { @@ -185,7 +184,7 @@ static RSA_additional_prime *rsa_parse_additional_prime(CBS *cbs) { OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE); return 0; } - memset(ret, 0, sizeof(RSA_additional_prime)); + OPENSSL_memset(ret, 0, sizeof(RSA_additional_prime)); CBS child; if (!CBS_get_asn1(cbs, &child, CBS_ASN1_SEQUENCE) || @@ -282,6 +281,11 @@ RSA *RSA_parse_private_key(CBS *cbs) { goto err; } + if (!RSA_check_key(ret)) { + OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_RSA_PARAMETERS); + goto err; + } + BN_CTX_free(ctx); BN_free(product_of_primes_so_far); return ret; @@ -325,22 +329,23 @@ int RSA_marshal_private_key(CBB *cbb, const RSA *rsa) { return 0; } + CBB other_prime_infos; if (is_multiprime) { - CBB other_prime_infos; if (!CBB_add_asn1(&child, &other_prime_infos, CBS_ASN1_SEQUENCE)) { OPENSSL_PUT_ERROR(RSA, RSA_R_ENCODE_ERROR); return 0; } - size_t i; - for (i = 0; i < sk_RSA_additional_prime_num(rsa->additional_primes); i++) { + for (size_t i = 0; i < sk_RSA_additional_prime_num(rsa->additional_primes); + i++) { RSA_additional_prime *ap = - sk_RSA_additional_prime_value(rsa->additional_primes, i); + sk_RSA_additional_prime_value(rsa->additional_primes, i); CBB other_prime_info; if (!CBB_add_asn1(&other_prime_infos, &other_prime_info, CBS_ASN1_SEQUENCE) || !marshal_integer(&other_prime_info, ap->prime) || !marshal_integer(&other_prime_info, ap->exp) || - !marshal_integer(&other_prime_info, ap->coeff)) { + !marshal_integer(&other_prime_info, ap->coeff) || + !CBB_flush(&other_prime_infos)) { OPENSSL_PUT_ERROR(RSA, RSA_R_ENCODE_ERROR); return 0; } @@ -390,6 +395,7 @@ int i2d_RSAPublicKey(const RSA *in, uint8_t **outp) { CBB cbb; if (!CBB_init(&cbb, 0) || !RSA_marshal_public_key(&cbb, in)) { + CBB_cleanup(&cbb); return -1; } return CBB_finish_i2d(&cbb, outp); @@ -417,20 +423,12 @@ int i2d_RSAPrivateKey(const RSA *in, uint8_t **outp) { CBB cbb; if (!CBB_init(&cbb, 0) || !RSA_marshal_private_key(&cbb, in)) { + CBB_cleanup(&cbb); return -1; } return CBB_finish_i2d(&cbb, outp); } -ASN1_SEQUENCE(RSA_PSS_PARAMS) = { - ASN1_EXP_OPT(RSA_PSS_PARAMS, hashAlgorithm, X509_ALGOR,0), - ASN1_EXP_OPT(RSA_PSS_PARAMS, maskGenAlgorithm, X509_ALGOR,1), - ASN1_EXP_OPT(RSA_PSS_PARAMS, saltLength, ASN1_INTEGER,2), - ASN1_EXP_OPT(RSA_PSS_PARAMS, trailerField, ASN1_INTEGER,3), -} ASN1_SEQUENCE_END(RSA_PSS_PARAMS); - -IMPLEMENT_ASN1_FUNCTIONS(RSA_PSS_PARAMS); - RSA *RSAPublicKey_dup(const RSA *rsa) { uint8_t *der; size_t der_len; diff --git a/Sources/BoringSSL/crypto/rsa/rsa_impl.c b/Sources/BoringSSL/crypto/rsa/rsa_impl.c index ba3107395..8e0aa9c62 100644 --- a/Sources/BoringSSL/crypto/rsa/rsa_impl.c +++ b/Sources/BoringSSL/crypto/rsa/rsa_impl.c @@ -56,6 +56,7 @@ #include +#include #include #include @@ -64,26 +65,43 @@ #include #include "internal.h" +#include "../bn/internal.h" #include "../internal.h" static int check_modulus_and_exponent_sizes(const RSA *rsa) { unsigned rsa_bits = BN_num_bits(rsa->n); + if (rsa_bits > 16 * 1024) { OPENSSL_PUT_ERROR(RSA, RSA_R_MODULUS_TOO_LARGE); return 0; } - if (BN_ucmp(rsa->n, rsa->e) <= 0) { + /* Mitigate DoS attacks by limiting the exponent size. 33 bits was chosen as + * the limit based on the recommendations in [1] and [2]. Windows CryptoAPI + * doesn't support values larger than 32 bits [3], so it is unlikely that + * exponents larger than 32 bits are being used for anything Windows commonly + * does. + * + * [1] https://www.imperialviolet.org/2012/03/16/rsae.html + * [2] https://www.imperialviolet.org/2012/03/17/rsados.html + * [3] https://msdn.microsoft.com/en-us/library/aa387685(VS.85).aspx */ + static const unsigned kMaxExponentBits = 33; + + if (BN_num_bits(rsa->e) > kMaxExponentBits) { OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_E_VALUE); return 0; } - /* For large moduli only, enforce exponent limit. */ - if (rsa_bits > 3072 && BN_num_bits(rsa->e) > 64) { - OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_E_VALUE); + /* Verify |n > e|. Comparing |rsa_bits| to |kMaxExponentBits| is a small + * shortcut to comparing |n| and |e| directly. In reality, |kMaxExponentBits| + * is much smaller than the minimum RSA key size that any application should + * accept. */ + if (rsa_bits <= kMaxExponentBits) { + OPENSSL_PUT_ERROR(RSA, RSA_R_KEY_SIZE_TOO_SMALL); return 0; } + assert(BN_ucmp(rsa->n, rsa->e) > 0); return 1; } @@ -154,13 +172,8 @@ int rsa_default_encrypt(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out, goto err; } - if (rsa->flags & RSA_FLAG_CACHE_PUBLIC) { - if (BN_MONT_CTX_set_locked(&rsa->mont_n, &rsa->lock, rsa->n, ctx) == NULL) { - goto err; - } - } - - if (!rsa->meth->bn_mod_exp(result, f, rsa->e, rsa->n, ctx, rsa->mont_n)) { + if (!BN_MONT_CTX_set_locked(&rsa->mont_n, &rsa->lock, rsa->n, ctx) || + !BN_mod_exp_mont(result, f, rsa->e, rsa->n, ctx, rsa->mont_n)) { goto err; } @@ -201,6 +214,9 @@ int rsa_default_encrypt(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out, * |*index_used| and must be passed to |rsa_blinding_release| when finished. */ static BN_BLINDING *rsa_blinding_get(RSA *rsa, unsigned *index_used, BN_CTX *ctx) { + assert(ctx != NULL); + assert(rsa->mont_n != NULL); + BN_BLINDING *ret = NULL; BN_BLINDING **new_blindings; uint8_t *new_blindings_inuse; @@ -219,7 +235,7 @@ static BN_BLINDING *rsa_blinding_get(RSA *rsa, unsigned *index_used, } if (ret != NULL) { - CRYPTO_MUTEX_unlock(&rsa->lock); + CRYPTO_MUTEX_unlock_write(&rsa->lock); return ret; } @@ -228,8 +244,8 @@ static BN_BLINDING *rsa_blinding_get(RSA *rsa, unsigned *index_used, /* We didn't find a free BN_BLINDING to use so increase the length of * the arrays by one and use the newly created element. */ - CRYPTO_MUTEX_unlock(&rsa->lock); - ret = rsa_setup_blinding(rsa, ctx); + CRYPTO_MUTEX_unlock_write(&rsa->lock); + ret = BN_BLINDING_new(); if (ret == NULL) { return NULL; } @@ -248,7 +264,7 @@ static BN_BLINDING *rsa_blinding_get(RSA *rsa, unsigned *index_used, if (new_blindings == NULL) { goto err1; } - memcpy(new_blindings, rsa->blindings, + OPENSSL_memcpy(new_blindings, rsa->blindings, sizeof(BN_BLINDING *) * rsa->num_blindings); new_blindings[rsa->num_blindings] = ret; @@ -256,7 +272,7 @@ static BN_BLINDING *rsa_blinding_get(RSA *rsa, unsigned *index_used, if (new_blindings_inuse == NULL) { goto err2; } - memcpy(new_blindings_inuse, rsa->blindings_inuse, rsa->num_blindings); + OPENSSL_memcpy(new_blindings_inuse, rsa->blindings_inuse, rsa->num_blindings); new_blindings_inuse[rsa->num_blindings] = 1; *index_used = rsa->num_blindings; @@ -266,14 +282,14 @@ static BN_BLINDING *rsa_blinding_get(RSA *rsa, unsigned *index_used, rsa->blindings_inuse = new_blindings_inuse; rsa->num_blindings++; - CRYPTO_MUTEX_unlock(&rsa->lock); + CRYPTO_MUTEX_unlock_write(&rsa->lock); return ret; err2: OPENSSL_free(new_blindings); err1: - CRYPTO_MUTEX_unlock(&rsa->lock); + CRYPTO_MUTEX_unlock_write(&rsa->lock); BN_BLINDING_free(ret); return NULL; } @@ -290,7 +306,7 @@ static void rsa_blinding_release(RSA *rsa, BN_BLINDING *blinding, CRYPTO_MUTEX_lock_write(&rsa->lock); rsa->blindings_inuse[blinding_index] = 0; - CRYPTO_MUTEX_unlock(&rsa->lock); + CRYPTO_MUTEX_unlock_write(&rsa->lock); } /* signing */ @@ -409,33 +425,49 @@ int rsa_default_decrypt(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out, return ret; } -int rsa_default_verify_raw(RSA *rsa, size_t *out_len, uint8_t *out, - size_t max_out, const uint8_t *in, size_t in_len, - int padding) { +static int mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa, BN_CTX *ctx); + +int RSA_verify_raw(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out, + const uint8_t *in, size_t in_len, int padding) { + if (rsa->n == NULL || rsa->e == NULL) { + OPENSSL_PUT_ERROR(RSA, RSA_R_VALUE_MISSING); + return 0; + } + const unsigned rsa_size = RSA_size(rsa); BIGNUM *f, *result; - int ret = 0; int r = -1; - uint8_t *buf = NULL; - BN_CTX *ctx = NULL; if (max_out < rsa_size) { OPENSSL_PUT_ERROR(RSA, RSA_R_OUTPUT_BUFFER_TOO_SMALL); return 0; } + if (in_len != rsa_size) { + OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_LEN_NOT_EQUAL_TO_MOD_LEN); + return 0; + } + if (!check_modulus_and_exponent_sizes(rsa)) { return 0; } - ctx = BN_CTX_new(); + BN_CTX *ctx = BN_CTX_new(); if (ctx == NULL) { - goto err; + return 0; } + int ret = 0; + uint8_t *buf = NULL; + BN_CTX_start(ctx); f = BN_CTX_get(ctx); result = BN_CTX_get(ctx); + if (f == NULL || result == NULL) { + OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE); + goto err; + } + if (padding == RSA_NO_PADDING) { buf = out; } else { @@ -446,15 +478,6 @@ int rsa_default_verify_raw(RSA *rsa, size_t *out_len, uint8_t *out, goto err; } } - if (!f || !result) { - OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE); - goto err; - } - - if (in_len != rsa_size) { - OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_LEN_NOT_EQUAL_TO_MOD_LEN); - goto err; - } if (BN_bin2bn(in, in_len, f) == NULL) { goto err; @@ -465,13 +488,8 @@ int rsa_default_verify_raw(RSA *rsa, size_t *out_len, uint8_t *out, goto err; } - if (rsa->flags & RSA_FLAG_CACHE_PUBLIC) { - if (BN_MONT_CTX_set_locked(&rsa->mont_n, &rsa->lock, rsa->n, ctx) == NULL) { - goto err; - } - } - - if (!rsa->meth->bn_mod_exp(result, f, rsa->e, rsa->n, ctx, rsa->mont_n)) { + if (!BN_MONT_CTX_set_locked(&rsa->mont_n, &rsa->lock, rsa->n, ctx) || + !BN_mod_exp_mont(result, f, rsa->e, rsa->n, ctx, rsa->mont_n)) { goto err; } @@ -500,12 +518,9 @@ int rsa_default_verify_raw(RSA *rsa, size_t *out_len, uint8_t *out, } err: - if (ctx != NULL) { - BN_CTX_end(ctx); - BN_CTX_free(ctx); - } - if (padding != RSA_NO_PADDING && buf != NULL) { - OPENSSL_cleanse(buf, rsa_size); + BN_CTX_end(ctx); + BN_CTX_free(ctx); + if (buf != out) { OPENSSL_free(buf); } return ret; @@ -542,45 +557,64 @@ int rsa_default_private_transform(RSA *rsa, uint8_t *out, const uint8_t *in, goto err; } - if (!(rsa->flags & RSA_FLAG_NO_BLINDING)) { + if (!BN_MONT_CTX_set_locked(&rsa->mont_n, &rsa->lock, rsa->n, ctx)) { + OPENSSL_PUT_ERROR(RSA, ERR_R_INTERNAL_ERROR); + goto err; + } + + /* We cannot do blinding or verification without |e|, and continuing without + * those countermeasures is dangerous. However, the Java/Android RSA API + * requires support for keys where only |d| and |n| (and not |e|) are known. + * The callers that require that bad behavior set |RSA_FLAG_NO_BLINDING|. */ + int disable_security = (rsa->flags & RSA_FLAG_NO_BLINDING) && rsa->e == NULL; + + if (!disable_security) { + /* Keys without public exponents must have blinding explicitly disabled to + * be used. */ + if (rsa->e == NULL) { + OPENSSL_PUT_ERROR(RSA, RSA_R_NO_PUBLIC_EXPONENT); + goto err; + } + blinding = rsa_blinding_get(rsa, &blinding_index, ctx); if (blinding == NULL) { OPENSSL_PUT_ERROR(RSA, ERR_R_INTERNAL_ERROR); goto err; } - if (!BN_BLINDING_convert(f, blinding, ctx)) { + if (!BN_BLINDING_convert(f, blinding, rsa->e, rsa->mont_n, ctx)) { goto err; } } - if ((rsa->flags & RSA_FLAG_EXT_PKEY) || - ((rsa->p != NULL) && (rsa->q != NULL) && (rsa->dmp1 != NULL) && - (rsa->dmq1 != NULL) && (rsa->iqmp != NULL))) { - if (!rsa->meth->mod_exp(result, f, rsa, ctx)) { + if (rsa->p != NULL && rsa->q != NULL && rsa->e != NULL && rsa->dmp1 != NULL && + rsa->dmq1 != NULL && rsa->iqmp != NULL) { + if (!mod_exp(result, f, rsa, ctx)) { goto err; } - } else { - BIGNUM local_d; - BIGNUM *d = NULL; - - BN_init(&local_d); - d = &local_d; - BN_with_flags(d, rsa->d, BN_FLG_CONSTTIME); - - if (rsa->flags & RSA_FLAG_CACHE_PUBLIC) { - if (BN_MONT_CTX_set_locked(&rsa->mont_n, &rsa->lock, rsa->n, ctx) == - NULL) { - goto err; - } - } + } else if (!BN_mod_exp_mont_consttime(result, f, rsa->d, rsa->n, ctx, + rsa->mont_n)) { + goto err; + } - if (!rsa->meth->bn_mod_exp(result, f, d, rsa->n, ctx, rsa->mont_n)) { + /* Verify the result to protect against fault attacks as described in the + * 1997 paper "On the Importance of Checking Cryptographic Protocols for + * Faults" by Dan Boneh, Richard A. DeMillo, and Richard J. Lipton. Some + * implementations do this only when the CRT is used, but we do it in all + * cases. Section 6 of the aforementioned paper describes an attack that + * works when the CRT isn't used. That attack is much less likely to succeed + * than the CRT attack, but there have likely been improvements since 1997. + * + * This check is cheap assuming |e| is small; it almost always is. */ + if (!disable_security) { + BIGNUM *vrfy = BN_CTX_get(ctx); + if (vrfy == NULL || + !BN_mod_exp_mont(vrfy, result, rsa->e, rsa->n, ctx, rsa->mont_n) || + !BN_equal_consttime(vrfy, f)) { + OPENSSL_PUT_ERROR(RSA, ERR_R_INTERNAL_ERROR); goto err; } - } - if (blinding) { - if (!BN_BLINDING_invert(result, blinding, ctx)) { + if (!BN_BLINDING_invert(result, blinding, rsa->mont_n, ctx)) { goto err; } } @@ -605,9 +639,18 @@ int rsa_default_private_transform(RSA *rsa, uint8_t *out, const uint8_t *in, } static int mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa, BN_CTX *ctx) { + assert(ctx != NULL); + + assert(rsa->n != NULL); + assert(rsa->e != NULL); + assert(rsa->d != NULL); + assert(rsa->p != NULL); + assert(rsa->q != NULL); + assert(rsa->dmp1 != NULL); + assert(rsa->dmq1 != NULL); + assert(rsa->iqmp != NULL); + BIGNUM *r1, *m1, *vrfy; - BIGNUM local_dmp1, local_dmq1, local_c, local_r1; - BIGNUM *dmp1, *dmq1, *c, *pr1; int ret = 0; size_t i, num_additional_primes = 0; @@ -619,62 +662,38 @@ static int mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa, BN_CTX *ctx) { r1 = BN_CTX_get(ctx); m1 = BN_CTX_get(ctx); vrfy = BN_CTX_get(ctx); + if (r1 == NULL || + m1 == NULL || + vrfy == NULL) { + goto err; + } - { - BIGNUM local_p, local_q; - BIGNUM *p = NULL, *q = NULL; - - /* Make sure BN_mod_inverse in Montgomery intialization uses the - * BN_FLG_CONSTTIME flag. */ - BN_init(&local_p); - p = &local_p; - BN_with_flags(p, rsa->p, BN_FLG_CONSTTIME); - - BN_init(&local_q); - q = &local_q; - BN_with_flags(q, rsa->q, BN_FLG_CONSTTIME); - - if (rsa->flags & RSA_FLAG_CACHE_PRIVATE) { - if (BN_MONT_CTX_set_locked(&rsa->mont_p, &rsa->lock, p, ctx) == NULL) { - goto err; - } - if (BN_MONT_CTX_set_locked(&rsa->mont_q, &rsa->lock, q, ctx) == NULL) { - goto err; - } - } + if (!BN_MONT_CTX_set_locked(&rsa->mont_p, &rsa->lock, rsa->p, ctx) || + !BN_MONT_CTX_set_locked(&rsa->mont_q, &rsa->lock, rsa->q, ctx)) { + goto err; } - if (rsa->flags & RSA_FLAG_CACHE_PUBLIC) { - if (BN_MONT_CTX_set_locked(&rsa->mont_n, &rsa->lock, rsa->n, ctx) == NULL) { - goto err; - } + if (!BN_MONT_CTX_set_locked(&rsa->mont_n, &rsa->lock, rsa->n, ctx)) { + goto err; } /* compute I mod q */ - c = &local_c; - BN_with_flags(c, I, BN_FLG_CONSTTIME); - if (!BN_mod(r1, c, rsa->q, ctx)) { + if (!BN_mod(r1, I, rsa->q, ctx)) { goto err; } /* compute r1^dmq1 mod q */ - dmq1 = &local_dmq1; - BN_with_flags(dmq1, rsa->dmq1, BN_FLG_CONSTTIME); - if (!rsa->meth->bn_mod_exp(m1, r1, dmq1, rsa->q, ctx, rsa->mont_q)) { + if (!BN_mod_exp_mont_consttime(m1, r1, rsa->dmq1, rsa->q, ctx, rsa->mont_q)) { goto err; } /* compute I mod p */ - c = &local_c; - BN_with_flags(c, I, BN_FLG_CONSTTIME); - if (!BN_mod(r1, c, rsa->p, ctx)) { + if (!BN_mod(r1, I, rsa->p, ctx)) { goto err; } /* compute r1^dmp1 mod p */ - dmp1 = &local_dmp1; - BN_with_flags(dmp1, rsa->dmp1, BN_FLG_CONSTTIME); - if (!rsa->meth->bn_mod_exp(r0, r1, dmp1, rsa->p, ctx, rsa->mont_p)) { + if (!BN_mod_exp_mont_consttime(r0, r1, rsa->dmp1, rsa->p, ctx, rsa->mont_p)) { goto err; } @@ -693,11 +712,7 @@ static int mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa, BN_CTX *ctx) { goto err; } - /* Turn BN_FLG_CONSTTIME flag on before division operation */ - pr1 = &local_r1; - BN_with_flags(pr1, r1, BN_FLG_CONSTTIME); - - if (!BN_mod(r0, pr1, rsa->p, ctx)) { + if (!BN_mod(r0, r1, rsa->p, ctx)) { goto err; } @@ -721,74 +736,29 @@ static int mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa, BN_CTX *ctx) { for (i = 0; i < num_additional_primes; i++) { /* multi-prime RSA. */ - BIGNUM local_exp, local_prime; - BIGNUM *exp = &local_exp, *prime = &local_prime; RSA_additional_prime *ap = sk_RSA_additional_prime_value(rsa->additional_primes, i); - BN_with_flags(exp, ap->exp, BN_FLG_CONSTTIME); - BN_with_flags(prime, ap->prime, BN_FLG_CONSTTIME); - /* c will already point to a BIGNUM with the correct flags. */ - if (!BN_mod(r1, c, prime, ctx)) { - goto err; - } - - if ((rsa->flags & RSA_FLAG_CACHE_PRIVATE) && - !BN_MONT_CTX_set_locked(&ap->mont, &rsa->lock, prime, ctx)) { + if (!BN_mod(r1, I, ap->prime, ctx)) { goto err; } - if (!rsa->meth->bn_mod_exp(m1, r1, exp, prime, ctx, ap->mont)) { + if (!BN_MONT_CTX_set_locked(&ap->mont, &rsa->lock, ap->prime, ctx) || + !BN_mod_exp_mont_consttime(m1, r1, ap->exp, ap->prime, ctx, ap->mont)) { goto err; } - BN_set_flags(m1, BN_FLG_CONSTTIME); - if (!BN_sub(m1, m1, r0) || !BN_mul(m1, m1, ap->coeff, ctx) || - !BN_mod(m1, m1, prime, ctx) || - (BN_is_negative(m1) && !BN_add(m1, m1, prime)) || + !BN_mod(m1, m1, ap->prime, ctx) || + (BN_is_negative(m1) && !BN_add(m1, m1, ap->prime)) || !BN_mul(m1, m1, ap->r, ctx) || !BN_add(r0, r0, m1)) { goto err; } } - if (rsa->e && rsa->n) { - if (!rsa->meth->bn_mod_exp(vrfy, r0, rsa->e, rsa->n, ctx, rsa->mont_n)) { - goto err; - } - /* If 'I' was greater than (or equal to) rsa->n, the operation - * will be equivalent to using 'I mod n'. However, the result of - * the verify will *always* be less than 'n' so we don't check - * for absolute equality, just congruency. */ - if (!BN_sub(vrfy, vrfy, I)) { - goto err; - } - if (!BN_mod(vrfy, vrfy, rsa->n, ctx)) { - goto err; - } - if (BN_is_negative(vrfy)) { - if (!BN_add(vrfy, vrfy, rsa->n)) { - goto err; - } - } - if (!BN_is_zero(vrfy)) { - /* 'I' and 'vrfy' aren't congruent mod n. Don't leak - * miscalculated CRT output, just do a raw (slower) - * mod_exp and return that instead. */ - - BIGNUM local_d; - BIGNUM *d = NULL; - - d = &local_d; - BN_with_flags(d, rsa->d, BN_FLG_CONSTTIME); - if (!rsa->meth->bn_mod_exp(r0, I, d, rsa->n, ctx, rsa->mont_n)) { - goto err; - } - } - } ret = 1; err: @@ -799,8 +769,6 @@ static int mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa, BN_CTX *ctx) { int rsa_default_multi_prime_keygen(RSA *rsa, int bits, int num_primes, BIGNUM *e_value, BN_GENCB *cb) { BIGNUM *r0 = NULL, *r1 = NULL, *r2 = NULL, *r3 = NULL, *tmp; - BIGNUM local_r0, local_d, local_p; - BIGNUM *pr0, *d, *p; int prime_bits, ok = -1, n = 0, i, j; BN_CTX *ctx = NULL; STACK_OF(RSA_additional_prime) *additional_primes = NULL; @@ -836,7 +804,7 @@ int rsa_default_multi_prime_keygen(RSA *rsa, int bits, int num_primes, if (ap == NULL) { goto err; } - memset(ap, 0, sizeof(RSA_additional_prime)); + OPENSSL_memset(ap, 0, sizeof(RSA_additional_prime)); ap->prime = BN_new(); ap->exp = BN_new(); ap->coeff = BN_new(); @@ -1029,31 +997,27 @@ int rsa_default_multi_prime_keygen(RSA *rsa, int bits, int num_primes, goto err; } } - pr0 = &local_r0; - BN_with_flags(pr0, r0, BN_FLG_CONSTTIME); - if (!BN_mod_inverse(rsa->d, rsa->e, pr0, ctx)) { + if (!BN_mod_inverse(rsa->d, rsa->e, r0, ctx)) { goto err; /* d */ } - /* set up d for correct BN_FLG_CONSTTIME flag */ - d = &local_d; - BN_with_flags(d, rsa->d, BN_FLG_CONSTTIME); - /* calculate d mod (p-1) */ - if (!BN_mod(rsa->dmp1, d, r1, ctx)) { + if (!BN_mod(rsa->dmp1, rsa->d, r1, ctx)) { goto err; } /* calculate d mod (q-1) */ - if (!BN_mod(rsa->dmq1, d, r2, ctx)) { + if (!BN_mod(rsa->dmq1, rsa->d, r2, ctx)) { goto err; } - /* calculate inverse of q mod p */ - p = &local_p; - BN_with_flags(p, rsa->p, BN_FLG_CONSTTIME); - - if (!BN_mod_inverse(rsa->iqmp, rsa->q, p, ctx)) { + /* Calculate inverse of q mod p. Note that although RSA key generation is far + * from constant-time, |bn_mod_inverse_secret_prime| uses the same modular + * exponentation logic as in RSA private key operations and, if the RSAZ-1024 + * code is enabled, will be optimized for common RSA prime sizes. */ + if (!BN_MONT_CTX_set_locked(&rsa->mont_p, &rsa->lock, rsa->p, ctx) || + !bn_mod_inverse_secret_prime(rsa->iqmp, rsa->q, rsa->p, ctx, + rsa->mont_p)) { goto err; } @@ -1062,15 +1026,24 @@ int rsa_default_multi_prime_keygen(RSA *rsa, int bits, int num_primes, sk_RSA_additional_prime_value(additional_primes, i - 2); if (!BN_sub(ap->exp, ap->prime, BN_value_one()) || !BN_mod(ap->exp, rsa->d, ap->exp, ctx) || - !BN_mod_inverse(ap->coeff, ap->r, ap->prime, ctx)) { + !BN_MONT_CTX_set_locked(&ap->mont, &rsa->lock, ap->prime, ctx) || + !bn_mod_inverse_secret_prime(ap->coeff, ap->r, ap->prime, ctx, + ap->mont)) { goto err; } } - ok = 1; rsa->additional_primes = additional_primes; additional_primes = NULL; + /* The key generation process is complex and thus error-prone. It could be + * disastrous to generate and then use a bad key so double-check that the key + * makes sense. */ + ok = RSA_check_key(rsa); + if (!ok) { + OPENSSL_PUT_ERROR(RSA, RSA_R_INTERNAL_ERROR); + } + err: if (ok == -1) { OPENSSL_PUT_ERROR(RSA, ERR_LIB_BN); @@ -1090,9 +1063,9 @@ int rsa_default_keygen(RSA *rsa, int bits, BIGNUM *e_value, BN_GENCB *cb) { cb); } -/* Many of these methods are NULL to more easily drop unused functions. The - * wrapper functions will select the appropriate |rsa_default_*| for all - * methods. */ +/* All of the methods are NULL to make it easier for the compiler/linker to drop + * unused functions. The wrapper functions will select the appropriate + * |rsa_default_*| implementation. */ const RSA_METHOD RSA_default_method = { { 0 /* references */, @@ -1115,8 +1088,8 @@ const RSA_METHOD RSA_default_method = { NULL /* private_transform (defaults to rsa_default_private_transform) */, - mod_exp, - BN_mod_exp_mont /* bn_mod_exp */, + NULL /* mod_exp (ignored) */, + NULL /* bn_mod_exp (ignored) */, RSA_FLAG_CACHE_PUBLIC | RSA_FLAG_CACHE_PRIVATE, diff --git a/Sources/BoringSSL/crypto/sha/sha1-altivec.c b/Sources/BoringSSL/crypto/sha/sha1-altivec.c new file mode 100644 index 000000000..500986e14 --- /dev/null +++ b/Sources/BoringSSL/crypto/sha/sha1-altivec.c @@ -0,0 +1,346 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +/* Altivec-optimized SHA1 in C. This is tested on ppc64le only. + * + * References: + * https://software.intel.com/en-us/articles/improving-the-performance-of-the-secure-hash-algorithm-1 + * http://arctic.org/~dean/crypto/sha1.html + * + * This code used the generic SHA-1 from OpenSSL as a basis and AltiVec + * optimisations were added on top. */ + +#include + +#if defined(OPENSSL_PPC64LE) + +#include + +void sha1_block_data_order(uint32_t *state, const uint8_t *data, size_t num); + +static uint32_t rotate(uint32_t a, int n) { return (a << n) | (a >> (32 - n)); } + +typedef vector unsigned int vec_uint32_t; +typedef vector unsigned char vec_uint8_t; + +/* Vector constants */ +static const vec_uint8_t k_swap_endianness = {3, 2, 1, 0, 7, 6, 5, 4, + 11, 10, 9, 8, 15, 14, 13, 12}; + +/* Shift amounts for byte and bit shifts and rotations */ +static const vec_uint8_t k_4_bytes = {32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32}; +static const vec_uint8_t k_12_bytes = {96, 96, 96, 96, 96, 96, 96, 96, + 96, 96, 96, 96, 96, 96, 96, 96}; + +#define K_00_19 0x5a827999UL +#define K_20_39 0x6ed9eba1UL +#define K_40_59 0x8f1bbcdcUL +#define K_60_79 0xca62c1d6UL + +/* Vector versions of the above. */ +static const vec_uint32_t K_00_19_x_4 = {K_00_19, K_00_19, K_00_19, K_00_19}; +static const vec_uint32_t K_20_39_x_4 = {K_20_39, K_20_39, K_20_39, K_20_39}; +static const vec_uint32_t K_40_59_x_4 = {K_40_59, K_40_59, K_40_59, K_40_59}; +static const vec_uint32_t K_60_79_x_4 = {K_60_79, K_60_79, K_60_79, K_60_79}; + +/* vector message scheduling: compute message schedule for round i..i+3 where i + * is divisible by 4. We return the schedule w[i..i+3] as a vector. In + * addition, we also precompute sum w[i..+3] and an additive constant K. This + * is done to offload some computation of f() in the integer execution units. + * + * Byte shifting code below may not be correct for big-endian systems. */ +static vec_uint32_t sched_00_15(vec_uint32_t *pre_added, const void *data, + vec_uint32_t k) { + const vec_uint32_t v = *((const vec_uint32_t *)data); + const vec_uint32_t w = vec_perm(v, v, k_swap_endianness); + vec_st(w + k, 0, pre_added); + return w; +} + +/* Compute w[i..i+3] using these steps for i in [16, 20, 24, 28] + * + * w'[i ] = (w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16]) <<< 1 + * w'[i+1] = (w[i-2] ^ w[i-7] ^ w[i-13] ^ w[i-15]) <<< 1 + * w'[i+2] = (w[i-1] ^ w[i-6] ^ w[i-12] ^ w[i-14]) <<< 1 + * w'[i+3] = ( 0 ^ w[i-5] ^ w[i-11] ^ w[i-13]) <<< 1 + * + * w[ i] = w'[ i] + * w[i+1] = w'[i+1] + * w[i+2] = w'[i+2] + * w[i+3] = w'[i+3] ^ (w'[i] <<< 1) */ +static vec_uint32_t sched_16_31(vec_uint32_t *pre_added, vec_uint32_t minus_4, + vec_uint32_t minus_8, vec_uint32_t minus_12, + vec_uint32_t minus_16, vec_uint32_t k) { + const vec_uint32_t minus_3 = vec_sro(minus_4, k_4_bytes); + const vec_uint32_t minus_14 = vec_sld((minus_12), (minus_16), 8); + const vec_uint32_t k_1_bit = vec_splat_u32(1); + const vec_uint32_t w_prime = + vec_rl(minus_3 ^ minus_8 ^ minus_14 ^ minus_16, k_1_bit); + const vec_uint32_t w = + w_prime ^ vec_rl(vec_slo(w_prime, k_12_bytes), k_1_bit); + vec_st(w + k, 0, pre_added); + return w; +} + +/* Compute w[i..i+3] using this relation for i in [32, 36, 40 ... 76] + * w[i] = (w[i-6] ^ w[i-16] ^ w[i-28] ^ w[i-32]), 2) <<< 2 */ +static vec_uint32_t sched_32_79(vec_uint32_t *pre_added, vec_uint32_t minus_4, + vec_uint32_t minus_8, vec_uint32_t minus_16, + vec_uint32_t minus_28, vec_uint32_t minus_32, + vec_uint32_t k) { + const vec_uint32_t minus_6 = vec_sld(minus_4, minus_8, 8); + const vec_uint32_t k_2_bits = vec_splat_u32(2); + const vec_uint32_t w = + vec_rl(minus_6 ^ minus_16 ^ minus_28 ^ minus_32, k_2_bits); + vec_st(w + k, 0, pre_added); + return w; +} + +/* As pointed out by Wei Dai , F() below can be simplified + * to the code in F_00_19. Wei attributes these optimisations to Peter + * Gutmann's SHS code, and he attributes it to Rich Schroeppel. #define + * F(x,y,z) (((x) & (y)) | ((~(x)) & (z))) I've just become aware of another + * tweak to be made, again from Wei Dai, in F_40_59, (x&a)|(y&a) -> (x|y)&a */ +#define F_00_19(b, c, d) ((((c) ^ (d)) & (b)) ^ (d)) +#define F_20_39(b, c, d) ((b) ^ (c) ^ (d)) +#define F_40_59(b, c, d) (((b) & (c)) | (((b) | (c)) & (d))) +#define F_60_79(b, c, d) F_20_39(b, c, d) + +/* We pre-added the K constants during message scheduling. */ +#define BODY_00_19(i, a, b, c, d, e, f) \ + do { \ + (f) = w[i] + (e) + rotate((a), 5) + F_00_19((b), (c), (d)); \ + (b) = rotate((b), 30); \ + } while (0) + +#define BODY_20_39(i, a, b, c, d, e, f) \ + do { \ + (f) = w[i] + (e) + rotate((a), 5) + F_20_39((b), (c), (d)); \ + (b) = rotate((b), 30); \ + } while (0) + +#define BODY_40_59(i, a, b, c, d, e, f) \ + do { \ + (f) = w[i] + (e) + rotate((a), 5) + F_40_59((b), (c), (d)); \ + (b) = rotate((b), 30); \ + } while (0) + +#define BODY_60_79(i, a, b, c, d, e, f) \ + do { \ + (f) = w[i] + (e) + rotate((a), 5) + F_60_79((b), (c), (d)); \ + (b) = rotate((b), 30); \ + } while (0) + +void sha1_block_data_order(uint32_t *state, const uint8_t *data, size_t num) { + uint32_t A, B, C, D, E, T; + + A = state[0]; + B = state[1]; + C = state[2]; + D = state[3]; + E = state[4]; + + for (;;) { + vec_uint32_t vw[20]; + const uint32_t *w = (const uint32_t *)&vw; + + vec_uint32_t k = K_00_19_x_4; + const vec_uint32_t w0 = sched_00_15(vw + 0, data + 0, k); + BODY_00_19(0, A, B, C, D, E, T); + BODY_00_19(1, T, A, B, C, D, E); + BODY_00_19(2, E, T, A, B, C, D); + BODY_00_19(3, D, E, T, A, B, C); + + const vec_uint32_t w4 = sched_00_15(vw + 1, data + 16, k); + BODY_00_19(4, C, D, E, T, A, B); + BODY_00_19(5, B, C, D, E, T, A); + BODY_00_19(6, A, B, C, D, E, T); + BODY_00_19(7, T, A, B, C, D, E); + + const vec_uint32_t w8 = sched_00_15(vw + 2, data + 32, k); + BODY_00_19(8, E, T, A, B, C, D); + BODY_00_19(9, D, E, T, A, B, C); + BODY_00_19(10, C, D, E, T, A, B); + BODY_00_19(11, B, C, D, E, T, A); + + const vec_uint32_t w12 = sched_00_15(vw + 3, data + 48, k); + BODY_00_19(12, A, B, C, D, E, T); + BODY_00_19(13, T, A, B, C, D, E); + BODY_00_19(14, E, T, A, B, C, D); + BODY_00_19(15, D, E, T, A, B, C); + + const vec_uint32_t w16 = sched_16_31(vw + 4, w12, w8, w4, w0, k); + BODY_00_19(16, C, D, E, T, A, B); + BODY_00_19(17, B, C, D, E, T, A); + BODY_00_19(18, A, B, C, D, E, T); + BODY_00_19(19, T, A, B, C, D, E); + + k = K_20_39_x_4; + const vec_uint32_t w20 = sched_16_31(vw + 5, w16, w12, w8, w4, k); + BODY_20_39(20, E, T, A, B, C, D); + BODY_20_39(21, D, E, T, A, B, C); + BODY_20_39(22, C, D, E, T, A, B); + BODY_20_39(23, B, C, D, E, T, A); + + const vec_uint32_t w24 = sched_16_31(vw + 6, w20, w16, w12, w8, k); + BODY_20_39(24, A, B, C, D, E, T); + BODY_20_39(25, T, A, B, C, D, E); + BODY_20_39(26, E, T, A, B, C, D); + BODY_20_39(27, D, E, T, A, B, C); + + const vec_uint32_t w28 = sched_16_31(vw + 7, w24, w20, w16, w12, k); + BODY_20_39(28, C, D, E, T, A, B); + BODY_20_39(29, B, C, D, E, T, A); + BODY_20_39(30, A, B, C, D, E, T); + BODY_20_39(31, T, A, B, C, D, E); + + const vec_uint32_t w32 = sched_32_79(vw + 8, w28, w24, w16, w4, w0, k); + BODY_20_39(32, E, T, A, B, C, D); + BODY_20_39(33, D, E, T, A, B, C); + BODY_20_39(34, C, D, E, T, A, B); + BODY_20_39(35, B, C, D, E, T, A); + + const vec_uint32_t w36 = sched_32_79(vw + 9, w32, w28, w20, w8, w4, k); + BODY_20_39(36, A, B, C, D, E, T); + BODY_20_39(37, T, A, B, C, D, E); + BODY_20_39(38, E, T, A, B, C, D); + BODY_20_39(39, D, E, T, A, B, C); + + k = K_40_59_x_4; + const vec_uint32_t w40 = sched_32_79(vw + 10, w36, w32, w24, w12, w8, k); + BODY_40_59(40, C, D, E, T, A, B); + BODY_40_59(41, B, C, D, E, T, A); + BODY_40_59(42, A, B, C, D, E, T); + BODY_40_59(43, T, A, B, C, D, E); + + const vec_uint32_t w44 = sched_32_79(vw + 11, w40, w36, w28, w16, w12, k); + BODY_40_59(44, E, T, A, B, C, D); + BODY_40_59(45, D, E, T, A, B, C); + BODY_40_59(46, C, D, E, T, A, B); + BODY_40_59(47, B, C, D, E, T, A); + + const vec_uint32_t w48 = sched_32_79(vw + 12, w44, w40, w32, w20, w16, k); + BODY_40_59(48, A, B, C, D, E, T); + BODY_40_59(49, T, A, B, C, D, E); + BODY_40_59(50, E, T, A, B, C, D); + BODY_40_59(51, D, E, T, A, B, C); + + const vec_uint32_t w52 = sched_32_79(vw + 13, w48, w44, w36, w24, w20, k); + BODY_40_59(52, C, D, E, T, A, B); + BODY_40_59(53, B, C, D, E, T, A); + BODY_40_59(54, A, B, C, D, E, T); + BODY_40_59(55, T, A, B, C, D, E); + + const vec_uint32_t w56 = sched_32_79(vw + 14, w52, w48, w40, w28, w24, k); + BODY_40_59(56, E, T, A, B, C, D); + BODY_40_59(57, D, E, T, A, B, C); + BODY_40_59(58, C, D, E, T, A, B); + BODY_40_59(59, B, C, D, E, T, A); + + k = K_60_79_x_4; + const vec_uint32_t w60 = sched_32_79(vw + 15, w56, w52, w44, w32, w28, k); + BODY_60_79(60, A, B, C, D, E, T); + BODY_60_79(61, T, A, B, C, D, E); + BODY_60_79(62, E, T, A, B, C, D); + BODY_60_79(63, D, E, T, A, B, C); + + const vec_uint32_t w64 = sched_32_79(vw + 16, w60, w56, w48, w36, w32, k); + BODY_60_79(64, C, D, E, T, A, B); + BODY_60_79(65, B, C, D, E, T, A); + BODY_60_79(66, A, B, C, D, E, T); + BODY_60_79(67, T, A, B, C, D, E); + + const vec_uint32_t w68 = sched_32_79(vw + 17, w64, w60, w52, w40, w36, k); + BODY_60_79(68, E, T, A, B, C, D); + BODY_60_79(69, D, E, T, A, B, C); + BODY_60_79(70, C, D, E, T, A, B); + BODY_60_79(71, B, C, D, E, T, A); + + const vec_uint32_t w72 = sched_32_79(vw + 18, w68, w64, w56, w44, w40, k); + BODY_60_79(72, A, B, C, D, E, T); + BODY_60_79(73, T, A, B, C, D, E); + BODY_60_79(74, E, T, A, B, C, D); + BODY_60_79(75, D, E, T, A, B, C); + + /* We don't use the last value */ + (void)sched_32_79(vw + 19, w72, w68, w60, w48, w44, k); + BODY_60_79(76, C, D, E, T, A, B); + BODY_60_79(77, B, C, D, E, T, A); + BODY_60_79(78, A, B, C, D, E, T); + BODY_60_79(79, T, A, B, C, D, E); + + const uint32_t mask = 0xffffffffUL; + state[0] = (state[0] + E) & mask; + state[1] = (state[1] + T) & mask; + state[2] = (state[2] + A) & mask; + state[3] = (state[3] + B) & mask; + state[4] = (state[4] + C) & mask; + + data += 64; + if (--num == 0) { + break; + } + + A = state[0]; + B = state[1]; + C = state[2]; + D = state[3]; + E = state[4]; + } +} + +#endif /* OPENSSL_PPC64LE */ diff --git a/Sources/BoringSSL/crypto/sha/sha1.c b/Sources/BoringSSL/crypto/sha/sha1.c index 74e841caf..7c7271322 100644 --- a/Sources/BoringSSL/crypto/sha/sha1.c +++ b/Sources/BoringSSL/crypto/sha/sha1.c @@ -60,15 +60,18 @@ #include +#include "../internal.h" + #if !defined(OPENSSL_NO_ASM) && \ (defined(OPENSSL_X86) || defined(OPENSSL_X86_64) || \ - defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64)) + defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64) || \ + defined(OPENSSL_PPC64LE)) #define SHA1_ASM #endif int SHA1_Init(SHA_CTX *sha) { - memset(sha, 0, sizeof(SHA_CTX)); + OPENSSL_memset(sha, 0, sizeof(SHA_CTX)); sha->h[0] = 0x67452301UL; sha->h[1] = 0xefcdab89UL; sha->h[2] = 0x98badcfeUL; @@ -119,7 +122,10 @@ uint8_t *SHA1(const uint8_t *data, size_t len, uint8_t *out) { #define HASH_BLOCK_DATA_ORDER sha1_block_data_order #define ROTATE(a, n) (((a) << (n)) | ((a) >> (32 - (n)))) #define Xupdate(a, ix, ia, ib, ic, id) \ - ((a) = (ia ^ ib ^ ic ^ id), ix = (a) = ROTATE((a), 1)) + do { \ + (a) = ((ia) ^ (ib) ^ (ic) ^ (id)); \ + (ix) = (a) = ROTATE((a), 1); \ + } while (0) #ifndef SHA1_ASM static @@ -143,34 +149,46 @@ void sha1_block_data_order(uint32_t *state, const uint8_t *data, size_t num); #define F_40_59(b, c, d) (((b) & (c)) | (((b) | (c)) & (d))) #define F_60_79(b, c, d) F_20_39(b, c, d) -#define BODY_00_15(i, a, b, c, d, e, f, xi) \ - (f) = xi + (e) + K_00_19 + ROTATE((a), 5) + F_00_19((b), (c), (d)); \ - (b) = ROTATE((b), 30); +#define BODY_00_15(i, a, b, c, d, e, f, xi) \ + do { \ + (f) = (xi) + (e) + K_00_19 + ROTATE((a), 5) + F_00_19((b), (c), (d)); \ + (b) = ROTATE((b), 30); \ + } while (0) -#define BODY_16_19(i, a, b, c, d, e, f, xi, xa, xb, xc, xd) \ - Xupdate(f, xi, xa, xb, xc, xd); \ - (f) += (e) + K_00_19 + ROTATE((a), 5) + F_00_19((b), (c), (d)); \ - (b) = ROTATE((b), 30); +#define BODY_16_19(i, a, b, c, d, e, f, xi, xa, xb, xc, xd) \ + do { \ + Xupdate(f, xi, xa, xb, xc, xd); \ + (f) += (e) + K_00_19 + ROTATE((a), 5) + F_00_19((b), (c), (d)); \ + (b) = ROTATE((b), 30); \ + } while (0) -#define BODY_20_31(i, a, b, c, d, e, f, xi, xa, xb, xc, xd) \ - Xupdate(f, xi, xa, xb, xc, xd); \ - (f) += (e) + K_20_39 + ROTATE((a), 5) + F_20_39((b), (c), (d)); \ - (b) = ROTATE((b), 30); +#define BODY_20_31(i, a, b, c, d, e, f, xi, xa, xb, xc, xd) \ + do { \ + Xupdate(f, xi, xa, xb, xc, xd); \ + (f) += (e) + K_20_39 + ROTATE((a), 5) + F_20_39((b), (c), (d)); \ + (b) = ROTATE((b), 30); \ + } while (0) -#define BODY_32_39(i, a, b, c, d, e, f, xa, xb, xc, xd) \ - Xupdate(f, xa, xa, xb, xc, xd); \ - (f) += (e) + K_20_39 + ROTATE((a), 5) + F_20_39((b), (c), (d)); \ - (b) = ROTATE((b), 30); +#define BODY_32_39(i, a, b, c, d, e, f, xa, xb, xc, xd) \ + do { \ + Xupdate(f, xa, xa, xb, xc, xd); \ + (f) += (e) + K_20_39 + ROTATE((a), 5) + F_20_39((b), (c), (d)); \ + (b) = ROTATE((b), 30); \ + } while (0) -#define BODY_40_59(i, a, b, c, d, e, f, xa, xb, xc, xd) \ - Xupdate(f, xa, xa, xb, xc, xd); \ - (f) += (e) + K_40_59 + ROTATE((a), 5) + F_40_59((b), (c), (d)); \ - (b) = ROTATE((b), 30); +#define BODY_40_59(i, a, b, c, d, e, f, xa, xb, xc, xd) \ + do { \ + Xupdate(f, xa, xa, xb, xc, xd); \ + (f) += (e) + K_40_59 + ROTATE((a), 5) + F_40_59((b), (c), (d)); \ + (b) = ROTATE((b), 30); \ + } while (0) -#define BODY_60_79(i, a, b, c, d, e, f, xa, xb, xc, xd) \ - Xupdate(f, xa, xa, xb, xc, xd); \ - (f) = xa + (e) + K_60_79 + ROTATE((a), 5) + F_60_79((b), (c), (d)); \ - (b) = ROTATE((b), 30); +#define BODY_60_79(i, a, b, c, d, e, f, xa, xb, xc, xd) \ + do { \ + Xupdate(f, xa, xa, xb, xc, xd); \ + (f) = (xa) + (e) + K_60_79 + ROTATE((a), 5) + F_60_79((b), (c), (d)); \ + (b) = ROTATE((b), 30); \ + } while (0) #ifdef X #undef X @@ -199,51 +217,51 @@ static void sha1_block_data_order(uint32_t *state, const uint8_t *data, E = state[4]; for (;;) { - (void)HOST_c2l(data, l); + HOST_c2l(data, l); X(0) = l; - (void)HOST_c2l(data, l); + HOST_c2l(data, l); X(1) = l; BODY_00_15(0, A, B, C, D, E, T, X(0)); - (void)HOST_c2l(data, l); + HOST_c2l(data, l); X(2) = l; BODY_00_15(1, T, A, B, C, D, E, X(1)); - (void)HOST_c2l(data, l); + HOST_c2l(data, l); X(3) = l; BODY_00_15(2, E, T, A, B, C, D, X(2)); - (void)HOST_c2l(data, l); + HOST_c2l(data, l); X(4) = l; BODY_00_15(3, D, E, T, A, B, C, X(3)); - (void)HOST_c2l(data, l); + HOST_c2l(data, l); X(5) = l; BODY_00_15(4, C, D, E, T, A, B, X(4)); - (void)HOST_c2l(data, l); + HOST_c2l(data, l); X(6) = l; BODY_00_15(5, B, C, D, E, T, A, X(5)); - (void)HOST_c2l(data, l); + HOST_c2l(data, l); X(7) = l; BODY_00_15(6, A, B, C, D, E, T, X(6)); - (void)HOST_c2l(data, l); + HOST_c2l(data, l); X(8) = l; BODY_00_15(7, T, A, B, C, D, E, X(7)); - (void)HOST_c2l(data, l); + HOST_c2l(data, l); X(9) = l; BODY_00_15(8, E, T, A, B, C, D, X(8)); - (void)HOST_c2l(data, l); + HOST_c2l(data, l); X(10) = l; BODY_00_15(9, D, E, T, A, B, C, X(9)); - (void)HOST_c2l(data, l); + HOST_c2l(data, l); X(11) = l; BODY_00_15(10, C, D, E, T, A, B, X(10)); - (void)HOST_c2l(data, l); + HOST_c2l(data, l); X(12) = l; BODY_00_15(11, B, C, D, E, T, A, X(11)); - (void)HOST_c2l(data, l); + HOST_c2l(data, l); X(13) = l; BODY_00_15(12, A, B, C, D, E, T, X(12)); - (void)HOST_c2l(data, l); + HOST_c2l(data, l); X(14) = l; BODY_00_15(13, T, A, B, C, D, E, X(13)); - (void)HOST_c2l(data, l); + HOST_c2l(data, l); X(15) = l; BODY_00_15(14, E, T, A, B, C, D, X(14)); BODY_00_15(15, D, E, T, A, B, C, X(15)); diff --git a/Sources/BoringSSL/crypto/sha/sha256.c b/Sources/BoringSSL/crypto/sha/sha256.c index 0ddacbad0..fb950d75f 100644 --- a/Sources/BoringSSL/crypto/sha/sha256.c +++ b/Sources/BoringSSL/crypto/sha/sha256.c @@ -60,6 +60,8 @@ #include +#include "../internal.h" + #if !defined(OPENSSL_NO_ASM) && \ (defined(OPENSSL_X86) || defined(OPENSSL_X86_64) || \ @@ -68,7 +70,7 @@ #endif int SHA224_Init(SHA256_CTX *sha) { - memset(sha, 0, sizeof(SHA256_CTX)); + OPENSSL_memset(sha, 0, sizeof(SHA256_CTX)); sha->h[0] = 0xc1059ed8UL; sha->h[1] = 0x367cd507UL; sha->h[2] = 0x3070dd17UL; @@ -82,7 +84,7 @@ int SHA224_Init(SHA256_CTX *sha) { } int SHA256_Init(SHA256_CTX *sha) { - memset(sha, 0, sizeof(SHA256_CTX)); + OPENSSL_memset(sha, 0, sizeof(SHA256_CTX)); sha->h[0] = 0x6a09e667UL; sha->h[1] = 0xbb67ae85UL; sha->h[2] = 0x3c6ef372UL; @@ -104,8 +106,8 @@ uint8_t *SHA224(const uint8_t *data, size_t len, uint8_t *out) { out = buf; } SHA224_Init(&ctx); - SHA256_Update(&ctx, data, len); - SHA256_Final(out, &ctx); + SHA224_Update(&ctx, data, len); + SHA224_Final(out, &ctx); OPENSSL_cleanse(&ctx, sizeof(ctx)); return out; } diff --git a/Sources/BoringSSL/crypto/sha/sha512.c b/Sources/BoringSSL/crypto/sha/sha512.c index 6ad8d40ce..876115082 100644 --- a/Sources/BoringSSL/crypto/sha/sha512.c +++ b/Sources/BoringSSL/crypto/sha/sha512.c @@ -60,6 +60,8 @@ #include +#include "../internal.h" + /* IMPLEMENTATION NOTES. * @@ -129,8 +131,8 @@ uint8_t *SHA384(const uint8_t *data, size_t len, uint8_t *out) { } SHA384_Init(&ctx); - SHA512_Update(&ctx, data, len); - SHA512_Final(out, &ctx); + SHA384_Update(&ctx, data, len); + SHA384_Final(out, &ctx); OPENSSL_cleanse(&ctx, sizeof(ctx)); return out; } @@ -164,14 +166,14 @@ int SHA384_Update(SHA512_CTX *sha, const void *data, size_t len) { return SHA512_Update(sha, data, len); } -void SHA512_Transform(SHA512_CTX *c, const uint8_t *data) { +void SHA512_Transform(SHA512_CTX *c, const uint8_t *block) { #ifndef SHA512_BLOCK_CAN_MANAGE_UNALIGNED_DATA - if ((size_t)data % sizeof(c->u.d[0]) != 0) { - memcpy(c->u.p, data, sizeof(c->u.p)); - data = c->u.p; + if ((size_t)block % sizeof(c->u.d[0]) != 0) { + OPENSSL_memcpy(c->u.p, block, sizeof(c->u.p)); + block = c->u.p; } #endif - sha512_block_data_order(c->h, (uint64_t *)data, 1); + sha512_block_data_order(c->h, (uint64_t *)block, 1); } int SHA512_Update(SHA512_CTX *c, const void *in_data, size_t len) { @@ -196,11 +198,11 @@ int SHA512_Update(SHA512_CTX *c, const void *in_data, size_t len) { size_t n = sizeof(c->u) - c->num; if (len < n) { - memcpy(p + c->num, data, len); + OPENSSL_memcpy(p + c->num, data, len); c->num += (unsigned int)len; return 1; } else { - memcpy(p + c->num, data, n), c->num = 0; + OPENSSL_memcpy(p + c->num, data, n), c->num = 0; len -= n; data += n; sha512_block_data_order(c->h, (uint64_t *)p, 1); @@ -211,7 +213,7 @@ int SHA512_Update(SHA512_CTX *c, const void *in_data, size_t len) { #ifndef SHA512_BLOCK_CAN_MANAGE_UNALIGNED_DATA if ((size_t)data % sizeof(c->u.d[0]) != 0) { while (len >= sizeof(c->u)) { - memcpy(p, data, sizeof(c->u)); + OPENSSL_memcpy(p, data, sizeof(c->u)); sha512_block_data_order(c->h, (uint64_t *)p, 1); len -= sizeof(c->u); data += sizeof(c->u); @@ -227,7 +229,7 @@ int SHA512_Update(SHA512_CTX *c, const void *in_data, size_t len) { } if (len != 0) { - memcpy(p, data, len); + OPENSSL_memcpy(p, data, len); c->num = (int)len; } @@ -241,12 +243,12 @@ int SHA512_Final(uint8_t *md, SHA512_CTX *sha) { p[n] = 0x80; /* There always is a room for one */ n++; if (n > (sizeof(sha->u) - 16)) { - memset(p + n, 0, sizeof(sha->u) - n); + OPENSSL_memset(p + n, 0, sizeof(sha->u) - n); n = 0; sha512_block_data_order(sha->h, (uint64_t *)p, 1); } - memset(p + n, 0, sizeof(sha->u) - 16 - n); + OPENSSL_memset(p + n, 0, sizeof(sha->u) - 16 - n); p[sizeof(sha->u) - 1] = (uint8_t)(sha->Nl); p[sizeof(sha->u) - 2] = (uint8_t)(sha->Nl >> 8); p[sizeof(sha->u) - 3] = (uint8_t)(sha->Nl >> 16); diff --git a/Sources/BoringSSL/crypto/stack/stack.c b/Sources/BoringSSL/crypto/stack/stack.c index c5845159f..f78209d5a 100644 --- a/Sources/BoringSSL/crypto/stack/stack.c +++ b/Sources/BoringSSL/crypto/stack/stack.c @@ -60,6 +60,9 @@ #include +#include "../internal.h" + + /* kMinSize is the number of pointers that will be initially allocated in a new * stack. */ static const size_t kMinSize = 4; @@ -71,14 +74,14 @@ _STACK *sk_new(stack_cmp_func comp) { if (ret == NULL) { goto err; } - memset(ret, 0, sizeof(_STACK)); + OPENSSL_memset(ret, 0, sizeof(_STACK)); ret->data = OPENSSL_malloc(sizeof(void *) * kMinSize); if (ret->data == NULL) { goto err; } - memset(ret->data, 0, sizeof(void *) * kMinSize); + OPENSSL_memset(ret->data, 0, sizeof(void *) * kMinSize); ret->comp = comp; ret->num_alloc = kMinSize; @@ -103,7 +106,7 @@ void sk_zero(_STACK *sk) { if (sk == NULL || sk->num == 0) { return; } - memset(sk->data, 0, sizeof(void*) * sk->num); + OPENSSL_memset(sk->data, 0, sizeof(void*) * sk->num); sk->num = 0; sk->sorted = 0; } @@ -131,13 +134,11 @@ void sk_free(_STACK *sk) { } void sk_pop_free(_STACK *sk, void (*func)(void *)) { - size_t i; - if (sk == NULL) { return; } - for (i = 0; i < sk->num; i++) { + for (size_t i = 0; i < sk->num; i++) { if (sk->data[i] != NULL) { func(sk->data[i]); } @@ -179,8 +180,8 @@ size_t sk_insert(_STACK *sk, void *p, size_t where) { if (where >= sk->num) { sk->data[sk->num] = p; } else { - memmove(&sk->data[where + 1], &sk->data[where], - sizeof(void *) * (sk->num - where)); + OPENSSL_memmove(&sk->data[where + 1], &sk->data[where], + sizeof(void *) * (sk->num - where)); sk->data[where] = p; } @@ -200,7 +201,7 @@ void *sk_delete(_STACK *sk, size_t where) { ret = sk->data[where]; if (where != sk->num - 1) { - memmove(&sk->data[where], &sk->data[where + 1], + OPENSSL_memmove(&sk->data[where], &sk->data[where + 1], sizeof(void *) * (sk->num - where - 1)); } @@ -209,13 +210,11 @@ void *sk_delete(_STACK *sk, size_t where) { } void *sk_delete_ptr(_STACK *sk, void *p) { - size_t i; - if (sk == NULL) { return NULL; } - for (i = 0; i < sk->num; i++) { + for (size_t i = 0; i < sk->num; i++) { if (sk->data[i] == p) { return sk_delete(sk, i); } @@ -225,17 +224,13 @@ void *sk_delete_ptr(_STACK *sk, void *p) { } int sk_find(_STACK *sk, size_t *out_index, void *p) { - const void *const *r; - size_t i; - int (*comp_func)(const void *,const void *); - if (sk == NULL) { return 0; } if (sk->comp == NULL) { /* Use pointer equality when no comparison function has been set. */ - for (i = 0; i < sk->num; i++) { + for (size_t i = 0; i < sk->num; i++) { if (sk->data[i] == p) { if (out_index) { *out_index = i; @@ -257,18 +252,19 @@ int sk_find(_STACK *sk, size_t *out_index, void *p) { * elements. However, since we're passing an array of pointers to * qsort/bsearch, we can just cast the comparison function and everything * works. */ - comp_func=(int (*)(const void *,const void *))(sk->comp); - r = bsearch(&p, sk->data, sk->num, sizeof(void *), comp_func); + const void *const *r = bsearch(&p, sk->data, sk->num, sizeof(void *), + (int (*)(const void *, const void *))sk->comp); if (r == NULL) { return 0; } - i = ((void **)r) - sk->data; + size_t idx = ((void **)r) - sk->data; /* This function always returns the first result. */ - while (i > 0 && sk->comp((const void**) &p, (const void**) &sk->data[i-1]) == 0) { - i--; + while (idx > 0 && + sk->comp((const void **)&p, (const void **)&sk->data[idx - 1]) == 0) { + idx--; } if (out_index) { - *out_index = i; + *out_index = idx; } return 1; } @@ -315,7 +311,7 @@ _STACK *sk_dup(const _STACK *sk) { ret->data = s; ret->num = sk->num; - memcpy(ret->data, sk->data, sizeof(void *) * sk->num); + OPENSSL_memcpy(ret->data, sk->data, sizeof(void *) * sk->num); ret->sorted = sk->sorted; ret->num_alloc = sk->num_alloc; ret->comp = sk->comp; @@ -329,7 +325,7 @@ _STACK *sk_dup(const _STACK *sk) { void sk_sort(_STACK *sk) { int (*comp_func)(const void *,const void *); - if (sk == NULL || sk->sorted) { + if (sk == NULL || sk->comp == NULL || sk->sorted) { return; } @@ -364,15 +360,13 @@ _STACK *sk_deep_copy(const _STACK *sk, void *(*copy_func)(void *), return NULL; } - size_t i; - for (i = 0; i < ret->num; i++) { + for (size_t i = 0; i < ret->num; i++) { if (ret->data[i] == NULL) { continue; } ret->data[i] = copy_func(ret->data[i]); if (ret->data[i] == NULL) { - size_t j; - for (j = 0; j < i; j++) { + for (size_t j = 0; j < i; j++) { if (ret->data[j] != NULL) { free_func(ret->data[j]); } diff --git a/Sources/BoringSSL/crypto/thread.c b/Sources/BoringSSL/crypto/thread.c index 88371159c..25acce1b8 100644 --- a/Sources/BoringSSL/crypto/thread.c +++ b/Sources/BoringSSL/crypto/thread.c @@ -56,24 +56,17 @@ #include -#include - -#if !defined(OPENSSL_WINDOWS) -#include -#else -#pragma warning(push, 3) -#include -#pragma warning(pop) -#endif - -#include - int CRYPTO_num_locks(void) { return 1; } void CRYPTO_set_locking_callback(void (*func)(int mode, int lock_num, const char *file, int line)) {} +void (*CRYPTO_get_locking_callback(void))(int mode, int lock_num, + const char *file, int line) { + return NULL; +} + void CRYPTO_set_add_lock_callback(int (*func)(int *num, int mount, int lock_num, const char *file, int line)) {} @@ -99,3 +92,19 @@ void CRYPTO_set_dynlock_lock_callback(void (*dyn_lock_function)( void CRYPTO_set_dynlock_destroy_callback(void (*dyn_destroy_function)( struct CRYPTO_dynlock_value *l, const char *file, int line)) {} + +struct CRYPTO_dynlock_value *(*CRYPTO_get_dynlock_create_callback(void))( + const char *file, int line) { + return NULL; +} + +void (*CRYPTO_get_dynlock_lock_callback(void))(int mode, + struct CRYPTO_dynlock_value *l, + const char *file, int line) { + return NULL; +} + +void (*CRYPTO_get_dynlock_destroy_callback(void))( + struct CRYPTO_dynlock_value *l, const char *file, int line) { + return NULL; +} diff --git a/Sources/BoringSSL/crypto/thread_none.c b/Sources/BoringSSL/crypto/thread_none.c index cf4e85a74..85768b4bf 100644 --- a/Sources/BoringSSL/crypto/thread_none.c +++ b/Sources/BoringSSL/crypto/thread_none.c @@ -22,7 +22,9 @@ void CRYPTO_MUTEX_lock_read(CRYPTO_MUTEX *lock) {} void CRYPTO_MUTEX_lock_write(CRYPTO_MUTEX *lock) {} -void CRYPTO_MUTEX_unlock(CRYPTO_MUTEX *lock) {} +void CRYPTO_MUTEX_unlock_read(CRYPTO_MUTEX *lock) {} + +void CRYPTO_MUTEX_unlock_write(CRYPTO_MUTEX *lock) {} void CRYPTO_MUTEX_cleanup(CRYPTO_MUTEX *lock) {} @@ -30,7 +32,9 @@ void CRYPTO_STATIC_MUTEX_lock_read(struct CRYPTO_STATIC_MUTEX *lock) {} void CRYPTO_STATIC_MUTEX_lock_write(struct CRYPTO_STATIC_MUTEX *lock) {} -void CRYPTO_STATIC_MUTEX_unlock(struct CRYPTO_STATIC_MUTEX *lock) {} +void CRYPTO_STATIC_MUTEX_unlock_read(struct CRYPTO_STATIC_MUTEX *lock) {} + +void CRYPTO_STATIC_MUTEX_unlock_write(struct CRYPTO_STATIC_MUTEX *lock) {} void CRYPTO_once(CRYPTO_once_t *once, void (*init)(void)) { if (*once) { diff --git a/Sources/BoringSSL/crypto/thread_pthread.c b/Sources/BoringSSL/crypto/thread_pthread.c index 68aaab5b4..d9e87f2d6 100644 --- a/Sources/BoringSSL/crypto/thread_pthread.c +++ b/Sources/BoringSSL/crypto/thread_pthread.c @@ -14,10 +14,9 @@ #include "internal.h" -#if !defined(OPENSSL_WINDOWS) && !defined(OPENSSL_NO_THREADS) +#if defined(OPENSSL_PTHREADS) #include -#include #include #include @@ -46,7 +45,13 @@ void CRYPTO_MUTEX_lock_write(CRYPTO_MUTEX *lock) { } } -void CRYPTO_MUTEX_unlock(CRYPTO_MUTEX *lock) { +void CRYPTO_MUTEX_unlock_read(CRYPTO_MUTEX *lock) { + if (pthread_rwlock_unlock((pthread_rwlock_t *) lock) != 0) { + abort(); + } +} + +void CRYPTO_MUTEX_unlock_write(CRYPTO_MUTEX *lock) { if (pthread_rwlock_unlock((pthread_rwlock_t *) lock) != 0) { abort(); } @@ -68,7 +73,13 @@ void CRYPTO_STATIC_MUTEX_lock_write(struct CRYPTO_STATIC_MUTEX *lock) { } } -void CRYPTO_STATIC_MUTEX_unlock(struct CRYPTO_STATIC_MUTEX *lock) { +void CRYPTO_STATIC_MUTEX_unlock_read(struct CRYPTO_STATIC_MUTEX *lock) { + if (pthread_rwlock_unlock(&lock->lock) != 0) { + abort(); + } +} + +void CRYPTO_STATIC_MUTEX_unlock_write(struct CRYPTO_STATIC_MUTEX *lock) { if (pthread_rwlock_unlock(&lock->lock) != 0) { abort(); } @@ -76,8 +87,6 @@ void CRYPTO_STATIC_MUTEX_unlock(struct CRYPTO_STATIC_MUTEX *lock) { void CRYPTO_once(CRYPTO_once_t *once, void (*init)(void)) { if (pthread_once(once, init) != 0) { - fprintf(stderr, - "pthread_once failed. Did you link against a threading library?\n"); abort(); } } @@ -94,7 +103,7 @@ static void thread_local_destructor(void *arg) { if (pthread_mutex_lock(&g_destructors_lock) != 0) { return; } - memcpy(destructors, g_destructors, sizeof(destructors)); + OPENSSL_memcpy(destructors, g_destructors, sizeof(destructors)); pthread_mutex_unlock(&g_destructors_lock); unsigned i; @@ -145,7 +154,7 @@ int CRYPTO_set_thread_local(thread_local_data_t index, void *value, destructor(value); return 0; } - memset(pointers, 0, sizeof(void *) * NUM_OPENSSL_THREAD_LOCALS); + OPENSSL_memset(pointers, 0, sizeof(void *) * NUM_OPENSSL_THREAD_LOCALS); if (pthread_setspecific(g_thread_local_key, pointers) != 0) { OPENSSL_free(pointers); destructor(value); @@ -164,4 +173,4 @@ int CRYPTO_set_thread_local(thread_local_data_t index, void *value, return 1; } -#endif /* !OPENSSL_WINDOWS && !OPENSSL_NO_THREADS */ +#endif /* OPENSSL_PTHREADS */ diff --git a/Sources/BoringSSL/crypto/thread_win.c b/Sources/BoringSSL/crypto/thread_win.c index e48ab5f55..62119b4ef 100644 --- a/Sources/BoringSSL/crypto/thread_win.c +++ b/Sources/BoringSSL/crypto/thread_win.c @@ -14,13 +14,12 @@ #include "internal.h" -#if defined(OPENSSL_WINDOWS) && !defined(OPENSSL_NO_THREADS) +#if defined(OPENSSL_WINDOWS_THREADS) -#pragma warning(push, 3) +OPENSSL_MSVC_PRAGMA(warning(push, 3)) #include -#pragma warning(pop) +OPENSSL_MSVC_PRAGMA(warning(pop)) -#include #include #include @@ -28,110 +27,59 @@ #include -OPENSSL_COMPILE_ASSERT(sizeof(CRYPTO_MUTEX) >= sizeof(CRITICAL_SECTION), +OPENSSL_COMPILE_ASSERT(sizeof(CRYPTO_MUTEX) >= sizeof(SRWLOCK), CRYPTO_MUTEX_too_small); -union run_once_arg_t { - void (*func)(void); - void *data; -}; - -static void run_once(CRYPTO_once_t *once, void (*init)(union run_once_arg_t), - union run_once_arg_t arg) { - /* Values must be aligned. */ - assert((((uintptr_t) once) & 3) == 0); - - /* This assumes that reading *once has acquire semantics. This should be true - * on x86 and x86-64, where we expect Windows to run. */ -#if !defined(OPENSSL_X86) && !defined(OPENSSL_X86_64) -#error "Windows once code may not work on other platforms." \ - "You can use InitOnceBeginInitialize on >=Vista" -#endif - if (*once == 1) { - return; - } - - for (;;) { - switch (InterlockedCompareExchange(once, 2, 0)) { - case 0: - /* The value was zero so we are the first thread to call |CRYPTO_once| - * on it. */ - init(arg); - /* Write one to indicate that initialisation is complete. */ - InterlockedExchange(once, 1); - return; - - case 1: - /* Another thread completed initialisation between our fast-path check - * and |InterlockedCompareExchange|. */ - return; - - case 2: - /* Another thread is running the initialisation. Switch to it then try - * again. */ - SwitchToThread(); - break; - - default: - abort(); - } - } -} - -static void call_once_init(union run_once_arg_t arg) { - arg.func(); +static BOOL CALLBACK call_once_init(INIT_ONCE *once, void *arg, void **out) { + void (**init)(void) = (void (**)(void))arg; + (**init)(); + return TRUE; } -void CRYPTO_once(CRYPTO_once_t *in_once, void (*init)(void)) { - union run_once_arg_t arg; - arg.func = init; - run_once(in_once, call_once_init, arg); +void CRYPTO_once(CRYPTO_once_t *once, void (*init)(void)) { + if (!InitOnceExecuteOnce(once, call_once_init, &init, NULL)) { + abort(); + } } void CRYPTO_MUTEX_init(CRYPTO_MUTEX *lock) { - if (!InitializeCriticalSectionAndSpinCount((CRITICAL_SECTION *) lock, 0x400)) { - abort(); - } + InitializeSRWLock((SRWLOCK *) lock); } void CRYPTO_MUTEX_lock_read(CRYPTO_MUTEX *lock) { - /* Since we have to support Windows XP, read locks are actually exclusive. */ - EnterCriticalSection((CRITICAL_SECTION *) lock); + AcquireSRWLockShared((SRWLOCK *) lock); } void CRYPTO_MUTEX_lock_write(CRYPTO_MUTEX *lock) { - EnterCriticalSection((CRITICAL_SECTION *) lock); + AcquireSRWLockExclusive((SRWLOCK *) lock); } -void CRYPTO_MUTEX_unlock(CRYPTO_MUTEX *lock) { - LeaveCriticalSection((CRITICAL_SECTION *) lock); +void CRYPTO_MUTEX_unlock_read(CRYPTO_MUTEX *lock) { + ReleaseSRWLockShared((SRWLOCK *) lock); } -void CRYPTO_MUTEX_cleanup(CRYPTO_MUTEX *lock) { - DeleteCriticalSection((CRITICAL_SECTION *) lock); +void CRYPTO_MUTEX_unlock_write(CRYPTO_MUTEX *lock) { + ReleaseSRWLockExclusive((SRWLOCK *) lock); } -static void static_lock_init(union run_once_arg_t arg) { - struct CRYPTO_STATIC_MUTEX *lock = arg.data; - if (!InitializeCriticalSectionAndSpinCount(&lock->lock, 0x400)) { - abort(); - } +void CRYPTO_MUTEX_cleanup(CRYPTO_MUTEX *lock) { + /* SRWLOCKs require no cleanup. */ } void CRYPTO_STATIC_MUTEX_lock_read(struct CRYPTO_STATIC_MUTEX *lock) { - union run_once_arg_t arg; - arg.data = lock; - /* Since we have to support Windows XP, read locks are actually exclusive. */ - run_once(&lock->once, static_lock_init, arg); - EnterCriticalSection(&lock->lock); + AcquireSRWLockShared(&lock->lock); } void CRYPTO_STATIC_MUTEX_lock_write(struct CRYPTO_STATIC_MUTEX *lock) { - CRYPTO_STATIC_MUTEX_lock_read(lock); + AcquireSRWLockExclusive(&lock->lock); +} + +void CRYPTO_STATIC_MUTEX_unlock_read(struct CRYPTO_STATIC_MUTEX *lock) { + ReleaseSRWLockShared(&lock->lock); } -void CRYPTO_STATIC_MUTEX_unlock(struct CRYPTO_STATIC_MUTEX *lock) { - LeaveCriticalSection(&lock->lock); +void CRYPTO_STATIC_MUTEX_unlock_write(struct CRYPTO_STATIC_MUTEX *lock) { + ReleaseSRWLockExclusive(&lock->lock); } static CRITICAL_SECTION g_destructors_lock; @@ -150,9 +98,14 @@ static void thread_local_init(void) { g_thread_local_failed = (g_thread_local_key == TLS_OUT_OF_INDEXES); } -static void NTAPI thread_local_destructor(PVOID module, - DWORD reason, PVOID reserved) { - if (DLL_THREAD_DETACH != reason && DLL_PROCESS_DETACH != reason) { +static void NTAPI thread_local_destructor(PVOID module, DWORD reason, + PVOID reserved) { + /* Only free memory on |DLL_THREAD_DETACH|, not |DLL_PROCESS_DETACH|. In + * VS2015's debug runtime, the C runtime has been unloaded by the time + * |DLL_PROCESS_DETACH| runs. See https://crbug.com/575795. This is consistent + * with |pthread_key_create| which does not call destructors on process exit, + * only thread exit. */ + if (reason != DLL_THREAD_DETACH) { return; } @@ -169,7 +122,7 @@ static void NTAPI thread_local_destructor(PVOID module, thread_local_destructor_t destructors[NUM_OPENSSL_THREAD_LOCALS]; EnterCriticalSection(&g_destructors_lock); - memcpy(destructors, g_destructors, sizeof(destructors)); + OPENSSL_memcpy(destructors, g_destructors, sizeof(destructors)); LeaveCriticalSection(&g_destructors_lock); unsigned i; @@ -265,7 +218,7 @@ int CRYPTO_set_thread_local(thread_local_data_t index, void *value, destructor(value); return 0; } - memset(pointers, 0, sizeof(void *) * NUM_OPENSSL_THREAD_LOCALS); + OPENSSL_memset(pointers, 0, sizeof(void *) * NUM_OPENSSL_THREAD_LOCALS); if (TlsSetValue(g_thread_local_key, pointers) == 0) { OPENSSL_free(pointers); destructor(value); @@ -281,4 +234,4 @@ int CRYPTO_set_thread_local(thread_local_data_t index, void *value, return 1; } -#endif /* OPENSSL_WINDOWS && !OPENSSL_NO_THREADS */ +#endif /* OPENSSL_WINDOWS_THREADS */ diff --git a/Sources/BoringSSL/crypto/x509/a_sign.c b/Sources/BoringSSL/crypto/x509/a_sign.c index 74f234385..13a3ac25e 100644 --- a/Sources/BoringSSL/crypto/x509/a_sign.c +++ b/Sources/BoringSSL/crypto/x509/a_sign.c @@ -62,7 +62,7 @@ #include #include -#include "../evp/internal.h" +#include "internal.h" int ASN1_item_sign(const ASN1_ITEM *it, X509_ALGOR *algor1, X509_ALGOR *algor2, ASN1_BIT_STRING *signature, void *asn, @@ -88,10 +88,10 @@ int ASN1_item_sign_ctx(const ASN1_ITEM *it, pkey = EVP_PKEY_CTX_get0_pkey(ctx->pctx); /* Write out the requested copies of the AlgorithmIdentifier. */ - if (algor1 && !EVP_DigestSignAlgorithm(ctx, algor1)) { + if (algor1 && !x509_digest_sign_algorithm(ctx, algor1)) { goto err; } - if (algor2 && !EVP_DigestSignAlgorithm(ctx, algor2)) { + if (algor2 && !x509_digest_sign_algorithm(ctx, algor2)) { goto err; } diff --git a/Sources/BoringSSL/crypto/x509/a_strex.c b/Sources/BoringSSL/crypto/x509/a_strex.c index aa2501a48..d0d83564e 100644 --- a/Sources/BoringSSL/crypto/x509/a_strex.c +++ b/Sources/BoringSSL/crypto/x509/a_strex.c @@ -321,7 +321,7 @@ static const signed char tag2nbyte[] = { -1, -1, -1, -1, -1, /* 5-9 */ -1, -1, 0, -1, /* 10-13 */ -1, -1, -1, -1, /* 15-17 */ - -1, 1, 1, /* 18-20 */ + 1, 1, 1, /* 18-20 */ -1, 1, 1, 1, /* 21-24 */ -1, 1, -1, /* 25-27 */ 4, -1, 2 /* 28-30 */ diff --git a/Sources/BoringSSL/crypto/x509/a_verify.c b/Sources/BoringSSL/crypto/x509/a_verify.c index 969591c04..0af4197c3 100644 --- a/Sources/BoringSSL/crypto/x509/a_verify.c +++ b/Sources/BoringSSL/crypto/x509/a_verify.c @@ -68,7 +68,7 @@ #include #include -#include "../evp/internal.h" +#include "internal.h" int ASN1_item_verify(const ASN1_ITEM *it, X509_ALGOR *a, ASN1_BIT_STRING *signature, void *asn, EVP_PKEY *pkey) @@ -89,7 +89,7 @@ int ASN1_item_verify(const ASN1_ITEM *it, X509_ALGOR *a, EVP_MD_CTX_init(&ctx); - if (!EVP_DigestVerifyInitFromAlgorithm(&ctx, a, pkey)) { + if (!x509_digest_verify_init(&ctx, a, pkey)) { goto err; } @@ -119,7 +119,7 @@ int ASN1_item_verify(const ASN1_ITEM *it, X509_ALGOR *a, * we don't need to zero the 'ctx' because we just checked public * information */ - /* memset(&ctx,0,sizeof(ctx)); */ + /* OPENSSL_memset(&ctx,0,sizeof(ctx)); */ ret = 1; err: EVP_MD_CTX_cleanup(&ctx); diff --git a/Sources/BoringSSL/crypto/evp/algorithm.c b/Sources/BoringSSL/crypto/x509/algorithm.c similarity index 66% rename from Sources/BoringSSL/crypto/evp/algorithm.c rename to Sources/BoringSSL/crypto/x509/algorithm.c index 63bc77af6..78ae882b8 100644 --- a/Sources/BoringSSL/crypto/evp/algorithm.c +++ b/Sources/BoringSSL/crypto/x509/algorithm.c @@ -54,100 +54,84 @@ * copied and put under another distribution licence * [including the GNU Public Licence.] */ -#include - -#include +#include #include +#include #include +#include #include -#include #include "internal.h" -int EVP_DigestSignAlgorithm(EVP_MD_CTX *ctx, X509_ALGOR *algor) { - const EVP_MD *digest; - EVP_PKEY *pkey; - int sign_nid, paramtype; - - digest = EVP_MD_CTX_md(ctx); - pkey = EVP_PKEY_CTX_get0_pkey(ctx->pctx); - if (!digest || !pkey) { - OPENSSL_PUT_ERROR(EVP, EVP_R_CONTEXT_NOT_INITIALISED); +int x509_digest_sign_algorithm(EVP_MD_CTX *ctx, X509_ALGOR *algor) { + const EVP_MD *digest = EVP_MD_CTX_md(ctx); + EVP_PKEY *pkey = EVP_PKEY_CTX_get0_pkey(ctx->pctx); + if (digest == NULL || pkey == NULL) { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_CONTEXT_NOT_INITIALISED); return 0; } - if (pkey->ameth->digest_sign_algorithm) { - switch (pkey->ameth->digest_sign_algorithm(ctx, algor)) { - case EVP_DIGEST_SIGN_ALGORITHM_ERROR: - return 0; - case EVP_DIGEST_SIGN_ALGORITHM_SUCCESS: - return 1; - case EVP_DIGEST_SIGN_ALGORITHM_DEFAULT: - /* Use default behavior. */ - break; - default: - assert(0); + if (EVP_PKEY_id(pkey) == EVP_PKEY_RSA) { + int pad_mode; + if (!EVP_PKEY_CTX_get_rsa_padding(ctx->pctx, &pad_mode)) { + return 0; + } + /* RSA-PSS has special signature algorithm logic. */ + if (pad_mode == RSA_PKCS1_PSS_PADDING) { + return x509_rsa_ctx_to_pss(ctx, algor); } } /* Default behavior: look up the OID for the algorithm/hash pair and encode * that. */ + int sign_nid; if (!OBJ_find_sigid_by_algs(&sign_nid, EVP_MD_type(digest), - pkey->ameth->pkey_id)) { - OPENSSL_PUT_ERROR(EVP, EVP_R_DIGEST_AND_KEY_TYPE_NOT_SUPPORTED); + EVP_PKEY_id(pkey))) { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_DIGEST_AND_KEY_TYPE_NOT_SUPPORTED); return 0; } - if (pkey->ameth->pkey_flags & ASN1_PKEY_SIGPARAM_NULL) { - paramtype = V_ASN1_NULL; - } else { - paramtype = V_ASN1_UNDEF; - } - + /* RSA signature algorithms include an explicit NULL parameter. Others omit + * it. */ + int paramtype = + (EVP_PKEY_id(pkey) == EVP_PKEY_RSA) ? V_ASN1_NULL : V_ASN1_UNDEF; X509_ALGOR_set0(algor, OBJ_nid2obj(sign_nid), paramtype, NULL); return 1; } -int EVP_DigestVerifyInitFromAlgorithm(EVP_MD_CTX *ctx, - X509_ALGOR *algor, - EVP_PKEY *pkey) { +int x509_digest_verify_init(EVP_MD_CTX *ctx, X509_ALGOR *sigalg, + EVP_PKEY *pkey) { + /* Convert the signature OID into digest and public key OIDs. */ + int sigalg_nid = OBJ_obj2nid(sigalg->algorithm); int digest_nid, pkey_nid; - const EVP_PKEY_ASN1_METHOD *ameth; - const EVP_MD *digest; - - /* Convert signature OID into digest and public key OIDs */ - if (!OBJ_find_sigid_algs(OBJ_obj2nid(algor->algorithm), &digest_nid, - &pkey_nid)) { - OPENSSL_PUT_ERROR(EVP, EVP_R_UNKNOWN_SIGNATURE_ALGORITHM); + if (!OBJ_find_sigid_algs(sigalg_nid, &digest_nid, &pkey_nid)) { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_UNKNOWN_SIGNATURE_ALGORITHM); return 0; } - /* Check public key OID matches public key type */ - ameth = EVP_PKEY_asn1_find(NULL, pkey_nid); - if (ameth == NULL || ameth->pkey_id != pkey->ameth->pkey_id) { - OPENSSL_PUT_ERROR(EVP, EVP_R_WRONG_PUBLIC_KEY_TYPE); + /* Check the public key OID matches the public key type. */ + if (pkey_nid != EVP_PKEY_id(pkey)) { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_WRONG_PUBLIC_KEY_TYPE); return 0; } /* NID_undef signals that there are custom parameters to set. */ if (digest_nid == NID_undef) { - if (!pkey->ameth || !pkey->ameth->digest_verify_init_from_algorithm) { - OPENSSL_PUT_ERROR(EVP, EVP_R_UNKNOWN_SIGNATURE_ALGORITHM); + if (sigalg_nid != NID_rsassaPss) { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_UNKNOWN_SIGNATURE_ALGORITHM); return 0; } - - return pkey->ameth->digest_verify_init_from_algorithm(ctx, algor, pkey); + return x509_rsa_pss_to_ctx(ctx, sigalg, pkey); } /* Otherwise, initialize with the digest from the OID. */ - digest = EVP_get_digestbynid(digest_nid); + const EVP_MD *digest = EVP_get_digestbynid(digest_nid); if (digest == NULL) { - OPENSSL_PUT_ERROR(EVP, EVP_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM); + OPENSSL_PUT_ERROR(ASN1, ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM); return 0; } return EVP_DigestVerifyInit(ctx, NULL, digest, NULL, pkey); } - diff --git a/Sources/BoringSSL/crypto/x509/asn1_gen.c b/Sources/BoringSSL/crypto/x509/asn1_gen.c index 0660840f4..c52a1ac01 100644 --- a/Sources/BoringSSL/crypto/x509/asn1_gen.c +++ b/Sources/BoringSSL/crypto/x509/asn1_gen.c @@ -142,7 +142,6 @@ ASN1_TYPE *ASN1_generate_nconf(char *str, CONF *nconf) } ASN1_TYPE *ASN1_generate_v3(char *str, X509V3_CTX *cnf) - OPENSSL_SUPPRESS_POTENTIALLY_UNINITIALIZED_WARNINGS { ASN1_TYPE *ret; tag_exp_arg asn1_tags; @@ -155,7 +154,7 @@ ASN1_TYPE *ASN1_generate_v3(char *str, X509V3_CTX *cnf) unsigned char *p; const unsigned char *cp; int cpy_len; - long hdr_len; + long hdr_len = 0; int hdr_constructed = 0, hdr_tag, hdr_class; int r; @@ -262,7 +261,7 @@ ASN1_TYPE *ASN1_generate_v3(char *str, X509V3_CTX *cnf) } /* Copy across original encoding */ - memcpy(p, cpy_start, cpy_len); + OPENSSL_memcpy(p, cpy_start, cpy_len); cp = new_der; diff --git a/Sources/BoringSSL/crypto/x509/by_dir.c b/Sources/BoringSSL/crypto/x509/by_dir.c index 4f0a49e2e..e68ca5a35 100644 --- a/Sources/BoringSSL/crypto/x509/by_dir.c +++ b/Sources/BoringSSL/crypto/x509/by_dir.c @@ -327,7 +327,7 @@ static int get_cert_by_subject(X509_LOOKUP *xl, int type, X509_NAME *name, hent = NULL; k = 0; } - CRYPTO_STATIC_MUTEX_unlock(&g_ent_hashes_lock); + CRYPTO_STATIC_MUTEX_unlock_read(&g_ent_hashes_lock); } else { k = 0; hent = NULL; @@ -362,7 +362,7 @@ static int get_cert_by_subject(X509_LOOKUP *xl, int type, X509_NAME *name, postfix, k); } #ifndef OPENSSL_NO_POSIX_IO -# ifdef _WIN32 +# if defined(_WIN32) && !defined(stat) # define stat _stat # endif { @@ -392,7 +392,7 @@ static int get_cert_by_subject(X509_LOOKUP *xl, int type, X509_NAME *name, if (sk_X509_OBJECT_find(xl->store_ctx->objs, &idx, &stmp)) { tmp = sk_X509_OBJECT_value(xl->store_ctx->objs, idx); } - CRYPTO_MUTEX_unlock(&xl->store_ctx->objs_lock); + CRYPTO_MUTEX_unlock_write(&xl->store_ctx->objs_lock); /* * If a CRL, update the last file suffix added for this @@ -412,14 +412,14 @@ static int get_cert_by_subject(X509_LOOKUP *xl, int type, X509_NAME *name, if (!hent) { hent = OPENSSL_malloc(sizeof(BY_DIR_HASH)); if (hent == NULL) { - CRYPTO_STATIC_MUTEX_unlock(&g_ent_hashes_lock); + CRYPTO_STATIC_MUTEX_unlock_write(&g_ent_hashes_lock); ok = 0; goto finish; } hent->hash = h; hent->suffix = k; if (!sk_BY_DIR_HASH_push(ent->hashes, hent)) { - CRYPTO_STATIC_MUTEX_unlock(&g_ent_hashes_lock); + CRYPTO_STATIC_MUTEX_unlock_write(&g_ent_hashes_lock); OPENSSL_free(hent); ok = 0; goto finish; @@ -427,13 +427,13 @@ static int get_cert_by_subject(X509_LOOKUP *xl, int type, X509_NAME *name, } else if (hent->suffix < k) hent->suffix = k; - CRYPTO_STATIC_MUTEX_unlock(&g_ent_hashes_lock); + CRYPTO_STATIC_MUTEX_unlock_write(&g_ent_hashes_lock); } if (tmp != NULL) { ok = 1; ret->type = tmp->type; - memcpy(&ret->data, &tmp->data, sizeof(ret->data)); + OPENSSL_memcpy(&ret->data, &tmp->data, sizeof(ret->data)); /* * If we were going to up the reference count, we would need * to do it on a perl 'type' basis diff --git a/Sources/BoringSSL/crypto/x509/internal.h b/Sources/BoringSSL/crypto/x509/internal.h new file mode 100644 index 000000000..4957c1e14 --- /dev/null +++ b/Sources/BoringSSL/crypto/x509/internal.h @@ -0,0 +1,66 @@ +/* Copyright (c) 2016, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#ifndef OPENSSL_HEADER_X509_INTERNAL_H +#define OPENSSL_HEADER_X509_INTERNAL_H + +#include +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* RSA-PSS functions. */ + +/* x509_rsa_pss_to_ctx configures |ctx| for an RSA-PSS operation based on + * signature algorithm parameters in |sigalg| (which must have type + * |NID_rsassaPss|) and key |pkey|. It returns one on success and zero on + * error. */ +int x509_rsa_pss_to_ctx(EVP_MD_CTX *ctx, X509_ALGOR *sigalg, EVP_PKEY *pkey); + +/* x509_rsa_pss_to_ctx sets |algor| to the signature algorithm parameters for + * |ctx|, which must have been configured for an RSA-PSS signing operation. It + * returns one on success and zero on error. */ +int x509_rsa_ctx_to_pss(EVP_MD_CTX *ctx, X509_ALGOR *algor); + +/* x509_print_rsa_pss_params prints a human-readable representation of RSA-PSS + * parameters in |sigalg| to |bp|. It returns one on success and zero on + * error. */ +int x509_print_rsa_pss_params(BIO *bp, const X509_ALGOR *sigalg, int indent, + ASN1_PCTX *pctx); + + +/* Signature algorithm functions. */ + +/* x509_digest_sign_algorithm encodes the signing parameters of |ctx| as an + * AlgorithmIdentifer and saves the result in |algor|. It returns one on + * success, or zero on error. */ +int x509_digest_sign_algorithm(EVP_MD_CTX *ctx, X509_ALGOR *algor); + +/* x509_digest_verify_init sets up |ctx| for a signature verification operation + * with public key |pkey| and parameters from |algor|. The |ctx| argument must + * have been initialised with |EVP_MD_CTX_init|. It returns one on success, or + * zero on error. */ +int x509_digest_verify_init(EVP_MD_CTX *ctx, X509_ALGOR *sigalg, + EVP_PKEY *pkey); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_X509_INTERNAL_H */ diff --git a/Sources/BoringSSL/crypto/x509/rsa_pss.c b/Sources/BoringSSL/crypto/x509/rsa_pss.c new file mode 100644 index 000000000..4913c3d20 --- /dev/null +++ b/Sources/BoringSSL/crypto/x509/rsa_pss.c @@ -0,0 +1,385 @@ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 2006. + */ +/* ==================================================================== + * Copyright (c) 2006 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include "internal.h" + + +ASN1_SEQUENCE(RSA_PSS_PARAMS) = { + ASN1_EXP_OPT(RSA_PSS_PARAMS, hashAlgorithm, X509_ALGOR,0), + ASN1_EXP_OPT(RSA_PSS_PARAMS, maskGenAlgorithm, X509_ALGOR,1), + ASN1_EXP_OPT(RSA_PSS_PARAMS, saltLength, ASN1_INTEGER,2), + ASN1_EXP_OPT(RSA_PSS_PARAMS, trailerField, ASN1_INTEGER,3), +} ASN1_SEQUENCE_END(RSA_PSS_PARAMS) + +IMPLEMENT_ASN1_FUNCTIONS(RSA_PSS_PARAMS) + + +/* Given an MGF1 Algorithm ID decode to an Algorithm Identifier */ +static X509_ALGOR *rsa_mgf1_decode(X509_ALGOR *alg) { + if (alg == NULL || alg->parameter == NULL || + OBJ_obj2nid(alg->algorithm) != NID_mgf1 || + alg->parameter->type != V_ASN1_SEQUENCE) { + return NULL; + } + + const uint8_t *p = alg->parameter->value.sequence->data; + int plen = alg->parameter->value.sequence->length; + return d2i_X509_ALGOR(NULL, &p, plen); +} + +static RSA_PSS_PARAMS *rsa_pss_decode(const X509_ALGOR *alg, + X509_ALGOR **pmaskHash) { + *pmaskHash = NULL; + + if (alg->parameter == NULL || alg->parameter->type != V_ASN1_SEQUENCE) { + return NULL; + } + + const uint8_t *p = alg->parameter->value.sequence->data; + int plen = alg->parameter->value.sequence->length; + RSA_PSS_PARAMS *pss = d2i_RSA_PSS_PARAMS(NULL, &p, plen); + if (pss == NULL) { + return NULL; + } + + *pmaskHash = rsa_mgf1_decode(pss->maskGenAlgorithm); + return pss; +} + +/* allocate and set algorithm ID from EVP_MD, default SHA1 */ +static int rsa_md_to_algor(X509_ALGOR **palg, const EVP_MD *md) { + if (EVP_MD_type(md) == NID_sha1) { + return 1; + } + *palg = X509_ALGOR_new(); + if (*palg == NULL) { + return 0; + } + X509_ALGOR_set_md(*palg, md); + return 1; +} + +/* Allocate and set MGF1 algorithm ID from EVP_MD */ +static int rsa_md_to_mgf1(X509_ALGOR **palg, const EVP_MD *mgf1md) { + X509_ALGOR *algtmp = NULL; + ASN1_STRING *stmp = NULL; + *palg = NULL; + + if (EVP_MD_type(mgf1md) == NID_sha1) { + return 1; + } + /* need to embed algorithm ID inside another */ + if (!rsa_md_to_algor(&algtmp, mgf1md) || + !ASN1_item_pack(algtmp, ASN1_ITEM_rptr(X509_ALGOR), &stmp)) { + goto err; + } + *palg = X509_ALGOR_new(); + if (!*palg) { + goto err; + } + X509_ALGOR_set0(*palg, OBJ_nid2obj(NID_mgf1), V_ASN1_SEQUENCE, stmp); + stmp = NULL; + +err: + ASN1_STRING_free(stmp); + X509_ALGOR_free(algtmp); + if (*palg) { + return 1; + } + + return 0; +} + +/* convert algorithm ID to EVP_MD, default SHA1 */ +static const EVP_MD *rsa_algor_to_md(X509_ALGOR *alg) { + const EVP_MD *md; + if (!alg) { + return EVP_sha1(); + } + md = EVP_get_digestbyobj(alg->algorithm); + if (md == NULL) { + OPENSSL_PUT_ERROR(X509, X509_R_INVALID_PSS_PARAMETERS); + } + return md; +} + +/* convert MGF1 algorithm ID to EVP_MD, default SHA1 */ +static const EVP_MD *rsa_mgf1_to_md(X509_ALGOR *alg, X509_ALGOR *maskHash) { + const EVP_MD *md; + if (!alg) { + return EVP_sha1(); + } + /* Check mask and lookup mask hash algorithm */ + if (OBJ_obj2nid(alg->algorithm) != NID_mgf1 || + maskHash == NULL) { + OPENSSL_PUT_ERROR(X509, X509_R_INVALID_PSS_PARAMETERS); + return NULL; + } + md = EVP_get_digestbyobj(maskHash->algorithm); + if (md == NULL) { + OPENSSL_PUT_ERROR(X509, X509_R_INVALID_PSS_PARAMETERS); + return NULL; + } + return md; +} + +int x509_rsa_ctx_to_pss(EVP_MD_CTX *ctx, X509_ALGOR *algor) { + const EVP_MD *sigmd, *mgf1md; + int saltlen; + if (!EVP_PKEY_CTX_get_signature_md(ctx->pctx, &sigmd) || + !EVP_PKEY_CTX_get_rsa_mgf1_md(ctx->pctx, &mgf1md) || + !EVP_PKEY_CTX_get_rsa_pss_saltlen(ctx->pctx, &saltlen)) { + return 0; + } + + EVP_PKEY *pk = EVP_PKEY_CTX_get0_pkey(ctx->pctx); + if (saltlen == -1) { + saltlen = EVP_MD_size(sigmd); + } else if (saltlen == -2) { + saltlen = EVP_PKEY_size(pk) - EVP_MD_size(sigmd) - 2; + if (((EVP_PKEY_bits(pk) - 1) & 0x7) == 0) { + saltlen--; + } + } else { + return 0; + } + + int ret = 0; + ASN1_STRING *os = NULL; + RSA_PSS_PARAMS *pss = RSA_PSS_PARAMS_new(); + if (!pss) { + goto err; + } + + if (saltlen != 20) { + pss->saltLength = ASN1_INTEGER_new(); + if (!pss->saltLength || + !ASN1_INTEGER_set(pss->saltLength, saltlen)) { + goto err; + } + } + + if (!rsa_md_to_algor(&pss->hashAlgorithm, sigmd) || + !rsa_md_to_mgf1(&pss->maskGenAlgorithm, mgf1md)) { + goto err; + } + + /* Finally create string with pss parameter encoding. */ + if (!ASN1_item_pack(pss, ASN1_ITEM_rptr(RSA_PSS_PARAMS), &os)) { + goto err; + } + + X509_ALGOR_set0(algor, OBJ_nid2obj(NID_rsassaPss), V_ASN1_SEQUENCE, os); + os = NULL; + ret = 1; + +err: + RSA_PSS_PARAMS_free(pss); + ASN1_STRING_free(os); + return ret; +} + +int x509_rsa_pss_to_ctx(EVP_MD_CTX *ctx, X509_ALGOR *sigalg, EVP_PKEY *pkey) { + assert(OBJ_obj2nid(sigalg->algorithm) == NID_rsassaPss); + + /* Decode PSS parameters */ + int ret = 0; + X509_ALGOR *maskHash; + RSA_PSS_PARAMS *pss = rsa_pss_decode(sigalg, &maskHash); + if (pss == NULL) { + OPENSSL_PUT_ERROR(X509, X509_R_INVALID_PSS_PARAMETERS); + goto err; + } + + const EVP_MD *mgf1md = rsa_mgf1_to_md(pss->maskGenAlgorithm, maskHash); + const EVP_MD *md = rsa_algor_to_md(pss->hashAlgorithm); + if (mgf1md == NULL || md == NULL) { + goto err; + } + + int saltlen = 20; + if (pss->saltLength != NULL) { + saltlen = ASN1_INTEGER_get(pss->saltLength); + + /* Could perform more salt length sanity checks but the main + * RSA routines will trap other invalid values anyway. */ + if (saltlen < 0) { + OPENSSL_PUT_ERROR(X509, X509_R_INVALID_PSS_PARAMETERS); + goto err; + } + } + + /* low-level routines support only trailer field 0xbc (value 1) + * and PKCS#1 says we should reject any other value anyway. */ + if (pss->trailerField != NULL && ASN1_INTEGER_get(pss->trailerField) != 1) { + OPENSSL_PUT_ERROR(X509, X509_R_INVALID_PSS_PARAMETERS); + goto err; + } + + EVP_PKEY_CTX *pkctx; + if (!EVP_DigestVerifyInit(ctx, &pkctx, md, NULL, pkey) || + !EVP_PKEY_CTX_set_rsa_padding(pkctx, RSA_PKCS1_PSS_PADDING) || + !EVP_PKEY_CTX_set_rsa_pss_saltlen(pkctx, saltlen) || + !EVP_PKEY_CTX_set_rsa_mgf1_md(pkctx, mgf1md)) { + goto err; + } + + ret = 1; + +err: + RSA_PSS_PARAMS_free(pss); + X509_ALGOR_free(maskHash); + return ret; +} + +int x509_print_rsa_pss_params(BIO *bp, const X509_ALGOR *sigalg, int indent, + ASN1_PCTX *pctx) { + assert(OBJ_obj2nid(sigalg->algorithm) == NID_rsassaPss); + + int rv = 0; + X509_ALGOR *maskHash; + RSA_PSS_PARAMS *pss = rsa_pss_decode(sigalg, &maskHash); + if (!pss) { + if (BIO_puts(bp, " (INVALID PSS PARAMETERS)\n") <= 0) { + goto err; + } + rv = 1; + goto err; + } + + if (BIO_puts(bp, "\n") <= 0 || + !BIO_indent(bp, indent, 128) || + BIO_puts(bp, "Hash Algorithm: ") <= 0) { + goto err; + } + + if (pss->hashAlgorithm) { + if (i2a_ASN1_OBJECT(bp, pss->hashAlgorithm->algorithm) <= 0) { + goto err; + } + } else if (BIO_puts(bp, "sha1 (default)") <= 0) { + goto err; + } + + if (BIO_puts(bp, "\n") <= 0 || + !BIO_indent(bp, indent, 128) || + BIO_puts(bp, "Mask Algorithm: ") <= 0) { + goto err; + } + + if (pss->maskGenAlgorithm) { + if (i2a_ASN1_OBJECT(bp, pss->maskGenAlgorithm->algorithm) <= 0 || + BIO_puts(bp, " with ") <= 0) { + goto err; + } + + if (maskHash) { + if (i2a_ASN1_OBJECT(bp, maskHash->algorithm) <= 0) { + goto err; + } + } else if (BIO_puts(bp, "INVALID") <= 0) { + goto err; + } + } else if (BIO_puts(bp, "mgf1 with sha1 (default)") <= 0) { + goto err; + } + BIO_puts(bp, "\n"); + + if (!BIO_indent(bp, indent, 128) || + BIO_puts(bp, "Salt Length: 0x") <= 0) { + goto err; + } + + if (pss->saltLength) { + if (i2a_ASN1_INTEGER(bp, pss->saltLength) <= 0) { + goto err; + } + } else if (BIO_puts(bp, "14 (default)") <= 0) { + goto err; + } + BIO_puts(bp, "\n"); + + if (!BIO_indent(bp, indent, 128) || + BIO_puts(bp, "Trailer Field: 0x") <= 0) { + goto err; + } + + if (pss->trailerField) { + if (i2a_ASN1_INTEGER(bp, pss->trailerField) <= 0) { + goto err; + } + } else if (BIO_puts(bp, "BC (default)") <= 0) { + goto err; + } + BIO_puts(bp, "\n"); + + rv = 1; + +err: + RSA_PSS_PARAMS_free(pss); + X509_ALGOR_free(maskHash); + return rv; +} diff --git a/Sources/BoringSSL/crypto/x509/t_x509.c b/Sources/BoringSSL/crypto/x509/t_x509.c index 1afcf601e..d4f6bba58 100644 --- a/Sources/BoringSSL/crypto/x509/t_x509.c +++ b/Sources/BoringSSL/crypto/x509/t_x509.c @@ -54,6 +54,7 @@ * copied and put under another distribution licence * [including the GNU Public Licence.] */ +#include #include #include #include @@ -64,7 +65,8 @@ #include #include -#include "../evp/internal.h" +#include "internal.h" + #ifndef OPENSSL_NO_FP_API int X509_print_ex_fp(FILE *fp, X509 *x, unsigned long nmflag, @@ -132,7 +134,8 @@ int X509_print_ex(BIO *bp, X509 *x, unsigned long nmflags, goto err; bs = X509_get_serialNumber(x); - if (bs->length <= (int)sizeof(long)) { + if (bs->length < (int)sizeof(long) + || (bs->length == sizeof(long) && (bs->data[0] & 0x80) == 0)) { l = ASN1_INTEGER_get(bs); if (bs->type == V_ASN1_NEG_INTEGER) { l = -l; @@ -205,7 +208,7 @@ int X509_print_ex(BIO *bp, X509 *x, unsigned long nmflags, pkey = X509_get_pubkey(x); if (pkey == NULL) { BIO_printf(bp, "%12sUnable to load Public Key\n", ""); - BIO_print_errors(bp); + ERR_print_errors(bp); } else { EVP_PKEY_print_public(bp, pkey, 16, NULL); EVP_PKEY_free(pkey); @@ -298,22 +301,18 @@ int X509_ocspid_print(BIO *bp, X509 *x) int X509_signature_print(BIO *bp, X509_ALGOR *sigalg, ASN1_STRING *sig) { - int sig_nid; if (BIO_puts(bp, " Signature Algorithm: ") <= 0) return 0; if (i2a_ASN1_OBJECT(bp, sigalg->algorithm) <= 0) return 0; - sig_nid = OBJ_obj2nid(sigalg->algorithm); - if (sig_nid != NID_undef) { - int pkey_nid, dig_nid; - const EVP_PKEY_ASN1_METHOD *ameth; - if (OBJ_find_sigid_algs(sig_nid, &dig_nid, &pkey_nid)) { - ameth = EVP_PKEY_asn1_find(NULL, pkey_nid); - if (ameth && ameth->sig_print) - return ameth->sig_print(bp, sigalg, sig, 9, 0); - } + /* RSA-PSS signatures have parameters to print. */ + int sig_nid = OBJ_obj2nid(sigalg->algorithm); + if (sig_nid == NID_rsassaPss && + !x509_print_rsa_pss_params(bp, sigalg, 9, 0)) { + return 0; } + if (sig) return X509_signature_dump(bp, sig, 9); else if (BIO_puts(bp, "\n") <= 0) @@ -417,45 +416,84 @@ int ASN1_GENERALIZEDTIME_print(BIO *bp, const ASN1_GENERALIZEDTIME *tm) return (0); } -int ASN1_UTCTIME_print(BIO *bp, const ASN1_UTCTIME *tm) -{ - const char *v; - int gmt = 0; - int i; - int y = 0, M = 0, d = 0, h = 0, m = 0, s = 0; +// consume_two_digits is a helper function for ASN1_UTCTIME_print. If |*v|, +// assumed to be |*len| bytes long, has two leading digits, updates |*out| with +// their value, updates |v| and |len|, and returns one. Otherwise, returns +// zero. +static int consume_two_digits(int* out, const char **v, int *len) { + if (*len < 2|| !isdigit((*v)[0]) || !isdigit((*v)[1])) { + return 0; + } + *out = ((*v)[0] - '0') * 10 + ((*v)[1] - '0'); + *len -= 2; + *v += 2; + return 1; +} - i = tm->length; - v = (const char *)tm->data; +// consume_zulu_timezone is a helper function for ASN1_UTCTIME_print. If |*v|, +// assumed to be |*len| bytes long, starts with "Z" then it updates |*v| and +// |*len| and returns one. Otherwise returns zero. +static int consume_zulu_timezone(const char **v, int *len) { + if (*len == 0 || (*v)[0] != 'Z') { + return 0; + } + + *len -= 1; + *v += 1; + return 1; +} - if (i < 10) - goto err; - if (v[i - 1] == 'Z') - gmt = 1; - for (i = 0; i < 10; i++) - if ((v[i] > '9') || (v[i] < '0')) - goto err; - y = (v[0] - '0') * 10 + (v[1] - '0'); - if (y < 50) - y += 100; - M = (v[2] - '0') * 10 + (v[3] - '0'); - if ((M > 12) || (M < 1)) - goto err; - d = (v[4] - '0') * 10 + (v[5] - '0'); - h = (v[6] - '0') * 10 + (v[7] - '0'); - m = (v[8] - '0') * 10 + (v[9] - '0'); - if (tm->length >= 12 && - (v[10] >= '0') && (v[10] <= '9') && (v[11] >= '0') && (v[11] <= '9')) - s = (v[10] - '0') * 10 + (v[11] - '0'); - - if (BIO_printf(bp, "%s %2d %02d:%02d:%02d %d%s", - mon[M - 1], d, h, m, s, y + 1900, - (gmt) ? " GMT" : "") <= 0) - return (0); - else - return (1); - err: - BIO_write(bp, "Bad time value", 14); - return (0); +int ASN1_UTCTIME_print(BIO *bp, const ASN1_UTCTIME *tm) { + const char *v = (const char *)tm->data; + int len = tm->length; + int Y = 0, M = 0, D = 0, h = 0, m = 0, s = 0; + + // YYMMDDhhmm are required to be present. + if (!consume_two_digits(&Y, &v, &len) || + !consume_two_digits(&M, &v, &len) || + !consume_two_digits(&D, &v, &len) || + !consume_two_digits(&h, &v, &len) || + !consume_two_digits(&m, &v, &len)) { + goto err; + } + // https://tools.ietf.org/html/rfc5280, section 4.1.2.5.1, requires seconds + // to be present, but historically this code has forgiven its absence. + consume_two_digits(&s, &v, &len); + + // https://tools.ietf.org/html/rfc5280, section 4.1.2.5.1, specifies this + // interpretation of the year. + if (Y < 50) { + Y += 2000; + } else { + Y += 1900; + } + if (M > 12 || M == 0) { + goto err; + } + if (D > 31 || D == 0) { + goto err; + } + if (h > 23 || m > 59 || s > 60) { + goto err; + } + + // https://tools.ietf.org/html/rfc5280, section 4.1.2.5.1, requires the "Z" + // to be present, but historically this code has forgiven its absence. + const int is_gmt = consume_zulu_timezone(&v, &len); + + // https://tools.ietf.org/html/rfc5280, section 4.1.2.5.1, does not permit + // the specification of timezones using the +hhmm / -hhmm syntax, which is + // the only other thing that might legitimately be found at the end. + if (len) { + goto err; + } + + return BIO_printf(bp, "%s %2d %02d:%02d:%02d %d%s", mon[M - 1], D, h, m, s, Y, + is_gmt ? " GMT" : "") > 0; + +err: + BIO_write(bp, "Bad time value", 14); + return 0; } int X509_NAME_print(BIO *bp, X509_NAME *name, int obase) diff --git a/Sources/BoringSSL/crypto/x509/x509.c b/Sources/BoringSSL/crypto/x509/x509.c index 31f9e1eb5..188fd4963 100644 --- a/Sources/BoringSSL/crypto/x509/x509.c +++ b/Sources/BoringSSL/crypto/x509/x509.c @@ -57,9 +57,14 @@ #include #include +#include #include +/* |X509_R_UNSUPPORTED_ALGORITHM| is no longer emitted, but continue to define + * it to avoid downstream churn. */ +OPENSSL_DECLARE_ERROR_REASON(X509, UNSUPPORTED_ALGORITHM) + int PKCS8_pkey_set0(PKCS8_PRIV_KEY_INFO *priv, ASN1_OBJECT *aobj, int version, int ptype, void *pval, uint8_t *penc, int penclen) { uint8_t **ppenc = NULL; diff --git a/Sources/BoringSSL/crypto/x509/x509_att.c b/Sources/BoringSSL/crypto/x509/x509_att.c index b83d32f92..85d65e7e8 100644 --- a/Sources/BoringSSL/crypto/x509/x509_att.c +++ b/Sources/BoringSSL/crypto/x509/x509_att.c @@ -287,7 +287,7 @@ int X509_ATTRIBUTE_set1_object(X509_ATTRIBUTE *attr, const ASN1_OBJECT *obj) int X509_ATTRIBUTE_set1_data(X509_ATTRIBUTE *attr, int attrtype, const void *data, int len) { - ASN1_TYPE *ttmp; + ASN1_TYPE *ttmp = NULL; ASN1_STRING *stmp = NULL; int atype = 0; if (!attr) @@ -315,20 +315,26 @@ int X509_ATTRIBUTE_set1_data(X509_ATTRIBUTE *attr, int attrtype, * least one value but some types use and zero length SET and require * this. */ - if (attrtype == 0) + if (attrtype == 0) { + ASN1_STRING_free(stmp); return 1; + } if (!(ttmp = ASN1_TYPE_new())) goto err; if ((len == -1) && !(attrtype & MBSTRING_FLAG)) { if (!ASN1_TYPE_set1(ttmp, attrtype, data)) goto err; - } else + } else { ASN1_TYPE_set(ttmp, atype, stmp); + stmp = NULL; + } if (!sk_ASN1_TYPE_push(attr->value.set, ttmp)) goto err; return 1; err: OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + ASN1_TYPE_free(ttmp); + ASN1_STRING_free(stmp); return 0; } diff --git a/Sources/BoringSSL/crypto/x509/x509_cmp.c b/Sources/BoringSSL/crypto/x509/x509_cmp.c index 32862ebc9..98236d9fe 100644 --- a/Sources/BoringSSL/crypto/x509/x509_cmp.c +++ b/Sources/BoringSSL/crypto/x509/x509_cmp.c @@ -67,6 +67,9 @@ #include #include +#include "../internal.h" + + int X509_issuer_and_serial_cmp(const X509 *a, const X509 *b) { int i; @@ -125,7 +128,7 @@ int X509_CRL_cmp(const X509_CRL *a, const X509_CRL *b) int X509_CRL_match(const X509_CRL *a, const X509_CRL *b) { - return memcmp(a->sha1_hash, b->sha1_hash, 20); + return OPENSSL_memcmp(a->sha1_hash, b->sha1_hash, 20); } X509_NAME *X509_get_issuer_name(X509 *a) @@ -178,7 +181,7 @@ int X509_cmp(const X509 *a, const X509 *b) X509_check_purpose((X509 *)a, -1, 0); X509_check_purpose((X509 *)b, -1, 0); - rv = memcmp(a->sha1_hash, b->sha1_hash, SHA_DIGEST_LENGTH); + rv = OPENSSL_memcmp(a->sha1_hash, b->sha1_hash, SHA_DIGEST_LENGTH); if (rv) return rv; /* Check for match against stored encoding too */ @@ -186,8 +189,8 @@ int X509_cmp(const X509 *a, const X509 *b) rv = (int)(a->cert_info->enc.len - b->cert_info->enc.len); if (rv) return rv; - return memcmp(a->cert_info->enc.enc, b->cert_info->enc.enc, - a->cert_info->enc.len); + return OPENSSL_memcmp(a->cert_info->enc.enc, b->cert_info->enc.enc, + a->cert_info->enc.len); } return rv; } @@ -215,7 +218,7 @@ int X509_NAME_cmp(const X509_NAME *a, const X509_NAME *b) if (ret) return ret; - return memcmp(a->canon_enc, b->canon_enc, a->canon_enclen); + return OPENSSL_memcmp(a->canon_enc, b->canon_enc, a->canon_enclen); } diff --git a/Sources/BoringSSL/crypto/x509/x509_lu.c b/Sources/BoringSSL/crypto/x509/x509_lu.c index bfe6b11b5..9e4596405 100644 --- a/Sources/BoringSSL/crypto/x509/x509_lu.c +++ b/Sources/BoringSSL/crypto/x509/x509_lu.c @@ -130,18 +130,18 @@ int X509_LOOKUP_by_subject(X509_LOOKUP *ctx, int type, X509_NAME *name, X509_OBJECT *ret) { if ((ctx->method == NULL) || (ctx->method->get_by_subject == NULL)) - return X509_LU_FAIL; + return 0; if (ctx->skip) return 0; - return ctx->method->get_by_subject(ctx, type, name, ret); + return ctx->method->get_by_subject(ctx, type, name, ret) > 0; } int X509_LOOKUP_by_issuer_serial(X509_LOOKUP *ctx, int type, X509_NAME *name, ASN1_INTEGER *serial, X509_OBJECT *ret) { if ((ctx->method == NULL) || (ctx->method->get_by_issuer_serial == NULL)) - return X509_LU_FAIL; - return ctx->method->get_by_issuer_serial(ctx, type, name, serial, ret); + return 0; + return ctx->method->get_by_issuer_serial(ctx, type, name, serial, ret) > 0; } int X509_LOOKUP_by_fingerprint(X509_LOOKUP *ctx, int type, @@ -149,16 +149,16 @@ int X509_LOOKUP_by_fingerprint(X509_LOOKUP *ctx, int type, X509_OBJECT *ret) { if ((ctx->method == NULL) || (ctx->method->get_by_fingerprint == NULL)) - return X509_LU_FAIL; - return ctx->method->get_by_fingerprint(ctx, type, bytes, len, ret); + return 0; + return ctx->method->get_by_fingerprint(ctx, type, bytes, len, ret) > 0; } int X509_LOOKUP_by_alias(X509_LOOKUP *ctx, int type, char *str, int len, X509_OBJECT *ret) { if ((ctx->method == NULL) || (ctx->method->get_by_alias == NULL)) - return X509_LU_FAIL; - return ctx->method->get_by_alias(ctx, type, str, len, ret); + return 0; + return ctx->method->get_by_alias(ctx, type, str, len, ret) > 0; } static int x509_object_cmp(const X509_OBJECT **a, const X509_OBJECT **b) @@ -188,7 +188,7 @@ X509_STORE *X509_STORE_new(void) if ((ret = (X509_STORE *)OPENSSL_malloc(sizeof(X509_STORE))) == NULL) return NULL; - memset(ret, 0, sizeof(*ret)); + OPENSSL_memset(ret, 0, sizeof(*ret)); CRYPTO_MUTEX_init(&ret->objs_lock); ret->objs = sk_X509_OBJECT_new(x509_object_cmp); if (ret->objs == NULL) @@ -217,6 +217,12 @@ X509_STORE *X509_STORE_new(void) return NULL; } +int X509_STORE_up_ref(X509_STORE *store) +{ + CRYPTO_refcount_inc(&store->references); + return 1; +} + static void cleanup(X509_OBJECT *a) { if (a == NULL) { @@ -296,26 +302,20 @@ int X509_STORE_get_by_subject(X509_STORE_CTX *vs, int type, X509_NAME *name, X509_STORE *ctx = vs->ctx; X509_LOOKUP *lu; X509_OBJECT stmp, *tmp; - int i, j; + int i; CRYPTO_MUTEX_lock_write(&ctx->objs_lock); tmp = X509_OBJECT_retrieve_by_subject(ctx->objs, type, name); - CRYPTO_MUTEX_unlock(&ctx->objs_lock); + CRYPTO_MUTEX_unlock_write(&ctx->objs_lock); if (tmp == NULL || type == X509_LU_CRL) { - for (i = vs->current_method; - i < (int)sk_X509_LOOKUP_num(ctx->get_cert_methods); i++) { + for (i = 0; i < (int)sk_X509_LOOKUP_num(ctx->get_cert_methods); i++) { lu = sk_X509_LOOKUP_value(ctx->get_cert_methods, i); - j = X509_LOOKUP_by_subject(lu, type, name, &stmp); - if (j < 0) { - vs->current_method = j; - return j; - } else if (j) { + if (X509_LOOKUP_by_subject(lu, type, name, &stmp)) { tmp = &stmp; break; } } - vs->current_method = 0; if (tmp == NULL) return 0; } @@ -359,7 +359,7 @@ int X509_STORE_add_cert(X509_STORE *ctx, X509 *x) } else sk_X509_OBJECT_push(ctx->objs, obj); - CRYPTO_MUTEX_unlock(&ctx->objs_lock); + CRYPTO_MUTEX_unlock_write(&ctx->objs_lock); return ret; } @@ -391,12 +391,17 @@ int X509_STORE_add_crl(X509_STORE *ctx, X509_CRL *x) } else sk_X509_OBJECT_push(ctx->objs, obj); - CRYPTO_MUTEX_unlock(&ctx->objs_lock); + CRYPTO_MUTEX_unlock_write(&ctx->objs_lock); return ret; } -void X509_OBJECT_up_ref_count(X509_OBJECT *a) +void X509_STORE_set0_additional_untrusted(X509_STORE *ctx, + STACK_OF(X509) *untrusted) { + ctx->additional_untrusted = untrusted; +} + +int X509_OBJECT_up_ref_count(X509_OBJECT *a) { switch (a->type) { case X509_LU_X509: @@ -406,6 +411,7 @@ void X509_OBJECT_up_ref_count(X509_OBJECT *a) X509_CRL_up_ref(a->data.crl); break; } + return 1; } void X509_OBJECT_free_contents(X509_OBJECT *a) @@ -499,7 +505,7 @@ STACK_OF (X509) * X509_STORE_get1_certs(X509_STORE_CTX *ctx, X509_NAME *nm) * cache */ X509_OBJECT xobj; - CRYPTO_MUTEX_unlock(&ctx->ctx->objs_lock); + CRYPTO_MUTEX_unlock_write(&ctx->ctx->objs_lock); if (!X509_STORE_get_by_subject(ctx, X509_LU_X509, nm, &xobj)) { sk_X509_free(sk); return NULL; @@ -508,7 +514,7 @@ STACK_OF (X509) * X509_STORE_get1_certs(X509_STORE_CTX *ctx, X509_NAME *nm) CRYPTO_MUTEX_lock_write(&ctx->ctx->objs_lock); idx = x509_object_idx_cnt(ctx->ctx->objs, X509_LU_X509, nm, &cnt); if (idx < 0) { - CRYPTO_MUTEX_unlock(&ctx->ctx->objs_lock); + CRYPTO_MUTEX_unlock_write(&ctx->ctx->objs_lock); sk_X509_free(sk); return NULL; } @@ -516,14 +522,14 @@ STACK_OF (X509) * X509_STORE_get1_certs(X509_STORE_CTX *ctx, X509_NAME *nm) for (i = 0; i < cnt; i++, idx++) { obj = sk_X509_OBJECT_value(ctx->ctx->objs, idx); x = obj->data.x509; - if (!sk_X509_push(sk, X509_up_ref(x))) { - CRYPTO_MUTEX_unlock(&ctx->ctx->objs_lock); - X509_free(x); + if (!sk_X509_push(sk, x)) { + CRYPTO_MUTEX_unlock_write(&ctx->ctx->objs_lock); sk_X509_pop_free(sk, X509_free); return NULL; } + X509_up_ref(x); } - CRYPTO_MUTEX_unlock(&ctx->ctx->objs_lock); + CRYPTO_MUTEX_unlock_write(&ctx->ctx->objs_lock); return sk; } @@ -547,7 +553,7 @@ STACK_OF (X509_CRL) * X509_STORE_get1_crls(X509_STORE_CTX *ctx, X509_NAME *nm) CRYPTO_MUTEX_lock_write(&ctx->ctx->objs_lock); idx = x509_object_idx_cnt(ctx->ctx->objs, X509_LU_CRL, nm, &cnt); if (idx < 0) { - CRYPTO_MUTEX_unlock(&ctx->ctx->objs_lock); + CRYPTO_MUTEX_unlock_write(&ctx->ctx->objs_lock); sk_X509_CRL_free(sk); return NULL; } @@ -557,13 +563,13 @@ STACK_OF (X509_CRL) * X509_STORE_get1_crls(X509_STORE_CTX *ctx, X509_NAME *nm) x = obj->data.crl; X509_CRL_up_ref(x); if (!sk_X509_CRL_push(sk, x)) { - CRYPTO_MUTEX_unlock(&ctx->ctx->objs_lock); + CRYPTO_MUTEX_unlock_write(&ctx->ctx->objs_lock); X509_CRL_free(x); sk_X509_CRL_pop_free(sk, X509_CRL_free); return NULL; } } - CRYPTO_MUTEX_unlock(&ctx->ctx->objs_lock); + CRYPTO_MUTEX_unlock_write(&ctx->ctx->objs_lock); return sk; } @@ -606,22 +612,11 @@ int X509_STORE_CTX_get1_issuer(X509 **issuer, X509_STORE_CTX *ctx, X509 *x) { X509_NAME *xn; X509_OBJECT obj, *pobj; - int ok, idx, ret; + int idx, ret; size_t i; xn = X509_get_issuer_name(x); - ok = X509_STORE_get_by_subject(ctx, X509_LU_X509, xn, &obj); - if (ok != X509_LU_X509) { - if (ok == X509_LU_RETRY) { - X509_OBJECT_free_contents(&obj); - OPENSSL_PUT_ERROR(X509, X509_R_SHOULD_RETRY); - return -1; - } else if (ok != X509_LU_FAIL) { - X509_OBJECT_free_contents(&obj); - /* not good :-(, break anyway */ - return -1; - } + if (!X509_STORE_get_by_subject(ctx, X509_LU_X509, xn, &obj)) return 0; - } /* If certificate matches all OK */ if (ctx->check_issued(ctx, x, obj.data.x509)) { *issuer = obj.data.x509; @@ -651,7 +646,7 @@ int X509_STORE_CTX_get1_issuer(X509 **issuer, X509_STORE_CTX *ctx, X509 *x) } } } - CRYPTO_MUTEX_unlock(&ctx->ctx->objs_lock); + CRYPTO_MUTEX_unlock_write(&ctx->ctx->objs_lock); return ret; } diff --git a/Sources/BoringSSL/crypto/x509/x509_obj.c b/Sources/BoringSSL/crypto/x509/x509_obj.c index 641e308d1..33eafc421 100644 --- a/Sources/BoringSSL/crypto/x509/x509_obj.c +++ b/Sources/BoringSSL/crypto/x509/x509_obj.c @@ -64,6 +64,16 @@ #include #include +#include "../internal.h" + + +/* + * Limit to ensure we don't overflow: much greater than + * anything enountered in practice. + */ + +#define NAME_ONELINE_MAX (1024 * 1024) + char *X509_NAME_oneline(X509_NAME *a, char *buf, int len) { X509_NAME_ENTRY *ne; @@ -84,6 +94,8 @@ char *X509_NAME_oneline(X509_NAME *a, char *buf, int len) goto err; b->data[0] = '\0'; len = 200; + } else if (len <= 0) { + return NULL; } if (a == NULL) { if (b) { @@ -108,6 +120,10 @@ char *X509_NAME_oneline(X509_NAME *a, char *buf, int len) type = ne->value->type; num = ne->value->length; + if (num > NAME_ONELINE_MAX) { + OPENSSL_PUT_ERROR(X509, X509_R_NAME_TOO_LONG); + goto end; + } q = ne->value->data; if ((type == V_ASN1_GENERALSTRING) && ((num % 4) == 0)) { @@ -135,6 +151,10 @@ char *X509_NAME_oneline(X509_NAME *a, char *buf, int len) lold = l; l += 1 + l1 + 1 + l2; + if (l > NAME_ONELINE_MAX) { + OPENSSL_PUT_ERROR(X509, X509_R_NAME_TOO_LONG); + goto end; + } if (b != NULL) { if (!BUF_MEM_grow(b, l + 1)) goto err; @@ -144,7 +164,7 @@ char *X509_NAME_oneline(X509_NAME *a, char *buf, int len) } else p = &(buf[lold]); *(p++) = '/'; - memcpy(p, s, (unsigned int)l1); + OPENSSL_memcpy(p, s, (unsigned int)l1); p += l1; *(p++) = '='; @@ -174,7 +194,7 @@ char *X509_NAME_oneline(X509_NAME *a, char *buf, int len) return (p); err: OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); - if (b != NULL) - BUF_MEM_free(b); + end: + BUF_MEM_free(b); return (NULL); } diff --git a/Sources/BoringSSL/crypto/x509/x509_r2x.c b/Sources/BoringSSL/crypto/x509/x509_r2x.c index 83951a2e7..9bdf441f2 100644 --- a/Sources/BoringSSL/crypto/x509/x509_r2x.c +++ b/Sources/BoringSSL/crypto/x509/x509_r2x.c @@ -68,10 +68,12 @@ X509 *X509_REQ_to_X509(X509_REQ *r, int days, EVP_PKEY *pkey) X509 *ret = NULL; X509_CINF *xi = NULL; X509_NAME *xn; + EVP_PKEY *pubkey = NULL; + int res; if ((ret = X509_new()) == NULL) { OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); - goto err; + return NULL; } /* duplicate the request */ @@ -89,9 +91,9 @@ X509 *X509_REQ_to_X509(X509_REQ *r, int days, EVP_PKEY *pkey) } xn = X509_REQ_get_subject_name(r); - if (X509_set_subject_name(ret, X509_NAME_dup(xn)) == 0) + if (X509_set_subject_name(ret, xn) == 0) goto err; - if (X509_set_issuer_name(ret, X509_NAME_dup(xn)) == 0) + if (X509_set_issuer_name(ret, xn) == 0) goto err; if (X509_gmtime_adj(xi->validity->notBefore, 0) == NULL) @@ -100,9 +102,11 @@ X509 *X509_REQ_to_X509(X509_REQ *r, int days, EVP_PKEY *pkey) NULL) goto err; - X509_set_pubkey(ret, X509_REQ_get_pubkey(r)); + pubkey = X509_REQ_get_pubkey(r); + res = X509_set_pubkey(ret, pubkey); + EVP_PKEY_free(pubkey); - if (!X509_sign(ret, pkey, EVP_md5())) + if (!res || !X509_sign(ret, pkey, EVP_md5())) goto err; if (0) { err: diff --git a/Sources/BoringSSL/crypto/x509/x509_set.c b/Sources/BoringSSL/crypto/x509/x509_set.c index 42e9cf0f1..67c1842c2 100644 --- a/Sources/BoringSSL/crypto/x509/x509_set.c +++ b/Sources/BoringSSL/crypto/x509/x509_set.c @@ -147,3 +147,8 @@ int X509_set_pubkey(X509 *x, EVP_PKEY *pkey) return (0); return (X509_PUBKEY_set(&(x->cert_info->key), pkey)); } + +STACK_OF(X509_EXTENSION) *X509_get0_extensions(const X509 *x) +{ + return x->cert_info->extensions; +} diff --git a/Sources/BoringSSL/crypto/x509/x509_txt.c b/Sources/BoringSSL/crypto/x509/x509_txt.c index 86af3fec6..17e6cdb9c 100644 --- a/Sources/BoringSSL/crypto/x509/x509_txt.c +++ b/Sources/BoringSSL/crypto/x509/x509_txt.c @@ -199,6 +199,11 @@ const char *X509_verify_cert_error_string(long n) case X509_V_ERR_IP_ADDRESS_MISMATCH: return ("IP address mismatch"); + case X509_V_ERR_INVALID_CALL: + return ("Invalid certificate verification context"); + case X509_V_ERR_STORE_LOOKUP: + return ("Issuer certificate lookup error"); + default: BIO_snprintf(buf, sizeof buf, "error number %ld", n); return (buf); diff --git a/Sources/BoringSSL/crypto/x509/x509_vfy.c b/Sources/BoringSSL/crypto/x509/x509_vfy.c index 602c8fbce..27b58f45b 100644 --- a/Sources/BoringSSL/crypto/x509/x509_vfy.c +++ b/Sources/BoringSSL/crypto/x509/x509_vfy.c @@ -193,11 +193,12 @@ int X509_verify_cert(X509_STORE_CTX *ctx) int bad_chain = 0; X509_VERIFY_PARAM *param = ctx->param; int depth, i, ok = 0; - int num, j, retry; + int num, j, retry, trust; int (*cb) (int xok, X509_STORE_CTX *xctx); STACK_OF(X509) *sktmp = NULL; if (ctx->cert == NULL) { OPENSSL_PUT_ERROR(X509, X509_R_NO_CERT_SET_FOR_US_TO_VERIFY); + ctx->error = X509_V_ERR_INVALID_CALL; return -1; } if (ctx->chain != NULL) { @@ -206,6 +207,7 @@ int X509_verify_cert(X509_STORE_CTX *ctx) * cannot do another one. */ OPENSSL_PUT_ERROR(X509, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + ctx->error = X509_V_ERR_INVALID_CALL; return -1; } @@ -218,18 +220,43 @@ int X509_verify_cert(X509_STORE_CTX *ctx) ctx->chain = sk_X509_new_null(); if (ctx->chain == NULL || !sk_X509_push(ctx->chain, ctx->cert)) { OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + ctx->error = X509_V_ERR_OUT_OF_MEM; goto end; } X509_up_ref(ctx->cert); ctx->last_untrusted = 1; - /* We use a temporary STACK so we can chop and hack at it */ + /* We use a temporary STACK so we can chop and hack at it. + * sktmp = ctx->untrusted ++ ctx->ctx->additional_untrusted */ if (ctx->untrusted != NULL && (sktmp = sk_X509_dup(ctx->untrusted)) == NULL) { OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + ctx->error = X509_V_ERR_OUT_OF_MEM; goto end; } + if (ctx->ctx->additional_untrusted != NULL) { + if (sktmp == NULL) { + sktmp = sk_X509_new_null(); + if (sktmp == NULL) { + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + ctx->error = X509_V_ERR_OUT_OF_MEM; + goto end; + } + } + + for (size_t k = 0; k < sk_X509_num(ctx->ctx->additional_untrusted); + k++) { + if (!sk_X509_push(sktmp, + sk_X509_value(ctx->ctx->additional_untrusted, + k))) { + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + ctx->error = X509_V_ERR_OUT_OF_MEM; + goto end; + } + } + } + num = sk_X509_num(ctx->chain); x = sk_X509_value(ctx->chain, num - 1); depth = param->depth; @@ -250,8 +277,10 @@ int X509_verify_cert(X509_STORE_CTX *ctx) */ if (ctx->param->flags & X509_V_FLAG_TRUSTED_FIRST) { ok = ctx->get_issuer(&xtmp, ctx, x); - if (ok < 0) + if (ok < 0) { + ctx->error = X509_V_ERR_STORE_LOOKUP; goto end; + } /* * If successful for now free up cert so it will be picked up * again later. @@ -263,11 +292,13 @@ int X509_verify_cert(X509_STORE_CTX *ctx) } /* If we were passed a cert chain, use it first */ - if (ctx->untrusted != NULL) { + if (sktmp != NULL) { xtmp = find_issuer(ctx, sktmp, x); if (xtmp != NULL) { if (!sk_X509_push(ctx->chain, xtmp)) { OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + ctx->error = X509_V_ERR_OUT_OF_MEM; + ok = 0; goto end; } X509_up_ref(xtmp); @@ -348,14 +379,17 @@ int X509_verify_cert(X509_STORE_CTX *ctx) break; ok = ctx->get_issuer(&xtmp, ctx, x); - if (ok < 0) + if (ok < 0) { + ctx->error = X509_V_ERR_STORE_LOOKUP; goto end; + } if (ok == 0) break; x = xtmp; if (!sk_X509_push(ctx->chain, x)) { X509_free(xtmp); OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + ctx->error = X509_V_ERR_OUT_OF_MEM; ok = 0; goto end; } @@ -363,11 +397,13 @@ int X509_verify_cert(X509_STORE_CTX *ctx) } /* we now have our chain, lets check it... */ - i = check_trust(ctx); + trust = check_trust(ctx); /* If explicitly rejected error */ - if (i == X509_TRUST_REJECTED) + if (trust == X509_TRUST_REJECTED) { + ok = 0; goto end; + } /* * If it's not explicitly trusted then check if there is an alternative * chain that could be used. We only do this if we haven't already @@ -375,7 +411,7 @@ int X509_verify_cert(X509_STORE_CTX *ctx) * chain checking */ retry = 0; - if (i != X509_TRUST_TRUSTED + if (trust != X509_TRUST_TRUSTED && !(ctx->param->flags & X509_V_FLAG_TRUSTED_FIRST) && !(ctx->param->flags & X509_V_FLAG_NO_ALT_CHAINS)) { while (j-- > 1) { @@ -412,7 +448,7 @@ int X509_verify_cert(X509_STORE_CTX *ctx) * self signed certificate in which case we've indicated an error already * and set bad_chain == 1 */ - if (i != X509_TRUST_TRUSTED && !bad_chain) { + if (trust != X509_TRUST_TRUSTED && !bad_chain) { if ((chain_ss == NULL) || !ctx->check_issued(ctx, x, chain_ss)) { if (ctx->last_untrusted >= num) ctx->error = X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY; @@ -463,10 +499,10 @@ int X509_verify_cert(X509_STORE_CTX *ctx) if (!ok) goto end; - i = X509_chain_check_suiteb(&ctx->error_depth, NULL, ctx->chain, - ctx->param->flags); - if (i != X509_V_OK) { - ctx->error = i; + int err = X509_chain_check_suiteb(&ctx->error_depth, NULL, ctx->chain, + ctx->param->flags); + if (err != X509_V_OK) { + ctx->error = err; ctx->current_cert = sk_X509_value(ctx->chain, ctx->error_depth); ok = cb(0, ctx); if (!ok) @@ -490,6 +526,10 @@ int X509_verify_cert(X509_STORE_CTX *ctx) sk_X509_free(sktmp); if (chain_ss != NULL) X509_free(chain_ss); + + /* Safety net, error returns must set ctx->error */ + if (ok <= 0 && ctx->error == X509_V_OK) + ctx->error = X509_V_ERR_UNSPECIFIED; return ok; } @@ -571,12 +611,6 @@ static int check_chain_extensions(X509_STORE_CTX *ctx) } else { allow_proxy_certs = ! !(ctx->param->flags & X509_V_FLAG_ALLOW_PROXY_CERTS); - /* - * A hack to keep people who don't want to modify their software - * happy - */ - if (getenv("OPENSSL_ALLOW_PROXY_CERTS")) - allow_proxy_certs = 1; purpose = ctx->param->purpose; } @@ -706,12 +740,19 @@ static int check_name_constraints(X509_STORE_CTX *ctx) NAME_CONSTRAINTS *nc = sk_X509_value(ctx->chain, j)->nc; if (nc) { rv = NAME_CONSTRAINTS_check(x, nc); - if (rv != X509_V_OK) { + switch (rv) { + case X509_V_OK: + continue; + case X509_V_ERR_OUT_OF_MEM: + ctx->error = rv; + return 0; + default: ctx->error = rv; ctx->error_depth = i; ctx->current_cert = x; if (!ctx->verify_cb(0, ctx)) return 0; + break; } } } @@ -841,11 +882,10 @@ static int check_revocation(X509_STORE_CTX *ctx) } static int check_cert(X509_STORE_CTX *ctx) - OPENSSL_SUPPRESS_POTENTIALLY_UNINITIALIZED_WARNINGS { X509_CRL *crl = NULL, *dcrl = NULL; X509 *x; - int ok, cnum; + int ok = 0, cnum; unsigned int last_reasons; cnum = ctx->error_depth; x = sk_X509_value(ctx->chain, cnum); @@ -984,13 +1024,25 @@ static int get_crl_sk(X509_STORE_CTX *ctx, X509_CRL **pcrl, X509_CRL **pdcrl, crl = sk_X509_CRL_value(crls, i); reasons = *preasons; crl_score = get_crl_score(ctx, &crl_issuer, &reasons, crl, x); - - if (crl_score > best_score) { - best_crl = crl; - best_crl_issuer = crl_issuer; - best_score = crl_score; - best_reasons = reasons; + if (crl_score < best_score || crl_score == 0) + continue; + /* If current CRL is equivalent use it if it is newer */ + if (crl_score == best_score && best_crl != NULL) { + int day, sec; + if (ASN1_TIME_diff(&day, &sec, X509_CRL_get_lastUpdate(best_crl), + X509_CRL_get_lastUpdate(crl)) == 0) + continue; + /* + * ASN1_TIME_diff never returns inconsistent signs for |day| + * and |sec|. + */ + if (day <= 0 && sec <= 0) + continue; } + best_crl = crl; + best_crl_issuer = crl_issuer; + best_score = crl_score; + best_reasons = reasons; } if (best_crl) { @@ -1229,6 +1281,17 @@ static void crl_akid_check(X509_STORE_CTX *ctx, X509_CRL *crl, return; } } + + for (i = 0; i < sk_X509_num(ctx->ctx->additional_untrusted); i++) { + crl_issuer = sk_X509_value(ctx->ctx->additional_untrusted, i); + if (X509_NAME_cmp(X509_get_subject_name(crl_issuer), cnm)) + continue; + if (X509_check_akid(crl_issuer, crl->akid) == X509_V_OK) { + *pissuer = crl_issuer; + *pcrl_score |= CRL_SCORE_AKID; + return; + } + } } /* @@ -1603,6 +1666,7 @@ static int check_policy(X509_STORE_CTX *ctx) ctx->param->policies, ctx->param->flags); if (ret == 0) { OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + ctx->error = X509_V_ERR_OUT_OF_MEM; return 0; } /* Invalid or inconsistent extensions */ @@ -1631,7 +1695,12 @@ static int check_policy(X509_STORE_CTX *ctx) if (ctx->param->flags & X509_V_FLAG_NOTIFY_POLICY) { ctx->current_cert = NULL; - ctx->error = X509_V_OK; + /* + * Verification errors need to be "sticky", a callback may have allowed + * an SSL handshake to continue despite an error, and we must then + * remain in an error state. Therefore, we MUST NOT clear earlier + * verification errors by setting the error to X509_V_OK. + */ if (!ctx->verify_cb(2, ctx)) return 0; } @@ -1724,9 +1793,7 @@ static int internal_verify(X509_STORE_CTX *ctx) * explicitly asked for. It doesn't add any security and just wastes * time. */ - if (!xs->valid - && (xs != xi - || (ctx->param->flags & X509_V_FLAG_CHECK_SS_SIGNATURE))) { + if (xs != xi || (ctx->param->flags & X509_V_FLAG_CHECK_SS_SIGNATURE)) { if ((pkey = X509_get_pubkey(xi)) == NULL) { ctx->error = X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY; ctx->current_cert = xi; @@ -1746,8 +1813,6 @@ static int internal_verify(X509_STORE_CTX *ctx) pkey = NULL; } - xs->valid = 1; - check_cert: ok = check_cert_time(ctx, xs); if (!ok) @@ -1798,7 +1863,7 @@ int X509_cmp_time(const ASN1_TIME *ctm, time_t *cmp_time) int max_length = sizeof("YYMMDDHHMMSS+hhmm") - 1; if (remaining < min_length || remaining > max_length) return 0; - memcpy(p, str, 10); + OPENSSL_memcpy(p, str, 10); p += 10; str += 10; remaining -= 10; @@ -1810,7 +1875,7 @@ int X509_cmp_time(const ASN1_TIME *ctm, time_t *cmp_time) int max_length = sizeof("YYYYMMDDHHMMSS.fff+hhmm") - 1; if (remaining < min_length || remaining > max_length) return 0; - memcpy(p, str, 12); + OPENSSL_memcpy(p, str, 12); p += 12; str += 12; remaining -= 12; @@ -2195,7 +2260,7 @@ X509_STORE_CTX *X509_STORE_CTX_new(void) OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); return NULL; } - memset(ctx, 0, sizeof(X509_STORE_CTX)); + OPENSSL_memset(ctx, 0, sizeof(X509_STORE_CTX)); return ctx; } @@ -2213,7 +2278,7 @@ int X509_STORE_CTX_init(X509_STORE_CTX *ctx, X509_STORE *store, X509 *x509, { int ret = 1; - memset(ctx, 0, sizeof(X509_STORE_CTX)); + OPENSSL_memset(ctx, 0, sizeof(X509_STORE_CTX)); ctx->ctx = store; ctx->cert = x509; ctx->untrusted = chain; @@ -2306,7 +2371,7 @@ int X509_STORE_CTX_init(X509_STORE_CTX *ctx, X509_STORE *store, X509 *x509, X509_VERIFY_PARAM_free(ctx->param); } - memset(ctx, 0, sizeof(X509_STORE_CTX)); + OPENSSL_memset(ctx, 0, sizeof(X509_STORE_CTX)); OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); return 0; } @@ -2344,7 +2409,7 @@ void X509_STORE_CTX_cleanup(X509_STORE_CTX *ctx) ctx->chain = NULL; } CRYPTO_free_ex_data(&g_ex_data_class, ctx, &(ctx->ex_data)); - memset(&ctx->ex_data, 0, sizeof(CRYPTO_EX_DATA)); + OPENSSL_memset(&ctx->ex_data, 0, sizeof(CRYPTO_EX_DATA)); } void X509_STORE_CTX_set_depth(X509_STORE_CTX *ctx, int depth) diff --git a/Sources/BoringSSL/crypto/x509/x509_vpm.c b/Sources/BoringSSL/crypto/x509/x509_vpm.c index b51bc176b..2317214c1 100644 --- a/Sources/BoringSSL/crypto/x509/x509_vpm.c +++ b/Sources/BoringSSL/crypto/x509/x509_vpm.c @@ -65,6 +65,8 @@ #include #include "vpm_int.h" +#include "../internal.h" + /* X509_VERIFY_PARAM functions */ @@ -92,7 +94,7 @@ static int int_x509_param_set_hosts(X509_VERIFY_PARAM_ID *id, int mode, * Refuse names with embedded NUL bytes. * XXX: Do we need to push an error onto the error stack? */ - if (name && memchr(name, '\0', namelen)) + if (name && OPENSSL_memchr(name, '\0', namelen)) return 0; if (mode == SET_HOST && id->hosts) { @@ -176,8 +178,8 @@ X509_VERIFY_PARAM *X509_VERIFY_PARAM_new(void) OPENSSL_free(param); return NULL; } - memset(param, 0, sizeof(X509_VERIFY_PARAM)); - memset(paramid, 0, sizeof(X509_VERIFY_PARAM_ID)); + OPENSSL_memset(param, 0, sizeof(X509_VERIFY_PARAM)); + OPENSSL_memset(paramid, 0, sizeof(X509_VERIFY_PARAM_ID)); param->id = paramid; x509_verify_param_zero(param); return param; @@ -192,32 +194,43 @@ void X509_VERIFY_PARAM_free(X509_VERIFY_PARAM *param) OPENSSL_free(param); } -/* +/*- * This function determines how parameters are "inherited" from one structure - * to another. There are several different ways this can happen. 1. If a - * child structure needs to have its values initialized from a parent they are - * simply copied across. For example SSL_CTX copied to SSL. 2. If the - * structure should take on values only if they are currently unset. For - * example the values in an SSL structure will take appropriate value for SSL - * servers or clients but only if the application has not set new ones. The - * "inh_flags" field determines how this function behaves. Normally any - * values which are set in the default are not copied from the destination and - * verify flags are ORed together. If X509_VP_FLAG_DEFAULT is set then - * anything set in the source is copied to the destination. Effectively the - * values in "to" become default values which will be used only if nothing new - * is set in "from". If X509_VP_FLAG_OVERWRITE is set then all value are - * copied across whether they are set or not. Flags is still Ored though. If - * X509_VP_FLAG_RESET_FLAGS is set then the flags value is copied instead of - * ORed. If X509_VP_FLAG_LOCKED is set then no values are copied. If - * X509_VP_FLAG_ONCE is set then the current inh_flags setting is zeroed after - * the next call. + * to another. There are several different ways this can happen. + * + * 1. If a child structure needs to have its values initialized from a parent + * they are simply copied across. For example SSL_CTX copied to SSL. + * 2. If the structure should take on values only if they are currently unset. + * For example the values in an SSL structure will take appropriate value + * for SSL servers or clients but only if the application has not set new + * ones. + * + * The "inh_flags" field determines how this function behaves. + * + * Normally any values which are set in the default are not copied from the + * destination and verify flags are ORed together. + * + * If X509_VP_FLAG_DEFAULT is set then anything set in the source is copied + * to the destination. Effectively the values in "to" become default values + * which will be used only if nothing new is set in "from". + * + * If X509_VP_FLAG_OVERWRITE is set then all value are copied across whether + * they are set or not. Flags is still Ored though. + * + * If X509_VP_FLAG_RESET_FLAGS is set then the flags value is copied instead + * of ORed. + * + * If X509_VP_FLAG_LOCKED is set then no values are copied. + * + * If X509_VP_FLAG_ONCE is set then the current inh_flags setting is zeroed + * after the next call. */ /* Macro to test if a field should be copied from src to dest */ #define test_x509_verify_param_copy(field, def) \ - (to_overwrite || \ - ((src->field != def) && (to_default || (dest->field == def)))) + (to_overwrite || \ + ((src->field != (def)) && (to_default || (dest->field == (def))))) /* As above but for ID fields */ @@ -502,7 +515,7 @@ const char *X509_VERIFY_PARAM_get0_name(const X509_VERIFY_PARAM *param) static const X509_VERIFY_PARAM_ID _empty_id = { NULL, 0U, NULL, NULL, 0, NULL, 0 }; -#define vpm_empty_id (X509_VERIFY_PARAM_ID *)&_empty_id +#define vpm_empty_id ((X509_VERIFY_PARAM_ID *)&_empty_id) /* * Default verify parameters: these are used for various applications and can diff --git a/Sources/BoringSSL/crypto/x509/x509cset.c b/Sources/BoringSSL/crypto/x509/x509cset.c index a292710ee..2fd48a9c8 100644 --- a/Sources/BoringSSL/crypto/x509/x509cset.c +++ b/Sources/BoringSSL/crypto/x509/x509cset.c @@ -129,9 +129,10 @@ int X509_CRL_sort(X509_CRL *c) return 1; } -void X509_CRL_up_ref(X509_CRL *crl) +int X509_CRL_up_ref(X509_CRL *crl) { CRYPTO_refcount_inc(&crl->references); + return 1; } int X509_REVOKED_set_revocationDate(X509_REVOKED *x, ASN1_TIME *tm) diff --git a/Sources/BoringSSL/crypto/x509/x509name.c b/Sources/BoringSSL/crypto/x509/x509name.c index 050e16a84..610de5f29 100644 --- a/Sources/BoringSSL/crypto/x509/x509name.c +++ b/Sources/BoringSSL/crypto/x509/x509name.c @@ -63,6 +63,9 @@ #include #include +#include "../internal.h" + + int X509_NAME_get_text_by_NID(X509_NAME *name, int nid, char *buf, int len) { const ASN1_OBJECT *obj; @@ -86,7 +89,7 @@ int X509_NAME_get_text_by_OBJ(X509_NAME *name, const ASN1_OBJECT *obj, i = (data->length > (len - 1)) ? (len - 1) : data->length; if (buf == NULL) return (data->length); - memcpy(buf, data->data, i); + OPENSSL_memcpy(buf, data->data, i); buf[i] = '\0'; return (i); } diff --git a/Sources/BoringSSL/crypto/x509/x_crl.c b/Sources/BoringSSL/crypto/x509/x_crl.c index cd6489012..6450e8470 100644 --- a/Sources/BoringSSL/crypto/x509/x_crl.c +++ b/Sources/BoringSSL/crypto/x509/x_crl.c @@ -283,7 +283,7 @@ static int crl_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it, if ((nid == NID_issuing_distribution_point) || (nid == NID_authority_key_identifier) || (nid == NID_delta_crl)) - break;; + continue; crl->flags |= EXFLAG_CRITICAL; break; } @@ -299,7 +299,9 @@ static int crl_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it, break; case ASN1_OP_FREE_POST: - if (crl->meth->crl_free) { + /* |crl->meth| may be NULL if constructing the object failed before + * |ASN1_OP_NEW_POST| was run. */ + if (crl->meth && crl->meth->crl_free) { if (!crl->meth->crl_free(crl)) return 0; } @@ -460,14 +462,14 @@ static int def_crl_lookup(X509_CRL *crl, CRYPTO_STATIC_MUTEX_lock_read(&g_crl_sort_lock); const int is_sorted = sk_X509_REVOKED_is_sorted(crl->crl->revoked); - CRYPTO_STATIC_MUTEX_unlock(&g_crl_sort_lock); + CRYPTO_STATIC_MUTEX_unlock_read(&g_crl_sort_lock); if (!is_sorted) { CRYPTO_STATIC_MUTEX_lock_write(&g_crl_sort_lock); if (!sk_X509_REVOKED_is_sorted(crl->crl->revoked)) { sk_X509_REVOKED_sort(crl->crl->revoked); } - CRYPTO_STATIC_MUTEX_unlock(&g_crl_sort_lock); + CRYPTO_STATIC_MUTEX_unlock_write(&g_crl_sort_lock); } if (!sk_X509_REVOKED_find(crl->crl->revoked, &idx, &rtmp)) diff --git a/Sources/BoringSSL/crypto/x509/x_name.c b/Sources/BoringSSL/crypto/x509/x_name.c index 226e76dc4..4abdc9163 100644 --- a/Sources/BoringSSL/crypto/x509/x_name.c +++ b/Sources/BoringSSL/crypto/x509/x_name.c @@ -67,10 +67,19 @@ #include #include "../asn1/asn1_locl.h" +#include "../internal.h" + typedef STACK_OF(X509_NAME_ENTRY) STACK_OF_X509_NAME_ENTRY; DECLARE_STACK_OF(STACK_OF_X509_NAME_ENTRY) +/* + * Maximum length of X509_NAME: much larger than anything we should + * ever see in practice. + */ + +#define X509_NAME_MAX (1024 * 1024) + static int x509_name_ex_d2i(ASN1_VALUE **val, const unsigned char **in, long len, const ASN1_ITEM *it, @@ -87,10 +96,6 @@ static int asn1_string_canon(ASN1_STRING *out, ASN1_STRING *in); static int i2d_name_canon(STACK_OF(STACK_OF_X509_NAME_ENTRY) * intname, unsigned char **in); -static int x509_name_ex_print(BIO *out, ASN1_VALUE **pval, - int indent, - const char *fname, const ASN1_PCTX *pctx); - ASN1_SEQUENCE(X509_NAME_ENTRY) = { ASN1_SIMPLE(X509_NAME_ENTRY, object, ASN1_OBJECT), ASN1_SIMPLE(X509_NAME_ENTRY, value, ASN1_PRINTABLE) @@ -126,7 +131,7 @@ static const ASN1_EXTERN_FUNCS x509_name_ff = { 0, /* Default clear behaviour is OK */ x509_name_ex_d2i, x509_name_ex_i2d, - x509_name_ex_print + NULL, }; IMPLEMENT_EXTERN_ASN1(X509_NAME, V_ASN1_SEQUENCE, x509_name_ff) @@ -208,6 +213,10 @@ static int x509_name_ex_d2i(ASN1_VALUE **val, int ret; STACK_OF(X509_NAME_ENTRY) *entries; X509_NAME_ENTRY *entry; + /* Bound the size of an X509_NAME we are willing to parse. */ + if (len > X509_NAME_MAX) { + len = X509_NAME_MAX; + } q = p; /* Get internal representation of Name */ @@ -220,13 +229,12 @@ static int x509_name_ex_d2i(ASN1_VALUE **val, if (*val) x509_name_ex_free(val, NULL); + if (!x509_name_ex_new(&nm.a, NULL)) + goto err; /* We've decoded it: now cache encoding */ - if (!x509_name_ex_new(&nm.a, NULL) || !BUF_MEM_grow(nm.x->bytes, p - q)) { - sk_STACK_OF_X509_NAME_ENTRY_pop_free(intname.s, - local_sk_X509_NAME_ENTRY_pop_free); + if (!BUF_MEM_grow(nm.x->bytes, p - q)) goto err; - } - memcpy(nm.x->bytes->data, q, p - q); + OPENSSL_memcpy(nm.x->bytes->data, q, p - q); /* Convert internal representation to X509_NAME structure */ for (i = 0; i < sk_STACK_OF_X509_NAME_ENTRY_num(intname.s); i++) { @@ -236,13 +244,14 @@ static int x509_name_ex_d2i(ASN1_VALUE **val, entry->set = i; if (!sk_X509_NAME_ENTRY_push(nm.x->entries, entry)) goto err; + sk_X509_NAME_ENTRY_set(entries, j, NULL); } - sk_X509_NAME_ENTRY_free(entries); } - sk_STACK_OF_X509_NAME_ENTRY_free(intname.s); ret = x509_name_canon(nm.x); if (!ret) goto err; + sk_STACK_OF_X509_NAME_ENTRY_pop_free(intname.s, + local_sk_X509_NAME_ENTRY_free); nm.x->modified = 0; *val = nm.a; *in = p; @@ -250,6 +259,8 @@ static int x509_name_ex_d2i(ASN1_VALUE **val, err: if (nm.x != NULL) X509_NAME_free(nm.x); + sk_STACK_OF_X509_NAME_ENTRY_pop_free(intname.s, + local_sk_X509_NAME_ENTRY_pop_free); OPENSSL_PUT_ERROR(X509, ERR_R_ASN1_LIB); return 0; } @@ -269,7 +280,7 @@ static int x509_name_ex_i2d(ASN1_VALUE **val, unsigned char **out, } ret = a->bytes->length; if (out != NULL) { - memcpy(*out, a->bytes->data, ret); + OPENSSL_memcpy(*out, a->bytes->data, ret); *out += ret; } return ret; @@ -298,8 +309,10 @@ static int x509_name_encode(X509_NAME *a) entries = sk_X509_NAME_ENTRY_new_null(); if (!entries) goto memerr; - if (!sk_STACK_OF_X509_NAME_ENTRY_push(intname.s, entries)) + if (!sk_STACK_OF_X509_NAME_ENTRY_push(intname.s, entries)) { + sk_X509_NAME_ENTRY_free(entries); goto memerr; + } set = entry->set; } if (!sk_X509_NAME_ENTRY_push(entries, entry)) @@ -323,24 +336,14 @@ static int x509_name_encode(X509_NAME *a) return -1; } -static int x509_name_ex_print(BIO *out, ASN1_VALUE **pval, - int indent, - const char *fname, const ASN1_PCTX *pctx) -{ - if (X509_NAME_print_ex(out, (X509_NAME *)*pval, - indent, pctx->nm_flags) <= 0) - return 0; - return 2; -} - /* * This function generates the canonical encoding of the Name structure. In * it all strings are converted to UTF8, leading, trailing and multiple * spaces collapsed, converted to lower case and the leading SEQUENCE header * removed. In future we could also normalize the UTF8 too. By doing this * comparison of Name structures can be rapidly perfomed by just using - * memcmp() of the canonical encoding. By omitting the leading SEQUENCE name - * constraints of type dirName can also be checked with a simple memcmp(). + * OPENSSL_memcmp() of the canonical encoding. By omitting the leading SEQUENCE name + * constraints of type dirName can also be checked with a simple OPENSSL_memcmp(). */ static int x509_name_canon(X509_NAME *a) @@ -349,7 +352,7 @@ static int x509_name_canon(X509_NAME *a) STACK_OF(STACK_OF_X509_NAME_ENTRY) *intname = NULL; STACK_OF(X509_NAME_ENTRY) *entries = NULL; X509_NAME_ENTRY *entry, *tmpentry = NULL; - int set = -1, ret = 0; + int set = -1, ret = 0, len; size_t i; if (a->canon_enc) { @@ -389,7 +392,11 @@ static int x509_name_canon(X509_NAME *a) /* Finally generate encoding */ - a->canon_enclen = i2d_name_canon(intname, NULL); + len = i2d_name_canon(intname, NULL); + if (len < 0) { + goto err; + } + a->canon_enclen = len; p = OPENSSL_malloc(a->canon_enclen); @@ -453,10 +460,10 @@ static int asn1_string_canon(ASN1_STRING *out, ASN1_STRING *in) len--; } - to = from + len - 1; + to = from + len; /* Ignore trailing spaces */ - while ((len > 0) && !(*to & 0x80) && isspace(*to)) { + while ((len > 0) && !(to[-1] & 0x80) && isspace(to[-1])) { to--; len--; } diff --git a/Sources/BoringSSL/crypto/x509/x_pkey.c b/Sources/BoringSSL/crypto/x509/x_pkey.c index fc445954e..8231a24b3 100644 --- a/Sources/BoringSSL/crypto/x509/x_pkey.c +++ b/Sources/BoringSSL/crypto/x509/x_pkey.c @@ -63,6 +63,9 @@ #include #include +#include "../internal.h" + + X509_PKEY *X509_PKEY_new(void) { X509_PKEY *ret = OPENSSL_malloc(sizeof(X509_PKEY)); @@ -70,7 +73,7 @@ X509_PKEY *X509_PKEY_new(void) OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); goto err; } - memset(ret, 0, sizeof(X509_PKEY)); + OPENSSL_memset(ret, 0, sizeof(X509_PKEY)); ret->enc_algor = X509_ALGOR_new(); if (ret->enc_algor == NULL) diff --git a/Sources/BoringSSL/crypto/x509/x_pubkey.c b/Sources/BoringSSL/crypto/x509/x_pubkey.c index 47f256c76..3d07d661b 100644 --- a/Sources/BoringSSL/crypto/x509/x_pubkey.c +++ b/Sources/BoringSSL/crypto/x509/x_pubkey.c @@ -54,6 +54,8 @@ * copied and put under another distribution licence * [including the GNU Public Licence.] */ +#include + #include #include @@ -64,7 +66,6 @@ #include #include #include -#include #include "../internal.h" @@ -139,10 +140,11 @@ EVP_PKEY *X509_PUBKEY_get(X509_PUBKEY *key) CRYPTO_STATIC_MUTEX_lock_read(&g_pubkey_lock); if (key->pkey != NULL) { - CRYPTO_STATIC_MUTEX_unlock(&g_pubkey_lock); - return EVP_PKEY_up_ref(key->pkey); + CRYPTO_STATIC_MUTEX_unlock_read(&g_pubkey_lock); + EVP_PKEY_up_ref(key->pkey); + return key->pkey; } - CRYPTO_STATIC_MUTEX_unlock(&g_pubkey_lock); + CRYPTO_STATIC_MUTEX_unlock_read(&g_pubkey_lock); /* Re-encode the |X509_PUBKEY| to DER and parse it. */ int spki_len = i2d_X509_PUBKEY(key, &spki); @@ -160,16 +162,17 @@ EVP_PKEY *X509_PUBKEY_get(X509_PUBKEY *key) /* Check to see if another thread set key->pkey first */ CRYPTO_STATIC_MUTEX_lock_write(&g_pubkey_lock); if (key->pkey) { - CRYPTO_STATIC_MUTEX_unlock(&g_pubkey_lock); + CRYPTO_STATIC_MUTEX_unlock_write(&g_pubkey_lock); EVP_PKEY_free(ret); ret = key->pkey; } else { key->pkey = ret; - CRYPTO_STATIC_MUTEX_unlock(&g_pubkey_lock); + CRYPTO_STATIC_MUTEX_unlock_write(&g_pubkey_lock); } OPENSSL_free(spki); - return EVP_PKEY_up_ref(ret); + EVP_PKEY_up_ref(ret); + return ret; error: OPENSSL_free(spki); diff --git a/Sources/BoringSSL/crypto/x509/x_x509.c b/Sources/BoringSSL/crypto/x509/x_x509.c index 1ae37c4b0..15118d299 100644 --- a/Sources/BoringSSL/crypto/x509/x_x509.c +++ b/Sources/BoringSSL/crypto/x509/x_x509.c @@ -55,12 +55,15 @@ * copied and put under another distribution licence * [including the GNU Public Licence.] */ +#include +#include #include #include #include #include #include +#include #include #include #include @@ -95,7 +98,6 @@ static int x509_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it, switch (operation) { case ASN1_OP_NEW_POST: - ret->valid = 0; ret->name = NULL; ret->ex_flags = 0; ret->ex_pathlen = -1; @@ -103,7 +105,14 @@ static int x509_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it, ret->akid = NULL; ret->aux = NULL; ret->crldp = NULL; + ret->buf = NULL; CRYPTO_new_ex_data(&ret->ex_data); + CRYPTO_MUTEX_init(&ret->lock); + break; + + case ASN1_OP_D2I_PRE: + CRYPTO_BUFFER_free(ret->buf); + ret->buf = NULL; break; case ASN1_OP_D2I_POST: @@ -113,6 +122,7 @@ static int x509_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it, break; case ASN1_OP_FREE_POST: + CRYPTO_MUTEX_cleanup(&ret->lock); CRYPTO_free_ex_data(&g_ex_data_class, ret, &ret->ex_data); X509_CERT_AUX_free(ret->aux); ASN1_OCTET_STRING_free(ret->skid); @@ -121,9 +131,8 @@ static int x509_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it, policy_cache_free(ret->policy_cache); GENERAL_NAMES_free(ret->altname); NAME_CONSTRAINTS_free(ret->nc); - - if (ret->name != NULL) - OPENSSL_free(ret->name); + CRYPTO_BUFFER_free(ret->buf); + OPENSSL_free(ret->name); break; } @@ -142,10 +151,40 @@ IMPLEMENT_ASN1_FUNCTIONS(X509) IMPLEMENT_ASN1_DUP_FUNCTION(X509) -X509 *X509_up_ref(X509 *x) +X509 *X509_parse_from_buffer(CRYPTO_BUFFER *buf) { + if (CRYPTO_BUFFER_len(buf) > LONG_MAX) { + OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW); + return 0; + } + + X509 *x509 = X509_new(); + if (x509 == NULL) { + return NULL; + } + + x509->cert_info->enc.alias_only_on_next_parse = 1; + + const uint8_t *inp = CRYPTO_BUFFER_data(buf); + X509 *x509p = x509; + X509 *ret = d2i_X509(&x509p, &inp, CRYPTO_BUFFER_len(buf)); + if (ret == NULL || + inp - CRYPTO_BUFFER_data(buf) != (ptrdiff_t)CRYPTO_BUFFER_len(buf)) { + X509_free(x509p); + return NULL; + } + assert(x509p == x509); + assert(ret == x509); + + CRYPTO_BUFFER_up_ref(buf); + ret->buf = buf; + + return ret; +} + +int X509_up_ref(X509 *x) { CRYPTO_refcount_inc(&x->references); - return x; + return 1; } int X509_get_ex_new_index(long argl, void *argp, CRYPTO_EX_unused * unused, @@ -204,12 +243,73 @@ X509 *d2i_X509_AUX(X509 **a, const unsigned char **pp, long length) return NULL; } +/* + * Serialize trusted certificate to *pp or just return the required buffer + * length if pp == NULL. We ultimately want to avoid modifying *pp in the + * error path, but that depends on similar hygiene in lower-level functions. + * Here we avoid compounding the problem. + */ +static int i2d_x509_aux_internal(X509 *a, unsigned char **pp) +{ + int length, tmplen; + unsigned char *start = pp != NULL ? *pp : NULL; + + assert(pp == NULL || *pp != NULL); + + /* + * This might perturb *pp on error, but fixing that belongs in i2d_X509() + * not here. It should be that if a == NULL length is zero, but we check + * both just in case. + */ + length = i2d_X509(a, pp); + if (length <= 0 || a == NULL) { + return length; + } + + tmplen = i2d_X509_CERT_AUX(a->aux, pp); + if (tmplen < 0) { + if (start != NULL) + *pp = start; + return tmplen; + } + length += tmplen; + + return length; +} + +/* + * Serialize trusted certificate to *pp, or just return the required buffer + * length if pp == NULL. + * + * When pp is not NULL, but *pp == NULL, we allocate the buffer, but since + * we're writing two ASN.1 objects back to back, we can't have i2d_X509() do + * the allocation, nor can we allow i2d_X509_CERT_AUX() to increment the + * allocated buffer. + */ int i2d_X509_AUX(X509 *a, unsigned char **pp) { int length; - length = i2d_X509(a, pp); - if (a) - length += i2d_X509_CERT_AUX(a->aux, pp); + unsigned char *tmp; + + /* Buffer provided by caller */ + if (pp == NULL || *pp != NULL) + return i2d_x509_aux_internal(a, pp); + + /* Obtain the combined length */ + if ((length = i2d_x509_aux_internal(a, NULL)) <= 0) + return length; + + /* Allocate requisite combined storage */ + *pp = tmp = OPENSSL_malloc(length); + if (tmp == NULL) + return -1; /* Push error onto error stack? */ + + /* Encode, but keep *pp at the originally malloced pointer */ + length = i2d_x509_aux_internal(a, &tmp); + if (length <= 0) { + OPENSSL_free(*pp); + *pp = NULL; + } return length; } diff --git a/Sources/BoringSSL/crypto/x509v3/pcy_cache.c b/Sources/BoringSSL/crypto/x509v3/pcy_cache.c index f1e512eab..b8a4be274 100644 --- a/Sources/BoringSSL/crypto/x509v3/pcy_cache.c +++ b/Sources/BoringSSL/crypto/x509v3/pcy_cache.c @@ -241,7 +241,7 @@ const X509_POLICY_CACHE *policy_cache_set(X509 *x) CRYPTO_STATIC_MUTEX_lock_read(&g_x509_policy_cache_lock); cache = x->policy_cache; - CRYPTO_STATIC_MUTEX_unlock(&g_x509_policy_cache_lock); + CRYPTO_STATIC_MUTEX_unlock_read(&g_x509_policy_cache_lock); if (cache != NULL) return cache; @@ -250,7 +250,7 @@ const X509_POLICY_CACHE *policy_cache_set(X509 *x) if (x->policy_cache == NULL) policy_cache_new(x); cache = x->policy_cache; - CRYPTO_STATIC_MUTEX_unlock(&g_x509_policy_cache_lock); + CRYPTO_STATIC_MUTEX_unlock_write(&g_x509_policy_cache_lock); return cache; } diff --git a/Sources/BoringSSL/crypto/x509v3/pcy_int.h b/Sources/BoringSSL/crypto/x509v3/pcy_int.h index b5075f9ed..1e7650374 100644 --- a/Sources/BoringSSL/crypto/x509v3/pcy_int.h +++ b/Sources/BoringSSL/crypto/x509v3/pcy_int.h @@ -180,8 +180,8 @@ struct X509_POLICY_TREE_st { /* Useful macros */ -#define node_data_critical(data) (data->flags & POLICY_DATA_FLAG_CRITICAL) -#define node_critical(node) node_data_critical(node->data) +#define node_data_critical(data) ((data)->flags & POLICY_DATA_FLAG_CRITICAL) +#define node_critical(node) node_data_critical((node)->data) /* Internal functions */ diff --git a/Sources/BoringSSL/crypto/x509v3/pcy_tree.c b/Sources/BoringSSL/crypto/x509v3/pcy_tree.c index e7484e52c..a588107b8 100644 --- a/Sources/BoringSSL/crypto/x509v3/pcy_tree.c +++ b/Sources/BoringSSL/crypto/x509v3/pcy_tree.c @@ -66,6 +66,7 @@ #include #include "pcy_int.h" +#include "../internal.h" /* * Enable this to print out the complete policy tree at various point during @@ -238,7 +239,7 @@ static int tree_init(X509_POLICY_TREE **ptree, STACK_OF(X509) *certs, return 0; } - memset(tree->levels, 0, n * sizeof(X509_POLICY_LEVEL)); + OPENSSL_memset(tree->levels, 0, n * sizeof(X509_POLICY_LEVEL)); tree->nlevel = n; @@ -255,7 +256,8 @@ static int tree_init(X509_POLICY_TREE **ptree, STACK_OF(X509) *certs, level++; x = sk_X509_value(certs, i); cache = policy_cache_set(x); - level->cert = X509_up_ref(x); + X509_up_ref(x); + level->cert = x; if (!cache->anyPolicy) level->flags |= X509_V_FLAG_INHIBIT_ANY; diff --git a/Sources/BoringSSL/crypto/x509v3/v3_conf.c b/Sources/BoringSSL/crypto/x509v3/v3_conf.c index 7405e1e4b..ff2eae141 100644 --- a/Sources/BoringSSL/crypto/x509v3/v3_conf.c +++ b/Sources/BoringSSL/crypto/x509v3/v3_conf.c @@ -138,10 +138,12 @@ static X509_EXTENSION *do_ext_nconf(CONF *conf, X509V3_CTX *ctx, int ext_nid, nval = NCONF_get_section(conf, value + 1); else nval = X509V3_parse_list(value); - if (sk_CONF_VALUE_num(nval) <= 0) { + if (nval == NULL || sk_CONF_VALUE_num(nval) <= 0) { OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_EXTENSION_STRING); ERR_add_error_data(4, "name=", OBJ_nid2sn(ext_nid), ",section=", value); + if (*value != '@') + sk_CONF_VALUE_pop_free(nval, X509V3_conf_free); return NULL; } ext_struc = method->v2i(method, ctx, nval); @@ -263,10 +265,9 @@ static int v3_check_generic(char **value) static X509_EXTENSION *v3_generic_extension(const char *ext, char *value, int crit, int gen_type, X509V3_CTX *ctx) - OPENSSL_SUPPRESS_POTENTIALLY_UNINITIALIZED_WARNINGS { unsigned char *ext_der = NULL; - long ext_len; + long ext_len = 0; ASN1_OBJECT *obj = NULL; ASN1_OCTET_STRING *oct = NULL; X509_EXTENSION *extension = NULL; diff --git a/Sources/BoringSSL/crypto/x509v3/v3_cpols.c b/Sources/BoringSSL/crypto/x509v3/v3_cpols.c index 4d086ab5f..7de54962b 100644 --- a/Sources/BoringSSL/crypto/x509v3/v3_cpols.c +++ b/Sources/BoringSSL/crypto/x509v3/v3_cpols.c @@ -190,6 +190,11 @@ static STACK_OF(POLICYINFO) *r2i_certpol(X509V3_EXT_METHOD *method, goto err; } pol = POLICYINFO_new(); + if (pol == NULL) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + ASN1_OBJECT_free(pobj); + goto err; + } pol->policyid = pobj; } if (!sk_POLICYINFO_push(pols, pol)) { @@ -395,10 +400,10 @@ static int nref_nos(STACK_OF(ASN1_INTEGER) *nnums, STACK_OF(CONF_VALUE) *nos) return 1; merr: + ASN1_INTEGER_free(aint); OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); err: - sk_ASN1_INTEGER_pop_free(nnums, ASN1_STRING_free); return 0; } diff --git a/Sources/BoringSSL/crypto/x509v3/v3_ia5.c b/Sources/BoringSSL/crypto/x509v3/v3_ia5.c index 6fc6b59b5..6b2056dcb 100644 --- a/Sources/BoringSSL/crypto/x509v3/v3_ia5.c +++ b/Sources/BoringSSL/crypto/x509v3/v3_ia5.c @@ -67,6 +67,9 @@ #include #include +#include "../internal.h" + + static char *i2s_ASN1_IA5STRING(X509V3_EXT_METHOD *method, ASN1_IA5STRING *ia5); static ASN1_IA5STRING *s2i_ASN1_IA5STRING(X509V3_EXT_METHOD *method, @@ -92,7 +95,7 @@ static char *i2s_ASN1_IA5STRING(X509V3_EXT_METHOD *method, OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); return NULL; } - memcpy(tmp, ia5->data, ia5->length); + OPENSSL_memcpy(tmp, ia5->data, ia5->length); tmp[ia5->length] = 0; return tmp; } diff --git a/Sources/BoringSSL/crypto/x509v3/v3_ncons.c b/Sources/BoringSSL/crypto/x509v3/v3_ncons.c index 368ad2726..fc2843ef1 100644 --- a/Sources/BoringSSL/crypto/x509v3/v3_ncons.c +++ b/Sources/BoringSSL/crypto/x509v3/v3_ncons.c @@ -65,6 +65,9 @@ #include #include +#include "../internal.h" + + static void *v2i_NAME_CONSTRAINTS(const X509V3_EXT_METHOD *method, X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval); @@ -365,7 +368,7 @@ static int nc_dn(X509_NAME *nm, X509_NAME *base) return X509_V_ERR_OUT_OF_MEM; if (base->canon_enclen > nm->canon_enclen) return X509_V_ERR_PERMITTED_VIOLATION; - if (memcmp(base->canon_enc, nm->canon_enc, base->canon_enclen)) + if (OPENSSL_memcmp(base->canon_enc, nm->canon_enc, base->canon_enclen)) return X509_V_ERR_PERMITTED_VIOLATION; return X509_V_OK; } diff --git a/Sources/BoringSSL/crypto/x509v3/v3_pci.c b/Sources/BoringSSL/crypto/x509v3/v3_pci.c index 220f65e11..68dca5e7b 100644 --- a/Sources/BoringSSL/crypto/x509v3/v3_pci.c +++ b/Sources/BoringSSL/crypto/x509v3/v3_pci.c @@ -44,6 +44,9 @@ #include #include +#include "../internal.h" + + static int i2r_pci(X509V3_EXT_METHOD *method, PROXY_CERT_INFO_EXTENSION *ext, BIO *out, int indent); static PROXY_CERT_INFO_EXTENSION *r2i_pci(X509V3_EXT_METHOD *method, @@ -133,7 +136,7 @@ static int process_pci_value(CONF_VALUE *val, (*policy)->length + val_len + 1); if (tmp_data) { (*policy)->data = tmp_data; - memcpy(&(*policy)->data[(*policy)->length], + OPENSSL_memcpy(&(*policy)->data[(*policy)->length], tmp_data2, val_len); (*policy)->length += val_len; (*policy)->data[(*policy)->length] = '\0'; @@ -171,7 +174,7 @@ static int process_pci_value(CONF_VALUE *val, break; (*policy)->data = tmp_data; - memcpy(&(*policy)->data[(*policy)->length], buf, n); + OPENSSL_memcpy(&(*policy)->data[(*policy)->length], buf, n); (*policy)->length += n; (*policy)->data[(*policy)->length] = '\0'; } @@ -188,7 +191,7 @@ static int process_pci_value(CONF_VALUE *val, (*policy)->length + val_len + 1); if (tmp_data) { (*policy)->data = tmp_data; - memcpy(&(*policy)->data[(*policy)->length], + OPENSSL_memcpy(&(*policy)->data[(*policy)->length], val->value + 5, val_len); (*policy)->length += val_len; (*policy)->data[(*policy)->length] = '\0'; diff --git a/Sources/BoringSSL/crypto/x509v3/v3_prn.c b/Sources/BoringSSL/crypto/x509v3/v3_prn.c index 5015efcc1..2f5efcff0 100644 --- a/Sources/BoringSSL/crypto/x509v3/v3_prn.c +++ b/Sources/BoringSSL/crypto/x509v3/v3_prn.c @@ -207,9 +207,6 @@ static int unknown_ext_print(BIO *out, X509_EXTENSION *ext, return 1; case X509V3_EXT_PARSE_UNKNOWN: - return ASN1_parse_dump(out, - ext->value->data, ext->value->length, indent, - -1); case X509V3_EXT_DUMP_UNKNOWN: return BIO_hexdump(out, ext->value->data, ext->value->length, indent); diff --git a/Sources/BoringSSL/crypto/x509v3/v3_purp.c b/Sources/BoringSSL/crypto/x509v3/v3_purp.c index 85bc15b74..324de85a0 100644 --- a/Sources/BoringSSL/crypto/x509v3/v3_purp.c +++ b/Sources/BoringSSL/crypto/x509v3/v3_purp.c @@ -146,9 +146,7 @@ int X509_check_purpose(X509 *x, int id, int ca) { int idx; const X509_PURPOSE *pt; - if (!(x->ex_flags & EXFLAG_SET)) { - x509v3_cache_extensions(x); - } + x509v3_cache_extensions(x); if (id == -1) return 1; idx = X509_PURPOSE_get_by_id(id); @@ -407,16 +405,6 @@ static void setup_crldp(X509 *x) setup_dp(x, sk_DIST_POINT_value(x->crldp, i)); } -/* - * g_x509_cache_extensions_lock is used to protect against concurrent calls - * to |x509v3_cache_extensions|. Ideally this would be done with a - * |CRYPTO_once_t| in the |X509| structure, but |CRYPTO_once_t| isn't public. - * Note: it's not entirely clear whether this lock is needed. Not all paths to - * this function took a lock in OpenSSL. - */ -static struct CRYPTO_STATIC_MUTEX g_x509_cache_extensions_lock = - CRYPTO_STATIC_MUTEX_INIT; - static void x509v3_cache_extensions(X509 *x) { BASIC_CONSTRAINTS *bs; @@ -428,10 +416,17 @@ static void x509v3_cache_extensions(X509 *x) size_t i; int j; - CRYPTO_STATIC_MUTEX_lock_write(&g_x509_cache_extensions_lock); + CRYPTO_MUTEX_lock_read(&x->lock); + const int is_set = x->ex_flags & EXFLAG_SET; + CRYPTO_MUTEX_unlock_read(&x->lock); + if (is_set) { + return; + } + + CRYPTO_MUTEX_lock_write(&x->lock); if (x->ex_flags & EXFLAG_SET) { - CRYPTO_STATIC_MUTEX_unlock(&g_x509_cache_extensions_lock); + CRYPTO_MUTEX_unlock_write(&x->lock); return; } @@ -564,7 +559,7 @@ static void x509v3_cache_extensions(X509 *x) } x->ex_flags |= EXFLAG_SET; - CRYPTO_STATIC_MUTEX_unlock(&g_x509_cache_extensions_lock); + CRYPTO_MUTEX_unlock_write(&x->lock); } /* @@ -604,10 +599,7 @@ static int check_ca(const X509 *x) int X509_check_ca(X509 *x) { - if (!(x->ex_flags & EXFLAG_SET)) { - x509v3_cache_extensions(x); - } - + x509v3_cache_extensions(x); return check_ca(x); } @@ -647,7 +639,7 @@ static int check_purpose_ssl_client(const X509_PURPOSE *xp, const X509 *x, * key types. */ #define KU_TLS \ - KU_DIGITAL_SIGNATURE|KU_KEY_ENCIPHERMENT|KU_KEY_AGREEMENT + (KU_DIGITAL_SIGNATURE|KU_KEY_ENCIPHERMENT|KU_KEY_AGREEMENT) static int check_purpose_ssl_server(const X509_PURPOSE *xp, const X509 *x, int ca) diff --git a/Sources/BoringSSL/crypto/x509v3/v3_utl.c b/Sources/BoringSSL/crypto/x509v3/v3_utl.c index 6b6a6f883..fe7787bbe 100644 --- a/Sources/BoringSSL/crypto/x509v3/v3_utl.c +++ b/Sources/BoringSSL/crypto/x509v3/v3_utl.c @@ -71,6 +71,8 @@ #include #include "../conf/internal.h" +#include "../internal.h" + static char *strip_spaces(char *name); static int sk_strcmp(const OPENSSL_STRING *a, const OPENSSL_STRING *b); @@ -690,7 +692,7 @@ static int equal_nocase(const unsigned char *pattern, size_t pattern_len, return 1; } -/* Compare using memcmp. */ +/* Compare using OPENSSL_memcmp. */ static int equal_case(const unsigned char *pattern, size_t pattern_len, const unsigned char *subject, size_t subject_len, unsigned int flags) @@ -698,7 +700,7 @@ static int equal_case(const unsigned char *pattern, size_t pattern_len, skip_prefix(&pattern, &pattern_len, subject, subject_len, flags); if (pattern_len != subject_len) return 0; - return !memcmp(pattern, subject, pattern_len); + return !OPENSSL_memcmp(pattern, subject, pattern_len); } /* @@ -822,37 +824,22 @@ static const unsigned char *valid_star(const unsigned char *p, size_t len, return NULL; star = &p[i]; state &= ~LABEL_START; - } else if ((state & LABEL_START) != 0) { - /* - * At the start of a label, skip any "xn--" and - * remain in the LABEL_START state, but set the - * IDNA label state - */ - if ((state & LABEL_IDNA) == 0 && len - i >= 4 - && OPENSSL_strncasecmp((char *)&p[i], "xn--", 4) == 0) { - i += 3; - state |= LABEL_IDNA; - continue; - } - /* Labels must start with a letter or digit */ - state &= ~LABEL_START; - if (('a' <= p[i] && p[i] <= 'z') - || ('A' <= p[i] && p[i] <= 'Z') - || ('0' <= p[i] && p[i] <= '9')) - continue; - return NULL; } else if (('a' <= p[i] && p[i] <= 'z') || ('A' <= p[i] && p[i] <= 'Z') || ('0' <= p[i] && p[i] <= '9')) { - state &= LABEL_IDNA; - continue; + if ((state & LABEL_START) != 0 + && len - i >= 4 + && OPENSSL_strncasecmp((char *)&p[i], "xn--", 4) == 0) + state |= LABEL_IDNA; + state &= ~(LABEL_HYPHEN | LABEL_START); } else if (p[i] == '.') { - if (state & (LABEL_HYPHEN | LABEL_START)) + if ((state & (LABEL_HYPHEN | LABEL_START)) != 0) return NULL; state = LABEL_START; ++dots; } else if (p[i] == '-') { - if (state & LABEL_HYPHEN) + /* no domain/subdomain starts with '-' */ + if ((state & LABEL_START) != 0) return NULL; state |= LABEL_HYPHEN; } else @@ -908,7 +895,7 @@ static int do_check_string(ASN1_STRING *a, int cmp_type, equal_fn equal, return 0; if (cmp_type == V_ASN1_IA5STRING) rv = equal(a->data, a->length, (unsigned char *)b, blen, flags); - else if (a->length == (int)blen && !memcmp(a->data, b, blen)) + else if (a->length == (int)blen && !OPENSSL_memcmp(a->data, b, blen)) rv = 1; if (rv > 0 && peername) *peername = BUF_strndup((char *)a->data, a->length); @@ -1013,7 +1000,7 @@ int X509_check_host(X509 *x, const char *chk, size_t chklen, { if (chk == NULL) return -2; - if (memchr(chk, '\0', chklen)) + if (OPENSSL_memchr(chk, '\0', chklen)) return -2; return do_x509_check(x, chk, chklen, flags, GEN_DNS, peername); } @@ -1023,7 +1010,7 @@ int X509_check_email(X509 *x, const char *chk, size_t chklen, { if (chk == NULL) return -2; - if (memchr(chk, '\0', chklen)) + if (OPENSSL_memchr(chk, '\0', chklen)) return -2; return do_x509_check(x, chk, chklen, flags, GEN_EMAIL, NULL); } @@ -1212,16 +1199,16 @@ static int ipv6_from_asc(unsigned char *v6, const char *in) if (v6stat.zero_pos >= 0) { /* Copy initial part */ - memcpy(v6, v6stat.tmp, v6stat.zero_pos); + OPENSSL_memcpy(v6, v6stat.tmp, v6stat.zero_pos); /* Zero middle */ - memset(v6 + v6stat.zero_pos, 0, 16 - v6stat.total); + OPENSSL_memset(v6 + v6stat.zero_pos, 0, 16 - v6stat.total); /* Copy final part */ if (v6stat.total != v6stat.zero_pos) - memcpy(v6 + v6stat.zero_pos + 16 - v6stat.total, - v6stat.tmp + v6stat.zero_pos, - v6stat.total - v6stat.zero_pos); + OPENSSL_memcpy(v6 + v6stat.zero_pos + 16 - v6stat.total, + v6stat.tmp + v6stat.zero_pos, + v6stat.total - v6stat.zero_pos); } else - memcpy(v6, v6stat.tmp, 16); + OPENSSL_memcpy(v6, v6stat.tmp, 16); return 1; } diff --git a/Sources/BoringSSL/err_data.c b/Sources/BoringSSL/err_data.c index d4cc08bd9..88462d137 100644 --- a/Sources/BoringSSL/err_data.c +++ b/Sources/BoringSSL/err_data.c @@ -54,182 +54,166 @@ OPENSSL_COMPILE_ASSERT(ERR_LIB_USER == 32, library_values_changed_32); OPENSSL_COMPILE_ASSERT(ERR_NUM_LIBS == 33, library_values_changed_num); const uint32_t kOpenSSLReasonValues[] = { - 0xc3207ab, - 0xc3287c5, - 0xc3307d4, - 0xc3387e4, - 0xc3407f3, - 0xc34880c, - 0xc350818, - 0xc358835, - 0xc360847, - 0xc368855, - 0xc370865, - 0xc378872, - 0xc380882, - 0xc38888d, - 0xc3908a3, - 0xc3988b2, - 0xc3a08c6, - 0xc3a87b8, - 0xc3b00b0, - 0x10321484, - 0x10329490, - 0x103314a9, - 0x103394bc, - 0x10340ded, - 0x103494cf, - 0x103514e4, - 0x10359516, - 0x1036152f, - 0x10369544, - 0x10371562, - 0x10379571, - 0x1038158d, - 0x103895a8, - 0x103915b7, - 0x103995d3, - 0x103a15ee, - 0x103a9605, - 0x103b1616, - 0x103b962a, - 0x103c1649, - 0x103c9658, - 0x103d166f, - 0x103d9682, - 0x103e0b5d, - 0x103e96b3, - 0x103f16c6, - 0x103f96e0, - 0x104016f0, - 0x10409704, - 0x1041171a, - 0x10419732, - 0x10421747, - 0x1042975b, - 0x1043176d, - 0x104385c1, - 0x104408b2, - 0x10449782, - 0x10451799, - 0x104597ae, - 0x104617bc, - 0x10469695, - 0x104714f7, - 0x104787b8, - 0x104800b0, - 0x10488b8c, - 0x14320b40, - 0x14328b4e, - 0x14330b5d, - 0x14338b6f, + 0xc320838, + 0xc328852, + 0xc330861, + 0xc338871, + 0xc340880, + 0xc348899, + 0xc3508a5, + 0xc3588c2, + 0xc3608d4, + 0xc3688e2, + 0xc3708f2, + 0xc3788ff, + 0xc38090f, + 0xc38891a, + 0xc390930, + 0xc39893f, + 0xc3a0953, + 0xc3a8845, + 0xc3b00ea, + 0x10320845, + 0x103293ab, + 0x103313b7, + 0x103393d0, + 0x103413e3, + 0x10348e8b, + 0x10350c19, + 0x103593f6, + 0x1036140b, + 0x1036941e, + 0x1037143d, + 0x10379456, + 0x1038146b, + 0x10389489, + 0x10391498, + 0x103994b4, + 0x103a14cf, + 0x103a94de, + 0x103b14fa, + 0x103b9515, + 0x103c152c, + 0x103c80ea, + 0x103d153d, + 0x103d9551, + 0x103e1570, + 0x103e957f, + 0x103f1596, + 0x103f95a9, + 0x10400bea, + 0x104095bc, + 0x104115da, + 0x104195ed, + 0x10421607, + 0x10429617, + 0x1043162b, + 0x10439641, + 0x10441659, + 0x1044966e, + 0x10451682, + 0x10459694, + 0x104605fb, + 0x1046893f, + 0x104716a9, + 0x104796c0, + 0x104816d5, + 0x104896e3, + 0x14320bcd, + 0x14328bdb, + 0x14330bea, + 0x14338bfc, + 0x143400ac, + 0x143480ea, 0x18320083, - 0x18328e53, - 0x18340e81, - 0x18348e95, - 0x18358ecc, - 0x18368ef9, - 0x18370f0c, - 0x18378f20, - 0x18380f44, - 0x18388f52, - 0x18390f68, - 0x18398f7c, - 0x183a0f8c, - 0x183b0f9c, - 0x183b8fb1, - 0x183c8fdc, - 0x183d0ff0, - 0x183d9000, - 0x183e0b98, - 0x183e900d, - 0x183f101f, - 0x183f902a, - 0x1840103a, - 0x1840904b, - 0x1841105c, - 0x1841906e, - 0x18421097, - 0x184290c9, - 0x184310d8, - 0x18451141, - 0x18459157, - 0x18461172, - 0x18468ee4, - 0x184709ca, - 0x18478094, - 0x18480fc8, - 0x1848910d, - 0x18490e69, - 0x18498eaa, - 0x184a11a8, - 0x184a9125, - 0x184b10ec, - 0x184b8e43, - 0x184c10b0, - 0x184c865c, - 0x184d118d, - 0x184d80b0, - 0x203211cf, - 0x243211db, - 0x243288f8, - 0x243311ed, - 0x243391fa, - 0x24341207, - 0x24349219, - 0x24351228, - 0x24359245, - 0x24361252, - 0x24369260, - 0x2437126e, - 0x2437927c, - 0x24381285, - 0x24389292, - 0x243912a5, - 0x28320b80, - 0x28328b98, - 0x28330b5d, - 0x28338bab, - 0x28340b8c, - 0x28348094, - 0x283500b0, - 0x2c32281d, - 0x2c32a82b, - 0x2c33283d, - 0x2c33a84f, - 0x2c342863, - 0x2c34a875, - 0x2c352890, - 0x2c35a8a2, - 0x2c3628b5, - 0x2c3682f3, - 0x2c3728c2, - 0x2c37a8d4, - 0x2c3828e7, - 0x2c38a8f5, - 0x2c392905, - 0x2c39a917, - 0x2c3a292b, - 0x2c3aa93c, - 0x2c3b1365, - 0x2c3ba94d, - 0x2c3c2961, - 0x2c3ca977, - 0x2c3d2990, - 0x2c3da9be, - 0x2c3e29cc, - 0x2c3ea9e4, - 0x2c3f29fc, - 0x2c3faa09, - 0x2c402a2c, - 0x2c40aa4b, - 0x2c4111cf, - 0x2c41aa5c, - 0x2c422a6f, - 0x2c429141, - 0x2c432a80, - 0x2c438693, - 0x2c4429ad, + 0x18328ee1, + 0x183300ac, + 0x18338ef7, + 0x18340f0b, + 0x183480ea, + 0x18350f20, + 0x18358f38, + 0x18360f4d, + 0x18368f61, + 0x18370f85, + 0x18378f9b, + 0x18380faf, + 0x18388fbf, + 0x18390a57, + 0x18398fcf, + 0x183a0fe4, + 0x183a8ff8, + 0x183b0c25, + 0x183b9005, + 0x183c1017, + 0x183c9022, + 0x183d1032, + 0x183d9043, + 0x183e1054, + 0x183e9066, + 0x183f108f, + 0x183f90a8, + 0x184010c0, + 0x184086d3, + 0x203210e7, + 0x243210f3, + 0x24328985, + 0x24331105, + 0x24339112, + 0x2434111f, + 0x24349131, + 0x24351140, + 0x2435915d, + 0x2436116a, + 0x24369178, + 0x24371186, + 0x24379194, + 0x2438119d, + 0x243891aa, + 0x243911bd, + 0x28320c0d, + 0x28328c25, + 0x28330bea, + 0x28338c38, + 0x28340c19, + 0x283480ac, + 0x283500ea, + 0x2c3229b1, + 0x2c32a9bf, + 0x2c3329d1, + 0x2c33a9e3, + 0x2c3429f7, + 0x2c34aa09, + 0x2c352a24, + 0x2c35aa36, + 0x2c362a49, + 0x2c36832d, + 0x2c372a56, + 0x2c37aa68, + 0x2c382a7b, + 0x2c38aa92, + 0x2c392aa0, + 0x2c39aab0, + 0x2c3a2ac2, + 0x2c3aaad6, + 0x2c3b2ae7, + 0x2c3bab06, + 0x2c3c2b1a, + 0x2c3cab30, + 0x2c3d2b49, + 0x2c3dab66, + 0x2c3e2b77, + 0x2c3eab85, + 0x2c3f2b9d, + 0x2c3fabb5, + 0x2c402bc2, + 0x2c4090e7, + 0x2c412bd3, + 0x2c41abe6, + 0x2c4210c0, + 0x2c42abf7, + 0x2c430720, + 0x2c43aaf8, 0x30320000, 0x30328015, 0x3033001f, @@ -239,443 +223,474 @@ const uint32_t kOpenSSLReasonValues[] = { 0x3035006b, 0x30358083, 0x30360094, - 0x303680a1, - 0x303700b0, - 0x303780bd, - 0x303800d0, - 0x303880eb, - 0x30390100, - 0x30398114, - 0x303a0128, - 0x303a8139, - 0x303b0152, - 0x303b816f, - 0x303c017d, - 0x303c8191, - 0x303d01a1, - 0x303d81ba, - 0x303e01ca, - 0x303e81dd, - 0x303f01ec, - 0x303f81f8, - 0x3040020d, - 0x3040821d, - 0x30410234, - 0x30418241, - 0x30420254, - 0x30428263, - 0x30430278, - 0x30438299, - 0x304402ac, - 0x304482bf, - 0x304502d8, - 0x304582f3, - 0x30460310, - 0x30468329, - 0x30470337, - 0x30478348, - 0x30480357, - 0x3048836f, - 0x30490381, - 0x30498395, - 0x304a03b4, - 0x304a83c7, - 0x304b03d2, - 0x304b83e3, - 0x304c03ef, - 0x304c8405, - 0x304d0413, - 0x304d8429, - 0x304e043b, - 0x304e844d, - 0x304f0460, - 0x304f8473, - 0x30500484, - 0x30508494, - 0x305104ac, - 0x305184c1, - 0x305204d9, - 0x305284ed, - 0x30530505, - 0x3053851e, - 0x30540537, - 0x30548554, - 0x3055055f, - 0x30558577, - 0x30560587, - 0x30568598, - 0x305705ab, - 0x305785c1, - 0x305805ca, - 0x305885df, - 0x305905f2, - 0x30598601, - 0x305a0621, - 0x305a8630, - 0x305b063c, - 0x305b865c, - 0x305c0678, - 0x305c8689, - 0x305d0693, - 0x34320aba, - 0x34328ace, - 0x34330aeb, - 0x34338afe, - 0x34340b0d, - 0x34348b2a, + 0x303680ac, + 0x303700b9, + 0x303780c8, + 0x303800ea, + 0x303880f7, + 0x3039010a, + 0x30398125, + 0x303a013a, + 0x303a814e, + 0x303b0162, + 0x303b8173, + 0x303c018c, + 0x303c81a9, + 0x303d01b7, + 0x303d81cb, + 0x303e01db, + 0x303e81f4, + 0x303f0204, + 0x303f8217, + 0x30400226, + 0x30408232, + 0x30410247, + 0x30418257, + 0x3042026e, + 0x3042827b, + 0x3043028e, + 0x3043829d, + 0x304402b2, + 0x304482d3, + 0x304502e6, + 0x304582f9, + 0x30460312, + 0x3046832d, + 0x3047034a, + 0x30478363, + 0x30480371, + 0x30488382, + 0x30490391, + 0x304983a9, + 0x304a03bb, + 0x304a83cf, + 0x304b03ee, + 0x304b8401, + 0x304c040c, + 0x304c841d, + 0x304d0429, + 0x304d843f, + 0x304e044d, + 0x304e8463, + 0x304f0475, + 0x304f8487, + 0x3050049a, + 0x305084ad, + 0x305104be, + 0x305184ce, + 0x305204e6, + 0x305284fb, + 0x30530513, + 0x30538527, + 0x3054053f, + 0x30548558, + 0x30550571, + 0x3055858e, + 0x30560599, + 0x305685b1, + 0x305705c1, + 0x305785d2, + 0x305805e5, + 0x305885fb, + 0x30590604, + 0x30598619, + 0x305a062c, + 0x305a863b, + 0x305b065b, + 0x305b866a, + 0x305c068b, + 0x305c86a7, + 0x305d06b3, + 0x305d86d3, + 0x305e06ef, + 0x305e8700, + 0x305f0716, + 0x305f8720, + 0x34320b47, + 0x34328b5b, + 0x34330b78, + 0x34338b8b, + 0x34340b9a, + 0x34348bb7, 0x3c320083, - 0x3c328bd5, - 0x3c330bee, - 0x3c338c09, - 0x3c340c26, - 0x3c348c50, - 0x3c350c6b, - 0x3c358c80, - 0x3c360c99, - 0x3c368cb1, - 0x3c370cc2, - 0x3c378cd0, - 0x3c380cdd, - 0x3c388cf1, - 0x3c390b98, - 0x3c398d05, - 0x3c3a0d19, - 0x3c3a8872, - 0x3c3b0d29, - 0x3c3b8d44, - 0x3c3c0d56, - 0x3c3c8d6c, - 0x3c3d0d76, - 0x3c3d8d8a, - 0x3c3e0d98, - 0x3c3e8dbd, - 0x3c3f0bc1, - 0x3c3f8da6, - 0x3c400094, - 0x3c4080b0, - 0x3c410c41, - 0x403217d3, - 0x403297e9, - 0x40331817, - 0x40339821, - 0x40341838, - 0x40349856, - 0x40351866, - 0x40359878, - 0x40361885, - 0x40369891, - 0x403718a6, - 0x403798b8, - 0x403818c3, - 0x403898d5, - 0x40390ded, - 0x403998e5, - 0x403a18f8, - 0x403a9919, - 0x403b192a, - 0x403b993a, + 0x3c328c62, + 0x3c330c7b, + 0x3c338c96, + 0x3c340cb3, + 0x3c348cdd, + 0x3c350cf8, + 0x3c358d1e, + 0x3c360d37, + 0x3c368d4f, + 0x3c370d60, + 0x3c378d6e, + 0x3c380d7b, + 0x3c388d8f, + 0x3c390c25, + 0x3c398da3, + 0x3c3a0db7, + 0x3c3a88ff, + 0x3c3b0dc7, + 0x3c3b8de2, + 0x3c3c0df4, + 0x3c3c8e0a, + 0x3c3d0e14, + 0x3c3d8e28, + 0x3c3e0e36, + 0x3c3e8e5b, + 0x3c3f0c4e, + 0x3c3f8e44, + 0x3c4000ac, + 0x3c4080ea, + 0x3c410cce, + 0x3c418d0d, + 0x403216fa, + 0x40329710, + 0x4033173e, + 0x40339748, + 0x4034175f, + 0x4034977d, + 0x4035178d, + 0x4035979f, + 0x403617ac, + 0x403697b8, + 0x403717cd, + 0x403797df, + 0x403817ea, + 0x403897fc, + 0x40390e8b, + 0x4039980c, + 0x403a181f, + 0x403a9840, + 0x403b1851, + 0x403b9861, 0x403c0064, 0x403c8083, - 0x403d1946, - 0x403d995c, - 0x403e196b, - 0x403e997e, - 0x403f1998, - 0x403f99a6, - 0x404019bb, - 0x404099cf, - 0x404119ec, - 0x40419a07, - 0x40421a20, - 0x40429a33, - 0x40431a47, - 0x40439a5f, - 0x40441a76, - 0x40448094, - 0x40451a8b, - 0x40459a9d, - 0x40461ac1, - 0x40469ae1, - 0x40471aef, - 0x40479b03, - 0x40481b18, - 0x40489b31, - 0x40491b48, - 0x40499b62, - 0x404a1b79, - 0x404a9b97, - 0x404b1baf, - 0x404b9bc6, - 0x404c1bdc, - 0x404c9bee, - 0x404d1c0f, - 0x404d9c31, - 0x404e1c45, - 0x404e9c52, - 0x404f1c69, - 0x404f9c79, - 0x40501c89, - 0x40509c9d, - 0x40511cb8, - 0x40519cc8, - 0x40521cdf, - 0x40529cf1, - 0x40531d09, - 0x40539d1c, - 0x40541d31, - 0x40549d54, - 0x40551d62, - 0x40559d7f, - 0x40561d8c, - 0x40569da5, - 0x40571dbd, - 0x40579dd0, - 0x40581de5, - 0x40589df7, - 0x40591e07, - 0x40599e20, - 0x405a1e34, - 0x405a9e44, - 0x405b1e5c, - 0x405b9e6d, - 0x405c1e80, - 0x405c9e91, - 0x405d1e9e, - 0x405d9eb5, - 0x405e1ed5, - 0x405e8a08, - 0x405f1ef6, - 0x405f9f03, - 0x40601f11, - 0x40609f33, - 0x40611f5b, - 0x40619f70, - 0x40621f87, - 0x40629f98, - 0x40631fa9, - 0x40639fbe, - 0x40641fd5, - 0x40649fe6, - 0x40652001, - 0x4065a018, - 0x40662030, - 0x4066a05a, - 0x40672085, - 0x4067a0a6, - 0x406820b9, - 0x4068a0da, - 0x406920f5, - 0x4069a123, - 0x406a2144, - 0x406aa164, - 0x406b22ec, - 0x406ba30f, - 0x406c2325, - 0x406ca551, - 0x406d2580, - 0x406da5a8, - 0x406e25c1, - 0x406ea5d9, - 0x406f25f8, - 0x406fa60d, - 0x40702620, - 0x4070a63d, - 0x40710773, - 0x4071a64f, - 0x40722662, - 0x4072a67b, - 0x40732693, - 0x407390c9, - 0x407426a7, - 0x4074a6c1, - 0x407526d2, - 0x4075a6e6, - 0x407626f4, - 0x40769292, - 0x40772719, - 0x4077a73b, - 0x40782756, - 0x4078a76b, - 0x40792782, - 0x4079a798, - 0x407a27a4, - 0x407aa7b7, - 0x407b27cc, - 0x407ba7de, - 0x407c27f3, - 0x407ca7fc, - 0x41f42217, - 0x41f922a9, - 0x41fe219c, - 0x41fea378, - 0x41ff2469, - 0x42032230, - 0x42082252, - 0x4208a28e, - 0x42092180, - 0x4209a2c8, - 0x420a21d7, - 0x420aa1b7, - 0x420b21f7, - 0x420ba270, - 0x420c2485, - 0x420ca345, - 0x420d235f, - 0x420da396, - 0x421223b0, - 0x4217244c, - 0x4217a3f2, - 0x421c2414, - 0x421f23cf, - 0x4221249c, - 0x4226242f, - 0x422b2535, - 0x422ba4fe, - 0x422c251d, - 0x422ca4d8, - 0x422d24b7, - 0x4432069e, - 0x443286ad, - 0x443306b9, - 0x443386c7, - 0x443406da, - 0x443486eb, - 0x443506f2, - 0x443586fc, - 0x4436070f, - 0x44368725, - 0x44370737, - 0x44378744, - 0x44380753, - 0x4438875b, - 0x44390773, - 0x44398781, - 0x443a0794, - 0x4c3212bc, - 0x4c3292cc, - 0x4c3312df, - 0x4c3392ff, - 0x4c340094, - 0x4c3480b0, - 0x4c35130b, - 0x4c359319, - 0x4c361335, - 0x4c369348, - 0x4c371357, - 0x4c379365, - 0x4c38137a, - 0x4c389386, - 0x4c3913a6, - 0x4c3993d0, - 0x4c3a13e9, - 0x4c3a9402, - 0x4c3b05c1, - 0x4c3b941b, - 0x4c3c142d, - 0x4c3c943c, - 0x4c3d10c9, - 0x4c3d9455, - 0x4c3e1462, - 0x50322a92, - 0x5032aaa1, - 0x50332aac, - 0x5033aabc, - 0x50342ad5, - 0x5034aaef, - 0x50352afd, - 0x5035ab13, - 0x50362b25, - 0x5036ab3b, - 0x50372b54, - 0x5037ab67, - 0x50382b7f, - 0x5038ab90, - 0x50392ba5, - 0x5039abb9, - 0x503a2bd9, - 0x503aabef, - 0x503b2c07, - 0x503bac19, - 0x503c2c35, - 0x503cac4c, - 0x503d2c65, - 0x503dac7b, - 0x503e2c88, - 0x503eac9e, - 0x503f2cb0, - 0x503f8348, - 0x50402cc3, - 0x5040acd3, - 0x50412ced, - 0x5041acfc, - 0x50422d16, - 0x5042ad33, - 0x50432d43, - 0x5043ad53, - 0x50442d62, - 0x50448405, - 0x50452d76, - 0x5045ad94, - 0x50462da7, - 0x5046adbd, - 0x50472dcf, - 0x5047ade4, - 0x50482e0a, - 0x5048ae18, - 0x50492e2b, - 0x5049ae40, - 0x504a2e56, - 0x504aae66, - 0x504b2e86, - 0x504bae99, - 0x504c2ebc, - 0x504caeea, - 0x504d2efc, - 0x504daf19, - 0x504e2f34, - 0x504eaf50, - 0x504f2f62, - 0x504faf79, - 0x50502f88, - 0x50508678, - 0x50512f9b, - 0x58320e2b, - 0x68320ded, - 0x68328b98, - 0x68330bab, - 0x68338dfb, - 0x68340e0b, - 0x683480b0, - 0x6c320dc9, - 0x6c328b6f, - 0x6c330dd4, - 0x7432097e, - 0x783208e3, - 0x783288f8, - 0x78330904, + 0x403d18c1, + 0x403d98d7, + 0x403e18e6, + 0x403e98f9, + 0x403f1913, + 0x403f9921, + 0x40401936, + 0x4040994a, + 0x40411967, + 0x40419982, + 0x4042199b, + 0x404299ae, + 0x404319c2, + 0x404399da, + 0x404419f1, + 0x404480ac, + 0x40451a06, + 0x40459a18, + 0x40461a3c, + 0x40469a5c, + 0x40471a6a, + 0x40479a91, + 0x40481ace, + 0x40489ae7, + 0x40491afe, + 0x40499b18, + 0x404a1b2f, + 0x404a9b4d, + 0x404b1b65, + 0x404b9b7c, + 0x404c1b92, + 0x404c9ba4, + 0x404d1bc5, + 0x404d9be7, + 0x404e1bfb, + 0x404e9c08, + 0x404f1c35, + 0x404f9c5e, + 0x40501c99, + 0x40509cad, + 0x40511cc8, + 0x40519cd8, + 0x40521cef, + 0x40529d13, + 0x40531d2b, + 0x40539d3e, + 0x40541d53, + 0x40549d76, + 0x40551d84, + 0x40559da1, + 0x40561dae, + 0x40569dc7, + 0x40571ddf, + 0x40579df2, + 0x40581e07, + 0x40589e2e, + 0x40591e5d, + 0x40599e8a, + 0x405a1e9e, + 0x405a9eae, + 0x405b1ec6, + 0x405b9ed7, + 0x405c1eea, + 0x405c9f0b, + 0x405d1f18, + 0x405d9f2f, + 0x405e1f6d, + 0x405e8a95, + 0x405f1f8e, + 0x405f9f9b, + 0x40601fa9, + 0x40609fcb, + 0x4061200f, + 0x4061a047, + 0x4062205e, + 0x4062a06f, + 0x40632080, + 0x4063a095, + 0x406420ac, + 0x4064a0d8, + 0x406520f3, + 0x4065a10a, + 0x40662122, + 0x4066a14c, + 0x40672177, + 0x4067a198, + 0x406821ab, + 0x4068a1cc, + 0x406921fe, + 0x4069a22c, + 0x406a224d, + 0x406aa26d, + 0x406b23f5, + 0x406ba418, + 0x406c242e, + 0x406ca690, + 0x406d26bf, + 0x406da6e7, + 0x406e2715, + 0x406ea749, + 0x406f2768, + 0x406fa77d, + 0x40702790, + 0x4070a7ad, + 0x40710800, + 0x4071a7bf, + 0x407227d2, + 0x4072a7eb, + 0x40732803, + 0x4073936d, + 0x40742817, + 0x4074a831, + 0x40752842, + 0x4075a856, + 0x40762864, + 0x407691aa, + 0x40772889, + 0x4077a8ab, + 0x407828c6, + 0x4078a8ff, + 0x40792916, + 0x4079a92c, + 0x407a2938, + 0x407aa94b, + 0x407b2960, + 0x407ba972, + 0x407c2987, + 0x407ca990, + 0x407d21e7, + 0x407d9c6e, + 0x407e28db, + 0x407e9e3e, + 0x407f1a7e, + 0x407f9887, + 0x40801c45, + 0x40809aa6, + 0x40811d01, + 0x40819c1f, + 0x40822700, + 0x4082986d, + 0x40831e19, + 0x4083a0bd, + 0x40841aba, + 0x40849e76, + 0x40851efb, + 0x40859ff3, + 0x40861f4f, + 0x40869c88, + 0x4087272d, + 0x4087a024, + 0x408818aa, + 0x41f42320, + 0x41f923b2, + 0x41fe22a5, + 0x41fea481, + 0x41ff2572, + 0x42032339, + 0x4208235b, + 0x4208a397, + 0x42092289, + 0x4209a3d1, + 0x420a22e0, + 0x420aa2c0, + 0x420b2300, + 0x420ba379, + 0x420c258e, + 0x420ca44e, + 0x420d2468, + 0x420da49f, + 0x421224b9, + 0x42172555, + 0x4217a4fb, + 0x421c251d, + 0x421f24d8, + 0x422125a5, + 0x42262538, + 0x422b2674, + 0x422ba622, + 0x422c265c, + 0x422ca5e1, + 0x422d25c0, + 0x422da641, + 0x422e2607, + 0x4432072b, + 0x4432873a, + 0x44330746, + 0x44338754, + 0x44340767, + 0x44348778, + 0x4435077f, + 0x44358789, + 0x4436079c, + 0x443687b2, + 0x443707c4, + 0x443787d1, + 0x443807e0, + 0x443887e8, + 0x44390800, + 0x4439880e, + 0x443a0821, + 0x4c3211d4, + 0x4c3291e4, + 0x4c3311f7, + 0x4c339217, + 0x4c3400ac, + 0x4c3480ea, + 0x4c351223, + 0x4c359231, + 0x4c36124d, + 0x4c369260, + 0x4c37126f, + 0x4c37927d, + 0x4c381292, + 0x4c38929e, + 0x4c3912be, + 0x4c3992e8, + 0x4c3a1301, + 0x4c3a931a, + 0x4c3b05fb, + 0x4c3b9333, + 0x4c3c1345, + 0x4c3c9354, + 0x4c3d136d, + 0x4c3d937c, + 0x4c3e1389, + 0x50322c09, + 0x5032ac18, + 0x50332c23, + 0x5033ac33, + 0x50342c4c, + 0x5034ac66, + 0x50352c74, + 0x5035ac8a, + 0x50362c9c, + 0x5036acb2, + 0x50372ccb, + 0x5037acde, + 0x50382cf6, + 0x5038ad07, + 0x50392d1c, + 0x5039ad30, + 0x503a2d50, + 0x503aad66, + 0x503b2d7e, + 0x503bad90, + 0x503c2dac, + 0x503cadc3, + 0x503d2ddc, + 0x503dadf2, + 0x503e2dff, + 0x503eae15, + 0x503f2e27, + 0x503f8382, + 0x50402e3a, + 0x5040ae4a, + 0x50412e64, + 0x5041ae73, + 0x50422e8d, + 0x5042aeaa, + 0x50432eba, + 0x5043aeca, + 0x50442ed9, + 0x5044843f, + 0x50452eed, + 0x5045af0b, + 0x50462f1e, + 0x5046af34, + 0x50472f46, + 0x5047af5b, + 0x50482f81, + 0x5048af8f, + 0x50492fa2, + 0x5049afb7, + 0x504a2fcd, + 0x504aafdd, + 0x504b2ffd, + 0x504bb010, + 0x504c3033, + 0x504cb061, + 0x504d3073, + 0x504db090, + 0x504e30ab, + 0x504eb0c7, + 0x504f30d9, + 0x504fb0f0, + 0x505030ff, + 0x505086ef, + 0x50513112, + 0x58320ec9, + 0x68320e8b, + 0x68328c25, + 0x68330c38, + 0x68338e99, + 0x68340ea9, + 0x683480ea, + 0x6c320e67, + 0x6c328bfc, + 0x6c330e72, + 0x74320a0b, + 0x78320970, + 0x78328985, + 0x78330991, 0x78338083, - 0x78340913, - 0x78348928, - 0x78350947, - 0x78358969, - 0x7836097e, - 0x78368994, - 0x783709a4, - 0x783789b7, - 0x783809ca, - 0x783889dc, - 0x783909e9, - 0x78398a08, - 0x783a0a1d, - 0x783a8a2b, - 0x783b0a35, - 0x783b8a49, - 0x783c0a60, - 0x783c8a75, - 0x783d0a8c, - 0x783d8aa1, - 0x783e09f7, - 0x7c3211be, + 0x783409a0, + 0x783489b5, + 0x783509d4, + 0x783589f6, + 0x78360a0b, + 0x78368a21, + 0x78370a31, + 0x78378a44, + 0x78380a57, + 0x78388a69, + 0x78390a76, + 0x78398a95, + 0x783a0aaa, + 0x783a8ab8, + 0x783b0ac2, + 0x783b8ad6, + 0x783c0aed, + 0x783c8b02, + 0x783d0b19, + 0x783d8b2e, + 0x783e0a84, + 0x7c3210d6, }; const size_t kOpenSSLReasonValuesLen = sizeof(kOpenSSLReasonValues) / sizeof(kOpenSSLReasonValues[0]); @@ -689,8 +704,10 @@ const char kOpenSSLReasonStringData[] = "BN_LIB\0" "BOOLEAN_IS_WRONG_LENGTH\0" "BUFFER_TOO_SMALL\0" + "CONTEXT_NOT_INITIALISED\0" "DECODE_ERROR\0" "DEPTH_EXCEEDED\0" + "DIGEST_AND_KEY_TYPE_NOT_SUPPORTED\0" "ENCODE_ERROR\0" "ERROR_GETTING_TIME\0" "EXPECTING_AN_ASN1_SEQUENCE\0" @@ -762,10 +779,13 @@ const char kOpenSSLReasonStringData[] = "UNEXPECTED_EOC\0" "UNIVERSALSTRING_IS_WRONG_LENGTH\0" "UNKNOWN_FORMAT\0" + "UNKNOWN_MESSAGE_DIGEST_ALGORITHM\0" + "UNKNOWN_SIGNATURE_ALGORITHM\0" "UNKNOWN_TAG\0" "UNSUPPORTED_ANY_DEFINED_BY_TYPE\0" "UNSUPPORTED_PUBLIC_KEY_TYPE\0" "UNSUPPORTED_TYPE\0" + "WRONG_PUBLIC_KEY_TYPE\0" "WRONG_TAG\0" "WRONG_TYPE\0" "BAD_FOPEN_MODE\0" @@ -849,6 +869,7 @@ const char kOpenSSLReasonStringData[] = "GROUP_MISMATCH\0" "I2D_ECPKPARAMETERS_FAILURE\0" "INCOMPATIBLE_OBJECTS\0" + "INVALID_COFACTOR\0" "INVALID_COMPRESSED_POINT\0" "INVALID_COMPRESSION_BIT\0" "INVALID_ENCODING\0" @@ -873,27 +894,19 @@ const char kOpenSSLReasonStringData[] = "NOT_IMPLEMENTED\0" "RANDOM_NUMBER_GENERATION_FAILED\0" "OPERATION_NOT_SUPPORTED\0" - "BN_DECODE_ERROR\0" "COMMAND_NOT_SUPPORTED\0" - "CONTEXT_NOT_INITIALISED\0" "DIFFERENT_KEY_TYPES\0" "DIFFERENT_PARAMETERS\0" - "DIGEST_AND_KEY_TYPE_NOT_SUPPORTED\0" "EXPECTING_AN_EC_KEY_KEY\0" "EXPECTING_AN_RSA_KEY\0" - "EXPECTING_A_DH_KEY\0" "EXPECTING_A_DSA_KEY\0" "ILLEGAL_OR_UNSUPPORTED_PADDING_MODE\0" - "INVALID_CURVE\0" "INVALID_DIGEST_LENGTH\0" "INVALID_DIGEST_TYPE\0" "INVALID_KEYBITS\0" "INVALID_MGF1_MD\0" "INVALID_PADDING_MODE\0" - "INVALID_PSS_PARAMETERS\0" "INVALID_PSS_SALTLEN\0" - "INVALID_SALT_LENGTH\0" - "INVALID_TRAILER\0" "KEYS_NOT_SET\0" "NO_DEFAULT_DIGEST\0" "NO_KEY_SET\0" @@ -903,17 +916,8 @@ const char kOpenSSLReasonStringData[] = "NO_PARAMETERS_SET\0" "OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE\0" "OPERATON_NOT_INITIALIZED\0" - "PARAMETER_ENCODING_ERROR\0" - "UNKNOWN_DIGEST\0" - "UNKNOWN_MASK_DIGEST\0" - "UNKNOWN_MESSAGE_DIGEST_ALGORITHM\0" "UNKNOWN_PUBLIC_KEY_TYPE\0" - "UNKNOWN_SIGNATURE_ALGORITHM\0" "UNSUPPORTED_ALGORITHM\0" - "UNSUPPORTED_MASK_ALGORITHM\0" - "UNSUPPORTED_MASK_PARAMETER\0" - "UNSUPPORTED_SIGNATURE_TYPE\0" - "WRONG_PUBLIC_KEY_TYPE\0" "OUTPUT_TOO_LARGE\0" "UNKNOWN_NID\0" "BAD_BASE64_DECODE\0" @@ -949,6 +953,7 @@ const char kOpenSSLReasonStringData[] = "UNKNOWN_ALGORITHM\0" "UNKNOWN_CIPHER\0" "UNKNOWN_CIPHER_ALGORITHM\0" + "UNKNOWN_DIGEST\0" "UNKNOWN_HASH\0" "UNSUPPORTED_PRIVATE_KEY_ALGORITHM\0" "BAD_E_VALUE\0" @@ -1009,6 +1014,9 @@ const char kOpenSSLReasonStringData[] = "BAD_SSL_FILETYPE\0" "BAD_WRITE_RETRY\0" "BIO_NOT_SET\0" + "BLOCK_CIPHER_PAD_IS_WRONG\0" + "BUFFERED_MESSAGES_ON_CIPHER_CHANGE\0" + "CANNOT_PARSE_LEAF_CERT\0" "CA_DN_LENGTH_MISMATCH\0" "CA_DN_TOO_LONG\0" "CCS_RECEIVED_EARLY\0" @@ -1029,7 +1037,10 @@ const char kOpenSSLReasonStringData[] = "DH_PUBLIC_VALUE_LENGTH_IS_WRONG\0" "DH_P_TOO_LONG\0" "DIGEST_CHECK_FAILED\0" + "DOWNGRADE_DETECTED\0" "DTLS_MESSAGE_TOO_BIG\0" + "DUPLICATE_EXTENSION\0" + "DUPLICATE_KEY_SHARE\0" "ECC_CERT_NOT_FOR_SIGNING\0" "EMS_STATE_INCONSISTENT\0" "ENCRYPTED_LENGTH_TOO_LONG\0" @@ -1044,13 +1055,18 @@ const char kOpenSSLReasonStringData[] = "HTTPS_PROXY_REQUEST\0" "HTTP_REQUEST\0" "INAPPROPRIATE_FALLBACK\0" + "INVALID_ALPN_PROTOCOL\0" "INVALID_COMMAND\0" + "INVALID_COMPRESSION_LIST\0" "INVALID_MESSAGE\0" + "INVALID_OUTER_RECORD_TYPE\0" + "INVALID_SCT_LIST\0" "INVALID_SSL_SESSION\0" "INVALID_TICKET_KEYS_LENGTH\0" "LENGTH_MISMATCH\0" "LIBRARY_HAS_NO_CIPHERS\0" "MISSING_EXTENSION\0" + "MISSING_KEY_SHARE\0" "MISSING_RSA_CERTIFICATE\0" "MISSING_TMP_DH_KEY\0" "MISSING_TMP_ECDH_KEY\0" @@ -1063,29 +1079,37 @@ const char kOpenSSLReasonStringData[] = "NO_CERTIFICATE_SET\0" "NO_CIPHERS_AVAILABLE\0" "NO_CIPHERS_PASSED\0" + "NO_CIPHERS_SPECIFIED\0" "NO_CIPHER_MATCH\0" + "NO_COMMON_SIGNATURE_ALGORITHMS\0" "NO_COMPRESSION_SPECIFIED\0" + "NO_GROUPS_SPECIFIED\0" "NO_METHOD_SPECIFIED\0" "NO_P256_SUPPORT\0" "NO_PRIVATE_KEY_ASSIGNED\0" "NO_RENEGOTIATION\0" "NO_REQUIRED_DIGEST\0" "NO_SHARED_CIPHER\0" + "NO_SHARED_GROUP\0" "NULL_SSL_CTX\0" "NULL_SSL_METHOD_PASSED\0" "OLD_SESSION_CIPHER_NOT_RETURNED\0" + "OLD_SESSION_PRF_HASH_MISMATCH\0" "OLD_SESSION_VERSION_NOT_RETURNED\0" "PARSE_TLSEXT\0" "PATH_TOO_LONG\0" "PEER_DID_NOT_RETURN_A_CERTIFICATE\0" "PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE\0" + "PRE_SHARED_KEY_MUST_BE_LAST\0" "PROTOCOL_IS_SHUTDOWN\0" + "PSK_IDENTITY_BINDER_COUNT_MISMATCH\0" "PSK_IDENTITY_NOT_FOUND\0" "PSK_NO_CLIENT_CB\0" "PSK_NO_SERVER_CB\0" "READ_TIMEOUT_EXPIRED\0" "RECORD_LENGTH_MISMATCH\0" "RECORD_TOO_LARGE\0" + "RENEGOTIATION_EMS_MISMATCH\0" "RENEGOTIATION_ENCODING_ERR\0" "RENEGOTIATION_MISMATCH\0" "REQUIRED_CIPHER_MISSING\0" @@ -1095,6 +1119,7 @@ const char kOpenSSLReasonStringData[] = "SERVERHELLO_TLSEXT\0" "SESSION_ID_CONTEXT_UNINITIALIZED\0" "SESSION_MAY_NOT_BE_CREATED\0" + "SHUTDOWN_WHILE_IN_INIT\0" "SIGNATURE_ALGORITHMS_EXTENSION_SENT_BY_SERVER\0" "SRTP_COULD_NOT_ALLOCATE_PROFILES\0" "SRTP_UNKNOWN_PROTECTION_PROFILE\0" @@ -1129,13 +1154,17 @@ const char kOpenSSLReasonStringData[] = "TLSV1_ALERT_USER_CANCELLED\0" "TLSV1_BAD_CERTIFICATE_HASH_VALUE\0" "TLSV1_BAD_CERTIFICATE_STATUS_RESPONSE\0" + "TLSV1_CERTIFICATE_REQUIRED\0" "TLSV1_CERTIFICATE_UNOBTAINABLE\0" + "TLSV1_UNKNOWN_PSK_IDENTITY\0" "TLSV1_UNRECOGNIZED_NAME\0" "TLSV1_UNSUPPORTED_EXTENSION\0" "TLS_PEER_DID_NOT_RESPOND_WITH_CERTIFICATE_LIST\0" "TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG\0" "TOO_MANY_EMPTY_FRAGMENTS\0" + "TOO_MANY_KEY_UPDATES\0" "TOO_MANY_WARNING_ALERTS\0" + "TOO_MUCH_SKIPPED_EARLY_DATA\0" "UNABLE_TO_FIND_ECDH_PARAMETERS\0" "UNEXPECTED_EXTENSION\0" "UNEXPECTED_MESSAGE\0" @@ -1153,6 +1182,7 @@ const char kOpenSSLReasonStringData[] = "UNSUPPORTED_COMPRESSION_ALGORITHM\0" "UNSUPPORTED_ELLIPTIC_CURVE\0" "UNSUPPORTED_PROTOCOL\0" + "UNSUPPORTED_PROTOCOL_FOR_CUSTOM_KEY\0" "WRONG_CERTIFICATE_TYPE\0" "WRONG_CIPHER_RETURNED\0" "WRONG_CURVE\0" @@ -1173,12 +1203,14 @@ const char kOpenSSLReasonStringData[] = "IDP_MISMATCH\0" "INVALID_DIRECTORY\0" "INVALID_FIELD_NAME\0" + "INVALID_PSS_PARAMETERS\0" "INVALID_TRUST\0" "ISSUER_MISMATCH\0" "KEY_TYPE_MISMATCH\0" "KEY_VALUES_MISMATCH\0" "LOADING_CERT_DIR\0" "LOADING_DEFAULTS\0" + "NAME_TOO_LONG\0" "NEWER_CRL_NOT_NEWER\0" "NOT_PKCS7_SIGNED_DATA\0" "NO_CERTIFICATES_INCLUDED\0" @@ -1188,8 +1220,6 @@ const char kOpenSSLReasonStringData[] = "PUBLIC_KEY_DECODE_ERROR\0" "PUBLIC_KEY_ENCODE_ERROR\0" "SHOULD_RETRY\0" - "UNABLE_TO_FIND_PARAMETERS_IN_CHAIN\0" - "UNABLE_TO_GET_CERTS_PUBLIC_KEY\0" "UNKNOWN_KEY_TYPE\0" "UNKNOWN_PURPOSE_ID\0" "UNKNOWN_TRUST_ID\0" diff --git a/Sources/BoringSSL/include/openssl/aead.h b/Sources/BoringSSL/include/openssl/aead.h index 092d2f623..bd655d6c8 100644 --- a/Sources/BoringSSL/include/openssl/aead.h +++ b/Sources/BoringSSL/include/openssl/aead.h @@ -64,7 +64,7 @@ extern "C" { * * The "seal" and "open" operations are atomic - an entire message must be * encrypted or decrypted in a single call. Large messages may have to be split - * up in order to accomodate this. When doing so, be mindful of the need not to + * up in order to accommodate this. When doing so, be mindful of the need not to * repeat nonces and the possibility that an attacker could duplicate, reorder * or drop message chunks. For example, using a single key for a given (large) * message and sealing chunks with nonces counting from zero would be secure as @@ -82,10 +82,8 @@ extern "C" { * permits implicit context to be authenticated but may be empty if not needed. * * The "seal" and "open" operations may work in-place if the |out| and |in| - * arguments are equal. They may also be used to shift the data left inside the - * same buffer if |out| is less than |in|. However, |out| may not point inside - * the input data otherwise the input may be overwritten before it has been - * read. This situation will cause an error. + * arguments are equal. Otherwise, if |out| and |in| alias, input data may be + * overwritten before it is read. This situation will cause an error. * * The "seal" and "open" operations return one on success and zero on error. */ @@ -102,25 +100,6 @@ OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_256_gcm(void); * Poly1305 as described in RFC 7539. */ OPENSSL_EXPORT const EVP_AEAD *EVP_aead_chacha20_poly1305(void); -/* EVP_aead_chacha20_poly1305_old is an AEAD built from ChaCha20 and - * Poly1305 that is used in the experimental ChaCha20-Poly1305 TLS cipher - * suites. */ -OPENSSL_EXPORT const EVP_AEAD *EVP_aead_chacha20_poly1305_old(void); - -/* EVP_aead_aes_128_key_wrap is AES-128 Key Wrap mode. This should never be - * used except to interoperate with existing systems that use this mode. - * - * If the nonce is empty then the default nonce will be used, otherwise it must - * be eight bytes long. The input must be a multiple of eight bytes long. No - * additional data can be given to this mode. */ -OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_128_key_wrap(void); - -/* EVP_aead_aes_256_key_wrap is AES-256 in Key Wrap mode. This should never be - * used except to interoperate with existing systems that use this mode. - * - * See |EVP_aead_aes_128_key_wrap| for details. */ -OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_256_key_wrap(void); - /* EVP_aead_aes_128_ctr_hmac_sha256 is AES-128 in CTR mode with HMAC-SHA256 for * authentication. The nonce is 12 bytes; the bottom 32-bits are used as the * block counter, thus the maximum plaintext size is 64GB. */ @@ -130,54 +109,19 @@ OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_128_ctr_hmac_sha256(void); * authentication. See |EVP_aead_aes_128_ctr_hmac_sha256| for details. */ OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_256_ctr_hmac_sha256(void); +/* EVP_aead_aes_128_gcm_siv is AES-128 in GCM-SIV mode. See + * https://tools.ietf.org/html/draft-irtf-cfrg-gcmsiv-02 */ +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_128_gcm_siv(void); + +/* EVP_aead_aes_256_gcm_siv is AES-256 in GCM-SIV mode. See + * https://tools.ietf.org/html/draft-irtf-cfrg-gcmsiv-02 */ +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_256_gcm_siv(void); + /* EVP_has_aes_hardware returns one if we enable hardware support for fast and * constant-time AES-GCM. */ OPENSSL_EXPORT int EVP_has_aes_hardware(void); -/* TLS-specific AEAD algorithms. - * - * These AEAD primitives do not meet the definition of generic AEADs. They are - * all specific to TLS and should not be used outside of that context. They must - * be initialized with |EVP_AEAD_CTX_init_with_direction|, are stateful, and may - * not be used concurrently. Any nonces are used as IVs, so they must be - * unpredictable. They only accept an |ad| parameter of length 11 (the standard - * TLS one with length omitted). */ - -OPENSSL_EXPORT const EVP_AEAD *EVP_aead_rc4_md5_tls(void); -OPENSSL_EXPORT const EVP_AEAD *EVP_aead_rc4_sha1_tls(void); - -OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_128_cbc_sha1_tls(void); -OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_128_cbc_sha1_tls_implicit_iv(void); -OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_128_cbc_sha256_tls(void); - -OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_256_cbc_sha1_tls(void); -OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_256_cbc_sha1_tls_implicit_iv(void); -OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_256_cbc_sha256_tls(void); -OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_256_cbc_sha384_tls(void); - -OPENSSL_EXPORT const EVP_AEAD *EVP_aead_des_ede3_cbc_sha1_tls(void); -OPENSSL_EXPORT const EVP_AEAD *EVP_aead_des_ede3_cbc_sha1_tls_implicit_iv(void); - -OPENSSL_EXPORT const EVP_AEAD *EVP_aead_null_sha1_tls(void); - - -/* SSLv3-specific AEAD algorithms. - * - * These AEAD primitives do not meet the definition of generic AEADs. They are - * all specific to SSLv3 and should not be used outside of that context. They - * must be initialized with |EVP_AEAD_CTX_init_with_direction|, are stateful, - * and may not be used concurrently. They only accept an |ad| parameter of - * length 9 (the standard TLS one with length and version omitted). */ - -OPENSSL_EXPORT const EVP_AEAD *EVP_aead_rc4_md5_ssl3(void); -OPENSSL_EXPORT const EVP_AEAD *EVP_aead_rc4_sha1_ssl3(void); -OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_128_cbc_sha1_ssl3(void); -OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_256_cbc_sha1_ssl3(void); -OPENSSL_EXPORT const EVP_AEAD *EVP_aead_des_ede3_cbc_sha1_ssl3(void); -OPENSSL_EXPORT const EVP_AEAD *EVP_aead_null_sha1_ssl3(void); - - /* Utility functions. */ /* EVP_AEAD_key_length returns the length, in bytes, of the keys used by @@ -226,12 +170,6 @@ typedef struct evp_aead_ctx_st { * be used. */ #define EVP_AEAD_DEFAULT_TAG_LENGTH 0 -/* evp_aead_direction_t denotes the direction of an AEAD operation. */ -enum evp_aead_direction_t { - evp_aead_open, - evp_aead_seal, -}; - /* EVP_AEAD_CTX_zero sets an uninitialized |ctx| to the zero state. It must be * initialized with |EVP_AEAD_CTX_init| before use. It is safe, but not * necessary, to call |EVP_AEAD_CTX_cleanup| in this state. This may be used for @@ -251,13 +189,6 @@ OPENSSL_EXPORT int EVP_AEAD_CTX_init(EVP_AEAD_CTX *ctx, const EVP_AEAD *aead, const uint8_t *key, size_t key_len, size_t tag_len, ENGINE *impl); -/* EVP_AEAD_CTX_init_with_direction calls |EVP_AEAD_CTX_init| for normal - * AEADs. For TLS-specific and SSL3-specific AEADs, it initializes |ctx| for a - * given direction. */ -OPENSSL_EXPORT int EVP_AEAD_CTX_init_with_direction( - EVP_AEAD_CTX *ctx, const EVP_AEAD *aead, const uint8_t *key, size_t key_len, - size_t tag_len, enum evp_aead_direction_t dir); - /* EVP_AEAD_CTX_cleanup frees any data allocated by |ctx|. It is a no-op to * call |EVP_AEAD_CTX_cleanup| on a |EVP_AEAD_CTX| that has been |memset| to * all zeros. */ @@ -282,7 +213,7 @@ OPENSSL_EXPORT void EVP_AEAD_CTX_cleanup(EVP_AEAD_CTX *ctx); * insufficient, zero will be returned. (In this case, |*out_len| is set to * zero.) * - * If |in| and |out| alias then |out| must be <= |in|. */ + * If |in| and |out| alias then |out| must be == |in|. */ OPENSSL_EXPORT int EVP_AEAD_CTX_seal(const EVP_AEAD_CTX *ctx, uint8_t *out, size_t *out_len, size_t max_out_len, const uint8_t *nonce, size_t nonce_len, @@ -307,20 +238,70 @@ OPENSSL_EXPORT int EVP_AEAD_CTX_seal(const EVP_AEAD_CTX *ctx, uint8_t *out, * insufficient, zero will be returned. (In this case, |*out_len| is set to * zero.) * - * If |in| and |out| alias then |out| must be <= |in|. */ + * If |in| and |out| alias then |out| must be == |in|. */ OPENSSL_EXPORT int EVP_AEAD_CTX_open(const EVP_AEAD_CTX *ctx, uint8_t *out, size_t *out_len, size_t max_out_len, const uint8_t *nonce, size_t nonce_len, const uint8_t *in, size_t in_len, const uint8_t *ad, size_t ad_len); +/* EVP_AEAD_CTX_aead returns the underlying AEAD for |ctx|, or NULL if one has + * not been set. */ +OPENSSL_EXPORT const EVP_AEAD *EVP_AEAD_CTX_aead(const EVP_AEAD_CTX *ctx); + + +/* TLS-specific AEAD algorithms. + * + * These AEAD primitives do not meet the definition of generic AEADs. They are + * all specific to TLS and should not be used outside of that context. They must + * be initialized with |EVP_AEAD_CTX_init_with_direction|, are stateful, and may + * not be used concurrently. Any nonces are used as IVs, so they must be + * unpredictable. They only accept an |ad| parameter of length 11 (the standard + * TLS one with length omitted). */ + +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_128_cbc_sha1_tls(void); +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_128_cbc_sha1_tls_implicit_iv(void); +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_128_cbc_sha256_tls(void); + +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_256_cbc_sha1_tls(void); +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_256_cbc_sha1_tls_implicit_iv(void); +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_256_cbc_sha256_tls(void); +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_256_cbc_sha384_tls(void); + +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_des_ede3_cbc_sha1_tls(void); +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_des_ede3_cbc_sha1_tls_implicit_iv(void); + +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_null_sha1_tls(void); + + +/* SSLv3-specific AEAD algorithms. + * + * These AEAD primitives do not meet the definition of generic AEADs. They are + * all specific to SSLv3 and should not be used outside of that context. They + * must be initialized with |EVP_AEAD_CTX_init_with_direction|, are stateful, + * and may not be used concurrently. They only accept an |ad| parameter of + * length 9 (the standard TLS one with length and version omitted). */ + +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_128_cbc_sha1_ssl3(void); +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_256_cbc_sha1_ssl3(void); +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_des_ede3_cbc_sha1_ssl3(void); +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_null_sha1_ssl3(void); + /* Obscure functions. */ -/* EVP_AEAD_CTX_get_rc4_state sets |*out_key| to point to an RC4 key structure. - * It returns one on success or zero if |ctx| doesn't have an RC4 key. */ -OPENSSL_EXPORT int EVP_AEAD_CTX_get_rc4_state(const EVP_AEAD_CTX *ctx, - const RC4_KEY **out_key); +/* evp_aead_direction_t denotes the direction of an AEAD operation. */ +enum evp_aead_direction_t { + evp_aead_open, + evp_aead_seal, +}; + +/* EVP_AEAD_CTX_init_with_direction calls |EVP_AEAD_CTX_init| for normal + * AEADs. For TLS-specific and SSL3-specific AEADs, it initializes |ctx| for a + * given direction. */ +OPENSSL_EXPORT int EVP_AEAD_CTX_init_with_direction( + EVP_AEAD_CTX *ctx, const EVP_AEAD *aead, const uint8_t *key, size_t key_len, + size_t tag_len, enum evp_aead_direction_t dir); /* EVP_AEAD_CTX_get_iv sets |*out_len| to the length of the IV for |ctx| and * sets |*out_iv| to point to that many bytes of the current IV. This is only @@ -331,16 +312,23 @@ OPENSSL_EXPORT int EVP_AEAD_CTX_get_iv(const EVP_AEAD_CTX *ctx, const uint8_t **out_iv, size_t *out_len); -/* Deprecated functions. */ +#if defined(__cplusplus) +} /* extern C */ + +#if !defined(BORINGSSL_NO_CXX) +extern "C++" { + +namespace bssl { -/* EVP_aead_chacha20_poly1305_rfc7539 calls |EVP_aead_chacha20_poly1305|. - * - * TODO(davidben): Remove this. */ -OPENSSL_EXPORT const EVP_AEAD *EVP_aead_chacha20_poly1305_rfc7539(void); +using ScopedEVP_AEAD_CTX = + internal::StackAllocated; +} // namespace bssl + +} // extern C++ +#endif -#if defined(__cplusplus) -} /* extern C */ #endif #endif /* OPENSSL_HEADER_AEAD_H */ diff --git a/Sources/BoringSSL/include/openssl/aes.h b/Sources/BoringSSL/include/openssl/aes.h index ed060ff66..2aef91825 100644 --- a/Sources/BoringSSL/include/openssl/aes.h +++ b/Sources/BoringSSL/include/openssl/aes.h @@ -139,16 +139,28 @@ OPENSSL_EXPORT void AES_cfb128_encrypt(const uint8_t *in, uint8_t *out, uint8_t *ivec, int *num, int enc); -/* Android compatibility section. +/* AES key wrap. * - * These functions are declared, temporarily, for Android because - * wpa_supplicant will take a little time to sync with upstream. Outside of - * Android they'll have no definition. */ - -OPENSSL_EXPORT int AES_wrap_key(AES_KEY *key, const uint8_t *iv, uint8_t *out, - const uint8_t *in, unsigned in_len); -OPENSSL_EXPORT int AES_unwrap_key(AES_KEY *key, const uint8_t *iv, uint8_t *out, - const uint8_t *in, unsigned in_len); + * These functions implement AES Key Wrap mode, as defined in RFC 3394. They + * should never be used except to interoperate with existing systems that use + * this mode. */ + +/* AES_wrap_key performs AES key wrap on |in| which must be a multiple of 8 + * bytes. |iv| must point to an 8 byte value or be NULL to use the default IV. + * |key| must have been configured for encryption. On success, it writes + * |in_len| + 8 bytes to |out| and returns |in_len| + 8. Otherwise, it returns + * -1. */ +OPENSSL_EXPORT int AES_wrap_key(const AES_KEY *key, const uint8_t *iv, + uint8_t *out, const uint8_t *in, size_t in_len); + +/* AES_unwrap_key performs AES key unwrap on |in| which must be a multiple of 8 + * bytes. |iv| must point to an 8 byte value or be NULL to use the default IV. + * |key| must have been configured for decryption. On success, it writes + * |in_len| - 8 bytes to |out| and returns |in_len| - 8. Otherwise, it returns + * -1. */ +OPENSSL_EXPORT int AES_unwrap_key(const AES_KEY *key, const uint8_t *iv, + uint8_t *out, const uint8_t *in, + size_t in_len); #if defined(__cplusplus) diff --git a/Sources/BoringSSL/include/openssl/arm_arch.h b/Sources/BoringSSL/include/openssl/arm_arch.h index 1471db90a..e7010f402 100644 --- a/Sources/BoringSSL/include/openssl/arm_arch.h +++ b/Sources/BoringSSL/include/openssl/arm_arch.h @@ -105,12 +105,6 @@ /* ARMV7_NEON is true when a NEON unit is present in the current CPU. */ #define ARMV7_NEON (1 << 0) -/* ARMV7_NEON_FUNCTIONAL is true when the NEON unit doesn't contain subtle bugs. - * The Poly1305 NEON code is known to trigger bugs in the NEON units of some - * phones. If this bit isn't set then the Poly1305 NEON code won't be used. - * See https://code.google.com/p/chromium/issues/detail?id=341598. */ -#define ARMV7_NEON_FUNCTIONAL (1 << 10) - /* ARMV8_AES indicates support for hardware AES instructions. */ #define ARMV8_AES (1 << 2) diff --git a/Sources/BoringSSL/include/openssl/asn1.h b/Sources/BoringSSL/include/openssl/asn1.h index e27164eb7..42386e0cf 100644 --- a/Sources/BoringSSL/include/openssl/asn1.h +++ b/Sources/BoringSSL/include/openssl/asn1.h @@ -205,6 +205,8 @@ struct asn1_object_st int flags; /* Should we free this one */ }; +DECLARE_STACK_OF(ASN1_OBJECT) + #define ASN1_STRING_FLAG_BITS_LEFT 0x08 /* Set if 0x07 has bits left value */ /* This indicates that the ASN1_STRING is not a real value but just a place * holder for the location where indefinite length constructed data should @@ -244,7 +246,15 @@ typedef struct ASN1_ENCODING_st { unsigned char *enc; /* DER encoding */ long len; /* Length of encoding */ - int modified; /* set to 1 if 'enc' is invalid */ + int modified; /* set to 1 if 'enc' is invalid */ + /* alias_only is zero if |enc| owns the buffer that it points to + * (although |enc| may still be NULL). If one, |enc| points into a + * buffer that is owned elsewhere. */ + unsigned alias_only:1; + /* alias_only_on_next_parse is one iff the next parsing operation + * should avoid taking a copy of the input and rather set + * |alias_only|. */ + unsigned alias_only_on_next_parse:1; } ASN1_ENCODING; /* Used with ASN1 LONG type: if a long is set to this it is omitted */ @@ -475,7 +485,7 @@ typedef const ASN1_ITEM ASN1_ITEM_EXP; DECLARE_ASN1_SET_OF(ASN1_INTEGER) -typedef struct asn1_type_st +struct asn1_type_st { int type; union { @@ -503,7 +513,7 @@ typedef struct asn1_type_st ASN1_STRING * sequence; ASN1_VALUE * asn1_value; } value; - } ASN1_TYPE; + }; DECLARE_ASN1_SET_OF(ASN1_TYPE) @@ -574,9 +584,6 @@ typedef struct BIT_STRING_BITNAME_st { (const ASN1_STRING *)a,(const ASN1_STRING *)b) #define M_ASN1_OCTET_STRING_set(a,b,c) ASN1_STRING_set((ASN1_STRING *)a,b,c) #define M_ASN1_OCTET_STRING_print(a,b) ASN1_STRING_print(a,(ASN1_STRING *)b) -#define M_i2d_ASN1_OCTET_STRING(a,pp) \ - i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_OCTET_STRING,\ - V_ASN1_UNIVERSAL) #define B_ASN1_TIME \ B_ASN1_UTCTIME | \ @@ -609,59 +616,26 @@ typedef struct BIT_STRING_BITNAME_st { #define M_ASN1_PRINTABLE_new() ASN1_STRING_type_new(V_ASN1_T61STRING) #define M_ASN1_PRINTABLE_free(a) ASN1_STRING_free((ASN1_STRING *)a) -#define M_i2d_ASN1_PRINTABLE(a,pp) i2d_ASN1_bytes((ASN1_STRING *)a,\ - pp,a->type,V_ASN1_UNIVERSAL) -#define M_d2i_ASN1_PRINTABLE(a,pp,l) \ - d2i_ASN1_type_bytes((ASN1_STRING **)a,pp,l, \ - B_ASN1_PRINTABLE) #define M_DIRECTORYSTRING_new() ASN1_STRING_type_new(V_ASN1_PRINTABLESTRING) #define M_DIRECTORYSTRING_free(a) ASN1_STRING_free((ASN1_STRING *)a) -#define M_i2d_DIRECTORYSTRING(a,pp) i2d_ASN1_bytes((ASN1_STRING *)a,\ - pp,a->type,V_ASN1_UNIVERSAL) -#define M_d2i_DIRECTORYSTRING(a,pp,l) \ - d2i_ASN1_type_bytes((ASN1_STRING **)a,pp,l, \ - B_ASN1_DIRECTORYSTRING) #define M_DISPLAYTEXT_new() ASN1_STRING_type_new(V_ASN1_VISIBLESTRING) #define M_DISPLAYTEXT_free(a) ASN1_STRING_free((ASN1_STRING *)a) -#define M_i2d_DISPLAYTEXT(a,pp) i2d_ASN1_bytes((ASN1_STRING *)a,\ - pp,a->type,V_ASN1_UNIVERSAL) -#define M_d2i_DISPLAYTEXT(a,pp,l) \ - d2i_ASN1_type_bytes((ASN1_STRING **)a,pp,l, \ - B_ASN1_DISPLAYTEXT) #define M_ASN1_PRINTABLESTRING_new() (ASN1_PRINTABLESTRING *)\ ASN1_STRING_type_new(V_ASN1_PRINTABLESTRING) #define M_ASN1_PRINTABLESTRING_free(a) ASN1_STRING_free((ASN1_STRING *)a) -#define M_i2d_ASN1_PRINTABLESTRING(a,pp) \ - i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_PRINTABLESTRING,\ - V_ASN1_UNIVERSAL) -#define M_d2i_ASN1_PRINTABLESTRING(a,pp,l) \ - (ASN1_PRINTABLESTRING *)d2i_ASN1_type_bytes\ - ((ASN1_STRING **)a,pp,l,B_ASN1_PRINTABLESTRING) #define M_ASN1_T61STRING_new() (ASN1_T61STRING *)\ ASN1_STRING_type_new(V_ASN1_T61STRING) #define M_ASN1_T61STRING_free(a) ASN1_STRING_free((ASN1_STRING *)a) -#define M_i2d_ASN1_T61STRING(a,pp) \ - i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_T61STRING,\ - V_ASN1_UNIVERSAL) -#define M_d2i_ASN1_T61STRING(a,pp,l) \ - (ASN1_T61STRING *)d2i_ASN1_type_bytes\ - ((ASN1_STRING **)a,pp,l,B_ASN1_T61STRING) #define M_ASN1_IA5STRING_new() (ASN1_IA5STRING *)\ ASN1_STRING_type_new(V_ASN1_IA5STRING) #define M_ASN1_IA5STRING_free(a) ASN1_STRING_free((ASN1_STRING *)a) #define M_ASN1_IA5STRING_dup(a) \ (ASN1_IA5STRING *)ASN1_STRING_dup((const ASN1_STRING *)a) -#define M_i2d_ASN1_IA5STRING(a,pp) \ - i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_IA5STRING,\ - V_ASN1_UNIVERSAL) -#define M_d2i_ASN1_IA5STRING(a,pp,l) \ - (ASN1_IA5STRING *)d2i_ASN1_type_bytes((ASN1_STRING **)a,pp,l,\ - B_ASN1_IA5STRING) #define M_ASN1_UTCTIME_new() (ASN1_UTCTIME *)\ ASN1_STRING_type_new(V_ASN1_UTCTIME) @@ -684,56 +658,22 @@ typedef struct BIT_STRING_BITNAME_st { #define M_ASN1_GENERALSTRING_new() (ASN1_GENERALSTRING *)\ ASN1_STRING_type_new(V_ASN1_GENERALSTRING) #define M_ASN1_GENERALSTRING_free(a) ASN1_STRING_free((ASN1_STRING *)a) -#define M_i2d_ASN1_GENERALSTRING(a,pp) \ - i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_GENERALSTRING,\ - V_ASN1_UNIVERSAL) -#define M_d2i_ASN1_GENERALSTRING(a,pp,l) \ - (ASN1_GENERALSTRING *)d2i_ASN1_type_bytes\ - ((ASN1_STRING **)a,pp,l,B_ASN1_GENERALSTRING) #define M_ASN1_UNIVERSALSTRING_new() (ASN1_UNIVERSALSTRING *)\ ASN1_STRING_type_new(V_ASN1_UNIVERSALSTRING) #define M_ASN1_UNIVERSALSTRING_free(a) ASN1_STRING_free((ASN1_STRING *)a) -#define M_i2d_ASN1_UNIVERSALSTRING(a,pp) \ - i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_UNIVERSALSTRING,\ - V_ASN1_UNIVERSAL) -#define M_d2i_ASN1_UNIVERSALSTRING(a,pp,l) \ - (ASN1_UNIVERSALSTRING *)d2i_ASN1_type_bytes\ - ((ASN1_STRING **)a,pp,l,B_ASN1_UNIVERSALSTRING) #define M_ASN1_BMPSTRING_new() (ASN1_BMPSTRING *)\ ASN1_STRING_type_new(V_ASN1_BMPSTRING) #define M_ASN1_BMPSTRING_free(a) ASN1_STRING_free((ASN1_STRING *)a) -#define M_i2d_ASN1_BMPSTRING(a,pp) \ - i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_BMPSTRING,\ - V_ASN1_UNIVERSAL) -#define M_d2i_ASN1_BMPSTRING(a,pp,l) \ - (ASN1_BMPSTRING *)d2i_ASN1_type_bytes\ - ((ASN1_STRING **)a,pp,l,B_ASN1_BMPSTRING) #define M_ASN1_VISIBLESTRING_new() (ASN1_VISIBLESTRING *)\ ASN1_STRING_type_new(V_ASN1_VISIBLESTRING) #define M_ASN1_VISIBLESTRING_free(a) ASN1_STRING_free((ASN1_STRING *)a) -#define M_i2d_ASN1_VISIBLESTRING(a,pp) \ - i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_VISIBLESTRING,\ - V_ASN1_UNIVERSAL) -#define M_d2i_ASN1_VISIBLESTRING(a,pp,l) \ - (ASN1_VISIBLESTRING *)d2i_ASN1_type_bytes\ - ((ASN1_STRING **)a,pp,l,B_ASN1_VISIBLESTRING) #define M_ASN1_UTF8STRING_new() (ASN1_UTF8STRING *)\ ASN1_STRING_type_new(V_ASN1_UTF8STRING) #define M_ASN1_UTF8STRING_free(a) ASN1_STRING_free((ASN1_STRING *)a) -#define M_i2d_ASN1_UTF8STRING(a,pp) \ - i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_UTF8STRING,\ - V_ASN1_UNIVERSAL) -#define M_d2i_ASN1_UTF8STRING(a,pp,l) \ - (ASN1_UTF8STRING *)d2i_ASN1_type_bytes\ - ((ASN1_STRING **)a,pp,l,B_ASN1_UTF8STRING) - - /* for the is_set parameter to i2d_ASN1_SET */ -#define IS_SEQUENCE 0 -#define IS_SET 1 DECLARE_ASN1_FUNCTIONS_fname(ASN1_TYPE, ASN1_ANY, ASN1_TYPE) @@ -842,19 +782,9 @@ OPENSSL_EXPORT int ASN1_TIME_check(ASN1_TIME *t); OPENSSL_EXPORT ASN1_GENERALIZEDTIME *ASN1_TIME_to_generalizedtime(ASN1_TIME *t, ASN1_GENERALIZEDTIME **out); OPENSSL_EXPORT int ASN1_TIME_set_string(ASN1_TIME *s, const char *str); -OPENSSL_EXPORT int i2d_ASN1_SET(STACK_OF(OPENSSL_BLOCK) *a, unsigned char **pp, i2d_of_void *i2d, int ex_tag, int ex_class, int is_set); -OPENSSL_EXPORT STACK_OF(OPENSSL_BLOCK) *d2i_ASN1_SET(STACK_OF(OPENSSL_BLOCK) **a, - const unsigned char **pp, - long length, d2i_of_void *d2i, - void (*free_func)(OPENSSL_BLOCK), int ex_tag, - int ex_class); - OPENSSL_EXPORT int i2a_ASN1_INTEGER(BIO *bp, ASN1_INTEGER *a); -OPENSSL_EXPORT int a2i_ASN1_INTEGER(BIO *bp,ASN1_INTEGER *bs,char *buf,int size); OPENSSL_EXPORT int i2a_ASN1_ENUMERATED(BIO *bp, ASN1_ENUMERATED *a); -OPENSSL_EXPORT int a2i_ASN1_ENUMERATED(BIO *bp,ASN1_ENUMERATED *bs,char *buf,int size); OPENSSL_EXPORT int i2a_ASN1_OBJECT(BIO *bp,ASN1_OBJECT *a); -OPENSSL_EXPORT int a2i_ASN1_STRING(BIO *bp,ASN1_STRING *bs,char *buf,int size); OPENSSL_EXPORT int i2a_ASN1_STRING(BIO *bp, ASN1_STRING *a, int type); OPENSSL_EXPORT int i2t_ASN1_OBJECT(char *buf,int buf_len,ASN1_OBJECT *a); @@ -875,11 +805,7 @@ OPENSSL_EXPORT BIGNUM *ASN1_ENUMERATED_to_BN(ASN1_ENUMERATED *ai,BIGNUM *bn); /* given a string, return the correct type, max is the maximum length */ OPENSSL_EXPORT int ASN1_PRINTABLE_type(const unsigned char *s, int max); -OPENSSL_EXPORT int i2d_ASN1_bytes(ASN1_STRING *a, unsigned char **pp, int tag, int xclass); -OPENSSL_EXPORT ASN1_STRING *d2i_ASN1_bytes(ASN1_STRING **a, const unsigned char **pp, long length, int Ptag, int Pclass); OPENSSL_EXPORT unsigned long ASN1_tag2bit(int tag); -/* type is one or more of the B_ASN1_ values. */ -OPENSSL_EXPORT ASN1_STRING *d2i_ASN1_type_bytes(ASN1_STRING **a,const unsigned char **pp, long length,int type); /* PARSING */ OPENSSL_EXPORT int asn1_Finish(ASN1_CTX *c); @@ -969,9 +895,6 @@ OPENSSL_EXPORT int ASN1_GENERALIZEDTIME_print(BIO *fp, const ASN1_GENERALIZEDTIM OPENSSL_EXPORT int ASN1_TIME_print(BIO *fp, const ASN1_TIME *a); OPENSSL_EXPORT int ASN1_STRING_print(BIO *bp, const ASN1_STRING *v); OPENSSL_EXPORT int ASN1_STRING_print_ex(BIO *out, ASN1_STRING *str, unsigned long flags); -OPENSSL_EXPORT int ASN1_bn_print(BIO *bp, const char *number, const BIGNUM *num, unsigned char *buf, int off); -OPENSSL_EXPORT int ASN1_parse(BIO *bp,const unsigned char *pp,long len,int indent); -OPENSSL_EXPORT int ASN1_parse_dump(BIO *bp,const unsigned char *pp,long len,int indent,int dump); OPENSSL_EXPORT const char *ASN1_tag2str(int tag); /* Used to load and write netscape format cert */ @@ -980,16 +903,7 @@ DECLARE_ASN1_FUNCTIONS(NETSCAPE_X509) int ASN1_UNIVERSALSTRING_to_string(ASN1_UNIVERSALSTRING *s); -OPENSSL_EXPORT STACK_OF(OPENSSL_BLOCK) *ASN1_seq_unpack(const unsigned char *buf, int len, d2i_of_void *d2i, void (*free_func)(OPENSSL_BLOCK)); -OPENSSL_EXPORT unsigned char *ASN1_seq_pack(STACK_OF(OPENSSL_BLOCK) *safes, i2d_of_void *i2d, unsigned char **buf, int *len ); -OPENSSL_EXPORT void *ASN1_unpack_string(ASN1_STRING *oct, d2i_of_void *d2i); OPENSSL_EXPORT void *ASN1_item_unpack(ASN1_STRING *oct, const ASN1_ITEM *it); -OPENSSL_EXPORT ASN1_STRING *ASN1_pack_string(void *obj, i2d_of_void *i2d, ASN1_OCTET_STRING **oct); - -#define ASN1_pack_string_of(type,obj,i2d,oct) \ - (ASN1_pack_string(CHECKED_PTR_OF(type, obj), \ - CHECKED_I2D_OF(type, i2d), \ - oct)) OPENSSL_EXPORT ASN1_STRING *ASN1_item_pack(void *obj, const ASN1_ITEM *it, ASN1_OCTET_STRING **oct); @@ -1013,70 +927,27 @@ OPENSSL_EXPORT ASN1_VALUE * ASN1_item_d2i(ASN1_VALUE **val, const unsigned char OPENSSL_EXPORT int ASN1_item_i2d(ASN1_VALUE *val, unsigned char **out, const ASN1_ITEM *it); OPENSSL_EXPORT int ASN1_item_ndef_i2d(ASN1_VALUE *val, unsigned char **out, const ASN1_ITEM *it); -OPENSSL_EXPORT void ASN1_add_oid_module(void); - OPENSSL_EXPORT ASN1_TYPE *ASN1_generate_nconf(char *str, CONF *nconf); OPENSSL_EXPORT ASN1_TYPE *ASN1_generate_v3(char *str, X509V3_CTX *cnf); -/* ASN1 Print flags */ - -/* Indicate missing OPTIONAL fields */ -#define ASN1_PCTX_FLAGS_SHOW_ABSENT 0x001 -/* Mark start and end of SEQUENCE */ -#define ASN1_PCTX_FLAGS_SHOW_SEQUENCE 0x002 -/* Mark start and end of SEQUENCE/SET OF */ -#define ASN1_PCTX_FLAGS_SHOW_SSOF 0x004 -/* Show the ASN1 type of primitives */ -#define ASN1_PCTX_FLAGS_SHOW_TYPE 0x008 -/* Don't show ASN1 type of ANY */ -#define ASN1_PCTX_FLAGS_NO_ANY_TYPE 0x010 -/* Don't show ASN1 type of MSTRINGs */ -#define ASN1_PCTX_FLAGS_NO_MSTRING_TYPE 0x020 -/* Don't show field names in SEQUENCE */ -#define ASN1_PCTX_FLAGS_NO_FIELD_NAME 0x040 -/* Show structure names of each SEQUENCE field */ -#define ASN1_PCTX_FLAGS_SHOW_FIELD_STRUCT_NAME 0x080 -/* Don't show structure name even at top level */ -#define ASN1_PCTX_FLAGS_NO_STRUCT_NAME 0x100 - -OPENSSL_EXPORT int ASN1_item_print(BIO *out, ASN1_VALUE *ifld, int indent, const ASN1_ITEM *it, const ASN1_PCTX *pctx); -OPENSSL_EXPORT ASN1_PCTX *ASN1_PCTX_new(void); -OPENSSL_EXPORT void ASN1_PCTX_free(ASN1_PCTX *p); -OPENSSL_EXPORT unsigned long ASN1_PCTX_get_flags(ASN1_PCTX *p); -OPENSSL_EXPORT void ASN1_PCTX_set_flags(ASN1_PCTX *p, unsigned long flags); -OPENSSL_EXPORT unsigned long ASN1_PCTX_get_nm_flags(ASN1_PCTX *p); -OPENSSL_EXPORT void ASN1_PCTX_set_nm_flags(ASN1_PCTX *p, unsigned long flags); -OPENSSL_EXPORT unsigned long ASN1_PCTX_get_cert_flags(ASN1_PCTX *p); -OPENSSL_EXPORT void ASN1_PCTX_set_cert_flags(ASN1_PCTX *p, unsigned long flags); -OPENSSL_EXPORT unsigned long ASN1_PCTX_get_oid_flags(ASN1_PCTX *p); -OPENSSL_EXPORT void ASN1_PCTX_set_oid_flags(ASN1_PCTX *p, unsigned long flags); -OPENSSL_EXPORT unsigned long ASN1_PCTX_get_str_flags(ASN1_PCTX *p); -OPENSSL_EXPORT void ASN1_PCTX_set_str_flags(ASN1_PCTX *p, unsigned long flags); - -OPENSSL_EXPORT const BIO_METHOD *BIO_f_asn1(void); - -OPENSSL_EXPORT BIO *BIO_new_NDEF(BIO *out, ASN1_VALUE *val, const ASN1_ITEM *it); - -OPENSSL_EXPORT int i2d_ASN1_bio_stream(BIO *out, ASN1_VALUE *val, BIO *in, int flags, const ASN1_ITEM *it); -OPENSSL_EXPORT int PEM_write_bio_ASN1_stream(BIO *out, ASN1_VALUE *val, BIO *in, int flags, const char *hdr, const ASN1_ITEM *it); -OPENSSL_EXPORT ASN1_VALUE *SMIME_read_ASN1(BIO *bio, BIO **bcont, const ASN1_ITEM *it); -OPENSSL_EXPORT int SMIME_crlf_copy(BIO *in, BIO *out, int flags); -OPENSSL_EXPORT int SMIME_text(BIO *in, BIO *out); - -/* BEGIN ERROR CODES */ -/* The following lines are auto generated by the script mkerr.pl. Any changes - * made after this point may be overwritten when the script is next run. - */ -void ERR_load_ASN1_strings(void); - -typedef int asn1_ps_func(BIO *b, unsigned char **pbuf, int *plen, void *parg); -OPENSSL_EXPORT int BIO_asn1_set_prefix(BIO *b, asn1_ps_func *prefix, asn1_ps_func *prefix_free); -OPENSSL_EXPORT int BIO_asn1_get_prefix(BIO *b, asn1_ps_func **pprefix, asn1_ps_func **pprefix_free); -OPENSSL_EXPORT int BIO_asn1_set_suffix(BIO *b, asn1_ps_func *suffix, asn1_ps_func *suffix_free); -OPENSSL_EXPORT int BIO_asn1_get_suffix(BIO *b, asn1_ps_func **psuffix, asn1_ps_func **psuffix_free); #ifdef __cplusplus } + +extern "C++" { + +namespace bssl { + +BORINGSSL_MAKE_STACK_DELETER(ASN1_OBJECT, ASN1_OBJECT_free) + +BORINGSSL_MAKE_DELETER(ASN1_OBJECT, ASN1_OBJECT_free) +BORINGSSL_MAKE_DELETER(ASN1_STRING, ASN1_STRING_free) +BORINGSSL_MAKE_DELETER(ASN1_TYPE, ASN1_TYPE_free) + +} // namespace bssl + +} /* extern C++ */ + #endif #define ASN1_R_ASN1_LENGTH_MISMATCH 100 @@ -1087,84 +958,89 @@ OPENSSL_EXPORT int BIO_asn1_get_suffix(BIO *b, asn1_ps_func **psuffix, asn1_ps_f #define ASN1_R_BN_LIB 105 #define ASN1_R_BOOLEAN_IS_WRONG_LENGTH 106 #define ASN1_R_BUFFER_TOO_SMALL 107 -#define ASN1_R_DECODE_ERROR 108 -#define ASN1_R_DEPTH_EXCEEDED 109 -#define ASN1_R_ENCODE_ERROR 110 -#define ASN1_R_ERROR_GETTING_TIME 111 -#define ASN1_R_EXPECTING_AN_ASN1_SEQUENCE 112 -#define ASN1_R_EXPECTING_AN_INTEGER 113 -#define ASN1_R_EXPECTING_AN_OBJECT 114 -#define ASN1_R_EXPECTING_A_BOOLEAN 115 -#define ASN1_R_EXPECTING_A_TIME 116 -#define ASN1_R_EXPLICIT_LENGTH_MISMATCH 117 -#define ASN1_R_EXPLICIT_TAG_NOT_CONSTRUCTED 118 -#define ASN1_R_FIELD_MISSING 119 -#define ASN1_R_FIRST_NUM_TOO_LARGE 120 -#define ASN1_R_HEADER_TOO_LONG 121 -#define ASN1_R_ILLEGAL_BITSTRING_FORMAT 122 -#define ASN1_R_ILLEGAL_BOOLEAN 123 -#define ASN1_R_ILLEGAL_CHARACTERS 124 -#define ASN1_R_ILLEGAL_FORMAT 125 -#define ASN1_R_ILLEGAL_HEX 126 -#define ASN1_R_ILLEGAL_IMPLICIT_TAG 127 -#define ASN1_R_ILLEGAL_INTEGER 128 -#define ASN1_R_ILLEGAL_NESTED_TAGGING 129 -#define ASN1_R_ILLEGAL_NULL 130 -#define ASN1_R_ILLEGAL_NULL_VALUE 131 -#define ASN1_R_ILLEGAL_OBJECT 132 -#define ASN1_R_ILLEGAL_OPTIONAL_ANY 133 -#define ASN1_R_ILLEGAL_OPTIONS_ON_ITEM_TEMPLATE 134 -#define ASN1_R_ILLEGAL_TAGGED_ANY 135 -#define ASN1_R_ILLEGAL_TIME_VALUE 136 -#define ASN1_R_INTEGER_NOT_ASCII_FORMAT 137 -#define ASN1_R_INTEGER_TOO_LARGE_FOR_LONG 138 -#define ASN1_R_INVALID_BIT_STRING_BITS_LEFT 139 -#define ASN1_R_INVALID_BMPSTRING_LENGTH 140 -#define ASN1_R_INVALID_DIGIT 141 -#define ASN1_R_INVALID_MODIFIER 142 -#define ASN1_R_INVALID_NUMBER 143 -#define ASN1_R_INVALID_OBJECT_ENCODING 144 -#define ASN1_R_INVALID_SEPARATOR 145 -#define ASN1_R_INVALID_TIME_FORMAT 146 -#define ASN1_R_INVALID_UNIVERSALSTRING_LENGTH 147 -#define ASN1_R_INVALID_UTF8STRING 148 -#define ASN1_R_LIST_ERROR 149 -#define ASN1_R_MISSING_ASN1_EOS 150 -#define ASN1_R_MISSING_EOC 151 -#define ASN1_R_MISSING_SECOND_NUMBER 152 -#define ASN1_R_MISSING_VALUE 153 -#define ASN1_R_MSTRING_NOT_UNIVERSAL 154 -#define ASN1_R_MSTRING_WRONG_TAG 155 -#define ASN1_R_NESTED_ASN1_ERROR 156 -#define ASN1_R_NESTED_ASN1_STRING 157 -#define ASN1_R_NON_HEX_CHARACTERS 158 -#define ASN1_R_NOT_ASCII_FORMAT 159 -#define ASN1_R_NOT_ENOUGH_DATA 160 -#define ASN1_R_NO_MATCHING_CHOICE_TYPE 161 -#define ASN1_R_NULL_IS_WRONG_LENGTH 162 -#define ASN1_R_OBJECT_NOT_ASCII_FORMAT 163 -#define ASN1_R_ODD_NUMBER_OF_CHARS 164 -#define ASN1_R_SECOND_NUMBER_TOO_LARGE 165 -#define ASN1_R_SEQUENCE_LENGTH_MISMATCH 166 -#define ASN1_R_SEQUENCE_NOT_CONSTRUCTED 167 -#define ASN1_R_SEQUENCE_OR_SET_NEEDS_CONFIG 168 -#define ASN1_R_SHORT_LINE 169 -#define ASN1_R_STREAMING_NOT_SUPPORTED 170 -#define ASN1_R_STRING_TOO_LONG 171 -#define ASN1_R_STRING_TOO_SHORT 172 -#define ASN1_R_TAG_VALUE_TOO_HIGH 173 -#define ASN1_R_TIME_NOT_ASCII_FORMAT 174 -#define ASN1_R_TOO_LONG 175 -#define ASN1_R_TYPE_NOT_CONSTRUCTED 176 -#define ASN1_R_TYPE_NOT_PRIMITIVE 177 -#define ASN1_R_UNEXPECTED_EOC 178 -#define ASN1_R_UNIVERSALSTRING_IS_WRONG_LENGTH 179 -#define ASN1_R_UNKNOWN_FORMAT 180 -#define ASN1_R_UNKNOWN_TAG 181 -#define ASN1_R_UNSUPPORTED_ANY_DEFINED_BY_TYPE 182 -#define ASN1_R_UNSUPPORTED_PUBLIC_KEY_TYPE 183 -#define ASN1_R_UNSUPPORTED_TYPE 184 -#define ASN1_R_WRONG_TAG 185 -#define ASN1_R_WRONG_TYPE 186 +#define ASN1_R_CONTEXT_NOT_INITIALISED 108 +#define ASN1_R_DECODE_ERROR 109 +#define ASN1_R_DEPTH_EXCEEDED 110 +#define ASN1_R_DIGEST_AND_KEY_TYPE_NOT_SUPPORTED 111 +#define ASN1_R_ENCODE_ERROR 112 +#define ASN1_R_ERROR_GETTING_TIME 113 +#define ASN1_R_EXPECTING_AN_ASN1_SEQUENCE 114 +#define ASN1_R_EXPECTING_AN_INTEGER 115 +#define ASN1_R_EXPECTING_AN_OBJECT 116 +#define ASN1_R_EXPECTING_A_BOOLEAN 117 +#define ASN1_R_EXPECTING_A_TIME 118 +#define ASN1_R_EXPLICIT_LENGTH_MISMATCH 119 +#define ASN1_R_EXPLICIT_TAG_NOT_CONSTRUCTED 120 +#define ASN1_R_FIELD_MISSING 121 +#define ASN1_R_FIRST_NUM_TOO_LARGE 122 +#define ASN1_R_HEADER_TOO_LONG 123 +#define ASN1_R_ILLEGAL_BITSTRING_FORMAT 124 +#define ASN1_R_ILLEGAL_BOOLEAN 125 +#define ASN1_R_ILLEGAL_CHARACTERS 126 +#define ASN1_R_ILLEGAL_FORMAT 127 +#define ASN1_R_ILLEGAL_HEX 128 +#define ASN1_R_ILLEGAL_IMPLICIT_TAG 129 +#define ASN1_R_ILLEGAL_INTEGER 130 +#define ASN1_R_ILLEGAL_NESTED_TAGGING 131 +#define ASN1_R_ILLEGAL_NULL 132 +#define ASN1_R_ILLEGAL_NULL_VALUE 133 +#define ASN1_R_ILLEGAL_OBJECT 134 +#define ASN1_R_ILLEGAL_OPTIONAL_ANY 135 +#define ASN1_R_ILLEGAL_OPTIONS_ON_ITEM_TEMPLATE 136 +#define ASN1_R_ILLEGAL_TAGGED_ANY 137 +#define ASN1_R_ILLEGAL_TIME_VALUE 138 +#define ASN1_R_INTEGER_NOT_ASCII_FORMAT 139 +#define ASN1_R_INTEGER_TOO_LARGE_FOR_LONG 140 +#define ASN1_R_INVALID_BIT_STRING_BITS_LEFT 141 +#define ASN1_R_INVALID_BMPSTRING_LENGTH 142 +#define ASN1_R_INVALID_DIGIT 143 +#define ASN1_R_INVALID_MODIFIER 144 +#define ASN1_R_INVALID_NUMBER 145 +#define ASN1_R_INVALID_OBJECT_ENCODING 146 +#define ASN1_R_INVALID_SEPARATOR 147 +#define ASN1_R_INVALID_TIME_FORMAT 148 +#define ASN1_R_INVALID_UNIVERSALSTRING_LENGTH 149 +#define ASN1_R_INVALID_UTF8STRING 150 +#define ASN1_R_LIST_ERROR 151 +#define ASN1_R_MISSING_ASN1_EOS 152 +#define ASN1_R_MISSING_EOC 153 +#define ASN1_R_MISSING_SECOND_NUMBER 154 +#define ASN1_R_MISSING_VALUE 155 +#define ASN1_R_MSTRING_NOT_UNIVERSAL 156 +#define ASN1_R_MSTRING_WRONG_TAG 157 +#define ASN1_R_NESTED_ASN1_ERROR 158 +#define ASN1_R_NESTED_ASN1_STRING 159 +#define ASN1_R_NON_HEX_CHARACTERS 160 +#define ASN1_R_NOT_ASCII_FORMAT 161 +#define ASN1_R_NOT_ENOUGH_DATA 162 +#define ASN1_R_NO_MATCHING_CHOICE_TYPE 163 +#define ASN1_R_NULL_IS_WRONG_LENGTH 164 +#define ASN1_R_OBJECT_NOT_ASCII_FORMAT 165 +#define ASN1_R_ODD_NUMBER_OF_CHARS 166 +#define ASN1_R_SECOND_NUMBER_TOO_LARGE 167 +#define ASN1_R_SEQUENCE_LENGTH_MISMATCH 168 +#define ASN1_R_SEQUENCE_NOT_CONSTRUCTED 169 +#define ASN1_R_SEQUENCE_OR_SET_NEEDS_CONFIG 170 +#define ASN1_R_SHORT_LINE 171 +#define ASN1_R_STREAMING_NOT_SUPPORTED 172 +#define ASN1_R_STRING_TOO_LONG 173 +#define ASN1_R_STRING_TOO_SHORT 174 +#define ASN1_R_TAG_VALUE_TOO_HIGH 175 +#define ASN1_R_TIME_NOT_ASCII_FORMAT 176 +#define ASN1_R_TOO_LONG 177 +#define ASN1_R_TYPE_NOT_CONSTRUCTED 178 +#define ASN1_R_TYPE_NOT_PRIMITIVE 179 +#define ASN1_R_UNEXPECTED_EOC 180 +#define ASN1_R_UNIVERSALSTRING_IS_WRONG_LENGTH 181 +#define ASN1_R_UNKNOWN_FORMAT 182 +#define ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM 183 +#define ASN1_R_UNKNOWN_SIGNATURE_ALGORITHM 184 +#define ASN1_R_UNKNOWN_TAG 185 +#define ASN1_R_UNSUPPORTED_ANY_DEFINED_BY_TYPE 186 +#define ASN1_R_UNSUPPORTED_PUBLIC_KEY_TYPE 187 +#define ASN1_R_UNSUPPORTED_TYPE 188 +#define ASN1_R_WRONG_PUBLIC_KEY_TYPE 189 +#define ASN1_R_WRONG_TAG 190 +#define ASN1_R_WRONG_TYPE 191 #endif diff --git a/Sources/BoringSSL/include/openssl/asn1_mac.h b/Sources/BoringSSL/include/openssl/asn1_mac.h index f319beec0..666e5696c 100644 --- a/Sources/BoringSSL/include/openssl/asn1_mac.h +++ b/Sources/BoringSSL/include/openssl/asn1_mac.h @@ -1,75 +1,18 @@ -/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) - * All rights reserved. +/* Copyright (c) 2016, Google Inc. * - * This package is an SSL implementation written - * by Eric Young (eay@cryptsoft.com). - * The implementation was written so as to conform with Netscapes SSL. - * - * This library is free for commercial and non-commercial use as long as - * the following conditions are aheared to. The following conditions - * apply to all code found in this distribution, be it the RC4, RSA, - * lhash, DES, etc., code; not just the SSL code. The SSL documentation - * included with this distribution is covered by the same copyright terms - * except that the holder is Tim Hudson (tjh@cryptsoft.com). - * - * Copyright remains Eric Young's, and as such any Copyright notices in - * the code are not to be removed. - * If this package is used in a product, Eric Young should be given attribution - * as the author of the parts of the library used. - * This can be in the form of a textual message at program startup or - * in documentation (online or textual) provided with the package. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * "This product includes cryptographic software written by - * Eric Young (eay@cryptsoft.com)" - * The word 'cryptographic' can be left out if the rouines from the library - * being used are not cryptographic related :-). - * 4. If you include any Windows specific code (or a derivative thereof) from - * the apps directory (application code) you must include an acknowledgement: - * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" - * - * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * The licence and distribution terms for any publically available version or - * derivative of this code cannot be changed. i.e. this code cannot simply be - * copied and put under another distribution licence - * [including the GNU Public Licence.] - */ - -#ifndef HEADER_ASN1_MAC_H -#define HEADER_ASN1_MAC_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - - -OPENSSL_EXPORT int asn1_GetSequence(ASN1_const_CTX *c, long *length); - - -#ifdef __cplusplus -} -#endif - -#endif + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +/* This header is provided in order to make compiling against code that expects + OpenSSL easier. */ + +#include "asn1.h" diff --git a/Sources/BoringSSL/include/openssl/asn1t.h b/Sources/BoringSSL/include/openssl/asn1t.h index b43c33281..10d32c436 100644 --- a/Sources/BoringSSL/include/openssl/asn1t.h +++ b/Sources/BoringSSL/include/openssl/asn1t.h @@ -631,6 +631,7 @@ typedef struct ASN1_EXTERN_FUNCS_st { ASN1_ex_free_func *asn1_ex_clear; ASN1_ex_d2i *asn1_ex_d2i; ASN1_ex_i2d *asn1_ex_i2d; + /* asn1_ex_print is unused. */ ASN1_ex_print_func *asn1_ex_print; } ASN1_EXTERN_FUNCS; @@ -835,17 +836,6 @@ typedef struct ASN1_STREAM_ARG_st { return ASN1_item_dup(ASN1_ITEM_rptr(stname), x); \ } -#define IMPLEMENT_ASN1_PRINT_FUNCTION(stname) \ - IMPLEMENT_ASN1_PRINT_FUNCTION_fname(stname, stname, stname) - -#define IMPLEMENT_ASN1_PRINT_FUNCTION_fname(stname, itname, fname) \ - int fname##_print_ctx(BIO *out, stname *x, int indent, \ - const ASN1_PCTX *pctx) \ - { \ - return ASN1_item_print(out, (ASN1_VALUE *)x, indent, \ - ASN1_ITEM_rptr(itname), pctx); \ - } - #define IMPLEMENT_ASN1_FUNCTIONS_const(name) \ IMPLEMENT_ASN1_FUNCTIONS_const_fname(name, name, name) diff --git a/Sources/BoringSSL/include/openssl/base.h b/Sources/BoringSSL/include/openssl/base.h index 473489cdc..ceb693df6 100644 --- a/Sources/BoringSSL/include/openssl/base.h +++ b/Sources/BoringSSL/include/openssl/base.h @@ -55,13 +55,23 @@ #define OPENSSL_NO_ASM + /* This file should be the first included by all BoringSSL headers. */ #include #include #include -#include +#if defined(__MINGW32__) +/* stdio.h is needed on MinGW for __MINGW_PRINTF_FORMAT. */ +#include +#endif + +#include + +#if defined(BORINGSSL_PREFIX) +#include +#endif #if defined(__cplusplus) extern "C" { @@ -80,8 +90,9 @@ extern "C" { #elif defined(__arm) || defined(__arm__) || defined(_M_ARM) #define OPENSSL_32_BIT #define OPENSSL_ARM -#elif defined(__PPC64__) || defined(__powerpc64__) +#elif (defined(__PPC64__) || defined(__powerpc64__)) && defined(_LITTLE_ENDIAN) #define OPENSSL_64_BIT +#define OPENSSL_PPC64LE #elif defined(__mips__) && !defined(__LP64__) #define OPENSSL_32_BIT #define OPENSSL_MIPS @@ -91,6 +102,8 @@ extern "C" { #elif defined(__pnacl__) #define OPENSSL_32_BIT #define OPENSSL_PNACL +#elif defined(__myriad2__) +#define OPENSSL_32_BIT #else #error "Unknown target CPU" #endif @@ -103,6 +116,14 @@ extern "C" { #define OPENSSL_WINDOWS #endif +#if defined(__linux__) +#define OPENSSL_LINUX +#endif + +#if defined(__Fuchsia__) +#define OPENSSL_FUCHSIA +#endif + #if defined(TRUSTY) #define OPENSSL_TRUSTY #define OPENSSL_NO_THREADS @@ -110,9 +131,20 @@ extern "C" { #define OPENSSL_IS_BORINGSSL #define BORINGSSL_201512 -#define OPENSSL_VERSION_NUMBER 0x10002000 +#define BORINGSSL_201603 +#define OPENSSL_VERSION_NUMBER 0x100020af #define SSLEAY_VERSION_NUMBER OPENSSL_VERSION_NUMBER +/* BORINGSSL_API_VERSION is a positive integer that increments as BoringSSL + * changes over time. The value itself is not meaningful. It will be incremented + * whenever is convenient to coordinate an API change with consumers. This will + * not denote any special point in development. + * + * A consumer may use this symbol in the preprocessor to temporarily build + * against multiple revisions of BoringSSL at the same time. It is not + * recommended to do so for longer than is necessary. */ +#define BORINGSSL_API_VERSION 2 + #if defined(BORINGSSL_SHARED_LIBRARY) #if defined(OPENSSL_WINDOWS) @@ -141,12 +173,32 @@ extern "C" { #if defined(__GNUC__) +/* MinGW has two different printf implementations. Ensure the format macro + * matches the selected implementation. See + * https://sourceforge.net/p/mingw-w64/wiki2/gnu%20printf/. */ +#if defined(__MINGW_PRINTF_FORMAT) #define OPENSSL_PRINTF_FORMAT_FUNC(string_index, first_to_check) \ - __attribute__((format(printf, string_index, first_to_check))) + __attribute__( \ + (__format__(__MINGW_PRINTF_FORMAT, string_index, first_to_check))) +#else +#define OPENSSL_PRINTF_FORMAT_FUNC(string_index, first_to_check) \ + __attribute__((__format__(__printf__, string_index, first_to_check))) +#endif #else #define OPENSSL_PRINTF_FORMAT_FUNC(string_index, first_to_check) #endif +/* OPENSSL_MSVC_PRAGMA emits a pragma on MSVC and nothing on other compilers. */ +#if defined(_MSC_VER) +#define OPENSSL_MSVC_PRAGMA(arg) __pragma(arg) +#else +#define OPENSSL_MSVC_PRAGMA(arg) +#endif + +#if defined(BORINGSSL_UNSAFE_FUZZER_MODE) && \ + !defined(BORINGSSL_UNSAFE_DETERMINISTIC_MODE) +#define BORINGSSL_UNSAFE_DETERMINISTIC_MODE +#endif /* CRYPTO_THREADID is a dummy value. */ typedef int CRYPTO_THREADID; @@ -172,21 +224,23 @@ typedef struct asn1_string_st ASN1_UNIVERSALSTRING; typedef struct asn1_string_st ASN1_UTCTIME; typedef struct asn1_string_st ASN1_UTF8STRING; typedef struct asn1_string_st ASN1_VISIBLESTRING; +typedef struct asn1_type_st ASN1_TYPE; typedef struct AUTHORITY_KEYID_st AUTHORITY_KEYID; +typedef struct BASIC_CONSTRAINTS_st BASIC_CONSTRAINTS; typedef struct DIST_POINT_st DIST_POINT; +typedef struct DSA_SIG_st DSA_SIG; typedef struct ISSUING_DIST_POINT_st ISSUING_DIST_POINT; typedef struct NAME_CONSTRAINTS_st NAME_CONSTRAINTS; typedef struct Netscape_certificate_sequence NETSCAPE_CERT_SEQUENCE; typedef struct Netscape_spkac_st NETSCAPE_SPKAC; typedef struct Netscape_spki_st NETSCAPE_SPKI; -typedef struct PBE2PARAM_st PBE2PARAM; -typedef struct PBEPARAM_st PBEPARAM; -typedef struct PBKDF2PARAM_st PBKDF2PARAM; +typedef struct RIPEMD160state_st RIPEMD160_CTX; typedef struct X509_POLICY_CACHE_st X509_POLICY_CACHE; typedef struct X509_POLICY_LEVEL_st X509_POLICY_LEVEL; typedef struct X509_POLICY_NODE_st X509_POLICY_NODE; typedef struct X509_POLICY_TREE_st X509_POLICY_TREE; +typedef struct X509_VERIFY_PARAM_st X509_VERIFY_PARAM; typedef struct X509_algor_st X509_ALGOR; typedef struct X509_crl_info_st X509_CRL_INFO; typedef struct X509_crl_st X509_CRL; @@ -212,9 +266,13 @@ typedef struct cbs_st CBS; typedef struct cmac_ctx_st CMAC_CTX; typedef struct conf_st CONF; typedef struct conf_value_st CONF_VALUE; +typedef struct crypto_buffer_pool_st CRYPTO_BUFFER_POOL; +typedef struct crypto_buffer_st CRYPTO_BUFFER; typedef struct dh_st DH; typedef struct dsa_st DSA; +typedef struct ec_group_st EC_GROUP; typedef struct ec_key_st EC_KEY; +typedef struct ec_point_st EC_POINT; typedef struct ecdsa_method_st ECDSA_METHOD; typedef struct ecdsa_sig_st ECDSA_SIG; typedef struct engine_st ENGINE; @@ -241,6 +299,7 @@ typedef struct rsa_st RSA; typedef struct sha256_state_st SHA256_CTX; typedef struct sha512_state_st SHA512_CTX; typedef struct sha_state_st SHA_CTX; +typedef struct spake2_ctx_st SPAKE2_CTX; typedef struct srtp_protection_profile_st SRTP_PROTECTION_PROFILE; typedef struct ssl_cipher_st SSL_CIPHER; typedef struct ssl_ctx_st SSL_CTX; @@ -255,6 +314,7 @@ typedef struct x509_cert_aux_st X509_CERT_AUX; typedef struct x509_cert_pair_st X509_CERT_PAIR; typedef struct x509_cinf_st X509_CINF; typedef struct x509_crl_method_st X509_CRL_METHOD; +typedef struct x509_lookup_st X509_LOOKUP; typedef struct x509_revoked_st X509_REVOKED; typedef struct x509_st X509; typedef struct x509_store_ctx_st X509_STORE_CTX; @@ -266,6 +326,116 @@ typedef void *OPENSSL_BLOCK; #if defined(__cplusplus) } /* extern C */ + +// MSVC doesn't set __cplusplus to 201103 to indicate C++11 support (see +// https://connect.microsoft.com/VisualStudio/feedback/details/763051/a-value-of-predefined-macro-cplusplus-is-still-199711l) +// so MSVC is just assumed to support C++11. +#if !defined(BORINGSSL_NO_CXX) && __cplusplus < 201103L && !defined(_MSC_VER) +#define BORINGSSL_NO_CXX +#endif + +#if !defined(BORINGSSL_NO_CXX) +extern "C++" { + +#include + +// STLPort, used by some Android consumers, not have std::unique_ptr. +#if defined(_STLPORT_VERSION) +#define BORINGSSL_NO_CXX +#endif + +} // extern C++ +#endif // !BORINGSSL_NO_CXX + +#if defined(BORINGSSL_NO_CXX) + +#define BORINGSSL_MAKE_DELETER(type, deleter) +#define BORINGSSL_MAKE_STACK_DELETER(type, deleter) + +#else + +extern "C++" { + +#include + +namespace bssl { + +namespace internal { + +template +struct DeleterImpl {}; + +template +struct Deleter { + void operator()(T *ptr) { + // Rather than specialize Deleter for each type, we specialize + // DeleterImpl. This allows bssl::UniquePtr to be used while only + // including base.h as long as the destructor is not emitted. This matches + // std::unique_ptr's behavior on forward-declared types. + // + // DeleterImpl itself is specialized in the corresponding module's header + // and must be included to release an object. If not included, the compiler + // will error that DeleterImpl does not have a method Free. + DeleterImpl::Free(ptr); + } +}; + +template +class StackAllocated { + public: + StackAllocated() { init(&ctx_); } + ~StackAllocated() { cleanup(&ctx_); } + + StackAllocated(const StackAllocated &) = delete; + T& operator=(const StackAllocated &) = delete; + + T *get() { return &ctx_; } + const T *get() const { return &ctx_; } + + void Reset() { + cleanup(&ctx_); + init(&ctx_); + } + + private: + T ctx_; +}; + +} // namespace internal + +#define BORINGSSL_MAKE_DELETER(type, deleter) \ + namespace internal { \ + template <> \ + struct DeleterImpl { \ + static void Free(type *ptr) { deleter(ptr); } \ + }; \ + } + +// This makes a unique_ptr to STACK_OF(type) that owns all elements on the +// stack, i.e. it uses sk_pop_free() to clean up. +#define BORINGSSL_MAKE_STACK_DELETER(type, deleter) \ + namespace internal { \ + template <> \ + struct DeleterImpl { \ + static void Free(STACK_OF(type) *ptr) { \ + sk_##type##_pop_free(ptr, deleter); \ + } \ + }; \ + } + +// Holds ownership of heap-allocated BoringSSL structures. Sample usage: +// bssl::UniquePtr rsa(RSA_new()); +// bssl::UniquePtr bio(BIO_new(BIO_s_mem())); +template +using UniquePtr = std::unique_ptr>; + +} // namespace bssl + +} /* extern C++ */ + +#endif // !BORINGSSL_NO_CXX + #endif #endif /* OPENSSL_HEADER_BASE_H */ diff --git a/Sources/BoringSSL/include/openssl/base64.h b/Sources/BoringSSL/include/openssl/base64.h index f28e7ddb5..4bf3888c0 100644 --- a/Sources/BoringSSL/include/openssl/base64.h +++ b/Sources/BoringSSL/include/openssl/base64.h @@ -87,15 +87,16 @@ OPENSSL_EXPORT int EVP_EncodedLength(size_t *out_len, size_t len); /* Decoding */ -/* EVP_DecodedLength sets |*out_len| to the maximum number of bytes - * that will be needed to call |EVP_DecodeBase64| on an input of - * length |len|. */ +/* EVP_DecodedLength sets |*out_len| to the maximum number of bytes that will + * be needed to call |EVP_DecodeBase64| on an input of length |len|. It returns + * one on success or zero if |len| is not a valid length for a base64-encoded + * string. */ OPENSSL_EXPORT int EVP_DecodedLength(size_t *out_len, size_t len); /* EVP_DecodeBase64 decodes |in_len| bytes from base64 and writes * |*out_len| bytes to |out|. |max_out| is the size of the output * buffer. If it is not enough for the maximum output size, the - * operation fails. */ + * operation fails. It returns one on success or zero on error. */ OPENSSL_EXPORT int EVP_DecodeBase64(uint8_t *out, size_t *out_len, size_t max_out, const uint8_t *in, size_t in_len); @@ -105,9 +106,7 @@ OPENSSL_EXPORT int EVP_DecodeBase64(uint8_t *out, size_t *out_len, * * OpenSSL provides a streaming base64 implementation, however its behavior is * very specific to PEM. It is also very lenient of invalid input. Use of any of - * these functions is thus deprecated. - * - * TODO(davidben): Import upstream's rewrite that rejects the invalid input. */ + * these functions is thus deprecated. */ /* EVP_EncodeInit initialises |*ctx|, which is typically stack * allocated, for an encoding operation. @@ -159,21 +158,25 @@ OPENSSL_EXPORT int EVP_DecodeFinal(EVP_ENCODE_CTX *ctx, uint8_t *out, * * WARNING: EVP_DecodeBlock's return value does not take padding into * account. It also strips leading whitespace and trailing - * whitespace. */ + * whitespace and minuses. */ OPENSSL_EXPORT int EVP_DecodeBlock(uint8_t *dst, const uint8_t *src, size_t src_len); struct evp_encode_ctx_st { - unsigned num; /* number saved in a partial encode/decode */ - unsigned length; /* The length is either the output line length - * (in input bytes) or the shortest input line - * length that is ok. Once decoding begins, - * the length is adjusted up each time a longer - * line is decoded */ - uint8_t enc_data[80]; /* data to encode */ - unsigned line_num; /* number read on current line */ - int expect_nl; + /* data_used indicates the number of bytes of |data| that are valid. When + * encoding, |data| will be filled and encoded as a lump. When decoding, only + * the first four bytes of |data| will be used. */ + unsigned data_used; + uint8_t data[48]; + + /* eof_seen indicates that the end of the base64 data has been seen when + * decoding. Only whitespace can follow. */ + char eof_seen; + + /* error_encountered indicates that invalid base64 data was found. This will + * cause all future calls to fail. */ + char error_encountered; }; diff --git a/Sources/BoringSSL/include/openssl/bio.h b/Sources/BoringSSL/include/openssl/bio.h index 6ca357518..6ba1421dd 100644 --- a/Sources/BoringSSL/include/openssl/bio.h +++ b/Sources/BoringSSL/include/openssl/bio.h @@ -61,6 +61,7 @@ #include /* For FILE */ +#include #include /* for ERR_print_errors_fp */ #include #include @@ -95,8 +96,8 @@ OPENSSL_EXPORT int BIO_free(BIO *bio); * TODO(fork): remove. */ OPENSSL_EXPORT void BIO_vfree(BIO *bio); -/* BIO_up_ref increments the reference count of |bio| and returns it. */ -OPENSSL_EXPORT BIO *BIO_up_ref(BIO *bio); +/* BIO_up_ref increments the reference count of |bio| and returns one. */ +OPENSSL_EXPORT int BIO_up_ref(BIO *bio); /* Basic I/O. */ @@ -151,6 +152,11 @@ OPENSSL_EXPORT long BIO_int_ctrl(BIO *bp, int cmd, long larg, int iarg); * otherwise. */ OPENSSL_EXPORT int BIO_reset(BIO *bio); +/* BIO_eof returns non-zero when |bio| has reached end-of-file. The precise + * meaning of which depends on the concrete type of |bio|. Note that in the + * case of BIO_pair this always returns non-zero. */ +OPENSSL_EXPORT int BIO_eof(BIO *bio); + /* BIO_set_flags ORs |flags| with |bio->flags|. */ OPENSSL_EXPORT void BIO_set_flags(BIO *bio, int flags); @@ -178,22 +184,12 @@ OPENSSL_EXPORT int BIO_should_retry(const BIO *bio); * |BIO_get_retry_reason|. */ OPENSSL_EXPORT int BIO_should_io_special(const BIO *bio); -/* BIO_RR_SSL_X509_LOOKUP indicates that an SSL BIO blocked because the SSL - * library returned with SSL_ERROR_WANT_X509_LOOKUP. - * - * TODO(fork): remove. */ -#define BIO_RR_SSL_X509_LOOKUP 0x01 - /* BIO_RR_CONNECT indicates that a connect would have blocked */ #define BIO_RR_CONNECT 0x02 /* BIO_RR_ACCEPT indicates that an accept would have blocked */ #define BIO_RR_ACCEPT 0x03 -/* BIO_RR_SSL_CHANNEL_ID_LOOKUP indicates that the ChannelID code cannot find - * a private key for a TLS connection. */ -#define BIO_RR_SSL_CHANNEL_ID_LOOKUP 0x04 - /* BIO_get_retry_reason returns the special I/O operation that needs to be * retried. The return value is one of the |BIO_RR_*| values. */ OPENSSL_EXPORT int BIO_get_retry_reason(const BIO *bio); @@ -230,7 +226,7 @@ typedef long (*bio_info_cb)(BIO *bio, int event, const char *parg, int cmd, long larg, long return_value); /* BIO_callback_ctrl allows the callback function to be manipulated. The |cmd| - * arg will generally be |BIO_CTRL_SET_CALLBACK| but arbitary command values + * arg will generally be |BIO_CTRL_SET_CALLBACK| but arbitrary command values * can be interpreted by the |BIO|. */ OPENSSL_EXPORT long BIO_callback_ctrl(BIO *bio, int cmd, bio_info_cb fp); @@ -327,9 +323,9 @@ OPENSSL_EXPORT int BIO_indent(BIO *bio, unsigned indent, unsigned max_indent); OPENSSL_EXPORT int BIO_hexdump(BIO *bio, const uint8_t *data, size_t len, unsigned indent); -/* BIO_print_errors prints the current contents of the error stack to |bio| +/* ERR_print_errors prints the current contents of the error stack to |bio| * using human readable strings where possible. */ -OPENSSL_EXPORT void BIO_print_errors(BIO *bio); +OPENSSL_EXPORT void ERR_print_errors(BIO *bio); /* BIO_read_asn1 reads a single ASN.1 object from |bio|. If successful it sets * |*out| to be an allocated buffer (that should be freed with |OPENSSL_free|), @@ -361,19 +357,17 @@ OPENSSL_EXPORT int BIO_read_asn1(BIO *bio, uint8_t **out, size_t *out_len, * * Memory BIOs support |BIO_gets| and |BIO_puts|. * - * |BIO_eof| is true if no data is in the BIO. - * * |BIO_ctrl_pending| returns the number of bytes currently stored. */ /* BIO_s_mem returns a |BIO_METHOD| that uses a in-memory buffer. */ OPENSSL_EXPORT const BIO_METHOD *BIO_s_mem(void); -/* BIO_new_mem_buf creates BIO that reads and writes from |len| bytes at |buf|. +/* BIO_new_mem_buf creates read-only BIO that reads from |len| bytes at |buf|. * It does not take ownership of |buf|. It returns the BIO or NULL on error. * * If |len| is negative, then |buf| is treated as a NUL-terminated string, but * don't depend on this in new code. */ -OPENSSL_EXPORT BIO *BIO_new_mem_buf(void *buf, int len); +OPENSSL_EXPORT BIO *BIO_new_mem_buf(const void *buf, int len); /* BIO_mem_contents sets |*out_contents| to point to the current contents of * |bio| and |*out_len| to contain the length of that data. It returns one on @@ -419,12 +413,7 @@ OPENSSL_EXPORT int BIO_set_mem_eof_return(BIO *bio, int eof_value); * underlying file descriptor when the BIO is freed. * * |BIO_reset| attempts to seek the file pointer to the start of file using - * |lseek|. - * - * |BIO_seek| sets the file pointer to position |off| from start of file using - * |lseek|. - * - * |BIO_tell| returns the current file position. */ + * |lseek|. */ /* BIO_s_fd returns a |BIO_METHOD| for file descriptor fds. */ OPENSSL_EXPORT const BIO_METHOD *BIO_s_fd(void); @@ -435,12 +424,18 @@ OPENSSL_EXPORT BIO *BIO_new_fd(int fd, int close_flag); /* BIO_set_fd sets the file descriptor of |bio| to |fd|. If |close_flag| is * non-zero then |fd| will be closed when |bio| is. It returns one on success - * or zero on error. */ + * or zero on error. + * + * This function may also be used with socket BIOs (see |BIO_s_socket| and + * |BIO_new_socket|). */ OPENSSL_EXPORT int BIO_set_fd(BIO *bio, int fd, int close_flag); /* BIO_get_fd returns the file descriptor currently in use by |bio| or -1 if * |bio| does not wrap a file descriptor. If there is a file descriptor and - * |out_fd| is not NULL, it also sets |*out_fd| to the file descriptor. */ + * |out_fd| is not NULL, it also sets |*out_fd| to the file descriptor. + * + * This function may also be used with socket BIOs (see |BIO_s_socket| and + * |BIO_new_socket|). */ OPENSSL_EXPORT int BIO_get_fd(BIO *bio, int *out_fd); @@ -453,11 +448,6 @@ OPENSSL_EXPORT int BIO_get_fd(BIO *bio, int *out_fd); * |BIO_reset| attempts to seek the file pointer to the start of file using * |fseek|. * - * |BIO_seek| sets the file pointer to the given position from the start of - * file using |fseek|. - * - * |BIO_eof| calls |feof|. - * * Setting the close flag causes |fclose| to be called on the stream when the * BIO is freed. */ @@ -479,7 +469,7 @@ OPENSSL_EXPORT int BIO_get_fp(BIO *bio, FILE **out_file); /* BIO_set_fp sets the |FILE| for |bio|. If |close_flag| is |BIO_CLOSE| then * |fclose| will be called on |file| when |bio| is closed. It returns one on - * sucess and zero otherwise. */ + * success and zero otherwise. */ OPENSSL_EXPORT int BIO_set_fp(BIO *bio, FILE *file, int close_flag); /* BIO_read_filename opens |filename| for reading and sets the result as the @@ -503,24 +493,17 @@ OPENSSL_EXPORT int BIO_append_filename(BIO *bio, const char *filename); OPENSSL_EXPORT int BIO_rw_filename(BIO *bio, const char *filename); -/* Buffer BIOs. +/* Socket BIOs. * - * Buffer BIOs are a filter-type BIO, i.e. they are designed to be used in a - * chain of BIOs. They provide buffering to reduce the number of operations on - * the underlying BIOs. */ - -OPENSSL_EXPORT const BIO_METHOD *BIO_f_buffer(void); - -/* BIO_set_read_buffer_size sets the size, in bytes, of the read buffer and - * clears it. It returns one on success and zero on failure. */ -OPENSSL_EXPORT int BIO_set_read_buffer_size(BIO *bio, int buffer_size); - -/* BIO_set_write_buffer_size sets the size, in bytes, of the write buffer and - * clears it. It returns one on success and zero on failure. */ -OPENSSL_EXPORT int BIO_set_write_buffer_size(BIO *bio, int buffer_size); - - -/* Socket BIOs. */ + * Socket BIOs behave like file descriptor BIOs but, on Windows systems, wrap + * the system's |recv| and |send| functions instead of |read| and |write|. On + * Windows, file descriptors are provided by C runtime and are not + * interchangeable with sockets. + * + * Socket BIOs may be used with |BIO_set_fd| and |BIO_get_fd|. + * + * TODO(davidben): Add separate APIs and fix the internals to use |SOCKET|s + * around rather than rely on int casts. */ OPENSSL_EXPORT const BIO_METHOD *BIO_s_socket(void); @@ -557,10 +540,18 @@ OPENSSL_EXPORT int BIO_set_conn_hostname(BIO *bio, * will connect to. It returns one on success and zero otherwise. */ OPENSSL_EXPORT int BIO_set_conn_port(BIO *bio, const char *port_str); +/* BIO_set_conn_int_port sets |*port| as the port that |bio| will connect to. + * It returns one on success and zero otherwise. */ +OPENSSL_EXPORT int BIO_set_conn_int_port(BIO *bio, const int *port); + /* BIO_set_nbio sets whether |bio| will use non-blocking I/O operations. It * returns one on success and zero otherwise. */ OPENSSL_EXPORT int BIO_set_nbio(BIO *bio, int on); +/* BIO_do_connect connects |bio| if it has not been connected yet. It returns + * one on success and <= 0 otherwise. */ +OPENSSL_EXPORT int BIO_do_connect(BIO *bio); + /* Datagram BIOs. * @@ -574,8 +565,12 @@ OPENSSL_EXPORT int BIO_set_nbio(BIO *bio, int on); #define BIO_CTRL_DGRAM_MTU_EXCEEDED 43 /* check whether the MTU was exceed in the previous write operation. */ -#define BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT \ - 45 /* Next DTLS handshake timeout to adjust socket timeouts */ +/* BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT sets a read deadline to drive + * retransmits. The |parg| argument to |BIO_ctrl| will be a pointer to a + * |timeval| struct. If the structure is all zeros, it clears the read + * deadline. Otherwise, |BIO_read| must fail with a temporary error + * (e.g. |EAGAIN|) after the deadline. */ +#define BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT 45 #define BIO_CTRL_DGRAM_GET_PEER 46 @@ -594,18 +589,6 @@ OPENSSL_EXPORT int BIO_set_nbio(BIO *bio, int on); OPENSSL_EXPORT int BIO_new_bio_pair(BIO **out1, size_t writebuf1, BIO **out2, size_t writebuf2); -/* BIO_new_bio_pair_external_buf is the same as |BIO_new_bio_pair| with the - * difference that the caller keeps ownership of the write buffers - * |ext_writebuf1_len| and |ext_writebuf2_len|. This is useful when using zero - * copy API for read and write operations, in cases where the buffers need to - * outlive the BIO pairs. It returns one on success and zero on error. */ -OPENSSL_EXPORT int BIO_new_bio_pair_external_buf(BIO** bio1_p, - size_t writebuf1_len, - uint8_t* ext_writebuf1, - BIO** bio2_p, - size_t writebuf2_len, - uint8_t* ext_writebuf2); - /* BIO_ctrl_get_read_request returns the number of bytes that the other side of * |bio| tried (unsuccessfully) to read. */ OPENSSL_EXPORT size_t BIO_ctrl_get_read_request(BIO *bio); @@ -621,63 +604,6 @@ OPENSSL_EXPORT size_t BIO_ctrl_get_write_guarantee(BIO *bio); OPENSSL_EXPORT int BIO_shutdown_wr(BIO *bio); -/* Zero copy versions of BIO_read and BIO_write for BIO pairs. */ - -/* BIO_zero_copy_get_read_buf initiates a zero copy read operation. - * |out_read_buf| is set to the internal read buffer, and |out_buf_offset| is - * set to the current read position of |out_read_buf|. The number of bytes - * available for read from |out_read_buf| + |out_buf_offset| is returned in - * |out_available_bytes|. Note that this function might report fewer bytes - * available than |BIO_pending|, if the internal ring buffer is wrapped. It - * returns one on success. In case of error it returns zero and pushes to the - * error stack. - * - * The zero copy read operation is completed by calling - * |BIO_zero_copy_get_read_buf_done|. Neither |BIO_zero_copy_get_read_buf| nor - * any other I/O read operation may be called while a zero copy read operation - * is active. */ -OPENSSL_EXPORT int BIO_zero_copy_get_read_buf(BIO* bio, - uint8_t** out_read_buf, - size_t* out_buf_offset, - size_t* out_available_bytes); - -/* BIO_zero_copy_get_read_buf_done must be called after reading from a BIO using - * |BIO_zero_copy_get_read_buf| to finish the read operation. The |bytes_read| - * argument is the number of bytes read. - * - * It returns one on success. In case of error it returns zero and pushes to the - * error stack. */ -OPENSSL_EXPORT int BIO_zero_copy_get_read_buf_done(BIO* bio, size_t bytes_read); - -/* BIO_zero_copy_get_write_buf initiates a zero copy write operation. - * |out_write_buf| is set to to the internal write buffer, and |out_buf_offset| - * is set to the current write position of |out_write_buf|. - * The number of bytes available for write from |out_write_buf| + - * |out_buf_offset| is returned in |out_available_bytes|. Note that this - * function might report fewer bytes available than - * |BIO_ctrl_get_write_guarantee|, if the internal buffer is wrapped. It returns - * one on success. In case of error it returns zero and pushes to the error - * stack. - * - * The zero copy write operation is completed by calling - * |BIO_zero_copy_get_write_buf_done|. Neither |BIO_zero_copy_get_write_buf| - * nor any other I/O write operation may be called while a zero copy write - * operation is active. */ -OPENSSL_EXPORT int BIO_zero_copy_get_write_buf(BIO* bio, - uint8_t** out_write_buf, - size_t* out_buf_offset, - size_t* out_available_bytes); - -/* BIO_zero_copy_get_write_buf_done must be called after writing to a BIO using - * |BIO_zero_copy_get_write_buf| to finish the write operation. The - * |bytes_written| argument gives the number of bytes written. - * - * It returns one on success. In case of error it returns zero and pushes to the - * error stack. */ -OPENSSL_EXPORT int BIO_zero_copy_get_write_buf_done(BIO* bio, - size_t bytes_written); - - /* BIO_NOCLOSE and |BIO_CLOSE| can be used as symbolic arguments when a "close * flag" is passed to a BIO function. */ #define BIO_NOCLOSE 0 @@ -701,6 +627,8 @@ OPENSSL_EXPORT int BIO_zero_copy_get_write_buf_done(BIO* bio, #define BIO_CTRL_INFO 3 /* opt - extra tit-bits */ #define BIO_CTRL_SET 4 /* man - set the 'IO' type */ #define BIO_CTRL_GET 5 /* man - get the 'IO' type */ +#define BIO_CTRL_PUSH 6 +#define BIO_CTRL_POP 7 #define BIO_CTRL_GET_CLOSE 8 /* man - set the 'close' on free */ #define BIO_CTRL_SET_CLOSE 9 /* man - set the 'close' on free */ #define BIO_CTRL_PENDING 10 /* opt - is their more data buffered */ @@ -711,18 +639,9 @@ OPENSSL_EXPORT int BIO_zero_copy_get_write_buf_done(BIO* bio, #define BIO_CTRL_GET_CALLBACK 15 /* opt - set callback function */ #define BIO_CTRL_SET_FILENAME 30 /* BIO_s_file special */ -/* These are never used, but exist to allow code to compile more easily. */ -#define BIO_CTRL_DUP 100 -#define BIO_CTRL_PUSH 101 -#define BIO_CTRL_POP 102 - - -/* Android compatibility section. - * - * A previous version of BoringSSL used in Android renamed ERR_print_errors_fp - * to BIO_print_errors_fp. It has subsequently been renamed back to - * ERR_print_errors_fp. */ -#define BIO_print_errors_fp ERR_print_errors_fp +/* BIO_CTRL_DUP is never used, but exists to allow code to compile more + * easily. */ +#define BIO_CTRL_DUP 12 /* Deprecated functions. */ @@ -734,8 +653,10 @@ OPENSSL_EXPORT int BIO_zero_copy_get_write_buf_done(BIO* bio, * on one line. */ OPENSSL_EXPORT const BIO_METHOD *BIO_f_base64(void); -/* ERR_print_errors is an alias for |BIO_print_errors|. */ -OPENSSL_EXPORT void ERR_print_errors(BIO *bio); +OPENSSL_EXPORT void BIO_set_retry_special(BIO *bio); + +/* BIO_set_write_buffer_size returns zero. */ +OPENSSL_EXPORT int BIO_set_write_buffer_size(BIO *bio, int buffer_size); /* Private functions */ @@ -878,6 +799,17 @@ struct bio_st { #if defined(__cplusplus) } /* extern C */ + +extern "C++" { + +namespace bssl { + +BORINGSSL_MAKE_DELETER(BIO, BIO_free) + +} // namespace bssl + +} /* extern C++ */ + #endif #define BIO_R_BAD_FOPEN_MODE 100 diff --git a/Sources/BoringSSL/include/openssl/bn.h b/Sources/BoringSSL/include/openssl/bn.h index 64ec5c964..a57c23a96 100644 --- a/Sources/BoringSSL/include/openssl/bn.h +++ b/Sources/BoringSSL/include/openssl/bn.h @@ -134,7 +134,7 @@ extern "C" { #endif -/* BN provides support for working with arbitary sized integers. For example, +/* BN provides support for working with arbitrary sized integers. For example, * although the largest integer supported by the compiler might be 64 bits, BN * will allow you to work with numbers until you run out of memory. */ @@ -148,15 +148,17 @@ extern "C" { #if defined(OPENSSL_64_BIT) #define BN_ULONG uint64_t #define BN_BITS2 64 -#define BN_DEC_FMT1 "%" PRIu64 -#define BN_DEC_FMT2 "%019" PRIu64 -#define BN_HEX_FMT1 "%" PRIx64 +#define BN_DEC_FMT1 "%" PRIu64 +#define BN_DEC_FMT2 "%019" PRIu64 +#define BN_HEX_FMT1 "%" PRIx64 +#define BN_HEX_FMT2 "%016" PRIx64 #elif defined(OPENSSL_32_BIT) #define BN_ULONG uint32_t #define BN_BITS2 32 -#define BN_DEC_FMT1 "%" PRIu32 -#define BN_DEC_FMT2 "%09" PRIu32 -#define BN_HEX_FMT1 "%" PRIx32 +#define BN_DEC_FMT1 "%" PRIu32 +#define BN_DEC_FMT2 "%09" PRIu32 +#define BN_HEX_FMT1 "%" PRIx32 +#define BN_HEX_FMT2 "%08" PRIx64 #else #error "Must define either OPENSSL_32_BIT or OPENSSL_64_BIT" #endif @@ -192,13 +194,6 @@ OPENSSL_EXPORT void BN_clear(BIGNUM *bn); /* BN_value_one returns a static BIGNUM with value 1. */ OPENSSL_EXPORT const BIGNUM *BN_value_one(void); -/* BN_with_flags initialises a stack allocated |BIGNUM| with pointers to the - * contents of |in| but with |flags| ORed into the flags field. - * - * Note: the two BIGNUMs share state and so |out| should /not/ be passed to - * |BN_free|. */ -OPENSSL_EXPORT void BN_with_flags(BIGNUM *out, const BIGNUM *in, int flags); - /* Basic functions. */ @@ -221,18 +216,16 @@ OPENSSL_EXPORT int BN_one(BIGNUM *bn); * allocation failure. */ OPENSSL_EXPORT int BN_set_word(BIGNUM *bn, BN_ULONG value); +/* BN_set_u64 sets |bn| to |value|. It returns one on success or zero on + * allocation failure. */ +OPENSSL_EXPORT int BN_set_u64(BIGNUM *bn, uint64_t value); + /* BN_set_negative sets the sign of |bn|. */ OPENSSL_EXPORT void BN_set_negative(BIGNUM *bn, int sign); /* BN_is_negative returns one if |bn| is negative and zero otherwise. */ OPENSSL_EXPORT int BN_is_negative(const BIGNUM *bn); -/* BN_get_flags returns |bn->flags| & |flags|. */ -OPENSSL_EXPORT int BN_get_flags(const BIGNUM *bn, int flags); - -/* BN_set_flags sets |flags| on |bn|. */ -OPENSSL_EXPORT void BN_set_flags(BIGNUM *bn, int flags); - /* Conversion functions. */ @@ -247,6 +240,18 @@ OPENSSL_EXPORT BIGNUM *BN_bin2bn(const uint8_t *in, size_t len, BIGNUM *ret); * number of bytes written. */ OPENSSL_EXPORT size_t BN_bn2bin(const BIGNUM *in, uint8_t *out); +/* BN_le2bn sets |*ret| to the value of |len| bytes from |in|, interpreted as + * a little-endian number, and returns |ret|. If |ret| is NULL then a fresh + * |BIGNUM| is allocated and returned. It returns NULL on allocation + * failure. */ +OPENSSL_EXPORT BIGNUM *BN_le2bn(const uint8_t *in, size_t len, BIGNUM *ret); + +/* BN_bn2le_padded serialises the absolute value of |in| to |out| as a + * little-endian integer, which must have |len| of space available, padding + * out the remainder of out with zeros. If |len| is smaller than |BN_num_bytes|, + * the function fails and returns 0. Otherwise, it returns 1. */ +OPENSSL_EXPORT int BN_bn2le_padded(uint8_t *out, size_t len, const BIGNUM *in); + /* BN_bn2bin_padded serialises the absolute value of |in| to |out| as a * big-endian integer. The integer is padded with leading zeros up to size * |len|. If |len| is smaller than |BN_num_bytes|, the function fails and @@ -300,6 +305,11 @@ OPENSSL_EXPORT int BN_print_fp(FILE *fp, const BIGNUM *a); * will be returned. */ OPENSSL_EXPORT BN_ULONG BN_get_word(const BIGNUM *bn); +/* BN_get_u64 sets |*out| to the absolute value of |bn| as a |uint64_t| and + * returns one. If |bn| is too large to be represented as a |uint64_t|, it + * returns zero. */ +OPENSSL_EXPORT int BN_get_u64(const BIGNUM *bn, uint64_t *out); + /* ASN.1 functions. */ @@ -323,11 +333,11 @@ OPENSSL_EXPORT int BN_marshal_asn1(CBB *cbb, const BIGNUM *bn); * what you want before turning to these. */ /* bn_correct_top decrements |bn->top| until |bn->d[top-1]| is non-zero or - * until |top| is zero. */ + * until |top| is zero. If |bn| is zero, |bn->neg| is set to zero. */ OPENSSL_EXPORT void bn_correct_top(BIGNUM *bn); /* bn_wexpand ensures that |bn| has at least |words| works of space without - * altering its value. It returns one on success or zero on allocation + * altering its value. It returns |bn| on success or NULL on allocation * failure. */ OPENSSL_EXPORT BIGNUM *bn_wexpand(BIGNUM *bn, size_t words); @@ -335,7 +345,7 @@ OPENSSL_EXPORT BIGNUM *bn_wexpand(BIGNUM *bn, size_t words); /* BIGNUM pools. * * Certain BIGNUM operations need to use many temporary variables and - * allocating and freeing them can be quite slow. Thus such opertions typically + * allocating and freeing them can be quite slow. Thus such operations typically * take a |BN_CTX| parameter, which contains a pool of |BIGNUMs|. The |ctx| * argument to a public function may be NULL, in which case a local |BN_CTX| * will be created just for the lifetime of that call. @@ -383,12 +393,12 @@ OPENSSL_EXPORT int BN_uadd(BIGNUM *r, const BIGNUM *a, const BIGNUM *b); /* BN_add_word adds |w| to |a|. It returns one on success and zero otherwise. */ OPENSSL_EXPORT int BN_add_word(BIGNUM *a, BN_ULONG w); -/* BN_sub sets |r| = |a| - |b|, where |r| must be a distinct pointer from |a| - * and |b|. It returns one on success and zero on allocation failure. */ +/* BN_sub sets |r| = |a| - |b|, where |r| may be the same pointer as either |a| + * or |b|. It returns one on success and zero on allocation failure. */ OPENSSL_EXPORT int BN_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b); /* BN_usub sets |r| = |a| - |b|, where |a| and |b| are non-negative integers, - * |b| < |a| and |r| must be a distinct pointer from |a| and |b|. It returns + * |b| < |a| and |r| may be the same pointer as either |a| or |b|. It returns * one on success and zero on allocation failure. */ OPENSSL_EXPORT int BN_usub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b); @@ -436,11 +446,20 @@ OPENSSL_EXPORT int BN_sqrt(BIGNUM *out_sqrt, const BIGNUM *in, BN_CTX *ctx); * less than, equal to or greater than |b|, respectively. */ OPENSSL_EXPORT int BN_cmp(const BIGNUM *a, const BIGNUM *b); +/* BN_cmp_word is like |BN_cmp| except it takes its second argument as a + * |BN_ULONG| instead of a |BIGNUM|. */ +OPENSSL_EXPORT int BN_cmp_word(const BIGNUM *a, BN_ULONG b); + /* BN_ucmp returns a value less than, equal to or greater than zero if the * absolute value of |a| is less than, equal to or greater than the absolute * value of |b|, respectively. */ OPENSSL_EXPORT int BN_ucmp(const BIGNUM *a, const BIGNUM *b); +/* BN_equal_consttime returns one if |a| is equal to |b|, and zero otherwise. + * It takes an amount of time dependent on the sizes of |a| and |b|, but + * independent of the contents (including the signs) of |a| and |b|. */ +OPENSSL_EXPORT int BN_equal_consttime(const BIGNUM *a, const BIGNUM *b); + /* BN_abs_is_word returns one if the absolute value of |bn| equals |w| and zero * otherwise. */ OPENSSL_EXPORT int BN_abs_is_word(const BIGNUM *bn, BN_ULONG w); @@ -457,6 +476,8 @@ OPENSSL_EXPORT int BN_is_word(const BIGNUM *bn, BN_ULONG w); /* BN_is_odd returns one if |bn| is odd and zero otherwise. */ OPENSSL_EXPORT int BN_is_odd(const BIGNUM *bn); +/* BN_is_pow2 returns 1 if |a| is a power of two, and 0 otherwise. */ +OPENSSL_EXPORT int BN_is_pow2(const BIGNUM *a); /* Bitwise operations. */ @@ -497,9 +518,17 @@ OPENSSL_EXPORT int BN_mask_bits(BIGNUM *a, int n); /* Modulo arithmetic. */ -/* BN_mod_word returns |a| mod |w|. */ +/* BN_mod_word returns |a| mod |w| or (BN_ULONG)-1 on error. */ OPENSSL_EXPORT BN_ULONG BN_mod_word(const BIGNUM *a, BN_ULONG w); +/* BN_mod_pow2 sets |r| = |a| mod 2^|e|. It returns 1 on success and + * 0 on error. */ +OPENSSL_EXPORT int BN_mod_pow2(BIGNUM *r, const BIGNUM *a, size_t e); + +/* BN_nnmod_pow2 sets |r| = |a| mod 2^|e| where |r| is always positive. + * It returns 1 on success and 0 on error. */ +OPENSSL_EXPORT int BN_nnmod_pow2(BIGNUM *r, const BIGNUM *a, size_t e); + /* BN_mod is a helper macro that calls |BN_div| and discards the quotient. */ #define BN_mod(rem, numerator, divisor, ctx) \ BN_div(NULL, (rem), (numerator), (divisor), (ctx)) @@ -560,31 +589,52 @@ OPENSSL_EXPORT int BN_mod_lshift1(BIGNUM *r, const BIGNUM *a, const BIGNUM *m, OPENSSL_EXPORT int BN_mod_lshift1_quick(BIGNUM *r, const BIGNUM *a, const BIGNUM *m); -/* BN_mod_sqrt returns a |BIGNUM|, r, such that r^2 == a (mod p). */ +/* BN_mod_sqrt returns a newly-allocated |BIGNUM|, r, such that + * r^2 == a (mod p). |p| must be a prime. It returns NULL on error or if |a| is + * not a square mod |p|. In the latter case, it will add |BN_R_NOT_A_SQUARE| to + * the error queue. */ OPENSSL_EXPORT BIGNUM *BN_mod_sqrt(BIGNUM *in, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx); /* Random and prime number generation. */ -/* BN_rand sets |rnd| to a random number of length |bits|. If |top| is zero, the - * most-significant bit, if any, will be set. If |top| is one, the two most - * significant bits, if any, will be set. +/* The following are values for the |top| parameter of |BN_rand|. */ +#define BN_RAND_TOP_ANY (-1) +#define BN_RAND_TOP_ONE 0 +#define BN_RAND_TOP_TWO 1 + +/* The following are values for the |bottom| parameter of |BN_rand|. */ +#define BN_RAND_BOTTOM_ANY 0 +#define BN_RAND_BOTTOM_ODD 1 + +/* BN_rand sets |rnd| to a random number of length |bits|. It returns one on + * success and zero otherwise. * - * If |top| is -1 then no extra action will be taken and |BN_num_bits(rnd)| may - * not equal |bits| if the most significant bits randomly ended up as zeros. + * |top| must be one of the |BN_RAND_TOP_*| values. If |BN_RAND_TOP_ONE|, the + * most-significant bit, if any, will be set. If |BN_RAND_TOP_TWO|, the two + * most significant bits, if any, will be set. If |BN_RAND_TOP_ANY|, no extra + * action will be taken and |BN_num_bits(rnd)| may not equal |bits| if the most + * significant bits randomly ended up as zeros. * - * If |bottom| is non-zero, the least-significant bit, if any, will be set. The - * function returns one on success or zero otherwise. */ + * |bottom| must be one of the |BN_RAND_BOTTOM_*| values. If + * |BN_RAND_BOTTOM_ODD|, the least-significant bit, if any, will be set. If + * |BN_RAND_BOTTOM_ANY|, no extra action will be taken. */ OPENSSL_EXPORT int BN_rand(BIGNUM *rnd, int bits, int top, int bottom); /* BN_pseudo_rand is an alias for |BN_rand|. */ OPENSSL_EXPORT int BN_pseudo_rand(BIGNUM *rnd, int bits, int top, int bottom); -/* BN_rand_range sets |rnd| to a random value [0..range). It returns one on - * success and zero otherwise. */ +/* BN_rand_range is equivalent to |BN_rand_range_ex| with |min_inclusive| set + * to zero and |max_exclusive| set to |range|. */ OPENSSL_EXPORT int BN_rand_range(BIGNUM *rnd, const BIGNUM *range); +/* BN_rand_range_ex sets |rnd| to a random value in + * [min_inclusive..max_exclusive). It returns one on success and zero + * otherwise. */ +OPENSSL_EXPORT int BN_rand_range_ex(BIGNUM *r, BN_ULONG min_inclusive, + const BIGNUM *max_exclusive); + /* BN_pseudo_rand_range is an alias for BN_rand_range. */ OPENSSL_EXPORT int BN_pseudo_rand_range(BIGNUM *rnd, const BIGNUM *range); @@ -604,7 +654,7 @@ OPENSSL_EXPORT int BN_generate_dsa_nonce(BIGNUM *out, const BIGNUM *range, * |BN_GENCB| structure. * * The callback receives the address of that |BN_GENCB| structure as its last - * argument and the user is free to put an arbitary pointer in |arg|. The other + * argument and the user is free to put an arbitrary pointer in |arg|. The other * arguments are set as follows: * event=BN_GENCB_GENERATED, n=i: after generating the i'th possible prime * number. @@ -706,20 +756,38 @@ OPENSSL_EXPORT int BN_is_prime_ex(const BIGNUM *candidate, int checks, OPENSSL_EXPORT int BN_gcd(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx); -/* BN_mod_inverse sets |out| equal to |a|^-1, mod |n|. If either of |a| or |n| - * have |BN_FLG_CONSTTIME| set then the operation is performed in constant - * time. If |out| is NULL, a fresh BIGNUM is allocated. It returns the result - * or NULL on error. */ +/* BN_mod_inverse sets |out| equal to |a|^-1, mod |n|. If |out| is NULL, a + * fresh BIGNUM is allocated. It returns the result or NULL on error. + * + * If |n| is even then the operation is performed using an algorithm that avoids + * some branches but which isn't constant-time. This function shouldn't be used + * for secret values; use |BN_mod_inverse_blinded| instead. Or, if |n| is + * guaranteed to be prime, use + * |BN_mod_exp_mont_consttime(out, a, m_minus_2, m, ctx, m_mont)|, taking + * advantage of Fermat's Little Theorem. */ OPENSSL_EXPORT BIGNUM *BN_mod_inverse(BIGNUM *out, const BIGNUM *a, const BIGNUM *n, BN_CTX *ctx); -/* BN_mod_inverse_ex acts like |BN_mod_inverse| except that, when it returns - * zero, it will set |*out_no_inverse| to one if the failure was caused because - * |a| has no inverse mod |n|. Otherwise it will set |*out_no_inverse| to +/* BN_mod_inverse_blinded sets |out| equal to |a|^-1, mod |n|, where |n| is the + * Montgomery modulus for |mont|. |a| must be non-negative and must be less + * than |n|. |n| must be greater than 1. |a| is blinded (masked by a random + * value) to protect it against side-channel attacks. On failure, if the failure + * was caused by |a| having no inverse mod |n| then |*out_no_inverse| will be + * set to one; otherwise it will be set to zero. */ +int BN_mod_inverse_blinded(BIGNUM *out, int *out_no_inverse, const BIGNUM *a, + const BN_MONT_CTX *mont, BN_CTX *ctx); + +/* BN_mod_inverse_odd sets |out| equal to |a|^-1, mod |n|. |a| must be + * non-negative and must be less than |n|. |n| must be odd. This function + * shouldn't be used for secret values; use |BN_mod_inverse_blinded| instead. + * Or, if |n| is guaranteed to be prime, use + * |BN_mod_exp_mont_consttime(out, a, m_minus_2, m, ctx, m_mont)|, taking + * advantage of Fermat's Little Theorem. It returns one on success or zero on + * failure. On failure, if the failure was caused by |a| having no inverse mod + * |n| then |*out_no_inverse| will be set to one; otherwise it will be set to * zero. */ -OPENSSL_EXPORT BIGNUM *BN_mod_inverse_ex(BIGNUM *out, int *out_no_inverse, - const BIGNUM *a, const BIGNUM *n, - BN_CTX *ctx); +int BN_mod_inverse_odd(BIGNUM *out, int *out_no_inverse, const BIGNUM *a, + const BIGNUM *n, BN_CTX *ctx); /* BN_kronecker returns the Kronecker symbol of |a| and |b| (which is -1, 0 or * 1), or -2 on error. */ @@ -749,25 +817,29 @@ OPENSSL_EXPORT int BN_MONT_CTX_set(BN_MONT_CTX *mont, const BIGNUM *mod, /* BN_MONT_CTX_set_locked takes |lock| and checks whether |*pmont| is NULL. If * so, it creates a new |BN_MONT_CTX| and sets the modulus for it to |mod|. It - * then stores it as |*pmont| and returns it, or NULL on error. + * then stores it as |*pmont|. It returns one on success and zero on error. * - * If |*pmont| is already non-NULL then the existing value is returned. */ -BN_MONT_CTX *BN_MONT_CTX_set_locked(BN_MONT_CTX **pmont, CRYPTO_MUTEX *lock, - const BIGNUM *mod, BN_CTX *bn_ctx); + * If |*pmont| is already non-NULL then it does nothing and returns one. */ +int BN_MONT_CTX_set_locked(BN_MONT_CTX **pmont, CRYPTO_MUTEX *lock, + const BIGNUM *mod, BN_CTX *bn_ctx); -/* BN_to_montgomery sets |ret| equal to |a| in the Montgomery domain. It - * returns one on success and zero on error. */ +/* BN_to_montgomery sets |ret| equal to |a| in the Montgomery domain. |a| is + * assumed to be in the range [0, n), where |n| is the Montgomery modulus. It + * returns one on success or zero on error. */ OPENSSL_EXPORT int BN_to_montgomery(BIGNUM *ret, const BIGNUM *a, const BN_MONT_CTX *mont, BN_CTX *ctx); -/* BN_from_montgomery sets |ret| equal to |a| * R^-1, i.e. translates values - * out of the Montgomery domain. It returns one on success or zero on error. */ +/* BN_from_montgomery sets |ret| equal to |a| * R^-1, i.e. translates values out + * of the Montgomery domain. |a| is assumed to be in the range [0, n), where |n| + * is the Montgomery modulus. It returns one on success or zero on error. */ OPENSSL_EXPORT int BN_from_montgomery(BIGNUM *ret, const BIGNUM *a, const BN_MONT_CTX *mont, BN_CTX *ctx); /* BN_mod_mul_montgomery set |r| equal to |a| * |b|, in the Montgomery domain. * Both |a| and |b| must already be in the Montgomery domain (by - * |BN_to_montgomery|). It returns one on success or zero on error. */ + * |BN_to_montgomery|). In particular, |a| and |b| are assumed to be in the + * range [0, n), where |n| is the Montgomery modulus. It returns one on success + * or zero on error. */ OPENSSL_EXPORT int BN_mod_mul_montgomery(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BN_MONT_CTX *mont, BN_CTX *ctx); @@ -782,9 +854,9 @@ OPENSSL_EXPORT int BN_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx); /* BN_mod_exp sets |r| equal to |a|^{|p|} mod |m|. It does so with the best - * algorithm for the values provided and can run in constant time if - * |BN_FLG_CONSTTIME| is set for |p|. It returns one on success or zero - * otherwise. */ + * algorithm for the values provided. It returns one on success or zero + * otherwise. The |BN_mod_exp_mont_consttime| variant must be used if the + * exponent is secret. */ OPENSSL_EXPORT int BN_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx); @@ -797,14 +869,6 @@ OPENSSL_EXPORT int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, BN_CTX *ctx, const BN_MONT_CTX *mont); -OPENSSL_EXPORT int BN_mod_exp_mont_word(BIGNUM *r, BN_ULONG a, const BIGNUM *p, - const BIGNUM *m, BN_CTX *ctx, - const BN_MONT_CTX *mont); -OPENSSL_EXPORT int BN_mod_exp2_mont(BIGNUM *r, const BIGNUM *a1, - const BIGNUM *p1, const BIGNUM *a2, - const BIGNUM *p2, const BIGNUM *m, - BN_CTX *ctx, const BN_MONT_CTX *mont); - /* Deprecated functions */ @@ -824,6 +888,20 @@ OPENSSL_EXPORT size_t BN_bn2mpi(const BIGNUM *in, uint8_t *out); * is updated. */ OPENSSL_EXPORT BIGNUM *BN_mpi2bn(const uint8_t *in, size_t len, BIGNUM *out); +/* BN_mod_exp_mont_word is like |BN_mod_exp_mont| except that the base |a| is + * given as a |BN_ULONG| instead of a |BIGNUM *|. It returns one on success + * or zero otherwise. */ +OPENSSL_EXPORT int BN_mod_exp_mont_word(BIGNUM *r, BN_ULONG a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx, + const BN_MONT_CTX *mont); + +/* BN_mod_exp2_mont calculates (a1^p1) * (a2^p2) mod m. It returns 1 on success + * or zero otherwise. */ +OPENSSL_EXPORT int BN_mod_exp2_mont(BIGNUM *r, const BIGNUM *a1, + const BIGNUM *p1, const BIGNUM *a2, + const BIGNUM *p2, const BIGNUM *m, + BN_CTX *ctx, const BN_MONT_CTX *mont); + /* Private functions */ @@ -846,23 +924,28 @@ OPENSSL_EXPORT unsigned BN_num_bits_word(BN_ULONG l); #define BN_FLG_MALLOCED 0x01 #define BN_FLG_STATIC_DATA 0x02 -/* avoid leaking exponent information through timing, BN_mod_exp_mont() will - * call BN_mod_exp_mont_consttime, BN_div() will call BN_div_no_branch, - * BN_mod_inverse() will call BN_mod_inverse_no_branch. */ -#define BN_FLG_CONSTTIME 0x04 +/* |BN_FLG_CONSTTIME| has been removed and intentionally omitted so code relying + * on it will not compile. Consumers outside BoringSSL should use the + * higher-level cryptographic algorithms exposed by other modules. Consumers + * within the library should call the appropriate timing-sensitive algorithm + * directly. */ -/* Android compatibility section. - * - * These functions are declared, temporarily, for Android because - * wpa_supplicant will take a little time to sync with upstream. Outside of - * Android they'll have no definition. */ +#if defined(__cplusplus) +} /* extern C */ -OPENSSL_EXPORT BIGNUM *get_rfc3526_prime_1536(BIGNUM *bn); +extern "C++" { +namespace bssl { + +BORINGSSL_MAKE_DELETER(BIGNUM, BN_free) +BORINGSSL_MAKE_DELETER(BN_CTX, BN_CTX_free) +BORINGSSL_MAKE_DELETER(BN_MONT_CTX, BN_MONT_CTX_free) + +} // namespace bssl + +} /* extern C++ */ -#if defined(__cplusplus) -} /* extern C */ #endif #define BN_R_ARG2_LT_ARG3 100 diff --git a/Sources/BoringSSL/include/openssl/buf.h b/Sources/BoringSSL/include/openssl/buf.h index f4e315cde..30f3af790 100644 --- a/Sources/BoringSSL/include/openssl/buf.h +++ b/Sources/BoringSSL/include/openssl/buf.h @@ -80,6 +80,10 @@ OPENSSL_EXPORT BUF_MEM *BUF_MEM_new(void); /* BUF_MEM_free frees |buf->data| if needed and then frees |buf| itself. */ OPENSSL_EXPORT void BUF_MEM_free(BUF_MEM *buf); +/* BUF_MEM_reserve ensures |buf| has capacity |cap| and allocates memory if + * needed. It returns one on success and zero on error. */ +OPENSSL_EXPORT int BUF_MEM_reserve(BUF_MEM *buf, size_t cap); + /* BUF_MEM_grow ensures that |buf| has length |len| and allocates memory if * needed. If the length of |buf| increased, the new bytes are filled with * zeros. It returns the length of |buf|, or zero if there's an error. */ @@ -113,6 +117,17 @@ OPENSSL_EXPORT size_t BUF_strlcat(char *dst, const char *src, size_t size); #if defined(__cplusplus) } /* extern C */ + +extern "C++" { + +namespace bssl { + +BORINGSSL_MAKE_DELETER(BUF_MEM, BUF_MEM_free) + +} // namespace bssl + +} /* extern C++ */ + #endif #endif /* OPENSSL_HEADER_BUFFER_H */ diff --git a/Sources/BoringSSL/include/openssl/bytestring.h b/Sources/BoringSSL/include/openssl/bytestring.h index cf424d071..bab268b5c 100644 --- a/Sources/BoringSSL/include/openssl/bytestring.h +++ b/Sources/BoringSSL/include/openssl/bytestring.h @@ -95,6 +95,10 @@ OPENSSL_EXPORT int CBS_get_u24(CBS *cbs, uint32_t *out); * and advances |cbs|. It returns one on success and zero on error. */ OPENSSL_EXPORT int CBS_get_u32(CBS *cbs, uint32_t *out); +/* CBS_get_last_u8 sets |*out| to the last uint8_t from |cbs| and shortens + * |cbs|. It returns one on success and zero on error. */ +OPENSSL_EXPORT int CBS_get_last_u8(CBS *cbs, uint8_t *out); + /* CBS_get_bytes sets |*out| to the next |len| bytes from |cbs| and advances * |cbs|. It returns one on success and zero on error. */ OPENSSL_EXPORT int CBS_get_bytes(CBS *cbs, CBS *out, size_t len); @@ -121,6 +125,7 @@ OPENSSL_EXPORT int CBS_get_u24_length_prefixed(CBS *cbs, CBS *out); /* Parsing ASN.1 */ +/* The following values are tag numbers for UNIVERSAL elements. */ #define CBS_ASN1_BOOLEAN 0x1 #define CBS_ASN1_INTEGER 0x2 #define CBS_ASN1_BITSTRING 0x3 @@ -128,6 +133,7 @@ OPENSSL_EXPORT int CBS_get_u24_length_prefixed(CBS *cbs, CBS *out); #define CBS_ASN1_NULL 0x5 #define CBS_ASN1_OBJECT 0x6 #define CBS_ASN1_ENUMERATED 0xa +#define CBS_ASN1_UTF8STRING 0xc #define CBS_ASN1_SEQUENCE (0x10 | CBS_ASN1_CONSTRUCTED) #define CBS_ASN1_SET (0x11 | CBS_ASN1_CONSTRUCTED) #define CBS_ASN1_NUMERICSTRING 0x12 @@ -143,8 +149,27 @@ OPENSSL_EXPORT int CBS_get_u24_length_prefixed(CBS *cbs, CBS *out); #define CBS_ASN1_UNIVERSALSTRING 0x1c #define CBS_ASN1_BMPSTRING 0x1e +/* CBS_ASN1_CONSTRUCTED may be ORed into a tag to toggle the constructed + * bit. |CBS| and |CBB| APIs consider the constructed bit to be part of the + * tag. */ #define CBS_ASN1_CONSTRUCTED 0x20 + +/* The following values specify the constructed bit or tag class and may be ORed + * into a tag number to produce the final tag. If none is used, the tag will be + * UNIVERSAL. + * + * Note that although they currently match the DER serialization, consumers must + * use these bits rather than make assumptions about the representation. This is + * to allow for tag numbers beyond 31 in the future. */ +#define CBS_ASN1_APPLICATION 0x40 #define CBS_ASN1_CONTEXT_SPECIFIC 0x80 +#define CBS_ASN1_PRIVATE 0xc0 + +/* CBS_ASN1_CLASS_MASK may be ANDed with a tag to query its class. */ +#define CBS_ASN1_CLASS_MASK 0xc0 + +/* CBS_ASN1_TAG_NUMBER_MASK may be ANDed with a tag to query its number. */ +#define CBS_ASN1_TAG_NUMBER_MASK 0x1f /* CBS_get_asn1 sets |*out| to the contents of DER-encoded, ASN.1 element (not * including tag and length bytes) and advances |cbs| over it. The ASN.1 @@ -165,6 +190,14 @@ OPENSSL_EXPORT int CBS_get_asn1_element(CBS *cbs, CBS *out, unsigned tag_value); * element is malformed. */ OPENSSL_EXPORT int CBS_peek_asn1_tag(const CBS *cbs, unsigned tag_value); +/* CBS_get_any_asn1 sets |*out| to contain the next ASN.1 element from |*cbs| + * (not including tag and length bytes), sets |*out_tag| to the tag number, and + * advances |*cbs|. It returns one on success and zero on error. Either of |out| + * and |out_tag| may be NULL to ignore the value. + * + * Tag numbers greater than 30 are not supported (i.e. short form only). */ +OPENSSL_EXPORT int CBS_get_any_asn1(CBS *cbs, CBS *out, unsigned *out_tag); + /* CBS_get_any_asn1_element sets |*out| to contain the next ASN.1 element from * |*cbs| (including header bytes) and advances |*cbs|. It sets |*out_tag| to * the tag number and |*out_header_len| to the length of the ASN.1 header. Each @@ -224,6 +257,15 @@ OPENSSL_EXPORT int CBS_get_optional_asn1_uint64(CBS *cbs, uint64_t *out, OPENSSL_EXPORT int CBS_get_optional_asn1_bool(CBS *cbs, int *out, unsigned tag, int default_value); +/* CBS_is_valid_asn1_bitstring returns one if |cbs| is a valid ASN.1 BIT STRING + * and zero otherwise. */ +OPENSSL_EXPORT int CBS_is_valid_asn1_bitstring(const CBS *cbs); + +/* CBS_asn1_bitstring_has_bit returns one if |cbs| is a valid ASN.1 BIT STRING + * and the specified bit is present and set. Otherwise, it returns zero. |bit| + * is indexed starting from zero. */ +OPENSSL_EXPORT int CBS_asn1_bitstring_has_bit(const CBS *cbs, unsigned bit); + /* CRYPTO ByteBuilder. * @@ -237,7 +279,8 @@ OPENSSL_EXPORT int CBS_get_optional_asn1_bool(CBS *cbs, int *out, unsigned tag, * not be used again. * * If one needs to force a length prefix to be written out because a |CBB| is - * going out of scope, use |CBB_flush|. */ + * going out of scope, use |CBB_flush|. If an operation on a |CBB| fails, it is + * in an undefined state and must not be used except to call |CBB_cleanup|. */ struct cbb_buffer_st { uint8_t *buf; @@ -245,6 +288,8 @@ struct cbb_buffer_st { size_t cap; /* The size of buf. */ char can_resize; /* One iff |buf| is owned by this object. If not then |buf| cannot be resized. */ + char error; /* One iff there was an error writing to this CBB. All future + operations will fail. */ }; struct cbb_st { @@ -299,8 +344,10 @@ OPENSSL_EXPORT void CBB_cleanup(CBB *cbb); OPENSSL_EXPORT int CBB_finish(CBB *cbb, uint8_t **out_data, size_t *out_len); /* CBB_flush causes any pending length prefixes to be written out and any child - * |CBB| objects of |cbb| to be invalidated. It returns one on success or zero - * on error. */ + * |CBB| objects of |cbb| to be invalidated. This allows |cbb| to continue to be + * used after the children go out of scope, e.g. when local |CBB| objects are + * added as children to a |CBB| that persists after a function returns. This + * function returns one on success or zero on error. */ OPENSSL_EXPORT int CBB_flush(CBB *cbb); /* CBB_data returns a pointer to the bytes written to |cbb|. It does not flush @@ -337,7 +384,7 @@ OPENSSL_EXPORT int CBB_add_u24_length_prefixed(CBB *cbb, CBB *out_contents); * the object. Passing in |tag| number 31 will return in an error since only * single octet identifiers are supported. It returns one on success or zero * on error. */ -OPENSSL_EXPORT int CBB_add_asn1(CBB *cbb, CBB *out_contents, uint8_t tag); +OPENSSL_EXPORT int CBB_add_asn1(CBB *cbb, CBB *out_contents, unsigned tag); /* CBB_add_bytes appends |len| bytes from |data| to |cbb|. It returns one on * success and zero otherwise. */ @@ -372,6 +419,10 @@ OPENSSL_EXPORT int CBB_add_u16(CBB *cbb, uint16_t value); * returns one on success and zero otherwise. */ OPENSSL_EXPORT int CBB_add_u24(CBB *cbb, uint32_t value); +/* CBB_add_u32 appends a 32-bit, big-endian number from |value| to |cbb|. It + * returns one on success and zero otherwise. */ +OPENSSL_EXPORT int CBB_add_u32(CBB *cbb, uint32_t value); + /* CBB_discard_child discards the current unflushed child of |cbb|. Neither the * child's contents nor the length prefix will be included in the output. */ OPENSSL_EXPORT void CBB_discard_child(CBB *cbb); @@ -384,6 +435,20 @@ OPENSSL_EXPORT int CBB_add_asn1_uint64(CBB *cbb, uint64_t value); #if defined(__cplusplus) } /* extern C */ + + +#if !defined(BORINGSSL_NO_CXX) +extern "C++" { + +namespace bssl { + +using ScopedCBB = internal::StackAllocated; + +} // namespace bssl + +} // extern C++ +#endif + #endif #endif /* OPENSSL_HEADER_BYTESTRING_H */ diff --git a/Sources/BoringSSL/include/openssl/chacha.h b/Sources/BoringSSL/include/openssl/chacha.h index 64713c248..3d035e69a 100644 --- a/Sources/BoringSSL/include/openssl/chacha.h +++ b/Sources/BoringSSL/include/openssl/chacha.h @@ -23,8 +23,8 @@ extern "C" { /* CRYPTO_chacha_20 encrypts |in_len| bytes from |in| with the given key and - * nonce and writes the result to |out|, which may be equal to |in|. The - * initial block counter is specified by |counter|. */ + * nonce and writes the result to |out|. If |in| and |out| alias, they must be + * equal. The initial block counter is specified by |counter|. */ OPENSSL_EXPORT void CRYPTO_chacha_20(uint8_t *out, const uint8_t *in, size_t in_len, const uint8_t key[32], const uint8_t nonce[12], uint32_t counter); diff --git a/Sources/BoringSSL/include/openssl/cipher.h b/Sources/BoringSSL/include/openssl/cipher.h index fb7171f0b..2ee74efcd 100644 --- a/Sources/BoringSSL/include/openssl/cipher.h +++ b/Sources/BoringSSL/include/openssl/cipher.h @@ -191,7 +191,7 @@ OPENSSL_EXPORT int EVP_DecryptUpdate(EVP_CIPHER_CTX *ctx, uint8_t *out, * |*out_len| to the number of bytes written. If padding is enabled (the * default) then padding is removed from the final block. * - * WARNING: it is unsafe to call this function with unauthenticted + * WARNING: it is unsafe to call this function with unauthenticated * ciphertext if padding is enabled. */ OPENSSL_EXPORT int EVP_DecryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *out_len); @@ -282,12 +282,13 @@ OPENSSL_EXPORT int EVP_CIPHER_CTX_set_padding(EVP_CIPHER_CTX *ctx, int pad); /* EVP_CIPHER_CTX_set_key_length sets the key length for |ctx|. This is only * valid for ciphers that can take a variable length key. It returns one on * success and zero on error. */ -OPENSSL_EXPORT int EVP_CIPHER_CTX_set_key_length(EVP_CIPHER_CTX *ctx, unsigned key_len); +OPENSSL_EXPORT int EVP_CIPHER_CTX_set_key_length(EVP_CIPHER_CTX *ctx, + unsigned key_len); /* Cipher accessors. */ -/* EVP_CIPHER_nid returns a NID identifing |cipher|. (For example, +/* EVP_CIPHER_nid returns a NID identifying |cipher|. (For example, * |NID_aes_128_gcm|.) */ OPENSSL_EXPORT int EVP_CIPHER_nid(const EVP_CIPHER *cipher); @@ -481,7 +482,7 @@ struct evp_cipher_ctx_st { /* num contains the number of bytes of |iv| which are valid for modes that * manage partial blocks themselves. */ - int num; + unsigned num; /* final_used is non-zero if the |final| buffer contains plaintext. */ int final_used; @@ -540,6 +541,23 @@ struct evp_cipher_st { #if defined(__cplusplus) } /* extern C */ + +#if !defined(BORINGSSL_NO_CXX) +extern "C++" { + +namespace bssl { + +BORINGSSL_MAKE_DELETER(EVP_CIPHER_CTX, EVP_CIPHER_CTX_free) + +using ScopedEVP_CIPHER_CTX = + internal::StackAllocated; + +} // namespace bssl + +} // extern C++ +#endif + #endif #define CIPHER_R_AES_KEY_SETUP_FAILED 100 diff --git a/Sources/BoringSSL/include/openssl/cmac.h b/Sources/BoringSSL/include/openssl/cmac.h index 0bb44b952..0f05bc935 100644 --- a/Sources/BoringSSL/include/openssl/cmac.h +++ b/Sources/BoringSSL/include/openssl/cmac.h @@ -71,6 +71,17 @@ OPENSSL_EXPORT int CMAC_Final(CMAC_CTX *ctx, uint8_t *out, size_t *out_len); #if defined(__cplusplus) } /* extern C */ + +extern "C++" { + +namespace bssl { + +BORINGSSL_MAKE_DELETER(CMAC_CTX, CMAC_CTX_free) + +} // namespace bssl + +} /* extern C++ */ + #endif #endif /* OPENSSL_HEADER_CMAC_H */ diff --git a/Sources/BoringSSL/include/openssl/conf.h b/Sources/BoringSSL/include/openssl/conf.h index 75f14f5b5..8b82fd459 100644 --- a/Sources/BoringSSL/include/openssl/conf.h +++ b/Sources/BoringSSL/include/openssl/conf.h @@ -77,7 +77,7 @@ extern "C" { * [section_name] * key2=value2 * - * Config files are representated by a |CONF|. */ + * Config files are represented by a |CONF|. */ struct conf_value_st { char *section; @@ -92,10 +92,10 @@ struct conf_st { /* NCONF_new returns a fresh, empty |CONF|, or NULL on error. The |method| * argument must be NULL. */ -CONF *NCONF_new(void *method); +OPENSSL_EXPORT CONF *NCONF_new(void *method); /* NCONF_free frees all the data owned by |conf| and then |conf| itself. */ -void NCONF_free(CONF *conf); +OPENSSL_EXPORT void NCONF_free(CONF *conf); /* NCONF_load parses the file named |filename| and adds the values found to * |conf|. It returns one on success and zero on error. In the event of an @@ -155,9 +155,23 @@ OPENSSL_EXPORT void CONF_modules_free(void); /* OPENSSL_config does nothing. */ OPENSSL_EXPORT void OPENSSL_config(CONF_MUST_BE_NULL *config_name); +/* OPENSSL_no_config does nothing. */ +OPENSSL_EXPORT void OPENSSL_no_config(void); + #if defined(__cplusplus) } /* extern C */ + +extern "C++" { + +namespace bssl { + +BORINGSSL_MAKE_DELETER(CONF, NCONF_free) + +} // namespace bssl + +} /* extern C++ */ + #endif #define CONF_R_LIST_CANNOT_BE_NULL 100 diff --git a/Sources/BoringSSL/include/openssl/cpu.h b/Sources/BoringSSL/include/openssl/cpu.h index e946304a3..457a47681 100644 --- a/Sources/BoringSSL/include/openssl/cpu.h +++ b/Sources/BoringSSL/include/openssl/cpu.h @@ -110,30 +110,23 @@ OPENSSL_EXPORT char CRYPTO_is_NEON_capable_at_runtime(void); /* CRYPTO_is_NEON_capable returns true if the current CPU has a NEON unit. If * this is known statically then it returns one immediately. */ static inline int CRYPTO_is_NEON_capable(void) { -#if defined(__ARM_NEON__) + /* Only statically skip the runtime lookup on aarch64. On arm, one CPU is + * known to have a broken NEON unit which is known to fail with on some + * hand-written NEON assembly. For now, continue to apply the workaround even + * when the compiler is instructed to freely emit NEON code. See + * https://crbug.com/341598 and https://crbug.com/606629. */ +#if defined(__ARM_NEON__) && !defined(OPENSSL_ARM) return 1; #else return CRYPTO_is_NEON_capable_at_runtime(); #endif } -/* CRYPTO_set_NEON_capable sets the return value of |CRYPTO_is_NEON_capable|. - * By default, unless the code was compiled with |-mfpu=neon|, NEON is assumed - * not to be present. It is not autodetected. Calling this with a zero - * argument also causes |CRYPTO_is_NEON_functional| to return false. */ -OPENSSL_EXPORT void CRYPTO_set_NEON_capable(char neon_capable); - -/* CRYPTO_is_NEON_functional returns true if the current CPU has a /working/ - * NEON unit. Some phones have a NEON unit, but the Poly1305 NEON code causes - * it to fail. See https://code.google.com/p/chromium/issues/detail?id=341598 */ -OPENSSL_EXPORT char CRYPTO_is_NEON_functional(void); - -/* CRYPTO_set_NEON_functional sets the "NEON functional" flag. For - * |CRYPTO_is_NEON_functional| to return true, both this flag and the NEON flag - * must be true. By default NEON is assumed to be functional if the code was - * compiled with |-mfpu=neon| or if |CRYPTO_set_NEON_capable| has been called - * with a non-zero argument. */ -OPENSSL_EXPORT void CRYPTO_set_NEON_functional(char neon_functional); +#if defined(OPENSSL_ARM) +/* CRYPTO_has_broken_NEON returns one if the current CPU is known to have a + * broken NEON unit. See https://crbug.com/341598. */ +OPENSSL_EXPORT int CRYPTO_has_broken_NEON(void); +#endif /* CRYPTO_is_ARMv8_AES_capable returns true if the current CPU supports the * ARMv8 AES instruction. */ @@ -153,10 +146,6 @@ static inline int CRYPTO_is_NEON_capable(void) { #endif } -static inline int CRYPTO_is_NEON_functional(void) { - return CRYPTO_is_NEON_capable(); -} - static inline int CRYPTO_is_ARMv8_AES_capable(void) { #if defined(OPENSSL_STATIC_ARMCAP_AES) return 1; @@ -174,7 +163,15 @@ static inline int CRYPTO_is_ARMv8_PMULL_capable(void) { } #endif /* OPENSSL_STATIC_ARMCAP */ -#endif /* OPENSSL_ARM */ +#endif /* OPENSSL_ARM || OPENSSL_AARCH64 */ + +#if defined(OPENSSL_PPC64LE) + +/* CRYPTO_is_PPC64LE_vcrypto_capable returns true iff the current CPU supports + * the Vector.AES category of instructions. */ +int CRYPTO_is_PPC64LE_vcrypto_capable(void); + +#endif /* OPENSSL_PPC64LE */ #if defined(__cplusplus) diff --git a/Sources/BoringSSL/include/openssl/crypto.h b/Sources/BoringSSL/include/openssl/crypto.h index 29d58921a..3a7e6b1be 100644 --- a/Sources/BoringSSL/include/openssl/crypto.h +++ b/Sources/BoringSSL/include/openssl/crypto.h @@ -36,9 +36,24 @@ extern "C" { /* CRYPTO_library_init initializes the crypto library. It must be called if the * library is built with BORINGSSL_NO_STATIC_INITIALIZER. Otherwise, it does - * nothing and a static initializer is used instead. */ + * nothing and a static initializer is used instead. It is safe to call this + * function multiple times and concurrently from multiple threads. + * + * On some ARM configurations, this function may require filesystem access and + * should be called before entering a sandbox. */ OPENSSL_EXPORT void CRYPTO_library_init(void); +/* CRYPTO_is_confidential_build returns one if the linked version of BoringSSL + * has been built with the BORINGSSL_CONFIDENTIAL define and zero otherwise. + * + * This is used by some consumers to identify whether they are using an + * internal version of BoringSSL. */ +OPENSSL_EXPORT int CRYPTO_is_confidential_build(void); + +/* CRYPTO_has_asm returns one unless BoringSSL was built with OPENSSL_NO_ASM, + * in which case it returns zero. */ +OPENSSL_EXPORT int CRYPTO_has_asm(void); + /* Deprecated functions. */ @@ -62,9 +77,15 @@ OPENSSL_EXPORT int CRYPTO_malloc_init(void); /* ENGINE_load_builtin_engines does nothing. */ OPENSSL_EXPORT void ENGINE_load_builtin_engines(void); +/* ENGINE_register_all_complete returns one. */ +OPENSSL_EXPORT int ENGINE_register_all_complete(void); + /* OPENSSL_load_builtin_modules does nothing. */ OPENSSL_EXPORT void OPENSSL_load_builtin_modules(void); +/* FIPS_mode returns zero. */ +OPENSSL_EXPORT int FIPS_mode(void); + #if defined(__cplusplus) } /* extern C */ diff --git a/Sources/BoringSSL/include/openssl/curve25519.h b/Sources/BoringSSL/include/openssl/curve25519.h index c202575fd..1bbb69a95 100644 --- a/Sources/BoringSSL/include/openssl/curve25519.h +++ b/Sources/BoringSSL/include/openssl/curve25519.h @@ -29,10 +29,13 @@ extern "C" { /* X25519. * - * Curve25519 is an elliptic curve. The same name is also sometimes used for - * the Diffie-Hellman primitive built from it but “X25519” is a more precise - * name for that, which is the one used here. See http://cr.yp.to/ecdh.html and - * https://tools.ietf.org/html/rfc7748. */ + * X25519 is the Diffie-Hellman primitive built from curve25519. It is + * sometimes referred to as “curve25519”, but “X25519” is a more precise name. + * See http://cr.yp.to/ecdh.html and https://tools.ietf.org/html/rfc7748. */ + +#define X25519_PRIVATE_KEY_LEN 32 +#define X25519_PUBLIC_VALUE_LEN 32 +#define X25519_SHARED_KEY_LEN 32 /* X25519_keypair sets |out_public_value| and |out_private_key| to a freshly * generated, public–private key pair. */ @@ -83,9 +86,111 @@ OPENSSL_EXPORT int ED25519_verify(const uint8_t *message, size_t message_len, const uint8_t signature[64], const uint8_t public_key[32]); +/* ED25519_keypair_from_seed calculates a public and private key from an + * Ed25519 “seed”. Seed values are not exposed by this API (although they + * happen to be the first 32 bytes of a private key) so this function is for + * interoperating with systems that may store just a seed instead of a full + * private key. */ +OPENSSL_EXPORT void ED25519_keypair_from_seed(uint8_t out_public_key[32], + uint8_t out_private_key[64], + const uint8_t seed[32]); + + +/* SPAKE2. + * + * SPAKE2 is a password-authenticated key-exchange. It allows two parties, + * who share a low-entropy secret (i.e. password), to agree on a shared key. + * An attacker can only make one guess of the password per execution of the + * protocol. + * + * See https://tools.ietf.org/html/draft-irtf-cfrg-spake2-02. */ + +/* spake2_role_t enumerates the different “roles” in SPAKE2. The protocol + * requires that the symmetry of the two parties be broken so one participant + * must be “Alice” and the other be “Bob”. */ +enum spake2_role_t { + spake2_role_alice, + spake2_role_bob, +}; + +/* SPAKE2_CTX_new creates a new |SPAKE2_CTX| (which can only be used for a + * single execution of the protocol). SPAKE2 requires the symmetry of the two + * parties to be broken which is indicated via |my_role| – each party must pass + * a different value for this argument. + * + * The |my_name| and |their_name| arguments allow optional, opaque names to be + * bound into the protocol. For example MAC addresses, hostnames, usernames + * etc. These values are not exposed and can avoid context-confusion attacks + * when a password is shared between several devices. */ +OPENSSL_EXPORT SPAKE2_CTX *SPAKE2_CTX_new( + enum spake2_role_t my_role, + const uint8_t *my_name, size_t my_name_len, + const uint8_t *their_name, size_t their_name_len); + +/* SPAKE2_CTX_free frees |ctx| and all the resources that it has allocated. */ +OPENSSL_EXPORT void SPAKE2_CTX_free(SPAKE2_CTX *ctx); + +/* SPAKE2_MAX_MSG_SIZE is the maximum size of a SPAKE2 message. */ +#define SPAKE2_MAX_MSG_SIZE 32 + +/* SPAKE2_generate_msg generates a SPAKE2 message given |password|, writes + * it to |out| and sets |*out_len| to the number of bytes written. + * + * At most |max_out_len| bytes are written to |out| and, in order to ensure + * success, |max_out_len| should be at least |SPAKE2_MAX_MSG_SIZE| bytes. + * + * This function can only be called once for a given |SPAKE2_CTX|. + * + * It returns one on success and zero on error. */ +OPENSSL_EXPORT int SPAKE2_generate_msg(SPAKE2_CTX *ctx, uint8_t *out, + size_t *out_len, size_t max_out_len, + const uint8_t *password, + size_t password_len); + +/* SPAKE2_MAX_KEY_SIZE is the maximum amount of key material that SPAKE2 will + * produce. */ +#define SPAKE2_MAX_KEY_SIZE 64 + +/* SPAKE2_process_msg completes the SPAKE2 exchange given the peer's message in + * |their_msg|, writes at most |max_out_key_len| bytes to |out_key| and sets + * |*out_key_len| to the number of bytes written. + * + * The resulting keying material is suitable for: + * a) Using directly in a key-confirmation step: i.e. each side could + * transmit a hash of their role, a channel-binding value and the key + * material to prove to the other side that they know the shared key. + * b) Using as input keying material to HKDF to generate a variety of subkeys + * for encryption etc. + * + * If |max_out_key_key| is smaller than the amount of key material generated + * then the key is silently truncated. If you want to ensure that no truncation + * occurs then |max_out_key| should be at least |SPAKE2_MAX_KEY_SIZE|. + * + * You must call |SPAKE2_generate_msg| on a given |SPAKE2_CTX| before calling + * this function. On successful return, |ctx| is complete and calling + * |SPAKE2_CTX_free| is the only acceptable operation on it. + * + * Returns one on success or zero on error. */ +OPENSSL_EXPORT int SPAKE2_process_msg(SPAKE2_CTX *ctx, uint8_t *out_key, + size_t *out_key_len, + size_t max_out_key_len, + const uint8_t *their_msg, + size_t their_msg_len); + #if defined(__cplusplus) } /* extern C */ + +extern "C++" { + +namespace bssl { + +BORINGSSL_MAKE_DELETER(SPAKE2_CTX, SPAKE2_CTX_free) + +} // namespace bssl + +} /* extern C++ */ + #endif #endif /* OPENSSL_HEADER_CURVE25519_H */ diff --git a/Sources/BoringSSL/include/openssl/dh.h b/Sources/BoringSSL/include/openssl/dh.h index 4066ae173..ed2396d1e 100644 --- a/Sources/BoringSSL/include/openssl/dh.h +++ b/Sources/BoringSSL/include/openssl/dh.h @@ -81,10 +81,24 @@ OPENSSL_EXPORT DH *DH_new(void); * count drops to zero. */ OPENSSL_EXPORT void DH_free(DH *dh); -/* DH_up_ref increments the reference count of |dh|. */ +/* DH_up_ref increments the reference count of |dh| and returns one. */ OPENSSL_EXPORT int DH_up_ref(DH *dh); +/* Properties. */ + +/* DH_get0_key sets |*out_pub_key| and |*out_priv_key|, if non-NULL, to |dh|'s + * public and private key, respectively. If |dh| is a public key, the private + * key will be set to NULL. */ +OPENSSL_EXPORT void DH_get0_key(const DH *dh, const BIGNUM **out_pub_key, + const BIGNUM **out_priv_key); + +/* DH_get0_pqg sets |*out_p|, |*out_q|, and |*out_g|, if non-NULL, to |dh|'s p, + * q, and g parameters, respectively. */ +OPENSSL_EXPORT void DH_get0_pqg(const DH *dh, const BIGNUM **out_p, + const BIGNUM **out_q, const BIGNUM **out_g); + + /* Standard parameters. * * These functions return new DH objects with standard parameters. They return @@ -96,6 +110,11 @@ OPENSSL_EXPORT DH *DH_get_1024_160(const ENGINE *engine); OPENSSL_EXPORT DH *DH_get_2048_224(const ENGINE *engine); OPENSSL_EXPORT DH *DH_get_2048_256(const ENGINE *engine); +/* BN_get_rfc3526_prime_1536 sets |*ret| to the 1536-bit MODP group from RFC + * 3526 and returns |ret|. If |ret| is NULL then a fresh |BIGNUM| is allocated + * and returned. It returns NULL on allocation failure. */ +OPENSSL_EXPORT BIGNUM *BN_get_rfc3526_prime_1536(BIGNUM *ret); + /* Parameter generation. */ @@ -174,22 +193,15 @@ OPENSSL_EXPORT DH *DHparams_dup(const DH *dh); /* ASN.1 functions. */ -/* d2i_DHparams parses an ASN.1, DER encoded Diffie-Hellman parameters - * structure from |len| bytes at |*inp|. If |ret| is not NULL then, on exit, a - * pointer to the result is in |*ret|. If |*ret| is already non-NULL on entry - * then the result is written directly into |*ret|, otherwise a fresh |DH| is - * allocated. However, one should not depend on writing into |*ret| because - * this behaviour is likely to change in the future. - * - * On successful exit, |*inp| is advanced past the DER structure. It - * returns the result or NULL on error. */ -OPENSSL_EXPORT DH *d2i_DHparams(DH **ret, const unsigned char **inp, long len); +/* DH_parse_parameters decodes a DER-encoded DHParameter structure (PKCS #3) + * from |cbs| and advances |cbs|. It returns a newly-allocated |DH| or NULL on + * error. */ +OPENSSL_EXPORT DH *DH_parse_parameters(CBS *cbs); -/* i2d_DHparams marshals |in| to an ASN.1, DER structure. If |outp| is not NULL - * then the result is written to |*outp| and |*outp| is advanced just past the - * output. It returns the number of bytes in the result, whether written or - * not, or a negative value on error. */ -OPENSSL_EXPORT int i2d_DHparams(const DH *in, unsigned char **outp); +/* DH_marshal_parameters marshals |dh| as a DER-encoded DHParameter structure + * (PKCS #3) and appends the result to |cbb|. It returns one on success and zero + * on error. */ +OPENSSL_EXPORT int DH_marshal_parameters(CBB *cbb, const DH *dh); /* ex_data functions. @@ -204,6 +216,36 @@ OPENSSL_EXPORT int DH_set_ex_data(DH *d, int idx, void *arg); OPENSSL_EXPORT void *DH_get_ex_data(DH *d, int idx); +/* Deprecated functions. */ + +/* DH_generate_parameters behaves like |DH_generate_parameters_ex|, which is + * what you should use instead. It returns NULL on error, or a newly-allocated + * |DH| on success. This function is provided for compatibility only. */ +OPENSSL_EXPORT DH *DH_generate_parameters(int prime_len, int generator, + void (*callback)(int, int, void *), + void *cb_arg); + +/* d2i_DHparams parses an ASN.1, DER encoded Diffie-Hellman parameters structure + * from |len| bytes at |*inp|. If |ret| is not NULL then, on exit, a pointer to + * the result is in |*ret|. Note that, even if |*ret| is already non-NULL on + * entry, it will not be written to. Rather, a fresh |DH| is allocated and the + * previous one is freed. + * + * On successful exit, |*inp| is advanced past the DER structure. It + * returns the result or NULL on error. + * + * Use |DH_parse_parameters| instead. */ +OPENSSL_EXPORT DH *d2i_DHparams(DH **ret, const unsigned char **inp, long len); + +/* i2d_DHparams marshals |in| to an ASN.1, DER structure. If |outp| is not NULL + * then the result is written to |*outp| and |*outp| is advanced just past the + * output. It returns the number of bytes in the result, whether written or + * not, or a negative value on error. + * + * Use |DH_marshal_parameters| instead. */ +OPENSSL_EXPORT int i2d_DHparams(const DH *in, unsigned char **outp); + + struct dh_st { BIGNUM *p; BIGNUM *g; @@ -232,11 +274,24 @@ struct dh_st { #if defined(__cplusplus) } /* extern C */ + +extern "C++" { + +namespace bssl { + +BORINGSSL_MAKE_DELETER(DH, DH_free) + +} // namespace bssl + +} /* extern C++ */ + #endif #define DH_R_BAD_GENERATOR 100 #define DH_R_INVALID_PUBKEY 101 #define DH_R_MODULUS_TOO_LARGE 102 #define DH_R_NO_PRIVATE_VALUE 103 +#define DH_R_DECODE_ERROR 104 +#define DH_R_ENCODE_ERROR 105 #endif /* OPENSSL_HEADER_DH_H */ diff --git a/Sources/BoringSSL/include/openssl/digest.h b/Sources/BoringSSL/include/openssl/digest.h index 80028efda..87de3dfe4 100644 --- a/Sources/BoringSSL/include/openssl/digest.h +++ b/Sources/BoringSSL/include/openssl/digest.h @@ -102,7 +102,8 @@ OPENSSL_EXPORT const EVP_MD *EVP_get_digestbyobj(const ASN1_OBJECT *obj); * An EVP_MD_CTX represents the state of a specific digest operation in * progress. */ -/* EVP_MD_CTX_init initialises an, already allocated, |EVP_MD_CTX|. */ +/* EVP_MD_CTX_init initialises an, already allocated, |EVP_MD_CTX|. This is the + * same as setting the structure to zero. */ OPENSSL_EXPORT void EVP_MD_CTX_init(EVP_MD_CTX *ctx); /* EVP_MD_CTX_create allocates and initialises a fresh |EVP_MD_CTX| and returns @@ -143,11 +144,16 @@ OPENSSL_EXPORT int EVP_DigestUpdate(EVP_MD_CTX *ctx, const void *data, * at least this much space. */ #define EVP_MAX_MD_SIZE 64 /* SHA-512 is the longest so far. */ +/* EVP_MAX_MD_BLOCK_SIZE is the largest digest block size supported, in + * bytes. */ +#define EVP_MAX_MD_BLOCK_SIZE 128 /* SHA-512 is the longest so far. */ + /* EVP_DigestFinal_ex finishes the digest in |ctx| and writes the output to - * |md_out|. At most |EVP_MAX_MD_SIZE| bytes are written. If |out_size| is not - * NULL then |*out_size| is set to the number of bytes written. It returns one. - * After this call, the hash cannot be updated or finished again until - * |EVP_DigestInit_ex| is called to start another hashing operation. */ + * |md_out|. |EVP_MD_CTX_size| bytes are written, which is at most + * |EVP_MAX_MD_SIZE|. If |out_size| is not NULL then |*out_size| is set to the + * number of bytes written. It returns one. After this call, the hash cannot be + * updated or finished again until |EVP_DigestInit_ex| is called to start + * another hashing operation. */ OPENSSL_EXPORT int EVP_DigestFinal_ex(EVP_MD_CTX *ctx, uint8_t *md_out, unsigned int *out_size); @@ -156,11 +162,11 @@ OPENSSL_EXPORT int EVP_DigestFinal_ex(EVP_MD_CTX *ctx, uint8_t *md_out, OPENSSL_EXPORT int EVP_DigestFinal(EVP_MD_CTX *ctx, uint8_t *md_out, unsigned int *out_size); -/* EVP_Digest performs a complete hashing operation in one call. It hashes - * |len| bytes from |data| and writes the digest to |md_out|. At most - * |EVP_MAX_MD_SIZE| bytes are written. If |out_size| is not NULL then - * |*out_size| is set to the number of bytes written. It returns one on success - * and zero otherwise. */ +/* EVP_Digest performs a complete hashing operation in one call. It hashes |len| + * bytes from |data| and writes the digest to |md_out|. |EVP_MD_CTX_size| bytes + * are written, which is at most |EVP_MAX_MD_SIZE|. If |out_size| is not NULL + * then |*out_size| is set to the number of bytes written. It returns one on + * success and zero otherwise. */ OPENSSL_EXPORT int EVP_Digest(const void *data, size_t len, uint8_t *md_out, unsigned int *md_out_size, const EVP_MD *type, ENGINE *impl); @@ -171,7 +177,7 @@ OPENSSL_EXPORT int EVP_Digest(const void *data, size_t len, uint8_t *md_out, * These functions allow code to learn details about an abstract hash * function. */ -/* EVP_MD_type returns a NID identifing |md|. (For example, |NID_sha256|.) */ +/* EVP_MD_type returns a NID identifying |md|. (For example, |NID_sha256|.) */ OPENSSL_EXPORT int EVP_MD_type(const EVP_MD *md); /* EVP_MD_flags returns the flags for |md|, which is a set of |EVP_MD_FLAG_*| @@ -209,6 +215,12 @@ OPENSSL_EXPORT int EVP_add_digest(const EVP_MD *digest); * |name|, or NULL if the name is unknown. */ OPENSSL_EXPORT const EVP_MD *EVP_get_digestbyname(const char *); +/* EVP_dss1 returns the value of EVP_sha1(). This was provided by OpenSSL to + * specifiy the original DSA signatures, which were fixed to use SHA-1. Note, + * however, that attempting to sign or verify DSA signatures with the EVP + * interface will always fail. */ +OPENSSL_EXPORT const EVP_MD *EVP_dss1(void); + /* Digest operation accessors. */ @@ -218,11 +230,11 @@ OPENSSL_EXPORT const EVP_MD *EVP_MD_CTX_md(const EVP_MD_CTX *ctx); /* EVP_MD_CTX_size returns the digest size of |ctx|, in bytes. It * will crash if a digest hasn't been set on |ctx|. */ -OPENSSL_EXPORT unsigned EVP_MD_CTX_size(const EVP_MD_CTX *ctx); +OPENSSL_EXPORT size_t EVP_MD_CTX_size(const EVP_MD_CTX *ctx); /* EVP_MD_CTX_block_size returns the block size of the digest function used by * |ctx|, in bytes. It will crash if a digest hasn't been set on |ctx|. */ -OPENSSL_EXPORT unsigned EVP_MD_CTX_block_size(const EVP_MD_CTX *ctx); +OPENSSL_EXPORT size_t EVP_MD_CTX_block_size(const EVP_MD_CTX *ctx); /* EVP_MD_CTX_type returns a NID describing the digest function used by |ctx|. * (For example, |NID_sha256|.) It will crash if a digest hasn't been set on @@ -251,6 +263,23 @@ struct env_md_ctx_st { #if defined(__cplusplus) } /* extern C */ + +#if !defined(BORINGSSL_NO_CXX) +extern "C++" { + +namespace bssl { + +BORINGSSL_MAKE_DELETER(EVP_MD_CTX, EVP_MD_CTX_destroy) + +using ScopedEVP_MD_CTX = + internal::StackAllocated; + +} // namespace bssl + +} // extern C++ +#endif + #endif #define DIGEST_R_INPUT_NOT_INITIALIZED 100 diff --git a/Sources/BoringSSL/include/openssl/dsa.h b/Sources/BoringSSL/include/openssl/dsa.h index 8cf008b66..29888778a 100644 --- a/Sources/BoringSSL/include/openssl/dsa.h +++ b/Sources/BoringSSL/include/openssl/dsa.h @@ -71,7 +71,7 @@ extern "C" { #endif -/* DSA contains functions for signing and verifing with the Digital Signature +/* DSA contains functions for signing and verifying with the Digital Signature * Algorithm. */ @@ -84,10 +84,24 @@ OPENSSL_EXPORT DSA *DSA_new(void); * reference count drops to zero. */ OPENSSL_EXPORT void DSA_free(DSA *dsa); -/* DSA_up_ref increments the reference count of |dsa|. */ +/* DSA_up_ref increments the reference count of |dsa| and returns one. */ OPENSSL_EXPORT int DSA_up_ref(DSA *dsa); +/* Properties. */ + +/* DSA_get0_key sets |*out_pub_key| and |*out_priv_key|, if non-NULL, to |dsa|'s + * public and private key, respectively. If |dsa| is a public key, the private + * key will be set to NULL. */ +OPENSSL_EXPORT void DSA_get0_key(const DSA *dsa, const BIGNUM **out_pub_key, + const BIGNUM **out_priv_key); + +/* DSA_get0_pqg sets |*out_p|, |*out_q|, and |*out_g|, if non-NULL, to |dsa|'s + * p, q, and g parameters, respectively. */ +OPENSSL_EXPORT void DSA_get0_pqg(const DSA *dsa, const BIGNUM **out_p, + const BIGNUM **out_q, const BIGNUM **out_g); + + /* Parameter generation. */ /* DSA_generate_parameters_ex generates a set of DSA parameters by following @@ -129,9 +143,9 @@ OPENSSL_EXPORT int DSA_generate_key(DSA *dsa); /* Signatures. */ /* DSA_SIG_st (aka |DSA_SIG|) contains a DSA signature as a pair of integers. */ -typedef struct DSA_SIG_st { +struct DSA_SIG_st { BIGNUM *r, *s; -} DSA_SIG; +}; /* DSA_SIG_new returns a freshly allocated, DIG_SIG structure or NULL on error. * Both |r| and |s| in the signature will be NULL. */ @@ -337,10 +351,10 @@ OPENSSL_EXPORT int i2d_DSAPublicKey(const DSA *in, uint8_t **outp); * Use |DSA_parse_private_key| instead. */ OPENSSL_EXPORT DSA *d2i_DSAPrivateKey(DSA **out, const uint8_t **inp, long len); -/* i2d_DSAPrivateKey marshals a private key from |in| to an ASN.1, DER structure. - * If |outp| is not NULL then the result is written to |*outp| and |*outp| is - * advanced just past the output. It returns the number of bytes in the result, - * whether written or not, or a negative value on error. +/* i2d_DSAPrivateKey marshals a private key from |in| to an ASN.1, DER + * structure. If |outp| is not NULL then the result is written to |*outp| and + * |*outp| is advanced just past the output. It returns the number of bytes in + * the result, whether written or not, or a negative value on error. * * Use |DSA_marshal_private_key| instead. */ OPENSSL_EXPORT int i2d_DSAPrivateKey(const DSA *in, uint8_t **outp); @@ -363,6 +377,15 @@ OPENSSL_EXPORT DSA *d2i_DSAparams(DSA **out, const uint8_t **inp, long len); * Use |DSA_marshal_parameters| instead. */ OPENSSL_EXPORT int i2d_DSAparams(const DSA *in, uint8_t **outp); +/* DSA_generate_parameters is a deprecated version of + * |DSA_generate_parameters_ex| that creates and returns a |DSA*|. Don't use + * it. */ +OPENSSL_EXPORT DSA *DSA_generate_parameters(int bits, unsigned char *seed, + int seed_len, int *counter_ret, + unsigned long *h_ret, + void (*callback)(int, int, void *), + void *cb_arg); + struct dsa_st { long version; @@ -378,8 +401,9 @@ struct dsa_st { int flags; /* Normally used to cache montgomery values */ - CRYPTO_MUTEX method_mont_p_lock; + CRYPTO_MUTEX method_mont_lock; BN_MONT_CTX *method_mont_p; + BN_MONT_CTX *method_mont_q; CRYPTO_refcount_t references; CRYPTO_EX_DATA ex_data; }; @@ -387,6 +411,18 @@ struct dsa_st { #if defined(__cplusplus) } /* extern C */ + +extern "C++" { + +namespace bssl { + +BORINGSSL_MAKE_DELETER(DSA, DSA_free) +BORINGSSL_MAKE_DELETER(DSA_SIG, DSA_SIG_free) + +} // namespace bssl + +} /* extern C++ */ + #endif #define DSA_R_BAD_Q_VALUE 100 diff --git a/Sources/BoringSSL/include/openssl/ec.h b/Sources/BoringSSL/include/openssl/ec.h index 4957066fd..a1cd5c71f 100644 --- a/Sources/BoringSSL/include/openssl/ec.h +++ b/Sources/BoringSSL/include/openssl/ec.h @@ -78,9 +78,6 @@ extern "C" { /* Low-level operations on elliptic curves. */ -typedef struct ec_group_st EC_GROUP; -typedef struct ec_point_st EC_POINT; - /* point_conversion_form_t enumerates forms, as defined in X9.62 (ECDSA), for * the encoding of a elliptic curve point (x,y) */ typedef enum { @@ -89,7 +86,7 @@ typedef enum { * is. */ POINT_CONVERSION_COMPRESSED = 2, - /* POINT_CONVERSION_COMPRESSED indicates that the point is encoded as + /* POINT_CONVERSION_UNCOMPRESSED indicates that the point is encoded as * z||x||y, where z is the octet 0x04. */ POINT_CONVERSION_UNCOMPRESSED = 4, @@ -189,12 +186,13 @@ OPENSSL_EXPORT int EC_POINT_is_at_infinity(const EC_GROUP *group, const EC_POINT *point); /* EC_POINT_is_on_curve returns one if |point| is an element of |group| and - * zero otheriwse. If |ctx| is non-NULL, it may be used. */ + * and zero otherwise or when an error occurs. This is different from OpenSSL, + * which returns -1 on error. If |ctx| is non-NULL, it may be used. */ OPENSSL_EXPORT int EC_POINT_is_on_curve(const EC_GROUP *group, const EC_POINT *point, BN_CTX *ctx); -/* EC_POINT_cmp returns zero if |a| is equal to |b|, greater than zero is - * non-equal and -1 on error. If |ctx| is not NULL, it may be used. */ +/* EC_POINT_cmp returns zero if |a| is equal to |b|, greater than zero if + * not equal and -1 on error. If |ctx| is not NULL, it may be used. */ OPENSSL_EXPORT int EC_POINT_cmp(const EC_GROUP *group, const EC_POINT *a, const EC_POINT *b, BN_CTX *ctx); @@ -220,10 +218,10 @@ OPENSSL_EXPORT int EC_POINT_get_affine_coordinates_GFp(const EC_GROUP *group, BIGNUM *x, BIGNUM *y, BN_CTX *ctx); -/* EC_POINT_set_affine_coordinates_GFp sets the value of |p| to be (|x|, |y|). - * The |ctx| argument may be used if not NULL. It returns one on success or - * zero on error. Note that, unlike with OpenSSL, it's considered an error if - * the point is not on the curve. */ +/* EC_POINT_set_affine_coordinates_GFp sets the value of |point| to be + * (|x|, |y|). The |ctx| argument may be used if not NULL. It returns one + * on success or zero on error. Note that, unlike with OpenSSL, it's + * considered an error if the point is not on the curve. */ OPENSSL_EXPORT int EC_POINT_set_affine_coordinates_GFp(const EC_GROUP *group, EC_POINT *point, const BIGNUM *x, @@ -274,8 +272,8 @@ OPENSSL_EXPORT int EC_POINT_add(const EC_GROUP *group, EC_POINT *r, OPENSSL_EXPORT int EC_POINT_dbl(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, BN_CTX *ctx); -/* EC_POINT_invert sets |a| equal to minus |a|. It returns one on success and zero - * otherwise. If |ctx| is not NULL, it may be used. */ +/* EC_POINT_invert sets |a| equal to minus |a|. It returns one on success and + * zero otherwise. If |ctx| is not NULL, it may be used. */ OPENSSL_EXPORT int EC_POINT_invert(const EC_GROUP *group, EC_POINT *a, BN_CTX *ctx); @@ -288,16 +286,31 @@ OPENSSL_EXPORT int EC_POINT_mul(const EC_GROUP *group, EC_POINT *r, /* Deprecated functions. */ -/* EC_GROUP_new_arbitrary creates a new, arbitrary elliptic curve group based on - * the equation y² = x³ + a·x + b. The generator is set to (gx, gy) which must - * have the given order and cofactor. It returns the new group or NULL on error. +/* EC_GROUP_new_curve_GFp creates a new, arbitrary elliptic curve group based + * on the equation y² = x³ + a·x + b. It returns the new group or NULL on + * error. + * + * This new group has no generator. It is an error to use a generator-less group + * with any functions except for |EC_GROUP_free|, |EC_POINT_new|, + * |EC_POINT_set_affine_coordinates_GFp|, and |EC_GROUP_set_generator|. * * |EC_GROUP|s returned by this function will always compare as unequal via * |EC_GROUP_cmp| (even to themselves). |EC_GROUP_get_curve_name| will always - * return |NID_undef|. */ -OPENSSL_EXPORT EC_GROUP *EC_GROUP_new_arbitrary( - const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, const BIGNUM *gx, - const BIGNUM *gy, const BIGNUM *order, const BIGNUM *cofactor); + * return |NID_undef|. + * + * Avoid using arbitrary curves and use |EC_GROUP_new_by_curve_name| instead. */ +OPENSSL_EXPORT EC_GROUP *EC_GROUP_new_curve_GFp(const BIGNUM *p, + const BIGNUM *a, + const BIGNUM *b, BN_CTX *ctx); + +/* EC_GROUP_set_generator sets the generator for |group| to |generator|, which + * must have the given order and cofactor. It may only be used with |EC_GROUP| + * objects returned by |EC_GROUP_new_curve_GFp| and may only be used once on + * each group. */ +OPENSSL_EXPORT int EC_GROUP_set_generator(EC_GROUP *group, + const EC_POINT *generator, + const BIGNUM *order, + const BIGNUM *cofactor); /* EC_GROUP_get_order sets |*order| to the order of |group|, if it's not * NULL. It returns one on success and zero otherwise. |ctx| is ignored. Use @@ -343,6 +356,18 @@ OPENSSL_EXPORT size_t EC_get_builtin_curves(EC_builtin_curve *out_curves, #if defined(__cplusplus) } /* extern C */ + +extern "C++" { + +namespace bssl { + +BORINGSSL_MAKE_DELETER(EC_POINT, EC_POINT_free) +BORINGSSL_MAKE_DELETER(EC_GROUP, EC_GROUP_free) + +} // namespace bssl + +} /* extern C++ */ + #endif #define EC_R_BUFFER_TOO_SMALL 100 @@ -376,5 +401,6 @@ OPENSSL_EXPORT size_t EC_get_builtin_curves(EC_builtin_curve *out_curves, #define EC_R_DECODE_ERROR 128 #define EC_R_ENCODE_ERROR 129 #define EC_R_GROUP_MISMATCH 130 +#define EC_R_INVALID_COFACTOR 131 #endif /* OPENSSL_HEADER_EC_H */ diff --git a/Sources/BoringSSL/include/openssl/ec_key.h b/Sources/BoringSSL/include/openssl/ec_key.h index 274235585..1dbae62db 100644 --- a/Sources/BoringSSL/include/openssl/ec_key.h +++ b/Sources/BoringSSL/include/openssl/ec_key.h @@ -105,8 +105,7 @@ OPENSSL_EXPORT EC_KEY *EC_KEY_copy(EC_KEY *dst, const EC_KEY *src); /* EC_KEY_dup returns a fresh copy of |src| or NULL on error. */ OPENSSL_EXPORT EC_KEY *EC_KEY_dup(const EC_KEY *src); -/* EC_KEY_up_ref increases the reference count of |key|. It returns one on - * success and zero otherwise. */ +/* EC_KEY_up_ref increases the reference count of |key| and returns one. */ OPENSSL_EXPORT int EC_KEY_up_ref(EC_KEY *key); /* EC_KEY_is_opaque returns one if |key| is opaque and doesn't expose its key @@ -192,10 +191,21 @@ OPENSSL_EXPORT EC_KEY *EC_KEY_parse_private_key(CBS *cbs, OPENSSL_EXPORT int EC_KEY_marshal_private_key(CBB *cbb, const EC_KEY *key, unsigned enc_flags); +/* EC_KEY_parse_curve_name parses a DER-encoded OBJECT IDENTIFIER as a curve + * name from |cbs| and advances |cbs|. It returns a newly-allocated |EC_GROUP| + * or NULL on error. */ +OPENSSL_EXPORT EC_GROUP *EC_KEY_parse_curve_name(CBS *cbs); + +/* EC_KEY_marshal_curve_name marshals |group| as a DER-encoded OBJECT IDENTIFIER + * and appends the result to |cbb|. It returns one on success and zero on + * failure. */ +OPENSSL_EXPORT int EC_KEY_marshal_curve_name(CBB *cbb, const EC_GROUP *group); + /* EC_KEY_parse_parameters parses a DER-encoded ECParameters structure (RFC * 5480) from |cbs| and advances |cbs|. It returns a newly-allocated |EC_GROUP| * or NULL on error. It supports the namedCurve and specifiedCurve options, but - * use of specifiedCurve is deprecated. */ + * use of specifiedCurve is deprecated. Use |EC_KEY_parse_curve_name| + * instead. */ OPENSSL_EXPORT EC_GROUP *EC_KEY_parse_parameters(CBS *cbs); @@ -237,7 +247,7 @@ struct ecdsa_method_st { int (*sign)(const uint8_t *digest, size_t digest_len, uint8_t *sig, unsigned int *sig_len, EC_KEY *eckey); - /* verify matches the arguments and behaviour of |ECDSA_verify|. */ + /* Ignored. Set this to NULL. */ int (*verify)(const uint8_t *digest, size_t digest_len, const uint8_t *sig, size_t sig_len, EC_KEY *eckey); @@ -279,7 +289,7 @@ OPENSSL_EXPORT int i2d_ECPrivateKey(const EC_KEY *key, uint8_t **outp); * allocated and the previous one is freed. On successful exit, |*inp| is * advanced past the DER structure. It returns the result or NULL on error. * - * Use EC_KEY_parse_parameters instead. */ + * Use |EC_KEY_parse_parameters| or |EC_KEY_parse_curve_name| instead. */ OPENSSL_EXPORT EC_KEY *d2i_ECParameters(EC_KEY **out_key, const uint8_t **inp, long len); @@ -288,7 +298,7 @@ OPENSSL_EXPORT EC_KEY *d2i_ECParameters(EC_KEY **out_key, const uint8_t **inp, * |*outp| is advanced just past the output. It returns the number of bytes in * the result, whether written or not, or a negative value on error. * - * Use |OBJ_nid2cbb| and |EC_GROUP_get_curve_name| instead. */ + * Use |EC_KEY_marshal_curve_name| instead. */ OPENSSL_EXPORT int i2d_ECParameters(const EC_KEY *key, uint8_t **outp); /* o2i_ECPublicKey parses an EC point from |len| bytes at |*inp| into @@ -311,6 +321,17 @@ OPENSSL_EXPORT int i2o_ECPublicKey(const EC_KEY *key, unsigned char **outp); #if defined(__cplusplus) } /* extern C */ + +extern "C++" { + +namespace bssl { + +BORINGSSL_MAKE_DELETER(EC_KEY, EC_KEY_free) + +} // namespace bssl + +} /* extern C++ */ + #endif #endif /* OPENSSL_HEADER_EC_KEY_H */ diff --git a/Sources/BoringSSL/include/openssl/ecdh.h b/Sources/BoringSSL/include/openssl/ecdh.h index 5fe3ae992..c16750309 100644 --- a/Sources/BoringSSL/include/openssl/ecdh.h +++ b/Sources/BoringSSL/include/openssl/ecdh.h @@ -85,10 +85,9 @@ extern "C" { * return value. Otherwise, as many bytes of the shared key as will fit are * copied directly to, at most, |outlen| bytes at |out|. It returns the number * of bytes written to |out|, or -1 on error. */ -OPENSSL_EXPORT int ECDH_compute_key(void *out, size_t outlen, - const EC_POINT *pub_key, EC_KEY *priv_key, - void *(*kdf)(const void *in, size_t inlen, - void *out, size_t *outlen)); +OPENSSL_EXPORT int ECDH_compute_key( + void *out, size_t outlen, const EC_POINT *pub_key, const EC_KEY *priv_key, + void *(*kdf)(const void *in, size_t inlen, void *out, size_t *outlen)); #if defined(__cplusplus) diff --git a/Sources/BoringSSL/include/openssl/ecdsa.h b/Sources/BoringSSL/include/openssl/ecdsa.h index a060eab34..8a158b87f 100644 --- a/Sources/BoringSSL/include/openssl/ecdsa.h +++ b/Sources/BoringSSL/include/openssl/ecdsa.h @@ -66,7 +66,7 @@ extern "C" { * Algorithm over elliptic curves. */ -/* Signing and verifing. */ +/* Signing and verifying. */ /* ECDSA_sign signs |digest_len| bytes from |digest| with |key| and writes the * resulting signature to |sig|, which must have |ECDSA_size(key)| bytes of @@ -75,15 +75,15 @@ extern "C" { * zero otherwise. */ OPENSSL_EXPORT int ECDSA_sign(int type, const uint8_t *digest, size_t digest_len, uint8_t *sig, - unsigned int *sig_len, EC_KEY *key); + unsigned int *sig_len, const EC_KEY *key); /* ECDSA_verify verifies that |sig_len| bytes from |sig| constitute a valid * signature by |key| of |digest|. (The |type| argument should be zero.) It * returns one on success or zero if the signature is invalid or an error - * occured. */ + * occurred. */ OPENSSL_EXPORT int ECDSA_verify(int type, const uint8_t *digest, size_t digest_len, const uint8_t *sig, - size_t sig_len, EC_KEY *key); + size_t sig_len, const EC_KEY *key); /* ECDSA_size returns the maximum size of an ECDSA signature using |key|. It * returns zero on error. */ @@ -109,13 +109,13 @@ OPENSSL_EXPORT void ECDSA_SIG_free(ECDSA_SIG *sig); /* ECDSA_do_sign signs |digest_len| bytes from |digest| with |key| and returns * the resulting signature structure, or NULL on error. */ OPENSSL_EXPORT ECDSA_SIG *ECDSA_do_sign(const uint8_t *digest, - size_t digest_len, EC_KEY *key); + size_t digest_len, const EC_KEY *key); /* ECDSA_do_verify verifies that |sig| constitutes a valid signature by |key| * of |digest|. It returns one on success or zero if the signature is invalid * or on error. */ OPENSSL_EXPORT int ECDSA_do_verify(const uint8_t *digest, size_t digest_len, - const ECDSA_SIG *sig, EC_KEY *key); + const ECDSA_SIG *sig, const EC_KEY *key); /* Signing with precomputation. @@ -128,22 +128,22 @@ OPENSSL_EXPORT int ECDSA_do_verify(const uint8_t *digest, size_t digest_len, /* ECDSA_sign_setup precomputes parts of an ECDSA signing operation. It sets * |*kinv| and |*rp| to the precomputed values and uses the |ctx| argument, if * not NULL. It returns one on success and zero otherwise. */ -OPENSSL_EXPORT int ECDSA_sign_setup(EC_KEY *eckey, BN_CTX *ctx, BIGNUM **kinv, - BIGNUM **rp); +OPENSSL_EXPORT int ECDSA_sign_setup(const EC_KEY *eckey, BN_CTX *ctx, + BIGNUM **kinv, BIGNUM **rp); /* ECDSA_do_sign_ex is the same as |ECDSA_do_sign| but takes precomputed values * as generated by |ECDSA_sign_setup|. */ OPENSSL_EXPORT ECDSA_SIG *ECDSA_do_sign_ex(const uint8_t *digest, size_t digest_len, const BIGNUM *kinv, const BIGNUM *rp, - EC_KEY *eckey); + const EC_KEY *eckey); /* ECDSA_sign_ex is the same as |ECDSA_sign| but takes precomputed values as * generated by |ECDSA_sign_setup|. */ OPENSSL_EXPORT int ECDSA_sign_ex(int type, const uint8_t *digest, size_t digest_len, uint8_t *sig, unsigned int *sig_len, const BIGNUM *kinv, - const BIGNUM *rp, EC_KEY *eckey); + const BIGNUM *rp, const EC_KEY *eckey); /* ASN.1 functions. */ @@ -194,6 +194,17 @@ OPENSSL_EXPORT int i2d_ECDSA_SIG(const ECDSA_SIG *sig, uint8_t **outp); #if defined(__cplusplus) } /* extern C */ + +extern "C++" { + +namespace bssl { + +BORINGSSL_MAKE_DELETER(ECDSA_SIG, ECDSA_SIG_free) + +} // namespace bssl + +} /* extern C++ */ + #endif #define ECDSA_R_BAD_SIGNATURE 100 diff --git a/Sources/BoringSSL/include/openssl/engine.h b/Sources/BoringSSL/include/openssl/engine.h index 128a2ae12..b029ef948 100644 --- a/Sources/BoringSSL/include/openssl/engine.h +++ b/Sources/BoringSSL/include/openssl/engine.h @@ -91,6 +91,17 @@ struct openssl_method_common_st { #if defined(__cplusplus) } /* extern C */ + +extern "C++" { + +namespace bssl { + +BORINGSSL_MAKE_DELETER(ENGINE, ENGINE_free) + +} // namespace bssl + +} /* extern C++ */ + #endif #define ENGINE_R_OPERATION_NOT_SUPPORTED 100 diff --git a/Sources/BoringSSL/include/openssl/err.h b/Sources/BoringSSL/include/openssl/err.h index cac50e0fb..a747b3037 100644 --- a/Sources/BoringSSL/include/openssl/err.h +++ b/Sources/BoringSSL/include/openssl/err.h @@ -120,7 +120,7 @@ extern "C" { /* Error queue handling functions. * - * Errors in OpenSSL are generally signalled by the return value of a function. + * Errors in OpenSSL are generally signaled by the return value of a function. * When a function fails it may add an entry to a per-thread error queue, * which is managed by the functions in this header. * @@ -306,7 +306,7 @@ OPENSSL_EXPORT void ERR_clear_system_error(void); ERR_put_error(ERR_LIB_SYS, 0, 0, __FILE__, __LINE__); /* ERR_put_error adds an error to the error queue, dropping the least recent - * error if neccessary for space reasons. */ + * error if necessary for space reasons. */ OPENSSL_EXPORT void ERR_put_error(int library, int unused, int reason, const char *file, unsigned line); @@ -331,14 +331,14 @@ OPENSSL_EXPORT int ERR_set_mark(void); OPENSSL_EXPORT int ERR_pop_to_mark(void); struct err_error_st { - /* file contains the filename where the error occured. */ + /* file contains the filename where the error occurred. */ const char *file; /* data contains optional data. It must be freed with |OPENSSL_free| if * |flags&ERR_FLAG_MALLOCED|. */ char *data; /* packed contains the error library and reason, as packed by ERR_PACK. */ uint32_t packed; - /* line contains the line number where the error occured. */ + /* line contains the line number where the error occurred. */ uint16_t line; /* flags contains a bitwise-OR of ERR_FLAG_* values. */ uint8_t flags; @@ -467,7 +467,7 @@ enum { #define ERR_R_OVERFLOW (5 | ERR_R_FATAL) #define ERR_PACK(lib, reason) \ - (((((uint32_t)lib) & 0xff) << 24) | ((((uint32_t)reason) & 0xfff))) + (((((uint32_t)(lib)) & 0xff) << 24) | ((((uint32_t)(reason)) & 0xfff))) #define ERR_GET_LIB(packed_error) ((int)(((packed_error) >> 24) & 0xff)) #define ERR_GET_FUNC(packed_error) 0 diff --git a/Sources/BoringSSL/include/openssl/evp.h b/Sources/BoringSSL/include/openssl/evp.h index 3db135bbc..7debbc5a3 100644 --- a/Sources/BoringSSL/include/openssl/evp.h +++ b/Sources/BoringSSL/include/openssl/evp.h @@ -69,7 +69,7 @@ #include #include #include -#include +#include #if defined(__cplusplus) extern "C" { @@ -89,8 +89,8 @@ OPENSSL_EXPORT EVP_PKEY *EVP_PKEY_new(void); * itself. */ OPENSSL_EXPORT void EVP_PKEY_free(EVP_PKEY *pkey); -/* EVP_PKEY_up_ref increments the reference count of |pkey| and returns it. */ -OPENSSL_EXPORT EVP_PKEY *EVP_PKEY_up_ref(EVP_PKEY *pkey); +/* EVP_PKEY_up_ref increments the reference count of |pkey| and returns one. */ +OPENSSL_EXPORT int EVP_PKEY_up_ref(EVP_PKEY *pkey); /* EVP_PKEY_is_opaque returns one if |pkey| is opaque. Opaque keys are backed by * custom implementations which do not expose key material and parameters. It is @@ -174,7 +174,7 @@ OPENSSL_EXPORT EC_KEY *EVP_PKEY_get1_EC_KEY(EVP_PKEY *pkey); OPENSSL_EXPORT int EVP_PKEY_assign(EVP_PKEY *pkey, int type, void *key); /* EVP_PKEY_set_type sets the type of |pkey| to |type|, which should be one of - * the |EVP_PKEY_*| values. It returns one if sucessful or zero otherwise. If + * the |EVP_PKEY_*| values. It returns one if successful or zero otherwise. If * |pkey| is NULL, it simply reports whether the type is known. */ OPENSSL_EXPORT int EVP_PKEY_set_type(EVP_PKEY *pkey, int type); @@ -250,15 +250,6 @@ OPENSSL_EXPORT int EVP_DigestSignUpdate(EVP_MD_CTX *ctx, const void *data, OPENSSL_EXPORT int EVP_DigestSignFinal(EVP_MD_CTX *ctx, uint8_t *out_sig, size_t *out_sig_len); -/* EVP_DigestSignAlgorithm encodes the signing parameters of |ctx| as an - * AlgorithmIdentifer and saves the result in |algor|. - * - * It returns one on success, or zero on error. - * - * TODO(davidben): This API should eventually lose the dependency on - * crypto/asn1/. */ -OPENSSL_EXPORT int EVP_DigestSignAlgorithm(EVP_MD_CTX *ctx, X509_ALGOR *algor); - /* Verifying */ @@ -273,18 +264,6 @@ OPENSSL_EXPORT int EVP_DigestVerifyInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx, const EVP_MD *type, ENGINE *e, EVP_PKEY *pkey); -/* EVP_DigestVerifyInitFromAlgorithm sets up |ctx| for a signature verification - * operation with public key |pkey| and parameters from |algor|. The |ctx| - * argument must have been initialised with |EVP_MD_CTX_init|. - * - * It returns one on success, or zero on error. - * - * TODO(davidben): This API should eventually lose the dependency on - * crypto/asn1/. */ -OPENSSL_EXPORT int EVP_DigestVerifyInitFromAlgorithm(EVP_MD_CTX *ctx, - X509_ALGOR *algor, - EVP_PKEY *pkey); - /* EVP_DigestVerifyUpdate appends |len| bytes from |data| to the data which * will be verified by |EVP_DigestVerifyFinal|. It returns one. */ OPENSSL_EXPORT int EVP_DigestVerifyUpdate(EVP_MD_CTX *ctx, const void *data, @@ -399,9 +378,10 @@ OPENSSL_EXPORT int PKCS5_PBKDF2_HMAC(const char *password, size_t password_len, /* PKCS5_PBKDF2_HMAC_SHA1 is the same as PKCS5_PBKDF2_HMAC, but with |digest| * fixed to |EVP_sha1|. */ OPENSSL_EXPORT int PKCS5_PBKDF2_HMAC_SHA1(const char *password, - size_t password_len, const uint8_t *salt, - size_t salt_len, unsigned iterations, - size_t key_len, uint8_t *out_key); + size_t password_len, + const uint8_t *salt, size_t salt_len, + unsigned iterations, size_t key_len, + uint8_t *out_key); /* Public key contexts. @@ -456,8 +436,8 @@ OPENSSL_EXPORT int EVP_PKEY_sign(EVP_PKEY_CTX *ctx, uint8_t *sig, * It returns one on success or zero on error. */ OPENSSL_EXPORT int EVP_PKEY_verify_init(EVP_PKEY_CTX *ctx); -/* EVP_PKEY_verify verifies that |sig_len| bytes from |sig| are a valid signature - * for |data|. +/* EVP_PKEY_verify verifies that |sig_len| bytes from |sig| are a valid + * signature for |data|. * * It returns one on success or zero on error. */ OPENSSL_EXPORT int EVP_PKEY_verify(EVP_PKEY_CTX *ctx, const uint8_t *sig, @@ -598,7 +578,10 @@ OPENSSL_EXPORT int EVP_PKEY_CTX_get_rsa_padding(EVP_PKEY_CTX *ctx, /* EVP_PKEY_CTX_set_rsa_pss_saltlen sets the length of the salt in a PSS-padded * signature. A value of -1 cause the salt to be the same length as the digest * in the signature. A value of -2 causes the salt to be the maximum length - * that will fit. Otherwise the value gives the size of the salt in bytes. + * that will fit when signing and recovered from the signature when verifying. + * Otherwise the value gives the size of the salt in bytes. + * + * If unsure, use -1. * * Returns one on success or zero on error. */ OPENSSL_EXPORT int EVP_PKEY_CTX_set_rsa_pss_saltlen(EVP_PKEY_CTX *ctx, @@ -675,6 +658,9 @@ OPENSSL_EXPORT int EVP_PKEY_CTX_get0_rsa_oaep_label(EVP_PKEY_CTX *ctx, /* OpenSSL_add_all_algorithms does nothing. */ OPENSSL_EXPORT void OpenSSL_add_all_algorithms(void); +/* OPENSSL_add_all_algorithms_conf does nothing. */ +OPENSSL_EXPORT void OPENSSL_add_all_algorithms_conf(void); + /* OpenSSL_add_all_ciphers does nothing. */ OPENSSL_EXPORT void OpenSSL_add_all_ciphers(void); @@ -719,11 +705,10 @@ OPENSSL_EXPORT int i2d_PublicKey(EVP_PKEY *key, uint8_t **outp); /* d2i_PrivateKey parses an ASN.1, DER-encoded, private key from |len| bytes at * |*inp|. If |out| is not NULL then, on exit, a pointer to the result is in - * |*out|. If |*out| is already non-NULL on entry then the result is written - * directly into |*out|, otherwise a fresh |EVP_PKEY| is allocated. However, - * one should not depend on writing into |*out| because this behaviour is - * likely to change in the future. On successful exit, |*inp| is advanced past - * the DER structure. It returns the result or NULL on error. + * |*out|. Note that, even if |*out| is already non-NULL on entry, it will not + * be written to. Rather, a fresh |EVP_PKEY| is allocated and the previous one + * is freed. On successful exit, |*inp| is advanced past the DER structure. It + * returns the result or NULL on error. * * This function tries to detect one of several formats. Instead, use * |EVP_parse_private_key| for a PrivateKeyInfo, |RSA_parse_private_key| for an @@ -740,22 +725,11 @@ OPENSSL_EXPORT EVP_PKEY *d2i_PrivateKey(int type, EVP_PKEY **out, OPENSSL_EXPORT EVP_PKEY *d2i_AutoPrivateKey(EVP_PKEY **out, const uint8_t **inp, long len); +/* EVP_PKEY_get0_DH returns NULL. */ +OPENSSL_EXPORT DH *EVP_PKEY_get0_DH(EVP_PKEY *pkey); -/* Private functions */ -/* EVP_PKEY_asn1_find returns the ASN.1 method table for the given |nid|, which - * should be one of the |EVP_PKEY_*| values. It returns NULL if |nid| is - * unknown. */ -OPENSSL_EXPORT const EVP_PKEY_ASN1_METHOD *EVP_PKEY_asn1_find(ENGINE **pengine, - int nid); - -/* EVP_PKEY_asn1_find_str returns an |EVP_PKEY_ASN1_METHOD| by matching values - * of the |len| bytes at |name|. For example, if name equals "EC" then it will - * return an ECC method. The |pengine| argument is ignored. - * - * TODO(fork): move to PEM? */ -OPENSSL_EXPORT const EVP_PKEY_ASN1_METHOD *EVP_PKEY_asn1_find_str( - ENGINE **pengine, const char *name, size_t len); +/* Private structures. */ struct evp_pkey_st { CRYPTO_refcount_t references; @@ -780,54 +754,48 @@ struct evp_pkey_st { #if defined(__cplusplus) } /* extern C */ + +extern "C++" { +namespace bssl { + +BORINGSSL_MAKE_DELETER(EVP_PKEY, EVP_PKEY_free) +BORINGSSL_MAKE_DELETER(EVP_PKEY_CTX, EVP_PKEY_CTX_free) + +} // namespace bssl + +} /* extern C++ */ + #endif #define EVP_R_BUFFER_TOO_SMALL 100 #define EVP_R_COMMAND_NOT_SUPPORTED 101 -#define EVP_R_DIFFERENT_KEY_TYPES 104 -#define EVP_R_DIFFERENT_PARAMETERS 105 -#define EVP_R_EXPECTING_AN_EC_KEY_KEY 107 -#define EVP_R_EXPECTING_A_DH_KEY 109 -#define EVP_R_EXPECTING_A_DSA_KEY 110 -#define EVP_R_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE 111 -#define EVP_R_INVALID_CURVE 112 -#define EVP_R_INVALID_DIGEST_LENGTH 113 -#define EVP_R_INVALID_DIGEST_TYPE 114 -#define EVP_R_INVALID_KEYBITS 115 -#define EVP_R_INVALID_MGF1_MD 116 -#define EVP_R_INVALID_PADDING_MODE 118 -#define EVP_R_INVALID_PSS_PARAMETERS 119 -#define EVP_R_INVALID_SALT_LENGTH 121 -#define EVP_R_INVALID_TRAILER 122 -#define EVP_R_KEYS_NOT_SET 123 -#define EVP_R_MISSING_PARAMETERS 124 -#define EVP_R_NO_DEFAULT_DIGEST 125 -#define EVP_R_NO_KEY_SET 126 -#define EVP_R_NO_MDC2_SUPPORT 127 -#define EVP_R_NO_NID_FOR_CURVE 128 -#define EVP_R_NO_OPERATION_SET 129 -#define EVP_R_NO_PARAMETERS_SET 130 -#define EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE 131 -#define EVP_R_OPERATON_NOT_INITIALIZED 132 -#define EVP_R_UNKNOWN_DIGEST 133 -#define EVP_R_UNKNOWN_MASK_DIGEST 134 -#define EVP_R_UNSUPPORTED_ALGORITHM 138 -#define EVP_R_UNSUPPORTED_MASK_ALGORITHM 139 -#define EVP_R_UNSUPPORTED_MASK_PARAMETER 140 -#define EVP_R_EXPECTING_AN_RSA_KEY 141 -#define EVP_R_INVALID_OPERATION 142 -#define EVP_R_DECODE_ERROR 143 -#define EVP_R_INVALID_PSS_SALTLEN 144 -#define EVP_R_UNKNOWN_PUBLIC_KEY_TYPE 145 -#define EVP_R_CONTEXT_NOT_INITIALISED 146 -#define EVP_R_DIGEST_AND_KEY_TYPE_NOT_SUPPORTED 147 -#define EVP_R_WRONG_PUBLIC_KEY_TYPE 148 -#define EVP_R_UNKNOWN_SIGNATURE_ALGORITHM 149 -#define EVP_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM 150 -#define EVP_R_BN_DECODE_ERROR 151 -#define EVP_R_PARAMETER_ENCODING_ERROR 152 -#define EVP_R_UNSUPPORTED_PUBLIC_KEY_TYPE 153 -#define EVP_R_UNSUPPORTED_SIGNATURE_TYPE 154 -#define EVP_R_ENCODE_ERROR 155 +#define EVP_R_DECODE_ERROR 102 +#define EVP_R_DIFFERENT_KEY_TYPES 103 +#define EVP_R_DIFFERENT_PARAMETERS 104 +#define EVP_R_ENCODE_ERROR 105 +#define EVP_R_EXPECTING_AN_EC_KEY_KEY 106 +#define EVP_R_EXPECTING_AN_RSA_KEY 107 +#define EVP_R_EXPECTING_A_DSA_KEY 108 +#define EVP_R_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE 109 +#define EVP_R_INVALID_DIGEST_LENGTH 110 +#define EVP_R_INVALID_DIGEST_TYPE 111 +#define EVP_R_INVALID_KEYBITS 112 +#define EVP_R_INVALID_MGF1_MD 113 +#define EVP_R_INVALID_OPERATION 114 +#define EVP_R_INVALID_PADDING_MODE 115 +#define EVP_R_INVALID_PSS_SALTLEN 116 +#define EVP_R_KEYS_NOT_SET 117 +#define EVP_R_MISSING_PARAMETERS 118 +#define EVP_R_NO_DEFAULT_DIGEST 119 +#define EVP_R_NO_KEY_SET 120 +#define EVP_R_NO_MDC2_SUPPORT 121 +#define EVP_R_NO_NID_FOR_CURVE 122 +#define EVP_R_NO_OPERATION_SET 123 +#define EVP_R_NO_PARAMETERS_SET 124 +#define EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE 125 +#define EVP_R_OPERATON_NOT_INITIALIZED 126 +#define EVP_R_UNKNOWN_PUBLIC_KEY_TYPE 127 +#define EVP_R_UNSUPPORTED_ALGORITHM 128 +#define EVP_R_UNSUPPORTED_PUBLIC_KEY_TYPE 129 #endif /* OPENSSL_HEADER_EVP_H */ diff --git a/Sources/BoringSSL/include/openssl/hkdf.h b/Sources/BoringSSL/include/openssl/hkdf.h index b7a0dc25e..bffb01ec7 100644 --- a/Sources/BoringSSL/include/openssl/hkdf.h +++ b/Sources/BoringSSL/include/openssl/hkdf.h @@ -17,14 +17,17 @@ #include -#ifdef __cplusplus +#if defined(__cplusplus) extern "C" { #endif -/* Computes HKDF (as specified by RFC 5869) of initial keying material |secret| - * with |salt| and |info| using |digest|, and outputs |out_len| bytes to - * |out_key|. It returns one on success and zero on error. +/* HKDF. */ + + +/* HKDF computes HKDF (as specified by RFC 5869) of initial keying material + * |secret| with |salt| and |info| using |digest|, and outputs |out_len| bytes + * to |out_key|. It returns one on success and zero on error. * * HKDF is an Extract-and-Expand algorithm. It does not do any key stretching, * and as such, is not suited to be used alone to generate a key from a @@ -34,6 +37,23 @@ OPENSSL_EXPORT int HKDF(uint8_t *out_key, size_t out_len, const EVP_MD *digest, const uint8_t *salt, size_t salt_len, const uint8_t *info, size_t info_len); +/* HKDF_extract computes a HKDF PRK (as specified by RFC 5869) from initial + * keying material |secret| and salt |salt| using |digest|, and outputs + * |out_len| bytes to |out_key|. The maximum output size is |EVP_MAX_MD_SIZE|. + * It returns one on success and zero on error. */ +OPENSSL_EXPORT int HKDF_extract(uint8_t *out_key, size_t *out_len, + const EVP_MD *digest, const uint8_t *secret, + size_t secret_len, const uint8_t *salt, + size_t salt_len); + +/* HKDF_expand computes a HKDF OKM (as specified by RFC 5869) of length + * |out_len| from the PRK |prk| and info |info| using |digest|, and outputs + * the result to |out_key|. It returns one on success and zero on error. */ +OPENSSL_EXPORT int HKDF_expand(uint8_t *out_key, size_t out_len, + const EVP_MD *digest, const uint8_t *prk, + size_t prk_len, const uint8_t *info, + size_t info_len); + #if defined(__cplusplus) } /* extern C */ diff --git a/Sources/BoringSSL/include/openssl/hmac.h b/Sources/BoringSSL/include/openssl/hmac.h index e521212d4..e4cc04e6e 100644 --- a/Sources/BoringSSL/include/openssl/hmac.h +++ b/Sources/BoringSSL/include/openssl/hmac.h @@ -74,8 +74,9 @@ extern "C" { /* HMAC calculates the HMAC of |data_len| bytes of |data|, using the given key * and hash function, and writes the result to |out|. On entry, |out| must - * contain |EVP_MAX_MD_SIZE| bytes of space. The actual length of the result is - * written to |*out_len|. It returns |out| or NULL on error. */ + * contain at least |EVP_MD_size| bytes of space. The actual length of the + * result is written to |*out_len|. An output size of |EVP_MAX_MD_SIZE| will + * always be large enough. It returns |out| or NULL on error. */ OPENSSL_EXPORT uint8_t *HMAC(const EVP_MD *evp_md, const void *key, size_t key_len, const uint8_t *data, size_t data_len, uint8_t *out, @@ -112,8 +113,9 @@ OPENSSL_EXPORT int HMAC_Update(HMAC_CTX *ctx, const uint8_t *data, /* HMAC_Final completes the HMAC operation in |ctx| and writes the result to * |out| and the sets |*out_len| to the length of the result. On entry, |out| - * must contain at least |EVP_MAX_MD_SIZE| bytes of space. It returns one on - * success or zero on error. */ + * must contain at least |HMAC_size| bytes of space. An output size of + * |EVP_MAX_MD_SIZE| will always be large enough. It returns one on success or + * zero on error. */ OPENSSL_EXPORT int HMAC_Final(HMAC_CTX *ctx, uint8_t *out, unsigned int *out_len); @@ -143,8 +145,6 @@ OPENSSL_EXPORT int HMAC_CTX_copy(HMAC_CTX *dest, const HMAC_CTX *src); /* Private functions */ -#define HMAC_MAX_MD_CBLOCK 128 /* largest known is SHA512 */ - struct hmac_ctx_st { const EVP_MD *md; EVP_MD_CTX md_ctx; @@ -155,6 +155,20 @@ struct hmac_ctx_st { #if defined(__cplusplus) } /* extern C */ + +#if !defined(BORINGSSL_NO_CXX) +extern "C++" { + +namespace bssl { + +using ScopedHMAC_CTX = + internal::StackAllocated; + +} // namespace bssl + +} // extern C++ +#endif + #endif #endif /* OPENSSL_HEADER_HMAC_H */ diff --git a/Sources/BoringSSL/include/openssl/lhash.h b/Sources/BoringSSL/include/openssl/lhash.h index 0d6d3aef1..b95d4f21b 100644 --- a/Sources/BoringSSL/include/openssl/lhash.h +++ b/Sources/BoringSSL/include/openssl/lhash.h @@ -97,6 +97,7 @@ extern "C" { * * LHASH_OF:ASN1_OBJECT * LHASH_OF:CONF_VALUE + * LHASH_OF:CRYPTO_BUFFER * LHASH_OF:SSL_SESSION */ #define IN_LHASH_H @@ -143,9 +144,7 @@ typedef struct lhash_st { lhash_hash_func hash; } _LHASH; -/* lh_new returns a new, empty hash table or NULL on error. If |comp| is NULL, - * |strcmp| will be used. If |hash| is NULL, a generic hash function will be - * used. */ +/* lh_new returns a new, empty hash table or NULL on error. */ OPENSSL_EXPORT _LHASH *lh_new(lhash_hash_func hash, lhash_cmp_func comp); /* lh_free frees the hash table itself but none of the elements. See diff --git a/Sources/BoringSSL/include/openssl/lhash_macros.h b/Sources/BoringSSL/include/openssl/lhash_macros.h index 1d981073e..ca349a975 100644 --- a/Sources/BoringSSL/include/openssl/lhash_macros.h +++ b/Sources/BoringSSL/include/openssl/lhash_macros.h @@ -17,11 +17,11 @@ #endif /* ASN1_OBJECT */ -#define lh_ASN1_OBJECT_new(hash, comp) \ - ((LHASH_OF(ASN1_OBJECT) *)lh_new( \ - CHECKED_CAST(lhash_hash_func, uint32_t (*)(const ASN1_OBJECT *), hash), \ - CHECKED_CAST(lhash_cmp_func, \ - int (*)(const ASN1_OBJECT *a, const ASN1_OBJECT *b), \ +#define lh_ASN1_OBJECT_new(hash, comp) \ + ((LHASH_OF(ASN1_OBJECT) *)lh_new( \ + CHECKED_CAST(lhash_hash_func, uint32_t(*)(const ASN1_OBJECT *), hash), \ + CHECKED_CAST(lhash_cmp_func, \ + int (*)(const ASN1_OBJECT *a, const ASN1_OBJECT *b), \ comp))) #define lh_ASN1_OBJECT_free(lh) \ @@ -55,11 +55,12 @@ void (*)(ASN1_OBJECT *, void *), func), \ arg); + /* CONF_VALUE */ -#define lh_CONF_VALUE_new(hash, comp) \ - ((LHASH_OF(CONF_VALUE) *)lh_new( \ - CHECKED_CAST(lhash_hash_func, uint32_t (*)(const CONF_VALUE *), hash), \ - CHECKED_CAST(lhash_cmp_func, \ +#define lh_CONF_VALUE_new(hash, comp) \ + ((LHASH_OF(CONF_VALUE) *)lh_new( \ + CHECKED_CAST(lhash_hash_func, uint32_t(*)(const CONF_VALUE *), hash), \ + CHECKED_CAST(lhash_cmp_func, \ int (*)(const CONF_VALUE *a, const CONF_VALUE *b), comp))) #define lh_CONF_VALUE_free(lh) \ @@ -92,12 +93,53 @@ void (*)(CONF_VALUE *, void *), func), \ arg); + +/* CRYPTO_BUFFER */ +#define lh_CRYPTO_BUFFER_new(hash, comp) \ + ((LHASH_OF(CRYPTO_BUFFER) *)lh_new( \ + CHECKED_CAST(lhash_hash_func, uint32_t(*)(const CRYPTO_BUFFER *), hash), \ + CHECKED_CAST(lhash_cmp_func, \ + int (*)(const CRYPTO_BUFFER *a, const CRYPTO_BUFFER *b), \ + comp))) + +#define lh_CRYPTO_BUFFER_free(lh) \ + lh_free(CHECKED_CAST(_LHASH *, LHASH_OF(CRYPTO_BUFFER) *, lh)); + +#define lh_CRYPTO_BUFFER_num_items(lh) \ + lh_num_items(CHECKED_CAST(_LHASH *, LHASH_OF(CRYPTO_BUFFER) *, lh)) + +#define lh_CRYPTO_BUFFER_retrieve(lh, data) \ + ((CRYPTO_BUFFER *)lh_retrieve( \ + CHECKED_CAST(_LHASH *, LHASH_OF(CRYPTO_BUFFER) *, lh), \ + CHECKED_CAST(void *, CRYPTO_BUFFER *, data))) + +#define lh_CRYPTO_BUFFER_insert(lh, old_data, data) \ + lh_insert(CHECKED_CAST(_LHASH *, LHASH_OF(CRYPTO_BUFFER) *, lh), \ + CHECKED_CAST(void **, CRYPTO_BUFFER **, old_data), \ + CHECKED_CAST(void *, CRYPTO_BUFFER *, data)) + +#define lh_CRYPTO_BUFFER_delete(lh, data) \ + ((CRYPTO_BUFFER *)lh_delete( \ + CHECKED_CAST(_LHASH *, LHASH_OF(CRYPTO_BUFFER) *, lh), \ + CHECKED_CAST(void *, CRYPTO_BUFFER *, data))) + +#define lh_CRYPTO_BUFFER_doall(lh, func) \ + lh_doall(CHECKED_CAST(_LHASH *, LHASH_OF(CRYPTO_BUFFER) *, lh), \ + CHECKED_CAST(void (*)(void *), void (*)(CRYPTO_BUFFER *), func)); + +#define lh_CRYPTO_BUFFER_doall_arg(lh, func, arg) \ + lh_doall_arg(CHECKED_CAST(_LHASH *, LHASH_OF(CRYPTO_BUFFER) *, lh), \ + CHECKED_CAST(void (*)(void *, void *), \ + void (*)(CRYPTO_BUFFER *, void *), func), \ + arg); + + /* SSL_SESSION */ -#define lh_SSL_SESSION_new(hash, comp) \ - ((LHASH_OF(SSL_SESSION) *)lh_new( \ - CHECKED_CAST(lhash_hash_func, uint32_t (*)(const SSL_SESSION *), hash), \ - CHECKED_CAST(lhash_cmp_func, \ - int (*)(const SSL_SESSION *a, const SSL_SESSION *b), \ +#define lh_SSL_SESSION_new(hash, comp) \ + ((LHASH_OF(SSL_SESSION) *)lh_new( \ + CHECKED_CAST(lhash_hash_func, uint32_t(*)(const SSL_SESSION *), hash), \ + CHECKED_CAST(lhash_cmp_func, \ + int (*)(const SSL_SESSION *a, const SSL_SESSION *b), \ comp))) #define lh_SSL_SESSION_free(lh) \ diff --git a/Sources/BoringSSL/include/openssl/md4.h b/Sources/BoringSSL/include/openssl/md4.h index 93c7af831..b66fcb0f3 100644 --- a/Sources/BoringSSL/include/openssl/md4.h +++ b/Sources/BoringSSL/include/openssl/md4.h @@ -83,6 +83,10 @@ OPENSSL_EXPORT int MD4_Update(MD4_CTX *md4, const void *data, size_t len); * returns one. */ OPENSSL_EXPORT int MD4_Final(uint8_t *md, MD4_CTX *md4); +/* MD4 writes the digest of |len| bytes from |data| to |out| and returns |out|. + * There must be at least |MD4_DIGEST_LENGTH| bytes of space in |out|. */ +OPENSSL_EXPORT uint8_t *MD4(const uint8_t *data, size_t len, uint8_t *out); + /* MD4_Transform is a low-level function that performs a single, MD4 block * transformation using the state from |md4| and 64 bytes from |block|. */ OPENSSL_EXPORT void MD4_Transform(MD4_CTX *md4, const uint8_t *block); diff --git a/Sources/BoringSSL/include/openssl/mem.h b/Sources/BoringSSL/include/openssl/mem.h index ba48f078a..5d96a2d72 100644 --- a/Sources/BoringSSL/include/openssl/mem.h +++ b/Sources/BoringSSL/include/openssl/mem.h @@ -124,8 +124,27 @@ OPENSSL_EXPORT int BIO_vsnprintf(char *buf, size_t n, const char *format, OPENSSL_PRINTF_FORMAT_FUNC(3, 0); +/* Deprecated functions. */ + +#define CRYPTO_malloc OPENSSL_malloc +#define CRYPTO_realloc OPENSSL_realloc +#define CRYPTO_free OPENSSL_free + + #if defined(__cplusplus) } /* extern C */ + +extern "C++" { + +namespace bssl { + +BORINGSSL_MAKE_DELETER(char, OPENSSL_free) +BORINGSSL_MAKE_DELETER(uint8_t, OPENSSL_free) + +} // namespace bssl + +} /* extern C++ */ + #endif #endif /* OPENSSL_HEADER_MEM_H */ diff --git a/Sources/BoringSSL/include/openssl/nid.h b/Sources/BoringSSL/include/openssl/nid.h new file mode 100644 index 000000000..4270dc1b4 --- /dev/null +++ b/Sources/BoringSSL/include/openssl/nid.h @@ -0,0 +1,4199 @@ +/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +/* This file is generated by crypto/obj/objects.go. */ + +#ifndef OPENSSL_HEADER_NID_H +#define OPENSSL_HEADER_NID_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +/* The nid library provides numbered values for ASN.1 object identifiers and + * other symbols. These values are used by other libraries to identify + * cryptographic primitives. + * + * A separate objects library, obj.h, provides functions for converting between + * nids and object identifiers. However it depends on large internal tables with + * the encodings of every nid defined. Consumers concerned with binary size + * should instead embed the encodings of the few consumed OIDs and compare + * against those. + * + * These values should not be used outside of a single process; they are not + * stable identifiers. */ + +#define SN_undef "UNDEF" +#define LN_undef "undefined" +#define NID_undef 0 +#define OBJ_undef 0L + +#define SN_rsadsi "rsadsi" +#define LN_rsadsi "RSA Data Security, Inc." +#define NID_rsadsi 1 +#define OBJ_rsadsi 1L, 2L, 840L, 113549L + +#define SN_pkcs "pkcs" +#define LN_pkcs "RSA Data Security, Inc. PKCS" +#define NID_pkcs 2 +#define OBJ_pkcs 1L, 2L, 840L, 113549L, 1L + +#define SN_md2 "MD2" +#define LN_md2 "md2" +#define NID_md2 3 +#define OBJ_md2 1L, 2L, 840L, 113549L, 2L, 2L + +#define SN_md5 "MD5" +#define LN_md5 "md5" +#define NID_md5 4 +#define OBJ_md5 1L, 2L, 840L, 113549L, 2L, 5L + +#define SN_rc4 "RC4" +#define LN_rc4 "rc4" +#define NID_rc4 5 +#define OBJ_rc4 1L, 2L, 840L, 113549L, 3L, 4L + +#define LN_rsaEncryption "rsaEncryption" +#define NID_rsaEncryption 6 +#define OBJ_rsaEncryption 1L, 2L, 840L, 113549L, 1L, 1L, 1L + +#define SN_md2WithRSAEncryption "RSA-MD2" +#define LN_md2WithRSAEncryption "md2WithRSAEncryption" +#define NID_md2WithRSAEncryption 7 +#define OBJ_md2WithRSAEncryption 1L, 2L, 840L, 113549L, 1L, 1L, 2L + +#define SN_md5WithRSAEncryption "RSA-MD5" +#define LN_md5WithRSAEncryption "md5WithRSAEncryption" +#define NID_md5WithRSAEncryption 8 +#define OBJ_md5WithRSAEncryption 1L, 2L, 840L, 113549L, 1L, 1L, 4L + +#define SN_pbeWithMD2AndDES_CBC "PBE-MD2-DES" +#define LN_pbeWithMD2AndDES_CBC "pbeWithMD2AndDES-CBC" +#define NID_pbeWithMD2AndDES_CBC 9 +#define OBJ_pbeWithMD2AndDES_CBC 1L, 2L, 840L, 113549L, 1L, 5L, 1L + +#define SN_pbeWithMD5AndDES_CBC "PBE-MD5-DES" +#define LN_pbeWithMD5AndDES_CBC "pbeWithMD5AndDES-CBC" +#define NID_pbeWithMD5AndDES_CBC 10 +#define OBJ_pbeWithMD5AndDES_CBC 1L, 2L, 840L, 113549L, 1L, 5L, 3L + +#define SN_X500 "X500" +#define LN_X500 "directory services (X.500)" +#define NID_X500 11 +#define OBJ_X500 2L, 5L + +#define SN_X509 "X509" +#define NID_X509 12 +#define OBJ_X509 2L, 5L, 4L + +#define SN_commonName "CN" +#define LN_commonName "commonName" +#define NID_commonName 13 +#define OBJ_commonName 2L, 5L, 4L, 3L + +#define SN_countryName "C" +#define LN_countryName "countryName" +#define NID_countryName 14 +#define OBJ_countryName 2L, 5L, 4L, 6L + +#define SN_localityName "L" +#define LN_localityName "localityName" +#define NID_localityName 15 +#define OBJ_localityName 2L, 5L, 4L, 7L + +#define SN_stateOrProvinceName "ST" +#define LN_stateOrProvinceName "stateOrProvinceName" +#define NID_stateOrProvinceName 16 +#define OBJ_stateOrProvinceName 2L, 5L, 4L, 8L + +#define SN_organizationName "O" +#define LN_organizationName "organizationName" +#define NID_organizationName 17 +#define OBJ_organizationName 2L, 5L, 4L, 10L + +#define SN_organizationalUnitName "OU" +#define LN_organizationalUnitName "organizationalUnitName" +#define NID_organizationalUnitName 18 +#define OBJ_organizationalUnitName 2L, 5L, 4L, 11L + +#define SN_rsa "RSA" +#define LN_rsa "rsa" +#define NID_rsa 19 +#define OBJ_rsa 2L, 5L, 8L, 1L, 1L + +#define SN_pkcs7 "pkcs7" +#define NID_pkcs7 20 +#define OBJ_pkcs7 1L, 2L, 840L, 113549L, 1L, 7L + +#define LN_pkcs7_data "pkcs7-data" +#define NID_pkcs7_data 21 +#define OBJ_pkcs7_data 1L, 2L, 840L, 113549L, 1L, 7L, 1L + +#define LN_pkcs7_signed "pkcs7-signedData" +#define NID_pkcs7_signed 22 +#define OBJ_pkcs7_signed 1L, 2L, 840L, 113549L, 1L, 7L, 2L + +#define LN_pkcs7_enveloped "pkcs7-envelopedData" +#define NID_pkcs7_enveloped 23 +#define OBJ_pkcs7_enveloped 1L, 2L, 840L, 113549L, 1L, 7L, 3L + +#define LN_pkcs7_signedAndEnveloped "pkcs7-signedAndEnvelopedData" +#define NID_pkcs7_signedAndEnveloped 24 +#define OBJ_pkcs7_signedAndEnveloped 1L, 2L, 840L, 113549L, 1L, 7L, 4L + +#define LN_pkcs7_digest "pkcs7-digestData" +#define NID_pkcs7_digest 25 +#define OBJ_pkcs7_digest 1L, 2L, 840L, 113549L, 1L, 7L, 5L + +#define LN_pkcs7_encrypted "pkcs7-encryptedData" +#define NID_pkcs7_encrypted 26 +#define OBJ_pkcs7_encrypted 1L, 2L, 840L, 113549L, 1L, 7L, 6L + +#define SN_pkcs3 "pkcs3" +#define NID_pkcs3 27 +#define OBJ_pkcs3 1L, 2L, 840L, 113549L, 1L, 3L + +#define LN_dhKeyAgreement "dhKeyAgreement" +#define NID_dhKeyAgreement 28 +#define OBJ_dhKeyAgreement 1L, 2L, 840L, 113549L, 1L, 3L, 1L + +#define SN_des_ecb "DES-ECB" +#define LN_des_ecb "des-ecb" +#define NID_des_ecb 29 +#define OBJ_des_ecb 1L, 3L, 14L, 3L, 2L, 6L + +#define SN_des_cfb64 "DES-CFB" +#define LN_des_cfb64 "des-cfb" +#define NID_des_cfb64 30 +#define OBJ_des_cfb64 1L, 3L, 14L, 3L, 2L, 9L + +#define SN_des_cbc "DES-CBC" +#define LN_des_cbc "des-cbc" +#define NID_des_cbc 31 +#define OBJ_des_cbc 1L, 3L, 14L, 3L, 2L, 7L + +#define SN_des_ede_ecb "DES-EDE" +#define LN_des_ede_ecb "des-ede" +#define NID_des_ede_ecb 32 +#define OBJ_des_ede_ecb 1L, 3L, 14L, 3L, 2L, 17L + +#define SN_des_ede3_ecb "DES-EDE3" +#define LN_des_ede3_ecb "des-ede3" +#define NID_des_ede3_ecb 33 + +#define SN_idea_cbc "IDEA-CBC" +#define LN_idea_cbc "idea-cbc" +#define NID_idea_cbc 34 +#define OBJ_idea_cbc 1L, 3L, 6L, 1L, 4L, 1L, 188L, 7L, 1L, 1L, 2L + +#define SN_idea_cfb64 "IDEA-CFB" +#define LN_idea_cfb64 "idea-cfb" +#define NID_idea_cfb64 35 + +#define SN_idea_ecb "IDEA-ECB" +#define LN_idea_ecb "idea-ecb" +#define NID_idea_ecb 36 + +#define SN_rc2_cbc "RC2-CBC" +#define LN_rc2_cbc "rc2-cbc" +#define NID_rc2_cbc 37 +#define OBJ_rc2_cbc 1L, 2L, 840L, 113549L, 3L, 2L + +#define SN_rc2_ecb "RC2-ECB" +#define LN_rc2_ecb "rc2-ecb" +#define NID_rc2_ecb 38 + +#define SN_rc2_cfb64 "RC2-CFB" +#define LN_rc2_cfb64 "rc2-cfb" +#define NID_rc2_cfb64 39 + +#define SN_rc2_ofb64 "RC2-OFB" +#define LN_rc2_ofb64 "rc2-ofb" +#define NID_rc2_ofb64 40 + +#define SN_sha "SHA" +#define LN_sha "sha" +#define NID_sha 41 +#define OBJ_sha 1L, 3L, 14L, 3L, 2L, 18L + +#define SN_shaWithRSAEncryption "RSA-SHA" +#define LN_shaWithRSAEncryption "shaWithRSAEncryption" +#define NID_shaWithRSAEncryption 42 +#define OBJ_shaWithRSAEncryption 1L, 3L, 14L, 3L, 2L, 15L + +#define SN_des_ede_cbc "DES-EDE-CBC" +#define LN_des_ede_cbc "des-ede-cbc" +#define NID_des_ede_cbc 43 + +#define SN_des_ede3_cbc "DES-EDE3-CBC" +#define LN_des_ede3_cbc "des-ede3-cbc" +#define NID_des_ede3_cbc 44 +#define OBJ_des_ede3_cbc 1L, 2L, 840L, 113549L, 3L, 7L + +#define SN_des_ofb64 "DES-OFB" +#define LN_des_ofb64 "des-ofb" +#define NID_des_ofb64 45 +#define OBJ_des_ofb64 1L, 3L, 14L, 3L, 2L, 8L + +#define SN_idea_ofb64 "IDEA-OFB" +#define LN_idea_ofb64 "idea-ofb" +#define NID_idea_ofb64 46 + +#define SN_pkcs9 "pkcs9" +#define NID_pkcs9 47 +#define OBJ_pkcs9 1L, 2L, 840L, 113549L, 1L, 9L + +#define LN_pkcs9_emailAddress "emailAddress" +#define NID_pkcs9_emailAddress 48 +#define OBJ_pkcs9_emailAddress 1L, 2L, 840L, 113549L, 1L, 9L, 1L + +#define LN_pkcs9_unstructuredName "unstructuredName" +#define NID_pkcs9_unstructuredName 49 +#define OBJ_pkcs9_unstructuredName 1L, 2L, 840L, 113549L, 1L, 9L, 2L + +#define LN_pkcs9_contentType "contentType" +#define NID_pkcs9_contentType 50 +#define OBJ_pkcs9_contentType 1L, 2L, 840L, 113549L, 1L, 9L, 3L + +#define LN_pkcs9_messageDigest "messageDigest" +#define NID_pkcs9_messageDigest 51 +#define OBJ_pkcs9_messageDigest 1L, 2L, 840L, 113549L, 1L, 9L, 4L + +#define LN_pkcs9_signingTime "signingTime" +#define NID_pkcs9_signingTime 52 +#define OBJ_pkcs9_signingTime 1L, 2L, 840L, 113549L, 1L, 9L, 5L + +#define LN_pkcs9_countersignature "countersignature" +#define NID_pkcs9_countersignature 53 +#define OBJ_pkcs9_countersignature 1L, 2L, 840L, 113549L, 1L, 9L, 6L + +#define LN_pkcs9_challengePassword "challengePassword" +#define NID_pkcs9_challengePassword 54 +#define OBJ_pkcs9_challengePassword 1L, 2L, 840L, 113549L, 1L, 9L, 7L + +#define LN_pkcs9_unstructuredAddress "unstructuredAddress" +#define NID_pkcs9_unstructuredAddress 55 +#define OBJ_pkcs9_unstructuredAddress 1L, 2L, 840L, 113549L, 1L, 9L, 8L + +#define LN_pkcs9_extCertAttributes "extendedCertificateAttributes" +#define NID_pkcs9_extCertAttributes 56 +#define OBJ_pkcs9_extCertAttributes 1L, 2L, 840L, 113549L, 1L, 9L, 9L + +#define SN_netscape "Netscape" +#define LN_netscape "Netscape Communications Corp." +#define NID_netscape 57 +#define OBJ_netscape 2L, 16L, 840L, 1L, 113730L + +#define SN_netscape_cert_extension "nsCertExt" +#define LN_netscape_cert_extension "Netscape Certificate Extension" +#define NID_netscape_cert_extension 58 +#define OBJ_netscape_cert_extension 2L, 16L, 840L, 1L, 113730L, 1L + +#define SN_netscape_data_type "nsDataType" +#define LN_netscape_data_type "Netscape Data Type" +#define NID_netscape_data_type 59 +#define OBJ_netscape_data_type 2L, 16L, 840L, 1L, 113730L, 2L + +#define SN_des_ede_cfb64 "DES-EDE-CFB" +#define LN_des_ede_cfb64 "des-ede-cfb" +#define NID_des_ede_cfb64 60 + +#define SN_des_ede3_cfb64 "DES-EDE3-CFB" +#define LN_des_ede3_cfb64 "des-ede3-cfb" +#define NID_des_ede3_cfb64 61 + +#define SN_des_ede_ofb64 "DES-EDE-OFB" +#define LN_des_ede_ofb64 "des-ede-ofb" +#define NID_des_ede_ofb64 62 + +#define SN_des_ede3_ofb64 "DES-EDE3-OFB" +#define LN_des_ede3_ofb64 "des-ede3-ofb" +#define NID_des_ede3_ofb64 63 + +#define SN_sha1 "SHA1" +#define LN_sha1 "sha1" +#define NID_sha1 64 +#define OBJ_sha1 1L, 3L, 14L, 3L, 2L, 26L + +#define SN_sha1WithRSAEncryption "RSA-SHA1" +#define LN_sha1WithRSAEncryption "sha1WithRSAEncryption" +#define NID_sha1WithRSAEncryption 65 +#define OBJ_sha1WithRSAEncryption 1L, 2L, 840L, 113549L, 1L, 1L, 5L + +#define SN_dsaWithSHA "DSA-SHA" +#define LN_dsaWithSHA "dsaWithSHA" +#define NID_dsaWithSHA 66 +#define OBJ_dsaWithSHA 1L, 3L, 14L, 3L, 2L, 13L + +#define SN_dsa_2 "DSA-old" +#define LN_dsa_2 "dsaEncryption-old" +#define NID_dsa_2 67 +#define OBJ_dsa_2 1L, 3L, 14L, 3L, 2L, 12L + +#define SN_pbeWithSHA1AndRC2_CBC "PBE-SHA1-RC2-64" +#define LN_pbeWithSHA1AndRC2_CBC "pbeWithSHA1AndRC2-CBC" +#define NID_pbeWithSHA1AndRC2_CBC 68 +#define OBJ_pbeWithSHA1AndRC2_CBC 1L, 2L, 840L, 113549L, 1L, 5L, 11L + +#define LN_id_pbkdf2 "PBKDF2" +#define NID_id_pbkdf2 69 +#define OBJ_id_pbkdf2 1L, 2L, 840L, 113549L, 1L, 5L, 12L + +#define SN_dsaWithSHA1_2 "DSA-SHA1-old" +#define LN_dsaWithSHA1_2 "dsaWithSHA1-old" +#define NID_dsaWithSHA1_2 70 +#define OBJ_dsaWithSHA1_2 1L, 3L, 14L, 3L, 2L, 27L + +#define SN_netscape_cert_type "nsCertType" +#define LN_netscape_cert_type "Netscape Cert Type" +#define NID_netscape_cert_type 71 +#define OBJ_netscape_cert_type 2L, 16L, 840L, 1L, 113730L, 1L, 1L + +#define SN_netscape_base_url "nsBaseUrl" +#define LN_netscape_base_url "Netscape Base Url" +#define NID_netscape_base_url 72 +#define OBJ_netscape_base_url 2L, 16L, 840L, 1L, 113730L, 1L, 2L + +#define SN_netscape_revocation_url "nsRevocationUrl" +#define LN_netscape_revocation_url "Netscape Revocation Url" +#define NID_netscape_revocation_url 73 +#define OBJ_netscape_revocation_url 2L, 16L, 840L, 1L, 113730L, 1L, 3L + +#define SN_netscape_ca_revocation_url "nsCaRevocationUrl" +#define LN_netscape_ca_revocation_url "Netscape CA Revocation Url" +#define NID_netscape_ca_revocation_url 74 +#define OBJ_netscape_ca_revocation_url 2L, 16L, 840L, 1L, 113730L, 1L, 4L + +#define SN_netscape_renewal_url "nsRenewalUrl" +#define LN_netscape_renewal_url "Netscape Renewal Url" +#define NID_netscape_renewal_url 75 +#define OBJ_netscape_renewal_url 2L, 16L, 840L, 1L, 113730L, 1L, 7L + +#define SN_netscape_ca_policy_url "nsCaPolicyUrl" +#define LN_netscape_ca_policy_url "Netscape CA Policy Url" +#define NID_netscape_ca_policy_url 76 +#define OBJ_netscape_ca_policy_url 2L, 16L, 840L, 1L, 113730L, 1L, 8L + +#define SN_netscape_ssl_server_name "nsSslServerName" +#define LN_netscape_ssl_server_name "Netscape SSL Server Name" +#define NID_netscape_ssl_server_name 77 +#define OBJ_netscape_ssl_server_name 2L, 16L, 840L, 1L, 113730L, 1L, 12L + +#define SN_netscape_comment "nsComment" +#define LN_netscape_comment "Netscape Comment" +#define NID_netscape_comment 78 +#define OBJ_netscape_comment 2L, 16L, 840L, 1L, 113730L, 1L, 13L + +#define SN_netscape_cert_sequence "nsCertSequence" +#define LN_netscape_cert_sequence "Netscape Certificate Sequence" +#define NID_netscape_cert_sequence 79 +#define OBJ_netscape_cert_sequence 2L, 16L, 840L, 1L, 113730L, 2L, 5L + +#define SN_desx_cbc "DESX-CBC" +#define LN_desx_cbc "desx-cbc" +#define NID_desx_cbc 80 + +#define SN_id_ce "id-ce" +#define NID_id_ce 81 +#define OBJ_id_ce 2L, 5L, 29L + +#define SN_subject_key_identifier "subjectKeyIdentifier" +#define LN_subject_key_identifier "X509v3 Subject Key Identifier" +#define NID_subject_key_identifier 82 +#define OBJ_subject_key_identifier 2L, 5L, 29L, 14L + +#define SN_key_usage "keyUsage" +#define LN_key_usage "X509v3 Key Usage" +#define NID_key_usage 83 +#define OBJ_key_usage 2L, 5L, 29L, 15L + +#define SN_private_key_usage_period "privateKeyUsagePeriod" +#define LN_private_key_usage_period "X509v3 Private Key Usage Period" +#define NID_private_key_usage_period 84 +#define OBJ_private_key_usage_period 2L, 5L, 29L, 16L + +#define SN_subject_alt_name "subjectAltName" +#define LN_subject_alt_name "X509v3 Subject Alternative Name" +#define NID_subject_alt_name 85 +#define OBJ_subject_alt_name 2L, 5L, 29L, 17L + +#define SN_issuer_alt_name "issuerAltName" +#define LN_issuer_alt_name "X509v3 Issuer Alternative Name" +#define NID_issuer_alt_name 86 +#define OBJ_issuer_alt_name 2L, 5L, 29L, 18L + +#define SN_basic_constraints "basicConstraints" +#define LN_basic_constraints "X509v3 Basic Constraints" +#define NID_basic_constraints 87 +#define OBJ_basic_constraints 2L, 5L, 29L, 19L + +#define SN_crl_number "crlNumber" +#define LN_crl_number "X509v3 CRL Number" +#define NID_crl_number 88 +#define OBJ_crl_number 2L, 5L, 29L, 20L + +#define SN_certificate_policies "certificatePolicies" +#define LN_certificate_policies "X509v3 Certificate Policies" +#define NID_certificate_policies 89 +#define OBJ_certificate_policies 2L, 5L, 29L, 32L + +#define SN_authority_key_identifier "authorityKeyIdentifier" +#define LN_authority_key_identifier "X509v3 Authority Key Identifier" +#define NID_authority_key_identifier 90 +#define OBJ_authority_key_identifier 2L, 5L, 29L, 35L + +#define SN_bf_cbc "BF-CBC" +#define LN_bf_cbc "bf-cbc" +#define NID_bf_cbc 91 +#define OBJ_bf_cbc 1L, 3L, 6L, 1L, 4L, 1L, 3029L, 1L, 2L + +#define SN_bf_ecb "BF-ECB" +#define LN_bf_ecb "bf-ecb" +#define NID_bf_ecb 92 + +#define SN_bf_cfb64 "BF-CFB" +#define LN_bf_cfb64 "bf-cfb" +#define NID_bf_cfb64 93 + +#define SN_bf_ofb64 "BF-OFB" +#define LN_bf_ofb64 "bf-ofb" +#define NID_bf_ofb64 94 + +#define SN_mdc2 "MDC2" +#define LN_mdc2 "mdc2" +#define NID_mdc2 95 +#define OBJ_mdc2 2L, 5L, 8L, 3L, 101L + +#define SN_mdc2WithRSA "RSA-MDC2" +#define LN_mdc2WithRSA "mdc2WithRSA" +#define NID_mdc2WithRSA 96 +#define OBJ_mdc2WithRSA 2L, 5L, 8L, 3L, 100L + +#define SN_rc4_40 "RC4-40" +#define LN_rc4_40 "rc4-40" +#define NID_rc4_40 97 + +#define SN_rc2_40_cbc "RC2-40-CBC" +#define LN_rc2_40_cbc "rc2-40-cbc" +#define NID_rc2_40_cbc 98 + +#define SN_givenName "GN" +#define LN_givenName "givenName" +#define NID_givenName 99 +#define OBJ_givenName 2L, 5L, 4L, 42L + +#define SN_surname "SN" +#define LN_surname "surname" +#define NID_surname 100 +#define OBJ_surname 2L, 5L, 4L, 4L + +#define SN_initials "initials" +#define LN_initials "initials" +#define NID_initials 101 +#define OBJ_initials 2L, 5L, 4L, 43L + +#define SN_crl_distribution_points "crlDistributionPoints" +#define LN_crl_distribution_points "X509v3 CRL Distribution Points" +#define NID_crl_distribution_points 103 +#define OBJ_crl_distribution_points 2L, 5L, 29L, 31L + +#define SN_md5WithRSA "RSA-NP-MD5" +#define LN_md5WithRSA "md5WithRSA" +#define NID_md5WithRSA 104 +#define OBJ_md5WithRSA 1L, 3L, 14L, 3L, 2L, 3L + +#define LN_serialNumber "serialNumber" +#define NID_serialNumber 105 +#define OBJ_serialNumber 2L, 5L, 4L, 5L + +#define SN_title "title" +#define LN_title "title" +#define NID_title 106 +#define OBJ_title 2L, 5L, 4L, 12L + +#define LN_description "description" +#define NID_description 107 +#define OBJ_description 2L, 5L, 4L, 13L + +#define SN_cast5_cbc "CAST5-CBC" +#define LN_cast5_cbc "cast5-cbc" +#define NID_cast5_cbc 108 +#define OBJ_cast5_cbc 1L, 2L, 840L, 113533L, 7L, 66L, 10L + +#define SN_cast5_ecb "CAST5-ECB" +#define LN_cast5_ecb "cast5-ecb" +#define NID_cast5_ecb 109 + +#define SN_cast5_cfb64 "CAST5-CFB" +#define LN_cast5_cfb64 "cast5-cfb" +#define NID_cast5_cfb64 110 + +#define SN_cast5_ofb64 "CAST5-OFB" +#define LN_cast5_ofb64 "cast5-ofb" +#define NID_cast5_ofb64 111 + +#define LN_pbeWithMD5AndCast5_CBC "pbeWithMD5AndCast5CBC" +#define NID_pbeWithMD5AndCast5_CBC 112 +#define OBJ_pbeWithMD5AndCast5_CBC 1L, 2L, 840L, 113533L, 7L, 66L, 12L + +#define SN_dsaWithSHA1 "DSA-SHA1" +#define LN_dsaWithSHA1 "dsaWithSHA1" +#define NID_dsaWithSHA1 113 +#define OBJ_dsaWithSHA1 1L, 2L, 840L, 10040L, 4L, 3L + +#define SN_md5_sha1 "MD5-SHA1" +#define LN_md5_sha1 "md5-sha1" +#define NID_md5_sha1 114 + +#define SN_sha1WithRSA "RSA-SHA1-2" +#define LN_sha1WithRSA "sha1WithRSA" +#define NID_sha1WithRSA 115 +#define OBJ_sha1WithRSA 1L, 3L, 14L, 3L, 2L, 29L + +#define SN_dsa "DSA" +#define LN_dsa "dsaEncryption" +#define NID_dsa 116 +#define OBJ_dsa 1L, 2L, 840L, 10040L, 4L, 1L + +#define SN_ripemd160 "RIPEMD160" +#define LN_ripemd160 "ripemd160" +#define NID_ripemd160 117 +#define OBJ_ripemd160 1L, 3L, 36L, 3L, 2L, 1L + +#define SN_ripemd160WithRSA "RSA-RIPEMD160" +#define LN_ripemd160WithRSA "ripemd160WithRSA" +#define NID_ripemd160WithRSA 119 +#define OBJ_ripemd160WithRSA 1L, 3L, 36L, 3L, 3L, 1L, 2L + +#define SN_rc5_cbc "RC5-CBC" +#define LN_rc5_cbc "rc5-cbc" +#define NID_rc5_cbc 120 +#define OBJ_rc5_cbc 1L, 2L, 840L, 113549L, 3L, 8L + +#define SN_rc5_ecb "RC5-ECB" +#define LN_rc5_ecb "rc5-ecb" +#define NID_rc5_ecb 121 + +#define SN_rc5_cfb64 "RC5-CFB" +#define LN_rc5_cfb64 "rc5-cfb" +#define NID_rc5_cfb64 122 + +#define SN_rc5_ofb64 "RC5-OFB" +#define LN_rc5_ofb64 "rc5-ofb" +#define NID_rc5_ofb64 123 + +#define SN_zlib_compression "ZLIB" +#define LN_zlib_compression "zlib compression" +#define NID_zlib_compression 125 +#define OBJ_zlib_compression 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 3L, 8L + +#define SN_ext_key_usage "extendedKeyUsage" +#define LN_ext_key_usage "X509v3 Extended Key Usage" +#define NID_ext_key_usage 126 +#define OBJ_ext_key_usage 2L, 5L, 29L, 37L + +#define SN_id_pkix "PKIX" +#define NID_id_pkix 127 +#define OBJ_id_pkix 1L, 3L, 6L, 1L, 5L, 5L, 7L + +#define SN_id_kp "id-kp" +#define NID_id_kp 128 +#define OBJ_id_kp 1L, 3L, 6L, 1L, 5L, 5L, 7L, 3L + +#define SN_server_auth "serverAuth" +#define LN_server_auth "TLS Web Server Authentication" +#define NID_server_auth 129 +#define OBJ_server_auth 1L, 3L, 6L, 1L, 5L, 5L, 7L, 3L, 1L + +#define SN_client_auth "clientAuth" +#define LN_client_auth "TLS Web Client Authentication" +#define NID_client_auth 130 +#define OBJ_client_auth 1L, 3L, 6L, 1L, 5L, 5L, 7L, 3L, 2L + +#define SN_code_sign "codeSigning" +#define LN_code_sign "Code Signing" +#define NID_code_sign 131 +#define OBJ_code_sign 1L, 3L, 6L, 1L, 5L, 5L, 7L, 3L, 3L + +#define SN_email_protect "emailProtection" +#define LN_email_protect "E-mail Protection" +#define NID_email_protect 132 +#define OBJ_email_protect 1L, 3L, 6L, 1L, 5L, 5L, 7L, 3L, 4L + +#define SN_time_stamp "timeStamping" +#define LN_time_stamp "Time Stamping" +#define NID_time_stamp 133 +#define OBJ_time_stamp 1L, 3L, 6L, 1L, 5L, 5L, 7L, 3L, 8L + +#define SN_ms_code_ind "msCodeInd" +#define LN_ms_code_ind "Microsoft Individual Code Signing" +#define NID_ms_code_ind 134 +#define OBJ_ms_code_ind 1L, 3L, 6L, 1L, 4L, 1L, 311L, 2L, 1L, 21L + +#define SN_ms_code_com "msCodeCom" +#define LN_ms_code_com "Microsoft Commercial Code Signing" +#define NID_ms_code_com 135 +#define OBJ_ms_code_com 1L, 3L, 6L, 1L, 4L, 1L, 311L, 2L, 1L, 22L + +#define SN_ms_ctl_sign "msCTLSign" +#define LN_ms_ctl_sign "Microsoft Trust List Signing" +#define NID_ms_ctl_sign 136 +#define OBJ_ms_ctl_sign 1L, 3L, 6L, 1L, 4L, 1L, 311L, 10L, 3L, 1L + +#define SN_ms_sgc "msSGC" +#define LN_ms_sgc "Microsoft Server Gated Crypto" +#define NID_ms_sgc 137 +#define OBJ_ms_sgc 1L, 3L, 6L, 1L, 4L, 1L, 311L, 10L, 3L, 3L + +#define SN_ms_efs "msEFS" +#define LN_ms_efs "Microsoft Encrypted File System" +#define NID_ms_efs 138 +#define OBJ_ms_efs 1L, 3L, 6L, 1L, 4L, 1L, 311L, 10L, 3L, 4L + +#define SN_ns_sgc "nsSGC" +#define LN_ns_sgc "Netscape Server Gated Crypto" +#define NID_ns_sgc 139 +#define OBJ_ns_sgc 2L, 16L, 840L, 1L, 113730L, 4L, 1L + +#define SN_delta_crl "deltaCRL" +#define LN_delta_crl "X509v3 Delta CRL Indicator" +#define NID_delta_crl 140 +#define OBJ_delta_crl 2L, 5L, 29L, 27L + +#define SN_crl_reason "CRLReason" +#define LN_crl_reason "X509v3 CRL Reason Code" +#define NID_crl_reason 141 +#define OBJ_crl_reason 2L, 5L, 29L, 21L + +#define SN_invalidity_date "invalidityDate" +#define LN_invalidity_date "Invalidity Date" +#define NID_invalidity_date 142 +#define OBJ_invalidity_date 2L, 5L, 29L, 24L + +#define SN_sxnet "SXNetID" +#define LN_sxnet "Strong Extranet ID" +#define NID_sxnet 143 +#define OBJ_sxnet 1L, 3L, 101L, 1L, 4L, 1L + +#define SN_pbe_WithSHA1And128BitRC4 "PBE-SHA1-RC4-128" +#define LN_pbe_WithSHA1And128BitRC4 "pbeWithSHA1And128BitRC4" +#define NID_pbe_WithSHA1And128BitRC4 144 +#define OBJ_pbe_WithSHA1And128BitRC4 1L, 2L, 840L, 113549L, 1L, 12L, 1L, 1L + +#define SN_pbe_WithSHA1And40BitRC4 "PBE-SHA1-RC4-40" +#define LN_pbe_WithSHA1And40BitRC4 "pbeWithSHA1And40BitRC4" +#define NID_pbe_WithSHA1And40BitRC4 145 +#define OBJ_pbe_WithSHA1And40BitRC4 1L, 2L, 840L, 113549L, 1L, 12L, 1L, 2L + +#define SN_pbe_WithSHA1And3_Key_TripleDES_CBC "PBE-SHA1-3DES" +#define LN_pbe_WithSHA1And3_Key_TripleDES_CBC "pbeWithSHA1And3-KeyTripleDES-CBC" +#define NID_pbe_WithSHA1And3_Key_TripleDES_CBC 146 +#define OBJ_pbe_WithSHA1And3_Key_TripleDES_CBC \ + 1L, 2L, 840L, 113549L, 1L, 12L, 1L, 3L + +#define SN_pbe_WithSHA1And2_Key_TripleDES_CBC "PBE-SHA1-2DES" +#define LN_pbe_WithSHA1And2_Key_TripleDES_CBC "pbeWithSHA1And2-KeyTripleDES-CBC" +#define NID_pbe_WithSHA1And2_Key_TripleDES_CBC 147 +#define OBJ_pbe_WithSHA1And2_Key_TripleDES_CBC \ + 1L, 2L, 840L, 113549L, 1L, 12L, 1L, 4L + +#define SN_pbe_WithSHA1And128BitRC2_CBC "PBE-SHA1-RC2-128" +#define LN_pbe_WithSHA1And128BitRC2_CBC "pbeWithSHA1And128BitRC2-CBC" +#define NID_pbe_WithSHA1And128BitRC2_CBC 148 +#define OBJ_pbe_WithSHA1And128BitRC2_CBC 1L, 2L, 840L, 113549L, 1L, 12L, 1L, 5L + +#define SN_pbe_WithSHA1And40BitRC2_CBC "PBE-SHA1-RC2-40" +#define LN_pbe_WithSHA1And40BitRC2_CBC "pbeWithSHA1And40BitRC2-CBC" +#define NID_pbe_WithSHA1And40BitRC2_CBC 149 +#define OBJ_pbe_WithSHA1And40BitRC2_CBC 1L, 2L, 840L, 113549L, 1L, 12L, 1L, 6L + +#define LN_keyBag "keyBag" +#define NID_keyBag 150 +#define OBJ_keyBag 1L, 2L, 840L, 113549L, 1L, 12L, 10L, 1L, 1L + +#define LN_pkcs8ShroudedKeyBag "pkcs8ShroudedKeyBag" +#define NID_pkcs8ShroudedKeyBag 151 +#define OBJ_pkcs8ShroudedKeyBag 1L, 2L, 840L, 113549L, 1L, 12L, 10L, 1L, 2L + +#define LN_certBag "certBag" +#define NID_certBag 152 +#define OBJ_certBag 1L, 2L, 840L, 113549L, 1L, 12L, 10L, 1L, 3L + +#define LN_crlBag "crlBag" +#define NID_crlBag 153 +#define OBJ_crlBag 1L, 2L, 840L, 113549L, 1L, 12L, 10L, 1L, 4L + +#define LN_secretBag "secretBag" +#define NID_secretBag 154 +#define OBJ_secretBag 1L, 2L, 840L, 113549L, 1L, 12L, 10L, 1L, 5L + +#define LN_safeContentsBag "safeContentsBag" +#define NID_safeContentsBag 155 +#define OBJ_safeContentsBag 1L, 2L, 840L, 113549L, 1L, 12L, 10L, 1L, 6L + +#define LN_friendlyName "friendlyName" +#define NID_friendlyName 156 +#define OBJ_friendlyName 1L, 2L, 840L, 113549L, 1L, 9L, 20L + +#define LN_localKeyID "localKeyID" +#define NID_localKeyID 157 +#define OBJ_localKeyID 1L, 2L, 840L, 113549L, 1L, 9L, 21L + +#define LN_x509Certificate "x509Certificate" +#define NID_x509Certificate 158 +#define OBJ_x509Certificate 1L, 2L, 840L, 113549L, 1L, 9L, 22L, 1L + +#define LN_sdsiCertificate "sdsiCertificate" +#define NID_sdsiCertificate 159 +#define OBJ_sdsiCertificate 1L, 2L, 840L, 113549L, 1L, 9L, 22L, 2L + +#define LN_x509Crl "x509Crl" +#define NID_x509Crl 160 +#define OBJ_x509Crl 1L, 2L, 840L, 113549L, 1L, 9L, 23L, 1L + +#define LN_pbes2 "PBES2" +#define NID_pbes2 161 +#define OBJ_pbes2 1L, 2L, 840L, 113549L, 1L, 5L, 13L + +#define LN_pbmac1 "PBMAC1" +#define NID_pbmac1 162 +#define OBJ_pbmac1 1L, 2L, 840L, 113549L, 1L, 5L, 14L + +#define LN_hmacWithSHA1 "hmacWithSHA1" +#define NID_hmacWithSHA1 163 +#define OBJ_hmacWithSHA1 1L, 2L, 840L, 113549L, 2L, 7L + +#define SN_id_qt_cps "id-qt-cps" +#define LN_id_qt_cps "Policy Qualifier CPS" +#define NID_id_qt_cps 164 +#define OBJ_id_qt_cps 1L, 3L, 6L, 1L, 5L, 5L, 7L, 2L, 1L + +#define SN_id_qt_unotice "id-qt-unotice" +#define LN_id_qt_unotice "Policy Qualifier User Notice" +#define NID_id_qt_unotice 165 +#define OBJ_id_qt_unotice 1L, 3L, 6L, 1L, 5L, 5L, 7L, 2L, 2L + +#define SN_rc2_64_cbc "RC2-64-CBC" +#define LN_rc2_64_cbc "rc2-64-cbc" +#define NID_rc2_64_cbc 166 + +#define SN_SMIMECapabilities "SMIME-CAPS" +#define LN_SMIMECapabilities "S/MIME Capabilities" +#define NID_SMIMECapabilities 167 +#define OBJ_SMIMECapabilities 1L, 2L, 840L, 113549L, 1L, 9L, 15L + +#define SN_pbeWithMD2AndRC2_CBC "PBE-MD2-RC2-64" +#define LN_pbeWithMD2AndRC2_CBC "pbeWithMD2AndRC2-CBC" +#define NID_pbeWithMD2AndRC2_CBC 168 +#define OBJ_pbeWithMD2AndRC2_CBC 1L, 2L, 840L, 113549L, 1L, 5L, 4L + +#define SN_pbeWithMD5AndRC2_CBC "PBE-MD5-RC2-64" +#define LN_pbeWithMD5AndRC2_CBC "pbeWithMD5AndRC2-CBC" +#define NID_pbeWithMD5AndRC2_CBC 169 +#define OBJ_pbeWithMD5AndRC2_CBC 1L, 2L, 840L, 113549L, 1L, 5L, 6L + +#define SN_pbeWithSHA1AndDES_CBC "PBE-SHA1-DES" +#define LN_pbeWithSHA1AndDES_CBC "pbeWithSHA1AndDES-CBC" +#define NID_pbeWithSHA1AndDES_CBC 170 +#define OBJ_pbeWithSHA1AndDES_CBC 1L, 2L, 840L, 113549L, 1L, 5L, 10L + +#define SN_ms_ext_req "msExtReq" +#define LN_ms_ext_req "Microsoft Extension Request" +#define NID_ms_ext_req 171 +#define OBJ_ms_ext_req 1L, 3L, 6L, 1L, 4L, 1L, 311L, 2L, 1L, 14L + +#define SN_ext_req "extReq" +#define LN_ext_req "Extension Request" +#define NID_ext_req 172 +#define OBJ_ext_req 1L, 2L, 840L, 113549L, 1L, 9L, 14L + +#define SN_name "name" +#define LN_name "name" +#define NID_name 173 +#define OBJ_name 2L, 5L, 4L, 41L + +#define SN_dnQualifier "dnQualifier" +#define LN_dnQualifier "dnQualifier" +#define NID_dnQualifier 174 +#define OBJ_dnQualifier 2L, 5L, 4L, 46L + +#define SN_id_pe "id-pe" +#define NID_id_pe 175 +#define OBJ_id_pe 1L, 3L, 6L, 1L, 5L, 5L, 7L, 1L + +#define SN_id_ad "id-ad" +#define NID_id_ad 176 +#define OBJ_id_ad 1L, 3L, 6L, 1L, 5L, 5L, 7L, 48L + +#define SN_info_access "authorityInfoAccess" +#define LN_info_access "Authority Information Access" +#define NID_info_access 177 +#define OBJ_info_access 1L, 3L, 6L, 1L, 5L, 5L, 7L, 1L, 1L + +#define SN_ad_OCSP "OCSP" +#define LN_ad_OCSP "OCSP" +#define NID_ad_OCSP 178 +#define OBJ_ad_OCSP 1L, 3L, 6L, 1L, 5L, 5L, 7L, 48L, 1L + +#define SN_ad_ca_issuers "caIssuers" +#define LN_ad_ca_issuers "CA Issuers" +#define NID_ad_ca_issuers 179 +#define OBJ_ad_ca_issuers 1L, 3L, 6L, 1L, 5L, 5L, 7L, 48L, 2L + +#define SN_OCSP_sign "OCSPSigning" +#define LN_OCSP_sign "OCSP Signing" +#define NID_OCSP_sign 180 +#define OBJ_OCSP_sign 1L, 3L, 6L, 1L, 5L, 5L, 7L, 3L, 9L + +#define SN_iso "ISO" +#define LN_iso "iso" +#define NID_iso 181 +#define OBJ_iso 1L + +#define SN_member_body "member-body" +#define LN_member_body "ISO Member Body" +#define NID_member_body 182 +#define OBJ_member_body 1L, 2L + +#define SN_ISO_US "ISO-US" +#define LN_ISO_US "ISO US Member Body" +#define NID_ISO_US 183 +#define OBJ_ISO_US 1L, 2L, 840L + +#define SN_X9_57 "X9-57" +#define LN_X9_57 "X9.57" +#define NID_X9_57 184 +#define OBJ_X9_57 1L, 2L, 840L, 10040L + +#define SN_X9cm "X9cm" +#define LN_X9cm "X9.57 CM ?" +#define NID_X9cm 185 +#define OBJ_X9cm 1L, 2L, 840L, 10040L, 4L + +#define SN_pkcs1 "pkcs1" +#define NID_pkcs1 186 +#define OBJ_pkcs1 1L, 2L, 840L, 113549L, 1L, 1L + +#define SN_pkcs5 "pkcs5" +#define NID_pkcs5 187 +#define OBJ_pkcs5 1L, 2L, 840L, 113549L, 1L, 5L + +#define SN_SMIME "SMIME" +#define LN_SMIME "S/MIME" +#define NID_SMIME 188 +#define OBJ_SMIME 1L, 2L, 840L, 113549L, 1L, 9L, 16L + +#define SN_id_smime_mod "id-smime-mod" +#define NID_id_smime_mod 189 +#define OBJ_id_smime_mod 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 0L + +#define SN_id_smime_ct "id-smime-ct" +#define NID_id_smime_ct 190 +#define OBJ_id_smime_ct 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 1L + +#define SN_id_smime_aa "id-smime-aa" +#define NID_id_smime_aa 191 +#define OBJ_id_smime_aa 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 2L + +#define SN_id_smime_alg "id-smime-alg" +#define NID_id_smime_alg 192 +#define OBJ_id_smime_alg 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 3L + +#define SN_id_smime_cd "id-smime-cd" +#define NID_id_smime_cd 193 +#define OBJ_id_smime_cd 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 4L + +#define SN_id_smime_spq "id-smime-spq" +#define NID_id_smime_spq 194 +#define OBJ_id_smime_spq 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 5L + +#define SN_id_smime_cti "id-smime-cti" +#define NID_id_smime_cti 195 +#define OBJ_id_smime_cti 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 6L + +#define SN_id_smime_mod_cms "id-smime-mod-cms" +#define NID_id_smime_mod_cms 196 +#define OBJ_id_smime_mod_cms 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 0L, 1L + +#define SN_id_smime_mod_ess "id-smime-mod-ess" +#define NID_id_smime_mod_ess 197 +#define OBJ_id_smime_mod_ess 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 0L, 2L + +#define SN_id_smime_mod_oid "id-smime-mod-oid" +#define NID_id_smime_mod_oid 198 +#define OBJ_id_smime_mod_oid 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 0L, 3L + +#define SN_id_smime_mod_msg_v3 "id-smime-mod-msg-v3" +#define NID_id_smime_mod_msg_v3 199 +#define OBJ_id_smime_mod_msg_v3 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 0L, 4L + +#define SN_id_smime_mod_ets_eSignature_88 "id-smime-mod-ets-eSignature-88" +#define NID_id_smime_mod_ets_eSignature_88 200 +#define OBJ_id_smime_mod_ets_eSignature_88 \ + 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 0L, 5L + +#define SN_id_smime_mod_ets_eSignature_97 "id-smime-mod-ets-eSignature-97" +#define NID_id_smime_mod_ets_eSignature_97 201 +#define OBJ_id_smime_mod_ets_eSignature_97 \ + 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 0L, 6L + +#define SN_id_smime_mod_ets_eSigPolicy_88 "id-smime-mod-ets-eSigPolicy-88" +#define NID_id_smime_mod_ets_eSigPolicy_88 202 +#define OBJ_id_smime_mod_ets_eSigPolicy_88 \ + 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 0L, 7L + +#define SN_id_smime_mod_ets_eSigPolicy_97 "id-smime-mod-ets-eSigPolicy-97" +#define NID_id_smime_mod_ets_eSigPolicy_97 203 +#define OBJ_id_smime_mod_ets_eSigPolicy_97 \ + 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 0L, 8L + +#define SN_id_smime_ct_receipt "id-smime-ct-receipt" +#define NID_id_smime_ct_receipt 204 +#define OBJ_id_smime_ct_receipt 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 1L, 1L + +#define SN_id_smime_ct_authData "id-smime-ct-authData" +#define NID_id_smime_ct_authData 205 +#define OBJ_id_smime_ct_authData 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 1L, 2L + +#define SN_id_smime_ct_publishCert "id-smime-ct-publishCert" +#define NID_id_smime_ct_publishCert 206 +#define OBJ_id_smime_ct_publishCert 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 1L, 3L + +#define SN_id_smime_ct_TSTInfo "id-smime-ct-TSTInfo" +#define NID_id_smime_ct_TSTInfo 207 +#define OBJ_id_smime_ct_TSTInfo 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 1L, 4L + +#define SN_id_smime_ct_TDTInfo "id-smime-ct-TDTInfo" +#define NID_id_smime_ct_TDTInfo 208 +#define OBJ_id_smime_ct_TDTInfo 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 1L, 5L + +#define SN_id_smime_ct_contentInfo "id-smime-ct-contentInfo" +#define NID_id_smime_ct_contentInfo 209 +#define OBJ_id_smime_ct_contentInfo 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 1L, 6L + +#define SN_id_smime_ct_DVCSRequestData "id-smime-ct-DVCSRequestData" +#define NID_id_smime_ct_DVCSRequestData 210 +#define OBJ_id_smime_ct_DVCSRequestData \ + 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 1L, 7L + +#define SN_id_smime_ct_DVCSResponseData "id-smime-ct-DVCSResponseData" +#define NID_id_smime_ct_DVCSResponseData 211 +#define OBJ_id_smime_ct_DVCSResponseData \ + 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 1L, 8L + +#define SN_id_smime_aa_receiptRequest "id-smime-aa-receiptRequest" +#define NID_id_smime_aa_receiptRequest 212 +#define OBJ_id_smime_aa_receiptRequest \ + 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 2L, 1L + +#define SN_id_smime_aa_securityLabel "id-smime-aa-securityLabel" +#define NID_id_smime_aa_securityLabel 213 +#define OBJ_id_smime_aa_securityLabel 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 2L, 2L + +#define SN_id_smime_aa_mlExpandHistory "id-smime-aa-mlExpandHistory" +#define NID_id_smime_aa_mlExpandHistory 214 +#define OBJ_id_smime_aa_mlExpandHistory \ + 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 2L, 3L + +#define SN_id_smime_aa_contentHint "id-smime-aa-contentHint" +#define NID_id_smime_aa_contentHint 215 +#define OBJ_id_smime_aa_contentHint 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 2L, 4L + +#define SN_id_smime_aa_msgSigDigest "id-smime-aa-msgSigDigest" +#define NID_id_smime_aa_msgSigDigest 216 +#define OBJ_id_smime_aa_msgSigDigest 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 2L, 5L + +#define SN_id_smime_aa_encapContentType "id-smime-aa-encapContentType" +#define NID_id_smime_aa_encapContentType 217 +#define OBJ_id_smime_aa_encapContentType \ + 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 2L, 6L + +#define SN_id_smime_aa_contentIdentifier "id-smime-aa-contentIdentifier" +#define NID_id_smime_aa_contentIdentifier 218 +#define OBJ_id_smime_aa_contentIdentifier \ + 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 2L, 7L + +#define SN_id_smime_aa_macValue "id-smime-aa-macValue" +#define NID_id_smime_aa_macValue 219 +#define OBJ_id_smime_aa_macValue 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 2L, 8L + +#define SN_id_smime_aa_equivalentLabels "id-smime-aa-equivalentLabels" +#define NID_id_smime_aa_equivalentLabels 220 +#define OBJ_id_smime_aa_equivalentLabels \ + 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 2L, 9L + +#define SN_id_smime_aa_contentReference "id-smime-aa-contentReference" +#define NID_id_smime_aa_contentReference 221 +#define OBJ_id_smime_aa_contentReference \ + 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 2L, 10L + +#define SN_id_smime_aa_encrypKeyPref "id-smime-aa-encrypKeyPref" +#define NID_id_smime_aa_encrypKeyPref 222 +#define OBJ_id_smime_aa_encrypKeyPref \ + 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 2L, 11L + +#define SN_id_smime_aa_signingCertificate "id-smime-aa-signingCertificate" +#define NID_id_smime_aa_signingCertificate 223 +#define OBJ_id_smime_aa_signingCertificate \ + 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 2L, 12L + +#define SN_id_smime_aa_smimeEncryptCerts "id-smime-aa-smimeEncryptCerts" +#define NID_id_smime_aa_smimeEncryptCerts 224 +#define OBJ_id_smime_aa_smimeEncryptCerts \ + 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 2L, 13L + +#define SN_id_smime_aa_timeStampToken "id-smime-aa-timeStampToken" +#define NID_id_smime_aa_timeStampToken 225 +#define OBJ_id_smime_aa_timeStampToken \ + 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 2L, 14L + +#define SN_id_smime_aa_ets_sigPolicyId "id-smime-aa-ets-sigPolicyId" +#define NID_id_smime_aa_ets_sigPolicyId 226 +#define OBJ_id_smime_aa_ets_sigPolicyId \ + 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 2L, 15L + +#define SN_id_smime_aa_ets_commitmentType "id-smime-aa-ets-commitmentType" +#define NID_id_smime_aa_ets_commitmentType 227 +#define OBJ_id_smime_aa_ets_commitmentType \ + 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 2L, 16L + +#define SN_id_smime_aa_ets_signerLocation "id-smime-aa-ets-signerLocation" +#define NID_id_smime_aa_ets_signerLocation 228 +#define OBJ_id_smime_aa_ets_signerLocation \ + 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 2L, 17L + +#define SN_id_smime_aa_ets_signerAttr "id-smime-aa-ets-signerAttr" +#define NID_id_smime_aa_ets_signerAttr 229 +#define OBJ_id_smime_aa_ets_signerAttr \ + 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 2L, 18L + +#define SN_id_smime_aa_ets_otherSigCert "id-smime-aa-ets-otherSigCert" +#define NID_id_smime_aa_ets_otherSigCert 230 +#define OBJ_id_smime_aa_ets_otherSigCert \ + 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 2L, 19L + +#define SN_id_smime_aa_ets_contentTimestamp "id-smime-aa-ets-contentTimestamp" +#define NID_id_smime_aa_ets_contentTimestamp 231 +#define OBJ_id_smime_aa_ets_contentTimestamp \ + 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 2L, 20L + +#define SN_id_smime_aa_ets_CertificateRefs "id-smime-aa-ets-CertificateRefs" +#define NID_id_smime_aa_ets_CertificateRefs 232 +#define OBJ_id_smime_aa_ets_CertificateRefs \ + 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 2L, 21L + +#define SN_id_smime_aa_ets_RevocationRefs "id-smime-aa-ets-RevocationRefs" +#define NID_id_smime_aa_ets_RevocationRefs 233 +#define OBJ_id_smime_aa_ets_RevocationRefs \ + 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 2L, 22L + +#define SN_id_smime_aa_ets_certValues "id-smime-aa-ets-certValues" +#define NID_id_smime_aa_ets_certValues 234 +#define OBJ_id_smime_aa_ets_certValues \ + 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 2L, 23L + +#define SN_id_smime_aa_ets_revocationValues "id-smime-aa-ets-revocationValues" +#define NID_id_smime_aa_ets_revocationValues 235 +#define OBJ_id_smime_aa_ets_revocationValues \ + 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 2L, 24L + +#define SN_id_smime_aa_ets_escTimeStamp "id-smime-aa-ets-escTimeStamp" +#define NID_id_smime_aa_ets_escTimeStamp 236 +#define OBJ_id_smime_aa_ets_escTimeStamp \ + 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 2L, 25L + +#define SN_id_smime_aa_ets_certCRLTimestamp "id-smime-aa-ets-certCRLTimestamp" +#define NID_id_smime_aa_ets_certCRLTimestamp 237 +#define OBJ_id_smime_aa_ets_certCRLTimestamp \ + 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 2L, 26L + +#define SN_id_smime_aa_ets_archiveTimeStamp "id-smime-aa-ets-archiveTimeStamp" +#define NID_id_smime_aa_ets_archiveTimeStamp 238 +#define OBJ_id_smime_aa_ets_archiveTimeStamp \ + 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 2L, 27L + +#define SN_id_smime_aa_signatureType "id-smime-aa-signatureType" +#define NID_id_smime_aa_signatureType 239 +#define OBJ_id_smime_aa_signatureType \ + 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 2L, 28L + +#define SN_id_smime_aa_dvcs_dvc "id-smime-aa-dvcs-dvc" +#define NID_id_smime_aa_dvcs_dvc 240 +#define OBJ_id_smime_aa_dvcs_dvc 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 2L, 29L + +#define SN_id_smime_alg_ESDHwith3DES "id-smime-alg-ESDHwith3DES" +#define NID_id_smime_alg_ESDHwith3DES 241 +#define OBJ_id_smime_alg_ESDHwith3DES 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 3L, 1L + +#define SN_id_smime_alg_ESDHwithRC2 "id-smime-alg-ESDHwithRC2" +#define NID_id_smime_alg_ESDHwithRC2 242 +#define OBJ_id_smime_alg_ESDHwithRC2 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 3L, 2L + +#define SN_id_smime_alg_3DESwrap "id-smime-alg-3DESwrap" +#define NID_id_smime_alg_3DESwrap 243 +#define OBJ_id_smime_alg_3DESwrap 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 3L, 3L + +#define SN_id_smime_alg_RC2wrap "id-smime-alg-RC2wrap" +#define NID_id_smime_alg_RC2wrap 244 +#define OBJ_id_smime_alg_RC2wrap 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 3L, 4L + +#define SN_id_smime_alg_ESDH "id-smime-alg-ESDH" +#define NID_id_smime_alg_ESDH 245 +#define OBJ_id_smime_alg_ESDH 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 3L, 5L + +#define SN_id_smime_alg_CMS3DESwrap "id-smime-alg-CMS3DESwrap" +#define NID_id_smime_alg_CMS3DESwrap 246 +#define OBJ_id_smime_alg_CMS3DESwrap 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 3L, 6L + +#define SN_id_smime_alg_CMSRC2wrap "id-smime-alg-CMSRC2wrap" +#define NID_id_smime_alg_CMSRC2wrap 247 +#define OBJ_id_smime_alg_CMSRC2wrap 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 3L, 7L + +#define SN_id_smime_cd_ldap "id-smime-cd-ldap" +#define NID_id_smime_cd_ldap 248 +#define OBJ_id_smime_cd_ldap 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 4L, 1L + +#define SN_id_smime_spq_ets_sqt_uri "id-smime-spq-ets-sqt-uri" +#define NID_id_smime_spq_ets_sqt_uri 249 +#define OBJ_id_smime_spq_ets_sqt_uri 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 5L, 1L + +#define SN_id_smime_spq_ets_sqt_unotice "id-smime-spq-ets-sqt-unotice" +#define NID_id_smime_spq_ets_sqt_unotice 250 +#define OBJ_id_smime_spq_ets_sqt_unotice \ + 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 5L, 2L + +#define SN_id_smime_cti_ets_proofOfOrigin "id-smime-cti-ets-proofOfOrigin" +#define NID_id_smime_cti_ets_proofOfOrigin 251 +#define OBJ_id_smime_cti_ets_proofOfOrigin \ + 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 6L, 1L + +#define SN_id_smime_cti_ets_proofOfReceipt "id-smime-cti-ets-proofOfReceipt" +#define NID_id_smime_cti_ets_proofOfReceipt 252 +#define OBJ_id_smime_cti_ets_proofOfReceipt \ + 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 6L, 2L + +#define SN_id_smime_cti_ets_proofOfDelivery "id-smime-cti-ets-proofOfDelivery" +#define NID_id_smime_cti_ets_proofOfDelivery 253 +#define OBJ_id_smime_cti_ets_proofOfDelivery \ + 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 6L, 3L + +#define SN_id_smime_cti_ets_proofOfSender "id-smime-cti-ets-proofOfSender" +#define NID_id_smime_cti_ets_proofOfSender 254 +#define OBJ_id_smime_cti_ets_proofOfSender \ + 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 6L, 4L + +#define SN_id_smime_cti_ets_proofOfApproval "id-smime-cti-ets-proofOfApproval" +#define NID_id_smime_cti_ets_proofOfApproval 255 +#define OBJ_id_smime_cti_ets_proofOfApproval \ + 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 6L, 5L + +#define SN_id_smime_cti_ets_proofOfCreation "id-smime-cti-ets-proofOfCreation" +#define NID_id_smime_cti_ets_proofOfCreation 256 +#define OBJ_id_smime_cti_ets_proofOfCreation \ + 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 6L, 6L + +#define SN_md4 "MD4" +#define LN_md4 "md4" +#define NID_md4 257 +#define OBJ_md4 1L, 2L, 840L, 113549L, 2L, 4L + +#define SN_id_pkix_mod "id-pkix-mod" +#define NID_id_pkix_mod 258 +#define OBJ_id_pkix_mod 1L, 3L, 6L, 1L, 5L, 5L, 7L, 0L + +#define SN_id_qt "id-qt" +#define NID_id_qt 259 +#define OBJ_id_qt 1L, 3L, 6L, 1L, 5L, 5L, 7L, 2L + +#define SN_id_it "id-it" +#define NID_id_it 260 +#define OBJ_id_it 1L, 3L, 6L, 1L, 5L, 5L, 7L, 4L + +#define SN_id_pkip "id-pkip" +#define NID_id_pkip 261 +#define OBJ_id_pkip 1L, 3L, 6L, 1L, 5L, 5L, 7L, 5L + +#define SN_id_alg "id-alg" +#define NID_id_alg 262 +#define OBJ_id_alg 1L, 3L, 6L, 1L, 5L, 5L, 7L, 6L + +#define SN_id_cmc "id-cmc" +#define NID_id_cmc 263 +#define OBJ_id_cmc 1L, 3L, 6L, 1L, 5L, 5L, 7L, 7L + +#define SN_id_on "id-on" +#define NID_id_on 264 +#define OBJ_id_on 1L, 3L, 6L, 1L, 5L, 5L, 7L, 8L + +#define SN_id_pda "id-pda" +#define NID_id_pda 265 +#define OBJ_id_pda 1L, 3L, 6L, 1L, 5L, 5L, 7L, 9L + +#define SN_id_aca "id-aca" +#define NID_id_aca 266 +#define OBJ_id_aca 1L, 3L, 6L, 1L, 5L, 5L, 7L, 10L + +#define SN_id_qcs "id-qcs" +#define NID_id_qcs 267 +#define OBJ_id_qcs 1L, 3L, 6L, 1L, 5L, 5L, 7L, 11L + +#define SN_id_cct "id-cct" +#define NID_id_cct 268 +#define OBJ_id_cct 1L, 3L, 6L, 1L, 5L, 5L, 7L, 12L + +#define SN_id_pkix1_explicit_88 "id-pkix1-explicit-88" +#define NID_id_pkix1_explicit_88 269 +#define OBJ_id_pkix1_explicit_88 1L, 3L, 6L, 1L, 5L, 5L, 7L, 0L, 1L + +#define SN_id_pkix1_implicit_88 "id-pkix1-implicit-88" +#define NID_id_pkix1_implicit_88 270 +#define OBJ_id_pkix1_implicit_88 1L, 3L, 6L, 1L, 5L, 5L, 7L, 0L, 2L + +#define SN_id_pkix1_explicit_93 "id-pkix1-explicit-93" +#define NID_id_pkix1_explicit_93 271 +#define OBJ_id_pkix1_explicit_93 1L, 3L, 6L, 1L, 5L, 5L, 7L, 0L, 3L + +#define SN_id_pkix1_implicit_93 "id-pkix1-implicit-93" +#define NID_id_pkix1_implicit_93 272 +#define OBJ_id_pkix1_implicit_93 1L, 3L, 6L, 1L, 5L, 5L, 7L, 0L, 4L + +#define SN_id_mod_crmf "id-mod-crmf" +#define NID_id_mod_crmf 273 +#define OBJ_id_mod_crmf 1L, 3L, 6L, 1L, 5L, 5L, 7L, 0L, 5L + +#define SN_id_mod_cmc "id-mod-cmc" +#define NID_id_mod_cmc 274 +#define OBJ_id_mod_cmc 1L, 3L, 6L, 1L, 5L, 5L, 7L, 0L, 6L + +#define SN_id_mod_kea_profile_88 "id-mod-kea-profile-88" +#define NID_id_mod_kea_profile_88 275 +#define OBJ_id_mod_kea_profile_88 1L, 3L, 6L, 1L, 5L, 5L, 7L, 0L, 7L + +#define SN_id_mod_kea_profile_93 "id-mod-kea-profile-93" +#define NID_id_mod_kea_profile_93 276 +#define OBJ_id_mod_kea_profile_93 1L, 3L, 6L, 1L, 5L, 5L, 7L, 0L, 8L + +#define SN_id_mod_cmp "id-mod-cmp" +#define NID_id_mod_cmp 277 +#define OBJ_id_mod_cmp 1L, 3L, 6L, 1L, 5L, 5L, 7L, 0L, 9L + +#define SN_id_mod_qualified_cert_88 "id-mod-qualified-cert-88" +#define NID_id_mod_qualified_cert_88 278 +#define OBJ_id_mod_qualified_cert_88 1L, 3L, 6L, 1L, 5L, 5L, 7L, 0L, 10L + +#define SN_id_mod_qualified_cert_93 "id-mod-qualified-cert-93" +#define NID_id_mod_qualified_cert_93 279 +#define OBJ_id_mod_qualified_cert_93 1L, 3L, 6L, 1L, 5L, 5L, 7L, 0L, 11L + +#define SN_id_mod_attribute_cert "id-mod-attribute-cert" +#define NID_id_mod_attribute_cert 280 +#define OBJ_id_mod_attribute_cert 1L, 3L, 6L, 1L, 5L, 5L, 7L, 0L, 12L + +#define SN_id_mod_timestamp_protocol "id-mod-timestamp-protocol" +#define NID_id_mod_timestamp_protocol 281 +#define OBJ_id_mod_timestamp_protocol 1L, 3L, 6L, 1L, 5L, 5L, 7L, 0L, 13L + +#define SN_id_mod_ocsp "id-mod-ocsp" +#define NID_id_mod_ocsp 282 +#define OBJ_id_mod_ocsp 1L, 3L, 6L, 1L, 5L, 5L, 7L, 0L, 14L + +#define SN_id_mod_dvcs "id-mod-dvcs" +#define NID_id_mod_dvcs 283 +#define OBJ_id_mod_dvcs 1L, 3L, 6L, 1L, 5L, 5L, 7L, 0L, 15L + +#define SN_id_mod_cmp2000 "id-mod-cmp2000" +#define NID_id_mod_cmp2000 284 +#define OBJ_id_mod_cmp2000 1L, 3L, 6L, 1L, 5L, 5L, 7L, 0L, 16L + +#define SN_biometricInfo "biometricInfo" +#define LN_biometricInfo "Biometric Info" +#define NID_biometricInfo 285 +#define OBJ_biometricInfo 1L, 3L, 6L, 1L, 5L, 5L, 7L, 1L, 2L + +#define SN_qcStatements "qcStatements" +#define NID_qcStatements 286 +#define OBJ_qcStatements 1L, 3L, 6L, 1L, 5L, 5L, 7L, 1L, 3L + +#define SN_ac_auditEntity "ac-auditEntity" +#define NID_ac_auditEntity 287 +#define OBJ_ac_auditEntity 1L, 3L, 6L, 1L, 5L, 5L, 7L, 1L, 4L + +#define SN_ac_targeting "ac-targeting" +#define NID_ac_targeting 288 +#define OBJ_ac_targeting 1L, 3L, 6L, 1L, 5L, 5L, 7L, 1L, 5L + +#define SN_aaControls "aaControls" +#define NID_aaControls 289 +#define OBJ_aaControls 1L, 3L, 6L, 1L, 5L, 5L, 7L, 1L, 6L + +#define SN_sbgp_ipAddrBlock "sbgp-ipAddrBlock" +#define NID_sbgp_ipAddrBlock 290 +#define OBJ_sbgp_ipAddrBlock 1L, 3L, 6L, 1L, 5L, 5L, 7L, 1L, 7L + +#define SN_sbgp_autonomousSysNum "sbgp-autonomousSysNum" +#define NID_sbgp_autonomousSysNum 291 +#define OBJ_sbgp_autonomousSysNum 1L, 3L, 6L, 1L, 5L, 5L, 7L, 1L, 8L + +#define SN_sbgp_routerIdentifier "sbgp-routerIdentifier" +#define NID_sbgp_routerIdentifier 292 +#define OBJ_sbgp_routerIdentifier 1L, 3L, 6L, 1L, 5L, 5L, 7L, 1L, 9L + +#define SN_textNotice "textNotice" +#define NID_textNotice 293 +#define OBJ_textNotice 1L, 3L, 6L, 1L, 5L, 5L, 7L, 2L, 3L + +#define SN_ipsecEndSystem "ipsecEndSystem" +#define LN_ipsecEndSystem "IPSec End System" +#define NID_ipsecEndSystem 294 +#define OBJ_ipsecEndSystem 1L, 3L, 6L, 1L, 5L, 5L, 7L, 3L, 5L + +#define SN_ipsecTunnel "ipsecTunnel" +#define LN_ipsecTunnel "IPSec Tunnel" +#define NID_ipsecTunnel 295 +#define OBJ_ipsecTunnel 1L, 3L, 6L, 1L, 5L, 5L, 7L, 3L, 6L + +#define SN_ipsecUser "ipsecUser" +#define LN_ipsecUser "IPSec User" +#define NID_ipsecUser 296 +#define OBJ_ipsecUser 1L, 3L, 6L, 1L, 5L, 5L, 7L, 3L, 7L + +#define SN_dvcs "DVCS" +#define LN_dvcs "dvcs" +#define NID_dvcs 297 +#define OBJ_dvcs 1L, 3L, 6L, 1L, 5L, 5L, 7L, 3L, 10L + +#define SN_id_it_caProtEncCert "id-it-caProtEncCert" +#define NID_id_it_caProtEncCert 298 +#define OBJ_id_it_caProtEncCert 1L, 3L, 6L, 1L, 5L, 5L, 7L, 4L, 1L + +#define SN_id_it_signKeyPairTypes "id-it-signKeyPairTypes" +#define NID_id_it_signKeyPairTypes 299 +#define OBJ_id_it_signKeyPairTypes 1L, 3L, 6L, 1L, 5L, 5L, 7L, 4L, 2L + +#define SN_id_it_encKeyPairTypes "id-it-encKeyPairTypes" +#define NID_id_it_encKeyPairTypes 300 +#define OBJ_id_it_encKeyPairTypes 1L, 3L, 6L, 1L, 5L, 5L, 7L, 4L, 3L + +#define SN_id_it_preferredSymmAlg "id-it-preferredSymmAlg" +#define NID_id_it_preferredSymmAlg 301 +#define OBJ_id_it_preferredSymmAlg 1L, 3L, 6L, 1L, 5L, 5L, 7L, 4L, 4L + +#define SN_id_it_caKeyUpdateInfo "id-it-caKeyUpdateInfo" +#define NID_id_it_caKeyUpdateInfo 302 +#define OBJ_id_it_caKeyUpdateInfo 1L, 3L, 6L, 1L, 5L, 5L, 7L, 4L, 5L + +#define SN_id_it_currentCRL "id-it-currentCRL" +#define NID_id_it_currentCRL 303 +#define OBJ_id_it_currentCRL 1L, 3L, 6L, 1L, 5L, 5L, 7L, 4L, 6L + +#define SN_id_it_unsupportedOIDs "id-it-unsupportedOIDs" +#define NID_id_it_unsupportedOIDs 304 +#define OBJ_id_it_unsupportedOIDs 1L, 3L, 6L, 1L, 5L, 5L, 7L, 4L, 7L + +#define SN_id_it_subscriptionRequest "id-it-subscriptionRequest" +#define NID_id_it_subscriptionRequest 305 +#define OBJ_id_it_subscriptionRequest 1L, 3L, 6L, 1L, 5L, 5L, 7L, 4L, 8L + +#define SN_id_it_subscriptionResponse "id-it-subscriptionResponse" +#define NID_id_it_subscriptionResponse 306 +#define OBJ_id_it_subscriptionResponse 1L, 3L, 6L, 1L, 5L, 5L, 7L, 4L, 9L + +#define SN_id_it_keyPairParamReq "id-it-keyPairParamReq" +#define NID_id_it_keyPairParamReq 307 +#define OBJ_id_it_keyPairParamReq 1L, 3L, 6L, 1L, 5L, 5L, 7L, 4L, 10L + +#define SN_id_it_keyPairParamRep "id-it-keyPairParamRep" +#define NID_id_it_keyPairParamRep 308 +#define OBJ_id_it_keyPairParamRep 1L, 3L, 6L, 1L, 5L, 5L, 7L, 4L, 11L + +#define SN_id_it_revPassphrase "id-it-revPassphrase" +#define NID_id_it_revPassphrase 309 +#define OBJ_id_it_revPassphrase 1L, 3L, 6L, 1L, 5L, 5L, 7L, 4L, 12L + +#define SN_id_it_implicitConfirm "id-it-implicitConfirm" +#define NID_id_it_implicitConfirm 310 +#define OBJ_id_it_implicitConfirm 1L, 3L, 6L, 1L, 5L, 5L, 7L, 4L, 13L + +#define SN_id_it_confirmWaitTime "id-it-confirmWaitTime" +#define NID_id_it_confirmWaitTime 311 +#define OBJ_id_it_confirmWaitTime 1L, 3L, 6L, 1L, 5L, 5L, 7L, 4L, 14L + +#define SN_id_it_origPKIMessage "id-it-origPKIMessage" +#define NID_id_it_origPKIMessage 312 +#define OBJ_id_it_origPKIMessage 1L, 3L, 6L, 1L, 5L, 5L, 7L, 4L, 15L + +#define SN_id_regCtrl "id-regCtrl" +#define NID_id_regCtrl 313 +#define OBJ_id_regCtrl 1L, 3L, 6L, 1L, 5L, 5L, 7L, 5L, 1L + +#define SN_id_regInfo "id-regInfo" +#define NID_id_regInfo 314 +#define OBJ_id_regInfo 1L, 3L, 6L, 1L, 5L, 5L, 7L, 5L, 2L + +#define SN_id_regCtrl_regToken "id-regCtrl-regToken" +#define NID_id_regCtrl_regToken 315 +#define OBJ_id_regCtrl_regToken 1L, 3L, 6L, 1L, 5L, 5L, 7L, 5L, 1L, 1L + +#define SN_id_regCtrl_authenticator "id-regCtrl-authenticator" +#define NID_id_regCtrl_authenticator 316 +#define OBJ_id_regCtrl_authenticator 1L, 3L, 6L, 1L, 5L, 5L, 7L, 5L, 1L, 2L + +#define SN_id_regCtrl_pkiPublicationInfo "id-regCtrl-pkiPublicationInfo" +#define NID_id_regCtrl_pkiPublicationInfo 317 +#define OBJ_id_regCtrl_pkiPublicationInfo 1L, 3L, 6L, 1L, 5L, 5L, 7L, 5L, 1L, 3L + +#define SN_id_regCtrl_pkiArchiveOptions "id-regCtrl-pkiArchiveOptions" +#define NID_id_regCtrl_pkiArchiveOptions 318 +#define OBJ_id_regCtrl_pkiArchiveOptions 1L, 3L, 6L, 1L, 5L, 5L, 7L, 5L, 1L, 4L + +#define SN_id_regCtrl_oldCertID "id-regCtrl-oldCertID" +#define NID_id_regCtrl_oldCertID 319 +#define OBJ_id_regCtrl_oldCertID 1L, 3L, 6L, 1L, 5L, 5L, 7L, 5L, 1L, 5L + +#define SN_id_regCtrl_protocolEncrKey "id-regCtrl-protocolEncrKey" +#define NID_id_regCtrl_protocolEncrKey 320 +#define OBJ_id_regCtrl_protocolEncrKey 1L, 3L, 6L, 1L, 5L, 5L, 7L, 5L, 1L, 6L + +#define SN_id_regInfo_utf8Pairs "id-regInfo-utf8Pairs" +#define NID_id_regInfo_utf8Pairs 321 +#define OBJ_id_regInfo_utf8Pairs 1L, 3L, 6L, 1L, 5L, 5L, 7L, 5L, 2L, 1L + +#define SN_id_regInfo_certReq "id-regInfo-certReq" +#define NID_id_regInfo_certReq 322 +#define OBJ_id_regInfo_certReq 1L, 3L, 6L, 1L, 5L, 5L, 7L, 5L, 2L, 2L + +#define SN_id_alg_des40 "id-alg-des40" +#define NID_id_alg_des40 323 +#define OBJ_id_alg_des40 1L, 3L, 6L, 1L, 5L, 5L, 7L, 6L, 1L + +#define SN_id_alg_noSignature "id-alg-noSignature" +#define NID_id_alg_noSignature 324 +#define OBJ_id_alg_noSignature 1L, 3L, 6L, 1L, 5L, 5L, 7L, 6L, 2L + +#define SN_id_alg_dh_sig_hmac_sha1 "id-alg-dh-sig-hmac-sha1" +#define NID_id_alg_dh_sig_hmac_sha1 325 +#define OBJ_id_alg_dh_sig_hmac_sha1 1L, 3L, 6L, 1L, 5L, 5L, 7L, 6L, 3L + +#define SN_id_alg_dh_pop "id-alg-dh-pop" +#define NID_id_alg_dh_pop 326 +#define OBJ_id_alg_dh_pop 1L, 3L, 6L, 1L, 5L, 5L, 7L, 6L, 4L + +#define SN_id_cmc_statusInfo "id-cmc-statusInfo" +#define NID_id_cmc_statusInfo 327 +#define OBJ_id_cmc_statusInfo 1L, 3L, 6L, 1L, 5L, 5L, 7L, 7L, 1L + +#define SN_id_cmc_identification "id-cmc-identification" +#define NID_id_cmc_identification 328 +#define OBJ_id_cmc_identification 1L, 3L, 6L, 1L, 5L, 5L, 7L, 7L, 2L + +#define SN_id_cmc_identityProof "id-cmc-identityProof" +#define NID_id_cmc_identityProof 329 +#define OBJ_id_cmc_identityProof 1L, 3L, 6L, 1L, 5L, 5L, 7L, 7L, 3L + +#define SN_id_cmc_dataReturn "id-cmc-dataReturn" +#define NID_id_cmc_dataReturn 330 +#define OBJ_id_cmc_dataReturn 1L, 3L, 6L, 1L, 5L, 5L, 7L, 7L, 4L + +#define SN_id_cmc_transactionId "id-cmc-transactionId" +#define NID_id_cmc_transactionId 331 +#define OBJ_id_cmc_transactionId 1L, 3L, 6L, 1L, 5L, 5L, 7L, 7L, 5L + +#define SN_id_cmc_senderNonce "id-cmc-senderNonce" +#define NID_id_cmc_senderNonce 332 +#define OBJ_id_cmc_senderNonce 1L, 3L, 6L, 1L, 5L, 5L, 7L, 7L, 6L + +#define SN_id_cmc_recipientNonce "id-cmc-recipientNonce" +#define NID_id_cmc_recipientNonce 333 +#define OBJ_id_cmc_recipientNonce 1L, 3L, 6L, 1L, 5L, 5L, 7L, 7L, 7L + +#define SN_id_cmc_addExtensions "id-cmc-addExtensions" +#define NID_id_cmc_addExtensions 334 +#define OBJ_id_cmc_addExtensions 1L, 3L, 6L, 1L, 5L, 5L, 7L, 7L, 8L + +#define SN_id_cmc_encryptedPOP "id-cmc-encryptedPOP" +#define NID_id_cmc_encryptedPOP 335 +#define OBJ_id_cmc_encryptedPOP 1L, 3L, 6L, 1L, 5L, 5L, 7L, 7L, 9L + +#define SN_id_cmc_decryptedPOP "id-cmc-decryptedPOP" +#define NID_id_cmc_decryptedPOP 336 +#define OBJ_id_cmc_decryptedPOP 1L, 3L, 6L, 1L, 5L, 5L, 7L, 7L, 10L + +#define SN_id_cmc_lraPOPWitness "id-cmc-lraPOPWitness" +#define NID_id_cmc_lraPOPWitness 337 +#define OBJ_id_cmc_lraPOPWitness 1L, 3L, 6L, 1L, 5L, 5L, 7L, 7L, 11L + +#define SN_id_cmc_getCert "id-cmc-getCert" +#define NID_id_cmc_getCert 338 +#define OBJ_id_cmc_getCert 1L, 3L, 6L, 1L, 5L, 5L, 7L, 7L, 15L + +#define SN_id_cmc_getCRL "id-cmc-getCRL" +#define NID_id_cmc_getCRL 339 +#define OBJ_id_cmc_getCRL 1L, 3L, 6L, 1L, 5L, 5L, 7L, 7L, 16L + +#define SN_id_cmc_revokeRequest "id-cmc-revokeRequest" +#define NID_id_cmc_revokeRequest 340 +#define OBJ_id_cmc_revokeRequest 1L, 3L, 6L, 1L, 5L, 5L, 7L, 7L, 17L + +#define SN_id_cmc_regInfo "id-cmc-regInfo" +#define NID_id_cmc_regInfo 341 +#define OBJ_id_cmc_regInfo 1L, 3L, 6L, 1L, 5L, 5L, 7L, 7L, 18L + +#define SN_id_cmc_responseInfo "id-cmc-responseInfo" +#define NID_id_cmc_responseInfo 342 +#define OBJ_id_cmc_responseInfo 1L, 3L, 6L, 1L, 5L, 5L, 7L, 7L, 19L + +#define SN_id_cmc_queryPending "id-cmc-queryPending" +#define NID_id_cmc_queryPending 343 +#define OBJ_id_cmc_queryPending 1L, 3L, 6L, 1L, 5L, 5L, 7L, 7L, 21L + +#define SN_id_cmc_popLinkRandom "id-cmc-popLinkRandom" +#define NID_id_cmc_popLinkRandom 344 +#define OBJ_id_cmc_popLinkRandom 1L, 3L, 6L, 1L, 5L, 5L, 7L, 7L, 22L + +#define SN_id_cmc_popLinkWitness "id-cmc-popLinkWitness" +#define NID_id_cmc_popLinkWitness 345 +#define OBJ_id_cmc_popLinkWitness 1L, 3L, 6L, 1L, 5L, 5L, 7L, 7L, 23L + +#define SN_id_cmc_confirmCertAcceptance "id-cmc-confirmCertAcceptance" +#define NID_id_cmc_confirmCertAcceptance 346 +#define OBJ_id_cmc_confirmCertAcceptance 1L, 3L, 6L, 1L, 5L, 5L, 7L, 7L, 24L + +#define SN_id_on_personalData "id-on-personalData" +#define NID_id_on_personalData 347 +#define OBJ_id_on_personalData 1L, 3L, 6L, 1L, 5L, 5L, 7L, 8L, 1L + +#define SN_id_pda_dateOfBirth "id-pda-dateOfBirth" +#define NID_id_pda_dateOfBirth 348 +#define OBJ_id_pda_dateOfBirth 1L, 3L, 6L, 1L, 5L, 5L, 7L, 9L, 1L + +#define SN_id_pda_placeOfBirth "id-pda-placeOfBirth" +#define NID_id_pda_placeOfBirth 349 +#define OBJ_id_pda_placeOfBirth 1L, 3L, 6L, 1L, 5L, 5L, 7L, 9L, 2L + +#define SN_id_pda_gender "id-pda-gender" +#define NID_id_pda_gender 351 +#define OBJ_id_pda_gender 1L, 3L, 6L, 1L, 5L, 5L, 7L, 9L, 3L + +#define SN_id_pda_countryOfCitizenship "id-pda-countryOfCitizenship" +#define NID_id_pda_countryOfCitizenship 352 +#define OBJ_id_pda_countryOfCitizenship 1L, 3L, 6L, 1L, 5L, 5L, 7L, 9L, 4L + +#define SN_id_pda_countryOfResidence "id-pda-countryOfResidence" +#define NID_id_pda_countryOfResidence 353 +#define OBJ_id_pda_countryOfResidence 1L, 3L, 6L, 1L, 5L, 5L, 7L, 9L, 5L + +#define SN_id_aca_authenticationInfo "id-aca-authenticationInfo" +#define NID_id_aca_authenticationInfo 354 +#define OBJ_id_aca_authenticationInfo 1L, 3L, 6L, 1L, 5L, 5L, 7L, 10L, 1L + +#define SN_id_aca_accessIdentity "id-aca-accessIdentity" +#define NID_id_aca_accessIdentity 355 +#define OBJ_id_aca_accessIdentity 1L, 3L, 6L, 1L, 5L, 5L, 7L, 10L, 2L + +#define SN_id_aca_chargingIdentity "id-aca-chargingIdentity" +#define NID_id_aca_chargingIdentity 356 +#define OBJ_id_aca_chargingIdentity 1L, 3L, 6L, 1L, 5L, 5L, 7L, 10L, 3L + +#define SN_id_aca_group "id-aca-group" +#define NID_id_aca_group 357 +#define OBJ_id_aca_group 1L, 3L, 6L, 1L, 5L, 5L, 7L, 10L, 4L + +#define SN_id_aca_role "id-aca-role" +#define NID_id_aca_role 358 +#define OBJ_id_aca_role 1L, 3L, 6L, 1L, 5L, 5L, 7L, 10L, 5L + +#define SN_id_qcs_pkixQCSyntax_v1 "id-qcs-pkixQCSyntax-v1" +#define NID_id_qcs_pkixQCSyntax_v1 359 +#define OBJ_id_qcs_pkixQCSyntax_v1 1L, 3L, 6L, 1L, 5L, 5L, 7L, 11L, 1L + +#define SN_id_cct_crs "id-cct-crs" +#define NID_id_cct_crs 360 +#define OBJ_id_cct_crs 1L, 3L, 6L, 1L, 5L, 5L, 7L, 12L, 1L + +#define SN_id_cct_PKIData "id-cct-PKIData" +#define NID_id_cct_PKIData 361 +#define OBJ_id_cct_PKIData 1L, 3L, 6L, 1L, 5L, 5L, 7L, 12L, 2L + +#define SN_id_cct_PKIResponse "id-cct-PKIResponse" +#define NID_id_cct_PKIResponse 362 +#define OBJ_id_cct_PKIResponse 1L, 3L, 6L, 1L, 5L, 5L, 7L, 12L, 3L + +#define SN_ad_timeStamping "ad_timestamping" +#define LN_ad_timeStamping "AD Time Stamping" +#define NID_ad_timeStamping 363 +#define OBJ_ad_timeStamping 1L, 3L, 6L, 1L, 5L, 5L, 7L, 48L, 3L + +#define SN_ad_dvcs "AD_DVCS" +#define LN_ad_dvcs "ad dvcs" +#define NID_ad_dvcs 364 +#define OBJ_ad_dvcs 1L, 3L, 6L, 1L, 5L, 5L, 7L, 48L, 4L + +#define SN_id_pkix_OCSP_basic "basicOCSPResponse" +#define LN_id_pkix_OCSP_basic "Basic OCSP Response" +#define NID_id_pkix_OCSP_basic 365 +#define OBJ_id_pkix_OCSP_basic 1L, 3L, 6L, 1L, 5L, 5L, 7L, 48L, 1L, 1L + +#define SN_id_pkix_OCSP_Nonce "Nonce" +#define LN_id_pkix_OCSP_Nonce "OCSP Nonce" +#define NID_id_pkix_OCSP_Nonce 366 +#define OBJ_id_pkix_OCSP_Nonce 1L, 3L, 6L, 1L, 5L, 5L, 7L, 48L, 1L, 2L + +#define SN_id_pkix_OCSP_CrlID "CrlID" +#define LN_id_pkix_OCSP_CrlID "OCSP CRL ID" +#define NID_id_pkix_OCSP_CrlID 367 +#define OBJ_id_pkix_OCSP_CrlID 1L, 3L, 6L, 1L, 5L, 5L, 7L, 48L, 1L, 3L + +#define SN_id_pkix_OCSP_acceptableResponses "acceptableResponses" +#define LN_id_pkix_OCSP_acceptableResponses "Acceptable OCSP Responses" +#define NID_id_pkix_OCSP_acceptableResponses 368 +#define OBJ_id_pkix_OCSP_acceptableResponses \ + 1L, 3L, 6L, 1L, 5L, 5L, 7L, 48L, 1L, 4L + +#define SN_id_pkix_OCSP_noCheck "noCheck" +#define LN_id_pkix_OCSP_noCheck "OCSP No Check" +#define NID_id_pkix_OCSP_noCheck 369 +#define OBJ_id_pkix_OCSP_noCheck 1L, 3L, 6L, 1L, 5L, 5L, 7L, 48L, 1L, 5L + +#define SN_id_pkix_OCSP_archiveCutoff "archiveCutoff" +#define LN_id_pkix_OCSP_archiveCutoff "OCSP Archive Cutoff" +#define NID_id_pkix_OCSP_archiveCutoff 370 +#define OBJ_id_pkix_OCSP_archiveCutoff 1L, 3L, 6L, 1L, 5L, 5L, 7L, 48L, 1L, 6L + +#define SN_id_pkix_OCSP_serviceLocator "serviceLocator" +#define LN_id_pkix_OCSP_serviceLocator "OCSP Service Locator" +#define NID_id_pkix_OCSP_serviceLocator 371 +#define OBJ_id_pkix_OCSP_serviceLocator 1L, 3L, 6L, 1L, 5L, 5L, 7L, 48L, 1L, 7L + +#define SN_id_pkix_OCSP_extendedStatus "extendedStatus" +#define LN_id_pkix_OCSP_extendedStatus "Extended OCSP Status" +#define NID_id_pkix_OCSP_extendedStatus 372 +#define OBJ_id_pkix_OCSP_extendedStatus 1L, 3L, 6L, 1L, 5L, 5L, 7L, 48L, 1L, 8L + +#define SN_id_pkix_OCSP_valid "valid" +#define NID_id_pkix_OCSP_valid 373 +#define OBJ_id_pkix_OCSP_valid 1L, 3L, 6L, 1L, 5L, 5L, 7L, 48L, 1L, 9L + +#define SN_id_pkix_OCSP_path "path" +#define NID_id_pkix_OCSP_path 374 +#define OBJ_id_pkix_OCSP_path 1L, 3L, 6L, 1L, 5L, 5L, 7L, 48L, 1L, 10L + +#define SN_id_pkix_OCSP_trustRoot "trustRoot" +#define LN_id_pkix_OCSP_trustRoot "Trust Root" +#define NID_id_pkix_OCSP_trustRoot 375 +#define OBJ_id_pkix_OCSP_trustRoot 1L, 3L, 6L, 1L, 5L, 5L, 7L, 48L, 1L, 11L + +#define SN_algorithm "algorithm" +#define LN_algorithm "algorithm" +#define NID_algorithm 376 +#define OBJ_algorithm 1L, 3L, 14L, 3L, 2L + +#define SN_rsaSignature "rsaSignature" +#define NID_rsaSignature 377 +#define OBJ_rsaSignature 1L, 3L, 14L, 3L, 2L, 11L + +#define SN_X500algorithms "X500algorithms" +#define LN_X500algorithms "directory services - algorithms" +#define NID_X500algorithms 378 +#define OBJ_X500algorithms 2L, 5L, 8L + +#define SN_org "ORG" +#define LN_org "org" +#define NID_org 379 +#define OBJ_org 1L, 3L + +#define SN_dod "DOD" +#define LN_dod "dod" +#define NID_dod 380 +#define OBJ_dod 1L, 3L, 6L + +#define SN_iana "IANA" +#define LN_iana "iana" +#define NID_iana 381 +#define OBJ_iana 1L, 3L, 6L, 1L + +#define SN_Directory "directory" +#define LN_Directory "Directory" +#define NID_Directory 382 +#define OBJ_Directory 1L, 3L, 6L, 1L, 1L + +#define SN_Management "mgmt" +#define LN_Management "Management" +#define NID_Management 383 +#define OBJ_Management 1L, 3L, 6L, 1L, 2L + +#define SN_Experimental "experimental" +#define LN_Experimental "Experimental" +#define NID_Experimental 384 +#define OBJ_Experimental 1L, 3L, 6L, 1L, 3L + +#define SN_Private "private" +#define LN_Private "Private" +#define NID_Private 385 +#define OBJ_Private 1L, 3L, 6L, 1L, 4L + +#define SN_Security "security" +#define LN_Security "Security" +#define NID_Security 386 +#define OBJ_Security 1L, 3L, 6L, 1L, 5L + +#define SN_SNMPv2 "snmpv2" +#define LN_SNMPv2 "SNMPv2" +#define NID_SNMPv2 387 +#define OBJ_SNMPv2 1L, 3L, 6L, 1L, 6L + +#define LN_Mail "Mail" +#define NID_Mail 388 +#define OBJ_Mail 1L, 3L, 6L, 1L, 7L + +#define SN_Enterprises "enterprises" +#define LN_Enterprises "Enterprises" +#define NID_Enterprises 389 +#define OBJ_Enterprises 1L, 3L, 6L, 1L, 4L, 1L + +#define SN_dcObject "dcobject" +#define LN_dcObject "dcObject" +#define NID_dcObject 390 +#define OBJ_dcObject 1L, 3L, 6L, 1L, 4L, 1L, 1466L, 344L + +#define SN_domainComponent "DC" +#define LN_domainComponent "domainComponent" +#define NID_domainComponent 391 +#define OBJ_domainComponent 0L, 9L, 2342L, 19200300L, 100L, 1L, 25L + +#define SN_Domain "domain" +#define LN_Domain "Domain" +#define NID_Domain 392 +#define OBJ_Domain 0L, 9L, 2342L, 19200300L, 100L, 4L, 13L + +#define SN_selected_attribute_types "selected-attribute-types" +#define LN_selected_attribute_types "Selected Attribute Types" +#define NID_selected_attribute_types 394 +#define OBJ_selected_attribute_types 2L, 5L, 1L, 5L + +#define SN_clearance "clearance" +#define NID_clearance 395 +#define OBJ_clearance 2L, 5L, 1L, 5L, 55L + +#define SN_md4WithRSAEncryption "RSA-MD4" +#define LN_md4WithRSAEncryption "md4WithRSAEncryption" +#define NID_md4WithRSAEncryption 396 +#define OBJ_md4WithRSAEncryption 1L, 2L, 840L, 113549L, 1L, 1L, 3L + +#define SN_ac_proxying "ac-proxying" +#define NID_ac_proxying 397 +#define OBJ_ac_proxying 1L, 3L, 6L, 1L, 5L, 5L, 7L, 1L, 10L + +#define SN_sinfo_access "subjectInfoAccess" +#define LN_sinfo_access "Subject Information Access" +#define NID_sinfo_access 398 +#define OBJ_sinfo_access 1L, 3L, 6L, 1L, 5L, 5L, 7L, 1L, 11L + +#define SN_id_aca_encAttrs "id-aca-encAttrs" +#define NID_id_aca_encAttrs 399 +#define OBJ_id_aca_encAttrs 1L, 3L, 6L, 1L, 5L, 5L, 7L, 10L, 6L + +#define SN_role "role" +#define LN_role "role" +#define NID_role 400 +#define OBJ_role 2L, 5L, 4L, 72L + +#define SN_policy_constraints "policyConstraints" +#define LN_policy_constraints "X509v3 Policy Constraints" +#define NID_policy_constraints 401 +#define OBJ_policy_constraints 2L, 5L, 29L, 36L + +#define SN_target_information "targetInformation" +#define LN_target_information "X509v3 AC Targeting" +#define NID_target_information 402 +#define OBJ_target_information 2L, 5L, 29L, 55L + +#define SN_no_rev_avail "noRevAvail" +#define LN_no_rev_avail "X509v3 No Revocation Available" +#define NID_no_rev_avail 403 +#define OBJ_no_rev_avail 2L, 5L, 29L, 56L + +#define SN_ansi_X9_62 "ansi-X9-62" +#define LN_ansi_X9_62 "ANSI X9.62" +#define NID_ansi_X9_62 405 +#define OBJ_ansi_X9_62 1L, 2L, 840L, 10045L + +#define SN_X9_62_prime_field "prime-field" +#define NID_X9_62_prime_field 406 +#define OBJ_X9_62_prime_field 1L, 2L, 840L, 10045L, 1L, 1L + +#define SN_X9_62_characteristic_two_field "characteristic-two-field" +#define NID_X9_62_characteristic_two_field 407 +#define OBJ_X9_62_characteristic_two_field 1L, 2L, 840L, 10045L, 1L, 2L + +#define SN_X9_62_id_ecPublicKey "id-ecPublicKey" +#define NID_X9_62_id_ecPublicKey 408 +#define OBJ_X9_62_id_ecPublicKey 1L, 2L, 840L, 10045L, 2L, 1L + +#define SN_X9_62_prime192v1 "prime192v1" +#define NID_X9_62_prime192v1 409 +#define OBJ_X9_62_prime192v1 1L, 2L, 840L, 10045L, 3L, 1L, 1L + +#define SN_X9_62_prime192v2 "prime192v2" +#define NID_X9_62_prime192v2 410 +#define OBJ_X9_62_prime192v2 1L, 2L, 840L, 10045L, 3L, 1L, 2L + +#define SN_X9_62_prime192v3 "prime192v3" +#define NID_X9_62_prime192v3 411 +#define OBJ_X9_62_prime192v3 1L, 2L, 840L, 10045L, 3L, 1L, 3L + +#define SN_X9_62_prime239v1 "prime239v1" +#define NID_X9_62_prime239v1 412 +#define OBJ_X9_62_prime239v1 1L, 2L, 840L, 10045L, 3L, 1L, 4L + +#define SN_X9_62_prime239v2 "prime239v2" +#define NID_X9_62_prime239v2 413 +#define OBJ_X9_62_prime239v2 1L, 2L, 840L, 10045L, 3L, 1L, 5L + +#define SN_X9_62_prime239v3 "prime239v3" +#define NID_X9_62_prime239v3 414 +#define OBJ_X9_62_prime239v3 1L, 2L, 840L, 10045L, 3L, 1L, 6L + +#define SN_X9_62_prime256v1 "prime256v1" +#define NID_X9_62_prime256v1 415 +#define OBJ_X9_62_prime256v1 1L, 2L, 840L, 10045L, 3L, 1L, 7L + +#define SN_ecdsa_with_SHA1 "ecdsa-with-SHA1" +#define NID_ecdsa_with_SHA1 416 +#define OBJ_ecdsa_with_SHA1 1L, 2L, 840L, 10045L, 4L, 1L + +#define SN_ms_csp_name "CSPName" +#define LN_ms_csp_name "Microsoft CSP Name" +#define NID_ms_csp_name 417 +#define OBJ_ms_csp_name 1L, 3L, 6L, 1L, 4L, 1L, 311L, 17L, 1L + +#define SN_aes_128_ecb "AES-128-ECB" +#define LN_aes_128_ecb "aes-128-ecb" +#define NID_aes_128_ecb 418 +#define OBJ_aes_128_ecb 2L, 16L, 840L, 1L, 101L, 3L, 4L, 1L, 1L + +#define SN_aes_128_cbc "AES-128-CBC" +#define LN_aes_128_cbc "aes-128-cbc" +#define NID_aes_128_cbc 419 +#define OBJ_aes_128_cbc 2L, 16L, 840L, 1L, 101L, 3L, 4L, 1L, 2L + +#define SN_aes_128_ofb128 "AES-128-OFB" +#define LN_aes_128_ofb128 "aes-128-ofb" +#define NID_aes_128_ofb128 420 +#define OBJ_aes_128_ofb128 2L, 16L, 840L, 1L, 101L, 3L, 4L, 1L, 3L + +#define SN_aes_128_cfb128 "AES-128-CFB" +#define LN_aes_128_cfb128 "aes-128-cfb" +#define NID_aes_128_cfb128 421 +#define OBJ_aes_128_cfb128 2L, 16L, 840L, 1L, 101L, 3L, 4L, 1L, 4L + +#define SN_aes_192_ecb "AES-192-ECB" +#define LN_aes_192_ecb "aes-192-ecb" +#define NID_aes_192_ecb 422 +#define OBJ_aes_192_ecb 2L, 16L, 840L, 1L, 101L, 3L, 4L, 1L, 21L + +#define SN_aes_192_cbc "AES-192-CBC" +#define LN_aes_192_cbc "aes-192-cbc" +#define NID_aes_192_cbc 423 +#define OBJ_aes_192_cbc 2L, 16L, 840L, 1L, 101L, 3L, 4L, 1L, 22L + +#define SN_aes_192_ofb128 "AES-192-OFB" +#define LN_aes_192_ofb128 "aes-192-ofb" +#define NID_aes_192_ofb128 424 +#define OBJ_aes_192_ofb128 2L, 16L, 840L, 1L, 101L, 3L, 4L, 1L, 23L + +#define SN_aes_192_cfb128 "AES-192-CFB" +#define LN_aes_192_cfb128 "aes-192-cfb" +#define NID_aes_192_cfb128 425 +#define OBJ_aes_192_cfb128 2L, 16L, 840L, 1L, 101L, 3L, 4L, 1L, 24L + +#define SN_aes_256_ecb "AES-256-ECB" +#define LN_aes_256_ecb "aes-256-ecb" +#define NID_aes_256_ecb 426 +#define OBJ_aes_256_ecb 2L, 16L, 840L, 1L, 101L, 3L, 4L, 1L, 41L + +#define SN_aes_256_cbc "AES-256-CBC" +#define LN_aes_256_cbc "aes-256-cbc" +#define NID_aes_256_cbc 427 +#define OBJ_aes_256_cbc 2L, 16L, 840L, 1L, 101L, 3L, 4L, 1L, 42L + +#define SN_aes_256_ofb128 "AES-256-OFB" +#define LN_aes_256_ofb128 "aes-256-ofb" +#define NID_aes_256_ofb128 428 +#define OBJ_aes_256_ofb128 2L, 16L, 840L, 1L, 101L, 3L, 4L, 1L, 43L + +#define SN_aes_256_cfb128 "AES-256-CFB" +#define LN_aes_256_cfb128 "aes-256-cfb" +#define NID_aes_256_cfb128 429 +#define OBJ_aes_256_cfb128 2L, 16L, 840L, 1L, 101L, 3L, 4L, 1L, 44L + +#define SN_hold_instruction_code "holdInstructionCode" +#define LN_hold_instruction_code "Hold Instruction Code" +#define NID_hold_instruction_code 430 +#define OBJ_hold_instruction_code 2L, 5L, 29L, 23L + +#define SN_hold_instruction_none "holdInstructionNone" +#define LN_hold_instruction_none "Hold Instruction None" +#define NID_hold_instruction_none 431 +#define OBJ_hold_instruction_none 1L, 2L, 840L, 10040L, 2L, 1L + +#define SN_hold_instruction_call_issuer "holdInstructionCallIssuer" +#define LN_hold_instruction_call_issuer "Hold Instruction Call Issuer" +#define NID_hold_instruction_call_issuer 432 +#define OBJ_hold_instruction_call_issuer 1L, 2L, 840L, 10040L, 2L, 2L + +#define SN_hold_instruction_reject "holdInstructionReject" +#define LN_hold_instruction_reject "Hold Instruction Reject" +#define NID_hold_instruction_reject 433 +#define OBJ_hold_instruction_reject 1L, 2L, 840L, 10040L, 2L, 3L + +#define SN_data "data" +#define NID_data 434 +#define OBJ_data 0L, 9L + +#define SN_pss "pss" +#define NID_pss 435 +#define OBJ_pss 0L, 9L, 2342L + +#define SN_ucl "ucl" +#define NID_ucl 436 +#define OBJ_ucl 0L, 9L, 2342L, 19200300L + +#define SN_pilot "pilot" +#define NID_pilot 437 +#define OBJ_pilot 0L, 9L, 2342L, 19200300L, 100L + +#define LN_pilotAttributeType "pilotAttributeType" +#define NID_pilotAttributeType 438 +#define OBJ_pilotAttributeType 0L, 9L, 2342L, 19200300L, 100L, 1L + +#define LN_pilotAttributeSyntax "pilotAttributeSyntax" +#define NID_pilotAttributeSyntax 439 +#define OBJ_pilotAttributeSyntax 0L, 9L, 2342L, 19200300L, 100L, 3L + +#define LN_pilotObjectClass "pilotObjectClass" +#define NID_pilotObjectClass 440 +#define OBJ_pilotObjectClass 0L, 9L, 2342L, 19200300L, 100L, 4L + +#define LN_pilotGroups "pilotGroups" +#define NID_pilotGroups 441 +#define OBJ_pilotGroups 0L, 9L, 2342L, 19200300L, 100L, 10L + +#define LN_iA5StringSyntax "iA5StringSyntax" +#define NID_iA5StringSyntax 442 +#define OBJ_iA5StringSyntax 0L, 9L, 2342L, 19200300L, 100L, 3L, 4L + +#define LN_caseIgnoreIA5StringSyntax "caseIgnoreIA5StringSyntax" +#define NID_caseIgnoreIA5StringSyntax 443 +#define OBJ_caseIgnoreIA5StringSyntax 0L, 9L, 2342L, 19200300L, 100L, 3L, 5L + +#define LN_pilotObject "pilotObject" +#define NID_pilotObject 444 +#define OBJ_pilotObject 0L, 9L, 2342L, 19200300L, 100L, 4L, 3L + +#define LN_pilotPerson "pilotPerson" +#define NID_pilotPerson 445 +#define OBJ_pilotPerson 0L, 9L, 2342L, 19200300L, 100L, 4L, 4L + +#define SN_account "account" +#define NID_account 446 +#define OBJ_account 0L, 9L, 2342L, 19200300L, 100L, 4L, 5L + +#define SN_document "document" +#define NID_document 447 +#define OBJ_document 0L, 9L, 2342L, 19200300L, 100L, 4L, 6L + +#define SN_room "room" +#define NID_room 448 +#define OBJ_room 0L, 9L, 2342L, 19200300L, 100L, 4L, 7L + +#define LN_documentSeries "documentSeries" +#define NID_documentSeries 449 +#define OBJ_documentSeries 0L, 9L, 2342L, 19200300L, 100L, 4L, 9L + +#define LN_rFC822localPart "rFC822localPart" +#define NID_rFC822localPart 450 +#define OBJ_rFC822localPart 0L, 9L, 2342L, 19200300L, 100L, 4L, 14L + +#define LN_dNSDomain "dNSDomain" +#define NID_dNSDomain 451 +#define OBJ_dNSDomain 0L, 9L, 2342L, 19200300L, 100L, 4L, 15L + +#define LN_domainRelatedObject "domainRelatedObject" +#define NID_domainRelatedObject 452 +#define OBJ_domainRelatedObject 0L, 9L, 2342L, 19200300L, 100L, 4L, 17L + +#define LN_friendlyCountry "friendlyCountry" +#define NID_friendlyCountry 453 +#define OBJ_friendlyCountry 0L, 9L, 2342L, 19200300L, 100L, 4L, 18L + +#define LN_simpleSecurityObject "simpleSecurityObject" +#define NID_simpleSecurityObject 454 +#define OBJ_simpleSecurityObject 0L, 9L, 2342L, 19200300L, 100L, 4L, 19L + +#define LN_pilotOrganization "pilotOrganization" +#define NID_pilotOrganization 455 +#define OBJ_pilotOrganization 0L, 9L, 2342L, 19200300L, 100L, 4L, 20L + +#define LN_pilotDSA "pilotDSA" +#define NID_pilotDSA 456 +#define OBJ_pilotDSA 0L, 9L, 2342L, 19200300L, 100L, 4L, 21L + +#define LN_qualityLabelledData "qualityLabelledData" +#define NID_qualityLabelledData 457 +#define OBJ_qualityLabelledData 0L, 9L, 2342L, 19200300L, 100L, 4L, 22L + +#define SN_userId "UID" +#define LN_userId "userId" +#define NID_userId 458 +#define OBJ_userId 0L, 9L, 2342L, 19200300L, 100L, 1L, 1L + +#define LN_textEncodedORAddress "textEncodedORAddress" +#define NID_textEncodedORAddress 459 +#define OBJ_textEncodedORAddress 0L, 9L, 2342L, 19200300L, 100L, 1L, 2L + +#define SN_rfc822Mailbox "mail" +#define LN_rfc822Mailbox "rfc822Mailbox" +#define NID_rfc822Mailbox 460 +#define OBJ_rfc822Mailbox 0L, 9L, 2342L, 19200300L, 100L, 1L, 3L + +#define SN_info "info" +#define NID_info 461 +#define OBJ_info 0L, 9L, 2342L, 19200300L, 100L, 1L, 4L + +#define LN_favouriteDrink "favouriteDrink" +#define NID_favouriteDrink 462 +#define OBJ_favouriteDrink 0L, 9L, 2342L, 19200300L, 100L, 1L, 5L + +#define LN_roomNumber "roomNumber" +#define NID_roomNumber 463 +#define OBJ_roomNumber 0L, 9L, 2342L, 19200300L, 100L, 1L, 6L + +#define SN_photo "photo" +#define NID_photo 464 +#define OBJ_photo 0L, 9L, 2342L, 19200300L, 100L, 1L, 7L + +#define LN_userClass "userClass" +#define NID_userClass 465 +#define OBJ_userClass 0L, 9L, 2342L, 19200300L, 100L, 1L, 8L + +#define SN_host "host" +#define NID_host 466 +#define OBJ_host 0L, 9L, 2342L, 19200300L, 100L, 1L, 9L + +#define SN_manager "manager" +#define NID_manager 467 +#define OBJ_manager 0L, 9L, 2342L, 19200300L, 100L, 1L, 10L + +#define LN_documentIdentifier "documentIdentifier" +#define NID_documentIdentifier 468 +#define OBJ_documentIdentifier 0L, 9L, 2342L, 19200300L, 100L, 1L, 11L + +#define LN_documentTitle "documentTitle" +#define NID_documentTitle 469 +#define OBJ_documentTitle 0L, 9L, 2342L, 19200300L, 100L, 1L, 12L + +#define LN_documentVersion "documentVersion" +#define NID_documentVersion 470 +#define OBJ_documentVersion 0L, 9L, 2342L, 19200300L, 100L, 1L, 13L + +#define LN_documentAuthor "documentAuthor" +#define NID_documentAuthor 471 +#define OBJ_documentAuthor 0L, 9L, 2342L, 19200300L, 100L, 1L, 14L + +#define LN_documentLocation "documentLocation" +#define NID_documentLocation 472 +#define OBJ_documentLocation 0L, 9L, 2342L, 19200300L, 100L, 1L, 15L + +#define LN_homeTelephoneNumber "homeTelephoneNumber" +#define NID_homeTelephoneNumber 473 +#define OBJ_homeTelephoneNumber 0L, 9L, 2342L, 19200300L, 100L, 1L, 20L + +#define SN_secretary "secretary" +#define NID_secretary 474 +#define OBJ_secretary 0L, 9L, 2342L, 19200300L, 100L, 1L, 21L + +#define LN_otherMailbox "otherMailbox" +#define NID_otherMailbox 475 +#define OBJ_otherMailbox 0L, 9L, 2342L, 19200300L, 100L, 1L, 22L + +#define LN_lastModifiedTime "lastModifiedTime" +#define NID_lastModifiedTime 476 +#define OBJ_lastModifiedTime 0L, 9L, 2342L, 19200300L, 100L, 1L, 23L + +#define LN_lastModifiedBy "lastModifiedBy" +#define NID_lastModifiedBy 477 +#define OBJ_lastModifiedBy 0L, 9L, 2342L, 19200300L, 100L, 1L, 24L + +#define LN_aRecord "aRecord" +#define NID_aRecord 478 +#define OBJ_aRecord 0L, 9L, 2342L, 19200300L, 100L, 1L, 26L + +#define LN_pilotAttributeType27 "pilotAttributeType27" +#define NID_pilotAttributeType27 479 +#define OBJ_pilotAttributeType27 0L, 9L, 2342L, 19200300L, 100L, 1L, 27L + +#define LN_mXRecord "mXRecord" +#define NID_mXRecord 480 +#define OBJ_mXRecord 0L, 9L, 2342L, 19200300L, 100L, 1L, 28L + +#define LN_nSRecord "nSRecord" +#define NID_nSRecord 481 +#define OBJ_nSRecord 0L, 9L, 2342L, 19200300L, 100L, 1L, 29L + +#define LN_sOARecord "sOARecord" +#define NID_sOARecord 482 +#define OBJ_sOARecord 0L, 9L, 2342L, 19200300L, 100L, 1L, 30L + +#define LN_cNAMERecord "cNAMERecord" +#define NID_cNAMERecord 483 +#define OBJ_cNAMERecord 0L, 9L, 2342L, 19200300L, 100L, 1L, 31L + +#define LN_associatedDomain "associatedDomain" +#define NID_associatedDomain 484 +#define OBJ_associatedDomain 0L, 9L, 2342L, 19200300L, 100L, 1L, 37L + +#define LN_associatedName "associatedName" +#define NID_associatedName 485 +#define OBJ_associatedName 0L, 9L, 2342L, 19200300L, 100L, 1L, 38L + +#define LN_homePostalAddress "homePostalAddress" +#define NID_homePostalAddress 486 +#define OBJ_homePostalAddress 0L, 9L, 2342L, 19200300L, 100L, 1L, 39L + +#define LN_personalTitle "personalTitle" +#define NID_personalTitle 487 +#define OBJ_personalTitle 0L, 9L, 2342L, 19200300L, 100L, 1L, 40L + +#define LN_mobileTelephoneNumber "mobileTelephoneNumber" +#define NID_mobileTelephoneNumber 488 +#define OBJ_mobileTelephoneNumber 0L, 9L, 2342L, 19200300L, 100L, 1L, 41L + +#define LN_pagerTelephoneNumber "pagerTelephoneNumber" +#define NID_pagerTelephoneNumber 489 +#define OBJ_pagerTelephoneNumber 0L, 9L, 2342L, 19200300L, 100L, 1L, 42L + +#define LN_friendlyCountryName "friendlyCountryName" +#define NID_friendlyCountryName 490 +#define OBJ_friendlyCountryName 0L, 9L, 2342L, 19200300L, 100L, 1L, 43L + +#define LN_organizationalStatus "organizationalStatus" +#define NID_organizationalStatus 491 +#define OBJ_organizationalStatus 0L, 9L, 2342L, 19200300L, 100L, 1L, 45L + +#define LN_janetMailbox "janetMailbox" +#define NID_janetMailbox 492 +#define OBJ_janetMailbox 0L, 9L, 2342L, 19200300L, 100L, 1L, 46L + +#define LN_mailPreferenceOption "mailPreferenceOption" +#define NID_mailPreferenceOption 493 +#define OBJ_mailPreferenceOption 0L, 9L, 2342L, 19200300L, 100L, 1L, 47L + +#define LN_buildingName "buildingName" +#define NID_buildingName 494 +#define OBJ_buildingName 0L, 9L, 2342L, 19200300L, 100L, 1L, 48L + +#define LN_dSAQuality "dSAQuality" +#define NID_dSAQuality 495 +#define OBJ_dSAQuality 0L, 9L, 2342L, 19200300L, 100L, 1L, 49L + +#define LN_singleLevelQuality "singleLevelQuality" +#define NID_singleLevelQuality 496 +#define OBJ_singleLevelQuality 0L, 9L, 2342L, 19200300L, 100L, 1L, 50L + +#define LN_subtreeMinimumQuality "subtreeMinimumQuality" +#define NID_subtreeMinimumQuality 497 +#define OBJ_subtreeMinimumQuality 0L, 9L, 2342L, 19200300L, 100L, 1L, 51L + +#define LN_subtreeMaximumQuality "subtreeMaximumQuality" +#define NID_subtreeMaximumQuality 498 +#define OBJ_subtreeMaximumQuality 0L, 9L, 2342L, 19200300L, 100L, 1L, 52L + +#define LN_personalSignature "personalSignature" +#define NID_personalSignature 499 +#define OBJ_personalSignature 0L, 9L, 2342L, 19200300L, 100L, 1L, 53L + +#define LN_dITRedirect "dITRedirect" +#define NID_dITRedirect 500 +#define OBJ_dITRedirect 0L, 9L, 2342L, 19200300L, 100L, 1L, 54L + +#define SN_audio "audio" +#define NID_audio 501 +#define OBJ_audio 0L, 9L, 2342L, 19200300L, 100L, 1L, 55L + +#define LN_documentPublisher "documentPublisher" +#define NID_documentPublisher 502 +#define OBJ_documentPublisher 0L, 9L, 2342L, 19200300L, 100L, 1L, 56L + +#define LN_x500UniqueIdentifier "x500UniqueIdentifier" +#define NID_x500UniqueIdentifier 503 +#define OBJ_x500UniqueIdentifier 2L, 5L, 4L, 45L + +#define SN_mime_mhs "mime-mhs" +#define LN_mime_mhs "MIME MHS" +#define NID_mime_mhs 504 +#define OBJ_mime_mhs 1L, 3L, 6L, 1L, 7L, 1L + +#define SN_mime_mhs_headings "mime-mhs-headings" +#define LN_mime_mhs_headings "mime-mhs-headings" +#define NID_mime_mhs_headings 505 +#define OBJ_mime_mhs_headings 1L, 3L, 6L, 1L, 7L, 1L, 1L + +#define SN_mime_mhs_bodies "mime-mhs-bodies" +#define LN_mime_mhs_bodies "mime-mhs-bodies" +#define NID_mime_mhs_bodies 506 +#define OBJ_mime_mhs_bodies 1L, 3L, 6L, 1L, 7L, 1L, 2L + +#define SN_id_hex_partial_message "id-hex-partial-message" +#define LN_id_hex_partial_message "id-hex-partial-message" +#define NID_id_hex_partial_message 507 +#define OBJ_id_hex_partial_message 1L, 3L, 6L, 1L, 7L, 1L, 1L, 1L + +#define SN_id_hex_multipart_message "id-hex-multipart-message" +#define LN_id_hex_multipart_message "id-hex-multipart-message" +#define NID_id_hex_multipart_message 508 +#define OBJ_id_hex_multipart_message 1L, 3L, 6L, 1L, 7L, 1L, 1L, 2L + +#define LN_generationQualifier "generationQualifier" +#define NID_generationQualifier 509 +#define OBJ_generationQualifier 2L, 5L, 4L, 44L + +#define LN_pseudonym "pseudonym" +#define NID_pseudonym 510 +#define OBJ_pseudonym 2L, 5L, 4L, 65L + +#define SN_id_set "id-set" +#define LN_id_set "Secure Electronic Transactions" +#define NID_id_set 512 +#define OBJ_id_set 2L, 23L, 42L + +#define SN_set_ctype "set-ctype" +#define LN_set_ctype "content types" +#define NID_set_ctype 513 +#define OBJ_set_ctype 2L, 23L, 42L, 0L + +#define SN_set_msgExt "set-msgExt" +#define LN_set_msgExt "message extensions" +#define NID_set_msgExt 514 +#define OBJ_set_msgExt 2L, 23L, 42L, 1L + +#define SN_set_attr "set-attr" +#define NID_set_attr 515 +#define OBJ_set_attr 2L, 23L, 42L, 3L + +#define SN_set_policy "set-policy" +#define NID_set_policy 516 +#define OBJ_set_policy 2L, 23L, 42L, 5L + +#define SN_set_certExt "set-certExt" +#define LN_set_certExt "certificate extensions" +#define NID_set_certExt 517 +#define OBJ_set_certExt 2L, 23L, 42L, 7L + +#define SN_set_brand "set-brand" +#define NID_set_brand 518 +#define OBJ_set_brand 2L, 23L, 42L, 8L + +#define SN_setct_PANData "setct-PANData" +#define NID_setct_PANData 519 +#define OBJ_setct_PANData 2L, 23L, 42L, 0L, 0L + +#define SN_setct_PANToken "setct-PANToken" +#define NID_setct_PANToken 520 +#define OBJ_setct_PANToken 2L, 23L, 42L, 0L, 1L + +#define SN_setct_PANOnly "setct-PANOnly" +#define NID_setct_PANOnly 521 +#define OBJ_setct_PANOnly 2L, 23L, 42L, 0L, 2L + +#define SN_setct_OIData "setct-OIData" +#define NID_setct_OIData 522 +#define OBJ_setct_OIData 2L, 23L, 42L, 0L, 3L + +#define SN_setct_PI "setct-PI" +#define NID_setct_PI 523 +#define OBJ_setct_PI 2L, 23L, 42L, 0L, 4L + +#define SN_setct_PIData "setct-PIData" +#define NID_setct_PIData 524 +#define OBJ_setct_PIData 2L, 23L, 42L, 0L, 5L + +#define SN_setct_PIDataUnsigned "setct-PIDataUnsigned" +#define NID_setct_PIDataUnsigned 525 +#define OBJ_setct_PIDataUnsigned 2L, 23L, 42L, 0L, 6L + +#define SN_setct_HODInput "setct-HODInput" +#define NID_setct_HODInput 526 +#define OBJ_setct_HODInput 2L, 23L, 42L, 0L, 7L + +#define SN_setct_AuthResBaggage "setct-AuthResBaggage" +#define NID_setct_AuthResBaggage 527 +#define OBJ_setct_AuthResBaggage 2L, 23L, 42L, 0L, 8L + +#define SN_setct_AuthRevReqBaggage "setct-AuthRevReqBaggage" +#define NID_setct_AuthRevReqBaggage 528 +#define OBJ_setct_AuthRevReqBaggage 2L, 23L, 42L, 0L, 9L + +#define SN_setct_AuthRevResBaggage "setct-AuthRevResBaggage" +#define NID_setct_AuthRevResBaggage 529 +#define OBJ_setct_AuthRevResBaggage 2L, 23L, 42L, 0L, 10L + +#define SN_setct_CapTokenSeq "setct-CapTokenSeq" +#define NID_setct_CapTokenSeq 530 +#define OBJ_setct_CapTokenSeq 2L, 23L, 42L, 0L, 11L + +#define SN_setct_PInitResData "setct-PInitResData" +#define NID_setct_PInitResData 531 +#define OBJ_setct_PInitResData 2L, 23L, 42L, 0L, 12L + +#define SN_setct_PI_TBS "setct-PI-TBS" +#define NID_setct_PI_TBS 532 +#define OBJ_setct_PI_TBS 2L, 23L, 42L, 0L, 13L + +#define SN_setct_PResData "setct-PResData" +#define NID_setct_PResData 533 +#define OBJ_setct_PResData 2L, 23L, 42L, 0L, 14L + +#define SN_setct_AuthReqTBS "setct-AuthReqTBS" +#define NID_setct_AuthReqTBS 534 +#define OBJ_setct_AuthReqTBS 2L, 23L, 42L, 0L, 16L + +#define SN_setct_AuthResTBS "setct-AuthResTBS" +#define NID_setct_AuthResTBS 535 +#define OBJ_setct_AuthResTBS 2L, 23L, 42L, 0L, 17L + +#define SN_setct_AuthResTBSX "setct-AuthResTBSX" +#define NID_setct_AuthResTBSX 536 +#define OBJ_setct_AuthResTBSX 2L, 23L, 42L, 0L, 18L + +#define SN_setct_AuthTokenTBS "setct-AuthTokenTBS" +#define NID_setct_AuthTokenTBS 537 +#define OBJ_setct_AuthTokenTBS 2L, 23L, 42L, 0L, 19L + +#define SN_setct_CapTokenData "setct-CapTokenData" +#define NID_setct_CapTokenData 538 +#define OBJ_setct_CapTokenData 2L, 23L, 42L, 0L, 20L + +#define SN_setct_CapTokenTBS "setct-CapTokenTBS" +#define NID_setct_CapTokenTBS 539 +#define OBJ_setct_CapTokenTBS 2L, 23L, 42L, 0L, 21L + +#define SN_setct_AcqCardCodeMsg "setct-AcqCardCodeMsg" +#define NID_setct_AcqCardCodeMsg 540 +#define OBJ_setct_AcqCardCodeMsg 2L, 23L, 42L, 0L, 22L + +#define SN_setct_AuthRevReqTBS "setct-AuthRevReqTBS" +#define NID_setct_AuthRevReqTBS 541 +#define OBJ_setct_AuthRevReqTBS 2L, 23L, 42L, 0L, 23L + +#define SN_setct_AuthRevResData "setct-AuthRevResData" +#define NID_setct_AuthRevResData 542 +#define OBJ_setct_AuthRevResData 2L, 23L, 42L, 0L, 24L + +#define SN_setct_AuthRevResTBS "setct-AuthRevResTBS" +#define NID_setct_AuthRevResTBS 543 +#define OBJ_setct_AuthRevResTBS 2L, 23L, 42L, 0L, 25L + +#define SN_setct_CapReqTBS "setct-CapReqTBS" +#define NID_setct_CapReqTBS 544 +#define OBJ_setct_CapReqTBS 2L, 23L, 42L, 0L, 26L + +#define SN_setct_CapReqTBSX "setct-CapReqTBSX" +#define NID_setct_CapReqTBSX 545 +#define OBJ_setct_CapReqTBSX 2L, 23L, 42L, 0L, 27L + +#define SN_setct_CapResData "setct-CapResData" +#define NID_setct_CapResData 546 +#define OBJ_setct_CapResData 2L, 23L, 42L, 0L, 28L + +#define SN_setct_CapRevReqTBS "setct-CapRevReqTBS" +#define NID_setct_CapRevReqTBS 547 +#define OBJ_setct_CapRevReqTBS 2L, 23L, 42L, 0L, 29L + +#define SN_setct_CapRevReqTBSX "setct-CapRevReqTBSX" +#define NID_setct_CapRevReqTBSX 548 +#define OBJ_setct_CapRevReqTBSX 2L, 23L, 42L, 0L, 30L + +#define SN_setct_CapRevResData "setct-CapRevResData" +#define NID_setct_CapRevResData 549 +#define OBJ_setct_CapRevResData 2L, 23L, 42L, 0L, 31L + +#define SN_setct_CredReqTBS "setct-CredReqTBS" +#define NID_setct_CredReqTBS 550 +#define OBJ_setct_CredReqTBS 2L, 23L, 42L, 0L, 32L + +#define SN_setct_CredReqTBSX "setct-CredReqTBSX" +#define NID_setct_CredReqTBSX 551 +#define OBJ_setct_CredReqTBSX 2L, 23L, 42L, 0L, 33L + +#define SN_setct_CredResData "setct-CredResData" +#define NID_setct_CredResData 552 +#define OBJ_setct_CredResData 2L, 23L, 42L, 0L, 34L + +#define SN_setct_CredRevReqTBS "setct-CredRevReqTBS" +#define NID_setct_CredRevReqTBS 553 +#define OBJ_setct_CredRevReqTBS 2L, 23L, 42L, 0L, 35L + +#define SN_setct_CredRevReqTBSX "setct-CredRevReqTBSX" +#define NID_setct_CredRevReqTBSX 554 +#define OBJ_setct_CredRevReqTBSX 2L, 23L, 42L, 0L, 36L + +#define SN_setct_CredRevResData "setct-CredRevResData" +#define NID_setct_CredRevResData 555 +#define OBJ_setct_CredRevResData 2L, 23L, 42L, 0L, 37L + +#define SN_setct_PCertReqData "setct-PCertReqData" +#define NID_setct_PCertReqData 556 +#define OBJ_setct_PCertReqData 2L, 23L, 42L, 0L, 38L + +#define SN_setct_PCertResTBS "setct-PCertResTBS" +#define NID_setct_PCertResTBS 557 +#define OBJ_setct_PCertResTBS 2L, 23L, 42L, 0L, 39L + +#define SN_setct_BatchAdminReqData "setct-BatchAdminReqData" +#define NID_setct_BatchAdminReqData 558 +#define OBJ_setct_BatchAdminReqData 2L, 23L, 42L, 0L, 40L + +#define SN_setct_BatchAdminResData "setct-BatchAdminResData" +#define NID_setct_BatchAdminResData 559 +#define OBJ_setct_BatchAdminResData 2L, 23L, 42L, 0L, 41L + +#define SN_setct_CardCInitResTBS "setct-CardCInitResTBS" +#define NID_setct_CardCInitResTBS 560 +#define OBJ_setct_CardCInitResTBS 2L, 23L, 42L, 0L, 42L + +#define SN_setct_MeAqCInitResTBS "setct-MeAqCInitResTBS" +#define NID_setct_MeAqCInitResTBS 561 +#define OBJ_setct_MeAqCInitResTBS 2L, 23L, 42L, 0L, 43L + +#define SN_setct_RegFormResTBS "setct-RegFormResTBS" +#define NID_setct_RegFormResTBS 562 +#define OBJ_setct_RegFormResTBS 2L, 23L, 42L, 0L, 44L + +#define SN_setct_CertReqData "setct-CertReqData" +#define NID_setct_CertReqData 563 +#define OBJ_setct_CertReqData 2L, 23L, 42L, 0L, 45L + +#define SN_setct_CertReqTBS "setct-CertReqTBS" +#define NID_setct_CertReqTBS 564 +#define OBJ_setct_CertReqTBS 2L, 23L, 42L, 0L, 46L + +#define SN_setct_CertResData "setct-CertResData" +#define NID_setct_CertResData 565 +#define OBJ_setct_CertResData 2L, 23L, 42L, 0L, 47L + +#define SN_setct_CertInqReqTBS "setct-CertInqReqTBS" +#define NID_setct_CertInqReqTBS 566 +#define OBJ_setct_CertInqReqTBS 2L, 23L, 42L, 0L, 48L + +#define SN_setct_ErrorTBS "setct-ErrorTBS" +#define NID_setct_ErrorTBS 567 +#define OBJ_setct_ErrorTBS 2L, 23L, 42L, 0L, 49L + +#define SN_setct_PIDualSignedTBE "setct-PIDualSignedTBE" +#define NID_setct_PIDualSignedTBE 568 +#define OBJ_setct_PIDualSignedTBE 2L, 23L, 42L, 0L, 50L + +#define SN_setct_PIUnsignedTBE "setct-PIUnsignedTBE" +#define NID_setct_PIUnsignedTBE 569 +#define OBJ_setct_PIUnsignedTBE 2L, 23L, 42L, 0L, 51L + +#define SN_setct_AuthReqTBE "setct-AuthReqTBE" +#define NID_setct_AuthReqTBE 570 +#define OBJ_setct_AuthReqTBE 2L, 23L, 42L, 0L, 52L + +#define SN_setct_AuthResTBE "setct-AuthResTBE" +#define NID_setct_AuthResTBE 571 +#define OBJ_setct_AuthResTBE 2L, 23L, 42L, 0L, 53L + +#define SN_setct_AuthResTBEX "setct-AuthResTBEX" +#define NID_setct_AuthResTBEX 572 +#define OBJ_setct_AuthResTBEX 2L, 23L, 42L, 0L, 54L + +#define SN_setct_AuthTokenTBE "setct-AuthTokenTBE" +#define NID_setct_AuthTokenTBE 573 +#define OBJ_setct_AuthTokenTBE 2L, 23L, 42L, 0L, 55L + +#define SN_setct_CapTokenTBE "setct-CapTokenTBE" +#define NID_setct_CapTokenTBE 574 +#define OBJ_setct_CapTokenTBE 2L, 23L, 42L, 0L, 56L + +#define SN_setct_CapTokenTBEX "setct-CapTokenTBEX" +#define NID_setct_CapTokenTBEX 575 +#define OBJ_setct_CapTokenTBEX 2L, 23L, 42L, 0L, 57L + +#define SN_setct_AcqCardCodeMsgTBE "setct-AcqCardCodeMsgTBE" +#define NID_setct_AcqCardCodeMsgTBE 576 +#define OBJ_setct_AcqCardCodeMsgTBE 2L, 23L, 42L, 0L, 58L + +#define SN_setct_AuthRevReqTBE "setct-AuthRevReqTBE" +#define NID_setct_AuthRevReqTBE 577 +#define OBJ_setct_AuthRevReqTBE 2L, 23L, 42L, 0L, 59L + +#define SN_setct_AuthRevResTBE "setct-AuthRevResTBE" +#define NID_setct_AuthRevResTBE 578 +#define OBJ_setct_AuthRevResTBE 2L, 23L, 42L, 0L, 60L + +#define SN_setct_AuthRevResTBEB "setct-AuthRevResTBEB" +#define NID_setct_AuthRevResTBEB 579 +#define OBJ_setct_AuthRevResTBEB 2L, 23L, 42L, 0L, 61L + +#define SN_setct_CapReqTBE "setct-CapReqTBE" +#define NID_setct_CapReqTBE 580 +#define OBJ_setct_CapReqTBE 2L, 23L, 42L, 0L, 62L + +#define SN_setct_CapReqTBEX "setct-CapReqTBEX" +#define NID_setct_CapReqTBEX 581 +#define OBJ_setct_CapReqTBEX 2L, 23L, 42L, 0L, 63L + +#define SN_setct_CapResTBE "setct-CapResTBE" +#define NID_setct_CapResTBE 582 +#define OBJ_setct_CapResTBE 2L, 23L, 42L, 0L, 64L + +#define SN_setct_CapRevReqTBE "setct-CapRevReqTBE" +#define NID_setct_CapRevReqTBE 583 +#define OBJ_setct_CapRevReqTBE 2L, 23L, 42L, 0L, 65L + +#define SN_setct_CapRevReqTBEX "setct-CapRevReqTBEX" +#define NID_setct_CapRevReqTBEX 584 +#define OBJ_setct_CapRevReqTBEX 2L, 23L, 42L, 0L, 66L + +#define SN_setct_CapRevResTBE "setct-CapRevResTBE" +#define NID_setct_CapRevResTBE 585 +#define OBJ_setct_CapRevResTBE 2L, 23L, 42L, 0L, 67L + +#define SN_setct_CredReqTBE "setct-CredReqTBE" +#define NID_setct_CredReqTBE 586 +#define OBJ_setct_CredReqTBE 2L, 23L, 42L, 0L, 68L + +#define SN_setct_CredReqTBEX "setct-CredReqTBEX" +#define NID_setct_CredReqTBEX 587 +#define OBJ_setct_CredReqTBEX 2L, 23L, 42L, 0L, 69L + +#define SN_setct_CredResTBE "setct-CredResTBE" +#define NID_setct_CredResTBE 588 +#define OBJ_setct_CredResTBE 2L, 23L, 42L, 0L, 70L + +#define SN_setct_CredRevReqTBE "setct-CredRevReqTBE" +#define NID_setct_CredRevReqTBE 589 +#define OBJ_setct_CredRevReqTBE 2L, 23L, 42L, 0L, 71L + +#define SN_setct_CredRevReqTBEX "setct-CredRevReqTBEX" +#define NID_setct_CredRevReqTBEX 590 +#define OBJ_setct_CredRevReqTBEX 2L, 23L, 42L, 0L, 72L + +#define SN_setct_CredRevResTBE "setct-CredRevResTBE" +#define NID_setct_CredRevResTBE 591 +#define OBJ_setct_CredRevResTBE 2L, 23L, 42L, 0L, 73L + +#define SN_setct_BatchAdminReqTBE "setct-BatchAdminReqTBE" +#define NID_setct_BatchAdminReqTBE 592 +#define OBJ_setct_BatchAdminReqTBE 2L, 23L, 42L, 0L, 74L + +#define SN_setct_BatchAdminResTBE "setct-BatchAdminResTBE" +#define NID_setct_BatchAdminResTBE 593 +#define OBJ_setct_BatchAdminResTBE 2L, 23L, 42L, 0L, 75L + +#define SN_setct_RegFormReqTBE "setct-RegFormReqTBE" +#define NID_setct_RegFormReqTBE 594 +#define OBJ_setct_RegFormReqTBE 2L, 23L, 42L, 0L, 76L + +#define SN_setct_CertReqTBE "setct-CertReqTBE" +#define NID_setct_CertReqTBE 595 +#define OBJ_setct_CertReqTBE 2L, 23L, 42L, 0L, 77L + +#define SN_setct_CertReqTBEX "setct-CertReqTBEX" +#define NID_setct_CertReqTBEX 596 +#define OBJ_setct_CertReqTBEX 2L, 23L, 42L, 0L, 78L + +#define SN_setct_CertResTBE "setct-CertResTBE" +#define NID_setct_CertResTBE 597 +#define OBJ_setct_CertResTBE 2L, 23L, 42L, 0L, 79L + +#define SN_setct_CRLNotificationTBS "setct-CRLNotificationTBS" +#define NID_setct_CRLNotificationTBS 598 +#define OBJ_setct_CRLNotificationTBS 2L, 23L, 42L, 0L, 80L + +#define SN_setct_CRLNotificationResTBS "setct-CRLNotificationResTBS" +#define NID_setct_CRLNotificationResTBS 599 +#define OBJ_setct_CRLNotificationResTBS 2L, 23L, 42L, 0L, 81L + +#define SN_setct_BCIDistributionTBS "setct-BCIDistributionTBS" +#define NID_setct_BCIDistributionTBS 600 +#define OBJ_setct_BCIDistributionTBS 2L, 23L, 42L, 0L, 82L + +#define SN_setext_genCrypt "setext-genCrypt" +#define LN_setext_genCrypt "generic cryptogram" +#define NID_setext_genCrypt 601 +#define OBJ_setext_genCrypt 2L, 23L, 42L, 1L, 1L + +#define SN_setext_miAuth "setext-miAuth" +#define LN_setext_miAuth "merchant initiated auth" +#define NID_setext_miAuth 602 +#define OBJ_setext_miAuth 2L, 23L, 42L, 1L, 3L + +#define SN_setext_pinSecure "setext-pinSecure" +#define NID_setext_pinSecure 603 +#define OBJ_setext_pinSecure 2L, 23L, 42L, 1L, 4L + +#define SN_setext_pinAny "setext-pinAny" +#define NID_setext_pinAny 604 +#define OBJ_setext_pinAny 2L, 23L, 42L, 1L, 5L + +#define SN_setext_track2 "setext-track2" +#define NID_setext_track2 605 +#define OBJ_setext_track2 2L, 23L, 42L, 1L, 7L + +#define SN_setext_cv "setext-cv" +#define LN_setext_cv "additional verification" +#define NID_setext_cv 606 +#define OBJ_setext_cv 2L, 23L, 42L, 1L, 8L + +#define SN_set_policy_root "set-policy-root" +#define NID_set_policy_root 607 +#define OBJ_set_policy_root 2L, 23L, 42L, 5L, 0L + +#define SN_setCext_hashedRoot "setCext-hashedRoot" +#define NID_setCext_hashedRoot 608 +#define OBJ_setCext_hashedRoot 2L, 23L, 42L, 7L, 0L + +#define SN_setCext_certType "setCext-certType" +#define NID_setCext_certType 609 +#define OBJ_setCext_certType 2L, 23L, 42L, 7L, 1L + +#define SN_setCext_merchData "setCext-merchData" +#define NID_setCext_merchData 610 +#define OBJ_setCext_merchData 2L, 23L, 42L, 7L, 2L + +#define SN_setCext_cCertRequired "setCext-cCertRequired" +#define NID_setCext_cCertRequired 611 +#define OBJ_setCext_cCertRequired 2L, 23L, 42L, 7L, 3L + +#define SN_setCext_tunneling "setCext-tunneling" +#define NID_setCext_tunneling 612 +#define OBJ_setCext_tunneling 2L, 23L, 42L, 7L, 4L + +#define SN_setCext_setExt "setCext-setExt" +#define NID_setCext_setExt 613 +#define OBJ_setCext_setExt 2L, 23L, 42L, 7L, 5L + +#define SN_setCext_setQualf "setCext-setQualf" +#define NID_setCext_setQualf 614 +#define OBJ_setCext_setQualf 2L, 23L, 42L, 7L, 6L + +#define SN_setCext_PGWYcapabilities "setCext-PGWYcapabilities" +#define NID_setCext_PGWYcapabilities 615 +#define OBJ_setCext_PGWYcapabilities 2L, 23L, 42L, 7L, 7L + +#define SN_setCext_TokenIdentifier "setCext-TokenIdentifier" +#define NID_setCext_TokenIdentifier 616 +#define OBJ_setCext_TokenIdentifier 2L, 23L, 42L, 7L, 8L + +#define SN_setCext_Track2Data "setCext-Track2Data" +#define NID_setCext_Track2Data 617 +#define OBJ_setCext_Track2Data 2L, 23L, 42L, 7L, 9L + +#define SN_setCext_TokenType "setCext-TokenType" +#define NID_setCext_TokenType 618 +#define OBJ_setCext_TokenType 2L, 23L, 42L, 7L, 10L + +#define SN_setCext_IssuerCapabilities "setCext-IssuerCapabilities" +#define NID_setCext_IssuerCapabilities 619 +#define OBJ_setCext_IssuerCapabilities 2L, 23L, 42L, 7L, 11L + +#define SN_setAttr_Cert "setAttr-Cert" +#define NID_setAttr_Cert 620 +#define OBJ_setAttr_Cert 2L, 23L, 42L, 3L, 0L + +#define SN_setAttr_PGWYcap "setAttr-PGWYcap" +#define LN_setAttr_PGWYcap "payment gateway capabilities" +#define NID_setAttr_PGWYcap 621 +#define OBJ_setAttr_PGWYcap 2L, 23L, 42L, 3L, 1L + +#define SN_setAttr_TokenType "setAttr-TokenType" +#define NID_setAttr_TokenType 622 +#define OBJ_setAttr_TokenType 2L, 23L, 42L, 3L, 2L + +#define SN_setAttr_IssCap "setAttr-IssCap" +#define LN_setAttr_IssCap "issuer capabilities" +#define NID_setAttr_IssCap 623 +#define OBJ_setAttr_IssCap 2L, 23L, 42L, 3L, 3L + +#define SN_set_rootKeyThumb "set-rootKeyThumb" +#define NID_set_rootKeyThumb 624 +#define OBJ_set_rootKeyThumb 2L, 23L, 42L, 3L, 0L, 0L + +#define SN_set_addPolicy "set-addPolicy" +#define NID_set_addPolicy 625 +#define OBJ_set_addPolicy 2L, 23L, 42L, 3L, 0L, 1L + +#define SN_setAttr_Token_EMV "setAttr-Token-EMV" +#define NID_setAttr_Token_EMV 626 +#define OBJ_setAttr_Token_EMV 2L, 23L, 42L, 3L, 2L, 1L + +#define SN_setAttr_Token_B0Prime "setAttr-Token-B0Prime" +#define NID_setAttr_Token_B0Prime 627 +#define OBJ_setAttr_Token_B0Prime 2L, 23L, 42L, 3L, 2L, 2L + +#define SN_setAttr_IssCap_CVM "setAttr-IssCap-CVM" +#define NID_setAttr_IssCap_CVM 628 +#define OBJ_setAttr_IssCap_CVM 2L, 23L, 42L, 3L, 3L, 3L + +#define SN_setAttr_IssCap_T2 "setAttr-IssCap-T2" +#define NID_setAttr_IssCap_T2 629 +#define OBJ_setAttr_IssCap_T2 2L, 23L, 42L, 3L, 3L, 4L + +#define SN_setAttr_IssCap_Sig "setAttr-IssCap-Sig" +#define NID_setAttr_IssCap_Sig 630 +#define OBJ_setAttr_IssCap_Sig 2L, 23L, 42L, 3L, 3L, 5L + +#define SN_setAttr_GenCryptgrm "setAttr-GenCryptgrm" +#define LN_setAttr_GenCryptgrm "generate cryptogram" +#define NID_setAttr_GenCryptgrm 631 +#define OBJ_setAttr_GenCryptgrm 2L, 23L, 42L, 3L, 3L, 3L, 1L + +#define SN_setAttr_T2Enc "setAttr-T2Enc" +#define LN_setAttr_T2Enc "encrypted track 2" +#define NID_setAttr_T2Enc 632 +#define OBJ_setAttr_T2Enc 2L, 23L, 42L, 3L, 3L, 4L, 1L + +#define SN_setAttr_T2cleartxt "setAttr-T2cleartxt" +#define LN_setAttr_T2cleartxt "cleartext track 2" +#define NID_setAttr_T2cleartxt 633 +#define OBJ_setAttr_T2cleartxt 2L, 23L, 42L, 3L, 3L, 4L, 2L + +#define SN_setAttr_TokICCsig "setAttr-TokICCsig" +#define LN_setAttr_TokICCsig "ICC or token signature" +#define NID_setAttr_TokICCsig 634 +#define OBJ_setAttr_TokICCsig 2L, 23L, 42L, 3L, 3L, 5L, 1L + +#define SN_setAttr_SecDevSig "setAttr-SecDevSig" +#define LN_setAttr_SecDevSig "secure device signature" +#define NID_setAttr_SecDevSig 635 +#define OBJ_setAttr_SecDevSig 2L, 23L, 42L, 3L, 3L, 5L, 2L + +#define SN_set_brand_IATA_ATA "set-brand-IATA-ATA" +#define NID_set_brand_IATA_ATA 636 +#define OBJ_set_brand_IATA_ATA 2L, 23L, 42L, 8L, 1L + +#define SN_set_brand_Diners "set-brand-Diners" +#define NID_set_brand_Diners 637 +#define OBJ_set_brand_Diners 2L, 23L, 42L, 8L, 30L + +#define SN_set_brand_AmericanExpress "set-brand-AmericanExpress" +#define NID_set_brand_AmericanExpress 638 +#define OBJ_set_brand_AmericanExpress 2L, 23L, 42L, 8L, 34L + +#define SN_set_brand_JCB "set-brand-JCB" +#define NID_set_brand_JCB 639 +#define OBJ_set_brand_JCB 2L, 23L, 42L, 8L, 35L + +#define SN_set_brand_Visa "set-brand-Visa" +#define NID_set_brand_Visa 640 +#define OBJ_set_brand_Visa 2L, 23L, 42L, 8L, 4L + +#define SN_set_brand_MasterCard "set-brand-MasterCard" +#define NID_set_brand_MasterCard 641 +#define OBJ_set_brand_MasterCard 2L, 23L, 42L, 8L, 5L + +#define SN_set_brand_Novus "set-brand-Novus" +#define NID_set_brand_Novus 642 +#define OBJ_set_brand_Novus 2L, 23L, 42L, 8L, 6011L + +#define SN_des_cdmf "DES-CDMF" +#define LN_des_cdmf "des-cdmf" +#define NID_des_cdmf 643 +#define OBJ_des_cdmf 1L, 2L, 840L, 113549L, 3L, 10L + +#define SN_rsaOAEPEncryptionSET "rsaOAEPEncryptionSET" +#define NID_rsaOAEPEncryptionSET 644 +#define OBJ_rsaOAEPEncryptionSET 1L, 2L, 840L, 113549L, 1L, 1L, 6L + +#define SN_itu_t "ITU-T" +#define LN_itu_t "itu-t" +#define NID_itu_t 645 +#define OBJ_itu_t 0L + +#define SN_joint_iso_itu_t "JOINT-ISO-ITU-T" +#define LN_joint_iso_itu_t "joint-iso-itu-t" +#define NID_joint_iso_itu_t 646 +#define OBJ_joint_iso_itu_t 2L + +#define SN_international_organizations "international-organizations" +#define LN_international_organizations "International Organizations" +#define NID_international_organizations 647 +#define OBJ_international_organizations 2L, 23L + +#define SN_ms_smartcard_login "msSmartcardLogin" +#define LN_ms_smartcard_login "Microsoft Smartcardlogin" +#define NID_ms_smartcard_login 648 +#define OBJ_ms_smartcard_login 1L, 3L, 6L, 1L, 4L, 1L, 311L, 20L, 2L, 2L + +#define SN_ms_upn "msUPN" +#define LN_ms_upn "Microsoft Universal Principal Name" +#define NID_ms_upn 649 +#define OBJ_ms_upn 1L, 3L, 6L, 1L, 4L, 1L, 311L, 20L, 2L, 3L + +#define SN_aes_128_cfb1 "AES-128-CFB1" +#define LN_aes_128_cfb1 "aes-128-cfb1" +#define NID_aes_128_cfb1 650 + +#define SN_aes_192_cfb1 "AES-192-CFB1" +#define LN_aes_192_cfb1 "aes-192-cfb1" +#define NID_aes_192_cfb1 651 + +#define SN_aes_256_cfb1 "AES-256-CFB1" +#define LN_aes_256_cfb1 "aes-256-cfb1" +#define NID_aes_256_cfb1 652 + +#define SN_aes_128_cfb8 "AES-128-CFB8" +#define LN_aes_128_cfb8 "aes-128-cfb8" +#define NID_aes_128_cfb8 653 + +#define SN_aes_192_cfb8 "AES-192-CFB8" +#define LN_aes_192_cfb8 "aes-192-cfb8" +#define NID_aes_192_cfb8 654 + +#define SN_aes_256_cfb8 "AES-256-CFB8" +#define LN_aes_256_cfb8 "aes-256-cfb8" +#define NID_aes_256_cfb8 655 + +#define SN_des_cfb1 "DES-CFB1" +#define LN_des_cfb1 "des-cfb1" +#define NID_des_cfb1 656 + +#define SN_des_cfb8 "DES-CFB8" +#define LN_des_cfb8 "des-cfb8" +#define NID_des_cfb8 657 + +#define SN_des_ede3_cfb1 "DES-EDE3-CFB1" +#define LN_des_ede3_cfb1 "des-ede3-cfb1" +#define NID_des_ede3_cfb1 658 + +#define SN_des_ede3_cfb8 "DES-EDE3-CFB8" +#define LN_des_ede3_cfb8 "des-ede3-cfb8" +#define NID_des_ede3_cfb8 659 + +#define SN_streetAddress "street" +#define LN_streetAddress "streetAddress" +#define NID_streetAddress 660 +#define OBJ_streetAddress 2L, 5L, 4L, 9L + +#define LN_postalCode "postalCode" +#define NID_postalCode 661 +#define OBJ_postalCode 2L, 5L, 4L, 17L + +#define SN_id_ppl "id-ppl" +#define NID_id_ppl 662 +#define OBJ_id_ppl 1L, 3L, 6L, 1L, 5L, 5L, 7L, 21L + +#define SN_proxyCertInfo "proxyCertInfo" +#define LN_proxyCertInfo "Proxy Certificate Information" +#define NID_proxyCertInfo 663 +#define OBJ_proxyCertInfo 1L, 3L, 6L, 1L, 5L, 5L, 7L, 1L, 14L + +#define SN_id_ppl_anyLanguage "id-ppl-anyLanguage" +#define LN_id_ppl_anyLanguage "Any language" +#define NID_id_ppl_anyLanguage 664 +#define OBJ_id_ppl_anyLanguage 1L, 3L, 6L, 1L, 5L, 5L, 7L, 21L, 0L + +#define SN_id_ppl_inheritAll "id-ppl-inheritAll" +#define LN_id_ppl_inheritAll "Inherit all" +#define NID_id_ppl_inheritAll 665 +#define OBJ_id_ppl_inheritAll 1L, 3L, 6L, 1L, 5L, 5L, 7L, 21L, 1L + +#define SN_name_constraints "nameConstraints" +#define LN_name_constraints "X509v3 Name Constraints" +#define NID_name_constraints 666 +#define OBJ_name_constraints 2L, 5L, 29L, 30L + +#define SN_Independent "id-ppl-independent" +#define LN_Independent "Independent" +#define NID_Independent 667 +#define OBJ_Independent 1L, 3L, 6L, 1L, 5L, 5L, 7L, 21L, 2L + +#define SN_sha256WithRSAEncryption "RSA-SHA256" +#define LN_sha256WithRSAEncryption "sha256WithRSAEncryption" +#define NID_sha256WithRSAEncryption 668 +#define OBJ_sha256WithRSAEncryption 1L, 2L, 840L, 113549L, 1L, 1L, 11L + +#define SN_sha384WithRSAEncryption "RSA-SHA384" +#define LN_sha384WithRSAEncryption "sha384WithRSAEncryption" +#define NID_sha384WithRSAEncryption 669 +#define OBJ_sha384WithRSAEncryption 1L, 2L, 840L, 113549L, 1L, 1L, 12L + +#define SN_sha512WithRSAEncryption "RSA-SHA512" +#define LN_sha512WithRSAEncryption "sha512WithRSAEncryption" +#define NID_sha512WithRSAEncryption 670 +#define OBJ_sha512WithRSAEncryption 1L, 2L, 840L, 113549L, 1L, 1L, 13L + +#define SN_sha224WithRSAEncryption "RSA-SHA224" +#define LN_sha224WithRSAEncryption "sha224WithRSAEncryption" +#define NID_sha224WithRSAEncryption 671 +#define OBJ_sha224WithRSAEncryption 1L, 2L, 840L, 113549L, 1L, 1L, 14L + +#define SN_sha256 "SHA256" +#define LN_sha256 "sha256" +#define NID_sha256 672 +#define OBJ_sha256 2L, 16L, 840L, 1L, 101L, 3L, 4L, 2L, 1L + +#define SN_sha384 "SHA384" +#define LN_sha384 "sha384" +#define NID_sha384 673 +#define OBJ_sha384 2L, 16L, 840L, 1L, 101L, 3L, 4L, 2L, 2L + +#define SN_sha512 "SHA512" +#define LN_sha512 "sha512" +#define NID_sha512 674 +#define OBJ_sha512 2L, 16L, 840L, 1L, 101L, 3L, 4L, 2L, 3L + +#define SN_sha224 "SHA224" +#define LN_sha224 "sha224" +#define NID_sha224 675 +#define OBJ_sha224 2L, 16L, 840L, 1L, 101L, 3L, 4L, 2L, 4L + +#define SN_identified_organization "identified-organization" +#define NID_identified_organization 676 +#define OBJ_identified_organization 1L, 3L + +#define SN_certicom_arc "certicom-arc" +#define NID_certicom_arc 677 +#define OBJ_certicom_arc 1L, 3L, 132L + +#define SN_wap "wap" +#define NID_wap 678 +#define OBJ_wap 2L, 23L, 43L + +#define SN_wap_wsg "wap-wsg" +#define NID_wap_wsg 679 +#define OBJ_wap_wsg 2L, 23L, 43L, 1L + +#define SN_X9_62_id_characteristic_two_basis "id-characteristic-two-basis" +#define NID_X9_62_id_characteristic_two_basis 680 +#define OBJ_X9_62_id_characteristic_two_basis 1L, 2L, 840L, 10045L, 1L, 2L, 3L + +#define SN_X9_62_onBasis "onBasis" +#define NID_X9_62_onBasis 681 +#define OBJ_X9_62_onBasis 1L, 2L, 840L, 10045L, 1L, 2L, 3L, 1L + +#define SN_X9_62_tpBasis "tpBasis" +#define NID_X9_62_tpBasis 682 +#define OBJ_X9_62_tpBasis 1L, 2L, 840L, 10045L, 1L, 2L, 3L, 2L + +#define SN_X9_62_ppBasis "ppBasis" +#define NID_X9_62_ppBasis 683 +#define OBJ_X9_62_ppBasis 1L, 2L, 840L, 10045L, 1L, 2L, 3L, 3L + +#define SN_X9_62_c2pnb163v1 "c2pnb163v1" +#define NID_X9_62_c2pnb163v1 684 +#define OBJ_X9_62_c2pnb163v1 1L, 2L, 840L, 10045L, 3L, 0L, 1L + +#define SN_X9_62_c2pnb163v2 "c2pnb163v2" +#define NID_X9_62_c2pnb163v2 685 +#define OBJ_X9_62_c2pnb163v2 1L, 2L, 840L, 10045L, 3L, 0L, 2L + +#define SN_X9_62_c2pnb163v3 "c2pnb163v3" +#define NID_X9_62_c2pnb163v3 686 +#define OBJ_X9_62_c2pnb163v3 1L, 2L, 840L, 10045L, 3L, 0L, 3L + +#define SN_X9_62_c2pnb176v1 "c2pnb176v1" +#define NID_X9_62_c2pnb176v1 687 +#define OBJ_X9_62_c2pnb176v1 1L, 2L, 840L, 10045L, 3L, 0L, 4L + +#define SN_X9_62_c2tnb191v1 "c2tnb191v1" +#define NID_X9_62_c2tnb191v1 688 +#define OBJ_X9_62_c2tnb191v1 1L, 2L, 840L, 10045L, 3L, 0L, 5L + +#define SN_X9_62_c2tnb191v2 "c2tnb191v2" +#define NID_X9_62_c2tnb191v2 689 +#define OBJ_X9_62_c2tnb191v2 1L, 2L, 840L, 10045L, 3L, 0L, 6L + +#define SN_X9_62_c2tnb191v3 "c2tnb191v3" +#define NID_X9_62_c2tnb191v3 690 +#define OBJ_X9_62_c2tnb191v3 1L, 2L, 840L, 10045L, 3L, 0L, 7L + +#define SN_X9_62_c2onb191v4 "c2onb191v4" +#define NID_X9_62_c2onb191v4 691 +#define OBJ_X9_62_c2onb191v4 1L, 2L, 840L, 10045L, 3L, 0L, 8L + +#define SN_X9_62_c2onb191v5 "c2onb191v5" +#define NID_X9_62_c2onb191v5 692 +#define OBJ_X9_62_c2onb191v5 1L, 2L, 840L, 10045L, 3L, 0L, 9L + +#define SN_X9_62_c2pnb208w1 "c2pnb208w1" +#define NID_X9_62_c2pnb208w1 693 +#define OBJ_X9_62_c2pnb208w1 1L, 2L, 840L, 10045L, 3L, 0L, 10L + +#define SN_X9_62_c2tnb239v1 "c2tnb239v1" +#define NID_X9_62_c2tnb239v1 694 +#define OBJ_X9_62_c2tnb239v1 1L, 2L, 840L, 10045L, 3L, 0L, 11L + +#define SN_X9_62_c2tnb239v2 "c2tnb239v2" +#define NID_X9_62_c2tnb239v2 695 +#define OBJ_X9_62_c2tnb239v2 1L, 2L, 840L, 10045L, 3L, 0L, 12L + +#define SN_X9_62_c2tnb239v3 "c2tnb239v3" +#define NID_X9_62_c2tnb239v3 696 +#define OBJ_X9_62_c2tnb239v3 1L, 2L, 840L, 10045L, 3L, 0L, 13L + +#define SN_X9_62_c2onb239v4 "c2onb239v4" +#define NID_X9_62_c2onb239v4 697 +#define OBJ_X9_62_c2onb239v4 1L, 2L, 840L, 10045L, 3L, 0L, 14L + +#define SN_X9_62_c2onb239v5 "c2onb239v5" +#define NID_X9_62_c2onb239v5 698 +#define OBJ_X9_62_c2onb239v5 1L, 2L, 840L, 10045L, 3L, 0L, 15L + +#define SN_X9_62_c2pnb272w1 "c2pnb272w1" +#define NID_X9_62_c2pnb272w1 699 +#define OBJ_X9_62_c2pnb272w1 1L, 2L, 840L, 10045L, 3L, 0L, 16L + +#define SN_X9_62_c2pnb304w1 "c2pnb304w1" +#define NID_X9_62_c2pnb304w1 700 +#define OBJ_X9_62_c2pnb304w1 1L, 2L, 840L, 10045L, 3L, 0L, 17L + +#define SN_X9_62_c2tnb359v1 "c2tnb359v1" +#define NID_X9_62_c2tnb359v1 701 +#define OBJ_X9_62_c2tnb359v1 1L, 2L, 840L, 10045L, 3L, 0L, 18L + +#define SN_X9_62_c2pnb368w1 "c2pnb368w1" +#define NID_X9_62_c2pnb368w1 702 +#define OBJ_X9_62_c2pnb368w1 1L, 2L, 840L, 10045L, 3L, 0L, 19L + +#define SN_X9_62_c2tnb431r1 "c2tnb431r1" +#define NID_X9_62_c2tnb431r1 703 +#define OBJ_X9_62_c2tnb431r1 1L, 2L, 840L, 10045L, 3L, 0L, 20L + +#define SN_secp112r1 "secp112r1" +#define NID_secp112r1 704 +#define OBJ_secp112r1 1L, 3L, 132L, 0L, 6L + +#define SN_secp112r2 "secp112r2" +#define NID_secp112r2 705 +#define OBJ_secp112r2 1L, 3L, 132L, 0L, 7L + +#define SN_secp128r1 "secp128r1" +#define NID_secp128r1 706 +#define OBJ_secp128r1 1L, 3L, 132L, 0L, 28L + +#define SN_secp128r2 "secp128r2" +#define NID_secp128r2 707 +#define OBJ_secp128r2 1L, 3L, 132L, 0L, 29L + +#define SN_secp160k1 "secp160k1" +#define NID_secp160k1 708 +#define OBJ_secp160k1 1L, 3L, 132L, 0L, 9L + +#define SN_secp160r1 "secp160r1" +#define NID_secp160r1 709 +#define OBJ_secp160r1 1L, 3L, 132L, 0L, 8L + +#define SN_secp160r2 "secp160r2" +#define NID_secp160r2 710 +#define OBJ_secp160r2 1L, 3L, 132L, 0L, 30L + +#define SN_secp192k1 "secp192k1" +#define NID_secp192k1 711 +#define OBJ_secp192k1 1L, 3L, 132L, 0L, 31L + +#define SN_secp224k1 "secp224k1" +#define NID_secp224k1 712 +#define OBJ_secp224k1 1L, 3L, 132L, 0L, 32L + +#define SN_secp224r1 "secp224r1" +#define NID_secp224r1 713 +#define OBJ_secp224r1 1L, 3L, 132L, 0L, 33L + +#define SN_secp256k1 "secp256k1" +#define NID_secp256k1 714 +#define OBJ_secp256k1 1L, 3L, 132L, 0L, 10L + +#define SN_secp384r1 "secp384r1" +#define NID_secp384r1 715 +#define OBJ_secp384r1 1L, 3L, 132L, 0L, 34L + +#define SN_secp521r1 "secp521r1" +#define NID_secp521r1 716 +#define OBJ_secp521r1 1L, 3L, 132L, 0L, 35L + +#define SN_sect113r1 "sect113r1" +#define NID_sect113r1 717 +#define OBJ_sect113r1 1L, 3L, 132L, 0L, 4L + +#define SN_sect113r2 "sect113r2" +#define NID_sect113r2 718 +#define OBJ_sect113r2 1L, 3L, 132L, 0L, 5L + +#define SN_sect131r1 "sect131r1" +#define NID_sect131r1 719 +#define OBJ_sect131r1 1L, 3L, 132L, 0L, 22L + +#define SN_sect131r2 "sect131r2" +#define NID_sect131r2 720 +#define OBJ_sect131r2 1L, 3L, 132L, 0L, 23L + +#define SN_sect163k1 "sect163k1" +#define NID_sect163k1 721 +#define OBJ_sect163k1 1L, 3L, 132L, 0L, 1L + +#define SN_sect163r1 "sect163r1" +#define NID_sect163r1 722 +#define OBJ_sect163r1 1L, 3L, 132L, 0L, 2L + +#define SN_sect163r2 "sect163r2" +#define NID_sect163r2 723 +#define OBJ_sect163r2 1L, 3L, 132L, 0L, 15L + +#define SN_sect193r1 "sect193r1" +#define NID_sect193r1 724 +#define OBJ_sect193r1 1L, 3L, 132L, 0L, 24L + +#define SN_sect193r2 "sect193r2" +#define NID_sect193r2 725 +#define OBJ_sect193r2 1L, 3L, 132L, 0L, 25L + +#define SN_sect233k1 "sect233k1" +#define NID_sect233k1 726 +#define OBJ_sect233k1 1L, 3L, 132L, 0L, 26L + +#define SN_sect233r1 "sect233r1" +#define NID_sect233r1 727 +#define OBJ_sect233r1 1L, 3L, 132L, 0L, 27L + +#define SN_sect239k1 "sect239k1" +#define NID_sect239k1 728 +#define OBJ_sect239k1 1L, 3L, 132L, 0L, 3L + +#define SN_sect283k1 "sect283k1" +#define NID_sect283k1 729 +#define OBJ_sect283k1 1L, 3L, 132L, 0L, 16L + +#define SN_sect283r1 "sect283r1" +#define NID_sect283r1 730 +#define OBJ_sect283r1 1L, 3L, 132L, 0L, 17L + +#define SN_sect409k1 "sect409k1" +#define NID_sect409k1 731 +#define OBJ_sect409k1 1L, 3L, 132L, 0L, 36L + +#define SN_sect409r1 "sect409r1" +#define NID_sect409r1 732 +#define OBJ_sect409r1 1L, 3L, 132L, 0L, 37L + +#define SN_sect571k1 "sect571k1" +#define NID_sect571k1 733 +#define OBJ_sect571k1 1L, 3L, 132L, 0L, 38L + +#define SN_sect571r1 "sect571r1" +#define NID_sect571r1 734 +#define OBJ_sect571r1 1L, 3L, 132L, 0L, 39L + +#define SN_wap_wsg_idm_ecid_wtls1 "wap-wsg-idm-ecid-wtls1" +#define NID_wap_wsg_idm_ecid_wtls1 735 +#define OBJ_wap_wsg_idm_ecid_wtls1 2L, 23L, 43L, 1L, 4L, 1L + +#define SN_wap_wsg_idm_ecid_wtls3 "wap-wsg-idm-ecid-wtls3" +#define NID_wap_wsg_idm_ecid_wtls3 736 +#define OBJ_wap_wsg_idm_ecid_wtls3 2L, 23L, 43L, 1L, 4L, 3L + +#define SN_wap_wsg_idm_ecid_wtls4 "wap-wsg-idm-ecid-wtls4" +#define NID_wap_wsg_idm_ecid_wtls4 737 +#define OBJ_wap_wsg_idm_ecid_wtls4 2L, 23L, 43L, 1L, 4L, 4L + +#define SN_wap_wsg_idm_ecid_wtls5 "wap-wsg-idm-ecid-wtls5" +#define NID_wap_wsg_idm_ecid_wtls5 738 +#define OBJ_wap_wsg_idm_ecid_wtls5 2L, 23L, 43L, 1L, 4L, 5L + +#define SN_wap_wsg_idm_ecid_wtls6 "wap-wsg-idm-ecid-wtls6" +#define NID_wap_wsg_idm_ecid_wtls6 739 +#define OBJ_wap_wsg_idm_ecid_wtls6 2L, 23L, 43L, 1L, 4L, 6L + +#define SN_wap_wsg_idm_ecid_wtls7 "wap-wsg-idm-ecid-wtls7" +#define NID_wap_wsg_idm_ecid_wtls7 740 +#define OBJ_wap_wsg_idm_ecid_wtls7 2L, 23L, 43L, 1L, 4L, 7L + +#define SN_wap_wsg_idm_ecid_wtls8 "wap-wsg-idm-ecid-wtls8" +#define NID_wap_wsg_idm_ecid_wtls8 741 +#define OBJ_wap_wsg_idm_ecid_wtls8 2L, 23L, 43L, 1L, 4L, 8L + +#define SN_wap_wsg_idm_ecid_wtls9 "wap-wsg-idm-ecid-wtls9" +#define NID_wap_wsg_idm_ecid_wtls9 742 +#define OBJ_wap_wsg_idm_ecid_wtls9 2L, 23L, 43L, 1L, 4L, 9L + +#define SN_wap_wsg_idm_ecid_wtls10 "wap-wsg-idm-ecid-wtls10" +#define NID_wap_wsg_idm_ecid_wtls10 743 +#define OBJ_wap_wsg_idm_ecid_wtls10 2L, 23L, 43L, 1L, 4L, 10L + +#define SN_wap_wsg_idm_ecid_wtls11 "wap-wsg-idm-ecid-wtls11" +#define NID_wap_wsg_idm_ecid_wtls11 744 +#define OBJ_wap_wsg_idm_ecid_wtls11 2L, 23L, 43L, 1L, 4L, 11L + +#define SN_wap_wsg_idm_ecid_wtls12 "wap-wsg-idm-ecid-wtls12" +#define NID_wap_wsg_idm_ecid_wtls12 745 +#define OBJ_wap_wsg_idm_ecid_wtls12 2L, 23L, 43L, 1L, 4L, 12L + +#define SN_any_policy "anyPolicy" +#define LN_any_policy "X509v3 Any Policy" +#define NID_any_policy 746 +#define OBJ_any_policy 2L, 5L, 29L, 32L, 0L + +#define SN_policy_mappings "policyMappings" +#define LN_policy_mappings "X509v3 Policy Mappings" +#define NID_policy_mappings 747 +#define OBJ_policy_mappings 2L, 5L, 29L, 33L + +#define SN_inhibit_any_policy "inhibitAnyPolicy" +#define LN_inhibit_any_policy "X509v3 Inhibit Any Policy" +#define NID_inhibit_any_policy 748 +#define OBJ_inhibit_any_policy 2L, 5L, 29L, 54L + +#define SN_ipsec3 "Oakley-EC2N-3" +#define LN_ipsec3 "ipsec3" +#define NID_ipsec3 749 + +#define SN_ipsec4 "Oakley-EC2N-4" +#define LN_ipsec4 "ipsec4" +#define NID_ipsec4 750 + +#define SN_camellia_128_cbc "CAMELLIA-128-CBC" +#define LN_camellia_128_cbc "camellia-128-cbc" +#define NID_camellia_128_cbc 751 +#define OBJ_camellia_128_cbc 1L, 2L, 392L, 200011L, 61L, 1L, 1L, 1L, 2L + +#define SN_camellia_192_cbc "CAMELLIA-192-CBC" +#define LN_camellia_192_cbc "camellia-192-cbc" +#define NID_camellia_192_cbc 752 +#define OBJ_camellia_192_cbc 1L, 2L, 392L, 200011L, 61L, 1L, 1L, 1L, 3L + +#define SN_camellia_256_cbc "CAMELLIA-256-CBC" +#define LN_camellia_256_cbc "camellia-256-cbc" +#define NID_camellia_256_cbc 753 +#define OBJ_camellia_256_cbc 1L, 2L, 392L, 200011L, 61L, 1L, 1L, 1L, 4L + +#define SN_camellia_128_ecb "CAMELLIA-128-ECB" +#define LN_camellia_128_ecb "camellia-128-ecb" +#define NID_camellia_128_ecb 754 +#define OBJ_camellia_128_ecb 0L, 3L, 4401L, 5L, 3L, 1L, 9L, 1L + +#define SN_camellia_192_ecb "CAMELLIA-192-ECB" +#define LN_camellia_192_ecb "camellia-192-ecb" +#define NID_camellia_192_ecb 755 +#define OBJ_camellia_192_ecb 0L, 3L, 4401L, 5L, 3L, 1L, 9L, 21L + +#define SN_camellia_256_ecb "CAMELLIA-256-ECB" +#define LN_camellia_256_ecb "camellia-256-ecb" +#define NID_camellia_256_ecb 756 +#define OBJ_camellia_256_ecb 0L, 3L, 4401L, 5L, 3L, 1L, 9L, 41L + +#define SN_camellia_128_cfb128 "CAMELLIA-128-CFB" +#define LN_camellia_128_cfb128 "camellia-128-cfb" +#define NID_camellia_128_cfb128 757 +#define OBJ_camellia_128_cfb128 0L, 3L, 4401L, 5L, 3L, 1L, 9L, 4L + +#define SN_camellia_192_cfb128 "CAMELLIA-192-CFB" +#define LN_camellia_192_cfb128 "camellia-192-cfb" +#define NID_camellia_192_cfb128 758 +#define OBJ_camellia_192_cfb128 0L, 3L, 4401L, 5L, 3L, 1L, 9L, 24L + +#define SN_camellia_256_cfb128 "CAMELLIA-256-CFB" +#define LN_camellia_256_cfb128 "camellia-256-cfb" +#define NID_camellia_256_cfb128 759 +#define OBJ_camellia_256_cfb128 0L, 3L, 4401L, 5L, 3L, 1L, 9L, 44L + +#define SN_camellia_128_cfb1 "CAMELLIA-128-CFB1" +#define LN_camellia_128_cfb1 "camellia-128-cfb1" +#define NID_camellia_128_cfb1 760 + +#define SN_camellia_192_cfb1 "CAMELLIA-192-CFB1" +#define LN_camellia_192_cfb1 "camellia-192-cfb1" +#define NID_camellia_192_cfb1 761 + +#define SN_camellia_256_cfb1 "CAMELLIA-256-CFB1" +#define LN_camellia_256_cfb1 "camellia-256-cfb1" +#define NID_camellia_256_cfb1 762 + +#define SN_camellia_128_cfb8 "CAMELLIA-128-CFB8" +#define LN_camellia_128_cfb8 "camellia-128-cfb8" +#define NID_camellia_128_cfb8 763 + +#define SN_camellia_192_cfb8 "CAMELLIA-192-CFB8" +#define LN_camellia_192_cfb8 "camellia-192-cfb8" +#define NID_camellia_192_cfb8 764 + +#define SN_camellia_256_cfb8 "CAMELLIA-256-CFB8" +#define LN_camellia_256_cfb8 "camellia-256-cfb8" +#define NID_camellia_256_cfb8 765 + +#define SN_camellia_128_ofb128 "CAMELLIA-128-OFB" +#define LN_camellia_128_ofb128 "camellia-128-ofb" +#define NID_camellia_128_ofb128 766 +#define OBJ_camellia_128_ofb128 0L, 3L, 4401L, 5L, 3L, 1L, 9L, 3L + +#define SN_camellia_192_ofb128 "CAMELLIA-192-OFB" +#define LN_camellia_192_ofb128 "camellia-192-ofb" +#define NID_camellia_192_ofb128 767 +#define OBJ_camellia_192_ofb128 0L, 3L, 4401L, 5L, 3L, 1L, 9L, 23L + +#define SN_camellia_256_ofb128 "CAMELLIA-256-OFB" +#define LN_camellia_256_ofb128 "camellia-256-ofb" +#define NID_camellia_256_ofb128 768 +#define OBJ_camellia_256_ofb128 0L, 3L, 4401L, 5L, 3L, 1L, 9L, 43L + +#define SN_subject_directory_attributes "subjectDirectoryAttributes" +#define LN_subject_directory_attributes "X509v3 Subject Directory Attributes" +#define NID_subject_directory_attributes 769 +#define OBJ_subject_directory_attributes 2L, 5L, 29L, 9L + +#define SN_issuing_distribution_point "issuingDistributionPoint" +#define LN_issuing_distribution_point "X509v3 Issuing Distribution Point" +#define NID_issuing_distribution_point 770 +#define OBJ_issuing_distribution_point 2L, 5L, 29L, 28L + +#define SN_certificate_issuer "certificateIssuer" +#define LN_certificate_issuer "X509v3 Certificate Issuer" +#define NID_certificate_issuer 771 +#define OBJ_certificate_issuer 2L, 5L, 29L, 29L + +#define SN_kisa "KISA" +#define LN_kisa "kisa" +#define NID_kisa 773 +#define OBJ_kisa 1L, 2L, 410L, 200004L + +#define SN_seed_ecb "SEED-ECB" +#define LN_seed_ecb "seed-ecb" +#define NID_seed_ecb 776 +#define OBJ_seed_ecb 1L, 2L, 410L, 200004L, 1L, 3L + +#define SN_seed_cbc "SEED-CBC" +#define LN_seed_cbc "seed-cbc" +#define NID_seed_cbc 777 +#define OBJ_seed_cbc 1L, 2L, 410L, 200004L, 1L, 4L + +#define SN_seed_ofb128 "SEED-OFB" +#define LN_seed_ofb128 "seed-ofb" +#define NID_seed_ofb128 778 +#define OBJ_seed_ofb128 1L, 2L, 410L, 200004L, 1L, 6L + +#define SN_seed_cfb128 "SEED-CFB" +#define LN_seed_cfb128 "seed-cfb" +#define NID_seed_cfb128 779 +#define OBJ_seed_cfb128 1L, 2L, 410L, 200004L, 1L, 5L + +#define SN_hmac_md5 "HMAC-MD5" +#define LN_hmac_md5 "hmac-md5" +#define NID_hmac_md5 780 +#define OBJ_hmac_md5 1L, 3L, 6L, 1L, 5L, 5L, 8L, 1L, 1L + +#define SN_hmac_sha1 "HMAC-SHA1" +#define LN_hmac_sha1 "hmac-sha1" +#define NID_hmac_sha1 781 +#define OBJ_hmac_sha1 1L, 3L, 6L, 1L, 5L, 5L, 8L, 1L, 2L + +#define SN_id_PasswordBasedMAC "id-PasswordBasedMAC" +#define LN_id_PasswordBasedMAC "password based MAC" +#define NID_id_PasswordBasedMAC 782 +#define OBJ_id_PasswordBasedMAC 1L, 2L, 840L, 113533L, 7L, 66L, 13L + +#define SN_id_DHBasedMac "id-DHBasedMac" +#define LN_id_DHBasedMac "Diffie-Hellman based MAC" +#define NID_id_DHBasedMac 783 +#define OBJ_id_DHBasedMac 1L, 2L, 840L, 113533L, 7L, 66L, 30L + +#define SN_id_it_suppLangTags "id-it-suppLangTags" +#define NID_id_it_suppLangTags 784 +#define OBJ_id_it_suppLangTags 1L, 3L, 6L, 1L, 5L, 5L, 7L, 4L, 16L + +#define SN_caRepository "caRepository" +#define LN_caRepository "CA Repository" +#define NID_caRepository 785 +#define OBJ_caRepository 1L, 3L, 6L, 1L, 5L, 5L, 7L, 48L, 5L + +#define SN_id_smime_ct_compressedData "id-smime-ct-compressedData" +#define NID_id_smime_ct_compressedData 786 +#define OBJ_id_smime_ct_compressedData \ + 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 1L, 9L + +#define SN_id_ct_asciiTextWithCRLF "id-ct-asciiTextWithCRLF" +#define NID_id_ct_asciiTextWithCRLF 787 +#define OBJ_id_ct_asciiTextWithCRLF 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 1L, 27L + +#define SN_id_aes128_wrap "id-aes128-wrap" +#define NID_id_aes128_wrap 788 +#define OBJ_id_aes128_wrap 2L, 16L, 840L, 1L, 101L, 3L, 4L, 1L, 5L + +#define SN_id_aes192_wrap "id-aes192-wrap" +#define NID_id_aes192_wrap 789 +#define OBJ_id_aes192_wrap 2L, 16L, 840L, 1L, 101L, 3L, 4L, 1L, 25L + +#define SN_id_aes256_wrap "id-aes256-wrap" +#define NID_id_aes256_wrap 790 +#define OBJ_id_aes256_wrap 2L, 16L, 840L, 1L, 101L, 3L, 4L, 1L, 45L + +#define SN_ecdsa_with_Recommended "ecdsa-with-Recommended" +#define NID_ecdsa_with_Recommended 791 +#define OBJ_ecdsa_with_Recommended 1L, 2L, 840L, 10045L, 4L, 2L + +#define SN_ecdsa_with_Specified "ecdsa-with-Specified" +#define NID_ecdsa_with_Specified 792 +#define OBJ_ecdsa_with_Specified 1L, 2L, 840L, 10045L, 4L, 3L + +#define SN_ecdsa_with_SHA224 "ecdsa-with-SHA224" +#define NID_ecdsa_with_SHA224 793 +#define OBJ_ecdsa_with_SHA224 1L, 2L, 840L, 10045L, 4L, 3L, 1L + +#define SN_ecdsa_with_SHA256 "ecdsa-with-SHA256" +#define NID_ecdsa_with_SHA256 794 +#define OBJ_ecdsa_with_SHA256 1L, 2L, 840L, 10045L, 4L, 3L, 2L + +#define SN_ecdsa_with_SHA384 "ecdsa-with-SHA384" +#define NID_ecdsa_with_SHA384 795 +#define OBJ_ecdsa_with_SHA384 1L, 2L, 840L, 10045L, 4L, 3L, 3L + +#define SN_ecdsa_with_SHA512 "ecdsa-with-SHA512" +#define NID_ecdsa_with_SHA512 796 +#define OBJ_ecdsa_with_SHA512 1L, 2L, 840L, 10045L, 4L, 3L, 4L + +#define LN_hmacWithMD5 "hmacWithMD5" +#define NID_hmacWithMD5 797 +#define OBJ_hmacWithMD5 1L, 2L, 840L, 113549L, 2L, 6L + +#define LN_hmacWithSHA224 "hmacWithSHA224" +#define NID_hmacWithSHA224 798 +#define OBJ_hmacWithSHA224 1L, 2L, 840L, 113549L, 2L, 8L + +#define LN_hmacWithSHA256 "hmacWithSHA256" +#define NID_hmacWithSHA256 799 +#define OBJ_hmacWithSHA256 1L, 2L, 840L, 113549L, 2L, 9L + +#define LN_hmacWithSHA384 "hmacWithSHA384" +#define NID_hmacWithSHA384 800 +#define OBJ_hmacWithSHA384 1L, 2L, 840L, 113549L, 2L, 10L + +#define LN_hmacWithSHA512 "hmacWithSHA512" +#define NID_hmacWithSHA512 801 +#define OBJ_hmacWithSHA512 1L, 2L, 840L, 113549L, 2L, 11L + +#define SN_dsa_with_SHA224 "dsa_with_SHA224" +#define NID_dsa_with_SHA224 802 +#define OBJ_dsa_with_SHA224 2L, 16L, 840L, 1L, 101L, 3L, 4L, 3L, 1L + +#define SN_dsa_with_SHA256 "dsa_with_SHA256" +#define NID_dsa_with_SHA256 803 +#define OBJ_dsa_with_SHA256 2L, 16L, 840L, 1L, 101L, 3L, 4L, 3L, 2L + +#define SN_whirlpool "whirlpool" +#define NID_whirlpool 804 +#define OBJ_whirlpool 1L, 0L, 10118L, 3L, 0L, 55L + +#define SN_cryptopro "cryptopro" +#define NID_cryptopro 805 +#define OBJ_cryptopro 1L, 2L, 643L, 2L, 2L + +#define SN_cryptocom "cryptocom" +#define NID_cryptocom 806 +#define OBJ_cryptocom 1L, 2L, 643L, 2L, 9L + +#define SN_id_GostR3411_94_with_GostR3410_2001 \ + "id-GostR3411-94-with-GostR3410-2001" +#define LN_id_GostR3411_94_with_GostR3410_2001 \ + "GOST R 34.11-94 with GOST R 34.10-2001" +#define NID_id_GostR3411_94_with_GostR3410_2001 807 +#define OBJ_id_GostR3411_94_with_GostR3410_2001 1L, 2L, 643L, 2L, 2L, 3L + +#define SN_id_GostR3411_94_with_GostR3410_94 "id-GostR3411-94-with-GostR3410-94" +#define LN_id_GostR3411_94_with_GostR3410_94 \ + "GOST R 34.11-94 with GOST R 34.10-94" +#define NID_id_GostR3411_94_with_GostR3410_94 808 +#define OBJ_id_GostR3411_94_with_GostR3410_94 1L, 2L, 643L, 2L, 2L, 4L + +#define SN_id_GostR3411_94 "md_gost94" +#define LN_id_GostR3411_94 "GOST R 34.11-94" +#define NID_id_GostR3411_94 809 +#define OBJ_id_GostR3411_94 1L, 2L, 643L, 2L, 2L, 9L + +#define SN_id_HMACGostR3411_94 "id-HMACGostR3411-94" +#define LN_id_HMACGostR3411_94 "HMAC GOST 34.11-94" +#define NID_id_HMACGostR3411_94 810 +#define OBJ_id_HMACGostR3411_94 1L, 2L, 643L, 2L, 2L, 10L + +#define SN_id_GostR3410_2001 "gost2001" +#define LN_id_GostR3410_2001 "GOST R 34.10-2001" +#define NID_id_GostR3410_2001 811 +#define OBJ_id_GostR3410_2001 1L, 2L, 643L, 2L, 2L, 19L + +#define SN_id_GostR3410_94 "gost94" +#define LN_id_GostR3410_94 "GOST R 34.10-94" +#define NID_id_GostR3410_94 812 +#define OBJ_id_GostR3410_94 1L, 2L, 643L, 2L, 2L, 20L + +#define SN_id_Gost28147_89 "gost89" +#define LN_id_Gost28147_89 "GOST 28147-89" +#define NID_id_Gost28147_89 813 +#define OBJ_id_Gost28147_89 1L, 2L, 643L, 2L, 2L, 21L + +#define SN_gost89_cnt "gost89-cnt" +#define NID_gost89_cnt 814 + +#define SN_id_Gost28147_89_MAC "gost-mac" +#define LN_id_Gost28147_89_MAC "GOST 28147-89 MAC" +#define NID_id_Gost28147_89_MAC 815 +#define OBJ_id_Gost28147_89_MAC 1L, 2L, 643L, 2L, 2L, 22L + +#define SN_id_GostR3411_94_prf "prf-gostr3411-94" +#define LN_id_GostR3411_94_prf "GOST R 34.11-94 PRF" +#define NID_id_GostR3411_94_prf 816 +#define OBJ_id_GostR3411_94_prf 1L, 2L, 643L, 2L, 2L, 23L + +#define SN_id_GostR3410_2001DH "id-GostR3410-2001DH" +#define LN_id_GostR3410_2001DH "GOST R 34.10-2001 DH" +#define NID_id_GostR3410_2001DH 817 +#define OBJ_id_GostR3410_2001DH 1L, 2L, 643L, 2L, 2L, 98L + +#define SN_id_GostR3410_94DH "id-GostR3410-94DH" +#define LN_id_GostR3410_94DH "GOST R 34.10-94 DH" +#define NID_id_GostR3410_94DH 818 +#define OBJ_id_GostR3410_94DH 1L, 2L, 643L, 2L, 2L, 99L + +#define SN_id_Gost28147_89_CryptoPro_KeyMeshing \ + "id-Gost28147-89-CryptoPro-KeyMeshing" +#define NID_id_Gost28147_89_CryptoPro_KeyMeshing 819 +#define OBJ_id_Gost28147_89_CryptoPro_KeyMeshing 1L, 2L, 643L, 2L, 2L, 14L, 1L + +#define SN_id_Gost28147_89_None_KeyMeshing "id-Gost28147-89-None-KeyMeshing" +#define NID_id_Gost28147_89_None_KeyMeshing 820 +#define OBJ_id_Gost28147_89_None_KeyMeshing 1L, 2L, 643L, 2L, 2L, 14L, 0L + +#define SN_id_GostR3411_94_TestParamSet "id-GostR3411-94-TestParamSet" +#define NID_id_GostR3411_94_TestParamSet 821 +#define OBJ_id_GostR3411_94_TestParamSet 1L, 2L, 643L, 2L, 2L, 30L, 0L + +#define SN_id_GostR3411_94_CryptoProParamSet "id-GostR3411-94-CryptoProParamSet" +#define NID_id_GostR3411_94_CryptoProParamSet 822 +#define OBJ_id_GostR3411_94_CryptoProParamSet 1L, 2L, 643L, 2L, 2L, 30L, 1L + +#define SN_id_Gost28147_89_TestParamSet "id-Gost28147-89-TestParamSet" +#define NID_id_Gost28147_89_TestParamSet 823 +#define OBJ_id_Gost28147_89_TestParamSet 1L, 2L, 643L, 2L, 2L, 31L, 0L + +#define SN_id_Gost28147_89_CryptoPro_A_ParamSet \ + "id-Gost28147-89-CryptoPro-A-ParamSet" +#define NID_id_Gost28147_89_CryptoPro_A_ParamSet 824 +#define OBJ_id_Gost28147_89_CryptoPro_A_ParamSet 1L, 2L, 643L, 2L, 2L, 31L, 1L + +#define SN_id_Gost28147_89_CryptoPro_B_ParamSet \ + "id-Gost28147-89-CryptoPro-B-ParamSet" +#define NID_id_Gost28147_89_CryptoPro_B_ParamSet 825 +#define OBJ_id_Gost28147_89_CryptoPro_B_ParamSet 1L, 2L, 643L, 2L, 2L, 31L, 2L + +#define SN_id_Gost28147_89_CryptoPro_C_ParamSet \ + "id-Gost28147-89-CryptoPro-C-ParamSet" +#define NID_id_Gost28147_89_CryptoPro_C_ParamSet 826 +#define OBJ_id_Gost28147_89_CryptoPro_C_ParamSet 1L, 2L, 643L, 2L, 2L, 31L, 3L + +#define SN_id_Gost28147_89_CryptoPro_D_ParamSet \ + "id-Gost28147-89-CryptoPro-D-ParamSet" +#define NID_id_Gost28147_89_CryptoPro_D_ParamSet 827 +#define OBJ_id_Gost28147_89_CryptoPro_D_ParamSet 1L, 2L, 643L, 2L, 2L, 31L, 4L + +#define SN_id_Gost28147_89_CryptoPro_Oscar_1_1_ParamSet \ + "id-Gost28147-89-CryptoPro-Oscar-1-1-ParamSet" +#define NID_id_Gost28147_89_CryptoPro_Oscar_1_1_ParamSet 828 +#define OBJ_id_Gost28147_89_CryptoPro_Oscar_1_1_ParamSet \ + 1L, 2L, 643L, 2L, 2L, 31L, 5L + +#define SN_id_Gost28147_89_CryptoPro_Oscar_1_0_ParamSet \ + "id-Gost28147-89-CryptoPro-Oscar-1-0-ParamSet" +#define NID_id_Gost28147_89_CryptoPro_Oscar_1_0_ParamSet 829 +#define OBJ_id_Gost28147_89_CryptoPro_Oscar_1_0_ParamSet \ + 1L, 2L, 643L, 2L, 2L, 31L, 6L + +#define SN_id_Gost28147_89_CryptoPro_RIC_1_ParamSet \ + "id-Gost28147-89-CryptoPro-RIC-1-ParamSet" +#define NID_id_Gost28147_89_CryptoPro_RIC_1_ParamSet 830 +#define OBJ_id_Gost28147_89_CryptoPro_RIC_1_ParamSet \ + 1L, 2L, 643L, 2L, 2L, 31L, 7L + +#define SN_id_GostR3410_94_TestParamSet "id-GostR3410-94-TestParamSet" +#define NID_id_GostR3410_94_TestParamSet 831 +#define OBJ_id_GostR3410_94_TestParamSet 1L, 2L, 643L, 2L, 2L, 32L, 0L + +#define SN_id_GostR3410_94_CryptoPro_A_ParamSet \ + "id-GostR3410-94-CryptoPro-A-ParamSet" +#define NID_id_GostR3410_94_CryptoPro_A_ParamSet 832 +#define OBJ_id_GostR3410_94_CryptoPro_A_ParamSet 1L, 2L, 643L, 2L, 2L, 32L, 2L + +#define SN_id_GostR3410_94_CryptoPro_B_ParamSet \ + "id-GostR3410-94-CryptoPro-B-ParamSet" +#define NID_id_GostR3410_94_CryptoPro_B_ParamSet 833 +#define OBJ_id_GostR3410_94_CryptoPro_B_ParamSet 1L, 2L, 643L, 2L, 2L, 32L, 3L + +#define SN_id_GostR3410_94_CryptoPro_C_ParamSet \ + "id-GostR3410-94-CryptoPro-C-ParamSet" +#define NID_id_GostR3410_94_CryptoPro_C_ParamSet 834 +#define OBJ_id_GostR3410_94_CryptoPro_C_ParamSet 1L, 2L, 643L, 2L, 2L, 32L, 4L + +#define SN_id_GostR3410_94_CryptoPro_D_ParamSet \ + "id-GostR3410-94-CryptoPro-D-ParamSet" +#define NID_id_GostR3410_94_CryptoPro_D_ParamSet 835 +#define OBJ_id_GostR3410_94_CryptoPro_D_ParamSet 1L, 2L, 643L, 2L, 2L, 32L, 5L + +#define SN_id_GostR3410_94_CryptoPro_XchA_ParamSet \ + "id-GostR3410-94-CryptoPro-XchA-ParamSet" +#define NID_id_GostR3410_94_CryptoPro_XchA_ParamSet 836 +#define OBJ_id_GostR3410_94_CryptoPro_XchA_ParamSet \ + 1L, 2L, 643L, 2L, 2L, 33L, 1L + +#define SN_id_GostR3410_94_CryptoPro_XchB_ParamSet \ + "id-GostR3410-94-CryptoPro-XchB-ParamSet" +#define NID_id_GostR3410_94_CryptoPro_XchB_ParamSet 837 +#define OBJ_id_GostR3410_94_CryptoPro_XchB_ParamSet \ + 1L, 2L, 643L, 2L, 2L, 33L, 2L + +#define SN_id_GostR3410_94_CryptoPro_XchC_ParamSet \ + "id-GostR3410-94-CryptoPro-XchC-ParamSet" +#define NID_id_GostR3410_94_CryptoPro_XchC_ParamSet 838 +#define OBJ_id_GostR3410_94_CryptoPro_XchC_ParamSet \ + 1L, 2L, 643L, 2L, 2L, 33L, 3L + +#define SN_id_GostR3410_2001_TestParamSet "id-GostR3410-2001-TestParamSet" +#define NID_id_GostR3410_2001_TestParamSet 839 +#define OBJ_id_GostR3410_2001_TestParamSet 1L, 2L, 643L, 2L, 2L, 35L, 0L + +#define SN_id_GostR3410_2001_CryptoPro_A_ParamSet \ + "id-GostR3410-2001-CryptoPro-A-ParamSet" +#define NID_id_GostR3410_2001_CryptoPro_A_ParamSet 840 +#define OBJ_id_GostR3410_2001_CryptoPro_A_ParamSet 1L, 2L, 643L, 2L, 2L, 35L, 1L + +#define SN_id_GostR3410_2001_CryptoPro_B_ParamSet \ + "id-GostR3410-2001-CryptoPro-B-ParamSet" +#define NID_id_GostR3410_2001_CryptoPro_B_ParamSet 841 +#define OBJ_id_GostR3410_2001_CryptoPro_B_ParamSet 1L, 2L, 643L, 2L, 2L, 35L, 2L + +#define SN_id_GostR3410_2001_CryptoPro_C_ParamSet \ + "id-GostR3410-2001-CryptoPro-C-ParamSet" +#define NID_id_GostR3410_2001_CryptoPro_C_ParamSet 842 +#define OBJ_id_GostR3410_2001_CryptoPro_C_ParamSet 1L, 2L, 643L, 2L, 2L, 35L, 3L + +#define SN_id_GostR3410_2001_CryptoPro_XchA_ParamSet \ + "id-GostR3410-2001-CryptoPro-XchA-ParamSet" +#define NID_id_GostR3410_2001_CryptoPro_XchA_ParamSet 843 +#define OBJ_id_GostR3410_2001_CryptoPro_XchA_ParamSet \ + 1L, 2L, 643L, 2L, 2L, 36L, 0L + +#define SN_id_GostR3410_2001_CryptoPro_XchB_ParamSet \ + "id-GostR3410-2001-CryptoPro-XchB-ParamSet" +#define NID_id_GostR3410_2001_CryptoPro_XchB_ParamSet 844 +#define OBJ_id_GostR3410_2001_CryptoPro_XchB_ParamSet \ + 1L, 2L, 643L, 2L, 2L, 36L, 1L + +#define SN_id_GostR3410_94_a "id-GostR3410-94-a" +#define NID_id_GostR3410_94_a 845 +#define OBJ_id_GostR3410_94_a 1L, 2L, 643L, 2L, 2L, 20L, 1L + +#define SN_id_GostR3410_94_aBis "id-GostR3410-94-aBis" +#define NID_id_GostR3410_94_aBis 846 +#define OBJ_id_GostR3410_94_aBis 1L, 2L, 643L, 2L, 2L, 20L, 2L + +#define SN_id_GostR3410_94_b "id-GostR3410-94-b" +#define NID_id_GostR3410_94_b 847 +#define OBJ_id_GostR3410_94_b 1L, 2L, 643L, 2L, 2L, 20L, 3L + +#define SN_id_GostR3410_94_bBis "id-GostR3410-94-bBis" +#define NID_id_GostR3410_94_bBis 848 +#define OBJ_id_GostR3410_94_bBis 1L, 2L, 643L, 2L, 2L, 20L, 4L + +#define SN_id_Gost28147_89_cc "id-Gost28147-89-cc" +#define LN_id_Gost28147_89_cc "GOST 28147-89 Cryptocom ParamSet" +#define NID_id_Gost28147_89_cc 849 +#define OBJ_id_Gost28147_89_cc 1L, 2L, 643L, 2L, 9L, 1L, 6L, 1L + +#define SN_id_GostR3410_94_cc "gost94cc" +#define LN_id_GostR3410_94_cc "GOST 34.10-94 Cryptocom" +#define NID_id_GostR3410_94_cc 850 +#define OBJ_id_GostR3410_94_cc 1L, 2L, 643L, 2L, 9L, 1L, 5L, 3L + +#define SN_id_GostR3410_2001_cc "gost2001cc" +#define LN_id_GostR3410_2001_cc "GOST 34.10-2001 Cryptocom" +#define NID_id_GostR3410_2001_cc 851 +#define OBJ_id_GostR3410_2001_cc 1L, 2L, 643L, 2L, 9L, 1L, 5L, 4L + +#define SN_id_GostR3411_94_with_GostR3410_94_cc \ + "id-GostR3411-94-with-GostR3410-94-cc" +#define LN_id_GostR3411_94_with_GostR3410_94_cc \ + "GOST R 34.11-94 with GOST R 34.10-94 Cryptocom" +#define NID_id_GostR3411_94_with_GostR3410_94_cc 852 +#define OBJ_id_GostR3411_94_with_GostR3410_94_cc \ + 1L, 2L, 643L, 2L, 9L, 1L, 3L, 3L + +#define SN_id_GostR3411_94_with_GostR3410_2001_cc \ + "id-GostR3411-94-with-GostR3410-2001-cc" +#define LN_id_GostR3411_94_with_GostR3410_2001_cc \ + "GOST R 34.11-94 with GOST R 34.10-2001 Cryptocom" +#define NID_id_GostR3411_94_with_GostR3410_2001_cc 853 +#define OBJ_id_GostR3411_94_with_GostR3410_2001_cc \ + 1L, 2L, 643L, 2L, 9L, 1L, 3L, 4L + +#define SN_id_GostR3410_2001_ParamSet_cc "id-GostR3410-2001-ParamSet-cc" +#define LN_id_GostR3410_2001_ParamSet_cc \ + "GOST R 3410-2001 Parameter Set Cryptocom" +#define NID_id_GostR3410_2001_ParamSet_cc 854 +#define OBJ_id_GostR3410_2001_ParamSet_cc 1L, 2L, 643L, 2L, 9L, 1L, 8L, 1L + +#define SN_hmac "HMAC" +#define LN_hmac "hmac" +#define NID_hmac 855 + +#define SN_LocalKeySet "LocalKeySet" +#define LN_LocalKeySet "Microsoft Local Key set" +#define NID_LocalKeySet 856 +#define OBJ_LocalKeySet 1L, 3L, 6L, 1L, 4L, 1L, 311L, 17L, 2L + +#define SN_freshest_crl "freshestCRL" +#define LN_freshest_crl "X509v3 Freshest CRL" +#define NID_freshest_crl 857 +#define OBJ_freshest_crl 2L, 5L, 29L, 46L + +#define SN_id_on_permanentIdentifier "id-on-permanentIdentifier" +#define LN_id_on_permanentIdentifier "Permanent Identifier" +#define NID_id_on_permanentIdentifier 858 +#define OBJ_id_on_permanentIdentifier 1L, 3L, 6L, 1L, 5L, 5L, 7L, 8L, 3L + +#define LN_searchGuide "searchGuide" +#define NID_searchGuide 859 +#define OBJ_searchGuide 2L, 5L, 4L, 14L + +#define LN_businessCategory "businessCategory" +#define NID_businessCategory 860 +#define OBJ_businessCategory 2L, 5L, 4L, 15L + +#define LN_postalAddress "postalAddress" +#define NID_postalAddress 861 +#define OBJ_postalAddress 2L, 5L, 4L, 16L + +#define LN_postOfficeBox "postOfficeBox" +#define NID_postOfficeBox 862 +#define OBJ_postOfficeBox 2L, 5L, 4L, 18L + +#define LN_physicalDeliveryOfficeName "physicalDeliveryOfficeName" +#define NID_physicalDeliveryOfficeName 863 +#define OBJ_physicalDeliveryOfficeName 2L, 5L, 4L, 19L + +#define LN_telephoneNumber "telephoneNumber" +#define NID_telephoneNumber 864 +#define OBJ_telephoneNumber 2L, 5L, 4L, 20L + +#define LN_telexNumber "telexNumber" +#define NID_telexNumber 865 +#define OBJ_telexNumber 2L, 5L, 4L, 21L + +#define LN_teletexTerminalIdentifier "teletexTerminalIdentifier" +#define NID_teletexTerminalIdentifier 866 +#define OBJ_teletexTerminalIdentifier 2L, 5L, 4L, 22L + +#define LN_facsimileTelephoneNumber "facsimileTelephoneNumber" +#define NID_facsimileTelephoneNumber 867 +#define OBJ_facsimileTelephoneNumber 2L, 5L, 4L, 23L + +#define LN_x121Address "x121Address" +#define NID_x121Address 868 +#define OBJ_x121Address 2L, 5L, 4L, 24L + +#define LN_internationaliSDNNumber "internationaliSDNNumber" +#define NID_internationaliSDNNumber 869 +#define OBJ_internationaliSDNNumber 2L, 5L, 4L, 25L + +#define LN_registeredAddress "registeredAddress" +#define NID_registeredAddress 870 +#define OBJ_registeredAddress 2L, 5L, 4L, 26L + +#define LN_destinationIndicator "destinationIndicator" +#define NID_destinationIndicator 871 +#define OBJ_destinationIndicator 2L, 5L, 4L, 27L + +#define LN_preferredDeliveryMethod "preferredDeliveryMethod" +#define NID_preferredDeliveryMethod 872 +#define OBJ_preferredDeliveryMethod 2L, 5L, 4L, 28L + +#define LN_presentationAddress "presentationAddress" +#define NID_presentationAddress 873 +#define OBJ_presentationAddress 2L, 5L, 4L, 29L + +#define LN_supportedApplicationContext "supportedApplicationContext" +#define NID_supportedApplicationContext 874 +#define OBJ_supportedApplicationContext 2L, 5L, 4L, 30L + +#define SN_member "member" +#define NID_member 875 +#define OBJ_member 2L, 5L, 4L, 31L + +#define SN_owner "owner" +#define NID_owner 876 +#define OBJ_owner 2L, 5L, 4L, 32L + +#define LN_roleOccupant "roleOccupant" +#define NID_roleOccupant 877 +#define OBJ_roleOccupant 2L, 5L, 4L, 33L + +#define SN_seeAlso "seeAlso" +#define NID_seeAlso 878 +#define OBJ_seeAlso 2L, 5L, 4L, 34L + +#define LN_userPassword "userPassword" +#define NID_userPassword 879 +#define OBJ_userPassword 2L, 5L, 4L, 35L + +#define LN_userCertificate "userCertificate" +#define NID_userCertificate 880 +#define OBJ_userCertificate 2L, 5L, 4L, 36L + +#define LN_cACertificate "cACertificate" +#define NID_cACertificate 881 +#define OBJ_cACertificate 2L, 5L, 4L, 37L + +#define LN_authorityRevocationList "authorityRevocationList" +#define NID_authorityRevocationList 882 +#define OBJ_authorityRevocationList 2L, 5L, 4L, 38L + +#define LN_certificateRevocationList "certificateRevocationList" +#define NID_certificateRevocationList 883 +#define OBJ_certificateRevocationList 2L, 5L, 4L, 39L + +#define LN_crossCertificatePair "crossCertificatePair" +#define NID_crossCertificatePair 884 +#define OBJ_crossCertificatePair 2L, 5L, 4L, 40L + +#define LN_enhancedSearchGuide "enhancedSearchGuide" +#define NID_enhancedSearchGuide 885 +#define OBJ_enhancedSearchGuide 2L, 5L, 4L, 47L + +#define LN_protocolInformation "protocolInformation" +#define NID_protocolInformation 886 +#define OBJ_protocolInformation 2L, 5L, 4L, 48L + +#define LN_distinguishedName "distinguishedName" +#define NID_distinguishedName 887 +#define OBJ_distinguishedName 2L, 5L, 4L, 49L + +#define LN_uniqueMember "uniqueMember" +#define NID_uniqueMember 888 +#define OBJ_uniqueMember 2L, 5L, 4L, 50L + +#define LN_houseIdentifier "houseIdentifier" +#define NID_houseIdentifier 889 +#define OBJ_houseIdentifier 2L, 5L, 4L, 51L + +#define LN_supportedAlgorithms "supportedAlgorithms" +#define NID_supportedAlgorithms 890 +#define OBJ_supportedAlgorithms 2L, 5L, 4L, 52L + +#define LN_deltaRevocationList "deltaRevocationList" +#define NID_deltaRevocationList 891 +#define OBJ_deltaRevocationList 2L, 5L, 4L, 53L + +#define SN_dmdName "dmdName" +#define NID_dmdName 892 +#define OBJ_dmdName 2L, 5L, 4L, 54L + +#define SN_id_alg_PWRI_KEK "id-alg-PWRI-KEK" +#define NID_id_alg_PWRI_KEK 893 +#define OBJ_id_alg_PWRI_KEK 1L, 2L, 840L, 113549L, 1L, 9L, 16L, 3L, 9L + +#define SN_cmac "CMAC" +#define LN_cmac "cmac" +#define NID_cmac 894 + +#define SN_aes_128_gcm "id-aes128-GCM" +#define LN_aes_128_gcm "aes-128-gcm" +#define NID_aes_128_gcm 895 +#define OBJ_aes_128_gcm 2L, 16L, 840L, 1L, 101L, 3L, 4L, 1L, 6L + +#define SN_aes_128_ccm "id-aes128-CCM" +#define LN_aes_128_ccm "aes-128-ccm" +#define NID_aes_128_ccm 896 +#define OBJ_aes_128_ccm 2L, 16L, 840L, 1L, 101L, 3L, 4L, 1L, 7L + +#define SN_id_aes128_wrap_pad "id-aes128-wrap-pad" +#define NID_id_aes128_wrap_pad 897 +#define OBJ_id_aes128_wrap_pad 2L, 16L, 840L, 1L, 101L, 3L, 4L, 1L, 8L + +#define SN_aes_192_gcm "id-aes192-GCM" +#define LN_aes_192_gcm "aes-192-gcm" +#define NID_aes_192_gcm 898 +#define OBJ_aes_192_gcm 2L, 16L, 840L, 1L, 101L, 3L, 4L, 1L, 26L + +#define SN_aes_192_ccm "id-aes192-CCM" +#define LN_aes_192_ccm "aes-192-ccm" +#define NID_aes_192_ccm 899 +#define OBJ_aes_192_ccm 2L, 16L, 840L, 1L, 101L, 3L, 4L, 1L, 27L + +#define SN_id_aes192_wrap_pad "id-aes192-wrap-pad" +#define NID_id_aes192_wrap_pad 900 +#define OBJ_id_aes192_wrap_pad 2L, 16L, 840L, 1L, 101L, 3L, 4L, 1L, 28L + +#define SN_aes_256_gcm "id-aes256-GCM" +#define LN_aes_256_gcm "aes-256-gcm" +#define NID_aes_256_gcm 901 +#define OBJ_aes_256_gcm 2L, 16L, 840L, 1L, 101L, 3L, 4L, 1L, 46L + +#define SN_aes_256_ccm "id-aes256-CCM" +#define LN_aes_256_ccm "aes-256-ccm" +#define NID_aes_256_ccm 902 +#define OBJ_aes_256_ccm 2L, 16L, 840L, 1L, 101L, 3L, 4L, 1L, 47L + +#define SN_id_aes256_wrap_pad "id-aes256-wrap-pad" +#define NID_id_aes256_wrap_pad 903 +#define OBJ_id_aes256_wrap_pad 2L, 16L, 840L, 1L, 101L, 3L, 4L, 1L, 48L + +#define SN_aes_128_ctr "AES-128-CTR" +#define LN_aes_128_ctr "aes-128-ctr" +#define NID_aes_128_ctr 904 + +#define SN_aes_192_ctr "AES-192-CTR" +#define LN_aes_192_ctr "aes-192-ctr" +#define NID_aes_192_ctr 905 + +#define SN_aes_256_ctr "AES-256-CTR" +#define LN_aes_256_ctr "aes-256-ctr" +#define NID_aes_256_ctr 906 + +#define SN_id_camellia128_wrap "id-camellia128-wrap" +#define NID_id_camellia128_wrap 907 +#define OBJ_id_camellia128_wrap 1L, 2L, 392L, 200011L, 61L, 1L, 1L, 3L, 2L + +#define SN_id_camellia192_wrap "id-camellia192-wrap" +#define NID_id_camellia192_wrap 908 +#define OBJ_id_camellia192_wrap 1L, 2L, 392L, 200011L, 61L, 1L, 1L, 3L, 3L + +#define SN_id_camellia256_wrap "id-camellia256-wrap" +#define NID_id_camellia256_wrap 909 +#define OBJ_id_camellia256_wrap 1L, 2L, 392L, 200011L, 61L, 1L, 1L, 3L, 4L + +#define SN_anyExtendedKeyUsage "anyExtendedKeyUsage" +#define LN_anyExtendedKeyUsage "Any Extended Key Usage" +#define NID_anyExtendedKeyUsage 910 +#define OBJ_anyExtendedKeyUsage 2L, 5L, 29L, 37L, 0L + +#define SN_mgf1 "MGF1" +#define LN_mgf1 "mgf1" +#define NID_mgf1 911 +#define OBJ_mgf1 1L, 2L, 840L, 113549L, 1L, 1L, 8L + +#define SN_rsassaPss "RSASSA-PSS" +#define LN_rsassaPss "rsassaPss" +#define NID_rsassaPss 912 +#define OBJ_rsassaPss 1L, 2L, 840L, 113549L, 1L, 1L, 10L + +#define SN_aes_128_xts "AES-128-XTS" +#define LN_aes_128_xts "aes-128-xts" +#define NID_aes_128_xts 913 + +#define SN_aes_256_xts "AES-256-XTS" +#define LN_aes_256_xts "aes-256-xts" +#define NID_aes_256_xts 914 + +#define SN_rc4_hmac_md5 "RC4-HMAC-MD5" +#define LN_rc4_hmac_md5 "rc4-hmac-md5" +#define NID_rc4_hmac_md5 915 + +#define SN_aes_128_cbc_hmac_sha1 "AES-128-CBC-HMAC-SHA1" +#define LN_aes_128_cbc_hmac_sha1 "aes-128-cbc-hmac-sha1" +#define NID_aes_128_cbc_hmac_sha1 916 + +#define SN_aes_192_cbc_hmac_sha1 "AES-192-CBC-HMAC-SHA1" +#define LN_aes_192_cbc_hmac_sha1 "aes-192-cbc-hmac-sha1" +#define NID_aes_192_cbc_hmac_sha1 917 + +#define SN_aes_256_cbc_hmac_sha1 "AES-256-CBC-HMAC-SHA1" +#define LN_aes_256_cbc_hmac_sha1 "aes-256-cbc-hmac-sha1" +#define NID_aes_256_cbc_hmac_sha1 918 + +#define SN_rsaesOaep "RSAES-OAEP" +#define LN_rsaesOaep "rsaesOaep" +#define NID_rsaesOaep 919 +#define OBJ_rsaesOaep 1L, 2L, 840L, 113549L, 1L, 1L, 7L + +#define SN_dhpublicnumber "dhpublicnumber" +#define LN_dhpublicnumber "X9.42 DH" +#define NID_dhpublicnumber 920 +#define OBJ_dhpublicnumber 1L, 2L, 840L, 10046L, 2L, 1L + +#define SN_brainpoolP160r1 "brainpoolP160r1" +#define NID_brainpoolP160r1 921 +#define OBJ_brainpoolP160r1 1L, 3L, 36L, 3L, 3L, 2L, 8L, 1L, 1L, 1L + +#define SN_brainpoolP160t1 "brainpoolP160t1" +#define NID_brainpoolP160t1 922 +#define OBJ_brainpoolP160t1 1L, 3L, 36L, 3L, 3L, 2L, 8L, 1L, 1L, 2L + +#define SN_brainpoolP192r1 "brainpoolP192r1" +#define NID_brainpoolP192r1 923 +#define OBJ_brainpoolP192r1 1L, 3L, 36L, 3L, 3L, 2L, 8L, 1L, 1L, 3L + +#define SN_brainpoolP192t1 "brainpoolP192t1" +#define NID_brainpoolP192t1 924 +#define OBJ_brainpoolP192t1 1L, 3L, 36L, 3L, 3L, 2L, 8L, 1L, 1L, 4L + +#define SN_brainpoolP224r1 "brainpoolP224r1" +#define NID_brainpoolP224r1 925 +#define OBJ_brainpoolP224r1 1L, 3L, 36L, 3L, 3L, 2L, 8L, 1L, 1L, 5L + +#define SN_brainpoolP224t1 "brainpoolP224t1" +#define NID_brainpoolP224t1 926 +#define OBJ_brainpoolP224t1 1L, 3L, 36L, 3L, 3L, 2L, 8L, 1L, 1L, 6L + +#define SN_brainpoolP256r1 "brainpoolP256r1" +#define NID_brainpoolP256r1 927 +#define OBJ_brainpoolP256r1 1L, 3L, 36L, 3L, 3L, 2L, 8L, 1L, 1L, 7L + +#define SN_brainpoolP256t1 "brainpoolP256t1" +#define NID_brainpoolP256t1 928 +#define OBJ_brainpoolP256t1 1L, 3L, 36L, 3L, 3L, 2L, 8L, 1L, 1L, 8L + +#define SN_brainpoolP320r1 "brainpoolP320r1" +#define NID_brainpoolP320r1 929 +#define OBJ_brainpoolP320r1 1L, 3L, 36L, 3L, 3L, 2L, 8L, 1L, 1L, 9L + +#define SN_brainpoolP320t1 "brainpoolP320t1" +#define NID_brainpoolP320t1 930 +#define OBJ_brainpoolP320t1 1L, 3L, 36L, 3L, 3L, 2L, 8L, 1L, 1L, 10L + +#define SN_brainpoolP384r1 "brainpoolP384r1" +#define NID_brainpoolP384r1 931 +#define OBJ_brainpoolP384r1 1L, 3L, 36L, 3L, 3L, 2L, 8L, 1L, 1L, 11L + +#define SN_brainpoolP384t1 "brainpoolP384t1" +#define NID_brainpoolP384t1 932 +#define OBJ_brainpoolP384t1 1L, 3L, 36L, 3L, 3L, 2L, 8L, 1L, 1L, 12L + +#define SN_brainpoolP512r1 "brainpoolP512r1" +#define NID_brainpoolP512r1 933 +#define OBJ_brainpoolP512r1 1L, 3L, 36L, 3L, 3L, 2L, 8L, 1L, 1L, 13L + +#define SN_brainpoolP512t1 "brainpoolP512t1" +#define NID_brainpoolP512t1 934 +#define OBJ_brainpoolP512t1 1L, 3L, 36L, 3L, 3L, 2L, 8L, 1L, 1L, 14L + +#define SN_pSpecified "PSPECIFIED" +#define LN_pSpecified "pSpecified" +#define NID_pSpecified 935 +#define OBJ_pSpecified 1L, 2L, 840L, 113549L, 1L, 1L, 9L + +#define SN_dhSinglePass_stdDH_sha1kdf_scheme "dhSinglePass-stdDH-sha1kdf-scheme" +#define NID_dhSinglePass_stdDH_sha1kdf_scheme 936 +#define OBJ_dhSinglePass_stdDH_sha1kdf_scheme \ + 1L, 3L, 133L, 16L, 840L, 63L, 0L, 2L + +#define SN_dhSinglePass_stdDH_sha224kdf_scheme \ + "dhSinglePass-stdDH-sha224kdf-scheme" +#define NID_dhSinglePass_stdDH_sha224kdf_scheme 937 +#define OBJ_dhSinglePass_stdDH_sha224kdf_scheme 1L, 3L, 132L, 1L, 11L, 0L + +#define SN_dhSinglePass_stdDH_sha256kdf_scheme \ + "dhSinglePass-stdDH-sha256kdf-scheme" +#define NID_dhSinglePass_stdDH_sha256kdf_scheme 938 +#define OBJ_dhSinglePass_stdDH_sha256kdf_scheme 1L, 3L, 132L, 1L, 11L, 1L + +#define SN_dhSinglePass_stdDH_sha384kdf_scheme \ + "dhSinglePass-stdDH-sha384kdf-scheme" +#define NID_dhSinglePass_stdDH_sha384kdf_scheme 939 +#define OBJ_dhSinglePass_stdDH_sha384kdf_scheme 1L, 3L, 132L, 1L, 11L, 2L + +#define SN_dhSinglePass_stdDH_sha512kdf_scheme \ + "dhSinglePass-stdDH-sha512kdf-scheme" +#define NID_dhSinglePass_stdDH_sha512kdf_scheme 940 +#define OBJ_dhSinglePass_stdDH_sha512kdf_scheme 1L, 3L, 132L, 1L, 11L, 3L + +#define SN_dhSinglePass_cofactorDH_sha1kdf_scheme \ + "dhSinglePass-cofactorDH-sha1kdf-scheme" +#define NID_dhSinglePass_cofactorDH_sha1kdf_scheme 941 +#define OBJ_dhSinglePass_cofactorDH_sha1kdf_scheme \ + 1L, 3L, 133L, 16L, 840L, 63L, 0L, 3L + +#define SN_dhSinglePass_cofactorDH_sha224kdf_scheme \ + "dhSinglePass-cofactorDH-sha224kdf-scheme" +#define NID_dhSinglePass_cofactorDH_sha224kdf_scheme 942 +#define OBJ_dhSinglePass_cofactorDH_sha224kdf_scheme 1L, 3L, 132L, 1L, 14L, 0L + +#define SN_dhSinglePass_cofactorDH_sha256kdf_scheme \ + "dhSinglePass-cofactorDH-sha256kdf-scheme" +#define NID_dhSinglePass_cofactorDH_sha256kdf_scheme 943 +#define OBJ_dhSinglePass_cofactorDH_sha256kdf_scheme 1L, 3L, 132L, 1L, 14L, 1L + +#define SN_dhSinglePass_cofactorDH_sha384kdf_scheme \ + "dhSinglePass-cofactorDH-sha384kdf-scheme" +#define NID_dhSinglePass_cofactorDH_sha384kdf_scheme 944 +#define OBJ_dhSinglePass_cofactorDH_sha384kdf_scheme 1L, 3L, 132L, 1L, 14L, 2L + +#define SN_dhSinglePass_cofactorDH_sha512kdf_scheme \ + "dhSinglePass-cofactorDH-sha512kdf-scheme" +#define NID_dhSinglePass_cofactorDH_sha512kdf_scheme 945 +#define OBJ_dhSinglePass_cofactorDH_sha512kdf_scheme 1L, 3L, 132L, 1L, 14L, 3L + +#define SN_dh_std_kdf "dh-std-kdf" +#define NID_dh_std_kdf 946 + +#define SN_dh_cofactor_kdf "dh-cofactor-kdf" +#define NID_dh_cofactor_kdf 947 + +#define SN_X25519 "X25519" +#define NID_X25519 948 + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_NID_H */ diff --git a/Sources/BoringSSL/include/openssl/obj.h b/Sources/BoringSSL/include/openssl/obj.h index 32a489484..63cf86625 100644 --- a/Sources/BoringSSL/include/openssl/obj.h +++ b/Sources/BoringSSL/include/openssl/obj.h @@ -60,7 +60,7 @@ #include #include -#include +#include #if defined(__cplusplus) extern "C" { @@ -135,7 +135,7 @@ OPENSSL_EXPORT int OBJ_nid2cbb(CBB *out, int nid); /* Dealing with textual representations of object identifiers. */ -/* OBJ_txt2obj returns an ASN1_OBJECT for the textual respresentation in |s|. +/* OBJ_txt2obj returns an ASN1_OBJECT for the textual representation in |s|. * If |dont_search_names| is zero, then |s| will be matched against the long * and short names of a known objects to find a match. Otherwise |s| must * contain an ASCII string with a dotted sequence of numbers. The resulting @@ -144,7 +144,7 @@ OPENSSL_EXPORT int OBJ_nid2cbb(CBB *out, int nid); OPENSSL_EXPORT ASN1_OBJECT *OBJ_txt2obj(const char *s, int dont_search_names); /* OBJ_obj2txt converts |obj| to a textual representation. If - * |dont_return_name| is zero then |obj| will be matched against known objects + * |always_return_oid| is zero then |obj| will be matched against known objects * and the long (preferably) or short name will be used if found. Otherwise * |obj| will be converted into a dotted sequence of integers. If |out| is not * NULL, then at most |out_len| bytes of the textual form will be written @@ -152,7 +152,7 @@ OPENSSL_EXPORT ASN1_OBJECT *OBJ_txt2obj(const char *s, int dont_search_names); * always be NUL terminated. It returns the number of characters that could * have been written, not including the final NUL, or -1 on error. */ OPENSSL_EXPORT int OBJ_obj2txt(char *out, int out_len, const ASN1_OBJECT *obj, - int dont_return_name); + int always_return_oid); /* Adding objects at runtime. */ @@ -189,6 +189,34 @@ OPENSSL_EXPORT int OBJ_find_sigid_by_algs(int *out_sign_nid, int digest_nid, int pkey_nid); +/* Deprecated functions. */ + +typedef struct obj_name_st { + int type; + int alias; + const char *name; + const char *data; +} OBJ_NAME; + +#define OBJ_NAME_TYPE_MD_METH 1 +#define OBJ_NAME_TYPE_CIPHER_METH 2 + +/* OBJ_NAME_do_all_sorted calls |callback| zero or more times, each time with + * the name of a different primitive. If |type| is |OBJ_NAME_TYPE_MD_METH| then + * the primitives will be hash functions, alternatively if |type| is + * |OBJ_NAME_TYPE_CIPHER_METH| then the primitives will be ciphers or cipher + * modes. + * + * This function is ill-specified and should never be used. */ +OPENSSL_EXPORT void OBJ_NAME_do_all_sorted( + int type, void (*callback)(const OBJ_NAME *, void *arg), void *arg); + +/* OBJ_NAME_do_all calls |OBJ_NAME_do_all_sorted|. */ +OPENSSL_EXPORT void OBJ_NAME_do_all(int type, void (*callback)(const OBJ_NAME *, + void *arg), + void *arg); + + #if defined(__cplusplus) } /* extern C */ #endif diff --git a/Sources/BoringSSL/include/openssl/obj_mac.h b/Sources/BoringSSL/include/openssl/obj_mac.h index b636adcfc..e7ccadc19 100644 --- a/Sources/BoringSSL/include/openssl/obj_mac.h +++ b/Sources/BoringSSL/include/openssl/obj_mac.h @@ -1,4144 +1,18 @@ -/* THIS FILE IS GENERATED FROM objects.txt by objects.pl via the - * following command: - * perl objects.pl objects.txt obj_mac.num ../../include/openssl/obj_mac.h */ - -/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com) - * All rights reserved. +/* Copyright (c) 2016, Google Inc. * - * This package is an SSL implementation written - * by Eric Young (eay@cryptsoft.com). - * The implementation was written so as to conform with Netscapes SSL. - * - * This library is free for commercial and non-commercial use as long as - * the following conditions are aheared to. The following conditions - * apply to all code found in this distribution, be it the RC4, RSA, - * lhash, DES, etc., code; not just the SSL code. The SSL documentation - * included with this distribution is covered by the same copyright terms - * except that the holder is Tim Hudson (tjh@cryptsoft.com). - * - * Copyright remains Eric Young's, and as such any Copyright notices in - * the code are not to be removed. - * If this package is used in a product, Eric Young should be given attribution - * as the author of the parts of the library used. - * This can be in the form of a textual message at program startup or - * in documentation (online or textual) provided with the package. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * "This product includes cryptographic software written by - * Eric Young (eay@cryptsoft.com)" - * The word 'cryptographic' can be left out if the rouines from the library - * being used are not cryptographic related :-). - * 4. If you include any Windows specific code (or a derivative thereof) from - * the apps directory (application code) you must include an acknowledgement: - * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" - * - * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * The licence and distribution terms for any publically available version or - * derivative of this code cannot be changed. i.e. this code cannot simply be - * copied and put under another distribution licence - * [including the GNU Public Licence.] - */ - -#define SN_undef "UNDEF" -#define LN_undef "undefined" -#define NID_undef 0 -#define OBJ_undef 0L - -#define SN_itu_t "ITU-T" -#define LN_itu_t "itu-t" -#define NID_itu_t 645 -#define OBJ_itu_t 0L - -#define NID_ccitt 404 -#define OBJ_ccitt OBJ_itu_t - -#define SN_iso "ISO" -#define LN_iso "iso" -#define NID_iso 181 -#define OBJ_iso 1L - -#define SN_joint_iso_itu_t "JOINT-ISO-ITU-T" -#define LN_joint_iso_itu_t "joint-iso-itu-t" -#define NID_joint_iso_itu_t 646 -#define OBJ_joint_iso_itu_t 2L - -#define NID_joint_iso_ccitt 393 -#define OBJ_joint_iso_ccitt OBJ_joint_iso_itu_t - -#define SN_member_body "member-body" -#define LN_member_body "ISO Member Body" -#define NID_member_body 182 -#define OBJ_member_body OBJ_iso,2L - -#define SN_identified_organization "identified-organization" -#define NID_identified_organization 676 -#define OBJ_identified_organization OBJ_iso,3L - -#define SN_hmac_md5 "HMAC-MD5" -#define LN_hmac_md5 "hmac-md5" -#define NID_hmac_md5 780 -#define OBJ_hmac_md5 OBJ_identified_organization,6L,1L,5L,5L,8L,1L,1L - -#define SN_hmac_sha1 "HMAC-SHA1" -#define LN_hmac_sha1 "hmac-sha1" -#define NID_hmac_sha1 781 -#define OBJ_hmac_sha1 OBJ_identified_organization,6L,1L,5L,5L,8L,1L,2L - -#define SN_certicom_arc "certicom-arc" -#define NID_certicom_arc 677 -#define OBJ_certicom_arc OBJ_identified_organization,132L - -#define SN_international_organizations "international-organizations" -#define LN_international_organizations "International Organizations" -#define NID_international_organizations 647 -#define OBJ_international_organizations OBJ_joint_iso_itu_t,23L - -#define SN_wap "wap" -#define NID_wap 678 -#define OBJ_wap OBJ_international_organizations,43L - -#define SN_wap_wsg "wap-wsg" -#define NID_wap_wsg 679 -#define OBJ_wap_wsg OBJ_wap,1L - -#define SN_selected_attribute_types "selected-attribute-types" -#define LN_selected_attribute_types "Selected Attribute Types" -#define NID_selected_attribute_types 394 -#define OBJ_selected_attribute_types OBJ_joint_iso_itu_t,5L,1L,5L - -#define SN_clearance "clearance" -#define NID_clearance 395 -#define OBJ_clearance OBJ_selected_attribute_types,55L - -#define SN_ISO_US "ISO-US" -#define LN_ISO_US "ISO US Member Body" -#define NID_ISO_US 183 -#define OBJ_ISO_US OBJ_member_body,840L - -#define SN_X9_57 "X9-57" -#define LN_X9_57 "X9.57" -#define NID_X9_57 184 -#define OBJ_X9_57 OBJ_ISO_US,10040L - -#define SN_X9cm "X9cm" -#define LN_X9cm "X9.57 CM ?" -#define NID_X9cm 185 -#define OBJ_X9cm OBJ_X9_57,4L - -#define SN_dsa "DSA" -#define LN_dsa "dsaEncryption" -#define NID_dsa 116 -#define OBJ_dsa OBJ_X9cm,1L - -#define SN_dsaWithSHA1 "DSA-SHA1" -#define LN_dsaWithSHA1 "dsaWithSHA1" -#define NID_dsaWithSHA1 113 -#define OBJ_dsaWithSHA1 OBJ_X9cm,3L - -#define SN_ansi_X9_62 "ansi-X9-62" -#define LN_ansi_X9_62 "ANSI X9.62" -#define NID_ansi_X9_62 405 -#define OBJ_ansi_X9_62 OBJ_ISO_US,10045L - -#define OBJ_X9_62_id_fieldType OBJ_ansi_X9_62,1L - -#define SN_X9_62_prime_field "prime-field" -#define NID_X9_62_prime_field 406 -#define OBJ_X9_62_prime_field OBJ_X9_62_id_fieldType,1L - -#define SN_X9_62_characteristic_two_field "characteristic-two-field" -#define NID_X9_62_characteristic_two_field 407 -#define OBJ_X9_62_characteristic_two_field OBJ_X9_62_id_fieldType,2L - -#define SN_X9_62_id_characteristic_two_basis "id-characteristic-two-basis" -#define NID_X9_62_id_characteristic_two_basis 680 -#define OBJ_X9_62_id_characteristic_two_basis OBJ_X9_62_characteristic_two_field,3L - -#define SN_X9_62_onBasis "onBasis" -#define NID_X9_62_onBasis 681 -#define OBJ_X9_62_onBasis OBJ_X9_62_id_characteristic_two_basis,1L - -#define SN_X9_62_tpBasis "tpBasis" -#define NID_X9_62_tpBasis 682 -#define OBJ_X9_62_tpBasis OBJ_X9_62_id_characteristic_two_basis,2L - -#define SN_X9_62_ppBasis "ppBasis" -#define NID_X9_62_ppBasis 683 -#define OBJ_X9_62_ppBasis OBJ_X9_62_id_characteristic_two_basis,3L - -#define OBJ_X9_62_id_publicKeyType OBJ_ansi_X9_62,2L - -#define SN_X9_62_id_ecPublicKey "id-ecPublicKey" -#define NID_X9_62_id_ecPublicKey 408 -#define OBJ_X9_62_id_ecPublicKey OBJ_X9_62_id_publicKeyType,1L - -#define OBJ_X9_62_ellipticCurve OBJ_ansi_X9_62,3L - -#define OBJ_X9_62_c_TwoCurve OBJ_X9_62_ellipticCurve,0L - -#define SN_X9_62_c2pnb163v1 "c2pnb163v1" -#define NID_X9_62_c2pnb163v1 684 -#define OBJ_X9_62_c2pnb163v1 OBJ_X9_62_c_TwoCurve,1L - -#define SN_X9_62_c2pnb163v2 "c2pnb163v2" -#define NID_X9_62_c2pnb163v2 685 -#define OBJ_X9_62_c2pnb163v2 OBJ_X9_62_c_TwoCurve,2L - -#define SN_X9_62_c2pnb163v3 "c2pnb163v3" -#define NID_X9_62_c2pnb163v3 686 -#define OBJ_X9_62_c2pnb163v3 OBJ_X9_62_c_TwoCurve,3L - -#define SN_X9_62_c2pnb176v1 "c2pnb176v1" -#define NID_X9_62_c2pnb176v1 687 -#define OBJ_X9_62_c2pnb176v1 OBJ_X9_62_c_TwoCurve,4L - -#define SN_X9_62_c2tnb191v1 "c2tnb191v1" -#define NID_X9_62_c2tnb191v1 688 -#define OBJ_X9_62_c2tnb191v1 OBJ_X9_62_c_TwoCurve,5L - -#define SN_X9_62_c2tnb191v2 "c2tnb191v2" -#define NID_X9_62_c2tnb191v2 689 -#define OBJ_X9_62_c2tnb191v2 OBJ_X9_62_c_TwoCurve,6L - -#define SN_X9_62_c2tnb191v3 "c2tnb191v3" -#define NID_X9_62_c2tnb191v3 690 -#define OBJ_X9_62_c2tnb191v3 OBJ_X9_62_c_TwoCurve,7L - -#define SN_X9_62_c2onb191v4 "c2onb191v4" -#define NID_X9_62_c2onb191v4 691 -#define OBJ_X9_62_c2onb191v4 OBJ_X9_62_c_TwoCurve,8L - -#define SN_X9_62_c2onb191v5 "c2onb191v5" -#define NID_X9_62_c2onb191v5 692 -#define OBJ_X9_62_c2onb191v5 OBJ_X9_62_c_TwoCurve,9L - -#define SN_X9_62_c2pnb208w1 "c2pnb208w1" -#define NID_X9_62_c2pnb208w1 693 -#define OBJ_X9_62_c2pnb208w1 OBJ_X9_62_c_TwoCurve,10L - -#define SN_X9_62_c2tnb239v1 "c2tnb239v1" -#define NID_X9_62_c2tnb239v1 694 -#define OBJ_X9_62_c2tnb239v1 OBJ_X9_62_c_TwoCurve,11L - -#define SN_X9_62_c2tnb239v2 "c2tnb239v2" -#define NID_X9_62_c2tnb239v2 695 -#define OBJ_X9_62_c2tnb239v2 OBJ_X9_62_c_TwoCurve,12L - -#define SN_X9_62_c2tnb239v3 "c2tnb239v3" -#define NID_X9_62_c2tnb239v3 696 -#define OBJ_X9_62_c2tnb239v3 OBJ_X9_62_c_TwoCurve,13L - -#define SN_X9_62_c2onb239v4 "c2onb239v4" -#define NID_X9_62_c2onb239v4 697 -#define OBJ_X9_62_c2onb239v4 OBJ_X9_62_c_TwoCurve,14L - -#define SN_X9_62_c2onb239v5 "c2onb239v5" -#define NID_X9_62_c2onb239v5 698 -#define OBJ_X9_62_c2onb239v5 OBJ_X9_62_c_TwoCurve,15L - -#define SN_X9_62_c2pnb272w1 "c2pnb272w1" -#define NID_X9_62_c2pnb272w1 699 -#define OBJ_X9_62_c2pnb272w1 OBJ_X9_62_c_TwoCurve,16L - -#define SN_X9_62_c2pnb304w1 "c2pnb304w1" -#define NID_X9_62_c2pnb304w1 700 -#define OBJ_X9_62_c2pnb304w1 OBJ_X9_62_c_TwoCurve,17L - -#define SN_X9_62_c2tnb359v1 "c2tnb359v1" -#define NID_X9_62_c2tnb359v1 701 -#define OBJ_X9_62_c2tnb359v1 OBJ_X9_62_c_TwoCurve,18L - -#define SN_X9_62_c2pnb368w1 "c2pnb368w1" -#define NID_X9_62_c2pnb368w1 702 -#define OBJ_X9_62_c2pnb368w1 OBJ_X9_62_c_TwoCurve,19L - -#define SN_X9_62_c2tnb431r1 "c2tnb431r1" -#define NID_X9_62_c2tnb431r1 703 -#define OBJ_X9_62_c2tnb431r1 OBJ_X9_62_c_TwoCurve,20L - -#define OBJ_X9_62_primeCurve OBJ_X9_62_ellipticCurve,1L - -#define SN_X9_62_prime192v1 "prime192v1" -#define NID_X9_62_prime192v1 409 -#define OBJ_X9_62_prime192v1 OBJ_X9_62_primeCurve,1L - -#define SN_X9_62_prime192v2 "prime192v2" -#define NID_X9_62_prime192v2 410 -#define OBJ_X9_62_prime192v2 OBJ_X9_62_primeCurve,2L - -#define SN_X9_62_prime192v3 "prime192v3" -#define NID_X9_62_prime192v3 411 -#define OBJ_X9_62_prime192v3 OBJ_X9_62_primeCurve,3L - -#define SN_X9_62_prime239v1 "prime239v1" -#define NID_X9_62_prime239v1 412 -#define OBJ_X9_62_prime239v1 OBJ_X9_62_primeCurve,4L - -#define SN_X9_62_prime239v2 "prime239v2" -#define NID_X9_62_prime239v2 413 -#define OBJ_X9_62_prime239v2 OBJ_X9_62_primeCurve,5L - -#define SN_X9_62_prime239v3 "prime239v3" -#define NID_X9_62_prime239v3 414 -#define OBJ_X9_62_prime239v3 OBJ_X9_62_primeCurve,6L - -#define SN_X9_62_prime256v1 "prime256v1" -#define NID_X9_62_prime256v1 415 -#define OBJ_X9_62_prime256v1 OBJ_X9_62_primeCurve,7L - -#define OBJ_X9_62_id_ecSigType OBJ_ansi_X9_62,4L - -#define SN_ecdsa_with_SHA1 "ecdsa-with-SHA1" -#define NID_ecdsa_with_SHA1 416 -#define OBJ_ecdsa_with_SHA1 OBJ_X9_62_id_ecSigType,1L - -#define SN_ecdsa_with_Recommended "ecdsa-with-Recommended" -#define NID_ecdsa_with_Recommended 791 -#define OBJ_ecdsa_with_Recommended OBJ_X9_62_id_ecSigType,2L - -#define SN_ecdsa_with_Specified "ecdsa-with-Specified" -#define NID_ecdsa_with_Specified 792 -#define OBJ_ecdsa_with_Specified OBJ_X9_62_id_ecSigType,3L - -#define SN_ecdsa_with_SHA224 "ecdsa-with-SHA224" -#define NID_ecdsa_with_SHA224 793 -#define OBJ_ecdsa_with_SHA224 OBJ_ecdsa_with_Specified,1L - -#define SN_ecdsa_with_SHA256 "ecdsa-with-SHA256" -#define NID_ecdsa_with_SHA256 794 -#define OBJ_ecdsa_with_SHA256 OBJ_ecdsa_with_Specified,2L - -#define SN_ecdsa_with_SHA384 "ecdsa-with-SHA384" -#define NID_ecdsa_with_SHA384 795 -#define OBJ_ecdsa_with_SHA384 OBJ_ecdsa_with_Specified,3L - -#define SN_ecdsa_with_SHA512 "ecdsa-with-SHA512" -#define NID_ecdsa_with_SHA512 796 -#define OBJ_ecdsa_with_SHA512 OBJ_ecdsa_with_Specified,4L - -#define OBJ_secg_ellipticCurve OBJ_certicom_arc,0L - -#define SN_secp112r1 "secp112r1" -#define NID_secp112r1 704 -#define OBJ_secp112r1 OBJ_secg_ellipticCurve,6L - -#define SN_secp112r2 "secp112r2" -#define NID_secp112r2 705 -#define OBJ_secp112r2 OBJ_secg_ellipticCurve,7L - -#define SN_secp128r1 "secp128r1" -#define NID_secp128r1 706 -#define OBJ_secp128r1 OBJ_secg_ellipticCurve,28L - -#define SN_secp128r2 "secp128r2" -#define NID_secp128r2 707 -#define OBJ_secp128r2 OBJ_secg_ellipticCurve,29L - -#define SN_secp160k1 "secp160k1" -#define NID_secp160k1 708 -#define OBJ_secp160k1 OBJ_secg_ellipticCurve,9L - -#define SN_secp160r1 "secp160r1" -#define NID_secp160r1 709 -#define OBJ_secp160r1 OBJ_secg_ellipticCurve,8L - -#define SN_secp160r2 "secp160r2" -#define NID_secp160r2 710 -#define OBJ_secp160r2 OBJ_secg_ellipticCurve,30L - -#define SN_secp192k1 "secp192k1" -#define NID_secp192k1 711 -#define OBJ_secp192k1 OBJ_secg_ellipticCurve,31L - -#define SN_secp224k1 "secp224k1" -#define NID_secp224k1 712 -#define OBJ_secp224k1 OBJ_secg_ellipticCurve,32L - -#define SN_secp224r1 "secp224r1" -#define NID_secp224r1 713 -#define OBJ_secp224r1 OBJ_secg_ellipticCurve,33L - -#define SN_secp256k1 "secp256k1" -#define NID_secp256k1 714 -#define OBJ_secp256k1 OBJ_secg_ellipticCurve,10L - -#define SN_secp384r1 "secp384r1" -#define NID_secp384r1 715 -#define OBJ_secp384r1 OBJ_secg_ellipticCurve,34L - -#define SN_secp521r1 "secp521r1" -#define NID_secp521r1 716 -#define OBJ_secp521r1 OBJ_secg_ellipticCurve,35L - -#define SN_sect113r1 "sect113r1" -#define NID_sect113r1 717 -#define OBJ_sect113r1 OBJ_secg_ellipticCurve,4L - -#define SN_sect113r2 "sect113r2" -#define NID_sect113r2 718 -#define OBJ_sect113r2 OBJ_secg_ellipticCurve,5L - -#define SN_sect131r1 "sect131r1" -#define NID_sect131r1 719 -#define OBJ_sect131r1 OBJ_secg_ellipticCurve,22L - -#define SN_sect131r2 "sect131r2" -#define NID_sect131r2 720 -#define OBJ_sect131r2 OBJ_secg_ellipticCurve,23L - -#define SN_sect163k1 "sect163k1" -#define NID_sect163k1 721 -#define OBJ_sect163k1 OBJ_secg_ellipticCurve,1L - -#define SN_sect163r1 "sect163r1" -#define NID_sect163r1 722 -#define OBJ_sect163r1 OBJ_secg_ellipticCurve,2L - -#define SN_sect163r2 "sect163r2" -#define NID_sect163r2 723 -#define OBJ_sect163r2 OBJ_secg_ellipticCurve,15L - -#define SN_sect193r1 "sect193r1" -#define NID_sect193r1 724 -#define OBJ_sect193r1 OBJ_secg_ellipticCurve,24L - -#define SN_sect193r2 "sect193r2" -#define NID_sect193r2 725 -#define OBJ_sect193r2 OBJ_secg_ellipticCurve,25L - -#define SN_sect233k1 "sect233k1" -#define NID_sect233k1 726 -#define OBJ_sect233k1 OBJ_secg_ellipticCurve,26L - -#define SN_sect233r1 "sect233r1" -#define NID_sect233r1 727 -#define OBJ_sect233r1 OBJ_secg_ellipticCurve,27L - -#define SN_sect239k1 "sect239k1" -#define NID_sect239k1 728 -#define OBJ_sect239k1 OBJ_secg_ellipticCurve,3L - -#define SN_sect283k1 "sect283k1" -#define NID_sect283k1 729 -#define OBJ_sect283k1 OBJ_secg_ellipticCurve,16L - -#define SN_sect283r1 "sect283r1" -#define NID_sect283r1 730 -#define OBJ_sect283r1 OBJ_secg_ellipticCurve,17L - -#define SN_sect409k1 "sect409k1" -#define NID_sect409k1 731 -#define OBJ_sect409k1 OBJ_secg_ellipticCurve,36L - -#define SN_sect409r1 "sect409r1" -#define NID_sect409r1 732 -#define OBJ_sect409r1 OBJ_secg_ellipticCurve,37L - -#define SN_sect571k1 "sect571k1" -#define NID_sect571k1 733 -#define OBJ_sect571k1 OBJ_secg_ellipticCurve,38L - -#define SN_sect571r1 "sect571r1" -#define NID_sect571r1 734 -#define OBJ_sect571r1 OBJ_secg_ellipticCurve,39L - -#define OBJ_wap_wsg_idm_ecid OBJ_wap_wsg,4L - -#define SN_wap_wsg_idm_ecid_wtls1 "wap-wsg-idm-ecid-wtls1" -#define NID_wap_wsg_idm_ecid_wtls1 735 -#define OBJ_wap_wsg_idm_ecid_wtls1 OBJ_wap_wsg_idm_ecid,1L - -#define SN_wap_wsg_idm_ecid_wtls3 "wap-wsg-idm-ecid-wtls3" -#define NID_wap_wsg_idm_ecid_wtls3 736 -#define OBJ_wap_wsg_idm_ecid_wtls3 OBJ_wap_wsg_idm_ecid,3L - -#define SN_wap_wsg_idm_ecid_wtls4 "wap-wsg-idm-ecid-wtls4" -#define NID_wap_wsg_idm_ecid_wtls4 737 -#define OBJ_wap_wsg_idm_ecid_wtls4 OBJ_wap_wsg_idm_ecid,4L - -#define SN_wap_wsg_idm_ecid_wtls5 "wap-wsg-idm-ecid-wtls5" -#define NID_wap_wsg_idm_ecid_wtls5 738 -#define OBJ_wap_wsg_idm_ecid_wtls5 OBJ_wap_wsg_idm_ecid,5L - -#define SN_wap_wsg_idm_ecid_wtls6 "wap-wsg-idm-ecid-wtls6" -#define NID_wap_wsg_idm_ecid_wtls6 739 -#define OBJ_wap_wsg_idm_ecid_wtls6 OBJ_wap_wsg_idm_ecid,6L - -#define SN_wap_wsg_idm_ecid_wtls7 "wap-wsg-idm-ecid-wtls7" -#define NID_wap_wsg_idm_ecid_wtls7 740 -#define OBJ_wap_wsg_idm_ecid_wtls7 OBJ_wap_wsg_idm_ecid,7L - -#define SN_wap_wsg_idm_ecid_wtls8 "wap-wsg-idm-ecid-wtls8" -#define NID_wap_wsg_idm_ecid_wtls8 741 -#define OBJ_wap_wsg_idm_ecid_wtls8 OBJ_wap_wsg_idm_ecid,8L - -#define SN_wap_wsg_idm_ecid_wtls9 "wap-wsg-idm-ecid-wtls9" -#define NID_wap_wsg_idm_ecid_wtls9 742 -#define OBJ_wap_wsg_idm_ecid_wtls9 OBJ_wap_wsg_idm_ecid,9L - -#define SN_wap_wsg_idm_ecid_wtls10 "wap-wsg-idm-ecid-wtls10" -#define NID_wap_wsg_idm_ecid_wtls10 743 -#define OBJ_wap_wsg_idm_ecid_wtls10 OBJ_wap_wsg_idm_ecid,10L - -#define SN_wap_wsg_idm_ecid_wtls11 "wap-wsg-idm-ecid-wtls11" -#define NID_wap_wsg_idm_ecid_wtls11 744 -#define OBJ_wap_wsg_idm_ecid_wtls11 OBJ_wap_wsg_idm_ecid,11L - -#define SN_wap_wsg_idm_ecid_wtls12 "wap-wsg-idm-ecid-wtls12" -#define NID_wap_wsg_idm_ecid_wtls12 745 -#define OBJ_wap_wsg_idm_ecid_wtls12 OBJ_wap_wsg_idm_ecid,12L - -#define SN_cast5_cbc "CAST5-CBC" -#define LN_cast5_cbc "cast5-cbc" -#define NID_cast5_cbc 108 -#define OBJ_cast5_cbc OBJ_ISO_US,113533L,7L,66L,10L - -#define SN_cast5_ecb "CAST5-ECB" -#define LN_cast5_ecb "cast5-ecb" -#define NID_cast5_ecb 109 - -#define SN_cast5_cfb64 "CAST5-CFB" -#define LN_cast5_cfb64 "cast5-cfb" -#define NID_cast5_cfb64 110 - -#define SN_cast5_ofb64 "CAST5-OFB" -#define LN_cast5_ofb64 "cast5-ofb" -#define NID_cast5_ofb64 111 - -#define LN_pbeWithMD5AndCast5_CBC "pbeWithMD5AndCast5CBC" -#define NID_pbeWithMD5AndCast5_CBC 112 -#define OBJ_pbeWithMD5AndCast5_CBC OBJ_ISO_US,113533L,7L,66L,12L - -#define SN_id_PasswordBasedMAC "id-PasswordBasedMAC" -#define LN_id_PasswordBasedMAC "password based MAC" -#define NID_id_PasswordBasedMAC 782 -#define OBJ_id_PasswordBasedMAC OBJ_ISO_US,113533L,7L,66L,13L - -#define SN_id_DHBasedMac "id-DHBasedMac" -#define LN_id_DHBasedMac "Diffie-Hellman based MAC" -#define NID_id_DHBasedMac 783 -#define OBJ_id_DHBasedMac OBJ_ISO_US,113533L,7L,66L,30L - -#define SN_rsadsi "rsadsi" -#define LN_rsadsi "RSA Data Security, Inc." -#define NID_rsadsi 1 -#define OBJ_rsadsi OBJ_ISO_US,113549L - -#define SN_pkcs "pkcs" -#define LN_pkcs "RSA Data Security, Inc. PKCS" -#define NID_pkcs 2 -#define OBJ_pkcs OBJ_rsadsi,1L - -#define SN_pkcs1 "pkcs1" -#define NID_pkcs1 186 -#define OBJ_pkcs1 OBJ_pkcs,1L - -#define LN_rsaEncryption "rsaEncryption" -#define NID_rsaEncryption 6 -#define OBJ_rsaEncryption OBJ_pkcs1,1L - -#define SN_md2WithRSAEncryption "RSA-MD2" -#define LN_md2WithRSAEncryption "md2WithRSAEncryption" -#define NID_md2WithRSAEncryption 7 -#define OBJ_md2WithRSAEncryption OBJ_pkcs1,2L - -#define SN_md4WithRSAEncryption "RSA-MD4" -#define LN_md4WithRSAEncryption "md4WithRSAEncryption" -#define NID_md4WithRSAEncryption 396 -#define OBJ_md4WithRSAEncryption OBJ_pkcs1,3L - -#define SN_md5WithRSAEncryption "RSA-MD5" -#define LN_md5WithRSAEncryption "md5WithRSAEncryption" -#define NID_md5WithRSAEncryption 8 -#define OBJ_md5WithRSAEncryption OBJ_pkcs1,4L - -#define SN_sha1WithRSAEncryption "RSA-SHA1" -#define LN_sha1WithRSAEncryption "sha1WithRSAEncryption" -#define NID_sha1WithRSAEncryption 65 -#define OBJ_sha1WithRSAEncryption OBJ_pkcs1,5L - -#define SN_rsaesOaep "RSAES-OAEP" -#define LN_rsaesOaep "rsaesOaep" -#define NID_rsaesOaep 919 -#define OBJ_rsaesOaep OBJ_pkcs1,7L - -#define SN_mgf1 "MGF1" -#define LN_mgf1 "mgf1" -#define NID_mgf1 911 -#define OBJ_mgf1 OBJ_pkcs1,8L - -#define SN_pSpecified "PSPECIFIED" -#define LN_pSpecified "pSpecified" -#define NID_pSpecified 935 -#define OBJ_pSpecified OBJ_pkcs1,9L - -#define SN_rsassaPss "RSASSA-PSS" -#define LN_rsassaPss "rsassaPss" -#define NID_rsassaPss 912 -#define OBJ_rsassaPss OBJ_pkcs1,10L - -#define SN_sha256WithRSAEncryption "RSA-SHA256" -#define LN_sha256WithRSAEncryption "sha256WithRSAEncryption" -#define NID_sha256WithRSAEncryption 668 -#define OBJ_sha256WithRSAEncryption OBJ_pkcs1,11L - -#define SN_sha384WithRSAEncryption "RSA-SHA384" -#define LN_sha384WithRSAEncryption "sha384WithRSAEncryption" -#define NID_sha384WithRSAEncryption 669 -#define OBJ_sha384WithRSAEncryption OBJ_pkcs1,12L - -#define SN_sha512WithRSAEncryption "RSA-SHA512" -#define LN_sha512WithRSAEncryption "sha512WithRSAEncryption" -#define NID_sha512WithRSAEncryption 670 -#define OBJ_sha512WithRSAEncryption OBJ_pkcs1,13L - -#define SN_sha224WithRSAEncryption "RSA-SHA224" -#define LN_sha224WithRSAEncryption "sha224WithRSAEncryption" -#define NID_sha224WithRSAEncryption 671 -#define OBJ_sha224WithRSAEncryption OBJ_pkcs1,14L - -#define SN_pkcs3 "pkcs3" -#define NID_pkcs3 27 -#define OBJ_pkcs3 OBJ_pkcs,3L - -#define LN_dhKeyAgreement "dhKeyAgreement" -#define NID_dhKeyAgreement 28 -#define OBJ_dhKeyAgreement OBJ_pkcs3,1L - -#define SN_pkcs5 "pkcs5" -#define NID_pkcs5 187 -#define OBJ_pkcs5 OBJ_pkcs,5L - -#define SN_pbeWithMD2AndDES_CBC "PBE-MD2-DES" -#define LN_pbeWithMD2AndDES_CBC "pbeWithMD2AndDES-CBC" -#define NID_pbeWithMD2AndDES_CBC 9 -#define OBJ_pbeWithMD2AndDES_CBC OBJ_pkcs5,1L - -#define SN_pbeWithMD5AndDES_CBC "PBE-MD5-DES" -#define LN_pbeWithMD5AndDES_CBC "pbeWithMD5AndDES-CBC" -#define NID_pbeWithMD5AndDES_CBC 10 -#define OBJ_pbeWithMD5AndDES_CBC OBJ_pkcs5,3L - -#define SN_pbeWithMD2AndRC2_CBC "PBE-MD2-RC2-64" -#define LN_pbeWithMD2AndRC2_CBC "pbeWithMD2AndRC2-CBC" -#define NID_pbeWithMD2AndRC2_CBC 168 -#define OBJ_pbeWithMD2AndRC2_CBC OBJ_pkcs5,4L - -#define SN_pbeWithMD5AndRC2_CBC "PBE-MD5-RC2-64" -#define LN_pbeWithMD5AndRC2_CBC "pbeWithMD5AndRC2-CBC" -#define NID_pbeWithMD5AndRC2_CBC 169 -#define OBJ_pbeWithMD5AndRC2_CBC OBJ_pkcs5,6L - -#define SN_pbeWithSHA1AndDES_CBC "PBE-SHA1-DES" -#define LN_pbeWithSHA1AndDES_CBC "pbeWithSHA1AndDES-CBC" -#define NID_pbeWithSHA1AndDES_CBC 170 -#define OBJ_pbeWithSHA1AndDES_CBC OBJ_pkcs5,10L - -#define SN_pbeWithSHA1AndRC2_CBC "PBE-SHA1-RC2-64" -#define LN_pbeWithSHA1AndRC2_CBC "pbeWithSHA1AndRC2-CBC" -#define NID_pbeWithSHA1AndRC2_CBC 68 -#define OBJ_pbeWithSHA1AndRC2_CBC OBJ_pkcs5,11L - -#define LN_id_pbkdf2 "PBKDF2" -#define NID_id_pbkdf2 69 -#define OBJ_id_pbkdf2 OBJ_pkcs5,12L - -#define LN_pbes2 "PBES2" -#define NID_pbes2 161 -#define OBJ_pbes2 OBJ_pkcs5,13L - -#define LN_pbmac1 "PBMAC1" -#define NID_pbmac1 162 -#define OBJ_pbmac1 OBJ_pkcs5,14L - -#define SN_pkcs7 "pkcs7" -#define NID_pkcs7 20 -#define OBJ_pkcs7 OBJ_pkcs,7L - -#define LN_pkcs7_data "pkcs7-data" -#define NID_pkcs7_data 21 -#define OBJ_pkcs7_data OBJ_pkcs7,1L - -#define LN_pkcs7_signed "pkcs7-signedData" -#define NID_pkcs7_signed 22 -#define OBJ_pkcs7_signed OBJ_pkcs7,2L - -#define LN_pkcs7_enveloped "pkcs7-envelopedData" -#define NID_pkcs7_enveloped 23 -#define OBJ_pkcs7_enveloped OBJ_pkcs7,3L - -#define LN_pkcs7_signedAndEnveloped "pkcs7-signedAndEnvelopedData" -#define NID_pkcs7_signedAndEnveloped 24 -#define OBJ_pkcs7_signedAndEnveloped OBJ_pkcs7,4L - -#define LN_pkcs7_digest "pkcs7-digestData" -#define NID_pkcs7_digest 25 -#define OBJ_pkcs7_digest OBJ_pkcs7,5L - -#define LN_pkcs7_encrypted "pkcs7-encryptedData" -#define NID_pkcs7_encrypted 26 -#define OBJ_pkcs7_encrypted OBJ_pkcs7,6L - -#define SN_pkcs9 "pkcs9" -#define NID_pkcs9 47 -#define OBJ_pkcs9 OBJ_pkcs,9L - -#define LN_pkcs9_emailAddress "emailAddress" -#define NID_pkcs9_emailAddress 48 -#define OBJ_pkcs9_emailAddress OBJ_pkcs9,1L - -#define LN_pkcs9_unstructuredName "unstructuredName" -#define NID_pkcs9_unstructuredName 49 -#define OBJ_pkcs9_unstructuredName OBJ_pkcs9,2L - -#define LN_pkcs9_contentType "contentType" -#define NID_pkcs9_contentType 50 -#define OBJ_pkcs9_contentType OBJ_pkcs9,3L - -#define LN_pkcs9_messageDigest "messageDigest" -#define NID_pkcs9_messageDigest 51 -#define OBJ_pkcs9_messageDigest OBJ_pkcs9,4L - -#define LN_pkcs9_signingTime "signingTime" -#define NID_pkcs9_signingTime 52 -#define OBJ_pkcs9_signingTime OBJ_pkcs9,5L - -#define LN_pkcs9_countersignature "countersignature" -#define NID_pkcs9_countersignature 53 -#define OBJ_pkcs9_countersignature OBJ_pkcs9,6L - -#define LN_pkcs9_challengePassword "challengePassword" -#define NID_pkcs9_challengePassword 54 -#define OBJ_pkcs9_challengePassword OBJ_pkcs9,7L - -#define LN_pkcs9_unstructuredAddress "unstructuredAddress" -#define NID_pkcs9_unstructuredAddress 55 -#define OBJ_pkcs9_unstructuredAddress OBJ_pkcs9,8L - -#define LN_pkcs9_extCertAttributes "extendedCertificateAttributes" -#define NID_pkcs9_extCertAttributes 56 -#define OBJ_pkcs9_extCertAttributes OBJ_pkcs9,9L - -#define SN_ext_req "extReq" -#define LN_ext_req "Extension Request" -#define NID_ext_req 172 -#define OBJ_ext_req OBJ_pkcs9,14L - -#define SN_SMIMECapabilities "SMIME-CAPS" -#define LN_SMIMECapabilities "S/MIME Capabilities" -#define NID_SMIMECapabilities 167 -#define OBJ_SMIMECapabilities OBJ_pkcs9,15L - -#define SN_SMIME "SMIME" -#define LN_SMIME "S/MIME" -#define NID_SMIME 188 -#define OBJ_SMIME OBJ_pkcs9,16L - -#define SN_id_smime_mod "id-smime-mod" -#define NID_id_smime_mod 189 -#define OBJ_id_smime_mod OBJ_SMIME,0L - -#define SN_id_smime_ct "id-smime-ct" -#define NID_id_smime_ct 190 -#define OBJ_id_smime_ct OBJ_SMIME,1L - -#define SN_id_smime_aa "id-smime-aa" -#define NID_id_smime_aa 191 -#define OBJ_id_smime_aa OBJ_SMIME,2L - -#define SN_id_smime_alg "id-smime-alg" -#define NID_id_smime_alg 192 -#define OBJ_id_smime_alg OBJ_SMIME,3L - -#define SN_id_smime_cd "id-smime-cd" -#define NID_id_smime_cd 193 -#define OBJ_id_smime_cd OBJ_SMIME,4L - -#define SN_id_smime_spq "id-smime-spq" -#define NID_id_smime_spq 194 -#define OBJ_id_smime_spq OBJ_SMIME,5L - -#define SN_id_smime_cti "id-smime-cti" -#define NID_id_smime_cti 195 -#define OBJ_id_smime_cti OBJ_SMIME,6L - -#define SN_id_smime_mod_cms "id-smime-mod-cms" -#define NID_id_smime_mod_cms 196 -#define OBJ_id_smime_mod_cms OBJ_id_smime_mod,1L - -#define SN_id_smime_mod_ess "id-smime-mod-ess" -#define NID_id_smime_mod_ess 197 -#define OBJ_id_smime_mod_ess OBJ_id_smime_mod,2L - -#define SN_id_smime_mod_oid "id-smime-mod-oid" -#define NID_id_smime_mod_oid 198 -#define OBJ_id_smime_mod_oid OBJ_id_smime_mod,3L - -#define SN_id_smime_mod_msg_v3 "id-smime-mod-msg-v3" -#define NID_id_smime_mod_msg_v3 199 -#define OBJ_id_smime_mod_msg_v3 OBJ_id_smime_mod,4L - -#define SN_id_smime_mod_ets_eSignature_88 "id-smime-mod-ets-eSignature-88" -#define NID_id_smime_mod_ets_eSignature_88 200 -#define OBJ_id_smime_mod_ets_eSignature_88 OBJ_id_smime_mod,5L - -#define SN_id_smime_mod_ets_eSignature_97 "id-smime-mod-ets-eSignature-97" -#define NID_id_smime_mod_ets_eSignature_97 201 -#define OBJ_id_smime_mod_ets_eSignature_97 OBJ_id_smime_mod,6L - -#define SN_id_smime_mod_ets_eSigPolicy_88 "id-smime-mod-ets-eSigPolicy-88" -#define NID_id_smime_mod_ets_eSigPolicy_88 202 -#define OBJ_id_smime_mod_ets_eSigPolicy_88 OBJ_id_smime_mod,7L - -#define SN_id_smime_mod_ets_eSigPolicy_97 "id-smime-mod-ets-eSigPolicy-97" -#define NID_id_smime_mod_ets_eSigPolicy_97 203 -#define OBJ_id_smime_mod_ets_eSigPolicy_97 OBJ_id_smime_mod,8L - -#define SN_id_smime_ct_receipt "id-smime-ct-receipt" -#define NID_id_smime_ct_receipt 204 -#define OBJ_id_smime_ct_receipt OBJ_id_smime_ct,1L - -#define SN_id_smime_ct_authData "id-smime-ct-authData" -#define NID_id_smime_ct_authData 205 -#define OBJ_id_smime_ct_authData OBJ_id_smime_ct,2L - -#define SN_id_smime_ct_publishCert "id-smime-ct-publishCert" -#define NID_id_smime_ct_publishCert 206 -#define OBJ_id_smime_ct_publishCert OBJ_id_smime_ct,3L - -#define SN_id_smime_ct_TSTInfo "id-smime-ct-TSTInfo" -#define NID_id_smime_ct_TSTInfo 207 -#define OBJ_id_smime_ct_TSTInfo OBJ_id_smime_ct,4L - -#define SN_id_smime_ct_TDTInfo "id-smime-ct-TDTInfo" -#define NID_id_smime_ct_TDTInfo 208 -#define OBJ_id_smime_ct_TDTInfo OBJ_id_smime_ct,5L - -#define SN_id_smime_ct_contentInfo "id-smime-ct-contentInfo" -#define NID_id_smime_ct_contentInfo 209 -#define OBJ_id_smime_ct_contentInfo OBJ_id_smime_ct,6L - -#define SN_id_smime_ct_DVCSRequestData "id-smime-ct-DVCSRequestData" -#define NID_id_smime_ct_DVCSRequestData 210 -#define OBJ_id_smime_ct_DVCSRequestData OBJ_id_smime_ct,7L - -#define SN_id_smime_ct_DVCSResponseData "id-smime-ct-DVCSResponseData" -#define NID_id_smime_ct_DVCSResponseData 211 -#define OBJ_id_smime_ct_DVCSResponseData OBJ_id_smime_ct,8L - -#define SN_id_smime_ct_compressedData "id-smime-ct-compressedData" -#define NID_id_smime_ct_compressedData 786 -#define OBJ_id_smime_ct_compressedData OBJ_id_smime_ct,9L - -#define SN_id_ct_asciiTextWithCRLF "id-ct-asciiTextWithCRLF" -#define NID_id_ct_asciiTextWithCRLF 787 -#define OBJ_id_ct_asciiTextWithCRLF OBJ_id_smime_ct,27L - -#define SN_id_smime_aa_receiptRequest "id-smime-aa-receiptRequest" -#define NID_id_smime_aa_receiptRequest 212 -#define OBJ_id_smime_aa_receiptRequest OBJ_id_smime_aa,1L - -#define SN_id_smime_aa_securityLabel "id-smime-aa-securityLabel" -#define NID_id_smime_aa_securityLabel 213 -#define OBJ_id_smime_aa_securityLabel OBJ_id_smime_aa,2L - -#define SN_id_smime_aa_mlExpandHistory "id-smime-aa-mlExpandHistory" -#define NID_id_smime_aa_mlExpandHistory 214 -#define OBJ_id_smime_aa_mlExpandHistory OBJ_id_smime_aa,3L - -#define SN_id_smime_aa_contentHint "id-smime-aa-contentHint" -#define NID_id_smime_aa_contentHint 215 -#define OBJ_id_smime_aa_contentHint OBJ_id_smime_aa,4L - -#define SN_id_smime_aa_msgSigDigest "id-smime-aa-msgSigDigest" -#define NID_id_smime_aa_msgSigDigest 216 -#define OBJ_id_smime_aa_msgSigDigest OBJ_id_smime_aa,5L - -#define SN_id_smime_aa_encapContentType "id-smime-aa-encapContentType" -#define NID_id_smime_aa_encapContentType 217 -#define OBJ_id_smime_aa_encapContentType OBJ_id_smime_aa,6L - -#define SN_id_smime_aa_contentIdentifier "id-smime-aa-contentIdentifier" -#define NID_id_smime_aa_contentIdentifier 218 -#define OBJ_id_smime_aa_contentIdentifier OBJ_id_smime_aa,7L - -#define SN_id_smime_aa_macValue "id-smime-aa-macValue" -#define NID_id_smime_aa_macValue 219 -#define OBJ_id_smime_aa_macValue OBJ_id_smime_aa,8L - -#define SN_id_smime_aa_equivalentLabels "id-smime-aa-equivalentLabels" -#define NID_id_smime_aa_equivalentLabels 220 -#define OBJ_id_smime_aa_equivalentLabels OBJ_id_smime_aa,9L - -#define SN_id_smime_aa_contentReference "id-smime-aa-contentReference" -#define NID_id_smime_aa_contentReference 221 -#define OBJ_id_smime_aa_contentReference OBJ_id_smime_aa,10L - -#define SN_id_smime_aa_encrypKeyPref "id-smime-aa-encrypKeyPref" -#define NID_id_smime_aa_encrypKeyPref 222 -#define OBJ_id_smime_aa_encrypKeyPref OBJ_id_smime_aa,11L - -#define SN_id_smime_aa_signingCertificate "id-smime-aa-signingCertificate" -#define NID_id_smime_aa_signingCertificate 223 -#define OBJ_id_smime_aa_signingCertificate OBJ_id_smime_aa,12L - -#define SN_id_smime_aa_smimeEncryptCerts "id-smime-aa-smimeEncryptCerts" -#define NID_id_smime_aa_smimeEncryptCerts 224 -#define OBJ_id_smime_aa_smimeEncryptCerts OBJ_id_smime_aa,13L - -#define SN_id_smime_aa_timeStampToken "id-smime-aa-timeStampToken" -#define NID_id_smime_aa_timeStampToken 225 -#define OBJ_id_smime_aa_timeStampToken OBJ_id_smime_aa,14L - -#define SN_id_smime_aa_ets_sigPolicyId "id-smime-aa-ets-sigPolicyId" -#define NID_id_smime_aa_ets_sigPolicyId 226 -#define OBJ_id_smime_aa_ets_sigPolicyId OBJ_id_smime_aa,15L - -#define SN_id_smime_aa_ets_commitmentType "id-smime-aa-ets-commitmentType" -#define NID_id_smime_aa_ets_commitmentType 227 -#define OBJ_id_smime_aa_ets_commitmentType OBJ_id_smime_aa,16L - -#define SN_id_smime_aa_ets_signerLocation "id-smime-aa-ets-signerLocation" -#define NID_id_smime_aa_ets_signerLocation 228 -#define OBJ_id_smime_aa_ets_signerLocation OBJ_id_smime_aa,17L - -#define SN_id_smime_aa_ets_signerAttr "id-smime-aa-ets-signerAttr" -#define NID_id_smime_aa_ets_signerAttr 229 -#define OBJ_id_smime_aa_ets_signerAttr OBJ_id_smime_aa,18L - -#define SN_id_smime_aa_ets_otherSigCert "id-smime-aa-ets-otherSigCert" -#define NID_id_smime_aa_ets_otherSigCert 230 -#define OBJ_id_smime_aa_ets_otherSigCert OBJ_id_smime_aa,19L - -#define SN_id_smime_aa_ets_contentTimestamp "id-smime-aa-ets-contentTimestamp" -#define NID_id_smime_aa_ets_contentTimestamp 231 -#define OBJ_id_smime_aa_ets_contentTimestamp OBJ_id_smime_aa,20L - -#define SN_id_smime_aa_ets_CertificateRefs "id-smime-aa-ets-CertificateRefs" -#define NID_id_smime_aa_ets_CertificateRefs 232 -#define OBJ_id_smime_aa_ets_CertificateRefs OBJ_id_smime_aa,21L - -#define SN_id_smime_aa_ets_RevocationRefs "id-smime-aa-ets-RevocationRefs" -#define NID_id_smime_aa_ets_RevocationRefs 233 -#define OBJ_id_smime_aa_ets_RevocationRefs OBJ_id_smime_aa,22L - -#define SN_id_smime_aa_ets_certValues "id-smime-aa-ets-certValues" -#define NID_id_smime_aa_ets_certValues 234 -#define OBJ_id_smime_aa_ets_certValues OBJ_id_smime_aa,23L - -#define SN_id_smime_aa_ets_revocationValues "id-smime-aa-ets-revocationValues" -#define NID_id_smime_aa_ets_revocationValues 235 -#define OBJ_id_smime_aa_ets_revocationValues OBJ_id_smime_aa,24L - -#define SN_id_smime_aa_ets_escTimeStamp "id-smime-aa-ets-escTimeStamp" -#define NID_id_smime_aa_ets_escTimeStamp 236 -#define OBJ_id_smime_aa_ets_escTimeStamp OBJ_id_smime_aa,25L - -#define SN_id_smime_aa_ets_certCRLTimestamp "id-smime-aa-ets-certCRLTimestamp" -#define NID_id_smime_aa_ets_certCRLTimestamp 237 -#define OBJ_id_smime_aa_ets_certCRLTimestamp OBJ_id_smime_aa,26L - -#define SN_id_smime_aa_ets_archiveTimeStamp "id-smime-aa-ets-archiveTimeStamp" -#define NID_id_smime_aa_ets_archiveTimeStamp 238 -#define OBJ_id_smime_aa_ets_archiveTimeStamp OBJ_id_smime_aa,27L - -#define SN_id_smime_aa_signatureType "id-smime-aa-signatureType" -#define NID_id_smime_aa_signatureType 239 -#define OBJ_id_smime_aa_signatureType OBJ_id_smime_aa,28L - -#define SN_id_smime_aa_dvcs_dvc "id-smime-aa-dvcs-dvc" -#define NID_id_smime_aa_dvcs_dvc 240 -#define OBJ_id_smime_aa_dvcs_dvc OBJ_id_smime_aa,29L - -#define SN_id_smime_alg_ESDHwith3DES "id-smime-alg-ESDHwith3DES" -#define NID_id_smime_alg_ESDHwith3DES 241 -#define OBJ_id_smime_alg_ESDHwith3DES OBJ_id_smime_alg,1L - -#define SN_id_smime_alg_ESDHwithRC2 "id-smime-alg-ESDHwithRC2" -#define NID_id_smime_alg_ESDHwithRC2 242 -#define OBJ_id_smime_alg_ESDHwithRC2 OBJ_id_smime_alg,2L - -#define SN_id_smime_alg_3DESwrap "id-smime-alg-3DESwrap" -#define NID_id_smime_alg_3DESwrap 243 -#define OBJ_id_smime_alg_3DESwrap OBJ_id_smime_alg,3L - -#define SN_id_smime_alg_RC2wrap "id-smime-alg-RC2wrap" -#define NID_id_smime_alg_RC2wrap 244 -#define OBJ_id_smime_alg_RC2wrap OBJ_id_smime_alg,4L - -#define SN_id_smime_alg_ESDH "id-smime-alg-ESDH" -#define NID_id_smime_alg_ESDH 245 -#define OBJ_id_smime_alg_ESDH OBJ_id_smime_alg,5L - -#define SN_id_smime_alg_CMS3DESwrap "id-smime-alg-CMS3DESwrap" -#define NID_id_smime_alg_CMS3DESwrap 246 -#define OBJ_id_smime_alg_CMS3DESwrap OBJ_id_smime_alg,6L - -#define SN_id_smime_alg_CMSRC2wrap "id-smime-alg-CMSRC2wrap" -#define NID_id_smime_alg_CMSRC2wrap 247 -#define OBJ_id_smime_alg_CMSRC2wrap OBJ_id_smime_alg,7L - -#define SN_id_alg_PWRI_KEK "id-alg-PWRI-KEK" -#define NID_id_alg_PWRI_KEK 893 -#define OBJ_id_alg_PWRI_KEK OBJ_id_smime_alg,9L - -#define SN_id_smime_cd_ldap "id-smime-cd-ldap" -#define NID_id_smime_cd_ldap 248 -#define OBJ_id_smime_cd_ldap OBJ_id_smime_cd,1L - -#define SN_id_smime_spq_ets_sqt_uri "id-smime-spq-ets-sqt-uri" -#define NID_id_smime_spq_ets_sqt_uri 249 -#define OBJ_id_smime_spq_ets_sqt_uri OBJ_id_smime_spq,1L - -#define SN_id_smime_spq_ets_sqt_unotice "id-smime-spq-ets-sqt-unotice" -#define NID_id_smime_spq_ets_sqt_unotice 250 -#define OBJ_id_smime_spq_ets_sqt_unotice OBJ_id_smime_spq,2L - -#define SN_id_smime_cti_ets_proofOfOrigin "id-smime-cti-ets-proofOfOrigin" -#define NID_id_smime_cti_ets_proofOfOrigin 251 -#define OBJ_id_smime_cti_ets_proofOfOrigin OBJ_id_smime_cti,1L - -#define SN_id_smime_cti_ets_proofOfReceipt "id-smime-cti-ets-proofOfReceipt" -#define NID_id_smime_cti_ets_proofOfReceipt 252 -#define OBJ_id_smime_cti_ets_proofOfReceipt OBJ_id_smime_cti,2L - -#define SN_id_smime_cti_ets_proofOfDelivery "id-smime-cti-ets-proofOfDelivery" -#define NID_id_smime_cti_ets_proofOfDelivery 253 -#define OBJ_id_smime_cti_ets_proofOfDelivery OBJ_id_smime_cti,3L - -#define SN_id_smime_cti_ets_proofOfSender "id-smime-cti-ets-proofOfSender" -#define NID_id_smime_cti_ets_proofOfSender 254 -#define OBJ_id_smime_cti_ets_proofOfSender OBJ_id_smime_cti,4L - -#define SN_id_smime_cti_ets_proofOfApproval "id-smime-cti-ets-proofOfApproval" -#define NID_id_smime_cti_ets_proofOfApproval 255 -#define OBJ_id_smime_cti_ets_proofOfApproval OBJ_id_smime_cti,5L - -#define SN_id_smime_cti_ets_proofOfCreation "id-smime-cti-ets-proofOfCreation" -#define NID_id_smime_cti_ets_proofOfCreation 256 -#define OBJ_id_smime_cti_ets_proofOfCreation OBJ_id_smime_cti,6L - -#define LN_friendlyName "friendlyName" -#define NID_friendlyName 156 -#define OBJ_friendlyName OBJ_pkcs9,20L - -#define LN_localKeyID "localKeyID" -#define NID_localKeyID 157 -#define OBJ_localKeyID OBJ_pkcs9,21L - -#define SN_ms_csp_name "CSPName" -#define LN_ms_csp_name "Microsoft CSP Name" -#define NID_ms_csp_name 417 -#define OBJ_ms_csp_name 1L,3L,6L,1L,4L,1L,311L,17L,1L - -#define SN_LocalKeySet "LocalKeySet" -#define LN_LocalKeySet "Microsoft Local Key set" -#define NID_LocalKeySet 856 -#define OBJ_LocalKeySet 1L,3L,6L,1L,4L,1L,311L,17L,2L - -#define OBJ_certTypes OBJ_pkcs9,22L - -#define LN_x509Certificate "x509Certificate" -#define NID_x509Certificate 158 -#define OBJ_x509Certificate OBJ_certTypes,1L - -#define LN_sdsiCertificate "sdsiCertificate" -#define NID_sdsiCertificate 159 -#define OBJ_sdsiCertificate OBJ_certTypes,2L - -#define OBJ_crlTypes OBJ_pkcs9,23L - -#define LN_x509Crl "x509Crl" -#define NID_x509Crl 160 -#define OBJ_x509Crl OBJ_crlTypes,1L - -#define OBJ_pkcs12 OBJ_pkcs,12L - -#define OBJ_pkcs12_pbeids OBJ_pkcs12,1L - -#define SN_pbe_WithSHA1And128BitRC4 "PBE-SHA1-RC4-128" -#define LN_pbe_WithSHA1And128BitRC4 "pbeWithSHA1And128BitRC4" -#define NID_pbe_WithSHA1And128BitRC4 144 -#define OBJ_pbe_WithSHA1And128BitRC4 OBJ_pkcs12_pbeids,1L - -#define SN_pbe_WithSHA1And40BitRC4 "PBE-SHA1-RC4-40" -#define LN_pbe_WithSHA1And40BitRC4 "pbeWithSHA1And40BitRC4" -#define NID_pbe_WithSHA1And40BitRC4 145 -#define OBJ_pbe_WithSHA1And40BitRC4 OBJ_pkcs12_pbeids,2L - -#define SN_pbe_WithSHA1And3_Key_TripleDES_CBC "PBE-SHA1-3DES" -#define LN_pbe_WithSHA1And3_Key_TripleDES_CBC "pbeWithSHA1And3-KeyTripleDES-CBC" -#define NID_pbe_WithSHA1And3_Key_TripleDES_CBC 146 -#define OBJ_pbe_WithSHA1And3_Key_TripleDES_CBC OBJ_pkcs12_pbeids,3L - -#define SN_pbe_WithSHA1And2_Key_TripleDES_CBC "PBE-SHA1-2DES" -#define LN_pbe_WithSHA1And2_Key_TripleDES_CBC "pbeWithSHA1And2-KeyTripleDES-CBC" -#define NID_pbe_WithSHA1And2_Key_TripleDES_CBC 147 -#define OBJ_pbe_WithSHA1And2_Key_TripleDES_CBC OBJ_pkcs12_pbeids,4L - -#define SN_pbe_WithSHA1And128BitRC2_CBC "PBE-SHA1-RC2-128" -#define LN_pbe_WithSHA1And128BitRC2_CBC "pbeWithSHA1And128BitRC2-CBC" -#define NID_pbe_WithSHA1And128BitRC2_CBC 148 -#define OBJ_pbe_WithSHA1And128BitRC2_CBC OBJ_pkcs12_pbeids,5L - -#define SN_pbe_WithSHA1And40BitRC2_CBC "PBE-SHA1-RC2-40" -#define LN_pbe_WithSHA1And40BitRC2_CBC "pbeWithSHA1And40BitRC2-CBC" -#define NID_pbe_WithSHA1And40BitRC2_CBC 149 -#define OBJ_pbe_WithSHA1And40BitRC2_CBC OBJ_pkcs12_pbeids,6L - -#define OBJ_pkcs12_Version1 OBJ_pkcs12,10L - -#define OBJ_pkcs12_BagIds OBJ_pkcs12_Version1,1L - -#define LN_keyBag "keyBag" -#define NID_keyBag 150 -#define OBJ_keyBag OBJ_pkcs12_BagIds,1L - -#define LN_pkcs8ShroudedKeyBag "pkcs8ShroudedKeyBag" -#define NID_pkcs8ShroudedKeyBag 151 -#define OBJ_pkcs8ShroudedKeyBag OBJ_pkcs12_BagIds,2L - -#define LN_certBag "certBag" -#define NID_certBag 152 -#define OBJ_certBag OBJ_pkcs12_BagIds,3L - -#define LN_crlBag "crlBag" -#define NID_crlBag 153 -#define OBJ_crlBag OBJ_pkcs12_BagIds,4L - -#define LN_secretBag "secretBag" -#define NID_secretBag 154 -#define OBJ_secretBag OBJ_pkcs12_BagIds,5L - -#define LN_safeContentsBag "safeContentsBag" -#define NID_safeContentsBag 155 -#define OBJ_safeContentsBag OBJ_pkcs12_BagIds,6L - -#define SN_md2 "MD2" -#define LN_md2 "md2" -#define NID_md2 3 -#define OBJ_md2 OBJ_rsadsi,2L,2L - -#define SN_md4 "MD4" -#define LN_md4 "md4" -#define NID_md4 257 -#define OBJ_md4 OBJ_rsadsi,2L,4L - -#define SN_md5 "MD5" -#define LN_md5 "md5" -#define NID_md5 4 -#define OBJ_md5 OBJ_rsadsi,2L,5L - -#define SN_md5_sha1 "MD5-SHA1" -#define LN_md5_sha1 "md5-sha1" -#define NID_md5_sha1 114 - -#define LN_hmacWithMD5 "hmacWithMD5" -#define NID_hmacWithMD5 797 -#define OBJ_hmacWithMD5 OBJ_rsadsi,2L,6L - -#define LN_hmacWithSHA1 "hmacWithSHA1" -#define NID_hmacWithSHA1 163 -#define OBJ_hmacWithSHA1 OBJ_rsadsi,2L,7L - -#define LN_hmacWithSHA224 "hmacWithSHA224" -#define NID_hmacWithSHA224 798 -#define OBJ_hmacWithSHA224 OBJ_rsadsi,2L,8L - -#define LN_hmacWithSHA256 "hmacWithSHA256" -#define NID_hmacWithSHA256 799 -#define OBJ_hmacWithSHA256 OBJ_rsadsi,2L,9L - -#define LN_hmacWithSHA384 "hmacWithSHA384" -#define NID_hmacWithSHA384 800 -#define OBJ_hmacWithSHA384 OBJ_rsadsi,2L,10L - -#define LN_hmacWithSHA512 "hmacWithSHA512" -#define NID_hmacWithSHA512 801 -#define OBJ_hmacWithSHA512 OBJ_rsadsi,2L,11L - -#define SN_rc2_cbc "RC2-CBC" -#define LN_rc2_cbc "rc2-cbc" -#define NID_rc2_cbc 37 -#define OBJ_rc2_cbc OBJ_rsadsi,3L,2L - -#define SN_rc2_ecb "RC2-ECB" -#define LN_rc2_ecb "rc2-ecb" -#define NID_rc2_ecb 38 - -#define SN_rc2_cfb64 "RC2-CFB" -#define LN_rc2_cfb64 "rc2-cfb" -#define NID_rc2_cfb64 39 - -#define SN_rc2_ofb64 "RC2-OFB" -#define LN_rc2_ofb64 "rc2-ofb" -#define NID_rc2_ofb64 40 - -#define SN_rc2_40_cbc "RC2-40-CBC" -#define LN_rc2_40_cbc "rc2-40-cbc" -#define NID_rc2_40_cbc 98 - -#define SN_rc2_64_cbc "RC2-64-CBC" -#define LN_rc2_64_cbc "rc2-64-cbc" -#define NID_rc2_64_cbc 166 - -#define SN_rc4 "RC4" -#define LN_rc4 "rc4" -#define NID_rc4 5 -#define OBJ_rc4 OBJ_rsadsi,3L,4L - -#define SN_rc4_40 "RC4-40" -#define LN_rc4_40 "rc4-40" -#define NID_rc4_40 97 - -#define SN_des_ede3_cbc "DES-EDE3-CBC" -#define LN_des_ede3_cbc "des-ede3-cbc" -#define NID_des_ede3_cbc 44 -#define OBJ_des_ede3_cbc OBJ_rsadsi,3L,7L - -#define SN_rc5_cbc "RC5-CBC" -#define LN_rc5_cbc "rc5-cbc" -#define NID_rc5_cbc 120 -#define OBJ_rc5_cbc OBJ_rsadsi,3L,8L - -#define SN_rc5_ecb "RC5-ECB" -#define LN_rc5_ecb "rc5-ecb" -#define NID_rc5_ecb 121 - -#define SN_rc5_cfb64 "RC5-CFB" -#define LN_rc5_cfb64 "rc5-cfb" -#define NID_rc5_cfb64 122 - -#define SN_rc5_ofb64 "RC5-OFB" -#define LN_rc5_ofb64 "rc5-ofb" -#define NID_rc5_ofb64 123 - -#define SN_ms_ext_req "msExtReq" -#define LN_ms_ext_req "Microsoft Extension Request" -#define NID_ms_ext_req 171 -#define OBJ_ms_ext_req 1L,3L,6L,1L,4L,1L,311L,2L,1L,14L - -#define SN_ms_code_ind "msCodeInd" -#define LN_ms_code_ind "Microsoft Individual Code Signing" -#define NID_ms_code_ind 134 -#define OBJ_ms_code_ind 1L,3L,6L,1L,4L,1L,311L,2L,1L,21L - -#define SN_ms_code_com "msCodeCom" -#define LN_ms_code_com "Microsoft Commercial Code Signing" -#define NID_ms_code_com 135 -#define OBJ_ms_code_com 1L,3L,6L,1L,4L,1L,311L,2L,1L,22L - -#define SN_ms_ctl_sign "msCTLSign" -#define LN_ms_ctl_sign "Microsoft Trust List Signing" -#define NID_ms_ctl_sign 136 -#define OBJ_ms_ctl_sign 1L,3L,6L,1L,4L,1L,311L,10L,3L,1L - -#define SN_ms_sgc "msSGC" -#define LN_ms_sgc "Microsoft Server Gated Crypto" -#define NID_ms_sgc 137 -#define OBJ_ms_sgc 1L,3L,6L,1L,4L,1L,311L,10L,3L,3L - -#define SN_ms_efs "msEFS" -#define LN_ms_efs "Microsoft Encrypted File System" -#define NID_ms_efs 138 -#define OBJ_ms_efs 1L,3L,6L,1L,4L,1L,311L,10L,3L,4L - -#define SN_ms_smartcard_login "msSmartcardLogin" -#define LN_ms_smartcard_login "Microsoft Smartcardlogin" -#define NID_ms_smartcard_login 648 -#define OBJ_ms_smartcard_login 1L,3L,6L,1L,4L,1L,311L,20L,2L,2L - -#define SN_ms_upn "msUPN" -#define LN_ms_upn "Microsoft Universal Principal Name" -#define NID_ms_upn 649 -#define OBJ_ms_upn 1L,3L,6L,1L,4L,1L,311L,20L,2L,3L - -#define SN_idea_cbc "IDEA-CBC" -#define LN_idea_cbc "idea-cbc" -#define NID_idea_cbc 34 -#define OBJ_idea_cbc 1L,3L,6L,1L,4L,1L,188L,7L,1L,1L,2L - -#define SN_idea_ecb "IDEA-ECB" -#define LN_idea_ecb "idea-ecb" -#define NID_idea_ecb 36 - -#define SN_idea_cfb64 "IDEA-CFB" -#define LN_idea_cfb64 "idea-cfb" -#define NID_idea_cfb64 35 - -#define SN_idea_ofb64 "IDEA-OFB" -#define LN_idea_ofb64 "idea-ofb" -#define NID_idea_ofb64 46 - -#define SN_bf_cbc "BF-CBC" -#define LN_bf_cbc "bf-cbc" -#define NID_bf_cbc 91 -#define OBJ_bf_cbc 1L,3L,6L,1L,4L,1L,3029L,1L,2L - -#define SN_bf_ecb "BF-ECB" -#define LN_bf_ecb "bf-ecb" -#define NID_bf_ecb 92 - -#define SN_bf_cfb64 "BF-CFB" -#define LN_bf_cfb64 "bf-cfb" -#define NID_bf_cfb64 93 - -#define SN_bf_ofb64 "BF-OFB" -#define LN_bf_ofb64 "bf-ofb" -#define NID_bf_ofb64 94 - -#define SN_id_pkix "PKIX" -#define NID_id_pkix 127 -#define OBJ_id_pkix 1L,3L,6L,1L,5L,5L,7L - -#define SN_id_pkix_mod "id-pkix-mod" -#define NID_id_pkix_mod 258 -#define OBJ_id_pkix_mod OBJ_id_pkix,0L - -#define SN_id_pe "id-pe" -#define NID_id_pe 175 -#define OBJ_id_pe OBJ_id_pkix,1L - -#define SN_id_qt "id-qt" -#define NID_id_qt 259 -#define OBJ_id_qt OBJ_id_pkix,2L - -#define SN_id_kp "id-kp" -#define NID_id_kp 128 -#define OBJ_id_kp OBJ_id_pkix,3L - -#define SN_id_it "id-it" -#define NID_id_it 260 -#define OBJ_id_it OBJ_id_pkix,4L - -#define SN_id_pkip "id-pkip" -#define NID_id_pkip 261 -#define OBJ_id_pkip OBJ_id_pkix,5L - -#define SN_id_alg "id-alg" -#define NID_id_alg 262 -#define OBJ_id_alg OBJ_id_pkix,6L - -#define SN_id_cmc "id-cmc" -#define NID_id_cmc 263 -#define OBJ_id_cmc OBJ_id_pkix,7L - -#define SN_id_on "id-on" -#define NID_id_on 264 -#define OBJ_id_on OBJ_id_pkix,8L - -#define SN_id_pda "id-pda" -#define NID_id_pda 265 -#define OBJ_id_pda OBJ_id_pkix,9L - -#define SN_id_aca "id-aca" -#define NID_id_aca 266 -#define OBJ_id_aca OBJ_id_pkix,10L - -#define SN_id_qcs "id-qcs" -#define NID_id_qcs 267 -#define OBJ_id_qcs OBJ_id_pkix,11L - -#define SN_id_cct "id-cct" -#define NID_id_cct 268 -#define OBJ_id_cct OBJ_id_pkix,12L - -#define SN_id_ppl "id-ppl" -#define NID_id_ppl 662 -#define OBJ_id_ppl OBJ_id_pkix,21L - -#define SN_id_ad "id-ad" -#define NID_id_ad 176 -#define OBJ_id_ad OBJ_id_pkix,48L - -#define SN_id_pkix1_explicit_88 "id-pkix1-explicit-88" -#define NID_id_pkix1_explicit_88 269 -#define OBJ_id_pkix1_explicit_88 OBJ_id_pkix_mod,1L - -#define SN_id_pkix1_implicit_88 "id-pkix1-implicit-88" -#define NID_id_pkix1_implicit_88 270 -#define OBJ_id_pkix1_implicit_88 OBJ_id_pkix_mod,2L - -#define SN_id_pkix1_explicit_93 "id-pkix1-explicit-93" -#define NID_id_pkix1_explicit_93 271 -#define OBJ_id_pkix1_explicit_93 OBJ_id_pkix_mod,3L - -#define SN_id_pkix1_implicit_93 "id-pkix1-implicit-93" -#define NID_id_pkix1_implicit_93 272 -#define OBJ_id_pkix1_implicit_93 OBJ_id_pkix_mod,4L - -#define SN_id_mod_crmf "id-mod-crmf" -#define NID_id_mod_crmf 273 -#define OBJ_id_mod_crmf OBJ_id_pkix_mod,5L - -#define SN_id_mod_cmc "id-mod-cmc" -#define NID_id_mod_cmc 274 -#define OBJ_id_mod_cmc OBJ_id_pkix_mod,6L - -#define SN_id_mod_kea_profile_88 "id-mod-kea-profile-88" -#define NID_id_mod_kea_profile_88 275 -#define OBJ_id_mod_kea_profile_88 OBJ_id_pkix_mod,7L - -#define SN_id_mod_kea_profile_93 "id-mod-kea-profile-93" -#define NID_id_mod_kea_profile_93 276 -#define OBJ_id_mod_kea_profile_93 OBJ_id_pkix_mod,8L - -#define SN_id_mod_cmp "id-mod-cmp" -#define NID_id_mod_cmp 277 -#define OBJ_id_mod_cmp OBJ_id_pkix_mod,9L - -#define SN_id_mod_qualified_cert_88 "id-mod-qualified-cert-88" -#define NID_id_mod_qualified_cert_88 278 -#define OBJ_id_mod_qualified_cert_88 OBJ_id_pkix_mod,10L - -#define SN_id_mod_qualified_cert_93 "id-mod-qualified-cert-93" -#define NID_id_mod_qualified_cert_93 279 -#define OBJ_id_mod_qualified_cert_93 OBJ_id_pkix_mod,11L - -#define SN_id_mod_attribute_cert "id-mod-attribute-cert" -#define NID_id_mod_attribute_cert 280 -#define OBJ_id_mod_attribute_cert OBJ_id_pkix_mod,12L - -#define SN_id_mod_timestamp_protocol "id-mod-timestamp-protocol" -#define NID_id_mod_timestamp_protocol 281 -#define OBJ_id_mod_timestamp_protocol OBJ_id_pkix_mod,13L - -#define SN_id_mod_ocsp "id-mod-ocsp" -#define NID_id_mod_ocsp 282 -#define OBJ_id_mod_ocsp OBJ_id_pkix_mod,14L - -#define SN_id_mod_dvcs "id-mod-dvcs" -#define NID_id_mod_dvcs 283 -#define OBJ_id_mod_dvcs OBJ_id_pkix_mod,15L - -#define SN_id_mod_cmp2000 "id-mod-cmp2000" -#define NID_id_mod_cmp2000 284 -#define OBJ_id_mod_cmp2000 OBJ_id_pkix_mod,16L - -#define SN_info_access "authorityInfoAccess" -#define LN_info_access "Authority Information Access" -#define NID_info_access 177 -#define OBJ_info_access OBJ_id_pe,1L - -#define SN_biometricInfo "biometricInfo" -#define LN_biometricInfo "Biometric Info" -#define NID_biometricInfo 285 -#define OBJ_biometricInfo OBJ_id_pe,2L - -#define SN_qcStatements "qcStatements" -#define NID_qcStatements 286 -#define OBJ_qcStatements OBJ_id_pe,3L - -#define SN_ac_auditEntity "ac-auditEntity" -#define NID_ac_auditEntity 287 -#define OBJ_ac_auditEntity OBJ_id_pe,4L - -#define SN_ac_targeting "ac-targeting" -#define NID_ac_targeting 288 -#define OBJ_ac_targeting OBJ_id_pe,5L - -#define SN_aaControls "aaControls" -#define NID_aaControls 289 -#define OBJ_aaControls OBJ_id_pe,6L - -#define SN_sbgp_ipAddrBlock "sbgp-ipAddrBlock" -#define NID_sbgp_ipAddrBlock 290 -#define OBJ_sbgp_ipAddrBlock OBJ_id_pe,7L - -#define SN_sbgp_autonomousSysNum "sbgp-autonomousSysNum" -#define NID_sbgp_autonomousSysNum 291 -#define OBJ_sbgp_autonomousSysNum OBJ_id_pe,8L - -#define SN_sbgp_routerIdentifier "sbgp-routerIdentifier" -#define NID_sbgp_routerIdentifier 292 -#define OBJ_sbgp_routerIdentifier OBJ_id_pe,9L - -#define SN_ac_proxying "ac-proxying" -#define NID_ac_proxying 397 -#define OBJ_ac_proxying OBJ_id_pe,10L - -#define SN_sinfo_access "subjectInfoAccess" -#define LN_sinfo_access "Subject Information Access" -#define NID_sinfo_access 398 -#define OBJ_sinfo_access OBJ_id_pe,11L - -#define SN_proxyCertInfo "proxyCertInfo" -#define LN_proxyCertInfo "Proxy Certificate Information" -#define NID_proxyCertInfo 663 -#define OBJ_proxyCertInfo OBJ_id_pe,14L - -#define SN_id_qt_cps "id-qt-cps" -#define LN_id_qt_cps "Policy Qualifier CPS" -#define NID_id_qt_cps 164 -#define OBJ_id_qt_cps OBJ_id_qt,1L - -#define SN_id_qt_unotice "id-qt-unotice" -#define LN_id_qt_unotice "Policy Qualifier User Notice" -#define NID_id_qt_unotice 165 -#define OBJ_id_qt_unotice OBJ_id_qt,2L - -#define SN_textNotice "textNotice" -#define NID_textNotice 293 -#define OBJ_textNotice OBJ_id_qt,3L - -#define SN_server_auth "serverAuth" -#define LN_server_auth "TLS Web Server Authentication" -#define NID_server_auth 129 -#define OBJ_server_auth OBJ_id_kp,1L - -#define SN_client_auth "clientAuth" -#define LN_client_auth "TLS Web Client Authentication" -#define NID_client_auth 130 -#define OBJ_client_auth OBJ_id_kp,2L - -#define SN_code_sign "codeSigning" -#define LN_code_sign "Code Signing" -#define NID_code_sign 131 -#define OBJ_code_sign OBJ_id_kp,3L - -#define SN_email_protect "emailProtection" -#define LN_email_protect "E-mail Protection" -#define NID_email_protect 132 -#define OBJ_email_protect OBJ_id_kp,4L - -#define SN_ipsecEndSystem "ipsecEndSystem" -#define LN_ipsecEndSystem "IPSec End System" -#define NID_ipsecEndSystem 294 -#define OBJ_ipsecEndSystem OBJ_id_kp,5L - -#define SN_ipsecTunnel "ipsecTunnel" -#define LN_ipsecTunnel "IPSec Tunnel" -#define NID_ipsecTunnel 295 -#define OBJ_ipsecTunnel OBJ_id_kp,6L - -#define SN_ipsecUser "ipsecUser" -#define LN_ipsecUser "IPSec User" -#define NID_ipsecUser 296 -#define OBJ_ipsecUser OBJ_id_kp,7L - -#define SN_time_stamp "timeStamping" -#define LN_time_stamp "Time Stamping" -#define NID_time_stamp 133 -#define OBJ_time_stamp OBJ_id_kp,8L - -#define SN_OCSP_sign "OCSPSigning" -#define LN_OCSP_sign "OCSP Signing" -#define NID_OCSP_sign 180 -#define OBJ_OCSP_sign OBJ_id_kp,9L - -#define SN_dvcs "DVCS" -#define LN_dvcs "dvcs" -#define NID_dvcs 297 -#define OBJ_dvcs OBJ_id_kp,10L - -#define SN_id_it_caProtEncCert "id-it-caProtEncCert" -#define NID_id_it_caProtEncCert 298 -#define OBJ_id_it_caProtEncCert OBJ_id_it,1L - -#define SN_id_it_signKeyPairTypes "id-it-signKeyPairTypes" -#define NID_id_it_signKeyPairTypes 299 -#define OBJ_id_it_signKeyPairTypes OBJ_id_it,2L - -#define SN_id_it_encKeyPairTypes "id-it-encKeyPairTypes" -#define NID_id_it_encKeyPairTypes 300 -#define OBJ_id_it_encKeyPairTypes OBJ_id_it,3L - -#define SN_id_it_preferredSymmAlg "id-it-preferredSymmAlg" -#define NID_id_it_preferredSymmAlg 301 -#define OBJ_id_it_preferredSymmAlg OBJ_id_it,4L - -#define SN_id_it_caKeyUpdateInfo "id-it-caKeyUpdateInfo" -#define NID_id_it_caKeyUpdateInfo 302 -#define OBJ_id_it_caKeyUpdateInfo OBJ_id_it,5L - -#define SN_id_it_currentCRL "id-it-currentCRL" -#define NID_id_it_currentCRL 303 -#define OBJ_id_it_currentCRL OBJ_id_it,6L - -#define SN_id_it_unsupportedOIDs "id-it-unsupportedOIDs" -#define NID_id_it_unsupportedOIDs 304 -#define OBJ_id_it_unsupportedOIDs OBJ_id_it,7L - -#define SN_id_it_subscriptionRequest "id-it-subscriptionRequest" -#define NID_id_it_subscriptionRequest 305 -#define OBJ_id_it_subscriptionRequest OBJ_id_it,8L - -#define SN_id_it_subscriptionResponse "id-it-subscriptionResponse" -#define NID_id_it_subscriptionResponse 306 -#define OBJ_id_it_subscriptionResponse OBJ_id_it,9L - -#define SN_id_it_keyPairParamReq "id-it-keyPairParamReq" -#define NID_id_it_keyPairParamReq 307 -#define OBJ_id_it_keyPairParamReq OBJ_id_it,10L - -#define SN_id_it_keyPairParamRep "id-it-keyPairParamRep" -#define NID_id_it_keyPairParamRep 308 -#define OBJ_id_it_keyPairParamRep OBJ_id_it,11L - -#define SN_id_it_revPassphrase "id-it-revPassphrase" -#define NID_id_it_revPassphrase 309 -#define OBJ_id_it_revPassphrase OBJ_id_it,12L - -#define SN_id_it_implicitConfirm "id-it-implicitConfirm" -#define NID_id_it_implicitConfirm 310 -#define OBJ_id_it_implicitConfirm OBJ_id_it,13L - -#define SN_id_it_confirmWaitTime "id-it-confirmWaitTime" -#define NID_id_it_confirmWaitTime 311 -#define OBJ_id_it_confirmWaitTime OBJ_id_it,14L - -#define SN_id_it_origPKIMessage "id-it-origPKIMessage" -#define NID_id_it_origPKIMessage 312 -#define OBJ_id_it_origPKIMessage OBJ_id_it,15L - -#define SN_id_it_suppLangTags "id-it-suppLangTags" -#define NID_id_it_suppLangTags 784 -#define OBJ_id_it_suppLangTags OBJ_id_it,16L - -#define SN_id_regCtrl "id-regCtrl" -#define NID_id_regCtrl 313 -#define OBJ_id_regCtrl OBJ_id_pkip,1L - -#define SN_id_regInfo "id-regInfo" -#define NID_id_regInfo 314 -#define OBJ_id_regInfo OBJ_id_pkip,2L - -#define SN_id_regCtrl_regToken "id-regCtrl-regToken" -#define NID_id_regCtrl_regToken 315 -#define OBJ_id_regCtrl_regToken OBJ_id_regCtrl,1L - -#define SN_id_regCtrl_authenticator "id-regCtrl-authenticator" -#define NID_id_regCtrl_authenticator 316 -#define OBJ_id_regCtrl_authenticator OBJ_id_regCtrl,2L - -#define SN_id_regCtrl_pkiPublicationInfo "id-regCtrl-pkiPublicationInfo" -#define NID_id_regCtrl_pkiPublicationInfo 317 -#define OBJ_id_regCtrl_pkiPublicationInfo OBJ_id_regCtrl,3L - -#define SN_id_regCtrl_pkiArchiveOptions "id-regCtrl-pkiArchiveOptions" -#define NID_id_regCtrl_pkiArchiveOptions 318 -#define OBJ_id_regCtrl_pkiArchiveOptions OBJ_id_regCtrl,4L - -#define SN_id_regCtrl_oldCertID "id-regCtrl-oldCertID" -#define NID_id_regCtrl_oldCertID 319 -#define OBJ_id_regCtrl_oldCertID OBJ_id_regCtrl,5L - -#define SN_id_regCtrl_protocolEncrKey "id-regCtrl-protocolEncrKey" -#define NID_id_regCtrl_protocolEncrKey 320 -#define OBJ_id_regCtrl_protocolEncrKey OBJ_id_regCtrl,6L - -#define SN_id_regInfo_utf8Pairs "id-regInfo-utf8Pairs" -#define NID_id_regInfo_utf8Pairs 321 -#define OBJ_id_regInfo_utf8Pairs OBJ_id_regInfo,1L - -#define SN_id_regInfo_certReq "id-regInfo-certReq" -#define NID_id_regInfo_certReq 322 -#define OBJ_id_regInfo_certReq OBJ_id_regInfo,2L - -#define SN_id_alg_des40 "id-alg-des40" -#define NID_id_alg_des40 323 -#define OBJ_id_alg_des40 OBJ_id_alg,1L - -#define SN_id_alg_noSignature "id-alg-noSignature" -#define NID_id_alg_noSignature 324 -#define OBJ_id_alg_noSignature OBJ_id_alg,2L - -#define SN_id_alg_dh_sig_hmac_sha1 "id-alg-dh-sig-hmac-sha1" -#define NID_id_alg_dh_sig_hmac_sha1 325 -#define OBJ_id_alg_dh_sig_hmac_sha1 OBJ_id_alg,3L - -#define SN_id_alg_dh_pop "id-alg-dh-pop" -#define NID_id_alg_dh_pop 326 -#define OBJ_id_alg_dh_pop OBJ_id_alg,4L - -#define SN_id_cmc_statusInfo "id-cmc-statusInfo" -#define NID_id_cmc_statusInfo 327 -#define OBJ_id_cmc_statusInfo OBJ_id_cmc,1L - -#define SN_id_cmc_identification "id-cmc-identification" -#define NID_id_cmc_identification 328 -#define OBJ_id_cmc_identification OBJ_id_cmc,2L - -#define SN_id_cmc_identityProof "id-cmc-identityProof" -#define NID_id_cmc_identityProof 329 -#define OBJ_id_cmc_identityProof OBJ_id_cmc,3L - -#define SN_id_cmc_dataReturn "id-cmc-dataReturn" -#define NID_id_cmc_dataReturn 330 -#define OBJ_id_cmc_dataReturn OBJ_id_cmc,4L - -#define SN_id_cmc_transactionId "id-cmc-transactionId" -#define NID_id_cmc_transactionId 331 -#define OBJ_id_cmc_transactionId OBJ_id_cmc,5L - -#define SN_id_cmc_senderNonce "id-cmc-senderNonce" -#define NID_id_cmc_senderNonce 332 -#define OBJ_id_cmc_senderNonce OBJ_id_cmc,6L - -#define SN_id_cmc_recipientNonce "id-cmc-recipientNonce" -#define NID_id_cmc_recipientNonce 333 -#define OBJ_id_cmc_recipientNonce OBJ_id_cmc,7L - -#define SN_id_cmc_addExtensions "id-cmc-addExtensions" -#define NID_id_cmc_addExtensions 334 -#define OBJ_id_cmc_addExtensions OBJ_id_cmc,8L - -#define SN_id_cmc_encryptedPOP "id-cmc-encryptedPOP" -#define NID_id_cmc_encryptedPOP 335 -#define OBJ_id_cmc_encryptedPOP OBJ_id_cmc,9L - -#define SN_id_cmc_decryptedPOP "id-cmc-decryptedPOP" -#define NID_id_cmc_decryptedPOP 336 -#define OBJ_id_cmc_decryptedPOP OBJ_id_cmc,10L - -#define SN_id_cmc_lraPOPWitness "id-cmc-lraPOPWitness" -#define NID_id_cmc_lraPOPWitness 337 -#define OBJ_id_cmc_lraPOPWitness OBJ_id_cmc,11L - -#define SN_id_cmc_getCert "id-cmc-getCert" -#define NID_id_cmc_getCert 338 -#define OBJ_id_cmc_getCert OBJ_id_cmc,15L - -#define SN_id_cmc_getCRL "id-cmc-getCRL" -#define NID_id_cmc_getCRL 339 -#define OBJ_id_cmc_getCRL OBJ_id_cmc,16L - -#define SN_id_cmc_revokeRequest "id-cmc-revokeRequest" -#define NID_id_cmc_revokeRequest 340 -#define OBJ_id_cmc_revokeRequest OBJ_id_cmc,17L - -#define SN_id_cmc_regInfo "id-cmc-regInfo" -#define NID_id_cmc_regInfo 341 -#define OBJ_id_cmc_regInfo OBJ_id_cmc,18L - -#define SN_id_cmc_responseInfo "id-cmc-responseInfo" -#define NID_id_cmc_responseInfo 342 -#define OBJ_id_cmc_responseInfo OBJ_id_cmc,19L - -#define SN_id_cmc_queryPending "id-cmc-queryPending" -#define NID_id_cmc_queryPending 343 -#define OBJ_id_cmc_queryPending OBJ_id_cmc,21L - -#define SN_id_cmc_popLinkRandom "id-cmc-popLinkRandom" -#define NID_id_cmc_popLinkRandom 344 -#define OBJ_id_cmc_popLinkRandom OBJ_id_cmc,22L - -#define SN_id_cmc_popLinkWitness "id-cmc-popLinkWitness" -#define NID_id_cmc_popLinkWitness 345 -#define OBJ_id_cmc_popLinkWitness OBJ_id_cmc,23L - -#define SN_id_cmc_confirmCertAcceptance "id-cmc-confirmCertAcceptance" -#define NID_id_cmc_confirmCertAcceptance 346 -#define OBJ_id_cmc_confirmCertAcceptance OBJ_id_cmc,24L - -#define SN_id_on_personalData "id-on-personalData" -#define NID_id_on_personalData 347 -#define OBJ_id_on_personalData OBJ_id_on,1L - -#define SN_id_on_permanentIdentifier "id-on-permanentIdentifier" -#define LN_id_on_permanentIdentifier "Permanent Identifier" -#define NID_id_on_permanentIdentifier 858 -#define OBJ_id_on_permanentIdentifier OBJ_id_on,3L - -#define SN_id_pda_dateOfBirth "id-pda-dateOfBirth" -#define NID_id_pda_dateOfBirth 348 -#define OBJ_id_pda_dateOfBirth OBJ_id_pda,1L - -#define SN_id_pda_placeOfBirth "id-pda-placeOfBirth" -#define NID_id_pda_placeOfBirth 349 -#define OBJ_id_pda_placeOfBirth OBJ_id_pda,2L - -#define SN_id_pda_gender "id-pda-gender" -#define NID_id_pda_gender 351 -#define OBJ_id_pda_gender OBJ_id_pda,3L - -#define SN_id_pda_countryOfCitizenship "id-pda-countryOfCitizenship" -#define NID_id_pda_countryOfCitizenship 352 -#define OBJ_id_pda_countryOfCitizenship OBJ_id_pda,4L - -#define SN_id_pda_countryOfResidence "id-pda-countryOfResidence" -#define NID_id_pda_countryOfResidence 353 -#define OBJ_id_pda_countryOfResidence OBJ_id_pda,5L - -#define SN_id_aca_authenticationInfo "id-aca-authenticationInfo" -#define NID_id_aca_authenticationInfo 354 -#define OBJ_id_aca_authenticationInfo OBJ_id_aca,1L - -#define SN_id_aca_accessIdentity "id-aca-accessIdentity" -#define NID_id_aca_accessIdentity 355 -#define OBJ_id_aca_accessIdentity OBJ_id_aca,2L - -#define SN_id_aca_chargingIdentity "id-aca-chargingIdentity" -#define NID_id_aca_chargingIdentity 356 -#define OBJ_id_aca_chargingIdentity OBJ_id_aca,3L - -#define SN_id_aca_group "id-aca-group" -#define NID_id_aca_group 357 -#define OBJ_id_aca_group OBJ_id_aca,4L - -#define SN_id_aca_role "id-aca-role" -#define NID_id_aca_role 358 -#define OBJ_id_aca_role OBJ_id_aca,5L - -#define SN_id_aca_encAttrs "id-aca-encAttrs" -#define NID_id_aca_encAttrs 399 -#define OBJ_id_aca_encAttrs OBJ_id_aca,6L - -#define SN_id_qcs_pkixQCSyntax_v1 "id-qcs-pkixQCSyntax-v1" -#define NID_id_qcs_pkixQCSyntax_v1 359 -#define OBJ_id_qcs_pkixQCSyntax_v1 OBJ_id_qcs,1L - -#define SN_id_cct_crs "id-cct-crs" -#define NID_id_cct_crs 360 -#define OBJ_id_cct_crs OBJ_id_cct,1L - -#define SN_id_cct_PKIData "id-cct-PKIData" -#define NID_id_cct_PKIData 361 -#define OBJ_id_cct_PKIData OBJ_id_cct,2L - -#define SN_id_cct_PKIResponse "id-cct-PKIResponse" -#define NID_id_cct_PKIResponse 362 -#define OBJ_id_cct_PKIResponse OBJ_id_cct,3L - -#define SN_id_ppl_anyLanguage "id-ppl-anyLanguage" -#define LN_id_ppl_anyLanguage "Any language" -#define NID_id_ppl_anyLanguage 664 -#define OBJ_id_ppl_anyLanguage OBJ_id_ppl,0L - -#define SN_id_ppl_inheritAll "id-ppl-inheritAll" -#define LN_id_ppl_inheritAll "Inherit all" -#define NID_id_ppl_inheritAll 665 -#define OBJ_id_ppl_inheritAll OBJ_id_ppl,1L - -#define SN_Independent "id-ppl-independent" -#define LN_Independent "Independent" -#define NID_Independent 667 -#define OBJ_Independent OBJ_id_ppl,2L - -#define SN_ad_OCSP "OCSP" -#define LN_ad_OCSP "OCSP" -#define NID_ad_OCSP 178 -#define OBJ_ad_OCSP OBJ_id_ad,1L - -#define SN_ad_ca_issuers "caIssuers" -#define LN_ad_ca_issuers "CA Issuers" -#define NID_ad_ca_issuers 179 -#define OBJ_ad_ca_issuers OBJ_id_ad,2L - -#define SN_ad_timeStamping "ad_timestamping" -#define LN_ad_timeStamping "AD Time Stamping" -#define NID_ad_timeStamping 363 -#define OBJ_ad_timeStamping OBJ_id_ad,3L - -#define SN_ad_dvcs "AD_DVCS" -#define LN_ad_dvcs "ad dvcs" -#define NID_ad_dvcs 364 -#define OBJ_ad_dvcs OBJ_id_ad,4L - -#define SN_caRepository "caRepository" -#define LN_caRepository "CA Repository" -#define NID_caRepository 785 -#define OBJ_caRepository OBJ_id_ad,5L - -#define OBJ_id_pkix_OCSP OBJ_ad_OCSP - -#define SN_id_pkix_OCSP_basic "basicOCSPResponse" -#define LN_id_pkix_OCSP_basic "Basic OCSP Response" -#define NID_id_pkix_OCSP_basic 365 -#define OBJ_id_pkix_OCSP_basic OBJ_id_pkix_OCSP,1L - -#define SN_id_pkix_OCSP_Nonce "Nonce" -#define LN_id_pkix_OCSP_Nonce "OCSP Nonce" -#define NID_id_pkix_OCSP_Nonce 366 -#define OBJ_id_pkix_OCSP_Nonce OBJ_id_pkix_OCSP,2L - -#define SN_id_pkix_OCSP_CrlID "CrlID" -#define LN_id_pkix_OCSP_CrlID "OCSP CRL ID" -#define NID_id_pkix_OCSP_CrlID 367 -#define OBJ_id_pkix_OCSP_CrlID OBJ_id_pkix_OCSP,3L - -#define SN_id_pkix_OCSP_acceptableResponses "acceptableResponses" -#define LN_id_pkix_OCSP_acceptableResponses "Acceptable OCSP Responses" -#define NID_id_pkix_OCSP_acceptableResponses 368 -#define OBJ_id_pkix_OCSP_acceptableResponses OBJ_id_pkix_OCSP,4L - -#define SN_id_pkix_OCSP_noCheck "noCheck" -#define LN_id_pkix_OCSP_noCheck "OCSP No Check" -#define NID_id_pkix_OCSP_noCheck 369 -#define OBJ_id_pkix_OCSP_noCheck OBJ_id_pkix_OCSP,5L - -#define SN_id_pkix_OCSP_archiveCutoff "archiveCutoff" -#define LN_id_pkix_OCSP_archiveCutoff "OCSP Archive Cutoff" -#define NID_id_pkix_OCSP_archiveCutoff 370 -#define OBJ_id_pkix_OCSP_archiveCutoff OBJ_id_pkix_OCSP,6L - -#define SN_id_pkix_OCSP_serviceLocator "serviceLocator" -#define LN_id_pkix_OCSP_serviceLocator "OCSP Service Locator" -#define NID_id_pkix_OCSP_serviceLocator 371 -#define OBJ_id_pkix_OCSP_serviceLocator OBJ_id_pkix_OCSP,7L - -#define SN_id_pkix_OCSP_extendedStatus "extendedStatus" -#define LN_id_pkix_OCSP_extendedStatus "Extended OCSP Status" -#define NID_id_pkix_OCSP_extendedStatus 372 -#define OBJ_id_pkix_OCSP_extendedStatus OBJ_id_pkix_OCSP,8L - -#define SN_id_pkix_OCSP_valid "valid" -#define NID_id_pkix_OCSP_valid 373 -#define OBJ_id_pkix_OCSP_valid OBJ_id_pkix_OCSP,9L - -#define SN_id_pkix_OCSP_path "path" -#define NID_id_pkix_OCSP_path 374 -#define OBJ_id_pkix_OCSP_path OBJ_id_pkix_OCSP,10L - -#define SN_id_pkix_OCSP_trustRoot "trustRoot" -#define LN_id_pkix_OCSP_trustRoot "Trust Root" -#define NID_id_pkix_OCSP_trustRoot 375 -#define OBJ_id_pkix_OCSP_trustRoot OBJ_id_pkix_OCSP,11L - -#define SN_algorithm "algorithm" -#define LN_algorithm "algorithm" -#define NID_algorithm 376 -#define OBJ_algorithm 1L,3L,14L,3L,2L - -#define SN_md5WithRSA "RSA-NP-MD5" -#define LN_md5WithRSA "md5WithRSA" -#define NID_md5WithRSA 104 -#define OBJ_md5WithRSA OBJ_algorithm,3L - -#define SN_des_ecb "DES-ECB" -#define LN_des_ecb "des-ecb" -#define NID_des_ecb 29 -#define OBJ_des_ecb OBJ_algorithm,6L - -#define SN_des_cbc "DES-CBC" -#define LN_des_cbc "des-cbc" -#define NID_des_cbc 31 -#define OBJ_des_cbc OBJ_algorithm,7L - -#define SN_des_ofb64 "DES-OFB" -#define LN_des_ofb64 "des-ofb" -#define NID_des_ofb64 45 -#define OBJ_des_ofb64 OBJ_algorithm,8L - -#define SN_des_cfb64 "DES-CFB" -#define LN_des_cfb64 "des-cfb" -#define NID_des_cfb64 30 -#define OBJ_des_cfb64 OBJ_algorithm,9L - -#define SN_rsaSignature "rsaSignature" -#define NID_rsaSignature 377 -#define OBJ_rsaSignature OBJ_algorithm,11L - -#define SN_dsa_2 "DSA-old" -#define LN_dsa_2 "dsaEncryption-old" -#define NID_dsa_2 67 -#define OBJ_dsa_2 OBJ_algorithm,12L - -#define SN_dsaWithSHA "DSA-SHA" -#define LN_dsaWithSHA "dsaWithSHA" -#define NID_dsaWithSHA 66 -#define OBJ_dsaWithSHA OBJ_algorithm,13L - -#define SN_shaWithRSAEncryption "RSA-SHA" -#define LN_shaWithRSAEncryption "shaWithRSAEncryption" -#define NID_shaWithRSAEncryption 42 -#define OBJ_shaWithRSAEncryption OBJ_algorithm,15L - -#define SN_des_ede_ecb "DES-EDE" -#define LN_des_ede_ecb "des-ede" -#define NID_des_ede_ecb 32 -#define OBJ_des_ede_ecb OBJ_algorithm,17L - -#define SN_des_ede3_ecb "DES-EDE3" -#define LN_des_ede3_ecb "des-ede3" -#define NID_des_ede3_ecb 33 - -#define SN_des_ede_cbc "DES-EDE-CBC" -#define LN_des_ede_cbc "des-ede-cbc" -#define NID_des_ede_cbc 43 - -#define SN_des_ede_cfb64 "DES-EDE-CFB" -#define LN_des_ede_cfb64 "des-ede-cfb" -#define NID_des_ede_cfb64 60 - -#define SN_des_ede3_cfb64 "DES-EDE3-CFB" -#define LN_des_ede3_cfb64 "des-ede3-cfb" -#define NID_des_ede3_cfb64 61 - -#define SN_des_ede_ofb64 "DES-EDE-OFB" -#define LN_des_ede_ofb64 "des-ede-ofb" -#define NID_des_ede_ofb64 62 - -#define SN_des_ede3_ofb64 "DES-EDE3-OFB" -#define LN_des_ede3_ofb64 "des-ede3-ofb" -#define NID_des_ede3_ofb64 63 - -#define SN_desx_cbc "DESX-CBC" -#define LN_desx_cbc "desx-cbc" -#define NID_desx_cbc 80 - -#define SN_sha "SHA" -#define LN_sha "sha" -#define NID_sha 41 -#define OBJ_sha OBJ_algorithm,18L - -#define SN_sha1 "SHA1" -#define LN_sha1 "sha1" -#define NID_sha1 64 -#define OBJ_sha1 OBJ_algorithm,26L - -#define SN_dsaWithSHA1_2 "DSA-SHA1-old" -#define LN_dsaWithSHA1_2 "dsaWithSHA1-old" -#define NID_dsaWithSHA1_2 70 -#define OBJ_dsaWithSHA1_2 OBJ_algorithm,27L - -#define SN_sha1WithRSA "RSA-SHA1-2" -#define LN_sha1WithRSA "sha1WithRSA" -#define NID_sha1WithRSA 115 -#define OBJ_sha1WithRSA OBJ_algorithm,29L - -#define SN_ripemd160 "RIPEMD160" -#define LN_ripemd160 "ripemd160" -#define NID_ripemd160 117 -#define OBJ_ripemd160 1L,3L,36L,3L,2L,1L - -#define SN_ripemd160WithRSA "RSA-RIPEMD160" -#define LN_ripemd160WithRSA "ripemd160WithRSA" -#define NID_ripemd160WithRSA 119 -#define OBJ_ripemd160WithRSA 1L,3L,36L,3L,3L,1L,2L - -#define SN_sxnet "SXNetID" -#define LN_sxnet "Strong Extranet ID" -#define NID_sxnet 143 -#define OBJ_sxnet 1L,3L,101L,1L,4L,1L - -#define SN_X500 "X500" -#define LN_X500 "directory services (X.500)" -#define NID_X500 11 -#define OBJ_X500 2L,5L - -#define SN_X509 "X509" -#define NID_X509 12 -#define OBJ_X509 OBJ_X500,4L - -#define SN_commonName "CN" -#define LN_commonName "commonName" -#define NID_commonName 13 -#define OBJ_commonName OBJ_X509,3L - -#define SN_surname "SN" -#define LN_surname "surname" -#define NID_surname 100 -#define OBJ_surname OBJ_X509,4L - -#define LN_serialNumber "serialNumber" -#define NID_serialNumber 105 -#define OBJ_serialNumber OBJ_X509,5L - -#define SN_countryName "C" -#define LN_countryName "countryName" -#define NID_countryName 14 -#define OBJ_countryName OBJ_X509,6L - -#define SN_localityName "L" -#define LN_localityName "localityName" -#define NID_localityName 15 -#define OBJ_localityName OBJ_X509,7L - -#define SN_stateOrProvinceName "ST" -#define LN_stateOrProvinceName "stateOrProvinceName" -#define NID_stateOrProvinceName 16 -#define OBJ_stateOrProvinceName OBJ_X509,8L - -#define SN_streetAddress "street" -#define LN_streetAddress "streetAddress" -#define NID_streetAddress 660 -#define OBJ_streetAddress OBJ_X509,9L - -#define SN_organizationName "O" -#define LN_organizationName "organizationName" -#define NID_organizationName 17 -#define OBJ_organizationName OBJ_X509,10L - -#define SN_organizationalUnitName "OU" -#define LN_organizationalUnitName "organizationalUnitName" -#define NID_organizationalUnitName 18 -#define OBJ_organizationalUnitName OBJ_X509,11L - -#define SN_title "title" -#define LN_title "title" -#define NID_title 106 -#define OBJ_title OBJ_X509,12L - -#define LN_description "description" -#define NID_description 107 -#define OBJ_description OBJ_X509,13L - -#define LN_searchGuide "searchGuide" -#define NID_searchGuide 859 -#define OBJ_searchGuide OBJ_X509,14L - -#define LN_businessCategory "businessCategory" -#define NID_businessCategory 860 -#define OBJ_businessCategory OBJ_X509,15L - -#define LN_postalAddress "postalAddress" -#define NID_postalAddress 861 -#define OBJ_postalAddress OBJ_X509,16L - -#define LN_postalCode "postalCode" -#define NID_postalCode 661 -#define OBJ_postalCode OBJ_X509,17L - -#define LN_postOfficeBox "postOfficeBox" -#define NID_postOfficeBox 862 -#define OBJ_postOfficeBox OBJ_X509,18L - -#define LN_physicalDeliveryOfficeName "physicalDeliveryOfficeName" -#define NID_physicalDeliveryOfficeName 863 -#define OBJ_physicalDeliveryOfficeName OBJ_X509,19L - -#define LN_telephoneNumber "telephoneNumber" -#define NID_telephoneNumber 864 -#define OBJ_telephoneNumber OBJ_X509,20L - -#define LN_telexNumber "telexNumber" -#define NID_telexNumber 865 -#define OBJ_telexNumber OBJ_X509,21L - -#define LN_teletexTerminalIdentifier "teletexTerminalIdentifier" -#define NID_teletexTerminalIdentifier 866 -#define OBJ_teletexTerminalIdentifier OBJ_X509,22L - -#define LN_facsimileTelephoneNumber "facsimileTelephoneNumber" -#define NID_facsimileTelephoneNumber 867 -#define OBJ_facsimileTelephoneNumber OBJ_X509,23L - -#define LN_x121Address "x121Address" -#define NID_x121Address 868 -#define OBJ_x121Address OBJ_X509,24L - -#define LN_internationaliSDNNumber "internationaliSDNNumber" -#define NID_internationaliSDNNumber 869 -#define OBJ_internationaliSDNNumber OBJ_X509,25L - -#define LN_registeredAddress "registeredAddress" -#define NID_registeredAddress 870 -#define OBJ_registeredAddress OBJ_X509,26L - -#define LN_destinationIndicator "destinationIndicator" -#define NID_destinationIndicator 871 -#define OBJ_destinationIndicator OBJ_X509,27L - -#define LN_preferredDeliveryMethod "preferredDeliveryMethod" -#define NID_preferredDeliveryMethod 872 -#define OBJ_preferredDeliveryMethod OBJ_X509,28L - -#define LN_presentationAddress "presentationAddress" -#define NID_presentationAddress 873 -#define OBJ_presentationAddress OBJ_X509,29L - -#define LN_supportedApplicationContext "supportedApplicationContext" -#define NID_supportedApplicationContext 874 -#define OBJ_supportedApplicationContext OBJ_X509,30L - -#define SN_member "member" -#define NID_member 875 -#define OBJ_member OBJ_X509,31L - -#define SN_owner "owner" -#define NID_owner 876 -#define OBJ_owner OBJ_X509,32L - -#define LN_roleOccupant "roleOccupant" -#define NID_roleOccupant 877 -#define OBJ_roleOccupant OBJ_X509,33L - -#define SN_seeAlso "seeAlso" -#define NID_seeAlso 878 -#define OBJ_seeAlso OBJ_X509,34L - -#define LN_userPassword "userPassword" -#define NID_userPassword 879 -#define OBJ_userPassword OBJ_X509,35L - -#define LN_userCertificate "userCertificate" -#define NID_userCertificate 880 -#define OBJ_userCertificate OBJ_X509,36L - -#define LN_cACertificate "cACertificate" -#define NID_cACertificate 881 -#define OBJ_cACertificate OBJ_X509,37L - -#define LN_authorityRevocationList "authorityRevocationList" -#define NID_authorityRevocationList 882 -#define OBJ_authorityRevocationList OBJ_X509,38L - -#define LN_certificateRevocationList "certificateRevocationList" -#define NID_certificateRevocationList 883 -#define OBJ_certificateRevocationList OBJ_X509,39L - -#define LN_crossCertificatePair "crossCertificatePair" -#define NID_crossCertificatePair 884 -#define OBJ_crossCertificatePair OBJ_X509,40L - -#define SN_name "name" -#define LN_name "name" -#define NID_name 173 -#define OBJ_name OBJ_X509,41L - -#define SN_givenName "GN" -#define LN_givenName "givenName" -#define NID_givenName 99 -#define OBJ_givenName OBJ_X509,42L - -#define SN_initials "initials" -#define LN_initials "initials" -#define NID_initials 101 -#define OBJ_initials OBJ_X509,43L - -#define LN_generationQualifier "generationQualifier" -#define NID_generationQualifier 509 -#define OBJ_generationQualifier OBJ_X509,44L - -#define LN_x500UniqueIdentifier "x500UniqueIdentifier" -#define NID_x500UniqueIdentifier 503 -#define OBJ_x500UniqueIdentifier OBJ_X509,45L - -#define SN_dnQualifier "dnQualifier" -#define LN_dnQualifier "dnQualifier" -#define NID_dnQualifier 174 -#define OBJ_dnQualifier OBJ_X509,46L - -#define LN_enhancedSearchGuide "enhancedSearchGuide" -#define NID_enhancedSearchGuide 885 -#define OBJ_enhancedSearchGuide OBJ_X509,47L - -#define LN_protocolInformation "protocolInformation" -#define NID_protocolInformation 886 -#define OBJ_protocolInformation OBJ_X509,48L - -#define LN_distinguishedName "distinguishedName" -#define NID_distinguishedName 887 -#define OBJ_distinguishedName OBJ_X509,49L - -#define LN_uniqueMember "uniqueMember" -#define NID_uniqueMember 888 -#define OBJ_uniqueMember OBJ_X509,50L - -#define LN_houseIdentifier "houseIdentifier" -#define NID_houseIdentifier 889 -#define OBJ_houseIdentifier OBJ_X509,51L - -#define LN_supportedAlgorithms "supportedAlgorithms" -#define NID_supportedAlgorithms 890 -#define OBJ_supportedAlgorithms OBJ_X509,52L - -#define LN_deltaRevocationList "deltaRevocationList" -#define NID_deltaRevocationList 891 -#define OBJ_deltaRevocationList OBJ_X509,53L - -#define SN_dmdName "dmdName" -#define NID_dmdName 892 -#define OBJ_dmdName OBJ_X509,54L - -#define LN_pseudonym "pseudonym" -#define NID_pseudonym 510 -#define OBJ_pseudonym OBJ_X509,65L - -#define SN_role "role" -#define LN_role "role" -#define NID_role 400 -#define OBJ_role OBJ_X509,72L - -#define SN_X500algorithms "X500algorithms" -#define LN_X500algorithms "directory services - algorithms" -#define NID_X500algorithms 378 -#define OBJ_X500algorithms OBJ_X500,8L - -#define SN_rsa "RSA" -#define LN_rsa "rsa" -#define NID_rsa 19 -#define OBJ_rsa OBJ_X500algorithms,1L,1L - -#define SN_mdc2WithRSA "RSA-MDC2" -#define LN_mdc2WithRSA "mdc2WithRSA" -#define NID_mdc2WithRSA 96 -#define OBJ_mdc2WithRSA OBJ_X500algorithms,3L,100L - -#define SN_mdc2 "MDC2" -#define LN_mdc2 "mdc2" -#define NID_mdc2 95 -#define OBJ_mdc2 OBJ_X500algorithms,3L,101L - -#define SN_id_ce "id-ce" -#define NID_id_ce 81 -#define OBJ_id_ce OBJ_X500,29L - -#define SN_subject_directory_attributes "subjectDirectoryAttributes" -#define LN_subject_directory_attributes "X509v3 Subject Directory Attributes" -#define NID_subject_directory_attributes 769 -#define OBJ_subject_directory_attributes OBJ_id_ce,9L - -#define SN_subject_key_identifier "subjectKeyIdentifier" -#define LN_subject_key_identifier "X509v3 Subject Key Identifier" -#define NID_subject_key_identifier 82 -#define OBJ_subject_key_identifier OBJ_id_ce,14L - -#define SN_key_usage "keyUsage" -#define LN_key_usage "X509v3 Key Usage" -#define NID_key_usage 83 -#define OBJ_key_usage OBJ_id_ce,15L - -#define SN_private_key_usage_period "privateKeyUsagePeriod" -#define LN_private_key_usage_period "X509v3 Private Key Usage Period" -#define NID_private_key_usage_period 84 -#define OBJ_private_key_usage_period OBJ_id_ce,16L - -#define SN_subject_alt_name "subjectAltName" -#define LN_subject_alt_name "X509v3 Subject Alternative Name" -#define NID_subject_alt_name 85 -#define OBJ_subject_alt_name OBJ_id_ce,17L - -#define SN_issuer_alt_name "issuerAltName" -#define LN_issuer_alt_name "X509v3 Issuer Alternative Name" -#define NID_issuer_alt_name 86 -#define OBJ_issuer_alt_name OBJ_id_ce,18L - -#define SN_basic_constraints "basicConstraints" -#define LN_basic_constraints "X509v3 Basic Constraints" -#define NID_basic_constraints 87 -#define OBJ_basic_constraints OBJ_id_ce,19L - -#define SN_crl_number "crlNumber" -#define LN_crl_number "X509v3 CRL Number" -#define NID_crl_number 88 -#define OBJ_crl_number OBJ_id_ce,20L - -#define SN_crl_reason "CRLReason" -#define LN_crl_reason "X509v3 CRL Reason Code" -#define NID_crl_reason 141 -#define OBJ_crl_reason OBJ_id_ce,21L - -#define SN_invalidity_date "invalidityDate" -#define LN_invalidity_date "Invalidity Date" -#define NID_invalidity_date 142 -#define OBJ_invalidity_date OBJ_id_ce,24L - -#define SN_delta_crl "deltaCRL" -#define LN_delta_crl "X509v3 Delta CRL Indicator" -#define NID_delta_crl 140 -#define OBJ_delta_crl OBJ_id_ce,27L - -#define SN_issuing_distribution_point "issuingDistributionPoint" -#define LN_issuing_distribution_point "X509v3 Issuing Distribution Point" -#define NID_issuing_distribution_point 770 -#define OBJ_issuing_distribution_point OBJ_id_ce,28L - -#define SN_certificate_issuer "certificateIssuer" -#define LN_certificate_issuer "X509v3 Certificate Issuer" -#define NID_certificate_issuer 771 -#define OBJ_certificate_issuer OBJ_id_ce,29L - -#define SN_name_constraints "nameConstraints" -#define LN_name_constraints "X509v3 Name Constraints" -#define NID_name_constraints 666 -#define OBJ_name_constraints OBJ_id_ce,30L - -#define SN_crl_distribution_points "crlDistributionPoints" -#define LN_crl_distribution_points "X509v3 CRL Distribution Points" -#define NID_crl_distribution_points 103 -#define OBJ_crl_distribution_points OBJ_id_ce,31L - -#define SN_certificate_policies "certificatePolicies" -#define LN_certificate_policies "X509v3 Certificate Policies" -#define NID_certificate_policies 89 -#define OBJ_certificate_policies OBJ_id_ce,32L - -#define SN_any_policy "anyPolicy" -#define LN_any_policy "X509v3 Any Policy" -#define NID_any_policy 746 -#define OBJ_any_policy OBJ_certificate_policies,0L - -#define SN_policy_mappings "policyMappings" -#define LN_policy_mappings "X509v3 Policy Mappings" -#define NID_policy_mappings 747 -#define OBJ_policy_mappings OBJ_id_ce,33L - -#define SN_authority_key_identifier "authorityKeyIdentifier" -#define LN_authority_key_identifier "X509v3 Authority Key Identifier" -#define NID_authority_key_identifier 90 -#define OBJ_authority_key_identifier OBJ_id_ce,35L - -#define SN_policy_constraints "policyConstraints" -#define LN_policy_constraints "X509v3 Policy Constraints" -#define NID_policy_constraints 401 -#define OBJ_policy_constraints OBJ_id_ce,36L - -#define SN_ext_key_usage "extendedKeyUsage" -#define LN_ext_key_usage "X509v3 Extended Key Usage" -#define NID_ext_key_usage 126 -#define OBJ_ext_key_usage OBJ_id_ce,37L - -#define SN_freshest_crl "freshestCRL" -#define LN_freshest_crl "X509v3 Freshest CRL" -#define NID_freshest_crl 857 -#define OBJ_freshest_crl OBJ_id_ce,46L - -#define SN_inhibit_any_policy "inhibitAnyPolicy" -#define LN_inhibit_any_policy "X509v3 Inhibit Any Policy" -#define NID_inhibit_any_policy 748 -#define OBJ_inhibit_any_policy OBJ_id_ce,54L - -#define SN_target_information "targetInformation" -#define LN_target_information "X509v3 AC Targeting" -#define NID_target_information 402 -#define OBJ_target_information OBJ_id_ce,55L - -#define SN_no_rev_avail "noRevAvail" -#define LN_no_rev_avail "X509v3 No Revocation Available" -#define NID_no_rev_avail 403 -#define OBJ_no_rev_avail OBJ_id_ce,56L - -#define SN_anyExtendedKeyUsage "anyExtendedKeyUsage" -#define LN_anyExtendedKeyUsage "Any Extended Key Usage" -#define NID_anyExtendedKeyUsage 910 -#define OBJ_anyExtendedKeyUsage OBJ_ext_key_usage,0L - -#define SN_netscape "Netscape" -#define LN_netscape "Netscape Communications Corp." -#define NID_netscape 57 -#define OBJ_netscape 2L,16L,840L,1L,113730L - -#define SN_netscape_cert_extension "nsCertExt" -#define LN_netscape_cert_extension "Netscape Certificate Extension" -#define NID_netscape_cert_extension 58 -#define OBJ_netscape_cert_extension OBJ_netscape,1L - -#define SN_netscape_data_type "nsDataType" -#define LN_netscape_data_type "Netscape Data Type" -#define NID_netscape_data_type 59 -#define OBJ_netscape_data_type OBJ_netscape,2L - -#define SN_netscape_cert_type "nsCertType" -#define LN_netscape_cert_type "Netscape Cert Type" -#define NID_netscape_cert_type 71 -#define OBJ_netscape_cert_type OBJ_netscape_cert_extension,1L - -#define SN_netscape_base_url "nsBaseUrl" -#define LN_netscape_base_url "Netscape Base Url" -#define NID_netscape_base_url 72 -#define OBJ_netscape_base_url OBJ_netscape_cert_extension,2L - -#define SN_netscape_revocation_url "nsRevocationUrl" -#define LN_netscape_revocation_url "Netscape Revocation Url" -#define NID_netscape_revocation_url 73 -#define OBJ_netscape_revocation_url OBJ_netscape_cert_extension,3L - -#define SN_netscape_ca_revocation_url "nsCaRevocationUrl" -#define LN_netscape_ca_revocation_url "Netscape CA Revocation Url" -#define NID_netscape_ca_revocation_url 74 -#define OBJ_netscape_ca_revocation_url OBJ_netscape_cert_extension,4L - -#define SN_netscape_renewal_url "nsRenewalUrl" -#define LN_netscape_renewal_url "Netscape Renewal Url" -#define NID_netscape_renewal_url 75 -#define OBJ_netscape_renewal_url OBJ_netscape_cert_extension,7L - -#define SN_netscape_ca_policy_url "nsCaPolicyUrl" -#define LN_netscape_ca_policy_url "Netscape CA Policy Url" -#define NID_netscape_ca_policy_url 76 -#define OBJ_netscape_ca_policy_url OBJ_netscape_cert_extension,8L - -#define SN_netscape_ssl_server_name "nsSslServerName" -#define LN_netscape_ssl_server_name "Netscape SSL Server Name" -#define NID_netscape_ssl_server_name 77 -#define OBJ_netscape_ssl_server_name OBJ_netscape_cert_extension,12L - -#define SN_netscape_comment "nsComment" -#define LN_netscape_comment "Netscape Comment" -#define NID_netscape_comment 78 -#define OBJ_netscape_comment OBJ_netscape_cert_extension,13L - -#define SN_netscape_cert_sequence "nsCertSequence" -#define LN_netscape_cert_sequence "Netscape Certificate Sequence" -#define NID_netscape_cert_sequence 79 -#define OBJ_netscape_cert_sequence OBJ_netscape_data_type,5L - -#define SN_ns_sgc "nsSGC" -#define LN_ns_sgc "Netscape Server Gated Crypto" -#define NID_ns_sgc 139 -#define OBJ_ns_sgc OBJ_netscape,4L,1L - -#define SN_org "ORG" -#define LN_org "org" -#define NID_org 379 -#define OBJ_org OBJ_iso,3L - -#define SN_dod "DOD" -#define LN_dod "dod" -#define NID_dod 380 -#define OBJ_dod OBJ_org,6L - -#define SN_iana "IANA" -#define LN_iana "iana" -#define NID_iana 381 -#define OBJ_iana OBJ_dod,1L - -#define OBJ_internet OBJ_iana - -#define SN_Directory "directory" -#define LN_Directory "Directory" -#define NID_Directory 382 -#define OBJ_Directory OBJ_internet,1L - -#define SN_Management "mgmt" -#define LN_Management "Management" -#define NID_Management 383 -#define OBJ_Management OBJ_internet,2L - -#define SN_Experimental "experimental" -#define LN_Experimental "Experimental" -#define NID_Experimental 384 -#define OBJ_Experimental OBJ_internet,3L - -#define SN_Private "private" -#define LN_Private "Private" -#define NID_Private 385 -#define OBJ_Private OBJ_internet,4L - -#define SN_Security "security" -#define LN_Security "Security" -#define NID_Security 386 -#define OBJ_Security OBJ_internet,5L - -#define SN_SNMPv2 "snmpv2" -#define LN_SNMPv2 "SNMPv2" -#define NID_SNMPv2 387 -#define OBJ_SNMPv2 OBJ_internet,6L - -#define LN_Mail "Mail" -#define NID_Mail 388 -#define OBJ_Mail OBJ_internet,7L - -#define SN_Enterprises "enterprises" -#define LN_Enterprises "Enterprises" -#define NID_Enterprises 389 -#define OBJ_Enterprises OBJ_Private,1L - -#define SN_dcObject "dcobject" -#define LN_dcObject "dcObject" -#define NID_dcObject 390 -#define OBJ_dcObject OBJ_Enterprises,1466L,344L - -#define SN_mime_mhs "mime-mhs" -#define LN_mime_mhs "MIME MHS" -#define NID_mime_mhs 504 -#define OBJ_mime_mhs OBJ_Mail,1L - -#define SN_mime_mhs_headings "mime-mhs-headings" -#define LN_mime_mhs_headings "mime-mhs-headings" -#define NID_mime_mhs_headings 505 -#define OBJ_mime_mhs_headings OBJ_mime_mhs,1L - -#define SN_mime_mhs_bodies "mime-mhs-bodies" -#define LN_mime_mhs_bodies "mime-mhs-bodies" -#define NID_mime_mhs_bodies 506 -#define OBJ_mime_mhs_bodies OBJ_mime_mhs,2L - -#define SN_id_hex_partial_message "id-hex-partial-message" -#define LN_id_hex_partial_message "id-hex-partial-message" -#define NID_id_hex_partial_message 507 -#define OBJ_id_hex_partial_message OBJ_mime_mhs_headings,1L - -#define SN_id_hex_multipart_message "id-hex-multipart-message" -#define LN_id_hex_multipart_message "id-hex-multipart-message" -#define NID_id_hex_multipart_message 508 -#define OBJ_id_hex_multipart_message OBJ_mime_mhs_headings,2L - -#define SN_zlib_compression "ZLIB" -#define LN_zlib_compression "zlib compression" -#define NID_zlib_compression 125 -#define OBJ_zlib_compression OBJ_id_smime_alg,8L - -#define OBJ_csor 2L,16L,840L,1L,101L,3L - -#define OBJ_nistAlgorithms OBJ_csor,4L - -#define OBJ_aes OBJ_nistAlgorithms,1L - -#define SN_aes_128_ecb "AES-128-ECB" -#define LN_aes_128_ecb "aes-128-ecb" -#define NID_aes_128_ecb 418 -#define OBJ_aes_128_ecb OBJ_aes,1L - -#define SN_aes_128_cbc "AES-128-CBC" -#define LN_aes_128_cbc "aes-128-cbc" -#define NID_aes_128_cbc 419 -#define OBJ_aes_128_cbc OBJ_aes,2L - -#define SN_aes_128_ofb128 "AES-128-OFB" -#define LN_aes_128_ofb128 "aes-128-ofb" -#define NID_aes_128_ofb128 420 -#define OBJ_aes_128_ofb128 OBJ_aes,3L - -#define SN_aes_128_cfb128 "AES-128-CFB" -#define LN_aes_128_cfb128 "aes-128-cfb" -#define NID_aes_128_cfb128 421 -#define OBJ_aes_128_cfb128 OBJ_aes,4L - -#define SN_id_aes128_wrap "id-aes128-wrap" -#define NID_id_aes128_wrap 788 -#define OBJ_id_aes128_wrap OBJ_aes,5L - -#define SN_aes_128_gcm "id-aes128-GCM" -#define LN_aes_128_gcm "aes-128-gcm" -#define NID_aes_128_gcm 895 -#define OBJ_aes_128_gcm OBJ_aes,6L - -#define SN_aes_128_ccm "id-aes128-CCM" -#define LN_aes_128_ccm "aes-128-ccm" -#define NID_aes_128_ccm 896 -#define OBJ_aes_128_ccm OBJ_aes,7L - -#define SN_id_aes128_wrap_pad "id-aes128-wrap-pad" -#define NID_id_aes128_wrap_pad 897 -#define OBJ_id_aes128_wrap_pad OBJ_aes,8L - -#define SN_aes_192_ecb "AES-192-ECB" -#define LN_aes_192_ecb "aes-192-ecb" -#define NID_aes_192_ecb 422 -#define OBJ_aes_192_ecb OBJ_aes,21L - -#define SN_aes_192_cbc "AES-192-CBC" -#define LN_aes_192_cbc "aes-192-cbc" -#define NID_aes_192_cbc 423 -#define OBJ_aes_192_cbc OBJ_aes,22L - -#define SN_aes_192_ofb128 "AES-192-OFB" -#define LN_aes_192_ofb128 "aes-192-ofb" -#define NID_aes_192_ofb128 424 -#define OBJ_aes_192_ofb128 OBJ_aes,23L - -#define SN_aes_192_cfb128 "AES-192-CFB" -#define LN_aes_192_cfb128 "aes-192-cfb" -#define NID_aes_192_cfb128 425 -#define OBJ_aes_192_cfb128 OBJ_aes,24L - -#define SN_id_aes192_wrap "id-aes192-wrap" -#define NID_id_aes192_wrap 789 -#define OBJ_id_aes192_wrap OBJ_aes,25L - -#define SN_aes_192_gcm "id-aes192-GCM" -#define LN_aes_192_gcm "aes-192-gcm" -#define NID_aes_192_gcm 898 -#define OBJ_aes_192_gcm OBJ_aes,26L - -#define SN_aes_192_ccm "id-aes192-CCM" -#define LN_aes_192_ccm "aes-192-ccm" -#define NID_aes_192_ccm 899 -#define OBJ_aes_192_ccm OBJ_aes,27L - -#define SN_id_aes192_wrap_pad "id-aes192-wrap-pad" -#define NID_id_aes192_wrap_pad 900 -#define OBJ_id_aes192_wrap_pad OBJ_aes,28L - -#define SN_aes_256_ecb "AES-256-ECB" -#define LN_aes_256_ecb "aes-256-ecb" -#define NID_aes_256_ecb 426 -#define OBJ_aes_256_ecb OBJ_aes,41L - -#define SN_aes_256_cbc "AES-256-CBC" -#define LN_aes_256_cbc "aes-256-cbc" -#define NID_aes_256_cbc 427 -#define OBJ_aes_256_cbc OBJ_aes,42L - -#define SN_aes_256_ofb128 "AES-256-OFB" -#define LN_aes_256_ofb128 "aes-256-ofb" -#define NID_aes_256_ofb128 428 -#define OBJ_aes_256_ofb128 OBJ_aes,43L - -#define SN_aes_256_cfb128 "AES-256-CFB" -#define LN_aes_256_cfb128 "aes-256-cfb" -#define NID_aes_256_cfb128 429 -#define OBJ_aes_256_cfb128 OBJ_aes,44L - -#define SN_id_aes256_wrap "id-aes256-wrap" -#define NID_id_aes256_wrap 790 -#define OBJ_id_aes256_wrap OBJ_aes,45L - -#define SN_aes_256_gcm "id-aes256-GCM" -#define LN_aes_256_gcm "aes-256-gcm" -#define NID_aes_256_gcm 901 -#define OBJ_aes_256_gcm OBJ_aes,46L - -#define SN_aes_256_ccm "id-aes256-CCM" -#define LN_aes_256_ccm "aes-256-ccm" -#define NID_aes_256_ccm 902 -#define OBJ_aes_256_ccm OBJ_aes,47L - -#define SN_id_aes256_wrap_pad "id-aes256-wrap-pad" -#define NID_id_aes256_wrap_pad 903 -#define OBJ_id_aes256_wrap_pad OBJ_aes,48L - -#define SN_aes_128_cfb1 "AES-128-CFB1" -#define LN_aes_128_cfb1 "aes-128-cfb1" -#define NID_aes_128_cfb1 650 - -#define SN_aes_192_cfb1 "AES-192-CFB1" -#define LN_aes_192_cfb1 "aes-192-cfb1" -#define NID_aes_192_cfb1 651 - -#define SN_aes_256_cfb1 "AES-256-CFB1" -#define LN_aes_256_cfb1 "aes-256-cfb1" -#define NID_aes_256_cfb1 652 - -#define SN_aes_128_cfb8 "AES-128-CFB8" -#define LN_aes_128_cfb8 "aes-128-cfb8" -#define NID_aes_128_cfb8 653 - -#define SN_aes_192_cfb8 "AES-192-CFB8" -#define LN_aes_192_cfb8 "aes-192-cfb8" -#define NID_aes_192_cfb8 654 - -#define SN_aes_256_cfb8 "AES-256-CFB8" -#define LN_aes_256_cfb8 "aes-256-cfb8" -#define NID_aes_256_cfb8 655 - -#define SN_aes_128_ctr "AES-128-CTR" -#define LN_aes_128_ctr "aes-128-ctr" -#define NID_aes_128_ctr 904 - -#define SN_aes_192_ctr "AES-192-CTR" -#define LN_aes_192_ctr "aes-192-ctr" -#define NID_aes_192_ctr 905 - -#define SN_aes_256_ctr "AES-256-CTR" -#define LN_aes_256_ctr "aes-256-ctr" -#define NID_aes_256_ctr 906 - -#define SN_aes_128_xts "AES-128-XTS" -#define LN_aes_128_xts "aes-128-xts" -#define NID_aes_128_xts 913 - -#define SN_aes_256_xts "AES-256-XTS" -#define LN_aes_256_xts "aes-256-xts" -#define NID_aes_256_xts 914 - -#define SN_des_cfb1 "DES-CFB1" -#define LN_des_cfb1 "des-cfb1" -#define NID_des_cfb1 656 - -#define SN_des_cfb8 "DES-CFB8" -#define LN_des_cfb8 "des-cfb8" -#define NID_des_cfb8 657 - -#define SN_des_ede3_cfb1 "DES-EDE3-CFB1" -#define LN_des_ede3_cfb1 "des-ede3-cfb1" -#define NID_des_ede3_cfb1 658 - -#define SN_des_ede3_cfb8 "DES-EDE3-CFB8" -#define LN_des_ede3_cfb8 "des-ede3-cfb8" -#define NID_des_ede3_cfb8 659 - -#define OBJ_nist_hashalgs OBJ_nistAlgorithms,2L - -#define SN_sha256 "SHA256" -#define LN_sha256 "sha256" -#define NID_sha256 672 -#define OBJ_sha256 OBJ_nist_hashalgs,1L - -#define SN_sha384 "SHA384" -#define LN_sha384 "sha384" -#define NID_sha384 673 -#define OBJ_sha384 OBJ_nist_hashalgs,2L - -#define SN_sha512 "SHA512" -#define LN_sha512 "sha512" -#define NID_sha512 674 -#define OBJ_sha512 OBJ_nist_hashalgs,3L - -#define SN_sha224 "SHA224" -#define LN_sha224 "sha224" -#define NID_sha224 675 -#define OBJ_sha224 OBJ_nist_hashalgs,4L - -#define OBJ_dsa_with_sha2 OBJ_nistAlgorithms,3L - -#define SN_dsa_with_SHA224 "dsa_with_SHA224" -#define NID_dsa_with_SHA224 802 -#define OBJ_dsa_with_SHA224 OBJ_dsa_with_sha2,1L - -#define SN_dsa_with_SHA256 "dsa_with_SHA256" -#define NID_dsa_with_SHA256 803 -#define OBJ_dsa_with_SHA256 OBJ_dsa_with_sha2,2L - -#define SN_hold_instruction_code "holdInstructionCode" -#define LN_hold_instruction_code "Hold Instruction Code" -#define NID_hold_instruction_code 430 -#define OBJ_hold_instruction_code OBJ_id_ce,23L - -#define OBJ_holdInstruction OBJ_X9_57,2L - -#define SN_hold_instruction_none "holdInstructionNone" -#define LN_hold_instruction_none "Hold Instruction None" -#define NID_hold_instruction_none 431 -#define OBJ_hold_instruction_none OBJ_holdInstruction,1L - -#define SN_hold_instruction_call_issuer "holdInstructionCallIssuer" -#define LN_hold_instruction_call_issuer "Hold Instruction Call Issuer" -#define NID_hold_instruction_call_issuer 432 -#define OBJ_hold_instruction_call_issuer OBJ_holdInstruction,2L - -#define SN_hold_instruction_reject "holdInstructionReject" -#define LN_hold_instruction_reject "Hold Instruction Reject" -#define NID_hold_instruction_reject 433 -#define OBJ_hold_instruction_reject OBJ_holdInstruction,3L - -#define SN_data "data" -#define NID_data 434 -#define OBJ_data OBJ_itu_t,9L - -#define SN_pss "pss" -#define NID_pss 435 -#define OBJ_pss OBJ_data,2342L - -#define SN_ucl "ucl" -#define NID_ucl 436 -#define OBJ_ucl OBJ_pss,19200300L - -#define SN_pilot "pilot" -#define NID_pilot 437 -#define OBJ_pilot OBJ_ucl,100L - -#define LN_pilotAttributeType "pilotAttributeType" -#define NID_pilotAttributeType 438 -#define OBJ_pilotAttributeType OBJ_pilot,1L - -#define LN_pilotAttributeSyntax "pilotAttributeSyntax" -#define NID_pilotAttributeSyntax 439 -#define OBJ_pilotAttributeSyntax OBJ_pilot,3L - -#define LN_pilotObjectClass "pilotObjectClass" -#define NID_pilotObjectClass 440 -#define OBJ_pilotObjectClass OBJ_pilot,4L - -#define LN_pilotGroups "pilotGroups" -#define NID_pilotGroups 441 -#define OBJ_pilotGroups OBJ_pilot,10L - -#define LN_iA5StringSyntax "iA5StringSyntax" -#define NID_iA5StringSyntax 442 -#define OBJ_iA5StringSyntax OBJ_pilotAttributeSyntax,4L - -#define LN_caseIgnoreIA5StringSyntax "caseIgnoreIA5StringSyntax" -#define NID_caseIgnoreIA5StringSyntax 443 -#define OBJ_caseIgnoreIA5StringSyntax OBJ_pilotAttributeSyntax,5L - -#define LN_pilotObject "pilotObject" -#define NID_pilotObject 444 -#define OBJ_pilotObject OBJ_pilotObjectClass,3L - -#define LN_pilotPerson "pilotPerson" -#define NID_pilotPerson 445 -#define OBJ_pilotPerson OBJ_pilotObjectClass,4L - -#define SN_account "account" -#define NID_account 446 -#define OBJ_account OBJ_pilotObjectClass,5L - -#define SN_document "document" -#define NID_document 447 -#define OBJ_document OBJ_pilotObjectClass,6L - -#define SN_room "room" -#define NID_room 448 -#define OBJ_room OBJ_pilotObjectClass,7L - -#define LN_documentSeries "documentSeries" -#define NID_documentSeries 449 -#define OBJ_documentSeries OBJ_pilotObjectClass,9L - -#define SN_Domain "domain" -#define LN_Domain "Domain" -#define NID_Domain 392 -#define OBJ_Domain OBJ_pilotObjectClass,13L - -#define LN_rFC822localPart "rFC822localPart" -#define NID_rFC822localPart 450 -#define OBJ_rFC822localPart OBJ_pilotObjectClass,14L - -#define LN_dNSDomain "dNSDomain" -#define NID_dNSDomain 451 -#define OBJ_dNSDomain OBJ_pilotObjectClass,15L - -#define LN_domainRelatedObject "domainRelatedObject" -#define NID_domainRelatedObject 452 -#define OBJ_domainRelatedObject OBJ_pilotObjectClass,17L - -#define LN_friendlyCountry "friendlyCountry" -#define NID_friendlyCountry 453 -#define OBJ_friendlyCountry OBJ_pilotObjectClass,18L - -#define LN_simpleSecurityObject "simpleSecurityObject" -#define NID_simpleSecurityObject 454 -#define OBJ_simpleSecurityObject OBJ_pilotObjectClass,19L - -#define LN_pilotOrganization "pilotOrganization" -#define NID_pilotOrganization 455 -#define OBJ_pilotOrganization OBJ_pilotObjectClass,20L - -#define LN_pilotDSA "pilotDSA" -#define NID_pilotDSA 456 -#define OBJ_pilotDSA OBJ_pilotObjectClass,21L - -#define LN_qualityLabelledData "qualityLabelledData" -#define NID_qualityLabelledData 457 -#define OBJ_qualityLabelledData OBJ_pilotObjectClass,22L - -#define SN_userId "UID" -#define LN_userId "userId" -#define NID_userId 458 -#define OBJ_userId OBJ_pilotAttributeType,1L - -#define LN_textEncodedORAddress "textEncodedORAddress" -#define NID_textEncodedORAddress 459 -#define OBJ_textEncodedORAddress OBJ_pilotAttributeType,2L - -#define SN_rfc822Mailbox "mail" -#define LN_rfc822Mailbox "rfc822Mailbox" -#define NID_rfc822Mailbox 460 -#define OBJ_rfc822Mailbox OBJ_pilotAttributeType,3L - -#define SN_info "info" -#define NID_info 461 -#define OBJ_info OBJ_pilotAttributeType,4L - -#define LN_favouriteDrink "favouriteDrink" -#define NID_favouriteDrink 462 -#define OBJ_favouriteDrink OBJ_pilotAttributeType,5L - -#define LN_roomNumber "roomNumber" -#define NID_roomNumber 463 -#define OBJ_roomNumber OBJ_pilotAttributeType,6L - -#define SN_photo "photo" -#define NID_photo 464 -#define OBJ_photo OBJ_pilotAttributeType,7L - -#define LN_userClass "userClass" -#define NID_userClass 465 -#define OBJ_userClass OBJ_pilotAttributeType,8L - -#define SN_host "host" -#define NID_host 466 -#define OBJ_host OBJ_pilotAttributeType,9L - -#define SN_manager "manager" -#define NID_manager 467 -#define OBJ_manager OBJ_pilotAttributeType,10L - -#define LN_documentIdentifier "documentIdentifier" -#define NID_documentIdentifier 468 -#define OBJ_documentIdentifier OBJ_pilotAttributeType,11L - -#define LN_documentTitle "documentTitle" -#define NID_documentTitle 469 -#define OBJ_documentTitle OBJ_pilotAttributeType,12L - -#define LN_documentVersion "documentVersion" -#define NID_documentVersion 470 -#define OBJ_documentVersion OBJ_pilotAttributeType,13L - -#define LN_documentAuthor "documentAuthor" -#define NID_documentAuthor 471 -#define OBJ_documentAuthor OBJ_pilotAttributeType,14L - -#define LN_documentLocation "documentLocation" -#define NID_documentLocation 472 -#define OBJ_documentLocation OBJ_pilotAttributeType,15L - -#define LN_homeTelephoneNumber "homeTelephoneNumber" -#define NID_homeTelephoneNumber 473 -#define OBJ_homeTelephoneNumber OBJ_pilotAttributeType,20L - -#define SN_secretary "secretary" -#define NID_secretary 474 -#define OBJ_secretary OBJ_pilotAttributeType,21L - -#define LN_otherMailbox "otherMailbox" -#define NID_otherMailbox 475 -#define OBJ_otherMailbox OBJ_pilotAttributeType,22L - -#define LN_lastModifiedTime "lastModifiedTime" -#define NID_lastModifiedTime 476 -#define OBJ_lastModifiedTime OBJ_pilotAttributeType,23L - -#define LN_lastModifiedBy "lastModifiedBy" -#define NID_lastModifiedBy 477 -#define OBJ_lastModifiedBy OBJ_pilotAttributeType,24L - -#define SN_domainComponent "DC" -#define LN_domainComponent "domainComponent" -#define NID_domainComponent 391 -#define OBJ_domainComponent OBJ_pilotAttributeType,25L - -#define LN_aRecord "aRecord" -#define NID_aRecord 478 -#define OBJ_aRecord OBJ_pilotAttributeType,26L - -#define LN_pilotAttributeType27 "pilotAttributeType27" -#define NID_pilotAttributeType27 479 -#define OBJ_pilotAttributeType27 OBJ_pilotAttributeType,27L - -#define LN_mXRecord "mXRecord" -#define NID_mXRecord 480 -#define OBJ_mXRecord OBJ_pilotAttributeType,28L - -#define LN_nSRecord "nSRecord" -#define NID_nSRecord 481 -#define OBJ_nSRecord OBJ_pilotAttributeType,29L - -#define LN_sOARecord "sOARecord" -#define NID_sOARecord 482 -#define OBJ_sOARecord OBJ_pilotAttributeType,30L - -#define LN_cNAMERecord "cNAMERecord" -#define NID_cNAMERecord 483 -#define OBJ_cNAMERecord OBJ_pilotAttributeType,31L - -#define LN_associatedDomain "associatedDomain" -#define NID_associatedDomain 484 -#define OBJ_associatedDomain OBJ_pilotAttributeType,37L - -#define LN_associatedName "associatedName" -#define NID_associatedName 485 -#define OBJ_associatedName OBJ_pilotAttributeType,38L - -#define LN_homePostalAddress "homePostalAddress" -#define NID_homePostalAddress 486 -#define OBJ_homePostalAddress OBJ_pilotAttributeType,39L - -#define LN_personalTitle "personalTitle" -#define NID_personalTitle 487 -#define OBJ_personalTitle OBJ_pilotAttributeType,40L - -#define LN_mobileTelephoneNumber "mobileTelephoneNumber" -#define NID_mobileTelephoneNumber 488 -#define OBJ_mobileTelephoneNumber OBJ_pilotAttributeType,41L - -#define LN_pagerTelephoneNumber "pagerTelephoneNumber" -#define NID_pagerTelephoneNumber 489 -#define OBJ_pagerTelephoneNumber OBJ_pilotAttributeType,42L - -#define LN_friendlyCountryName "friendlyCountryName" -#define NID_friendlyCountryName 490 -#define OBJ_friendlyCountryName OBJ_pilotAttributeType,43L - -#define LN_organizationalStatus "organizationalStatus" -#define NID_organizationalStatus 491 -#define OBJ_organizationalStatus OBJ_pilotAttributeType,45L - -#define LN_janetMailbox "janetMailbox" -#define NID_janetMailbox 492 -#define OBJ_janetMailbox OBJ_pilotAttributeType,46L - -#define LN_mailPreferenceOption "mailPreferenceOption" -#define NID_mailPreferenceOption 493 -#define OBJ_mailPreferenceOption OBJ_pilotAttributeType,47L - -#define LN_buildingName "buildingName" -#define NID_buildingName 494 -#define OBJ_buildingName OBJ_pilotAttributeType,48L - -#define LN_dSAQuality "dSAQuality" -#define NID_dSAQuality 495 -#define OBJ_dSAQuality OBJ_pilotAttributeType,49L - -#define LN_singleLevelQuality "singleLevelQuality" -#define NID_singleLevelQuality 496 -#define OBJ_singleLevelQuality OBJ_pilotAttributeType,50L - -#define LN_subtreeMinimumQuality "subtreeMinimumQuality" -#define NID_subtreeMinimumQuality 497 -#define OBJ_subtreeMinimumQuality OBJ_pilotAttributeType,51L - -#define LN_subtreeMaximumQuality "subtreeMaximumQuality" -#define NID_subtreeMaximumQuality 498 -#define OBJ_subtreeMaximumQuality OBJ_pilotAttributeType,52L - -#define LN_personalSignature "personalSignature" -#define NID_personalSignature 499 -#define OBJ_personalSignature OBJ_pilotAttributeType,53L - -#define LN_dITRedirect "dITRedirect" -#define NID_dITRedirect 500 -#define OBJ_dITRedirect OBJ_pilotAttributeType,54L - -#define SN_audio "audio" -#define NID_audio 501 -#define OBJ_audio OBJ_pilotAttributeType,55L - -#define LN_documentPublisher "documentPublisher" -#define NID_documentPublisher 502 -#define OBJ_documentPublisher OBJ_pilotAttributeType,56L - -#define SN_id_set "id-set" -#define LN_id_set "Secure Electronic Transactions" -#define NID_id_set 512 -#define OBJ_id_set OBJ_international_organizations,42L - -#define SN_set_ctype "set-ctype" -#define LN_set_ctype "content types" -#define NID_set_ctype 513 -#define OBJ_set_ctype OBJ_id_set,0L - -#define SN_set_msgExt "set-msgExt" -#define LN_set_msgExt "message extensions" -#define NID_set_msgExt 514 -#define OBJ_set_msgExt OBJ_id_set,1L - -#define SN_set_attr "set-attr" -#define NID_set_attr 515 -#define OBJ_set_attr OBJ_id_set,3L - -#define SN_set_policy "set-policy" -#define NID_set_policy 516 -#define OBJ_set_policy OBJ_id_set,5L - -#define SN_set_certExt "set-certExt" -#define LN_set_certExt "certificate extensions" -#define NID_set_certExt 517 -#define OBJ_set_certExt OBJ_id_set,7L - -#define SN_set_brand "set-brand" -#define NID_set_brand 518 -#define OBJ_set_brand OBJ_id_set,8L - -#define SN_setct_PANData "setct-PANData" -#define NID_setct_PANData 519 -#define OBJ_setct_PANData OBJ_set_ctype,0L - -#define SN_setct_PANToken "setct-PANToken" -#define NID_setct_PANToken 520 -#define OBJ_setct_PANToken OBJ_set_ctype,1L - -#define SN_setct_PANOnly "setct-PANOnly" -#define NID_setct_PANOnly 521 -#define OBJ_setct_PANOnly OBJ_set_ctype,2L - -#define SN_setct_OIData "setct-OIData" -#define NID_setct_OIData 522 -#define OBJ_setct_OIData OBJ_set_ctype,3L - -#define SN_setct_PI "setct-PI" -#define NID_setct_PI 523 -#define OBJ_setct_PI OBJ_set_ctype,4L - -#define SN_setct_PIData "setct-PIData" -#define NID_setct_PIData 524 -#define OBJ_setct_PIData OBJ_set_ctype,5L - -#define SN_setct_PIDataUnsigned "setct-PIDataUnsigned" -#define NID_setct_PIDataUnsigned 525 -#define OBJ_setct_PIDataUnsigned OBJ_set_ctype,6L - -#define SN_setct_HODInput "setct-HODInput" -#define NID_setct_HODInput 526 -#define OBJ_setct_HODInput OBJ_set_ctype,7L - -#define SN_setct_AuthResBaggage "setct-AuthResBaggage" -#define NID_setct_AuthResBaggage 527 -#define OBJ_setct_AuthResBaggage OBJ_set_ctype,8L - -#define SN_setct_AuthRevReqBaggage "setct-AuthRevReqBaggage" -#define NID_setct_AuthRevReqBaggage 528 -#define OBJ_setct_AuthRevReqBaggage OBJ_set_ctype,9L - -#define SN_setct_AuthRevResBaggage "setct-AuthRevResBaggage" -#define NID_setct_AuthRevResBaggage 529 -#define OBJ_setct_AuthRevResBaggage OBJ_set_ctype,10L - -#define SN_setct_CapTokenSeq "setct-CapTokenSeq" -#define NID_setct_CapTokenSeq 530 -#define OBJ_setct_CapTokenSeq OBJ_set_ctype,11L - -#define SN_setct_PInitResData "setct-PInitResData" -#define NID_setct_PInitResData 531 -#define OBJ_setct_PInitResData OBJ_set_ctype,12L - -#define SN_setct_PI_TBS "setct-PI-TBS" -#define NID_setct_PI_TBS 532 -#define OBJ_setct_PI_TBS OBJ_set_ctype,13L - -#define SN_setct_PResData "setct-PResData" -#define NID_setct_PResData 533 -#define OBJ_setct_PResData OBJ_set_ctype,14L - -#define SN_setct_AuthReqTBS "setct-AuthReqTBS" -#define NID_setct_AuthReqTBS 534 -#define OBJ_setct_AuthReqTBS OBJ_set_ctype,16L - -#define SN_setct_AuthResTBS "setct-AuthResTBS" -#define NID_setct_AuthResTBS 535 -#define OBJ_setct_AuthResTBS OBJ_set_ctype,17L - -#define SN_setct_AuthResTBSX "setct-AuthResTBSX" -#define NID_setct_AuthResTBSX 536 -#define OBJ_setct_AuthResTBSX OBJ_set_ctype,18L - -#define SN_setct_AuthTokenTBS "setct-AuthTokenTBS" -#define NID_setct_AuthTokenTBS 537 -#define OBJ_setct_AuthTokenTBS OBJ_set_ctype,19L - -#define SN_setct_CapTokenData "setct-CapTokenData" -#define NID_setct_CapTokenData 538 -#define OBJ_setct_CapTokenData OBJ_set_ctype,20L - -#define SN_setct_CapTokenTBS "setct-CapTokenTBS" -#define NID_setct_CapTokenTBS 539 -#define OBJ_setct_CapTokenTBS OBJ_set_ctype,21L - -#define SN_setct_AcqCardCodeMsg "setct-AcqCardCodeMsg" -#define NID_setct_AcqCardCodeMsg 540 -#define OBJ_setct_AcqCardCodeMsg OBJ_set_ctype,22L - -#define SN_setct_AuthRevReqTBS "setct-AuthRevReqTBS" -#define NID_setct_AuthRevReqTBS 541 -#define OBJ_setct_AuthRevReqTBS OBJ_set_ctype,23L - -#define SN_setct_AuthRevResData "setct-AuthRevResData" -#define NID_setct_AuthRevResData 542 -#define OBJ_setct_AuthRevResData OBJ_set_ctype,24L - -#define SN_setct_AuthRevResTBS "setct-AuthRevResTBS" -#define NID_setct_AuthRevResTBS 543 -#define OBJ_setct_AuthRevResTBS OBJ_set_ctype,25L - -#define SN_setct_CapReqTBS "setct-CapReqTBS" -#define NID_setct_CapReqTBS 544 -#define OBJ_setct_CapReqTBS OBJ_set_ctype,26L - -#define SN_setct_CapReqTBSX "setct-CapReqTBSX" -#define NID_setct_CapReqTBSX 545 -#define OBJ_setct_CapReqTBSX OBJ_set_ctype,27L - -#define SN_setct_CapResData "setct-CapResData" -#define NID_setct_CapResData 546 -#define OBJ_setct_CapResData OBJ_set_ctype,28L - -#define SN_setct_CapRevReqTBS "setct-CapRevReqTBS" -#define NID_setct_CapRevReqTBS 547 -#define OBJ_setct_CapRevReqTBS OBJ_set_ctype,29L - -#define SN_setct_CapRevReqTBSX "setct-CapRevReqTBSX" -#define NID_setct_CapRevReqTBSX 548 -#define OBJ_setct_CapRevReqTBSX OBJ_set_ctype,30L - -#define SN_setct_CapRevResData "setct-CapRevResData" -#define NID_setct_CapRevResData 549 -#define OBJ_setct_CapRevResData OBJ_set_ctype,31L - -#define SN_setct_CredReqTBS "setct-CredReqTBS" -#define NID_setct_CredReqTBS 550 -#define OBJ_setct_CredReqTBS OBJ_set_ctype,32L - -#define SN_setct_CredReqTBSX "setct-CredReqTBSX" -#define NID_setct_CredReqTBSX 551 -#define OBJ_setct_CredReqTBSX OBJ_set_ctype,33L - -#define SN_setct_CredResData "setct-CredResData" -#define NID_setct_CredResData 552 -#define OBJ_setct_CredResData OBJ_set_ctype,34L - -#define SN_setct_CredRevReqTBS "setct-CredRevReqTBS" -#define NID_setct_CredRevReqTBS 553 -#define OBJ_setct_CredRevReqTBS OBJ_set_ctype,35L - -#define SN_setct_CredRevReqTBSX "setct-CredRevReqTBSX" -#define NID_setct_CredRevReqTBSX 554 -#define OBJ_setct_CredRevReqTBSX OBJ_set_ctype,36L - -#define SN_setct_CredRevResData "setct-CredRevResData" -#define NID_setct_CredRevResData 555 -#define OBJ_setct_CredRevResData OBJ_set_ctype,37L - -#define SN_setct_PCertReqData "setct-PCertReqData" -#define NID_setct_PCertReqData 556 -#define OBJ_setct_PCertReqData OBJ_set_ctype,38L - -#define SN_setct_PCertResTBS "setct-PCertResTBS" -#define NID_setct_PCertResTBS 557 -#define OBJ_setct_PCertResTBS OBJ_set_ctype,39L - -#define SN_setct_BatchAdminReqData "setct-BatchAdminReqData" -#define NID_setct_BatchAdminReqData 558 -#define OBJ_setct_BatchAdminReqData OBJ_set_ctype,40L - -#define SN_setct_BatchAdminResData "setct-BatchAdminResData" -#define NID_setct_BatchAdminResData 559 -#define OBJ_setct_BatchAdminResData OBJ_set_ctype,41L - -#define SN_setct_CardCInitResTBS "setct-CardCInitResTBS" -#define NID_setct_CardCInitResTBS 560 -#define OBJ_setct_CardCInitResTBS OBJ_set_ctype,42L - -#define SN_setct_MeAqCInitResTBS "setct-MeAqCInitResTBS" -#define NID_setct_MeAqCInitResTBS 561 -#define OBJ_setct_MeAqCInitResTBS OBJ_set_ctype,43L - -#define SN_setct_RegFormResTBS "setct-RegFormResTBS" -#define NID_setct_RegFormResTBS 562 -#define OBJ_setct_RegFormResTBS OBJ_set_ctype,44L - -#define SN_setct_CertReqData "setct-CertReqData" -#define NID_setct_CertReqData 563 -#define OBJ_setct_CertReqData OBJ_set_ctype,45L - -#define SN_setct_CertReqTBS "setct-CertReqTBS" -#define NID_setct_CertReqTBS 564 -#define OBJ_setct_CertReqTBS OBJ_set_ctype,46L - -#define SN_setct_CertResData "setct-CertResData" -#define NID_setct_CertResData 565 -#define OBJ_setct_CertResData OBJ_set_ctype,47L - -#define SN_setct_CertInqReqTBS "setct-CertInqReqTBS" -#define NID_setct_CertInqReqTBS 566 -#define OBJ_setct_CertInqReqTBS OBJ_set_ctype,48L - -#define SN_setct_ErrorTBS "setct-ErrorTBS" -#define NID_setct_ErrorTBS 567 -#define OBJ_setct_ErrorTBS OBJ_set_ctype,49L - -#define SN_setct_PIDualSignedTBE "setct-PIDualSignedTBE" -#define NID_setct_PIDualSignedTBE 568 -#define OBJ_setct_PIDualSignedTBE OBJ_set_ctype,50L - -#define SN_setct_PIUnsignedTBE "setct-PIUnsignedTBE" -#define NID_setct_PIUnsignedTBE 569 -#define OBJ_setct_PIUnsignedTBE OBJ_set_ctype,51L - -#define SN_setct_AuthReqTBE "setct-AuthReqTBE" -#define NID_setct_AuthReqTBE 570 -#define OBJ_setct_AuthReqTBE OBJ_set_ctype,52L - -#define SN_setct_AuthResTBE "setct-AuthResTBE" -#define NID_setct_AuthResTBE 571 -#define OBJ_setct_AuthResTBE OBJ_set_ctype,53L - -#define SN_setct_AuthResTBEX "setct-AuthResTBEX" -#define NID_setct_AuthResTBEX 572 -#define OBJ_setct_AuthResTBEX OBJ_set_ctype,54L - -#define SN_setct_AuthTokenTBE "setct-AuthTokenTBE" -#define NID_setct_AuthTokenTBE 573 -#define OBJ_setct_AuthTokenTBE OBJ_set_ctype,55L - -#define SN_setct_CapTokenTBE "setct-CapTokenTBE" -#define NID_setct_CapTokenTBE 574 -#define OBJ_setct_CapTokenTBE OBJ_set_ctype,56L - -#define SN_setct_CapTokenTBEX "setct-CapTokenTBEX" -#define NID_setct_CapTokenTBEX 575 -#define OBJ_setct_CapTokenTBEX OBJ_set_ctype,57L - -#define SN_setct_AcqCardCodeMsgTBE "setct-AcqCardCodeMsgTBE" -#define NID_setct_AcqCardCodeMsgTBE 576 -#define OBJ_setct_AcqCardCodeMsgTBE OBJ_set_ctype,58L - -#define SN_setct_AuthRevReqTBE "setct-AuthRevReqTBE" -#define NID_setct_AuthRevReqTBE 577 -#define OBJ_setct_AuthRevReqTBE OBJ_set_ctype,59L - -#define SN_setct_AuthRevResTBE "setct-AuthRevResTBE" -#define NID_setct_AuthRevResTBE 578 -#define OBJ_setct_AuthRevResTBE OBJ_set_ctype,60L - -#define SN_setct_AuthRevResTBEB "setct-AuthRevResTBEB" -#define NID_setct_AuthRevResTBEB 579 -#define OBJ_setct_AuthRevResTBEB OBJ_set_ctype,61L - -#define SN_setct_CapReqTBE "setct-CapReqTBE" -#define NID_setct_CapReqTBE 580 -#define OBJ_setct_CapReqTBE OBJ_set_ctype,62L - -#define SN_setct_CapReqTBEX "setct-CapReqTBEX" -#define NID_setct_CapReqTBEX 581 -#define OBJ_setct_CapReqTBEX OBJ_set_ctype,63L - -#define SN_setct_CapResTBE "setct-CapResTBE" -#define NID_setct_CapResTBE 582 -#define OBJ_setct_CapResTBE OBJ_set_ctype,64L - -#define SN_setct_CapRevReqTBE "setct-CapRevReqTBE" -#define NID_setct_CapRevReqTBE 583 -#define OBJ_setct_CapRevReqTBE OBJ_set_ctype,65L - -#define SN_setct_CapRevReqTBEX "setct-CapRevReqTBEX" -#define NID_setct_CapRevReqTBEX 584 -#define OBJ_setct_CapRevReqTBEX OBJ_set_ctype,66L - -#define SN_setct_CapRevResTBE "setct-CapRevResTBE" -#define NID_setct_CapRevResTBE 585 -#define OBJ_setct_CapRevResTBE OBJ_set_ctype,67L - -#define SN_setct_CredReqTBE "setct-CredReqTBE" -#define NID_setct_CredReqTBE 586 -#define OBJ_setct_CredReqTBE OBJ_set_ctype,68L - -#define SN_setct_CredReqTBEX "setct-CredReqTBEX" -#define NID_setct_CredReqTBEX 587 -#define OBJ_setct_CredReqTBEX OBJ_set_ctype,69L - -#define SN_setct_CredResTBE "setct-CredResTBE" -#define NID_setct_CredResTBE 588 -#define OBJ_setct_CredResTBE OBJ_set_ctype,70L - -#define SN_setct_CredRevReqTBE "setct-CredRevReqTBE" -#define NID_setct_CredRevReqTBE 589 -#define OBJ_setct_CredRevReqTBE OBJ_set_ctype,71L - -#define SN_setct_CredRevReqTBEX "setct-CredRevReqTBEX" -#define NID_setct_CredRevReqTBEX 590 -#define OBJ_setct_CredRevReqTBEX OBJ_set_ctype,72L - -#define SN_setct_CredRevResTBE "setct-CredRevResTBE" -#define NID_setct_CredRevResTBE 591 -#define OBJ_setct_CredRevResTBE OBJ_set_ctype,73L - -#define SN_setct_BatchAdminReqTBE "setct-BatchAdminReqTBE" -#define NID_setct_BatchAdminReqTBE 592 -#define OBJ_setct_BatchAdminReqTBE OBJ_set_ctype,74L - -#define SN_setct_BatchAdminResTBE "setct-BatchAdminResTBE" -#define NID_setct_BatchAdminResTBE 593 -#define OBJ_setct_BatchAdminResTBE OBJ_set_ctype,75L - -#define SN_setct_RegFormReqTBE "setct-RegFormReqTBE" -#define NID_setct_RegFormReqTBE 594 -#define OBJ_setct_RegFormReqTBE OBJ_set_ctype,76L - -#define SN_setct_CertReqTBE "setct-CertReqTBE" -#define NID_setct_CertReqTBE 595 -#define OBJ_setct_CertReqTBE OBJ_set_ctype,77L - -#define SN_setct_CertReqTBEX "setct-CertReqTBEX" -#define NID_setct_CertReqTBEX 596 -#define OBJ_setct_CertReqTBEX OBJ_set_ctype,78L - -#define SN_setct_CertResTBE "setct-CertResTBE" -#define NID_setct_CertResTBE 597 -#define OBJ_setct_CertResTBE OBJ_set_ctype,79L - -#define SN_setct_CRLNotificationTBS "setct-CRLNotificationTBS" -#define NID_setct_CRLNotificationTBS 598 -#define OBJ_setct_CRLNotificationTBS OBJ_set_ctype,80L - -#define SN_setct_CRLNotificationResTBS "setct-CRLNotificationResTBS" -#define NID_setct_CRLNotificationResTBS 599 -#define OBJ_setct_CRLNotificationResTBS OBJ_set_ctype,81L - -#define SN_setct_BCIDistributionTBS "setct-BCIDistributionTBS" -#define NID_setct_BCIDistributionTBS 600 -#define OBJ_setct_BCIDistributionTBS OBJ_set_ctype,82L - -#define SN_setext_genCrypt "setext-genCrypt" -#define LN_setext_genCrypt "generic cryptogram" -#define NID_setext_genCrypt 601 -#define OBJ_setext_genCrypt OBJ_set_msgExt,1L - -#define SN_setext_miAuth "setext-miAuth" -#define LN_setext_miAuth "merchant initiated auth" -#define NID_setext_miAuth 602 -#define OBJ_setext_miAuth OBJ_set_msgExt,3L - -#define SN_setext_pinSecure "setext-pinSecure" -#define NID_setext_pinSecure 603 -#define OBJ_setext_pinSecure OBJ_set_msgExt,4L - -#define SN_setext_pinAny "setext-pinAny" -#define NID_setext_pinAny 604 -#define OBJ_setext_pinAny OBJ_set_msgExt,5L - -#define SN_setext_track2 "setext-track2" -#define NID_setext_track2 605 -#define OBJ_setext_track2 OBJ_set_msgExt,7L - -#define SN_setext_cv "setext-cv" -#define LN_setext_cv "additional verification" -#define NID_setext_cv 606 -#define OBJ_setext_cv OBJ_set_msgExt,8L - -#define SN_set_policy_root "set-policy-root" -#define NID_set_policy_root 607 -#define OBJ_set_policy_root OBJ_set_policy,0L - -#define SN_setCext_hashedRoot "setCext-hashedRoot" -#define NID_setCext_hashedRoot 608 -#define OBJ_setCext_hashedRoot OBJ_set_certExt,0L - -#define SN_setCext_certType "setCext-certType" -#define NID_setCext_certType 609 -#define OBJ_setCext_certType OBJ_set_certExt,1L - -#define SN_setCext_merchData "setCext-merchData" -#define NID_setCext_merchData 610 -#define OBJ_setCext_merchData OBJ_set_certExt,2L - -#define SN_setCext_cCertRequired "setCext-cCertRequired" -#define NID_setCext_cCertRequired 611 -#define OBJ_setCext_cCertRequired OBJ_set_certExt,3L - -#define SN_setCext_tunneling "setCext-tunneling" -#define NID_setCext_tunneling 612 -#define OBJ_setCext_tunneling OBJ_set_certExt,4L - -#define SN_setCext_setExt "setCext-setExt" -#define NID_setCext_setExt 613 -#define OBJ_setCext_setExt OBJ_set_certExt,5L - -#define SN_setCext_setQualf "setCext-setQualf" -#define NID_setCext_setQualf 614 -#define OBJ_setCext_setQualf OBJ_set_certExt,6L - -#define SN_setCext_PGWYcapabilities "setCext-PGWYcapabilities" -#define NID_setCext_PGWYcapabilities 615 -#define OBJ_setCext_PGWYcapabilities OBJ_set_certExt,7L - -#define SN_setCext_TokenIdentifier "setCext-TokenIdentifier" -#define NID_setCext_TokenIdentifier 616 -#define OBJ_setCext_TokenIdentifier OBJ_set_certExt,8L - -#define SN_setCext_Track2Data "setCext-Track2Data" -#define NID_setCext_Track2Data 617 -#define OBJ_setCext_Track2Data OBJ_set_certExt,9L - -#define SN_setCext_TokenType "setCext-TokenType" -#define NID_setCext_TokenType 618 -#define OBJ_setCext_TokenType OBJ_set_certExt,10L - -#define SN_setCext_IssuerCapabilities "setCext-IssuerCapabilities" -#define NID_setCext_IssuerCapabilities 619 -#define OBJ_setCext_IssuerCapabilities OBJ_set_certExt,11L - -#define SN_setAttr_Cert "setAttr-Cert" -#define NID_setAttr_Cert 620 -#define OBJ_setAttr_Cert OBJ_set_attr,0L - -#define SN_setAttr_PGWYcap "setAttr-PGWYcap" -#define LN_setAttr_PGWYcap "payment gateway capabilities" -#define NID_setAttr_PGWYcap 621 -#define OBJ_setAttr_PGWYcap OBJ_set_attr,1L - -#define SN_setAttr_TokenType "setAttr-TokenType" -#define NID_setAttr_TokenType 622 -#define OBJ_setAttr_TokenType OBJ_set_attr,2L - -#define SN_setAttr_IssCap "setAttr-IssCap" -#define LN_setAttr_IssCap "issuer capabilities" -#define NID_setAttr_IssCap 623 -#define OBJ_setAttr_IssCap OBJ_set_attr,3L - -#define SN_set_rootKeyThumb "set-rootKeyThumb" -#define NID_set_rootKeyThumb 624 -#define OBJ_set_rootKeyThumb OBJ_setAttr_Cert,0L - -#define SN_set_addPolicy "set-addPolicy" -#define NID_set_addPolicy 625 -#define OBJ_set_addPolicy OBJ_setAttr_Cert,1L - -#define SN_setAttr_Token_EMV "setAttr-Token-EMV" -#define NID_setAttr_Token_EMV 626 -#define OBJ_setAttr_Token_EMV OBJ_setAttr_TokenType,1L - -#define SN_setAttr_Token_B0Prime "setAttr-Token-B0Prime" -#define NID_setAttr_Token_B0Prime 627 -#define OBJ_setAttr_Token_B0Prime OBJ_setAttr_TokenType,2L - -#define SN_setAttr_IssCap_CVM "setAttr-IssCap-CVM" -#define NID_setAttr_IssCap_CVM 628 -#define OBJ_setAttr_IssCap_CVM OBJ_setAttr_IssCap,3L - -#define SN_setAttr_IssCap_T2 "setAttr-IssCap-T2" -#define NID_setAttr_IssCap_T2 629 -#define OBJ_setAttr_IssCap_T2 OBJ_setAttr_IssCap,4L - -#define SN_setAttr_IssCap_Sig "setAttr-IssCap-Sig" -#define NID_setAttr_IssCap_Sig 630 -#define OBJ_setAttr_IssCap_Sig OBJ_setAttr_IssCap,5L - -#define SN_setAttr_GenCryptgrm "setAttr-GenCryptgrm" -#define LN_setAttr_GenCryptgrm "generate cryptogram" -#define NID_setAttr_GenCryptgrm 631 -#define OBJ_setAttr_GenCryptgrm OBJ_setAttr_IssCap_CVM,1L - -#define SN_setAttr_T2Enc "setAttr-T2Enc" -#define LN_setAttr_T2Enc "encrypted track 2" -#define NID_setAttr_T2Enc 632 -#define OBJ_setAttr_T2Enc OBJ_setAttr_IssCap_T2,1L - -#define SN_setAttr_T2cleartxt "setAttr-T2cleartxt" -#define LN_setAttr_T2cleartxt "cleartext track 2" -#define NID_setAttr_T2cleartxt 633 -#define OBJ_setAttr_T2cleartxt OBJ_setAttr_IssCap_T2,2L - -#define SN_setAttr_TokICCsig "setAttr-TokICCsig" -#define LN_setAttr_TokICCsig "ICC or token signature" -#define NID_setAttr_TokICCsig 634 -#define OBJ_setAttr_TokICCsig OBJ_setAttr_IssCap_Sig,1L - -#define SN_setAttr_SecDevSig "setAttr-SecDevSig" -#define LN_setAttr_SecDevSig "secure device signature" -#define NID_setAttr_SecDevSig 635 -#define OBJ_setAttr_SecDevSig OBJ_setAttr_IssCap_Sig,2L - -#define SN_set_brand_IATA_ATA "set-brand-IATA-ATA" -#define NID_set_brand_IATA_ATA 636 -#define OBJ_set_brand_IATA_ATA OBJ_set_brand,1L - -#define SN_set_brand_Diners "set-brand-Diners" -#define NID_set_brand_Diners 637 -#define OBJ_set_brand_Diners OBJ_set_brand,30L - -#define SN_set_brand_AmericanExpress "set-brand-AmericanExpress" -#define NID_set_brand_AmericanExpress 638 -#define OBJ_set_brand_AmericanExpress OBJ_set_brand,34L - -#define SN_set_brand_JCB "set-brand-JCB" -#define NID_set_brand_JCB 639 -#define OBJ_set_brand_JCB OBJ_set_brand,35L - -#define SN_set_brand_Visa "set-brand-Visa" -#define NID_set_brand_Visa 640 -#define OBJ_set_brand_Visa OBJ_set_brand,4L - -#define SN_set_brand_MasterCard "set-brand-MasterCard" -#define NID_set_brand_MasterCard 641 -#define OBJ_set_brand_MasterCard OBJ_set_brand,5L - -#define SN_set_brand_Novus "set-brand-Novus" -#define NID_set_brand_Novus 642 -#define OBJ_set_brand_Novus OBJ_set_brand,6011L - -#define SN_des_cdmf "DES-CDMF" -#define LN_des_cdmf "des-cdmf" -#define NID_des_cdmf 643 -#define OBJ_des_cdmf OBJ_rsadsi,3L,10L - -#define SN_rsaOAEPEncryptionSET "rsaOAEPEncryptionSET" -#define NID_rsaOAEPEncryptionSET 644 -#define OBJ_rsaOAEPEncryptionSET OBJ_rsadsi,1L,1L,6L - -#define SN_ipsec3 "Oakley-EC2N-3" -#define LN_ipsec3 "ipsec3" -#define NID_ipsec3 749 - -#define SN_ipsec4 "Oakley-EC2N-4" -#define LN_ipsec4 "ipsec4" -#define NID_ipsec4 750 - -#define SN_whirlpool "whirlpool" -#define NID_whirlpool 804 -#define OBJ_whirlpool OBJ_iso,0L,10118L,3L,0L,55L - -#define SN_cryptopro "cryptopro" -#define NID_cryptopro 805 -#define OBJ_cryptopro OBJ_member_body,643L,2L,2L - -#define SN_cryptocom "cryptocom" -#define NID_cryptocom 806 -#define OBJ_cryptocom OBJ_member_body,643L,2L,9L - -#define SN_id_GostR3411_94_with_GostR3410_2001 "id-GostR3411-94-with-GostR3410-2001" -#define LN_id_GostR3411_94_with_GostR3410_2001 "GOST R 34.11-94 with GOST R 34.10-2001" -#define NID_id_GostR3411_94_with_GostR3410_2001 807 -#define OBJ_id_GostR3411_94_with_GostR3410_2001 OBJ_cryptopro,3L - -#define SN_id_GostR3411_94_with_GostR3410_94 "id-GostR3411-94-with-GostR3410-94" -#define LN_id_GostR3411_94_with_GostR3410_94 "GOST R 34.11-94 with GOST R 34.10-94" -#define NID_id_GostR3411_94_with_GostR3410_94 808 -#define OBJ_id_GostR3411_94_with_GostR3410_94 OBJ_cryptopro,4L - -#define SN_id_GostR3411_94 "md_gost94" -#define LN_id_GostR3411_94 "GOST R 34.11-94" -#define NID_id_GostR3411_94 809 -#define OBJ_id_GostR3411_94 OBJ_cryptopro,9L - -#define SN_id_HMACGostR3411_94 "id-HMACGostR3411-94" -#define LN_id_HMACGostR3411_94 "HMAC GOST 34.11-94" -#define NID_id_HMACGostR3411_94 810 -#define OBJ_id_HMACGostR3411_94 OBJ_cryptopro,10L - -#define SN_id_GostR3410_2001 "gost2001" -#define LN_id_GostR3410_2001 "GOST R 34.10-2001" -#define NID_id_GostR3410_2001 811 -#define OBJ_id_GostR3410_2001 OBJ_cryptopro,19L - -#define SN_id_GostR3410_94 "gost94" -#define LN_id_GostR3410_94 "GOST R 34.10-94" -#define NID_id_GostR3410_94 812 -#define OBJ_id_GostR3410_94 OBJ_cryptopro,20L - -#define SN_id_Gost28147_89 "gost89" -#define LN_id_Gost28147_89 "GOST 28147-89" -#define NID_id_Gost28147_89 813 -#define OBJ_id_Gost28147_89 OBJ_cryptopro,21L - -#define SN_gost89_cnt "gost89-cnt" -#define NID_gost89_cnt 814 - -#define SN_id_Gost28147_89_MAC "gost-mac" -#define LN_id_Gost28147_89_MAC "GOST 28147-89 MAC" -#define NID_id_Gost28147_89_MAC 815 -#define OBJ_id_Gost28147_89_MAC OBJ_cryptopro,22L - -#define SN_id_GostR3411_94_prf "prf-gostr3411-94" -#define LN_id_GostR3411_94_prf "GOST R 34.11-94 PRF" -#define NID_id_GostR3411_94_prf 816 -#define OBJ_id_GostR3411_94_prf OBJ_cryptopro,23L - -#define SN_id_GostR3410_2001DH "id-GostR3410-2001DH" -#define LN_id_GostR3410_2001DH "GOST R 34.10-2001 DH" -#define NID_id_GostR3410_2001DH 817 -#define OBJ_id_GostR3410_2001DH OBJ_cryptopro,98L - -#define SN_id_GostR3410_94DH "id-GostR3410-94DH" -#define LN_id_GostR3410_94DH "GOST R 34.10-94 DH" -#define NID_id_GostR3410_94DH 818 -#define OBJ_id_GostR3410_94DH OBJ_cryptopro,99L - -#define SN_id_Gost28147_89_CryptoPro_KeyMeshing "id-Gost28147-89-CryptoPro-KeyMeshing" -#define NID_id_Gost28147_89_CryptoPro_KeyMeshing 819 -#define OBJ_id_Gost28147_89_CryptoPro_KeyMeshing OBJ_cryptopro,14L,1L - -#define SN_id_Gost28147_89_None_KeyMeshing "id-Gost28147-89-None-KeyMeshing" -#define NID_id_Gost28147_89_None_KeyMeshing 820 -#define OBJ_id_Gost28147_89_None_KeyMeshing OBJ_cryptopro,14L,0L - -#define SN_id_GostR3411_94_TestParamSet "id-GostR3411-94-TestParamSet" -#define NID_id_GostR3411_94_TestParamSet 821 -#define OBJ_id_GostR3411_94_TestParamSet OBJ_cryptopro,30L,0L - -#define SN_id_GostR3411_94_CryptoProParamSet "id-GostR3411-94-CryptoProParamSet" -#define NID_id_GostR3411_94_CryptoProParamSet 822 -#define OBJ_id_GostR3411_94_CryptoProParamSet OBJ_cryptopro,30L,1L - -#define SN_id_Gost28147_89_TestParamSet "id-Gost28147-89-TestParamSet" -#define NID_id_Gost28147_89_TestParamSet 823 -#define OBJ_id_Gost28147_89_TestParamSet OBJ_cryptopro,31L,0L - -#define SN_id_Gost28147_89_CryptoPro_A_ParamSet "id-Gost28147-89-CryptoPro-A-ParamSet" -#define NID_id_Gost28147_89_CryptoPro_A_ParamSet 824 -#define OBJ_id_Gost28147_89_CryptoPro_A_ParamSet OBJ_cryptopro,31L,1L - -#define SN_id_Gost28147_89_CryptoPro_B_ParamSet "id-Gost28147-89-CryptoPro-B-ParamSet" -#define NID_id_Gost28147_89_CryptoPro_B_ParamSet 825 -#define OBJ_id_Gost28147_89_CryptoPro_B_ParamSet OBJ_cryptopro,31L,2L - -#define SN_id_Gost28147_89_CryptoPro_C_ParamSet "id-Gost28147-89-CryptoPro-C-ParamSet" -#define NID_id_Gost28147_89_CryptoPro_C_ParamSet 826 -#define OBJ_id_Gost28147_89_CryptoPro_C_ParamSet OBJ_cryptopro,31L,3L - -#define SN_id_Gost28147_89_CryptoPro_D_ParamSet "id-Gost28147-89-CryptoPro-D-ParamSet" -#define NID_id_Gost28147_89_CryptoPro_D_ParamSet 827 -#define OBJ_id_Gost28147_89_CryptoPro_D_ParamSet OBJ_cryptopro,31L,4L - -#define SN_id_Gost28147_89_CryptoPro_Oscar_1_1_ParamSet "id-Gost28147-89-CryptoPro-Oscar-1-1-ParamSet" -#define NID_id_Gost28147_89_CryptoPro_Oscar_1_1_ParamSet 828 -#define OBJ_id_Gost28147_89_CryptoPro_Oscar_1_1_ParamSet OBJ_cryptopro,31L,5L - -#define SN_id_Gost28147_89_CryptoPro_Oscar_1_0_ParamSet "id-Gost28147-89-CryptoPro-Oscar-1-0-ParamSet" -#define NID_id_Gost28147_89_CryptoPro_Oscar_1_0_ParamSet 829 -#define OBJ_id_Gost28147_89_CryptoPro_Oscar_1_0_ParamSet OBJ_cryptopro,31L,6L - -#define SN_id_Gost28147_89_CryptoPro_RIC_1_ParamSet "id-Gost28147-89-CryptoPro-RIC-1-ParamSet" -#define NID_id_Gost28147_89_CryptoPro_RIC_1_ParamSet 830 -#define OBJ_id_Gost28147_89_CryptoPro_RIC_1_ParamSet OBJ_cryptopro,31L,7L - -#define SN_id_GostR3410_94_TestParamSet "id-GostR3410-94-TestParamSet" -#define NID_id_GostR3410_94_TestParamSet 831 -#define OBJ_id_GostR3410_94_TestParamSet OBJ_cryptopro,32L,0L - -#define SN_id_GostR3410_94_CryptoPro_A_ParamSet "id-GostR3410-94-CryptoPro-A-ParamSet" -#define NID_id_GostR3410_94_CryptoPro_A_ParamSet 832 -#define OBJ_id_GostR3410_94_CryptoPro_A_ParamSet OBJ_cryptopro,32L,2L - -#define SN_id_GostR3410_94_CryptoPro_B_ParamSet "id-GostR3410-94-CryptoPro-B-ParamSet" -#define NID_id_GostR3410_94_CryptoPro_B_ParamSet 833 -#define OBJ_id_GostR3410_94_CryptoPro_B_ParamSet OBJ_cryptopro,32L,3L - -#define SN_id_GostR3410_94_CryptoPro_C_ParamSet "id-GostR3410-94-CryptoPro-C-ParamSet" -#define NID_id_GostR3410_94_CryptoPro_C_ParamSet 834 -#define OBJ_id_GostR3410_94_CryptoPro_C_ParamSet OBJ_cryptopro,32L,4L - -#define SN_id_GostR3410_94_CryptoPro_D_ParamSet "id-GostR3410-94-CryptoPro-D-ParamSet" -#define NID_id_GostR3410_94_CryptoPro_D_ParamSet 835 -#define OBJ_id_GostR3410_94_CryptoPro_D_ParamSet OBJ_cryptopro,32L,5L - -#define SN_id_GostR3410_94_CryptoPro_XchA_ParamSet "id-GostR3410-94-CryptoPro-XchA-ParamSet" -#define NID_id_GostR3410_94_CryptoPro_XchA_ParamSet 836 -#define OBJ_id_GostR3410_94_CryptoPro_XchA_ParamSet OBJ_cryptopro,33L,1L - -#define SN_id_GostR3410_94_CryptoPro_XchB_ParamSet "id-GostR3410-94-CryptoPro-XchB-ParamSet" -#define NID_id_GostR3410_94_CryptoPro_XchB_ParamSet 837 -#define OBJ_id_GostR3410_94_CryptoPro_XchB_ParamSet OBJ_cryptopro,33L,2L - -#define SN_id_GostR3410_94_CryptoPro_XchC_ParamSet "id-GostR3410-94-CryptoPro-XchC-ParamSet" -#define NID_id_GostR3410_94_CryptoPro_XchC_ParamSet 838 -#define OBJ_id_GostR3410_94_CryptoPro_XchC_ParamSet OBJ_cryptopro,33L,3L - -#define SN_id_GostR3410_2001_TestParamSet "id-GostR3410-2001-TestParamSet" -#define NID_id_GostR3410_2001_TestParamSet 839 -#define OBJ_id_GostR3410_2001_TestParamSet OBJ_cryptopro,35L,0L - -#define SN_id_GostR3410_2001_CryptoPro_A_ParamSet "id-GostR3410-2001-CryptoPro-A-ParamSet" -#define NID_id_GostR3410_2001_CryptoPro_A_ParamSet 840 -#define OBJ_id_GostR3410_2001_CryptoPro_A_ParamSet OBJ_cryptopro,35L,1L - -#define SN_id_GostR3410_2001_CryptoPro_B_ParamSet "id-GostR3410-2001-CryptoPro-B-ParamSet" -#define NID_id_GostR3410_2001_CryptoPro_B_ParamSet 841 -#define OBJ_id_GostR3410_2001_CryptoPro_B_ParamSet OBJ_cryptopro,35L,2L - -#define SN_id_GostR3410_2001_CryptoPro_C_ParamSet "id-GostR3410-2001-CryptoPro-C-ParamSet" -#define NID_id_GostR3410_2001_CryptoPro_C_ParamSet 842 -#define OBJ_id_GostR3410_2001_CryptoPro_C_ParamSet OBJ_cryptopro,35L,3L - -#define SN_id_GostR3410_2001_CryptoPro_XchA_ParamSet "id-GostR3410-2001-CryptoPro-XchA-ParamSet" -#define NID_id_GostR3410_2001_CryptoPro_XchA_ParamSet 843 -#define OBJ_id_GostR3410_2001_CryptoPro_XchA_ParamSet OBJ_cryptopro,36L,0L - -#define SN_id_GostR3410_2001_CryptoPro_XchB_ParamSet "id-GostR3410-2001-CryptoPro-XchB-ParamSet" -#define NID_id_GostR3410_2001_CryptoPro_XchB_ParamSet 844 -#define OBJ_id_GostR3410_2001_CryptoPro_XchB_ParamSet OBJ_cryptopro,36L,1L - -#define SN_id_GostR3410_94_a "id-GostR3410-94-a" -#define NID_id_GostR3410_94_a 845 -#define OBJ_id_GostR3410_94_a OBJ_id_GostR3410_94,1L - -#define SN_id_GostR3410_94_aBis "id-GostR3410-94-aBis" -#define NID_id_GostR3410_94_aBis 846 -#define OBJ_id_GostR3410_94_aBis OBJ_id_GostR3410_94,2L - -#define SN_id_GostR3410_94_b "id-GostR3410-94-b" -#define NID_id_GostR3410_94_b 847 -#define OBJ_id_GostR3410_94_b OBJ_id_GostR3410_94,3L - -#define SN_id_GostR3410_94_bBis "id-GostR3410-94-bBis" -#define NID_id_GostR3410_94_bBis 848 -#define OBJ_id_GostR3410_94_bBis OBJ_id_GostR3410_94,4L - -#define SN_id_Gost28147_89_cc "id-Gost28147-89-cc" -#define LN_id_Gost28147_89_cc "GOST 28147-89 Cryptocom ParamSet" -#define NID_id_Gost28147_89_cc 849 -#define OBJ_id_Gost28147_89_cc OBJ_cryptocom,1L,6L,1L - -#define SN_id_GostR3410_94_cc "gost94cc" -#define LN_id_GostR3410_94_cc "GOST 34.10-94 Cryptocom" -#define NID_id_GostR3410_94_cc 850 -#define OBJ_id_GostR3410_94_cc OBJ_cryptocom,1L,5L,3L - -#define SN_id_GostR3410_2001_cc "gost2001cc" -#define LN_id_GostR3410_2001_cc "GOST 34.10-2001 Cryptocom" -#define NID_id_GostR3410_2001_cc 851 -#define OBJ_id_GostR3410_2001_cc OBJ_cryptocom,1L,5L,4L - -#define SN_id_GostR3411_94_with_GostR3410_94_cc "id-GostR3411-94-with-GostR3410-94-cc" -#define LN_id_GostR3411_94_with_GostR3410_94_cc "GOST R 34.11-94 with GOST R 34.10-94 Cryptocom" -#define NID_id_GostR3411_94_with_GostR3410_94_cc 852 -#define OBJ_id_GostR3411_94_with_GostR3410_94_cc OBJ_cryptocom,1L,3L,3L - -#define SN_id_GostR3411_94_with_GostR3410_2001_cc "id-GostR3411-94-with-GostR3410-2001-cc" -#define LN_id_GostR3411_94_with_GostR3410_2001_cc "GOST R 34.11-94 with GOST R 34.10-2001 Cryptocom" -#define NID_id_GostR3411_94_with_GostR3410_2001_cc 853 -#define OBJ_id_GostR3411_94_with_GostR3410_2001_cc OBJ_cryptocom,1L,3L,4L - -#define SN_id_GostR3410_2001_ParamSet_cc "id-GostR3410-2001-ParamSet-cc" -#define LN_id_GostR3410_2001_ParamSet_cc "GOST R 3410-2001 Parameter Set Cryptocom" -#define NID_id_GostR3410_2001_ParamSet_cc 854 -#define OBJ_id_GostR3410_2001_ParamSet_cc OBJ_cryptocom,1L,8L,1L - -#define SN_camellia_128_cbc "CAMELLIA-128-CBC" -#define LN_camellia_128_cbc "camellia-128-cbc" -#define NID_camellia_128_cbc 751 -#define OBJ_camellia_128_cbc 1L,2L,392L,200011L,61L,1L,1L,1L,2L - -#define SN_camellia_192_cbc "CAMELLIA-192-CBC" -#define LN_camellia_192_cbc "camellia-192-cbc" -#define NID_camellia_192_cbc 752 -#define OBJ_camellia_192_cbc 1L,2L,392L,200011L,61L,1L,1L,1L,3L - -#define SN_camellia_256_cbc "CAMELLIA-256-CBC" -#define LN_camellia_256_cbc "camellia-256-cbc" -#define NID_camellia_256_cbc 753 -#define OBJ_camellia_256_cbc 1L,2L,392L,200011L,61L,1L,1L,1L,4L - -#define SN_id_camellia128_wrap "id-camellia128-wrap" -#define NID_id_camellia128_wrap 907 -#define OBJ_id_camellia128_wrap 1L,2L,392L,200011L,61L,1L,1L,3L,2L - -#define SN_id_camellia192_wrap "id-camellia192-wrap" -#define NID_id_camellia192_wrap 908 -#define OBJ_id_camellia192_wrap 1L,2L,392L,200011L,61L,1L,1L,3L,3L - -#define SN_id_camellia256_wrap "id-camellia256-wrap" -#define NID_id_camellia256_wrap 909 -#define OBJ_id_camellia256_wrap 1L,2L,392L,200011L,61L,1L,1L,3L,4L - -#define OBJ_ntt_ds 0L,3L,4401L,5L - -#define OBJ_camellia OBJ_ntt_ds,3L,1L,9L - -#define SN_camellia_128_ecb "CAMELLIA-128-ECB" -#define LN_camellia_128_ecb "camellia-128-ecb" -#define NID_camellia_128_ecb 754 -#define OBJ_camellia_128_ecb OBJ_camellia,1L - -#define SN_camellia_128_ofb128 "CAMELLIA-128-OFB" -#define LN_camellia_128_ofb128 "camellia-128-ofb" -#define NID_camellia_128_ofb128 766 -#define OBJ_camellia_128_ofb128 OBJ_camellia,3L - -#define SN_camellia_128_cfb128 "CAMELLIA-128-CFB" -#define LN_camellia_128_cfb128 "camellia-128-cfb" -#define NID_camellia_128_cfb128 757 -#define OBJ_camellia_128_cfb128 OBJ_camellia,4L - -#define SN_camellia_192_ecb "CAMELLIA-192-ECB" -#define LN_camellia_192_ecb "camellia-192-ecb" -#define NID_camellia_192_ecb 755 -#define OBJ_camellia_192_ecb OBJ_camellia,21L - -#define SN_camellia_192_ofb128 "CAMELLIA-192-OFB" -#define LN_camellia_192_ofb128 "camellia-192-ofb" -#define NID_camellia_192_ofb128 767 -#define OBJ_camellia_192_ofb128 OBJ_camellia,23L - -#define SN_camellia_192_cfb128 "CAMELLIA-192-CFB" -#define LN_camellia_192_cfb128 "camellia-192-cfb" -#define NID_camellia_192_cfb128 758 -#define OBJ_camellia_192_cfb128 OBJ_camellia,24L - -#define SN_camellia_256_ecb "CAMELLIA-256-ECB" -#define LN_camellia_256_ecb "camellia-256-ecb" -#define NID_camellia_256_ecb 756 -#define OBJ_camellia_256_ecb OBJ_camellia,41L - -#define SN_camellia_256_ofb128 "CAMELLIA-256-OFB" -#define LN_camellia_256_ofb128 "camellia-256-ofb" -#define NID_camellia_256_ofb128 768 -#define OBJ_camellia_256_ofb128 OBJ_camellia,43L - -#define SN_camellia_256_cfb128 "CAMELLIA-256-CFB" -#define LN_camellia_256_cfb128 "camellia-256-cfb" -#define NID_camellia_256_cfb128 759 -#define OBJ_camellia_256_cfb128 OBJ_camellia,44L - -#define SN_camellia_128_cfb1 "CAMELLIA-128-CFB1" -#define LN_camellia_128_cfb1 "camellia-128-cfb1" -#define NID_camellia_128_cfb1 760 - -#define SN_camellia_192_cfb1 "CAMELLIA-192-CFB1" -#define LN_camellia_192_cfb1 "camellia-192-cfb1" -#define NID_camellia_192_cfb1 761 - -#define SN_camellia_256_cfb1 "CAMELLIA-256-CFB1" -#define LN_camellia_256_cfb1 "camellia-256-cfb1" -#define NID_camellia_256_cfb1 762 - -#define SN_camellia_128_cfb8 "CAMELLIA-128-CFB8" -#define LN_camellia_128_cfb8 "camellia-128-cfb8" -#define NID_camellia_128_cfb8 763 - -#define SN_camellia_192_cfb8 "CAMELLIA-192-CFB8" -#define LN_camellia_192_cfb8 "camellia-192-cfb8" -#define NID_camellia_192_cfb8 764 - -#define SN_camellia_256_cfb8 "CAMELLIA-256-CFB8" -#define LN_camellia_256_cfb8 "camellia-256-cfb8" -#define NID_camellia_256_cfb8 765 - -#define SN_kisa "KISA" -#define LN_kisa "kisa" -#define NID_kisa 773 -#define OBJ_kisa OBJ_member_body,410L,200004L - -#define SN_seed_ecb "SEED-ECB" -#define LN_seed_ecb "seed-ecb" -#define NID_seed_ecb 776 -#define OBJ_seed_ecb OBJ_kisa,1L,3L - -#define SN_seed_cbc "SEED-CBC" -#define LN_seed_cbc "seed-cbc" -#define NID_seed_cbc 777 -#define OBJ_seed_cbc OBJ_kisa,1L,4L - -#define SN_seed_cfb128 "SEED-CFB" -#define LN_seed_cfb128 "seed-cfb" -#define NID_seed_cfb128 779 -#define OBJ_seed_cfb128 OBJ_kisa,1L,5L - -#define SN_seed_ofb128 "SEED-OFB" -#define LN_seed_ofb128 "seed-ofb" -#define NID_seed_ofb128 778 -#define OBJ_seed_ofb128 OBJ_kisa,1L,6L - -#define SN_hmac "HMAC" -#define LN_hmac "hmac" -#define NID_hmac 855 - -#define SN_cmac "CMAC" -#define LN_cmac "cmac" -#define NID_cmac 894 - -#define SN_rc4_hmac_md5 "RC4-HMAC-MD5" -#define LN_rc4_hmac_md5 "rc4-hmac-md5" -#define NID_rc4_hmac_md5 915 - -#define SN_aes_128_cbc_hmac_sha1 "AES-128-CBC-HMAC-SHA1" -#define LN_aes_128_cbc_hmac_sha1 "aes-128-cbc-hmac-sha1" -#define NID_aes_128_cbc_hmac_sha1 916 - -#define SN_aes_192_cbc_hmac_sha1 "AES-192-CBC-HMAC-SHA1" -#define LN_aes_192_cbc_hmac_sha1 "aes-192-cbc-hmac-sha1" -#define NID_aes_192_cbc_hmac_sha1 917 - -#define SN_aes_256_cbc_hmac_sha1 "AES-256-CBC-HMAC-SHA1" -#define LN_aes_256_cbc_hmac_sha1 "aes-256-cbc-hmac-sha1" -#define NID_aes_256_cbc_hmac_sha1 918 - -#define SN_dhpublicnumber "dhpublicnumber" -#define LN_dhpublicnumber "X9.42 DH" -#define NID_dhpublicnumber 920 -#define OBJ_dhpublicnumber OBJ_ISO_US,10046L,2L,1L - -#define SN_brainpoolP160r1 "brainpoolP160r1" -#define NID_brainpoolP160r1 921 -#define OBJ_brainpoolP160r1 1L,3L,36L,3L,3L,2L,8L,1L,1L,1L - -#define SN_brainpoolP160t1 "brainpoolP160t1" -#define NID_brainpoolP160t1 922 -#define OBJ_brainpoolP160t1 1L,3L,36L,3L,3L,2L,8L,1L,1L,2L - -#define SN_brainpoolP192r1 "brainpoolP192r1" -#define NID_brainpoolP192r1 923 -#define OBJ_brainpoolP192r1 1L,3L,36L,3L,3L,2L,8L,1L,1L,3L - -#define SN_brainpoolP192t1 "brainpoolP192t1" -#define NID_brainpoolP192t1 924 -#define OBJ_brainpoolP192t1 1L,3L,36L,3L,3L,2L,8L,1L,1L,4L - -#define SN_brainpoolP224r1 "brainpoolP224r1" -#define NID_brainpoolP224r1 925 -#define OBJ_brainpoolP224r1 1L,3L,36L,3L,3L,2L,8L,1L,1L,5L - -#define SN_brainpoolP224t1 "brainpoolP224t1" -#define NID_brainpoolP224t1 926 -#define OBJ_brainpoolP224t1 1L,3L,36L,3L,3L,2L,8L,1L,1L,6L - -#define SN_brainpoolP256r1 "brainpoolP256r1" -#define NID_brainpoolP256r1 927 -#define OBJ_brainpoolP256r1 1L,3L,36L,3L,3L,2L,8L,1L,1L,7L - -#define SN_brainpoolP256t1 "brainpoolP256t1" -#define NID_brainpoolP256t1 928 -#define OBJ_brainpoolP256t1 1L,3L,36L,3L,3L,2L,8L,1L,1L,8L - -#define SN_brainpoolP320r1 "brainpoolP320r1" -#define NID_brainpoolP320r1 929 -#define OBJ_brainpoolP320r1 1L,3L,36L,3L,3L,2L,8L,1L,1L,9L - -#define SN_brainpoolP320t1 "brainpoolP320t1" -#define NID_brainpoolP320t1 930 -#define OBJ_brainpoolP320t1 1L,3L,36L,3L,3L,2L,8L,1L,1L,10L - -#define SN_brainpoolP384r1 "brainpoolP384r1" -#define NID_brainpoolP384r1 931 -#define OBJ_brainpoolP384r1 1L,3L,36L,3L,3L,2L,8L,1L,1L,11L - -#define SN_brainpoolP384t1 "brainpoolP384t1" -#define NID_brainpoolP384t1 932 -#define OBJ_brainpoolP384t1 1L,3L,36L,3L,3L,2L,8L,1L,1L,12L - -#define SN_brainpoolP512r1 "brainpoolP512r1" -#define NID_brainpoolP512r1 933 -#define OBJ_brainpoolP512r1 1L,3L,36L,3L,3L,2L,8L,1L,1L,13L - -#define SN_brainpoolP512t1 "brainpoolP512t1" -#define NID_brainpoolP512t1 934 -#define OBJ_brainpoolP512t1 1L,3L,36L,3L,3L,2L,8L,1L,1L,14L - -#define OBJ_x9_63_scheme 1L,3L,133L,16L,840L,63L,0L - -#define OBJ_secg_scheme OBJ_certicom_arc,1L - -#define SN_dhSinglePass_stdDH_sha1kdf_scheme "dhSinglePass-stdDH-sha1kdf-scheme" -#define NID_dhSinglePass_stdDH_sha1kdf_scheme 936 -#define OBJ_dhSinglePass_stdDH_sha1kdf_scheme OBJ_x9_63_scheme,2L - -#define SN_dhSinglePass_stdDH_sha224kdf_scheme "dhSinglePass-stdDH-sha224kdf-scheme" -#define NID_dhSinglePass_stdDH_sha224kdf_scheme 937 -#define OBJ_dhSinglePass_stdDH_sha224kdf_scheme OBJ_secg_scheme,11L,0L - -#define SN_dhSinglePass_stdDH_sha256kdf_scheme "dhSinglePass-stdDH-sha256kdf-scheme" -#define NID_dhSinglePass_stdDH_sha256kdf_scheme 938 -#define OBJ_dhSinglePass_stdDH_sha256kdf_scheme OBJ_secg_scheme,11L,1L - -#define SN_dhSinglePass_stdDH_sha384kdf_scheme "dhSinglePass-stdDH-sha384kdf-scheme" -#define NID_dhSinglePass_stdDH_sha384kdf_scheme 939 -#define OBJ_dhSinglePass_stdDH_sha384kdf_scheme OBJ_secg_scheme,11L,2L - -#define SN_dhSinglePass_stdDH_sha512kdf_scheme "dhSinglePass-stdDH-sha512kdf-scheme" -#define NID_dhSinglePass_stdDH_sha512kdf_scheme 940 -#define OBJ_dhSinglePass_stdDH_sha512kdf_scheme OBJ_secg_scheme,11L,3L - -#define SN_dhSinglePass_cofactorDH_sha1kdf_scheme "dhSinglePass-cofactorDH-sha1kdf-scheme" -#define NID_dhSinglePass_cofactorDH_sha1kdf_scheme 941 -#define OBJ_dhSinglePass_cofactorDH_sha1kdf_scheme OBJ_x9_63_scheme,3L - -#define SN_dhSinglePass_cofactorDH_sha224kdf_scheme "dhSinglePass-cofactorDH-sha224kdf-scheme" -#define NID_dhSinglePass_cofactorDH_sha224kdf_scheme 942 -#define OBJ_dhSinglePass_cofactorDH_sha224kdf_scheme OBJ_secg_scheme,14L,0L - -#define SN_dhSinglePass_cofactorDH_sha256kdf_scheme "dhSinglePass-cofactorDH-sha256kdf-scheme" -#define NID_dhSinglePass_cofactorDH_sha256kdf_scheme 943 -#define OBJ_dhSinglePass_cofactorDH_sha256kdf_scheme OBJ_secg_scheme,14L,1L - -#define SN_dhSinglePass_cofactorDH_sha384kdf_scheme "dhSinglePass-cofactorDH-sha384kdf-scheme" -#define NID_dhSinglePass_cofactorDH_sha384kdf_scheme 944 -#define OBJ_dhSinglePass_cofactorDH_sha384kdf_scheme OBJ_secg_scheme,14L,2L - -#define SN_dhSinglePass_cofactorDH_sha512kdf_scheme "dhSinglePass-cofactorDH-sha512kdf-scheme" -#define NID_dhSinglePass_cofactorDH_sha512kdf_scheme 945 -#define OBJ_dhSinglePass_cofactorDH_sha512kdf_scheme OBJ_secg_scheme,14L,3L - -#define SN_dh_std_kdf "dh-std-kdf" -#define NID_dh_std_kdf 946 - -#define SN_dh_cofactor_kdf "dh-cofactor-kdf" -#define NID_dh_cofactor_kdf 947 - -#define SN_x25519 "X25519" -#define LN_x25519 "x25519" -#define NID_x25519 948 - + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +/* This header is provided in order to make compiling against code that expects + OpenSSL easier. */ + +#include "nid.h" diff --git a/Sources/BoringSSL/include/openssl/opensslfeatures.h b/Sources/BoringSSL/include/openssl/opensslconf.h similarity index 93% rename from Sources/BoringSSL/include/openssl/opensslfeatures.h rename to Sources/BoringSSL/include/openssl/opensslconf.h index c3f97d5a4..bf65fc3b2 100644 --- a/Sources/BoringSSL/include/openssl/opensslfeatures.h +++ b/Sources/BoringSSL/include/openssl/opensslconf.h @@ -15,8 +15,8 @@ /* This header is provided in order to make compiling against code that expects OpenSSL easier. */ -#ifndef OPENSSL_HEADER_OPENSSLFEATURES_H -#define OPENSSL_HEADER_OPENSSLFEATURES_H +#ifndef OPENSSL_HEADER_OPENSSLCONF_H +#define OPENSSL_HEADER_OPENSSLCONF_H #define OPENSSL_NO_BF @@ -57,4 +57,4 @@ #define OPENSSL_NO_WHIRLPOOL -#endif /* OPENSSL_HEADER_OPENSSLFEATURES_H */ +#endif /* OPENSSL_HEADER_OPENSSLCONF_H */ diff --git a/Sources/BoringSSL/include/openssl/pem.h b/Sources/BoringSSL/include/openssl/pem.h index c233a5018..58aecaf50 100644 --- a/Sources/BoringSSL/include/openssl/pem.h +++ b/Sources/BoringSSL/include/openssl/pem.h @@ -65,6 +65,10 @@ #include #include +/* For compatibility with open-iscsi, which assumes that it can get + * |OPENSSL_malloc| from pem.h or err.h */ +#include + #ifdef __cplusplus extern "C" { #endif @@ -120,6 +124,7 @@ extern "C" { #define PEM_STRING_RSA_PUBLIC "RSA PUBLIC KEY" #define PEM_STRING_DSA "DSA PRIVATE KEY" #define PEM_STRING_DSA_PUBLIC "DSA PUBLIC KEY" +#define PEM_STRING_EC "EC PRIVATE KEY" #define PEM_STRING_PKCS7 "PKCS7" #define PEM_STRING_PKCS7_SIGNED "PKCS #7 SIGNED DATA" #define PEM_STRING_PKCS8 "ENCRYPTED PRIVATE KEY" diff --git a/Sources/BoringSSL/include/openssl/pkcs8.h b/Sources/BoringSSL/include/openssl/pkcs8.h index 28cf6ac1f..70d6f4952 100644 --- a/Sources/BoringSSL/include/openssl/pkcs8.h +++ b/Sources/BoringSSL/include/openssl/pkcs8.h @@ -66,45 +66,42 @@ extern "C" { #endif -/* PKCS8_encrypt_pbe serializes and encrypts a PKCS8_PRIV_KEY_INFO with PBES1 or +/* PKCS8_encrypt serializes and encrypts a PKCS8_PRIV_KEY_INFO with PBES1 or * PBES2 as defined in PKCS #5. Only pbeWithSHAAnd128BitRC4, * pbeWithSHAAnd3-KeyTripleDES-CBC and pbeWithSHA1And40BitRC2, defined in PKCS * #12, and PBES2, are supported. PBES2 is selected by setting |cipher| and * passing -1 for |pbe_nid|. Otherwise, PBES1 is used and |cipher| is ignored. * - * The |pass_raw_len| bytes pointed to by |pass_raw| are used as the password. - * Note that any conversions from the password as supplied in a text string - * (such as those specified in B.1 of PKCS #12) must be performed by the caller. + * |pass| is used as the password. If a PBES1 scheme from PKCS #12 is used, this + * will be converted to a raw byte string as specified in B.1 of PKCS #12. If + * |pass| is NULL, it will be encoded as the empty byte string rather than two + * zero bytes, the PKCS #12 encoding of the empty string. * * If |salt| is NULL, a random salt of |salt_len| bytes is generated. If * |salt_len| is zero, a default salt length is used instead. * - * The resulting structure is stored in an X509_SIG which must be freed by the - * caller. - * - * TODO(davidben): Really? An X509_SIG? OpenSSL probably did that because it has - * the same structure as EncryptedPrivateKeyInfo. */ -OPENSSL_EXPORT X509_SIG *PKCS8_encrypt_pbe(int pbe_nid, - const EVP_CIPHER *cipher, - const uint8_t *pass_raw, - size_t pass_raw_len, - uint8_t *salt, size_t salt_len, - int iterations, - PKCS8_PRIV_KEY_INFO *p8inf); + * The resulting structure is stored in an |X509_SIG| which must be freed by the + * caller. */ +OPENSSL_EXPORT X509_SIG *PKCS8_encrypt(int pbe_nid, const EVP_CIPHER *cipher, + const char *pass, int pass_len, + const uint8_t *salt, size_t salt_len, + int iterations, + PKCS8_PRIV_KEY_INFO *p8inf); -/* PKCS8_decrypt_pbe decrypts and decodes a PKCS8_PRIV_KEY_INFO with PBES1 or - * PBES2 as defined in PKCS #5. Only pbeWithSHAAnd128BitRC4, +/* PKCS8_decrypt decrypts and decodes a PKCS8_PRIV_KEY_INFO with PBES1 or PBES2 + * as defined in PKCS #5. Only pbeWithSHAAnd128BitRC4, * pbeWithSHAAnd3-KeyTripleDES-CBC and pbeWithSHA1And40BitRC2, and PBES2, * defined in PKCS #12, are supported. * - * The |pass_raw_len| bytes pointed to by |pass_raw| are used as the password. - * Note that any conversions from the password as supplied in a text string - * (such as those specified in B.1 of PKCS #12) must be performed by the caller. + * |pass| is used as the password. If a PBES1 scheme from PKCS #12 is used, this + * will be converted to a raw byte string as specified in B.1 of PKCS #12. If + * |pass| is NULL, it will be encoded as the empty byte string rather than two + * zero bytes, the PKCS #12 encoding of the empty string. * * The resulting structure must be freed by the caller. */ -OPENSSL_EXPORT PKCS8_PRIV_KEY_INFO *PKCS8_decrypt_pbe(X509_SIG *pkcs8, - const uint8_t *pass_raw, - size_t pass_raw_len); +OPENSSL_EXPORT PKCS8_PRIV_KEY_INFO *PKCS8_decrypt(X509_SIG *pkcs8, + const char *pass, + int pass_len); /* PKCS12_get_key_and_certs parses a PKCS#12 structure from |in|, authenticates * and decrypts it using |password|, sets |*out_key| to the included private @@ -117,24 +114,6 @@ OPENSSL_EXPORT int PKCS12_get_key_and_certs(EVP_PKEY **out_key, /* Deprecated functions. */ -/* PKCS8_encrypt calls |PKCS8_encrypt_pbe| after (in the PKCS#12 case) treating - * |pass| as an ASCII string, appending U+0000, and converting to UCS-2. (So the - * empty password encodes as two NUL bytes.) In the PBES2 case, the password is - * unchanged. */ -OPENSSL_EXPORT X509_SIG *PKCS8_encrypt(int pbe_nid, const EVP_CIPHER *cipher, - const char *pass, int pass_len, - uint8_t *salt, size_t salt_len, - int iterations, - PKCS8_PRIV_KEY_INFO *p8inf); - -/* PKCS8_decrypt calls PKCS8_decrypt_pbe after (in the PKCS#12 case) treating - * |pass| as an ASCII string, appending U+0000, and converting to UCS-2. (So the - * empty password encodes as two NUL bytes.) In the PBES2 case, the password is - * unchanged. */ -OPENSSL_EXPORT PKCS8_PRIV_KEY_INFO *PKCS8_decrypt(X509_SIG *pkcs8, - const char *pass, - int pass_len); - /* PKCS12_PBE_add does nothing. It exists for compatibility with OpenSSL. */ OPENSSL_EXPORT void PKCS12_PBE_add(void); @@ -187,6 +166,18 @@ OPENSSL_EXPORT void PKCS12_free(PKCS12 *p12); #if defined(__cplusplus) } /* extern C */ + +extern "C++" { + +namespace bssl { + +BORINGSSL_MAKE_DELETER(PKCS12, PKCS12_free) +BORINGSSL_MAKE_DELETER(PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_free) + +} // namespace bssl + +} /* extern C++ */ + #endif #define PKCS8_R_BAD_PKCS12_DATA 100 diff --git a/Sources/BoringSSL/include/openssl/pool.h b/Sources/BoringSSL/include/openssl/pool.h new file mode 100644 index 000000000..dc5c938eb --- /dev/null +++ b/Sources/BoringSSL/include/openssl/pool.h @@ -0,0 +1,87 @@ +/* Copyright (c) 2016, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#ifndef OPENSSL_HEADER_POOL_H +#define OPENSSL_HEADER_POOL_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* Buffers and buffer pools. + * + * |CRYPTO_BUFFER|s are simply reference-counted blobs. A |CRYPTO_BUFFER_POOL| + * is an intern table for |CRYPTO_BUFFER|s. This allows for a single copy of a + * given blob to be kept in memory and referenced from multiple places. */ + + +/* CRYPTO_BUFFER_POOL_new returns a freshly allocated |CRYPTO_BUFFER_POOL| or + * NULL on error. */ +OPENSSL_EXPORT CRYPTO_BUFFER_POOL* CRYPTO_BUFFER_POOL_new(void); + +/* CRYPTO_BUFFER_POOL_free frees |pool|, which must be empty. */ +OPENSSL_EXPORT void CRYPTO_BUFFER_POOL_free(CRYPTO_BUFFER_POOL *pool); + +/* CRYPTO_BUFFER_new returns a |CRYPTO_BUFFER| containing a copy of |data|, or + * else NULL on error. If |pool| is not NULL then the returned value may be a + * reference to a previously existing |CRYPTO_BUFFER| that contained the same + * data. Otherwise, the returned, fresh |CRYPTO_BUFFER| will be added to the + * pool. */ +OPENSSL_EXPORT CRYPTO_BUFFER *CRYPTO_BUFFER_new(const uint8_t *data, size_t len, + CRYPTO_BUFFER_POOL *pool); + +/* CRYPTO_BUFFER_new_from_CBS acts the same as |CRYPTO_BUFFER_new|. */ +OPENSSL_EXPORT CRYPTO_BUFFER *CRYPTO_BUFFER_new_from_CBS( + CBS *cbs, CRYPTO_BUFFER_POOL *pool); + +/* CRYPTO_BUFFER_free decrements the reference count of |buf|. If there are no + * other references, or if the only remaining reference is from a pool, then + * |buf| will be freed. */ +OPENSSL_EXPORT void CRYPTO_BUFFER_free(CRYPTO_BUFFER *buf); + +/* CRYPTO_BUFFER_up_ref increments the reference count of |buf| and returns + * one. */ +OPENSSL_EXPORT int CRYPTO_BUFFER_up_ref(CRYPTO_BUFFER *buf); + +/* CRYPTO_BUFFER_data returns a pointer to the data contained in |buf|. */ +OPENSSL_EXPORT const uint8_t *CRYPTO_BUFFER_data(const CRYPTO_BUFFER *buf); + +/* CRYPTO_BUFFER_len returns the length, in bytes, of the data contained in + * |buf|. */ +OPENSSL_EXPORT size_t CRYPTO_BUFFER_len(const CRYPTO_BUFFER *buf); + +/* CRYPTO_BUFFER_init_CBS initialises |out| to point at the data from |buf|. */ +OPENSSL_EXPORT void CRYPTO_BUFFER_init_CBS(const CRYPTO_BUFFER *buf, CBS *out); + + +#if defined(__cplusplus) +} /* extern C */ + +extern "C++" { + +namespace bssl { + +BORINGSSL_MAKE_DELETER(CRYPTO_BUFFER_POOL, CRYPTO_BUFFER_POOL_free) +BORINGSSL_MAKE_DELETER(CRYPTO_BUFFER, CRYPTO_BUFFER_free) + +} // namespace bssl + +} /* extern C++ */ + +#endif + +#endif // OPENSSL_HEADER_POOL_H diff --git a/Sources/BoringSSL/include/openssl/pqueue.h b/Sources/BoringSSL/include/openssl/pqueue.h deleted file mode 100644 index ceb1fa2a7..000000000 --- a/Sources/BoringSSL/include/openssl/pqueue.h +++ /dev/null @@ -1,146 +0,0 @@ -/* - * DTLS implementation written by Nagendra Modadugu - * (nagendra@cs.stanford.edu) for the OpenSSL project 2005. - */ -/* ==================================================================== - * Copyright (c) 1999-2005 The OpenSSL Project. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the OpenSSL Project - * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" - * - * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to - * endorse or promote products derived from this software without - * prior written permission. For written permission, please contact - * openssl-core@OpenSSL.org. - * - * 5. Products derived from this software may not be called "OpenSSL" - * nor may "OpenSSL" appear in their names without prior written - * permission of the OpenSSL Project. - * - * 6. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the OpenSSL Project - * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" - * - * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This product includes cryptographic software written by Eric Young - * (eay@cryptsoft.com). This product includes software written by Tim - * Hudson (tjh@cryptsoft.com). */ - -#ifndef OPENSSL_HEADER_PQUEUE_H -#define OPENSSL_HEADER_PQUEUE_H - -#include - -#if defined(__cplusplus) -extern "C" { -#endif - - -/* Priority queue. - * - * The priority queue maintains a linked-list of nodes, each with a unique, - * 64-bit priority, in ascending priority order. */ - -typedef struct _pqueue *pqueue; - -typedef struct _pitem { - uint8_t priority[8]; /* 64-bit value in big-endian encoding */ - void *data; - struct _pitem *next; -} pitem; - -typedef struct _pitem *piterator; - - -/* Creating and freeing queues. */ - -/* pqueue_new allocates a fresh, empty priority queue object and returns it, or - * NULL on error. */ -OPENSSL_EXPORT pqueue pqueue_new(void); - -/* pqueue_free frees |pq| but not any of the items it points to. Thus |pq| must - * be empty or a memory leak will occur. */ -OPENSSL_EXPORT void pqueue_free(pqueue pq); - - -/* Creating and freeing items. */ - -/* pitem_new allocates a fresh priority queue item that points at |data| and - * has a priority given by |prio64be|, which is a 64-bit, unsigned number - * expressed in big-endian form. It returns the fresh item, or NULL on - * error. */ -OPENSSL_EXPORT pitem *pitem_new(uint8_t prio64be[8], void *data); - -/* pitem_free frees |item|, but not any data that it points to. */ -OPENSSL_EXPORT void pitem_free(pitem *item); - - -/* Queue accessor functions */ - -/* pqueue_peek returns the item with the smallest priority from |pq|, or NULL - * if empty. */ -OPENSSL_EXPORT pitem *pqueue_peek(pqueue pq); - -/* pqueue_find returns the item whose priority matches |prio64be| or NULL if no - * such item exists. */ -OPENSSL_EXPORT pitem *pqueue_find(pqueue pq, uint8_t *prio64be); - - -/* Queue mutation functions */ - -/* pqueue_insert inserts |item| into |pq| and returns item. */ -OPENSSL_EXPORT pitem *pqueue_insert(pqueue pq, pitem *item); - -/* pqueue_pop takes the item with the least priority from |pq| and returns it, - * or NULL if |pq| is empty. */ -OPENSSL_EXPORT pitem *pqueue_pop(pqueue pq); - -/* pqueue_size returns the number of items in |pq|. */ -OPENSSL_EXPORT size_t pqueue_size(pqueue pq); - - -/* Iterating */ - -/* pqueue_iterator returns an iterator that can be used to iterate over the - * contents of the queue. */ -OPENSSL_EXPORT piterator pqueue_iterator(pqueue pq); - -/* pqueue_next returns the current value of |iter| and advances it to the next - * position. If the iterator has advanced over all the elements, it returns - * NULL. */ -OPENSSL_EXPORT pitem *pqueue_next(piterator *iter); - - -#if defined(__cplusplus) -} /* extern C */ -#endif - -#endif /* OPENSSL_HEADER_PQUEUE_H */ diff --git a/Sources/BoringSSL/include/openssl/rand.h b/Sources/BoringSSL/include/openssl/rand.h index 2c9c9697e..0e9a8cd7c 100644 --- a/Sources/BoringSSL/include/openssl/rand.h +++ b/Sources/BoringSSL/include/openssl/rand.h @@ -62,6 +62,12 @@ OPENSSL_EXPORT void RAND_set_urandom_fd(int fd); OPENSSL_EXPORT void RAND_enable_fork_unsafe_buffering(int fd); #endif +#if defined(BORINGSSL_UNSAFE_DETERMINISTIC_MODE) +/* RAND_reset_for_fuzzing resets the fuzzer-only deterministic RNG. This + * function is only defined in the fuzzer-only build configuration. */ +OPENSSL_EXPORT void RAND_reset_for_fuzzing(void); +#endif + /* Deprecated functions */ diff --git a/Sources/BoringSSL/include/openssl/rc4.h b/Sources/BoringSSL/include/openssl/rc4.h index 0619cac35..68af8782e 100644 --- a/Sources/BoringSSL/include/openssl/rc4.h +++ b/Sources/BoringSSL/include/openssl/rc4.h @@ -83,6 +83,12 @@ OPENSSL_EXPORT void RC4(RC4_KEY *key, size_t len, const uint8_t *in, uint8_t *out); +/* Deprecated functions. */ + +/* RC4_options returns the string "rc4(ptr,int)". */ +OPENSSL_EXPORT const char *RC4_options(void); + + #if defined(__cplusplus) } /* extern C */ #endif diff --git a/Sources/BoringSSL/crypto/dh/internal.h b/Sources/BoringSSL/include/openssl/ripemd.h similarity index 68% rename from Sources/BoringSSL/crypto/dh/internal.h rename to Sources/BoringSSL/include/openssl/ripemd.h index 81b9c9029..cf1e49e2a 100644 --- a/Sources/BoringSSL/crypto/dh/internal.h +++ b/Sources/BoringSSL/include/openssl/ripemd.h @@ -54,27 +54,54 @@ * copied and put under another distribution licence * [including the GNU Public Licence.] */ -#ifndef OPENSSL_HEADER_DH_INTERNAL_H -#define OPENSSL_HEADER_DH_INTERNAL_H +#ifndef OPENSSL_HEADER_RIPEMD_H +#define OPENSSL_HEADER_RIPEMD_H #include -#include -#include - -#if defined(__cplusplus) +#ifdef __cplusplus extern "C" { #endif -/* DH_check_standard_parameters checks if the parameters in |dh| are well - * known and safe. If so, it sets |dh->priv_length| to an appropriately smaller - * value than the default. */ -void DH_check_standard_parameters(DH *dh); +# define RIPEMD160_CBLOCK 64 +# define RIPEMD160_LBLOCK (RIPEMD160_CBLOCK/4) +# define RIPEMD160_DIGEST_LENGTH 20 + +struct RIPEMD160state_st { + uint32_t h[5]; + uint32_t Nl, Nh; + uint8_t data[RIPEMD160_CBLOCK]; + unsigned num; +}; + +/* RIPEMD160_Init initialises |ctx| and returns one. */ +OPENSSL_EXPORT int RIPEMD160_Init(RIPEMD160_CTX *ctx); + +/* RIPEMD160_Update adds |len| bytes from |data| to |ctx| and returns one. */ +OPENSSL_EXPORT int RIPEMD160_Update(RIPEMD160_CTX *ctx, const void *data, + size_t len); + +/* RIPEMD160_Final adds the final padding to |ctx| and writes the resulting + * digest to |md|, which must have at least |RIPEMD160_DIGEST_LENGTH| bytes of + * space. It returns one. */ +OPENSSL_EXPORT int RIPEMD160_Final(uint8_t *md, RIPEMD160_CTX *ctx); + +/* RIPEMD160 writes the digest of |len| bytes from |data| to |out| and returns + * |out|. There must be at least |RIPEMD160_DIGEST_LENGTH| bytes of space in + * |out|. */ +OPENSSL_EXPORT uint8_t *RIPEMD160(const uint8_t *data, size_t len, + uint8_t *out); + +/* RIPEMD160_Transform is a low-level function that performs a single, + * RIPEMD160 block transformation using the state from |ctx| and 64 bytes from + * |block|. */ +OPENSSL_EXPORT void RIPEMD160_Transform(RIPEMD160_CTX *ctx, + const uint8_t *block); #if defined(__cplusplus) } /* extern C */ #endif -#endif /* OPENSSL_HEADER_DH_INTERNAL_H */ +#endif /* OPENSSL_HEADER_RIPEMD_H */ diff --git a/Sources/BoringSSL/include/openssl/rsa.h b/Sources/BoringSSL/include/openssl/rsa.h index 62d5935fc..bad3fad81 100644 --- a/Sources/BoringSSL/include/openssl/rsa.h +++ b/Sources/BoringSSL/include/openssl/rsa.h @@ -59,7 +59,6 @@ #include -#include #include #include #include @@ -84,10 +83,34 @@ OPENSSL_EXPORT RSA *RSA_new_method(const ENGINE *engine); * reference count drops to zero. */ OPENSSL_EXPORT void RSA_free(RSA *rsa); -/* RSA_up_ref increments the reference count of |rsa|. */ +/* RSA_up_ref increments the reference count of |rsa| and returns one. */ OPENSSL_EXPORT int RSA_up_ref(RSA *rsa); +/* Properties. */ + +/* RSA_get0_key sets |*out_n|, |*out_e|, and |*out_d|, if non-NULL, to |rsa|'s + * modulus, public exponent, and private exponent, respectively. If |rsa| is a + * public key, the private exponent will be set to NULL. */ +OPENSSL_EXPORT void RSA_get0_key(const RSA *rsa, const BIGNUM **out_n, + const BIGNUM **out_e, const BIGNUM **out_d); + +/* RSA_get0_factors sets |*out_p| and |*out_q|, if non-NULL, to |rsa|'s prime + * factors. If |rsa| is a public key, they will be set to NULL. If |rsa| is a + * multi-prime key, only the first two prime factors will be reported. */ +OPENSSL_EXPORT void RSA_get0_factors(const RSA *rsa, const BIGNUM **out_p, + const BIGNUM **out_q); + +/* RSA_get0_crt_params sets |*out_dmp1|, |*out_dmq1|, and |*out_iqmp|, if + * non-NULL, to |rsa|'s CRT parameters. These are d (mod p-1), d (mod q-1) and + * q^-1 (mod p), respectively. If |rsa| is a public key, each parameter will be + * set to NULL. If |rsa| is a multi-prime key, only the CRT parameters for the + * first two primes will be reported. */ +OPENSSL_EXPORT void RSA_get0_crt_params(const RSA *rsa, const BIGNUM **out_dmp1, + const BIGNUM **out_dmq1, + const BIGNUM **out_iqmp); + + /* Key generation. */ /* RSA_generate_key_ex generates a new RSA key where the modulus has size @@ -299,7 +322,9 @@ OPENSSL_EXPORT int RSA_recover_crt_params(RSA *rsa); * hash function for generating the mask. If NULL, |Hash| is used. The |sLen| * argument specifies the expected salt length in bytes. If |sLen| is -1 then * the salt length is the same as the hash length. If -2, then the salt length - * is maximal and is taken from the size of |EM|. + * is recovered and all values accepted. + * + * If unsure, use -1. * * It returns one on success or zero on error. */ OPENSSL_EXPORT int RSA_verify_PKCS1_PSS_mgf1(RSA *rsa, const uint8_t *mHash, @@ -322,6 +347,17 @@ OPENSSL_EXPORT int RSA_padding_add_PKCS1_PSS_mgf1(RSA *rsa, uint8_t *EM, const EVP_MD *mgf1Hash, int sLen); +/* RSA_padding_add_PKCS1_OAEP_mgf1 writes an OAEP padding of |from| to |to| + * with the given parameters and hash functions. If |md| is NULL then SHA-1 is + * used. If |mgf1md| is NULL then the value of |md| is used (which means SHA-1 + * if that, in turn, is NULL). + * + * It returns one on success or zero on error. */ +OPENSSL_EXPORT int RSA_padding_add_PKCS1_OAEP_mgf1( + uint8_t *to, unsigned to_len, const uint8_t *from, unsigned from_len, + const uint8_t *param, unsigned param_len, const EVP_MD *md, + const EVP_MD *mgf1md); + /* RSA_add_pkcs1_prefix builds a version of |msg| prefixed with the DigestInfo * header for the given hash function and sets |out_msg| to point to it. On * successful return, |*out_msg| may be allocated memory and, if so, @@ -400,20 +436,21 @@ OPENSSL_EXPORT void *RSA_get_ex_data(const RSA *r, int idx); * API, like a platform key store. */ #define RSA_FLAG_OPAQUE 1 -/* RSA_FLAG_CACHE_PUBLIC causes a precomputed Montgomery context to be created, - * on demand, for the public key operations. */ +/* Deprecated and ignored. */ #define RSA_FLAG_CACHE_PUBLIC 2 -/* RSA_FLAG_CACHE_PRIVATE causes a precomputed Montgomery context to be - * created, on demand, for the private key operations. */ +/* Deprecated and ignored. */ #define RSA_FLAG_CACHE_PRIVATE 4 -/* RSA_FLAG_NO_BLINDING disables blinding of private operations. */ +/* RSA_FLAG_NO_BLINDING disables blinding of private operations, which is a + * dangerous thing to do. It is deprecated and should not be used. It will + * be ignored whenever possible. + * + * This flag must be used if a key without the public exponent |e| is used for + * private key operations; avoid using such keys whenever possible. */ #define RSA_FLAG_NO_BLINDING 8 -/* RSA_FLAG_EXT_PKEY means that private key operations will be handled by - * |mod_exp| and that they do not depend on the private key components being - * present: for example a key stored in external hardware. */ +/* RSA_FLAG_EXT_PKEY is deprecated and ignored. */ #define RSA_FLAG_EXT_PKEY 0x20 /* RSA_FLAG_SIGN_VER causes the |sign| and |verify| functions of |rsa_meth_st| @@ -467,14 +504,26 @@ OPENSSL_EXPORT RSA *d2i_RSAPrivateKey(RSA **out, const uint8_t **inp, long len); * not, or a negative value on error. */ OPENSSL_EXPORT int i2d_RSAPrivateKey(const RSA *in, uint8_t **outp); -typedef struct rsa_pss_params_st { - X509_ALGOR *hashAlgorithm; - X509_ALGOR *maskGenAlgorithm; - ASN1_INTEGER *saltLength; - ASN1_INTEGER *trailerField; -} RSA_PSS_PARAMS; +/* RSA_padding_add_PKCS1_PSS acts like |RSA_padding_add_PKCS1_PSS_mgf1| but the + * |mgf1Hash| parameter of the latter is implicitly set to |Hash|. */ +OPENSSL_EXPORT int RSA_padding_add_PKCS1_PSS(RSA *rsa, uint8_t *EM, + const uint8_t *mHash, + const EVP_MD *Hash, int sLen); + +/* RSA_verify_PKCS1_PSS acts like |RSA_verify_PKCS1_PSS_mgf1| but the + * |mgf1Hash| parameter of the latter is implicitly set to |Hash|. */ +OPENSSL_EXPORT int RSA_verify_PKCS1_PSS(RSA *rsa, const uint8_t *mHash, + const EVP_MD *Hash, const uint8_t *EM, + int sLen); -DECLARE_ASN1_FUNCTIONS(RSA_PSS_PARAMS) +/* RSA_padding_add_PKCS1_OAEP acts like |RSA_padding_add_PKCS1_OAEP_mgf1| but + * the |md| and |mgf1md| parameters of the latter are implicitly set to NULL, + * which means SHA-1. */ +OPENSSL_EXPORT int RSA_padding_add_PKCS1_OAEP(uint8_t *to, unsigned to_len, + const uint8_t *from, + unsigned from_len, + const uint8_t *param, + unsigned param_len); struct rsa_meth_st { @@ -491,6 +540,7 @@ struct rsa_meth_st { int (*sign)(int type, const uint8_t *m, unsigned int m_length, uint8_t *sigret, unsigned int *siglen, const RSA *rsa); + /* Ignored. Set this to NULL. */ int (*verify)(int dtype, const uint8_t *m, unsigned int m_length, const uint8_t *sigbuf, unsigned int siglen, const RSA *rsa); @@ -503,6 +553,7 @@ struct rsa_meth_st { int (*decrypt)(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out, const uint8_t *in, size_t in_len, int padding); + /* Ignored. Set this to NULL. */ int (*verify_raw)(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out, const uint8_t *in, size_t in_len, int padding); @@ -521,8 +572,10 @@ struct rsa_meth_st { int (*private_transform)(RSA *rsa, uint8_t *out, const uint8_t *in, size_t len); - int (*mod_exp)(BIGNUM *r0, const BIGNUM *I, RSA *rsa, - BN_CTX *ctx); /* Can be null */ + /* mod_exp is deprecated and ignored. Set it to NULL. */ + int (*mod_exp)(BIGNUM *r0, const BIGNUM *I, RSA *rsa, BN_CTX *ctx); + + /* bn_mod_exp is deprecated and ignored. Set it to NULL. */ int (*bn_mod_exp)(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx, const BN_MONT_CTX *mont); @@ -585,53 +638,64 @@ struct rsa_st { #if defined(__cplusplus) } /* extern C */ + +extern "C++" { + +namespace bssl { + +BORINGSSL_MAKE_DELETER(RSA, RSA_free) + +} // namespace bssl + +} /* extern C++ */ + #endif -#define RSA_R_BAD_E_VALUE 100 -#define RSA_R_BAD_FIXED_HEADER_DECRYPT 101 -#define RSA_R_BAD_PAD_BYTE_COUNT 102 -#define RSA_R_BAD_RSA_PARAMETERS 103 -#define RSA_R_BAD_SIGNATURE 104 -#define RSA_R_BLOCK_TYPE_IS_NOT_01 105 -#define RSA_R_BN_NOT_INITIALIZED 106 -#define RSA_R_CRT_PARAMS_ALREADY_GIVEN 107 -#define RSA_R_CRT_VALUES_INCORRECT 108 -#define RSA_R_DATA_LEN_NOT_EQUAL_TO_MOD_LEN 109 -#define RSA_R_DATA_TOO_LARGE 110 -#define RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE 111 -#define RSA_R_DATA_TOO_LARGE_FOR_MODULUS 112 -#define RSA_R_DATA_TOO_SMALL 113 -#define RSA_R_DATA_TOO_SMALL_FOR_KEY_SIZE 114 -#define RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY 115 -#define RSA_R_D_E_NOT_CONGRUENT_TO_1 116 -#define RSA_R_EMPTY_PUBLIC_KEY 117 -#define RSA_R_FIRST_OCTET_INVALID 118 -#define RSA_R_INCONSISTENT_SET_OF_CRT_VALUES 119 -#define RSA_R_INTERNAL_ERROR 120 -#define RSA_R_INVALID_MESSAGE_LENGTH 121 -#define RSA_R_KEY_SIZE_TOO_SMALL 122 -#define RSA_R_LAST_OCTET_INVALID 123 -#define RSA_R_MODULUS_TOO_LARGE 124 -#define RSA_R_NO_PUBLIC_EXPONENT 125 -#define RSA_R_NULL_BEFORE_BLOCK_MISSING 126 -#define RSA_R_N_NOT_EQUAL_P_Q 127 -#define RSA_R_OAEP_DECODING_ERROR 128 -#define RSA_R_ONLY_ONE_OF_P_Q_GIVEN 129 -#define RSA_R_OUTPUT_BUFFER_TOO_SMALL 130 -#define RSA_R_PADDING_CHECK_FAILED 131 -#define RSA_R_PKCS_DECODING_ERROR 132 -#define RSA_R_SLEN_CHECK_FAILED 133 -#define RSA_R_SLEN_RECOVERY_FAILED 134 -#define RSA_R_TOO_LONG 135 -#define RSA_R_TOO_MANY_ITERATIONS 136 -#define RSA_R_UNKNOWN_ALGORITHM_TYPE 137 -#define RSA_R_UNKNOWN_PADDING_TYPE 138 -#define RSA_R_VALUE_MISSING 139 -#define RSA_R_WRONG_SIGNATURE_LENGTH 140 -#define RSA_R_MUST_HAVE_AT_LEAST_TWO_PRIMES 141 -#define RSA_R_CANNOT_RECOVER_MULTI_PRIME_KEY 142 -#define RSA_R_BAD_ENCODING 143 -#define RSA_R_ENCODE_ERROR 144 -#define RSA_R_BAD_VERSION 145 +#define RSA_R_BAD_ENCODING 100 +#define RSA_R_BAD_E_VALUE 101 +#define RSA_R_BAD_FIXED_HEADER_DECRYPT 102 +#define RSA_R_BAD_PAD_BYTE_COUNT 103 +#define RSA_R_BAD_RSA_PARAMETERS 104 +#define RSA_R_BAD_SIGNATURE 105 +#define RSA_R_BAD_VERSION 106 +#define RSA_R_BLOCK_TYPE_IS_NOT_01 107 +#define RSA_R_BN_NOT_INITIALIZED 108 +#define RSA_R_CANNOT_RECOVER_MULTI_PRIME_KEY 109 +#define RSA_R_CRT_PARAMS_ALREADY_GIVEN 110 +#define RSA_R_CRT_VALUES_INCORRECT 111 +#define RSA_R_DATA_LEN_NOT_EQUAL_TO_MOD_LEN 112 +#define RSA_R_DATA_TOO_LARGE 113 +#define RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE 114 +#define RSA_R_DATA_TOO_LARGE_FOR_MODULUS 115 +#define RSA_R_DATA_TOO_SMALL 116 +#define RSA_R_DATA_TOO_SMALL_FOR_KEY_SIZE 117 +#define RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY 118 +#define RSA_R_D_E_NOT_CONGRUENT_TO_1 119 +#define RSA_R_EMPTY_PUBLIC_KEY 120 +#define RSA_R_ENCODE_ERROR 121 +#define RSA_R_FIRST_OCTET_INVALID 122 +#define RSA_R_INCONSISTENT_SET_OF_CRT_VALUES 123 +#define RSA_R_INTERNAL_ERROR 124 +#define RSA_R_INVALID_MESSAGE_LENGTH 125 +#define RSA_R_KEY_SIZE_TOO_SMALL 126 +#define RSA_R_LAST_OCTET_INVALID 127 +#define RSA_R_MODULUS_TOO_LARGE 128 +#define RSA_R_MUST_HAVE_AT_LEAST_TWO_PRIMES 129 +#define RSA_R_NO_PUBLIC_EXPONENT 130 +#define RSA_R_NULL_BEFORE_BLOCK_MISSING 131 +#define RSA_R_N_NOT_EQUAL_P_Q 132 +#define RSA_R_OAEP_DECODING_ERROR 133 +#define RSA_R_ONLY_ONE_OF_P_Q_GIVEN 134 +#define RSA_R_OUTPUT_BUFFER_TOO_SMALL 135 +#define RSA_R_PADDING_CHECK_FAILED 136 +#define RSA_R_PKCS_DECODING_ERROR 137 +#define RSA_R_SLEN_CHECK_FAILED 138 +#define RSA_R_SLEN_RECOVERY_FAILED 139 +#define RSA_R_TOO_LONG 140 +#define RSA_R_TOO_MANY_ITERATIONS 141 +#define RSA_R_UNKNOWN_ALGORITHM_TYPE 142 +#define RSA_R_UNKNOWN_PADDING_TYPE 143 +#define RSA_R_VALUE_MISSING 144 +#define RSA_R_WRONG_SIGNATURE_LENGTH 145 #endif /* OPENSSL_HEADER_RSA_H */ diff --git a/Sources/BoringSSL/include/openssl/sha.h b/Sources/BoringSSL/include/openssl/sha.h index 48a52e8f0..7c310979c 100644 --- a/Sources/BoringSSL/include/openssl/sha.h +++ b/Sources/BoringSSL/include/openssl/sha.h @@ -73,10 +73,6 @@ extern "C" { /* SHA_DIGEST_LENGTH is the length of a SHA-1 digest. */ #define SHA_DIGEST_LENGTH 20 -/* TODO(fork): remove */ -#define SHA_LBLOCK 16 -#define SHA_LONG uint32_t - /* SHA1_Init initialises |sha| and returns one. */ OPENSSL_EXPORT int SHA1_Init(SHA_CTX *sha); @@ -94,7 +90,8 @@ OPENSSL_EXPORT int SHA1_Final(uint8_t *md, SHA_CTX *sha); OPENSSL_EXPORT uint8_t *SHA1(const uint8_t *data, size_t len, uint8_t *out); /* SHA1_Transform is a low-level function that performs a single, SHA-1 block - * transformation using the state from |sha| and 64 bytes from |block|. */ + * transformation using the state from |sha| and |SHA_CBLOCK| bytes from + * |block|. */ OPENSSL_EXPORT void SHA1_Transform(SHA_CTX *sha, const uint8_t *block); struct sha_state_st { @@ -169,9 +166,10 @@ OPENSSL_EXPORT int SHA256_Final(uint8_t *md, SHA256_CTX *sha); * |out|. */ OPENSSL_EXPORT uint8_t *SHA256(const uint8_t *data, size_t len, uint8_t *out); -/* SHA256_Transform is a low-level function that performs a single, SHA-1 block - * transformation using the state from |sha| and 64 bytes from |block|. */ -OPENSSL_EXPORT void SHA256_Transform(SHA256_CTX *sha, const uint8_t *data); +/* SHA256_Transform is a low-level function that performs a single, SHA-256 + * block transformation using the state from |sha| and |SHA256_CBLOCK| bytes + * from |block|. */ +OPENSSL_EXPORT void SHA256_Transform(SHA256_CTX *sha, const uint8_t *block); struct sha256_state_st { uint32_t h[8]; @@ -205,9 +203,10 @@ OPENSSL_EXPORT int SHA384_Final(uint8_t *md, SHA512_CTX *sha); * |out|. */ OPENSSL_EXPORT uint8_t *SHA384(const uint8_t *data, size_t len, uint8_t *out); -/* SHA384_Transform is a low-level function that performs a single, SHA-1 block - * transformation using the state from |sha| and 64 bytes from |block|. */ -OPENSSL_EXPORT void SHA384_Transform(SHA512_CTX *sha, const uint8_t *data); +/* SHA384_Transform is a low-level function that performs a single, SHA-384 + * block transformation using the state from |sha| and |SHA384_CBLOCK| bytes + * from |block|. */ +OPENSSL_EXPORT void SHA384_Transform(SHA512_CTX *sha, const uint8_t *block); /* SHA-512. */ @@ -234,9 +233,10 @@ OPENSSL_EXPORT int SHA512_Final(uint8_t *md, SHA512_CTX *sha); * |out|. */ OPENSSL_EXPORT uint8_t *SHA512(const uint8_t *data, size_t len, uint8_t *out); -/* SHA512_Transform is a low-level function that performs a single, SHA-1 block - * transformation using the state from |sha| and 64 bytes from |block|. */ -OPENSSL_EXPORT void SHA512_Transform(SHA512_CTX *sha, const uint8_t *data); +/* SHA512_Transform is a low-level function that performs a single, SHA-512 + * block transformation using the state from |sha| and |SHA512_CBLOCK| bytes + * from |block|. */ +OPENSSL_EXPORT void SHA512_Transform(SHA512_CTX *sha, const uint8_t *block); struct sha512_state_st { uint64_t h[8]; diff --git a/Sources/BoringSSL/include/openssl/ssl.h b/Sources/BoringSSL/include/openssl/ssl.h index 41813b2c6..313153980 100644 --- a/Sources/BoringSSL/include/openssl/ssl.h +++ b/Sources/BoringSSL/include/openssl/ssl.h @@ -158,9 +158,6 @@ #include #endif -/* wpa_supplicant expects to get the version functions from ssl.h */ -#include - /* Forward-declare struct timeval. On Windows, it is defined in winsock2.h and * Windows headers define too many macros to be included in public headers. * However, only a forward declaration is needed. */ @@ -194,6 +191,9 @@ OPENSSL_EXPORT const SSL_METHOD *DTLS_method(void); * on error. */ OPENSSL_EXPORT SSL_CTX *SSL_CTX_new(const SSL_METHOD *method); +/* SSL_CTX_up_ref increments the reference count of |ctx|. It returns one. */ +OPENSSL_EXPORT int SSL_CTX_up_ref(SSL_CTX *ctx); + /* SSL_CTX_free releases memory associated with |ctx|. */ OPENSSL_EXPORT void SSL_CTX_free(SSL_CTX *ctx); @@ -228,7 +228,10 @@ OPENSSL_EXPORT void SSL_set_accept_state(SSL *ssl); /* SSL_is_server returns one if |ssl| is configured as a server and zero * otherwise. */ -OPENSSL_EXPORT int SSL_is_server(SSL *ssl); +OPENSSL_EXPORT int SSL_is_server(const SSL *ssl); + +/* SSL_is_dtls returns one if |ssl| is a DTLS connection and zero otherwise. */ +OPENSSL_EXPORT int SSL_is_dtls(const SSL *ssl); /* SSL_set_bio configures |ssl| to read from |rbio| and write to |wbio|. |ssl| * takes ownership of the two |BIO|s. If |rbio| and |wbio| are the same, |ssl| @@ -237,9 +240,33 @@ OPENSSL_EXPORT int SSL_is_server(SSL *ssl); * In DTLS, if |rbio| is blocking, it must handle * |BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT| control requests to set read timeouts. * - * Calling this function on an already-configured |ssl| is deprecated. */ + * If |rbio| is the same as the currently configured |BIO| for reading, that + * side is left untouched and is not freed. + * + * If |wbio| is the same as the currently configured |BIO| for writing AND |ssl| + * is not currently configured to read from and write to the same |BIO|, that + * side is left untouched and is not freed. This asymmetry is present for + * historical reasons. + * + * Due to the very complex historical behavior of this function, calling this + * function if |ssl| already has |BIO|s configured is deprecated. Prefer + * |SSL_set0_rbio| and |SSL_set0_wbio| instead. */ OPENSSL_EXPORT void SSL_set_bio(SSL *ssl, BIO *rbio, BIO *wbio); +/* SSL_set0_rbio configures |ssl| to write to |rbio|. It takes ownership of + * |rbio|. + * + * Note that, although this function and |SSL_set0_wbio| may be called on the + * same |BIO|, each call takes a reference. Use |BIO_up_ref| to balance this. */ +OPENSSL_EXPORT void SSL_set0_rbio(SSL *ssl, BIO *rbio); + +/* SSL_set0_wbio configures |ssl| to write to |wbio|. It takes ownership of + * |wbio|. + * + * Note that, although this function and |SSL_set0_rbio| may be called on the + * same |BIO|, each call takes a reference. Use |BIO_up_ref| to balance this. */ +OPENSSL_EXPORT void SSL_set0_wbio(SSL *ssl, BIO *wbio); + /* SSL_get_rbio returns the |BIO| that |ssl| reads from. */ OPENSSL_EXPORT BIO *SSL_get_rbio(const SSL *ssl); @@ -251,25 +278,39 @@ OPENSSL_EXPORT int SSL_get_fd(const SSL *ssl); /* SSL_get_rfd returns the file descriptor that |ssl| is configured to read * from. If |ssl|'s read |BIO| is not configured or doesn't wrap a file - * descriptor then it returns -1. */ + * descriptor then it returns -1. + * + * Note: On Windows, this may return either a file descriptor or a socket (cast + * to int), depending on whether |ssl| was configured with a file descriptor or + * socket |BIO|. */ OPENSSL_EXPORT int SSL_get_rfd(const SSL *ssl); /* SSL_get_wfd returns the file descriptor that |ssl| is configured to write * to. If |ssl|'s write |BIO| is not configured or doesn't wrap a file - * descriptor then it returns -1. */ + * descriptor then it returns -1. + * + * Note: On Windows, this may return either a file descriptor or a socket (cast + * to int), depending on whether |ssl| was configured with a file descriptor or + * socket |BIO|. */ OPENSSL_EXPORT int SSL_get_wfd(const SSL *ssl); /* SSL_set_fd configures |ssl| to read from and write to |fd|. It returns one * on success and zero on allocation error. The caller retains ownership of - * |fd|. */ + * |fd|. + * + * On Windows, |fd| is cast to a |SOCKET| and used with Winsock APIs. */ OPENSSL_EXPORT int SSL_set_fd(SSL *ssl, int fd); /* SSL_set_rfd configures |ssl| to read from |fd|. It returns one on success and - * zero on allocation error. The caller retains ownership of |fd|. */ + * zero on allocation error. The caller retains ownership of |fd|. + * + * On Windows, |fd| is cast to a |SOCKET| and used with Winsock APIs. */ OPENSSL_EXPORT int SSL_set_rfd(SSL *ssl, int fd); /* SSL_set_wfd configures |ssl| to write to |fd|. It returns one on success and - * zero on allocation error. The caller retains ownership of |fd|. */ + * zero on allocation error. The caller retains ownership of |fd|. + * + * On Windows, |fd| is cast to a |SOCKET| and used with Winsock APIs. */ OPENSSL_EXPORT int SSL_set_wfd(SSL *ssl, int fd); /* SSL_do_handshake continues the current handshake. If there is none or the @@ -314,7 +355,7 @@ OPENSSL_EXPORT int SSL_pending(const SSL *ssl); /* SSL_write writes up to |num| bytes from |buf| into |ssl|. It implicitly runs * any pending handshakes, including renegotiations when enabled. On success, it - * returns the number of bytes read. Otherwise, it returns <= 0. The caller + * returns the number of bytes written. Otherwise, it returns <= 0. The caller * should pass the value into |SSL_get_error| to determine how to proceed. * * In TLS, a non-blocking |SSL_write| differs from non-blocking |write| in that @@ -353,14 +394,7 @@ OPENSSL_EXPORT int SSL_write(SSL *ssl, const void *buf, int num); * * |SSL_shutdown| returns -1 on failure. The caller should pass the return value * into |SSL_get_error| to determine how to proceed. If the underlying |BIO| is - * non-blocking, both stages may require retry. - * - * |SSL_shutdown| must be called to retain |ssl|'s session in the session - * cache. Use |SSL_CTX_set_quiet_shutdown| to configure |SSL_shutdown| to - * neither send nor wait for close_notify but still retain the session. - * - * TODO(davidben): Is there any point in the session cache interaction? Remove - * it? */ + * non-blocking, both stages may require retry. */ OPENSSL_EXPORT int SSL_shutdown(SSL *ssl); /* SSL_CTX_set_quiet_shutdown sets quiet shutdown on |ctx| to |mode|. If @@ -415,9 +449,9 @@ OPENSSL_EXPORT int SSL_get_error(const SSL *ssl, int ret_code); * See also |SSL_CTX_set_cert_cb| and |SSL_CTX_set_client_cert_cb|. */ #define SSL_ERROR_WANT_X509_LOOKUP 4 -/* SSL_ERROR_WANT_SYSCALL indicates the operation failed externally to the - * library. The caller should consult the system-specific error mechanism. This - * is typically |errno| but may be something custom if using a custom |BIO|. It +/* SSL_ERROR_SYSCALL indicates the operation failed externally to the library. + * The caller should consult the system-specific error mechanism. This is + * typically |errno| but may be something custom if using a custom |BIO|. It * may also be signaled if the transport returned EOF, in which case the * operation's return value will be zero. */ #define SSL_ERROR_SYSCALL 5 @@ -465,13 +499,24 @@ OPENSSL_EXPORT int SSL_get_error(const SSL *ssl, int ret_code); * a private key operation was unfinished. The caller may retry the operation * when the private key operation is complete. * - * See also |SSL_set_private_key_method|. */ + * See also |SSL_set_private_key_method| and + * |SSL_CTX_set_private_key_method|. */ #define SSL_ERROR_WANT_PRIVATE_KEY_OPERATION 13 /* SSL_set_mtu sets the |ssl|'s MTU in DTLS to |mtu|. It returns one on success * and zero on failure. */ OPENSSL_EXPORT int SSL_set_mtu(SSL *ssl, unsigned mtu); +/* DTLSv1_set_initial_timeout_duration sets the initial duration for a DTLS + * handshake timeout. + * + * This duration overrides the default of 1 second, which is the strong + * recommendation of RFC 6347 (see section 4.2.4.1). However, there may exist + * situations where a shorter timeout would be beneficial, such as for + * time-sensitive applications. */ +OPENSSL_EXPORT void DTLSv1_set_initial_timeout_duration(SSL *ssl, + unsigned duration_ms); + /* DTLSv1_get_timeout queries the next DTLS handshake timeout. If there is a * timeout in progress, it sets |*out| to the time remaining and returns one. * Otherwise, it returns zero. @@ -512,25 +557,34 @@ OPENSSL_EXPORT int DTLSv1_handle_timeout(SSL *ssl); #define TLS1_VERSION 0x0301 #define TLS1_1_VERSION 0x0302 #define TLS1_2_VERSION 0x0303 +#define TLS1_3_VERSION 0x0304 #define DTLS1_VERSION 0xfeff #define DTLS1_2_VERSION 0xfefd -/* SSL_CTX_set_min_version sets the minimum protocol version for |ctx| to - * |version|. */ -OPENSSL_EXPORT void SSL_CTX_set_min_version(SSL_CTX *ctx, uint16_t version); +#define TLS1_3_DRAFT_VERSION 0x7f12 -/* SSL_CTX_set_max_version sets the maximum protocol version for |ctx| to - * |version|. */ -OPENSSL_EXPORT void SSL_CTX_set_max_version(SSL_CTX *ctx, uint16_t version); +/* SSL_CTX_set_min_proto_version sets the minimum protocol version for |ctx| to + * |version|. If |version| is zero, the default minimum version is used. It + * returns one on success and zero if |version| is invalid. */ +OPENSSL_EXPORT int SSL_CTX_set_min_proto_version(SSL_CTX *ctx, + uint16_t version); -/* SSL_set_min_version sets the minimum protocol version for |ssl| to - * |version|. */ -OPENSSL_EXPORT void SSL_set_min_version(SSL *ssl, uint16_t version); +/* SSL_CTX_set_max_proto_version sets the maximum protocol version for |ctx| to + * |version|. If |version| is zero, the default maximum version is used. It + * returns one on success and zero if |version| is invalid. */ +OPENSSL_EXPORT int SSL_CTX_set_max_proto_version(SSL_CTX *ctx, + uint16_t version); -/* SSL_set_max_version sets the maximum protocol version for |ssl| to - * |version|. */ -OPENSSL_EXPORT void SSL_set_max_version(SSL *ssl, uint16_t version); +/* SSL_set_min_proto_version sets the minimum protocol version for |ssl| to + * |version|. If |version| is zero, the default minimum version is used. It + * returns one on success and zero if |version| is invalid. */ +OPENSSL_EXPORT int SSL_set_min_proto_version(SSL *ssl, uint16_t version); + +/* SSL_set_max_proto_version sets the maximum protocol version for |ssl| to + * |version|. If |version| is zero, the default maximum version is used. It + * returns one on success and zero if |version| is invalid. */ +OPENSSL_EXPORT int SSL_set_max_proto_version(SSL *ssl, uint16_t version); /* SSL_version returns the TLS or DTLS protocol version used by |ssl|, which is * one of the |*_VERSION| values. (E.g. |TLS1_2_VERSION|.) Before the version @@ -554,10 +608,16 @@ OPENSSL_EXPORT int SSL_version(const SSL *ssl); * client's. */ #define SSL_OP_CIPHER_SERVER_PREFERENCE 0x00400000L -/* SSL_OP_DISABLE_NPN configures an individual |SSL| to not advertise NPN, - * despite |SSL_CTX_set_next_proto_select_cb| being configured on the - * |SSL_CTX|. */ -#define SSL_OP_DISABLE_NPN 0x00800000L +/* The following flags toggle individual protocol versions. This is deprecated. + * Use |SSL_CTX_set_min_proto_version| and |SSL_CTX_set_max_proto_version| + * instead. */ +#define SSL_OP_NO_SSLv3 0x02000000L +#define SSL_OP_NO_TLSv1 0x04000000L +#define SSL_OP_NO_TLSv1_2 0x08000000L +#define SSL_OP_NO_TLSv1_1 0x10000000L +#define SSL_OP_NO_TLSv1_3 0x20000000L +#define SSL_OP_NO_DTLSv1 SSL_OP_NO_TLSv1 +#define SSL_OP_NO_DTLSv1_2 SSL_OP_NO_TLSv1_2 /* SSL_CTX_set_options enables all options set in |options| (which should be one * or more of the |SSL_OP_*| values, ORed together) in |ctx|. It returns a @@ -605,13 +665,14 @@ OPENSSL_EXPORT uint32_t SSL_get_options(const SSL *ssl); #define SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER 0x00000002L /* SSL_MODE_NO_AUTO_CHAIN disables automatically building a certificate chain - * before sending certificates to the peer. - * TODO(davidben): Remove this behavior. https://crbug.com/486295. */ + * before sending certificates to the peer. This flag is set (and the feature + * disabled) by default. + * TODO(davidben): Remove this behavior. https://crbug.com/boringssl/42. */ #define SSL_MODE_NO_AUTO_CHAIN 0x00000008L /* SSL_MODE_ENABLE_FALSE_START allows clients to send application data before - * receipt of ChangeCipherSpec and Finished. This mode enables full-handshakes - * to 'complete' in one RTT. See draft-bmoeller-tls-falsestart-01. + * receipt of ChangeCipherSpec and Finished. This mode enables full handshakes + * to 'complete' in one RTT. See RFC 7918. * * When False Start is enabled, |SSL_do_handshake| may succeed before the * handshake has completely finished. |SSL_write| will function at this point, @@ -668,6 +729,16 @@ OPENSSL_EXPORT uint32_t SSL_clear_mode(SSL *ssl, uint32_t mode); * modes enabled for |ssl|. */ OPENSSL_EXPORT uint32_t SSL_get_mode(const SSL *ssl); +/* SSL_CTX_set0_buffer_pool sets a |CRYPTO_BUFFER_POOL| that will be used to + * store certificates. This can allow multiple connections to share + * certificates and thus save memory. + * + * The SSL_CTX does not take ownership of |pool| and the caller must ensure + * that |pool| outlives |ctx| and all objects linked to it, including |SSL|, + * |X509| and |SSL_SESSION| objects. Basically, don't ever free |pool|. */ +OPENSSL_EXPORT void SSL_CTX_set0_buffer_pool(SSL_CTX *ctx, + CRYPTO_BUFFER_POOL *pool); + /* Configuring certificates and private keys. * @@ -754,7 +825,10 @@ OPENSSL_EXPORT int SSL_clear_chain_certs(SSL *ssl); * * On the client, the callback may call |SSL_get0_certificate_types| and * |SSL_get_client_CA_list| for information on the server's certificate - * request. */ + * request. + * + * On the server, the callback will be called on non-resumption handshakes, + * after extensions have been processed. */ OPENSSL_EXPORT void SSL_CTX_set_cert_cb(SSL_CTX *ctx, int (*cb)(SSL *ssl, void *arg), void *arg); @@ -830,20 +904,61 @@ OPENSSL_EXPORT int SSL_CTX_set_signed_cert_timestamp_list(SSL_CTX *ctx, const uint8_t *list, size_t list_len); -/* SSL_CTX_set_ocsp_response sets the OCSP reponse that is sent to clients +/* SSL_set_signed_cert_timestamp_list sets the list of signed certificate + * timestamps that is sent to clients that request is. The same format as the + * one used for |SSL_CTX_set_signed_cert_timestamp_list| applies. The caller + * retains ownership of |list|. */ +OPENSSL_EXPORT int SSL_set_signed_cert_timestamp_list(SSL *ctx, + const uint8_t *list, + size_t list_len); + +/* SSL_CTX_set_ocsp_response sets the OCSP response that is sent to clients * which request it. It returns one on success and zero on error. The caller * retains ownership of |response|. */ OPENSSL_EXPORT int SSL_CTX_set_ocsp_response(SSL_CTX *ctx, const uint8_t *response, size_t response_len); -/* SSL_set_private_key_digest_prefs copies |num_digests| NIDs from |digest_nids| - * into |ssl|. These digests will be used, in decreasing order of preference, - * when signing with |ssl|'s private key. It returns one on success and zero on - * error. */ -OPENSSL_EXPORT int SSL_set_private_key_digest_prefs(SSL *ssl, - const int *digest_nids, - size_t num_digests); +/* SSL_set_ocsp_response sets the OCSP response that is sent to clients which + * request it. It returns one on success and zero on error. The caller retains + * ownership of |response|. */ +OPENSSL_EXPORT int SSL_set_ocsp_response(SSL *ssl, + const uint8_t *response, + size_t response_len); + +/* SSL_SIGN_* are signature algorithm values as defined in TLS 1.3. */ +#define SSL_SIGN_RSA_PKCS1_SHA1 0x0201 +#define SSL_SIGN_RSA_PKCS1_SHA256 0x0401 +#define SSL_SIGN_RSA_PKCS1_SHA384 0x0501 +#define SSL_SIGN_RSA_PKCS1_SHA512 0x0601 +#define SSL_SIGN_ECDSA_SHA1 0x0203 +#define SSL_SIGN_ECDSA_SECP256R1_SHA256 0x0403 +#define SSL_SIGN_ECDSA_SECP384R1_SHA384 0x0503 +#define SSL_SIGN_ECDSA_SECP521R1_SHA512 0x0603 +#define SSL_SIGN_RSA_PSS_SHA256 0x0804 +#define SSL_SIGN_RSA_PSS_SHA384 0x0805 +#define SSL_SIGN_RSA_PSS_SHA512 0x0806 + +/* SSL_SIGN_RSA_PKCS1_MD5_SHA1 is an internal signature algorithm used to + * specify raw RSASSA-PKCS1-v1_5 with an MD5/SHA-1 concatenation, as used in TLS + * before TLS 1.2. */ +#define SSL_SIGN_RSA_PKCS1_MD5_SHA1 0xff01 + +/* SSL_CTX_set_signing_algorithm_prefs configures |ctx| to use |prefs| as the + * preference list when signing with |ctx|'s private key. It returns one on + * success and zero on error. |prefs| should not include the internal-only value + * |SSL_SIGN_RSA_PKCS1_MD5_SHA1|. */ +OPENSSL_EXPORT int SSL_CTX_set_signing_algorithm_prefs(SSL_CTX *ctx, + const uint16_t *prefs, + size_t num_prefs); + +/* SSL_set_signing_algorithm_prefs configures |ssl| to use |prefs| as the + * preference list when signing with |ssl|'s private key. It returns one on + * success and zero on error. |prefs| should not include the internal-only value + * |SSL_SIGN_RSA_PKCS1_MD5_SHA1|. */ +OPENSSL_EXPORT int SSL_set_signing_algorithm_prefs(SSL *ssl, + const uint16_t *prefs, + size_t num_prefs); /* Certificate and private key convenience functions. */ @@ -930,43 +1045,62 @@ enum ssl_private_key_result_t { /* SSL_PRIVATE_KEY_METHOD describes private key hooks. This is used to off-load * signing operations to a custom, potentially asynchronous, backend. */ typedef struct ssl_private_key_method_st { - /* type returns either |EVP_PKEY_RSA| or |EVP_PKEY_EC| to denote the type of - * key used by |ssl|. */ + /* type returns the type of the key used by |ssl|. For RSA keys, return + * |NID_rsaEncryption|. For ECDSA keys, return |NID_X9_62_prime256v1|, + * |NID_secp384r1|, or |NID_secp521r1|, depending on the curve. + * + * Returning |EVP_PKEY_EC| for ECDSA keys is deprecated and may result in + * connection failures in TLS 1.3. */ int (*type)(SSL *ssl); /* max_signature_len returns the maximum length of a signature signed by the * key used by |ssl|. This must be a constant value for a given |ssl|. */ size_t (*max_signature_len)(SSL *ssl); - /* sign signs |in_len| bytes of digest from |in|. |md| is the hash function - * used to calculate |in|. On success, it returns |ssl_private_key_success| - * and writes at most |max_out| bytes of signature data to |out|. On failure, - * it returns |ssl_private_key_failure|. If the operation has not completed, - * it returns |ssl_private_key_retry|. |sign| should arrange for the - * high-level operation on |ssl| to be retried when the operation is - * completed. This will result in a call to |sign_complete|. + /* sign signs the message |in| in using the specified signature algorithm. On + * success, it returns |ssl_private_key_success| and writes at most |max_out| + * bytes of signature data to |out| and sets |*out_len| to the number of bytes + * written. On failure, it returns |ssl_private_key_failure|. If the operation + * has not completed, it returns |ssl_private_key_retry|. |sign| should + * arrange for the high-level operation on |ssl| to be retried when the + * operation is completed. This will result in a call to |complete|. * - * If the key is an RSA key, implementations must use PKCS#1 padding. |in| is - * the digest itself, so the DigestInfo prefix, if any, must be prepended by - * |sign|. If |md| is |EVP_md5_sha1|, there is no prefix. + * |signature_algorithm| is one of the |SSL_SIGN_*| values, as defined in TLS + * 1.3. Note that, in TLS 1.2, ECDSA algorithms do not require that curve + * sizes match hash sizes, so the curve portion of |SSL_SIGN_ECDSA_*| values + * must be ignored. BoringSSL will internally handle the curve matching logic + * where appropriate. * * It is an error to call |sign| while another private key operation is in * progress on |ssl|. */ enum ssl_private_key_result_t (*sign)(SSL *ssl, uint8_t *out, size_t *out_len, - size_t max_out, const EVP_MD *md, + size_t max_out, + uint16_t signature_algorithm, const uint8_t *in, size_t in_len); - /* sign_complete completes a pending |sign| operation. If the operation has - * completed, it returns |ssl_private_key_success| and writes the result to - * |out| as in |sign|. Otherwise, it returns |ssl_private_key_failure| on - * failure and |ssl_private_key_retry| if the operation is still in progress. + /* sign_digest signs |in_len| bytes of digest from |in|. |md| is the hash + * function used to calculate |in|. On success, it returns + * |ssl_private_key_success| and writes at most |max_out| bytes of signature + * data to |out|. On failure, it returns |ssl_private_key_failure|. If the + * operation has not completed, it returns |ssl_private_key_retry|. |sign| + * should arrange for the high-level operation on |ssl| to be retried when the + * operation is completed. This will result in a call to |complete|. * - * |sign_complete| may be called arbitrarily many times before completion, but - * it is an error to call |sign_complete| if there is no pending |sign| - * operation in progress on |ssl|. */ - enum ssl_private_key_result_t (*sign_complete)(SSL *ssl, uint8_t *out, - size_t *out_len, - size_t max_out); + * If the key is an RSA key, implementations must use PKCS#1 padding. |in| is + * the digest itself, so the DigestInfo prefix, if any, must be prepended by + * |sign|. If |md| is |EVP_md5_sha1|, there is no prefix. + * + * It is an error to call |sign_digest| while another private key operation is + * in progress on |ssl|. + * + * This function is deprecated. Implement |sign| instead. + * + * TODO(davidben): Remove this function. */ + enum ssl_private_key_result_t (*sign_digest)(SSL *ssl, uint8_t *out, + size_t *out_len, size_t max_out, + const EVP_MD *md, + const uint8_t *in, + size_t in_len); /* decrypt decrypts |in_len| bytes of encrypted data from |in|. On success it * returns |ssl_private_key_success|, writes at most |max_out| bytes of @@ -974,9 +1108,9 @@ typedef struct ssl_private_key_method_st { * written. On failure it returns |ssl_private_key_failure|. If the operation * has not completed, it returns |ssl_private_key_retry|. The caller should * arrange for the high-level operation on |ssl| to be retried when the - * operation is completed, which will result in a call to |decrypt_complete|. - * This function only works with RSA keys and should perform a raw RSA - * decryption operation with no padding. + * operation is completed, which will result in a call to |complete|. This + * function only works with RSA keys and should perform a raw RSA decryption + * operation with no padding. * * It is an error to call |decrypt| while another private key operation is in * progress on |ssl|. */ @@ -984,18 +1118,16 @@ typedef struct ssl_private_key_method_st { size_t *out_len, size_t max_out, const uint8_t *in, size_t in_len); - /* decrypt_complete completes a pending |decrypt| operation. If the operation - * has completed, it returns |ssl_private_key_success| and writes the result - * to |out| as in |decrypt|. Otherwise, it returns |ssl_private_key_failure| - * on failure and |ssl_private_key_retry| if the operation is still in - * progress. + /* complete completes a pending operation. If the operation has completed, it + * returns |ssl_private_key_success| and writes the result to |out| as in + * |sign|. Otherwise, it returns |ssl_private_key_failure| on failure and + * |ssl_private_key_retry| if the operation is still in progress. * - * |decrypt_complete| may be called arbitrarily many times before completion, - * but it is an error to call |decrypt_complete| if there is no pending - * |decrypt| operation in progress on |ssl|. */ - enum ssl_private_key_result_t (*decrypt_complete)(SSL *ssl, uint8_t *out, - size_t *out_len, - size_t max_out); + * |complete| may be called arbitrarily many times before completion, but it + * is an error to call |complete| if there is no pending operation in progress + * on |ssl|. */ + enum ssl_private_key_result_t (*complete)(SSL *ssl, uint8_t *out, + size_t *out_len, size_t max_out); } SSL_PRIVATE_KEY_METHOD; /* SSL_set_private_key_method configures a custom private key on |ssl|. @@ -1003,6 +1135,11 @@ typedef struct ssl_private_key_method_st { OPENSSL_EXPORT void SSL_set_private_key_method( SSL *ssl, const SSL_PRIVATE_KEY_METHOD *key_method); +/* SSL_CTX_set_private_key_method configures a custom private key on |ctx|. + * |key_method| must remain valid for the lifetime of |ctx|. */ +OPENSSL_EXPORT void SSL_CTX_set_private_key_method( + SSL_CTX *ctx, const SSL_PRIVATE_KEY_METHOD *key_method); + /* Cipher suites. * @@ -1023,12 +1160,15 @@ OPENSSL_EXPORT uint32_t SSL_CIPHER_get_id(const SSL_CIPHER *cipher); * mode). */ OPENSSL_EXPORT int SSL_CIPHER_is_AES(const SSL_CIPHER *cipher); -/* SSL_CIPHER_has_MD5_HMAC returns one if |cipher| uses HMAC-MD5. */ -OPENSSL_EXPORT int SSL_CIPHER_has_MD5_HMAC(const SSL_CIPHER *cipher); - /* SSL_CIPHER_has_SHA1_HMAC returns one if |cipher| uses HMAC-SHA1. */ OPENSSL_EXPORT int SSL_CIPHER_has_SHA1_HMAC(const SSL_CIPHER *cipher); +/* SSL_CIPHER_has_SHA256_HMAC returns one if |cipher| uses HMAC-SHA256. */ +OPENSSL_EXPORT int SSL_CIPHER_has_SHA256_HMAC(const SSL_CIPHER *cipher); + +/* SSL_CIPHER_is_AEAD returns one if |cipher| uses an AEAD cipher. */ +OPENSSL_EXPORT int SSL_CIPHER_is_AEAD(const SSL_CIPHER *cipher); + /* SSL_CIPHER_is_AESGCM returns one if |cipher| uses AES-GCM. */ OPENSSL_EXPORT int SSL_CIPHER_is_AESGCM(const SSL_CIPHER *cipher); @@ -1044,35 +1184,43 @@ OPENSSL_EXPORT int SSL_CIPHER_is_AES128CBC(const SSL_CIPHER *cipher); OPENSSL_EXPORT int SSL_CIPHER_is_AES256CBC(const SSL_CIPHER *cipher); /* SSL_CIPHER_is_CHACHA20POLY1305 returns one if |cipher| uses - * CHACHA20_POLY1305. Note this includes both the - * draft-ietf-tls-chacha20-poly1305-04 and draft-agl-tls-chacha20poly1305-04 - * versions. */ + * CHACHA20_POLY1305. Note this includes both the RFC 7905 and + * draft-agl-tls-chacha20poly1305-04 versions. */ OPENSSL_EXPORT int SSL_CIPHER_is_CHACHA20POLY1305(const SSL_CIPHER *cipher); /* SSL_CIPHER_is_NULL returns one if |cipher| does not encrypt. */ OPENSSL_EXPORT int SSL_CIPHER_is_NULL(const SSL_CIPHER *cipher); -/* SSL_CIPHER_is_RC4 returns one if |cipher| uses RC4. */ -OPENSSL_EXPORT int SSL_CIPHER_is_RC4(const SSL_CIPHER *cipher); - /* SSL_CIPHER_is_block_cipher returns one if |cipher| is a block cipher. */ OPENSSL_EXPORT int SSL_CIPHER_is_block_cipher(const SSL_CIPHER *cipher); /* SSL_CIPHER_is_ECDSA returns one if |cipher| uses ECDSA. */ OPENSSL_EXPORT int SSL_CIPHER_is_ECDSA(const SSL_CIPHER *cipher); +/* SSL_CIPHER_is_DHE returns one if |cipher| uses DHE. */ +OPENSSL_EXPORT int SSL_CIPHER_is_DHE(const SSL_CIPHER *cipher); + /* SSL_CIPHER_is_ECDHE returns one if |cipher| uses ECDHE. */ OPENSSL_EXPORT int SSL_CIPHER_is_ECDHE(const SSL_CIPHER *cipher); +/* SSL_CIPHER_is_static_RSA returns one if |cipher| uses the static RSA key + * exchange. */ +OPENSSL_EXPORT int SSL_CIPHER_is_static_RSA(const SSL_CIPHER *cipher); + /* SSL_CIPHER_get_min_version returns the minimum protocol version required * for |cipher|. */ OPENSSL_EXPORT uint16_t SSL_CIPHER_get_min_version(const SSL_CIPHER *cipher); +/* SSL_CIPHER_get_max_version returns the maximum protocol version that + * supports |cipher|. */ +OPENSSL_EXPORT uint16_t SSL_CIPHER_get_max_version(const SSL_CIPHER *cipher); + /* SSL_CIPHER_get_name returns the OpenSSL name of |cipher|. */ OPENSSL_EXPORT const char *SSL_CIPHER_get_name(const SSL_CIPHER *cipher); /* SSL_CIPHER_get_kx_name returns a string that describes the key-exchange - * method used by |cipher|. For example, "ECDHE_ECDSA". */ + * method used by |cipher|. For example, "ECDHE_ECDSA". TLS 1.3 AEAD-only + * ciphers return the string "GENERIC". */ OPENSSL_EXPORT const char *SSL_CIPHER_get_kx_name(const SSL_CIPHER *cipher); /* SSL_CIPHER_get_rfc_name returns a newly-allocated string with the standard @@ -1136,11 +1284,11 @@ OPENSSL_EXPORT int SSL_CIPHER_get_bits(const SSL_CIPHER *cipher, * corresponding |k*| or |a*| cipher rule. |RSA| is an alias for |kRSA|, not * |aRSA|. * - * |3DES|, |RC4|, |AES128|, |AES256|, |AES|, |AESGCM|, |CHACHA20| match - * ciphers whose bulk cipher use the corresponding encryption scheme. Note - * that |AES|, |AES128|, and |AES256| match both CBC and GCM ciphers. + * |3DES|, |AES128|, |AES256|, |AES|, |AESGCM|, |CHACHA20| match ciphers + * whose bulk cipher use the corresponding encryption scheme. Note that + * |AES|, |AES128|, and |AES256| match both CBC and GCM ciphers. * - * |MD5|, |SHA1|, |SHA256|, and |SHA384| match legacy cipher suites using the + * |SHA1|, |SHA256|, and |SHA384| match legacy cipher suites using the * corresponding hash function in their MAC. AEADs are matched by none of * these. * @@ -1154,7 +1302,7 @@ OPENSSL_EXPORT int SSL_CIPHER_get_bits(const SSL_CIPHER *cipher, * |kEDH|, |EDH|, |kEECDH|, and |EECDH| are legacy aliases for |kDHE|, |DHE|, * |kECDHE|, and |ECDHE|, respectively. * - * |MEDIUM| and |HIGH| match RC4-based ciphers and all others, respectively. + * |HIGH| is an alias for |ALL|. * * |FIPS| is an alias for |HIGH|. * @@ -1162,7 +1310,9 @@ OPENSSL_EXPORT int SSL_CIPHER_get_bits(const SSL_CIPHER *cipher, * |TLSv1_2| matches ciphers new in TLS 1.2. This is confusing and should not * be used. * - * Unknown rules silently match nothing. + * Unknown rules are silently ignored by legacy APIs, and rejected by APIs with + * "strict" in the name, which should be preferred. Cipher lists can be long and + * it's easy to commit typos. * * The special |@STRENGTH| directive will sort all enabled ciphers by strength. * @@ -1180,35 +1330,43 @@ OPENSSL_EXPORT int SSL_CIPHER_get_bits(const SSL_CIPHER *cipher, * [ECDHE-ECDSA-CHACHA20-POLY1305|ECDHE-ECDSA-AES128-GCM-SHA256] * * Once an equal-preference group is used, future directives must be - * opcode-less. */ + * opcode-less. + * + * TLS 1.3 ciphers do not participate in this mechanism and instead have a + * built-in preference order. Functions to set cipher lists do not affect TLS + * 1.3, and functions to query the cipher list do not include TLS 1.3 + * ciphers. */ /* SSL_DEFAULT_CIPHER_LIST is the default cipher suite configuration. It is * substituted when a cipher string starts with 'DEFAULT'. */ #define SSL_DEFAULT_CIPHER_LIST "ALL" +/* SSL_CTX_set_strict_cipher_list configures the cipher list for |ctx|, + * evaluating |str| as a cipher string and returning error if |str| contains + * anything meaningless. It returns one on success and zero on failure. */ +OPENSSL_EXPORT int SSL_CTX_set_strict_cipher_list(SSL_CTX *ctx, + const char *str); + /* SSL_CTX_set_cipher_list configures the cipher list for |ctx|, evaluating - * |str| as a cipher string. It returns one on success and zero on failure. */ + * |str| as a cipher string. It returns one on success and zero on failure. + * + * Prefer to use |SSL_CTX_set_strict_cipher_list|. This function tolerates + * garbage inputs, unless an empty cipher list results. */ OPENSSL_EXPORT int SSL_CTX_set_cipher_list(SSL_CTX *ctx, const char *str); -/* SSL_CTX_set_cipher_list_tls10 configures the TLS 1.0+ cipher list for |ctx|, - * evaluating |str| as a cipher string. It returns one on success and zero on - * failure. If set, servers will use this cipher suite list for TLS 1.0 or - * higher. */ -OPENSSL_EXPORT int SSL_CTX_set_cipher_list_tls10(SSL_CTX *ctx, const char *str); - -/* SSL_CTX_set_cipher_list_tls11 configures the TLS 1.1+ cipher list for |ctx|, - * evaluating |str| as a cipher string. It returns one on success and zero on - * failure. If set, servers will use this cipher suite list for TLS 1.1 or - * higher. */ -OPENSSL_EXPORT int SSL_CTX_set_cipher_list_tls11(SSL_CTX *ctx, const char *str); +/* SSL_set_strict_cipher_list configures the cipher list for |ssl|, evaluating + * |str| as a cipher string and returning error if |str| contains anything + * meaningless. It returns one on success and zero on failure. */ +OPENSSL_EXPORT int SSL_set_strict_cipher_list(SSL *ssl, const char *str); /* SSL_set_cipher_list configures the cipher list for |ssl|, evaluating |str| as - * a cipher string. It returns one on success and zero on failure. */ + * a cipher string. It returns one on success and zero on failure. + * + * Prefer to use |SSL_set_strict_cipher_list|. This function tolerates garbage + * inputs, unless an empty cipher list results. */ OPENSSL_EXPORT int SSL_set_cipher_list(SSL *ssl, const char *str); -/* SSL_get_ciphers returns the cipher list for |ssl|, in order of preference. If - * |SSL_CTX_set_cipher_list_tls10| or |SSL_CTX_set_cipher_list_tls11| has been - * used, the corresponding list for the current version is returned. */ +/* SSL_get_ciphers returns the cipher list for |ssl|, in order of preference. */ OPENSSL_EXPORT STACK_OF(SSL_CIPHER) *SSL_get_ciphers(const SSL *ssl); @@ -1247,6 +1405,20 @@ OPENSSL_EXPORT X509 *SSL_get_peer_certificate(const SSL *ssl); * If a client, it does. */ OPENSSL_EXPORT STACK_OF(X509) *SSL_get_peer_cert_chain(const SSL *ssl); +/* SSL_get_peer_full_cert_chain returns the peer's certificate chain, or NULL if + * unavailable or the peer did not use certificates. This is the unverified + * list of certificates as sent by the peer, not the final chain built during + * verification. For historical reasons, this value may not be available if + * resuming a serialized |SSL_SESSION|. The caller does not take ownership of + * the result. + * + * This is the same as |SSL_get_peer_cert_chain| except that this function + * always returns the full chain, i.e. the first element of the return value + * (if any) will be the leaf certificate. In constrast, + * |SSL_get_peer_cert_chain| returns only the intermediate certificates if the + * |ssl| is a server. */ +OPENSSL_EXPORT STACK_OF(X509) *SSL_get_peer_full_cert_chain(const SSL *ssl); + /* SSL_get0_signed_cert_timestamp_list sets |*out| and |*out_len| to point to * |*out_len| bytes of SCT information from the server. This is only valid if * |ssl| is a client. The SCT information is a SignedCertificateTimestampList @@ -1287,8 +1459,8 @@ OPENSSL_EXPORT void SSL_get0_ocsp_response(const SSL *ssl, const uint8_t **out, OPENSSL_EXPORT int SSL_get_tls_unique(const SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out); -/* SSL_get_extms_support returns one if the Extended Master Secret - * extension was negotiated. Otherwise, it returns zero. */ +/* SSL_get_extms_support returns one if the Extended Master Secret extension or + * TLS 1.3 was negotiated. Otherwise, it returns zero. */ OPENSSL_EXPORT int SSL_get_extms_support(const SSL *ssl); /* SSL_get_current_cipher returns the cipher used in the current outgoing @@ -1303,7 +1475,7 @@ OPENSSL_EXPORT const SSL_CIPHER *SSL_get_current_cipher(const SSL *ssl); OPENSSL_EXPORT int SSL_session_reused(const SSL *ssl); /* SSL_get_secure_renegotiation_support returns one if the peer supports secure - * renegotiation (RFC 5746) and zero otherwise. */ + * renegotiation (RFC 5746) or TLS 1.3. Otherwise, it returns zero. */ OPENSSL_EXPORT int SSL_get_secure_renegotiation_support(const SSL *ssl); /* SSL_export_keying_material exports a value derived from the master secret, as @@ -1414,13 +1586,13 @@ DECLARE_LHASH_OF(SSL_SESSION) DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION) /* SSL_SESSION_new returns a newly-allocated blank |SSL_SESSION| or NULL on - * error. This may be useful in writing tests but otherwise should not be - * used outside the library. */ -OPENSSL_EXPORT SSL_SESSION *SSL_SESSION_new(void); + * error. This may be useful when writing tests but should otherwise not be + * used. */ +OPENSSL_EXPORT SSL_SESSION *SSL_SESSION_new(const SSL_CTX *ctx); -/* SSL_SESSION_up_ref, if |session| is not NULL, increments the reference count - * of |session|. It then returns |session|. */ -OPENSSL_EXPORT SSL_SESSION *SSL_SESSION_up_ref(SSL_SESSION *session); +/* SSL_SESSION_up_ref increments the reference count of |session| and returns + * one. */ +OPENSSL_EXPORT int SSL_SESSION_up_ref(SSL_SESSION *session); /* SSL_SESSION_free decrements the reference count of |session|. If it reaches * zero, all data referenced by |session| and |session| itself are released. */ @@ -1441,15 +1613,15 @@ OPENSSL_EXPORT int SSL_SESSION_to_bytes_for_ticket(const SSL_SESSION *in, /* SSL_SESSION_from_bytes parses |in_len| bytes from |in| as an SSL_SESSION. It * returns a newly-allocated |SSL_SESSION| on success or NULL on error. */ -OPENSSL_EXPORT SSL_SESSION *SSL_SESSION_from_bytes(const uint8_t *in, - size_t in_len); +OPENSSL_EXPORT SSL_SESSION *SSL_SESSION_from_bytes( + const uint8_t *in, size_t in_len, const SSL_CTX *ctx); /* SSL_SESSION_get_version returns a string describing the TLS version |session| * was established at. For example, "TLSv1.2" or "SSLv3". */ OPENSSL_EXPORT const char *SSL_SESSION_get_version(const SSL_SESSION *session); -/* SSL_SESSION_get_id returns a pointer to a buffer containg |session|'s session - * ID and sets |*out_len| to its length. */ +/* SSL_SESSION_get_id returns a pointer to a buffer containing |session|'s + * session ID and sets |*out_len| to its length. */ OPENSSL_EXPORT const uint8_t *SSL_SESSION_get_id(const SSL_SESSION *session, unsigned *out_len); @@ -1460,19 +1632,18 @@ OPENSSL_EXPORT long SSL_SESSION_get_time(const SSL_SESSION *session); /* SSL_SESSION_get_timeout returns the lifetime of |session| in seconds. */ OPENSSL_EXPORT long SSL_SESSION_get_timeout(const SSL_SESSION *session); -/* SSL_SESSION_get_key_exchange_info returns a value that describes the - * strength of the asymmetric operation that provides confidentiality to - * |session|. Its interpretation depends on the operation used. See the - * documentation for this value in the |SSL_SESSION| structure. */ -OPENSSL_EXPORT uint32_t SSL_SESSION_get_key_exchange_info( - const SSL_SESSION *session); - -/* SSL_SESSION_get0_peer return's the peer leaf certificate stored in +/* SSL_SESSION_get0_peer returns the peer leaf certificate stored in * |session|. * * TODO(davidben): This should return a const X509 *. */ OPENSSL_EXPORT X509 *SSL_SESSION_get0_peer(const SSL_SESSION *session); +/* SSL_SESSION_get_master_key writes up to |max_out| bytes of |session|'s master + * secret to |out| and returns the number of bytes written. If |max_out| is + * zero, it returns the size of the master secret. */ +OPENSSL_EXPORT size_t SSL_SESSION_get_master_key(const SSL_SESSION *session, + uint8_t *out, size_t max_out); + /* SSL_SESSION_set_time sets |session|'s creation time to |time| and returns * |time|. This function may be useful in writing tests but otherwise should not * be used. */ @@ -1489,7 +1660,7 @@ OPENSSL_EXPORT long SSL_SESSION_set_timeout(SSL_SESSION *session, long timeout); * should not be used. */ OPENSSL_EXPORT int SSL_SESSION_set1_id_context(SSL_SESSION *session, const uint8_t *sid_ctx, - unsigned sid_ctx_len); + size_t sid_ctx_len); /* Session caching. @@ -1511,7 +1682,7 @@ OPENSSL_EXPORT int SSL_SESSION_set1_id_context(SSL_SESSION *session, * * Note that offering or accepting a session short-circuits most parameter * negotiation. Resuming sessions across different configurations may result in - * surprising behavor. So, for instance, a client implementing a version + * surprising behavior. So, for instance, a client implementing a version * fallback should shard its session cache by maximum protocol version. */ /* SSL_SESS_CACHE_OFF disables all session caching. */ @@ -1524,7 +1695,7 @@ OPENSSL_EXPORT int SSL_SESSION_set1_id_context(SSL_SESSION *session, /* SSL_SESS_CACHE_SERVER enables session caching for a server. */ #define SSL_SESS_CACHE_SERVER 0x0002 -/* SSL_SESS_CACHE_SERVER enables session caching for both client and server. */ +/* SSL_SESS_CACHE_BOTH enables session caching for both client and server. */ #define SSL_SESS_CACHE_BOTH (SSL_SESS_CACHE_CLIENT | SSL_SESS_CACHE_SERVER) /* SSL_SESS_CACHE_NO_AUTO_CLEAR disables automatically calling @@ -1554,13 +1725,21 @@ OPENSSL_EXPORT int SSL_CTX_get_session_cache_mode(const SSL_CTX *ctx); /* SSL_set_session, for a client, configures |ssl| to offer to resume |session| * in the initial handshake and returns one. The caller retains ownership of - * |session|. */ + * |session|. + * + * It is an error to call this function after the handshake has begun. */ OPENSSL_EXPORT int SSL_set_session(SSL *ssl, SSL_SESSION *session); -/* SSL_get_session returns a non-owning pointer to |ssl|'s session. Prior to the - * initial handshake beginning, this is the session to be offered, set by - * |SSL_set_session|. After a handshake has finished, this is the currently - * active session. Its behavior is undefined while a handshake is progress. */ +/* SSL_get_session returns a non-owning pointer to |ssl|'s session. For + * historical reasons, which session it returns depends on |ssl|'s state. + * + * Prior to the start of the initial handshake, it returns the session the + * caller set with |SSL_set_session|. After the initial handshake has finished + * and if no additional handshakes are in progress, it returns the currently + * active session. Its behavior is undefined while a handshake is in progress. + * + * Using this function to add new sessions to an external session cache is + * deprecated. Use |SSL_CTX_sess_set_new_cb| instead. */ OPENSSL_EXPORT SSL_SESSION *SSL_get_session(const SSL *ssl); /* SSL_get0_session is an alias for |SSL_get_session|. */ @@ -1571,15 +1750,31 @@ OPENSSL_EXPORT SSL_SESSION *SSL_get_session(const SSL *ssl); OPENSSL_EXPORT SSL_SESSION *SSL_get1_session(SSL *ssl); /* SSL_DEFAULT_SESSION_TIMEOUT is the default lifetime, in seconds, of a - * session. */ + * session in TLS 1.2 or earlier. This is how long we are willing to use the + * secret to encrypt traffic without fresh key material. */ #define SSL_DEFAULT_SESSION_TIMEOUT (2 * 60 * 60) -/* SSL_CTX_set_timeout sets the lifetime, in seconds, of sessions created in - * |ctx| to |timeout|. */ +/* SSL_DEFAULT_SESSION_PSK_DHE_TIMEOUT is the default lifetime, in seconds, of a + * session for TLS 1.3 psk_dhe_ke. This is how long we are willing to use the + * secret as an authenticator. */ +#define SSL_DEFAULT_SESSION_PSK_DHE_TIMEOUT (2 * 24 * 60 * 60) + +/* SSL_DEFAULT_SESSION_AUTH_TIMEOUT is the default non-renewable lifetime, in + * seconds, of a TLS 1.3 session. This is how long we are willing to trust the + * signature in the initial handshake. */ +#define SSL_DEFAULT_SESSION_AUTH_TIMEOUT (7 * 24 * 60 * 60) + +/* SSL_CTX_set_timeout sets the lifetime, in seconds, of TLS 1.2 (or earlier) + * sessions created in |ctx| to |timeout|. */ OPENSSL_EXPORT long SSL_CTX_set_timeout(SSL_CTX *ctx, long timeout); -/* SSL_CTX_get_timeout returns the lifetime, in seconds, of sessions created in - * |ctx|. */ +/* SSL_CTX_set_session_psk_dhe_timeout sets the lifetime, in seconds, of TLS 1.3 + * sessions created in |ctx| to |timeout|. */ +OPENSSL_EXPORT void SSL_CTX_set_session_psk_dhe_timeout(SSL_CTX *ctx, + long timeout); + +/* SSL_CTX_get_timeout returns the lifetime, in seconds, of TLS 1.2 (or earlier) + * sessions created in |ctx|. */ OPENSSL_EXPORT long SSL_CTX_get_timeout(const SSL_CTX *ctx); /* SSL_CTX_set_session_id_context sets |ctx|'s session ID context to |sid_ctx|. @@ -1595,13 +1790,18 @@ OPENSSL_EXPORT long SSL_CTX_get_timeout(const SSL_CTX *ctx); * relevant if a server requires client auth. */ OPENSSL_EXPORT int SSL_CTX_set_session_id_context(SSL_CTX *ctx, const uint8_t *sid_ctx, - unsigned sid_ctx_len); + size_t sid_ctx_len); /* SSL_set_session_id_context sets |ssl|'s session ID context to |sid_ctx|. It * returns one on success and zero on error. See also * |SSL_CTX_set_session_id_context|. */ OPENSSL_EXPORT int SSL_set_session_id_context(SSL *ssl, const uint8_t *sid_ctx, - unsigned sid_ctx_len); + size_t sid_ctx_len); + +/* SSL_get0_session_id_context returns a pointer to |ssl|'s session ID context + * and sets |*out_len| to its length. */ +OPENSSL_EXPORT const uint8_t *SSL_get0_session_id_context(const SSL *ssl, + size_t *out_len); /* SSL_SESSION_CACHE_MAX_SIZE_DEFAULT is the default maximum size of a session * cache. */ @@ -1781,23 +1981,54 @@ OPENSSL_EXPORT int SSL_CTX_set_tlsext_ticket_key_cb( * are supported. ECDHE is always enabled, but the curve preferences may be * configured with these functions. * - * A client may use |SSL_SESSION_get_key_exchange_info| to determine the curve - * selected. */ + * Note that TLS 1.3 renames these from curves to groups. For consistency, we + * currently use the TLS 1.2 name in the API. */ /* SSL_CTX_set1_curves sets the preferred curves for |ctx| to be |curves|. Each * element of |curves| should be a curve nid. It returns one on success and - * zero on failure. */ + * zero on failure. + * + * Note that this API uses nid values from nid.h and not the |SSL_CURVE_*| + * values defined below. */ OPENSSL_EXPORT int SSL_CTX_set1_curves(SSL_CTX *ctx, const int *curves, size_t curves_len); /* SSL_set1_curves sets the preferred curves for |ssl| to be |curves|. Each * element of |curves| should be a curve nid. It returns one on success and - * zero on failure. */ + * zero on failure. + * + * Note that this API uses nid values from nid.h and not the |SSL_CURVE_*| + * values defined below. */ OPENSSL_EXPORT int SSL_set1_curves(SSL *ssl, const int *curves, size_t curves_len); -/* SSL_get_curve_name returns a human-readable name for the elliptic curve - * specified by the given TLS curve id, or NULL if the curve if unknown. */ +/* SSL_CTX_set1_curves_list sets the preferred curves for |ctx| to be the + * colon-separated list |curves|. Each element of |curves| should be a curve + * name (e.g. P-256, X25519, ...). It returns one on success and zero on + * failure. */ +OPENSSL_EXPORT int SSL_CTX_set1_curves_list(SSL_CTX *ctx, const char *curves); + +/* SSL_set1_curves_list sets the preferred curves for |ssl| to be the + * colon-separated list |curves|. Each element of |curves| should be a curve + * name (e.g. P-256, X25519, ...). It returns one on success and zero on + * failure. */ +OPENSSL_EXPORT int SSL_set1_curves_list(SSL *ssl, const char *curves); + +/* SSL_CURVE_* define TLS curve IDs. */ +#define SSL_CURVE_SECP256R1 23 +#define SSL_CURVE_SECP384R1 24 +#define SSL_CURVE_SECP521R1 25 +#define SSL_CURVE_X25519 29 + +/* SSL_get_curve_id returns the ID of the curve used by |ssl|'s most recently + * completed handshake or 0 if not applicable. + * + * TODO(davidben): This API currently does not work correctly if there is a + * renegotiation in progress. Fix this. */ +OPENSSL_EXPORT uint16_t SSL_get_curve_id(const SSL *ssl); + +/* SSL_get_curve_name returns a human-readable name for the curve specified by + * the given TLS curve id, or NULL if the curve is unknown. */ OPENSSL_EXPORT const char *SSL_get_curve_name(uint16_t curve_id); @@ -1805,11 +2036,7 @@ OPENSSL_EXPORT const char *SSL_get_curve_name(uint16_t curve_id); * * Cipher suites using a DHE key exchange perform Diffie-Hellman over a * multiplicative group selected by the server. These ciphers are disabled for a - * server unless a group is chosen with one of these functions. - * - * A client may use |SSL_SESSION_get_key_exchange_info| to determine the size of - * the selected group's prime, but note that servers may select degenerate - * groups. */ + * server unless a group is chosen with one of these functions. */ /* SSL_CTX_set_tmp_dh configures |ctx| to use the group from |dh| as the group * for DHE. Only the group is used, so |dh| needn't have a keypair. It returns @@ -2012,9 +2239,6 @@ OPENSSL_EXPORT int SSL_CTX_load_verify_locations(SSL_CTX *ctx, * either |X509_V_OK| or a |X509_V_ERR_*| value. */ OPENSSL_EXPORT long SSL_get_verify_result(const SSL *ssl); -/* SSL_set_verify_result overrides the result of certificate verification. */ -OPENSSL_EXPORT void SSL_set_verify_result(SSL *ssl, long result); - /* SSL_get_ex_data_X509_STORE_CTX_idx returns the ex_data index used to look up * the |SSL| associated with an |X509_STORE_CTX| in the verify callback. */ OPENSSL_EXPORT int SSL_get_ex_data_X509_STORE_CTX_idx(void); @@ -2025,20 +2249,19 @@ OPENSSL_EXPORT int SSL_get_ex_data_X509_STORE_CTX_idx(void); * zero on fatal error. It may use |X509_STORE_CTX_set_error| to set a * verification result. * - * The callback may use either the |arg| parameter or - * |SSL_get_ex_data_X509_STORE_CTX_idx| to recover the associated |SSL| - * object. */ + * The callback may use |SSL_get_ex_data_X509_STORE_CTX_idx| to recover the + * |SSL| object from |store_ctx|. */ OPENSSL_EXPORT void SSL_CTX_set_cert_verify_callback( SSL_CTX *ctx, int (*callback)(X509_STORE_CTX *store_ctx, void *arg), void *arg); /* SSL_enable_signed_cert_timestamps causes |ssl| (which must be the client end * of a connection) to request SCTs from the server. See - * https://tools.ietf.org/html/rfc6962. It returns one. + * https://tools.ietf.org/html/rfc6962. * * Call |SSL_get0_signed_cert_timestamp_list| to recover the SCT after the * handshake. */ -OPENSSL_EXPORT int SSL_enable_signed_cert_timestamps(SSL *ssl); +OPENSSL_EXPORT void SSL_enable_signed_cert_timestamps(SSL *ssl); /* SSL_CTX_enable_signed_cert_timestamps enables SCT requests on all client SSL * objects created from |ctx|. @@ -2048,12 +2271,11 @@ OPENSSL_EXPORT int SSL_enable_signed_cert_timestamps(SSL *ssl); OPENSSL_EXPORT void SSL_CTX_enable_signed_cert_timestamps(SSL_CTX *ctx); /* SSL_enable_ocsp_stapling causes |ssl| (which must be the client end of a - * connection) to request a stapled OCSP response from the server. It returns - * one. + * connection) to request a stapled OCSP response from the server. * * Call |SSL_get0_ocsp_response| to recover the OCSP response after the * handshake. */ -OPENSSL_EXPORT int SSL_enable_ocsp_stapling(SSL *ssl); +OPENSSL_EXPORT void SSL_enable_ocsp_stapling(SSL *ssl); /* SSL_CTX_enable_ocsp_stapling enables OCSP stapling on all client SSL objects * created from |ctx|. @@ -2062,6 +2284,28 @@ OPENSSL_EXPORT int SSL_enable_ocsp_stapling(SSL *ssl); * handshake. */ OPENSSL_EXPORT void SSL_CTX_enable_ocsp_stapling(SSL_CTX *ctx); +/* SSL_CTX_set0_verify_cert_store sets an |X509_STORE| that will be used + * exclusively for certificate verification and returns one. Ownership of + * |store| is transferred to the |SSL_CTX|. */ +OPENSSL_EXPORT int SSL_CTX_set0_verify_cert_store(SSL_CTX *ctx, + X509_STORE *store); + +/* SSL_CTX_set1_verify_cert_store sets an |X509_STORE| that will be used + * exclusively for certificate verification and returns one. An additional + * reference to |store| will be taken. */ +OPENSSL_EXPORT int SSL_CTX_set1_verify_cert_store(SSL_CTX *ctx, + X509_STORE *store); + +/* SSL_set0_verify_cert_store sets an |X509_STORE| that will be used + * exclusively for certificate verification and returns one. Ownership of + * |store| is transferred to the |SSL|. */ +OPENSSL_EXPORT int SSL_set0_verify_cert_store(SSL *ssl, X509_STORE *store); + +/* SSL_set1_verify_cert_store sets an |X509_STORE| that will be used + * exclusively for certificate verification and returns one. An additional + * reference to |store| will be taken. */ +OPENSSL_EXPORT int SSL_set1_verify_cert_store(SSL *ssl, X509_STORE *store); + /* Client certificate CA list. * @@ -2118,12 +2362,6 @@ OPENSSL_EXPORT STACK_OF(X509_NAME) *SSL_dup_CA_list(STACK_OF(X509_NAME) *list); OPENSSL_EXPORT int SSL_add_file_cert_subjects_to_stack(STACK_OF(X509_NAME) *out, const char *file); -/* SSL_add_dir_cert_subjects_to_stack lists files in directory |dir|. It calls - * |SSL_add_file_cert_subjects_to_stack| on each file and returns one on success - * or zero on error. */ -OPENSSL_EXPORT int SSL_add_dir_cert_subjects_to_stack(STACK_OF(X509_NAME) *out, - const char *dir); - /* Server name indication. * @@ -2149,14 +2387,15 @@ OPENSSL_EXPORT int SSL_get_servername_type(const SSL *ssl); /* SSL_CTX_set_tlsext_servername_callback configures |callback| to be called on * the server after ClientHello extensions have been parsed and returns one. - * The callback may use |SSL_get_servername| to examine the server_name extension - * and returns a |SSL_TLSEXT_ERR_*| value. The value of |arg| may be set by - * calling |SSL_CTX_set_tlsext_servername_arg|. + * The callback may use |SSL_get_servername| to examine the server_name + * extension and returns a |SSL_TLSEXT_ERR_*| value. The value of |arg| may be + * set by calling |SSL_CTX_set_tlsext_servername_arg|. * * If the callback returns |SSL_TLSEXT_ERR_NOACK|, the server_name extension is * not acknowledged in the ServerHello. If the return value is - * |SSL_TLSEXT_ERR_ALERT_FATAL| or |SSL_TLSEXT_ERR_ALERT_WARNING| then - * |*out_alert| must be set to the alert value to send. */ + * |SSL_TLSEXT_ERR_ALERT_FATAL|, then |*out_alert| is the alert to send, + * defaulting to |SSL_AD_UNRECOGNIZED_NAME|. |SSL_TLSEXT_ERR_ALERT_WARNING| is + * ignored and treated as |SSL_TLSEXT_ERR_OK|. */ OPENSSL_EXPORT int SSL_CTX_set_tlsext_servername_callback( SSL_CTX *ctx, int (*callback)(SSL *ssl, int *out_alert, void *arg)); @@ -2171,7 +2410,7 @@ OPENSSL_EXPORT int SSL_CTX_set_tlsext_servername_arg(SSL_CTX *ctx, void *arg); #define SSL_TLSEXT_ERR_NOACK 3 -/* Application-layer protocol negotation. +/* Application-layer protocol negotiation. * * The ALPN extension (RFC 7301) allows negotiating different application-layer * protocols over a single port. This is used, for example, to negotiate @@ -2207,7 +2446,10 @@ OPENSSL_EXPORT int SSL_set_alpn_protos(SSL *ssl, const uint8_t *protos, * |*out_len| to the selected protocol and return |SSL_TLSEXT_ERR_OK| on * success. It does not pass ownership of the buffer. Otherwise, it should * return |SSL_TLSEXT_ERR_NOACK|. Other |SSL_TLSEXT_ERR_*| values are - * unimplemented and will be treated as |SSL_TLSEXT_ERR_NOACK|. */ + * unimplemented and will be treated as |SSL_TLSEXT_ERR_NOACK|. + * + * The cipher suite is selected before negotiating ALPN. The callback may use + * |SSL_get_pending_cipher| to query the cipher suite. */ OPENSSL_EXPORT void SSL_CTX_set_alpn_select_cb( SSL_CTX *ctx, int (*cb)(SSL *ssl, const uint8_t **out, uint8_t *out_len, const uint8_t *in, unsigned in_len, void *arg), @@ -2283,7 +2525,7 @@ OPENSSL_EXPORT void SSL_get0_next_proto_negotiated(const SSL *ssl, * or have a default application level protocol. * * 2) If the server supports NPN, but advertises an empty list then the - * client selects the first protcol in its list, but indicates via the + * client selects the first protocol in its list, but indicates via the * API that this fallback case was enacted. * * 3) Otherwise, the client finds the first protocol in the server's list @@ -2311,15 +2553,14 @@ OPENSSL_EXPORT int SSL_select_next_proto(uint8_t **out, uint8_t *out_len, * * See draft-balfanz-tls-channelid-01. */ -/* SSL_CTX_enable_tls_channel_id either configures a TLS server to accept TLS - * Channel IDs from clients, or configures a client to send TLS Channel IDs to - * a server. It returns one. */ -OPENSSL_EXPORT int SSL_CTX_enable_tls_channel_id(SSL_CTX *ctx); +/* SSL_CTX_set_tls_channel_id_enabled configures whether connections associated + * with |ctx| should enable Channel ID. */ +OPENSSL_EXPORT void SSL_CTX_set_tls_channel_id_enabled(SSL_CTX *ctx, + int enabled); -/* SSL_enable_tls_channel_id either configures a TLS server to accept TLS - * Channel IDs from clients, or configures a client to send TLS Channel IDs to - * server. It returns one. */ -OPENSSL_EXPORT int SSL_enable_tls_channel_id(SSL *ssl); +/* SSL_set_tls_channel_id_enabled configures whether |ssl| should enable Channel + * ID. */ +OPENSSL_EXPORT void SSL_set_tls_channel_id_enabled(SSL *ssl, int enabled); /* SSL_CTX_set1_tls_channel_id configures a TLS client to send a TLS Channel ID * to compatible servers. |private_key| must be a P-256 EC key. It returns one @@ -2526,8 +2767,10 @@ OPENSSL_EXPORT const char *SSL_get_psk_identity(const SSL *ssl); #define SSL_AD_PROTOCOL_VERSION TLS1_AD_PROTOCOL_VERSION #define SSL_AD_INSUFFICIENT_SECURITY TLS1_AD_INSUFFICIENT_SECURITY #define SSL_AD_INTERNAL_ERROR TLS1_AD_INTERNAL_ERROR +#define SSL_AD_INAPPROPRIATE_FALLBACK SSL3_AD_INAPPROPRIATE_FALLBACK #define SSL_AD_USER_CANCELLED TLS1_AD_USER_CANCELLED #define SSL_AD_NO_RENEGOTIATION TLS1_AD_NO_RENEGOTIATION +#define SSL_AD_MISSING_EXTENSION TLS1_AD_MISSING_EXTENSION #define SSL_AD_UNSUPPORTED_EXTENSION TLS1_AD_UNSUPPORTED_EXTENSION #define SSL_AD_CERTIFICATE_UNOBTAINABLE TLS1_AD_CERTIFICATE_UNOBTAINABLE #define SSL_AD_UNRECOGNIZED_NAME TLS1_AD_UNRECOGNIZED_NAME @@ -2535,7 +2778,7 @@ OPENSSL_EXPORT const char *SSL_get_psk_identity(const SSL *ssl); TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE #define SSL_AD_BAD_CERTIFICATE_HASH_VALUE TLS1_AD_BAD_CERTIFICATE_HASH_VALUE #define SSL_AD_UNKNOWN_PSK_IDENTITY TLS1_AD_UNKNOWN_PSK_IDENTITY -#define SSL_AD_INAPPROPRIATE_FALLBACK SSL3_AD_INAPPROPRIATE_FALLBACK +#define SSL_AD_CERTIFICATE_REQUIRED TLS1_AD_CERTIFICATE_REQUIRED /* SSL_alert_type_string_long returns a string description of |value| as an * alert type (warning or fatal). */ @@ -2545,6 +2788,16 @@ OPENSSL_EXPORT const char *SSL_alert_type_string_long(int value); * alert description or "unknown" if unknown. */ OPENSSL_EXPORT const char *SSL_alert_desc_string_long(int value); +/* SSL_send_fatal_alert sends a fatal alert over |ssl| of the specified type, + * which should be one of the |SSL_AD_*| constants. It returns one on success + * and <= 0 on error. The caller should pass the return value into + * |SSL_get_error| to determine how to proceed. Once this function has been + * called, future calls to |SSL_write| will fail. + * + * If retrying a failed operation due to |SSL_ERROR_WANT_WRITE|, subsequent + * calls must use the same |alert| parameter. */ +OPENSSL_EXPORT int SSL_send_fatal_alert(SSL *ssl, uint8_t alert); + /* ex_data functions. * @@ -2576,12 +2829,6 @@ OPENSSL_EXPORT int SSL_CTX_get_ex_new_index(long argl, void *argp, /* Low-level record-layer state. */ -/* SSL_get_rc4_state sets |*read_key| and |*write_key| to the RC4 states for - * the read and write directions. It returns one on success or zero if |ssl| - * isn't using an RC4-based cipher suite. */ -OPENSSL_EXPORT int SSL_get_rc4_state(const SSL *ssl, const RC4_KEY **read_key, - const RC4_KEY **write_key); - /* SSL_get_ivs sets |*out_iv_len| to the length of the IVs for the ciphers * underlying |ssl| and sets |*out_read_iv| and |*out_write_iv| to point to the * current IVs for the read and write directions. This is only meaningful for @@ -2634,7 +2881,10 @@ OPENSSL_EXPORT void SSL_get_structure_sizes(size_t *ssl_size, * For each handshake message, ChangeCipherSpec, and alert, |version| is the * protocol version and |content_type| is the corresponding record type. The * |len| bytes from |buf| contain the handshake message, one-byte - * ChangeCipherSpec body, and two-byte alert, respectively. */ + * ChangeCipherSpec body, and two-byte alert, respectively. + * + * For a V2ClientHello, |version| is |SSL2_VERSION|, |content_type| is zero, and + * the |len| bytes from |buf| contain the V2ClientHello structure. */ OPENSSL_EXPORT void SSL_CTX_set_msg_callback( SSL_CTX *ctx, void (*cb)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg)); @@ -2662,6 +2912,18 @@ OPENSSL_EXPORT void SSL_set_msg_callback_arg(SSL *ssl, void *arg); OPENSSL_EXPORT void SSL_CTX_set_keylog_callback( SSL_CTX *ctx, void (*cb)(const SSL *ssl, const char *line)); +/* SSL_CTX_get_keylog_callback returns the callback configured by + * |SSL_CTX_set_keylog_callback|. */ +OPENSSL_EXPORT void (*SSL_CTX_get_keylog_callback(const SSL_CTX *ctx))( + const SSL *ssl, const char *line); + +/* SSL_CTX_set_current_time_cb configures a callback to retrieve the current + * time, which should be set in |*out_clock|. This can be used for testing + * purposes; for example, a callback can be configured that returns a time + * set explicitly by the test. */ +OPENSSL_EXPORT void SSL_CTX_set_current_time_cb( + SSL_CTX *ctx, void (*cb)(const SSL *ssl, struct timeval *out_clock)); + enum ssl_renegotiate_mode_t { ssl_renegotiate_never = 0, ssl_renegotiate_once, @@ -2690,12 +2952,17 @@ OPENSSL_EXPORT void SSL_set_renegotiate_mode(SSL *ssl, OPENSSL_EXPORT int SSL_renegotiate_pending(SSL *ssl); /* SSL_total_renegotiations returns the total number of renegotiation handshakes - * peformed by |ssl|. This includes the pending renegotiation, if any. */ + * performed by |ssl|. This includes the pending renegotiation, if any. */ OPENSSL_EXPORT int SSL_total_renegotiations(const SSL *ssl); +/* SSL_CTX_set_early_data_enabled sets whether early data is allowed to be used + * with resumptions using |ctx|. WARNING: This is experimental and may cause + * interoperability failures until fully implemented. */ +OPENSSL_EXPORT void SSL_CTX_set_early_data_enabled(SSL_CTX *ctx, int enabled); + /* SSL_MAX_CERT_LIST_DEFAULT is the default maximum length, in bytes, of a peer * certificate chain. */ -#define SSL_MAX_CERT_LIST_DEFAULT 1024 * 100 +#define SSL_MAX_CERT_LIST_DEFAULT (1024 * 100) /* SSL_CTX_get_max_cert_list returns the maximum length, in bytes, of a peer * certificate chain accepted by |ctx|. */ @@ -2730,13 +2997,21 @@ OPENSSL_EXPORT int SSL_CTX_set_max_send_fragment(SSL_CTX *ctx, OPENSSL_EXPORT int SSL_set_max_send_fragment(SSL *ssl, size_t max_send_fragment); -/* ssl_early_callback_ctx is passed to certain callbacks that are called very - * early on during the server handshake. At this point, much of the SSL* hasn't - * been filled out and only the ClientHello can be depended on. */ -struct ssl_early_callback_ctx { +/* SSL_get_v2clienthello_count returns the total number of V2ClientHellos that + * are accepted. */ +OPENSSL_EXPORT uint64_t SSL_get_v2clienthello_count(void); + +/* ssl_early_callback_ctx (aka |SSL_CLIENT_HELLO|) is passed to certain + * callbacks that are called very early on during the server handshake. At this + * point, much of the SSL* hasn't been filled out and only the ClientHello can + * be depended on. */ +typedef struct ssl_early_callback_ctx { SSL *ssl; const uint8_t *client_hello; size_t client_hello_len; + uint16_t version; + const uint8_t *random; + size_t random_len; const uint8_t *session_id; size_t session_id_len; const uint8_t *cipher_suites; @@ -2745,15 +3020,15 @@ struct ssl_early_callback_ctx { size_t compression_methods_len; const uint8_t *extensions; size_t extensions_len; -}; +} SSL_CLIENT_HELLO; -/* SSL_early_callback_ctx_extension_get searches the extensions in |ctx| for an - * extension of the given type. If not found, it returns zero. Otherwise it - * sets |out_data| to point to the extension contents (not including the type - * and length bytes), sets |out_len| to the length of the extension contents - * and returns one. */ +/* SSL_early_callback_ctx_extension_get searches the extensions in + * |client_hello| for an extension of the given type. If not found, it returns + * zero. Otherwise it sets |out_data| to point to the extension contents (not + * including the type and length bytes), sets |out_len| to the length of the + * extension contents and returns one. */ OPENSSL_EXPORT int SSL_early_callback_ctx_extension_get( - const struct ssl_early_callback_ctx *ctx, uint16_t extension_type, + const SSL_CLIENT_HELLO *client_hello, uint16_t extension_type, const uint8_t **out_data, size_t *out_len); /* SSL_CTX_set_select_certificate_cb sets a callback that is called before most @@ -2763,19 +3038,16 @@ OPENSSL_EXPORT int SSL_early_callback_ctx_extension_get( * pause the handshake to perform an asynchronous operation. If paused, * |SSL_get_error| will return |SSL_ERROR_PENDING_CERTIFICATE|. * - * Note: The |ssl_early_callback_ctx| is only valid for the duration of the - * callback and is not valid while the handshake is paused. Further, unlike with - * most callbacks, when the handshake loop is resumed, it will not call the - * callback a second time. The caller must finish reconfiguring the connection - * before resuming the handshake. */ + * Note: The |SSL_CLIENT_HELLO| is only valid for the duration of the callback + * and is not valid while the handshake is paused. */ OPENSSL_EXPORT void SSL_CTX_set_select_certificate_cb( - SSL_CTX *ctx, int (*cb)(const struct ssl_early_callback_ctx *)); + SSL_CTX *ctx, int (*cb)(const SSL_CLIENT_HELLO *)); /* SSL_CTX_set_dos_protection_cb sets a callback that is called once the * resumption decision for a ClientHello has been made. It can return one to * allow the handshake to continue or zero to cause the handshake to abort. */ OPENSSL_EXPORT void SSL_CTX_set_dos_protection_cb( - SSL_CTX *ctx, int (*cb)(const struct ssl_early_callback_ctx *)); + SSL_CTX *ctx, int (*cb)(const SSL_CLIENT_HELLO *)); /* SSL_ST_* are possible values for |SSL_state| and the bitmasks that make them * up. */ @@ -2785,6 +3057,7 @@ OPENSSL_EXPORT void SSL_CTX_set_dos_protection_cb( #define SSL_ST_INIT (SSL_ST_CONNECT | SSL_ST_ACCEPT) #define SSL_ST_OK 0x03 #define SSL_ST_RENEGOTIATE (0x04 | SSL_ST_INIT) +#define SSL_ST_TLS13 (0x05 | SSL_ST_INIT) /* SSL_CB_* are possible values for the |type| parameter in the info * callback and the bitmasks that make them up. */ @@ -2803,14 +3076,14 @@ OPENSSL_EXPORT void SSL_CTX_set_dos_protection_cb( #define SSL_CB_HANDSHAKE_DONE 0x20 /* SSL_CTX_set_info_callback configures a callback to be run when various - * events occur during a connection's lifetime. The |type| argumentj determines + * events occur during a connection's lifetime. The |type| argument determines * the type of event and the meaning of the |value| argument. Callbacks must * ignore unexpected |type| values. * * |SSL_CB_READ_ALERT| is signaled for each alert received, warning or fatal. * The |value| argument is a 16-bit value where the alert level (either - * |SSL3_AL_WARNING| or |SSL3_AL_FATAL|) is in the most-significant eight bits and - * the alert type (one of |SSL_AD_*|) is in the least-significant eight. + * |SSL3_AL_WARNING| or |SSL3_AL_FATAL|) is in the most-significant eight bits + * and the alert type (one of |SSL_AD_*|) is in the least-significant eight. * * |SSL_CB_WRITE_ALERT| is signaled for each alert sent. The |value| argument * is constructed as with |SSL_CB_READ_ALERT|. @@ -2827,8 +3100,7 @@ OPENSSL_EXPORT void SSL_CTX_set_dos_protection_cb( * * |SSL_CB_ACCEPT_LOOP| (respectively, |SSL_CB_CONNECT_LOOP|) is signaled when * a server (respectively, client) handshake progresses. The |value| argument - * is always one. For the duration of the callback, |SSL_state| will return the - * previous state. + * is always one. * * |SSL_CB_ACCEPT_EXIT| (respectively, |SSL_CB_CONNECT_EXIT|) is signaled when * a server (respectively, client) handshake completes, fails, or is paused. @@ -2879,10 +3151,9 @@ OPENSSL_EXPORT SSL_CTX *SSL_set_SSL_CTX(SSL *ssl, SSL_CTX *ctx); * respectively. */ OPENSSL_EXPORT int SSL_get_shutdown(const SSL *ssl); -/* SSL_get_server_key_exchange_hash, on a client, returns the hash the server - * used to sign the ServerKeyExchange in TLS 1.2. If not applicable, it returns - * |TLSEXT_hash_none|. */ -OPENSSL_EXPORT uint8_t SSL_get_server_key_exchange_hash(const SSL *ssl); +/* SSL_get_peer_signature_algorithm returns the signature algorithm used by the + * peer. If not applicable, it returns zero. */ +OPENSSL_EXPORT uint16_t SSL_get_peer_signature_algorithm(const SSL *ssl); /* SSL_get_client_random writes up to |max_out| bytes of the most recent * handshake's client_random to |out| and returns the number of bytes written. @@ -2900,6 +3171,14 @@ OPENSSL_EXPORT size_t SSL_get_server_random(const SSL *ssl, uint8_t *out, * NULL if one has not been negotiated yet or there is no pending handshake. */ OPENSSL_EXPORT const SSL_CIPHER *SSL_get_pending_cipher(const SSL *ssl); +/* SSL_set_retain_only_sha256_of_client_certs, on a server, sets whether only + * the SHA-256 hash of peer's certificate should be saved in memory and in the + * session. This can save memory, ticket size and session cache space. If + * enabled, |SSL_get_peer_certificate| will return NULL after the handshake + * completes. See the |peer_sha256| field of |SSL_SESSION| for the hash. */ +OPENSSL_EXPORT void SSL_set_retain_only_sha256_of_client_certs(SSL *ssl, + int enable); + /* SSL_CTX_set_retain_only_sha256_of_client_certs, on a server, sets whether * only the SHA-256 hash of peer's certificate should be saved in memory and in * the session. This can save memory, ticket size and session cache space. If @@ -2908,17 +3187,25 @@ OPENSSL_EXPORT const SSL_CIPHER *SSL_get_pending_cipher(const SSL *ssl); OPENSSL_EXPORT void SSL_CTX_set_retain_only_sha256_of_client_certs(SSL_CTX *ctx, int enable); +/* SSL_CTX_set_grease_enabled configures whether sockets on |ctx| should enable + * GREASE. See draft-davidben-tls-grease-01. */ +OPENSSL_EXPORT void SSL_CTX_set_grease_enabled(SSL_CTX *ctx, int enabled); + +/* SSL_max_seal_overhead returns the maximum overhead, in bytes, of sealing a + * record with |ssl|. */ +OPENSSL_EXPORT size_t SSL_max_seal_overhead(const SSL *ssl); + +/* SSL_CTX_set_short_header_enabled configures whether a short record header in + * TLS 1.3 may be negotiated. This allows client and server to negotiate + * https://github.com/tlswg/tls13-spec/pull/762 for testing. */ +OPENSSL_EXPORT void SSL_CTX_set_short_header_enabled(SSL_CTX *ctx, int enabled); + /* Deprecated functions. */ /* SSL_library_init calls |CRYPTO_library_init| and returns one. */ OPENSSL_EXPORT int SSL_library_init(void); -/* SSL_set_reject_peer_renegotiations calls |SSL_set_renegotiate_mode| with - * |ssl_never_renegotiate| if |reject| is one and |ssl_renegotiate_freely| if - * zero. */ -OPENSSL_EXPORT void SSL_set_reject_peer_renegotiations(SSL *ssl, int reject); - /* SSL_CIPHER_description writes a description of |cipher| into |buf| and * returns |buf|. If |buf| is NULL, it returns a newly allocated string, to be * freed with |OPENSSL_free|, or NULL on error. @@ -2944,12 +3231,16 @@ OPENSSL_EXPORT int SSL_COMP_add_compression_method(int id, COMP_METHOD *cm); /* SSL_COMP_get_name returns NULL. */ OPENSSL_EXPORT const char *SSL_COMP_get_name(const COMP_METHOD *comp); +/* SSL_COMP_free_compression_methods does nothing. */ +OPENSSL_EXPORT void SSL_COMP_free_compression_methods(void); + /* SSLv23_method calls |TLS_method|. */ OPENSSL_EXPORT const SSL_METHOD *SSLv23_method(void); /* These version-specific methods behave exactly like |TLS_method| and - * |DTLS_method| except they also call |SSL_CTX_set_min_version| and - * |SSL_CTX_set_max_version| to lock connections to that protocol version. */ + * |DTLS_method| except they also call |SSL_CTX_set_min_proto_version| and + * |SSL_CTX_set_max_proto_version| to lock connections to that protocol + * version. */ OPENSSL_EXPORT const SSL_METHOD *SSLv3_method(void); OPENSSL_EXPORT const SSL_METHOD *TLSv1_method(void); OPENSSL_EXPORT const SSL_METHOD *TLSv1_1_method(void); @@ -2959,6 +3250,8 @@ OPENSSL_EXPORT const SSL_METHOD *DTLSv1_2_method(void); /* These client- and server-specific methods call their corresponding generic * methods. */ +OPENSSL_EXPORT const SSL_METHOD *TLS_server_method(void); +OPENSSL_EXPORT const SSL_METHOD *TLS_client_method(void); OPENSSL_EXPORT const SSL_METHOD *SSLv23_server_method(void); OPENSSL_EXPORT const SSL_METHOD *SSLv23_client_method(void); OPENSSL_EXPORT const SSL_METHOD *SSLv3_server_method(void); @@ -3061,6 +3354,10 @@ OPENSSL_EXPORT int SSL_renegotiate(SSL *ssl); /* SSL_set_state does nothing. */ OPENSSL_EXPORT void SSL_set_state(SSL *ssl, int state); +/* SSL_get_shared_ciphers writes an empty string to |buf| and returns a + * pointer to |buf|, or NULL if |len| is less than or equal to zero. */ +OPENSSL_EXPORT char *SSL_get_shared_ciphers(const SSL *ssl, char *buf, int len); + /* SSL_MODE_HANDSHAKE_CUTTHROUGH is the same as SSL_MODE_ENABLE_FALSE_START. */ #define SSL_MODE_HANDSHAKE_CUTTHROUGH SSL_MODE_ENABLE_FALSE_START @@ -3119,30 +3416,33 @@ OPENSSL_EXPORT const COMP_METHOD *SSL_get_current_compression(SSL *s); /* SSL_get_current_expansion returns NULL. */ OPENSSL_EXPORT const COMP_METHOD *SSL_get_current_expansion(SSL *s); -#define SSL_set_app_data(s, arg) (SSL_set_ex_data(s, 0, (char *)arg)) +/* SSL_get_server_tmp_key returns zero. */ +OPENSSL_EXPORT int *SSL_get_server_tmp_key(SSL *ssl, EVP_PKEY **out_key); + +#define SSL_set_app_data(s, arg) (SSL_set_ex_data(s, 0, (char *)(arg))) #define SSL_get_app_data(s) (SSL_get_ex_data(s, 0)) #define SSL_SESSION_set_app_data(s, a) \ - (SSL_SESSION_set_ex_data(s, 0, (char *)a)) + (SSL_SESSION_set_ex_data(s, 0, (char *)(a))) #define SSL_SESSION_get_app_data(s) (SSL_SESSION_get_ex_data(s, 0)) #define SSL_CTX_get_app_data(ctx) (SSL_CTX_get_ex_data(ctx, 0)) #define SSL_CTX_set_app_data(ctx, arg) \ - (SSL_CTX_set_ex_data(ctx, 0, (char *)arg)) + (SSL_CTX_set_ex_data(ctx, 0, (char *)(arg))) #define OpenSSL_add_ssl_algorithms() SSL_library_init() #define SSLeay_add_ssl_algorithms() SSL_library_init() #define SSL_get_cipher(ssl) SSL_CIPHER_get_name(SSL_get_current_cipher(ssl)) #define SSL_get_cipher_bits(ssl, out_alg_bits) \ - SSL_CIPHER_get_bits(SSL_get_current_cipher(ssl), out_alg_bits) + SSL_CIPHER_get_bits(SSL_get_current_cipher(ssl), out_alg_bits) #define SSL_get_cipher_version(ssl) \ - SSL_CIPHER_get_version(SSL_get_current_cipher(ssl)) + SSL_CIPHER_get_version(SSL_get_current_cipher(ssl)) #define SSL_get_cipher_name(ssl) \ - SSL_CIPHER_get_name(SSL_get_current_cipher(ssl)) + SSL_CIPHER_get_name(SSL_get_current_cipher(ssl)) #define SSL_get_time(session) SSL_SESSION_get_time(session) #define SSL_set_time(session, time) SSL_SESSION_set_time((session), (time)) #define SSL_get_timeout(session) SSL_SESSION_get_timeout(session) #define SSL_set_timeout(session, timeout) \ - SSL_SESSION_set_timeout((session), (timeout)) + SSL_SESSION_set_timeout((session), (timeout)) typedef struct ssl_comp_st SSL_COMP; @@ -3154,15 +3454,6 @@ struct ssl_comp_st { DECLARE_STACK_OF(SSL_COMP) -/* The following flags toggle individual protocol versions. This is deprecated. - * Use |SSL_CTX_set_min_version| and |SSL_CTX_set_max_version| instead. */ -#define SSL_OP_NO_SSLv3 0x02000000L -#define SSL_OP_NO_TLSv1 0x04000000L -#define SSL_OP_NO_TLSv1_2 0x08000000L -#define SSL_OP_NO_TLSv1_1 0x10000000L -#define SSL_OP_NO_DTLSv1 SSL_OP_NO_TLSv1 -#define SSL_OP_NO_DTLSv1_2 SSL_OP_NO_TLSv1_2 - /* The following flags do nothing and are included only to make it easier to * compile code with BoringSSL. */ #define SSL_MODE_AUTO_RETRY 0 @@ -3195,7 +3486,7 @@ DECLARE_STACK_OF(SSL_COMP) #define SSL_OP_TLS_ROLLBACK_BUG 0 #define SSL_VERIFY_CLIENT_ONCE 0 -/* SSL_cache_hit calls |SSL_session_resumed|. */ +/* SSL_cache_hit calls |SSL_session_reused|. */ OPENSSL_EXPORT int SSL_cache_hit(SSL *ssl); /* SSL_get_default_timeout returns |SSL_DEFAULT_SESSION_TIMEOUT|. */ @@ -3206,7 +3497,7 @@ OPENSSL_EXPORT long SSL_get_default_timeout(const SSL *ssl); OPENSSL_EXPORT const char *SSL_get_version(const SSL *ssl); /* SSL_get_cipher_list returns the name of the |n|th cipher in the output of - * |SSL_get_ciphers| or NULL if out of range. Use |SSL_get_ciphers| insteads. */ + * |SSL_get_ciphers| or NULL if out of range. Use |SSL_get_ciphers| instead. */ OPENSSL_EXPORT const char *SSL_get_cipher_list(const SSL *ssl, int n); /* SSL_CTX_set_client_cert_cb sets a callback which is called on the client if @@ -3221,16 +3512,12 @@ OPENSSL_EXPORT const char *SSL_get_cipher_list(const SSL *ssl, int n); * |SSL_get_client_CA_list| for information on the server's certificate request. * * Use |SSL_CTX_set_cert_cb| instead. Configuring intermediate certificates with - * this function is confusing. */ + * this function is confusing. This callback may not be registered concurrently + * with |SSL_CTX_set_cert_cb| or |SSL_set_cert_cb|. */ OPENSSL_EXPORT void SSL_CTX_set_client_cert_cb( SSL_CTX *ctx, int (*client_cert_cb)(SSL *ssl, X509 **out_x509, EVP_PKEY **out_pkey)); -/* SSL_CTX_get_client_cert_cb returns the callback set by - * |SSL_CTX_set_client_cert_cb|. */ -OPENSSL_EXPORT int (*SSL_CTX_get_client_cert_cb(SSL_CTX *ctx))( - SSL *ssl, X509 **out_x509, EVP_PKEY **out_pkey); - #define SSL_NOTHING 1 #define SSL_WRITING 2 #define SSL_READING 3 @@ -3244,27 +3531,20 @@ OPENSSL_EXPORT int (*SSL_CTX_get_client_cert_cb(SSL_CTX *ctx))( * operation on |ssl| was blocked on. Use |SSL_get_error| instead. */ OPENSSL_EXPORT int SSL_want(const SSL *ssl); -#define SSL_want_nothing(ssl) (SSL_want(ssl) == SSL_NOTHING) #define SSL_want_read(ssl) (SSL_want(ssl) == SSL_READING) #define SSL_want_write(ssl) (SSL_want(ssl) == SSL_WRITING) -#define SSL_want_x509_lookup(ssl) (SSL_want(ssl) == SSL_X509_LOOKUP) -#define SSL_want_channel_id_lookup(ssl) (SSL_want(ssl) == SSL_CHANNEL_ID_LOOKUP) -#define SSL_want_session(ssl) (SSL_want(ssl) == SSL_PENDING_SESSION) -#define SSL_want_certificate(ssl) \ - (SSL_want(ssl) == SSL_CERTIFICATE_SELECTION_PENDING) -#define SSL_want_private_key_operation(ssl) \ - (SSL_want(ssl) == SSL_PRIVATE_KEY_OPERATION) /* SSL_get_finished writes up to |count| bytes of the Finished message sent by * |ssl| to |buf|. It returns the total untruncated length or zero if none has - * been sent yet. + * been sent yet. At SSL 3.0 or TLS 1.3 and later, it returns zero. * * Use |SSL_get_tls_unique| instead. */ OPENSSL_EXPORT size_t SSL_get_finished(const SSL *ssl, void *buf, size_t count); /* SSL_get_peer_finished writes up to |count| bytes of the Finished message * received from |ssl|'s peer to |buf|. It returns the total untruncated length - * or zero if none has been received yet. + * or zero if none has been received yet. At SSL 3.0 or TLS 1.3 and later, it + * returns zero. * * Use |SSL_get_tls_unique| instead. */ OPENSSL_EXPORT size_t SSL_get_peer_finished(const SSL *ssl, void *buf, @@ -3316,12 +3596,16 @@ OPENSSL_EXPORT const char *SSL_alert_desc_string(int value); #define SSL_TXT_TLSV1 "TLSv1" #define SSL_TXT_TLSV1_1 "TLSv1.1" #define SSL_TXT_TLSV1_2 "TLSv1.2" +#define SSL_TXT_TLSV1_3 "TLSv1.3" #define SSL_TXT_ALL "ALL" #define SSL_TXT_CMPDEF "COMPLEMENTOFDEFAULT" typedef struct ssl_conf_ctx_st SSL_CONF_CTX; -/* SSL_state returns the current state of the handshake state machine. */ +/* SSL_state returns |SSL_ST_INIT| if a handshake is in progress and |SSL_ST_OK| + * otherwise. + * + * Use |SSL_is_init| instead. */ OPENSSL_EXPORT int SSL_state(const SSL *ssl); #define SSL_get_state(ssl) SSL_state(ssl) @@ -3351,6 +3635,62 @@ OPENSSL_EXPORT int SSL_CTX_set_tmp_ecdh(SSL_CTX *ctx, const EC_KEY *ec_key); * |ec_key|'s curve. */ OPENSSL_EXPORT int SSL_set_tmp_ecdh(SSL *ssl, const EC_KEY *ec_key); +/* SSL_add_dir_cert_subjects_to_stack lists files in directory |dir|. It calls + * |SSL_add_file_cert_subjects_to_stack| on each file and returns one on success + * or zero on error. This function is only available from the libdecrepit + * library. */ +OPENSSL_EXPORT int SSL_add_dir_cert_subjects_to_stack(STACK_OF(X509_NAME) *out, + const char *dir); + +/* SSL_set_private_key_digest_prefs copies |num_digests| NIDs from |digest_nids| + * into |ssl|. These digests will be used, in decreasing order of preference, + * when signing with |ssl|'s private key. It returns one on success and zero on + * error. + * + * Use |SSL_set_signing_algorithm_prefs| instead. + * + * TODO(davidben): Remove this API when callers have been updated. */ +OPENSSL_EXPORT int SSL_set_private_key_digest_prefs(SSL *ssl, + const int *digest_nids, + size_t num_digests); + +/* SSL_set_verify_result calls |abort| unless |result| is |X509_V_OK|. + * + * TODO(davidben): Remove this function once it has been removed from + * netty-tcnative. */ +OPENSSL_EXPORT void SSL_set_verify_result(SSL *ssl, long result); + +/* SSL_CTX_set_min_version calls |SSL_CTX_set_min_proto_version|. */ +OPENSSL_EXPORT int SSL_CTX_set_min_version(SSL_CTX *ctx, uint16_t version); + +/* SSL_CTX_set_max_version calls |SSL_CTX_set_max_proto_version|. */ +OPENSSL_EXPORT int SSL_CTX_set_max_version(SSL_CTX *ctx, uint16_t version); + +/* SSL_set_min_version calls |SSL_set_min_proto_version|. */ +OPENSSL_EXPORT int SSL_set_min_version(SSL *ssl, uint16_t version); + +/* SSL_set_max_version calls |SSL_set_max_proto_version|. */ +OPENSSL_EXPORT int SSL_set_max_version(SSL *ssl, uint16_t version); + +/* SSL_CTX_enable_tls_channel_id calls |SSL_CTX_set_tls_channel_id_enabled|. */ +OPENSSL_EXPORT int SSL_CTX_enable_tls_channel_id(SSL_CTX *ctx); + +/* SSL_enable_tls_channel_id calls |SSL_set_tls_channel_id_enabled|. */ +OPENSSL_EXPORT int SSL_enable_tls_channel_id(SSL *ssl); + +/* BIO_f_ssl returns a |BIO_METHOD| that can wrap an |SSL*| in a |BIO*|. Note + * that this has quite different behaviour from the version in OpenSSL (notably + * that it doesn't try to auto renegotiate). + * + * IMPORTANT: if you are not curl, don't use this. */ +OPENSSL_EXPORT const BIO_METHOD *BIO_f_ssl(void); + +/* BIO_set_ssl sets |ssl| as the underlying connection for |bio|, which must + * have been created using |BIO_f_ssl|. If |take_owership| is true, |bio| will + * call |SSL_free| on |ssl| when closed. It returns one on success or something + * other than one on error. */ +OPENSSL_EXPORT long BIO_set_ssl(BIO *bio, SSL *ssl, int take_owership); + /* Private structures. * @@ -3358,8 +3698,7 @@ OPENSSL_EXPORT int SSL_set_tmp_ecdh(SSL *ssl, const EC_KEY *ec_key); * deprecated. */ typedef struct ssl_protocol_method_st SSL_PROTOCOL_METHOD; -typedef struct ssl3_enc_method SSL3_ENC_METHOD; -typedef struct ssl_aead_ctx_st SSL_AEAD_CTX; +typedef struct ssl_x509_method_st SSL_X509_METHOD; struct ssl_cipher_st { /* name is the OpenSSL name for the cipher. */ @@ -3375,12 +3714,6 @@ struct ssl_cipher_st { uint32_t algorithm_prf; }; -typedef struct ssl_ecdh_method_st SSL_ECDH_METHOD; -typedef struct ssl_ecdh_ctx_st { - const SSL_ECDH_METHOD *method; - void *data; -} SSL_ECDH_CTX; - #define SSL_MAX_SSL_SESSION_ID_LENGTH 32 #define SSL_MAX_SID_CTX_LENGTH 32 #define SSL_MAX_MASTER_KEY_LENGTH 48 @@ -3389,18 +3722,16 @@ struct ssl_session_st { CRYPTO_refcount_t references; int ssl_version; /* what ssl version session info is being kept in here? */ - /* key_exchange_info contains an indication of the size of the asymmetric - * primitive used in the handshake that created this session. In the event - * that two asymmetric operations are used, this value applies to the one - * that controls the confidentiality of the connection. Its interpretation - * depends on the primitive that was used; as specified by the cipher suite: - * DHE: the size, in bits, of the multiplicative group. - * RSA: the size, in bits, of the modulus. - * ECDHE: the TLS id for the curve. - * - * A zero indicates that the value is unknown. */ - uint32_t key_exchange_info; + /* group_id is the ID of the ECDH group used to establish this session or zero + * if not applicable or unknown. */ + uint16_t group_id; + /* peer_signature_algorithm is the signature algorithm used to authenticate + * the peer, or zero if not applicable or unknown. */ + uint16_t peer_signature_algorithm; + + /* master_key, in TLS 1.2 and below, is the master secret associated with the + * session. In TLS 1.3 and up, it is the resumption secret. */ int master_key_length; uint8_t master_key[SSL_MAX_MASTER_KEY_LENGTH]; @@ -3410,23 +3741,46 @@ struct ssl_session_st { /* this is used to determine whether the session is being reused in * the appropriate context. It is up to the application to set this, * via SSL_new */ - unsigned int sid_ctx_length; + uint8_t sid_ctx_length; uint8_t sid_ctx[SSL_MAX_SID_CTX_LENGTH]; char *psk_identity; - /* peer is the peer's certificate. */ - X509 *peer; - /* cert_chain is the certificate chain sent by the peer. NOTE: for historical + /* certs contains the certificate chain from the peer, starting with the leaf + * certificate. */ + STACK_OF(CRYPTO_BUFFER) *certs; + + const SSL_X509_METHOD *x509_method; + + /* x509_peer is the peer's certificate. */ + X509 *x509_peer; + + /* x509_chain is the certificate chain sent by the peer. NOTE: for historical * reasons, when a client (so the peer is a server), the chain includes * |peer|, but when a server it does not. */ - STACK_OF(X509) *cert_chain; + STACK_OF(X509) *x509_chain; + + /* x509_chain_without_leaf is a lazily constructed copy of |x509_chain| that + * omits the leaf certificate. This exists because OpenSSL, historically, + * didn't include the leaf certificate in the chain for a server, but did for + * a client. The |x509_chain| always includes it and, if an API call requires + * a chain without, it is stored here. */ + STACK_OF(X509) *x509_chain_without_leaf; - /* when app_verify_callback accepts a session where the peer's certificate is - * not ok, we must remember the error for session reuse: */ - long verify_result; /* only for servers */ + /* verify_result is the result of certificate verification in the case of + * non-fatal certificate errors. */ + long verify_result; + /* timeout is the lifetime of the session in seconds, measured from |time|. + * This is renewable up to |auth_timeout|. */ long timeout; + + /* auth_timeout is the non-renewable lifetime of the session in seconds, + * measured from |time|. */ + long auth_timeout; + + /* time is the time the session was issued, measured in seconds from the UNIX + * epoch. */ long time; const SSL_CIPHER *cipher; @@ -3457,10 +3811,22 @@ struct ssl_session_st { * SHA-2, depending on TLS version) for the original, full handshake that * created a session. This is used by Channel IDs during resumption. */ uint8_t original_handshake_hash[EVP_MAX_MD_SIZE]; - unsigned original_handshake_hash_len; + uint8_t original_handshake_hash_len; uint32_t tlsext_tick_lifetime_hint; /* Session lifetime hint in seconds */ + uint32_t ticket_age_add; + + /* ticket_max_early_data is the maximum amount of data allowed to be sent as + * early data. If zero, 0-RTT is disallowed. */ + uint32_t ticket_max_early_data; + + /* early_alpn is the ALPN protocol from the initial handshake. This is only + * stored for TLS 1.3 and above in order to enforce ALPN matching for 0-RTT + * resumptions. */ + uint8_t *early_alpn; + size_t early_alpn_len; + /* extended_master_secret is true if the master secret in this session was * generated using EMS and thus isn't vulnerable to the Triple Handshake * attack. */ @@ -3469,10 +3835,14 @@ struct ssl_session_st { /* peer_sha256_valid is non-zero if |peer_sha256| is valid. */ unsigned peer_sha256_valid:1; /* Non-zero if peer_sha256 is valid */ - /* not_resumable is used to indicate that session resumption is not allowed. - * Applications can also set this bit for a new session via - * not_resumable_session_cb to disable session caching and tickets. */ + /* not_resumable is used to indicate that session resumption is disallowed. */ unsigned not_resumable:1; + + /* ticket_age_add_valid is non-zero if |ticket_age_add| is valid. */ + unsigned ticket_age_add_valid:1; + + /* is_server is true if this session was created by a server. */ + unsigned is_server:1; }; /* ssl_cipher_preference_list_st contains a list of SSL_CIPHERs with @@ -3515,36 +3885,20 @@ struct ssl_cipher_preference_list_st { * connections. */ struct ssl_ctx_st { const SSL_PROTOCOL_METHOD *method; + const SSL_X509_METHOD *x509_method; /* lock is used to protect various operations on this object. */ CRYPTO_MUTEX lock; - /* max_version is the maximum acceptable protocol version. If zero, the - * maximum supported version, currently (D)TLS 1.2, is used. */ + /* max_version is the maximum acceptable protocol version. Note this version + * is normalized in DTLS. */ uint16_t max_version; - /* min_version is the minimum acceptable protocl version. If zero, the - * minimum supported version, currently SSL 3.0 and DTLS 1.0, is used */ + /* min_version is the minimum acceptable protocol version. Note this version + * is normalized in DTLS. */ uint16_t min_version; struct ssl_cipher_preference_list_st *cipher_list; - /* same as above but sorted for lookup */ - STACK_OF(SSL_CIPHER) *cipher_list_by_id; - - /* cipher_list_tls10 is the list of ciphers when TLS 1.0 or greater is in - * use. This only applies to server connections as, for clients, the version - * number is known at connect time and so the cipher list can be set then. If - * |cipher_list_tls11| is non-NULL then this applies only to TLS 1.0 - * connections. - * - * TODO(agl): this exists to assist in the death of SSLv3. It can hopefully - * be removed after that. */ - struct ssl_cipher_preference_list_st *cipher_list_tls10; - - /* cipher_list_tls11 is the list of ciphers when TLS 1.1 or greater is in - * use. This only applies to server connections as, for clients, the version - * number is known at connect time and so the cipher list can be set then. */ - struct ssl_cipher_preference_list_st *cipher_list_tls11; X509_STORE *cert_store; LHASH_OF(SSL_SESSION) *sessions; @@ -3565,10 +3919,14 @@ struct ssl_ctx_st { * SSL_accept which cache SSL_SESSIONS. */ int session_cache_mode; - /* If timeout is not 0, it is the default timeout value set when SSL_new() is - * called. This has been put in to make life easier to set things up */ + /* session_timeout is the default lifetime for new sessions in TLS 1.2 and + * earlier, in seconds. */ long session_timeout; + /* session_psk_dhe_timeout is the default lifetime for new sessions in TLS + * 1.3, in seconds. */ + long session_psk_dhe_timeout; + /* If this callback is not null, it will be called each time a session id is * added to the cache. If this function returns 1, it means that the * callback will do a SSL_SESSION_free() when it has finished using it. @@ -3629,8 +3987,6 @@ struct ssl_ctx_st { void *msg_callback_arg; int verify_mode; - unsigned int sid_ctx_length; - uint8_t sid_ctx[SSL_MAX_SID_CTX_LENGTH]; int (*default_verify_callback)( int ok, X509_STORE_CTX *ctx); /* called 'verify_callback' in the SSL */ @@ -3642,12 +3998,12 @@ struct ssl_ctx_st { * with an error and cause SSL_get_error to return * SSL_ERROR_PENDING_CERTIFICATE. Note: when the handshake loop is resumed, it * will not call the callback a second time. */ - int (*select_certificate_cb)(const struct ssl_early_callback_ctx *); + int (*select_certificate_cb)(const SSL_CLIENT_HELLO *); /* dos_protection_cb is called once the resumption decision for a ClientHello * has been made. It returns one to continue the handshake or zero to * abort. */ - int (*dos_protection_cb) (const struct ssl_early_callback_ctx *); + int (*dos_protection_cb) (const SSL_CLIENT_HELLO *); /* Maximum amount of data to send in one fragment. actual record size can be * more than this due to padding and MAC overheads. */ @@ -3718,33 +4074,34 @@ struct ssl_ctx_st { /* SRTP profiles we are willing to do from RFC 5764 */ STACK_OF(SRTP_PROTECTION_PROFILE) *srtp_profiles; - /* EC extension values inherited by SSL structure */ - size_t tlsext_ellipticcurvelist_length; - uint16_t *tlsext_ellipticcurvelist; + /* Supported group values inherited by SSL structure */ + size_t supported_group_list_len; + uint16_t *supported_group_list; /* The client's Channel ID private key. */ EVP_PKEY *tlsext_channel_id_private; - /* Signed certificate timestamp list to be sent to the client, if requested */ - uint8_t *signed_cert_timestamp_list; - size_t signed_cert_timestamp_list_length; - - /* OCSP response to be sent to the client, if requested. */ - uint8_t *ocsp_response; - size_t ocsp_response_length; - /* keylog_callback, if not NULL, is the key logging callback. See * |SSL_CTX_set_keylog_callback|. */ void (*keylog_callback)(const SSL *ssl, const char *line); /* current_time_cb, if not NULL, is the function to use to get the current - * time. It sets |*out_clock| to the current time. */ + * time. It sets |*out_clock| to the current time. See + * |SSL_CTX_set_current_time_cb|. */ void (*current_time_cb)(const SSL *ssl, struct timeval *out_clock); + /* pool is used for all |CRYPTO_BUFFER|s in case we wish to share certificate + * memory. */ + CRYPTO_BUFFER_POOL *pool; + /* quiet_shutdown is true if the connection should not send a close_notify on * shutdown. */ unsigned quiet_shutdown:1; + /* If enable_early_data is non-zero, early data can be sent and accepted over + * new connections. */ + unsigned enable_early_data:1; + /* ocsp_stapling_enabled is only used by client connections and indicates * whether OCSP stapling will be requested. */ unsigned ocsp_stapling_enabled:1; @@ -3752,464 +4109,20 @@ struct ssl_ctx_st { /* If true, a client will request certificate timestamps. */ unsigned signed_cert_timestamps_enabled:1; - /* tlsext_channel_id_enabled is copied from the |SSL_CTX|. For a server, - * means that we'll accept Channel IDs from clients. For a client, means that - * we'll advertise support. */ + /* tlsext_channel_id_enabled is one if Channel ID is enabled and zero + * otherwise. For a server, means that we'll accept Channel IDs from clients. + * For a client, means that we'll advertise support. */ unsigned tlsext_channel_id_enabled:1; - /* extra_certs is a dummy value included for compatibility. - * TODO(agl): remove once node.js no longer references this. */ - STACK_OF(X509)* extra_certs; - int freelist_max_len; -}; - -struct ssl_st { - /* version is the protocol version. */ - int version; - - /* max_version is the maximum acceptable protocol version. If zero, the - * maximum supported version, currently (D)TLS 1.2, is used. */ - uint16_t max_version; - - /* min_version is the minimum acceptable protocl version. If zero, the - * minimum supported version, currently SSL 3.0 and DTLS 1.0, is used */ - uint16_t min_version; - - /* method is the method table corresponding to the current protocol (DTLS or - * TLS). */ - const SSL_PROTOCOL_METHOD *method; - - /* There are 2 BIO's even though they are normally both the same. This is so - * data can be read and written to different handlers */ - - BIO *rbio; /* used by SSL_read */ - BIO *wbio; /* used by SSL_write */ - - /* bbio, if non-NULL, is a buffer placed in front of |wbio| to pack handshake - * messages within one flight into a single |BIO_write|. - * - * TODO(davidben): This does not work right for DTLS. It assumes the MTU is - * smaller than the buffer size so that the buffer's internal flushing never - * kicks in. It also doesn't kick in for DTLS retransmission. Replace this - * with a better mechanism. */ - BIO *bbio; - - int (*handshake_func)(SSL *); - - /* Imagine that here's a boolean member "init" that is switched as soon as - * SSL_set_{accept/connect}_state is called for the first time, so that - * "state" and "handshake_func" are properly initialized. But as - * handshake_func is == 0 until then, we use this test instead of an "init" - * member. */ - - int shutdown; /* we have shut things down, 0x01 sent, 0x02 - * for received */ - int state; /* where we are */ - - BUF_MEM *init_buf; /* buffer used during init */ - uint8_t *init_msg; /* pointer to handshake message body, set by - ssl3_get_message() */ - int init_num; /* amount read/written */ - int init_off; /* amount read/written */ - - struct ssl3_state_st *s3; /* SSLv3 variables */ - struct dtls1_state_st *d1; /* DTLSv1 variables */ - - /* callback that allows applications to peek at protocol messages */ - void (*msg_callback)(int write_p, int version, int content_type, - const void *buf, size_t len, SSL *ssl, void *arg); - void *msg_callback_arg; - - X509_VERIFY_PARAM *param; - - /* crypto */ - struct ssl_cipher_preference_list_st *cipher_list; - STACK_OF(SSL_CIPHER) *cipher_list_by_id; - - /* session info */ - - /* client cert? */ - /* This is used to hold the server certificate used */ - struct cert_st /* CERT */ *cert; - - /* This holds a variable that indicates what we were doing when a 0 or -1 is - * returned. This is needed for non-blocking IO so we know what request - * needs re-doing when in SSL_accept or SSL_connect */ - int rwstate; - - /* the session_id_context is used to ensure sessions are only reused - * in the appropriate context */ - unsigned int sid_ctx_length; - uint8_t sid_ctx[SSL_MAX_SID_CTX_LENGTH]; - - /* This can also be in the session once a session is established */ - SSL_SESSION *session; + /* grease_enabled is one if draft-davidben-tls-grease-01 is enabled and zero + * otherwise. */ + unsigned grease_enabled:1; - int (*verify_callback)(int ok, - X509_STORE_CTX *ctx); /* fail if callback returns 0 */ - - void (*info_callback)(const SSL *ssl, int type, int value); - - /* Server-only: psk_identity_hint is the identity hint to send in - * PSK-based key exchanges. */ - char *psk_identity_hint; - - unsigned int (*psk_client_callback)(SSL *ssl, const char *hint, - char *identity, - unsigned int max_identity_len, - uint8_t *psk, unsigned int max_psk_len); - unsigned int (*psk_server_callback)(SSL *ssl, const char *identity, - uint8_t *psk, unsigned int max_psk_len); - - SSL_CTX *ctx; - - /* extra application data */ - long verify_result; - CRYPTO_EX_DATA ex_data; - - /* for server side, keep the list of CA_dn we can use */ - STACK_OF(X509_NAME) *client_CA; - - uint32_t options; /* protocol behaviour */ - uint32_t mode; /* API behaviour */ - uint32_t max_cert_list; - int client_version; /* what was passed, used for - * SSLv3/TLS rollback check */ - uint16_t max_send_fragment; - char *tlsext_hostname; - /* RFC4507 session ticket expected to be received or sent */ - int tlsext_ticket_expected; - size_t tlsext_ellipticcurvelist_length; - uint16_t *tlsext_ellipticcurvelist; /* our list */ - - SSL_CTX *initial_ctx; /* initial ctx, used to store sessions */ - - /* srtp_profiles is the list of configured SRTP protection profiles for - * DTLS-SRTP. */ - STACK_OF(SRTP_PROTECTION_PROFILE) *srtp_profiles; - - /* srtp_profile is the selected SRTP protection profile for - * DTLS-SRTP. */ - const SRTP_PROTECTION_PROFILE *srtp_profile; - - /* The client's Channel ID private key. */ - EVP_PKEY *tlsext_channel_id_private; - - /* For a client, this contains the list of supported protocols in wire - * format. */ - uint8_t *alpn_client_proto_list; - unsigned alpn_client_proto_list_len; - - /* renegotiate_mode controls how peer renegotiation attempts are handled. */ - enum ssl_renegotiate_mode_t renegotiate_mode; - - /* These fields are always NULL and exist only to keep wpa_supplicant happy - * about the change to EVP_AEAD. They are only needed for EAP-FAST, which we - * don't support. */ - EVP_CIPHER_CTX *enc_read_ctx; - EVP_MD_CTX *read_hash; - - /* in_handshake is non-zero when we are actually in SSL_accept() or - * SSL_connect() */ - int in_handshake; - - /* verify_mode is a bitmask of |SSL_VERIFY_*| values. */ - uint8_t verify_mode; - - /* hit is true if this connection is resuming a previous session. */ - unsigned hit:1; - - /* server is true iff the this SSL* is the server half. Note: before the SSL* - * is initialized by either SSL_set_accept_state or SSL_set_connect_state, - * the side is not determined. In this state, server is always false. */ - unsigned server:1; - - /* quiet_shutdown is true if the connection should not send a close_notify on - * shutdown. */ - unsigned quiet_shutdown:1; - - /* Enable signed certificate time stamps. Currently client only. */ - unsigned signed_cert_timestamps_enabled:1; - - /* ocsp_stapling_enabled is only used by client connections and indicates - * whether OCSP stapling will be requested. */ - unsigned ocsp_stapling_enabled:1; - - /* tlsext_channel_id_enabled is copied from the |SSL_CTX|. For a server, - * means that we'll accept Channel IDs from clients. For a client, means that - * we'll advertise support. */ - unsigned tlsext_channel_id_enabled:1; - - /* TODO(agl): remove once node.js not longer references this. */ - int tlsext_status_type; + /* short_header_enabled is one if a short record header in TLS 1.3 may + * be negotiated and zero otherwise. */ + unsigned short_header_enabled:1; }; -typedef struct ssl3_record_st { - /* type is the record type. */ - uint8_t type; - /* length is the number of unconsumed bytes in the record. */ - uint16_t length; - /* data is a non-owning pointer to the first unconsumed byte of the record. */ - uint8_t *data; -} SSL3_RECORD; - -typedef struct ssl3_buffer_st { - /* buf is the memory allocated for this buffer. */ - uint8_t *buf; - /* offset is the offset into |buf| which the buffer contents start at. */ - uint16_t offset; - /* len is the length of the buffer contents from |buf| + |offset|. */ - uint16_t len; - /* cap is how much memory beyond |buf| + |offset| is available. */ - uint16_t cap; -} SSL3_BUFFER; - -typedef struct ssl3_state_st { - uint8_t read_sequence[8]; - uint8_t write_sequence[8]; - - uint8_t server_random[SSL3_RANDOM_SIZE]; - uint8_t client_random[SSL3_RANDOM_SIZE]; - - /* have_version is true if the connection's final version is known. Otherwise - * the version has not been negotiated yet. */ - char have_version; - - /* initial_handshake_complete is true if the initial handshake has - * completed. */ - char initial_handshake_complete; - - /* read_buffer holds data from the transport to be processed. */ - SSL3_BUFFER read_buffer; - /* write_buffer holds data to be written to the transport. */ - SSL3_BUFFER write_buffer; - - SSL3_RECORD rrec; /* each decoded record goes in here */ - - /* hello_request_len is the number of bytes of HelloRequest received, possibly - * split over multiple records. */ - uint8_t hello_request_len; - - /* partial write - check the numbers match */ - unsigned int wnum; /* number of bytes sent so far */ - int wpend_tot; /* number bytes written */ - int wpend_type; - int wpend_ret; /* number of bytes submitted */ - const uint8_t *wpend_buf; - - /* handshake_buffer, if non-NULL, contains the handshake transcript. */ - BUF_MEM *handshake_buffer; - /* handshake_hash, if initialized with an |EVP_MD|, maintains the handshake - * hash. For TLS 1.1 and below, it is the SHA-1 half. */ - EVP_MD_CTX handshake_hash; - /* handshake_md5, if initialized with an |EVP_MD|, maintains the MD5 half of - * the handshake hash for TLS 1.1 and below. */ - EVP_MD_CTX handshake_md5; - - int warn_alert; - int fatal_alert; - /* we allow one fatal and one warning alert to be outstanding, send close - * alert via the warning alert */ - int alert_dispatch; - uint8_t send_alert[2]; - - int total_renegotiations; - - /* empty_record_count is the number of consecutive empty records received. */ - uint8_t empty_record_count; - - /* warning_alert_count is the number of consecutive warning alerts - * received. */ - uint8_t warning_alert_count; - - /* aead_read_ctx is the current read cipher state. */ - SSL_AEAD_CTX *aead_read_ctx; - - /* aead_write_ctx is the current write cipher state. */ - SSL_AEAD_CTX *aead_write_ctx; - - /* enc_method is the method table corresponding to the current protocol - * version. */ - const SSL3_ENC_METHOD *enc_method; - - /* State pertaining to the pending handshake. - * - * TODO(davidben): State is current spread all over the place. Move - * pending handshake state here so it can be managed separately from - * established connection state in case of renegotiations. */ - struct { - uint8_t finish_md[EVP_MAX_MD_SIZE]; - int finish_md_len; - uint8_t peer_finish_md[EVP_MAX_MD_SIZE]; - int peer_finish_md_len; - - unsigned long message_size; - int message_type; - - /* used to hold the new cipher we are going to use */ - const SSL_CIPHER *new_cipher; - - /* used when SSL_ST_FLUSH_DATA is entered */ - int next_state; - - int reuse_message; - - union { - /* sent is a bitset where the bits correspond to elements of kExtensions - * in t1_lib.c. Each bit is set if that extension was sent in a - * ClientHello. It's not used by servers. */ - uint32_t sent; - /* received is a bitset, like |sent|, but is used by servers to record - * which extensions were received from a client. */ - uint32_t received; - } extensions; - - union { - /* sent is a bitset where the bits correspond to elements of - * |client_custom_extensions| in the |SSL_CTX|. Each bit is set if that - * extension was sent in a ClientHello. It's not used by servers. */ - uint16_t sent; - /* received is a bitset, like |sent|, but is used by servers to record - * which custom extensions were received from a client. The bits here - * correspond to |server_custom_extensions|. */ - uint16_t received; - } custom_extensions; - - /* SNI extension */ - - /* should_ack_sni is used by a server and indicates that the SNI extension - * should be echoed in the ServerHello. */ - unsigned should_ack_sni:1; - - - /* Client-only: cert_req determines if a client certificate is to be sent. - * This is 0 if no client Certificate message is to be sent, 1 if there is - * a client certificate, and 2 to send an empty client Certificate - * message. */ - int cert_req; - - /* Client-only: ca_names contains the list of CAs received in a - * CertificateRequest message. */ - STACK_OF(X509_NAME) *ca_names; - - /* Client-only: certificate_types contains the set of certificate types - * received in a CertificateRequest message. */ - uint8_t *certificate_types; - size_t num_certificate_types; - - uint8_t *key_block; - uint8_t key_block_length; - - uint8_t new_mac_secret_len; - uint8_t new_key_len; - uint8_t new_fixed_iv_len; - - /* Server-only: cert_request is true if a client certificate was - * requested. */ - int cert_request; - - /* certificate_status_expected is true if OCSP stapling was negotiated and - * the server is expected to send a CertificateStatus message. (This is - * used on both the client and server sides.) */ - unsigned certificate_status_expected:1; - - /* ocsp_stapling_requested is true if a client requested OCSP stapling. */ - unsigned ocsp_stapling_requested:1; - - /* Server-only: peer_ellipticcurvelist contains the EC curve IDs advertised - * by the peer. This is only set on the server's end. The server does not - * advertise this extension to the client. */ - uint16_t *peer_ellipticcurvelist; - size_t peer_ellipticcurvelist_length; - - /* extended_master_secret indicates whether the extended master secret - * computation is used in this handshake. Note that this is different from - * whether it was used for the current session. If this is a resumption - * handshake then EMS might be negotiated in the client and server hello - * messages, but it doesn't matter if the session that's being resumed - * didn't use it to create the master secret initially. */ - char extended_master_secret; - - /* Client-only: peer_psk_identity_hint is the psk_identity_hint sent by the - * server when using a PSK key exchange. */ - char *peer_psk_identity_hint; - - /* new_mac_secret_size is unused and exists only until wpa_supplicant can - * be updated. It is only needed for EAP-FAST, which we don't support. */ - uint8_t new_mac_secret_size; - - /* Client-only: in_false_start is one if there is a pending handshake in - * False Start. The client may write data at this point. */ - char in_false_start; - - /* server_key_exchange_hash, on a client, is the hash the server used to - * sign the ServerKeyExchange in TLS 1.2. If not applicable, it is - * |TLSEXT_hash_none|. */ - uint8_t server_key_exchange_hash; - - /* ecdh_ctx is the current ECDH instance. */ - SSL_ECDH_CTX ecdh_ctx; - - /* peer_key is the peer's ECDH key. */ - uint8_t *peer_key; - uint16_t peer_key_len; - } tmp; - - /* Connection binding to prevent renegotiation attacks */ - uint8_t previous_client_finished[EVP_MAX_MD_SIZE]; - uint8_t previous_client_finished_len; - uint8_t previous_server_finished[EVP_MAX_MD_SIZE]; - uint8_t previous_server_finished_len; - int send_connection_binding; /* TODOEKR */ - - /* Set if we saw the Next Protocol Negotiation extension from our peer. */ - int next_proto_neg_seen; - - /* Next protocol negotiation. For the client, this is the protocol that we - * sent in NextProtocol and is set when handling ServerHello extensions. - * - * For a server, this is the client's selected_protocol from NextProtocol and - * is set when handling the NextProtocol message, before the Finished - * message. */ - uint8_t *next_proto_negotiated; - size_t next_proto_negotiated_len; - - /* ALPN information - * (we are in the process of transitioning from NPN to ALPN.) */ - - /* In a server these point to the selected ALPN protocol after the - * ClientHello has been processed. In a client these contain the protocol - * that the server selected once the ServerHello has been processed. */ - uint8_t *alpn_selected; - size_t alpn_selected_len; - - /* In a client, this means that the server supported Channel ID and that a - * Channel ID was sent. In a server it means that we echoed support for - * Channel IDs and that tlsext_channel_id will be valid after the - * handshake. */ - char tlsext_channel_id_valid; - /* For a server: - * If |tlsext_channel_id_valid| is true, then this contains the - * verified Channel ID from the client: a P256 point, (x,y), where - * each are big-endian values. */ - uint8_t tlsext_channel_id[64]; -} SSL3_STATE; - - -/* Android compatibility section (hidden). - * - * These functions are declared, temporarily, for Android because - * wpa_supplicant will take a little time to sync with upstream. Outside of - * Android they'll have no definition. */ - -#define SSL_F_SSL_SET_SESSION_TICKET_EXT doesnt_exist - -OPENSSL_EXPORT int SSL_set_session_ticket_ext(SSL *s, void *ext_data, - int ext_len); -OPENSSL_EXPORT int SSL_set_session_secret_cb(SSL *s, void *cb, void *arg); -OPENSSL_EXPORT int SSL_set_session_ticket_ext_cb(SSL *s, void *cb, void *arg); -OPENSSL_EXPORT int SSL_set_ssl_method(SSL *s, const SSL_METHOD *method); - /* Nodejs compatibility section (hidden). * @@ -4227,7 +4140,12 @@ OPENSSL_EXPORT int SSL_set_ssl_method(SSL *s, const SSL_METHOD *method); * * Although using either the CTRL values or their wrapper macros in #ifdefs is * still supported, the CTRL values may not be passed to |SSL_ctrl| and - * |SSL_CTX_ctrl|. Call the functions (previously wrapper macros) instead. */ + * |SSL_CTX_ctrl|. Call the functions (previously wrapper macros) instead. + * + * See PORTING.md in the BoringSSL source tree for a table of corresponding + * functions. + * https://boringssl.googlesource.com/boringssl/+/master/PORTING.md#Replacements-for-values + */ #define DTLS_CTRL_GET_TIMEOUT doesnt_exist #define DTLS_CTRL_HANDLE_TIMEOUT doesnt_exist @@ -4255,8 +4173,8 @@ OPENSSL_EXPORT int SSL_set_ssl_method(SSL *s, const SSL_METHOD *method); #define SSL_CTRL_NEED_TMP_RSA doesnt_exist #define SSL_CTRL_OPTIONS doesnt_exist #define SSL_CTRL_SESS_NUMBER doesnt_exist -#define SSL_CTRL_SET_CHANNEL_ID doesnt_exist #define SSL_CTRL_SET_CURVES doesnt_exist +#define SSL_CTRL_SET_CURVES_LIST doesnt_exist #define SSL_CTRL_SET_MAX_CERT_LIST doesnt_exist #define SSL_CTRL_SET_MAX_SEND_FRAGMENT doesnt_exist #define SSL_CTRL_SET_MSG_CALLBACK doesnt_exist @@ -4286,7 +4204,6 @@ OPENSSL_EXPORT int SSL_set_ssl_method(SSL *s, const SSL_METHOD *method); #define SSL_CTX_clear_chain_certs SSL_CTX_clear_chain_certs #define SSL_CTX_clear_mode SSL_CTX_clear_mode #define SSL_CTX_clear_options SSL_CTX_clear_options -#define SSL_CTX_enable_tls_channel_id SSL_CTX_enable_tls_channel_id #define SSL_CTX_get0_chain_certs SSL_CTX_get0_chain_certs #define SSL_CTX_get_extra_chain_certs SSL_CTX_get_extra_chain_certs #define SSL_CTX_get_max_cert_list SSL_CTX_get_max_cert_list @@ -4302,7 +4219,6 @@ OPENSSL_EXPORT int SSL_set_ssl_method(SSL *s, const SSL_METHOD *method); #define SSL_CTX_set0_chain SSL_CTX_set0_chain #define SSL_CTX_set1_chain SSL_CTX_set1_chain #define SSL_CTX_set1_curves SSL_CTX_set1_curves -#define SSL_CTX_set1_tls_channel_id SSL_CTX_set1_tls_channel_id #define SSL_CTX_set_max_cert_list SSL_CTX_set_max_cert_list #define SSL_CTX_set_max_send_fragment SSL_CTX_set_max_send_fragment #define SSL_CTX_set_mode SSL_CTX_set_mode @@ -4323,7 +4239,6 @@ OPENSSL_EXPORT int SSL_set_ssl_method(SSL *s, const SSL_METHOD *method); #define SSL_clear_chain_certs SSL_clear_chain_certs #define SSL_clear_mode SSL_clear_mode #define SSL_clear_options SSL_clear_options -#define SSL_enable_tls_channel_id SSL_enable_tls_channel_id #define SSL_get0_certificate_types SSL_get0_certificate_types #define SSL_get0_chain_certs SSL_get0_chain_certs #define SSL_get_max_cert_list SSL_get_max_cert_list @@ -4331,14 +4246,12 @@ OPENSSL_EXPORT int SSL_set_ssl_method(SSL *s, const SSL_METHOD *method); #define SSL_get_options SSL_get_options #define SSL_get_secure_renegotiation_support \ SSL_get_secure_renegotiation_support -#define SSL_get_tls_channel_id SSL_get_tls_channel_id #define SSL_need_tmp_RSA SSL_need_tmp_RSA #define SSL_num_renegotiations SSL_num_renegotiations #define SSL_session_reused SSL_session_reused #define SSL_set0_chain SSL_set0_chain #define SSL_set1_chain SSL_set1_chain #define SSL_set1_curves SSL_set1_curves -#define SSL_set1_tls_channel_id SSL_set1_tls_channel_id #define SSL_set_max_cert_list SSL_set_max_cert_list #define SSL_set_max_send_fragment SSL_set_max_send_fragment #define SSL_set_mode SSL_set_mode @@ -4354,6 +4267,19 @@ OPENSSL_EXPORT int SSL_set_ssl_method(SSL *s, const SSL_METHOD *method); #if defined(__cplusplus) } /* extern C */ + +extern "C++" { + +namespace bssl { + +BORINGSSL_MAKE_DELETER(SSL, SSL_free) +BORINGSSL_MAKE_DELETER(SSL_CTX, SSL_CTX_free) +BORINGSSL_MAKE_DELETER(SSL_SESSION, SSL_SESSION_free) + +} // namespace bssl + +} /* extern C++ */ + #endif #define SSL_R_APP_DATA_IN_HANDSHAKE 100 @@ -4506,6 +4432,29 @@ OPENSSL_EXPORT int SSL_set_ssl_method(SSL *s, const SSL_METHOD *method); #define SSL_R_WRONG_VERSION_NUMBER 247 #define SSL_R_X509_LIB 248 #define SSL_R_X509_VERIFICATION_SETUP_PROBLEMS 249 +#define SSL_R_SHUTDOWN_WHILE_IN_INIT 250 +#define SSL_R_INVALID_OUTER_RECORD_TYPE 251 +#define SSL_R_UNSUPPORTED_PROTOCOL_FOR_CUSTOM_KEY 252 +#define SSL_R_NO_COMMON_SIGNATURE_ALGORITHMS 253 +#define SSL_R_DOWNGRADE_DETECTED 254 +#define SSL_R_BUFFERED_MESSAGES_ON_CIPHER_CHANGE 255 +#define SSL_R_INVALID_COMPRESSION_LIST 256 +#define SSL_R_DUPLICATE_EXTENSION 257 +#define SSL_R_MISSING_KEY_SHARE 258 +#define SSL_R_INVALID_ALPN_PROTOCOL 259 +#define SSL_R_TOO_MANY_KEY_UPDATES 260 +#define SSL_R_BLOCK_CIPHER_PAD_IS_WRONG 261 +#define SSL_R_NO_CIPHERS_SPECIFIED 262 +#define SSL_R_RENEGOTIATION_EMS_MISMATCH 263 +#define SSL_R_DUPLICATE_KEY_SHARE 264 +#define SSL_R_NO_GROUPS_SPECIFIED 265 +#define SSL_R_NO_SHARED_GROUP 266 +#define SSL_R_PRE_SHARED_KEY_MUST_BE_LAST 267 +#define SSL_R_OLD_SESSION_PRF_HASH_MISMATCH 268 +#define SSL_R_INVALID_SCT_LIST 269 +#define SSL_R_TOO_MUCH_SKIPPED_EARLY_DATA 270 +#define SSL_R_PSK_IDENTITY_BINDER_COUNT_MISMATCH 271 +#define SSL_R_CANNOT_PARSE_LEAF_CERT 272 #define SSL_R_SSLV3_ALERT_CLOSE_NOTIFY 1000 #define SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE 1010 #define SSL_R_SSLV3_ALERT_BAD_RECORD_MAC 1020 @@ -4536,5 +4485,7 @@ OPENSSL_EXPORT int SSL_set_ssl_method(SSL *s, const SSL_METHOD *method); #define SSL_R_TLSV1_UNRECOGNIZED_NAME 1112 #define SSL_R_TLSV1_BAD_CERTIFICATE_STATUS_RESPONSE 1113 #define SSL_R_TLSV1_BAD_CERTIFICATE_HASH_VALUE 1114 +#define SSL_R_TLSV1_UNKNOWN_PSK_IDENTITY 1115 +#define SSL_R_TLSV1_CERTIFICATE_REQUIRED 1116 #endif /* OPENSSL_HEADER_SSL_H */ diff --git a/Sources/BoringSSL/include/openssl/ssl3.h b/Sources/BoringSSL/include/openssl/ssl3.h index 957b740e9..fcaeb2df9 100644 --- a/Sources/BoringSSL/include/openssl/ssl3.h +++ b/Sources/BoringSSL/include/openssl/ssl3.h @@ -307,119 +307,92 @@ OPENSSL_COMPILE_ASSERT( #define SSL3_ST_CW_FLUSH (0x100 | SSL_ST_CONNECT) #define SSL3_ST_FALSE_START (0x101 | SSL_ST_CONNECT) #define SSL3_ST_VERIFY_SERVER_CERT (0x102 | SSL_ST_CONNECT) +#define SSL3_ST_FINISH_CLIENT_HANDSHAKE (0x103 | SSL_ST_CONNECT) /* write to server */ #define SSL3_ST_CW_CLNT_HELLO_A (0x110 | SSL_ST_CONNECT) -#define SSL3_ST_CW_CLNT_HELLO_B (0x111 | SSL_ST_CONNECT) /* read from server */ #define SSL3_ST_CR_SRVR_HELLO_A (0x120 | SSL_ST_CONNECT) -#define SSL3_ST_CR_SRVR_HELLO_B (0x121 | SSL_ST_CONNECT) #define DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A (0x126 | SSL_ST_CONNECT) -#define DTLS1_ST_CR_HELLO_VERIFY_REQUEST_B (0x127 | SSL_ST_CONNECT) #define SSL3_ST_CR_CERT_A (0x130 | SSL_ST_CONNECT) -#define SSL3_ST_CR_CERT_B (0x131 | SSL_ST_CONNECT) #define SSL3_ST_CR_KEY_EXCH_A (0x140 | SSL_ST_CONNECT) #define SSL3_ST_CR_KEY_EXCH_B (0x141 | SSL_ST_CONNECT) #define SSL3_ST_CR_CERT_REQ_A (0x150 | SSL_ST_CONNECT) -#define SSL3_ST_CR_CERT_REQ_B (0x151 | SSL_ST_CONNECT) #define SSL3_ST_CR_SRVR_DONE_A (0x160 | SSL_ST_CONNECT) -#define SSL3_ST_CR_SRVR_DONE_B (0x161 | SSL_ST_CONNECT) /* write to server */ #define SSL3_ST_CW_CERT_A (0x170 | SSL_ST_CONNECT) -#define SSL3_ST_CW_CERT_B (0x171 | SSL_ST_CONNECT) -#define SSL3_ST_CW_CERT_C (0x172 | SSL_ST_CONNECT) -#define SSL3_ST_CW_CERT_D (0x173 | SSL_ST_CONNECT) #define SSL3_ST_CW_KEY_EXCH_A (0x180 | SSL_ST_CONNECT) -#define SSL3_ST_CW_KEY_EXCH_B (0x181 | SSL_ST_CONNECT) #define SSL3_ST_CW_CERT_VRFY_A (0x190 | SSL_ST_CONNECT) #define SSL3_ST_CW_CERT_VRFY_B (0x191 | SSL_ST_CONNECT) -#define SSL3_ST_CW_CERT_VRFY_C (0x192 | SSL_ST_CONNECT) -#define SSL3_ST_CW_CHANGE_A (0x1A0 | SSL_ST_CONNECT) -#define SSL3_ST_CW_CHANGE_B (0x1A1 | SSL_ST_CONNECT) +#define SSL3_ST_CW_CHANGE (0x1A0 | SSL_ST_CONNECT) #define SSL3_ST_CW_NEXT_PROTO_A (0x200 | SSL_ST_CONNECT) -#define SSL3_ST_CW_NEXT_PROTO_B (0x201 | SSL_ST_CONNECT) #define SSL3_ST_CW_CHANNEL_ID_A (0x220 | SSL_ST_CONNECT) -#define SSL3_ST_CW_CHANNEL_ID_B (0x221 | SSL_ST_CONNECT) #define SSL3_ST_CW_FINISHED_A (0x1B0 | SSL_ST_CONNECT) -#define SSL3_ST_CW_FINISHED_B (0x1B1 | SSL_ST_CONNECT) /* read from server */ #define SSL3_ST_CR_CHANGE (0x1C0 | SSL_ST_CONNECT) #define SSL3_ST_CR_FINISHED_A (0x1D0 | SSL_ST_CONNECT) -#define SSL3_ST_CR_FINISHED_B (0x1D1 | SSL_ST_CONNECT) #define SSL3_ST_CR_SESSION_TICKET_A (0x1E0 | SSL_ST_CONNECT) -#define SSL3_ST_CR_SESSION_TICKET_B (0x1E1 | SSL_ST_CONNECT) #define SSL3_ST_CR_CERT_STATUS_A (0x1F0 | SSL_ST_CONNECT) -#define SSL3_ST_CR_CERT_STATUS_B (0x1F1 | SSL_ST_CONNECT) + +/* SSL3_ST_CR_SRVR_HELLO_B is a legacy alias for |SSL3_ST_CR_SRVR_HELLO_A| used + * by some consumers which check |SSL_state|. */ +#define SSL3_ST_CR_SRVR_HELLO_B SSL3_ST_CR_SRVR_HELLO_A /* server */ /* extra state */ #define SSL3_ST_SW_FLUSH (0x100 | SSL_ST_ACCEPT) /* read from client */ -#define SSL3_ST_SR_INITIAL_BYTES (0x240 | SSL_ST_ACCEPT) -#define SSL3_ST_SR_V2_CLIENT_HELLO (0x241 | SSL_ST_ACCEPT) #define SSL3_ST_SR_CLNT_HELLO_A (0x110 | SSL_ST_ACCEPT) #define SSL3_ST_SR_CLNT_HELLO_B (0x111 | SSL_ST_ACCEPT) #define SSL3_ST_SR_CLNT_HELLO_C (0x112 | SSL_ST_ACCEPT) -#define SSL3_ST_SR_CLNT_HELLO_D (0x115 | SSL_ST_ACCEPT) +#define SSL3_ST_SR_CLNT_HELLO_D (0x113 | SSL_ST_ACCEPT) /* write to client */ -#define SSL3_ST_SW_HELLO_REQ_A (0x120 | SSL_ST_ACCEPT) -#define SSL3_ST_SW_HELLO_REQ_B (0x121 | SSL_ST_ACCEPT) -#define SSL3_ST_SW_HELLO_REQ_C (0x122 | SSL_ST_ACCEPT) #define SSL3_ST_SW_SRVR_HELLO_A (0x130 | SSL_ST_ACCEPT) -#define SSL3_ST_SW_SRVR_HELLO_B (0x131 | SSL_ST_ACCEPT) #define SSL3_ST_SW_CERT_A (0x140 | SSL_ST_ACCEPT) -#define SSL3_ST_SW_CERT_B (0x141 | SSL_ST_ACCEPT) #define SSL3_ST_SW_KEY_EXCH_A (0x150 | SSL_ST_ACCEPT) #define SSL3_ST_SW_KEY_EXCH_B (0x151 | SSL_ST_ACCEPT) -#define SSL3_ST_SW_KEY_EXCH_C (0x152 | SSL_ST_ACCEPT) #define SSL3_ST_SW_CERT_REQ_A (0x160 | SSL_ST_ACCEPT) -#define SSL3_ST_SW_CERT_REQ_B (0x161 | SSL_ST_ACCEPT) #define SSL3_ST_SW_SRVR_DONE_A (0x170 | SSL_ST_ACCEPT) -#define SSL3_ST_SW_SRVR_DONE_B (0x171 | SSL_ST_ACCEPT) /* read from client */ #define SSL3_ST_SR_CERT_A (0x180 | SSL_ST_ACCEPT) -#define SSL3_ST_SR_CERT_B (0x181 | SSL_ST_ACCEPT) #define SSL3_ST_SR_KEY_EXCH_A (0x190 | SSL_ST_ACCEPT) #define SSL3_ST_SR_KEY_EXCH_B (0x191 | SSL_ST_ACCEPT) -#define SSL3_ST_SR_KEY_EXCH_C (0x192 | SSL_ST_ACCEPT) #define SSL3_ST_SR_CERT_VRFY_A (0x1A0 | SSL_ST_ACCEPT) -#define SSL3_ST_SR_CERT_VRFY_B (0x1A1 | SSL_ST_ACCEPT) #define SSL3_ST_SR_CHANGE (0x1B0 | SSL_ST_ACCEPT) #define SSL3_ST_SR_NEXT_PROTO_A (0x210 | SSL_ST_ACCEPT) -#define SSL3_ST_SR_NEXT_PROTO_B (0x211 | SSL_ST_ACCEPT) #define SSL3_ST_SR_CHANNEL_ID_A (0x230 | SSL_ST_ACCEPT) -#define SSL3_ST_SR_CHANNEL_ID_B (0x231 | SSL_ST_ACCEPT) #define SSL3_ST_SR_FINISHED_A (0x1C0 | SSL_ST_ACCEPT) -#define SSL3_ST_SR_FINISHED_B (0x1C1 | SSL_ST_ACCEPT) /* write to client */ -#define SSL3_ST_SW_CHANGE_A (0x1D0 | SSL_ST_ACCEPT) -#define SSL3_ST_SW_CHANGE_B (0x1D1 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_CHANGE (0x1D0 | SSL_ST_ACCEPT) #define SSL3_ST_SW_FINISHED_A (0x1E0 | SSL_ST_ACCEPT) -#define SSL3_ST_SW_FINISHED_B (0x1E1 | SSL_ST_ACCEPT) #define SSL3_ST_SW_SESSION_TICKET_A (0x1F0 | SSL_ST_ACCEPT) -#define SSL3_ST_SW_SESSION_TICKET_B (0x1F1 | SSL_ST_ACCEPT) #define SSL3_ST_SW_CERT_STATUS_A (0x200 | SSL_ST_ACCEPT) -#define SSL3_ST_SW_CERT_STATUS_B (0x201 | SSL_ST_ACCEPT) -#define SSL3_ST_SW_SUPPLEMENTAL_DATA_A (0x220 | SSL_ST_ACCEPT) -#define SSL3_ST_SW_SUPPLEMENTAL_DATA_B (0x221 | SSL_ST_ACCEPT) #define SSL3_MT_HELLO_REQUEST 0 #define SSL3_MT_CLIENT_HELLO 1 #define SSL3_MT_SERVER_HELLO 2 -#define SSL3_MT_NEWSESSION_TICKET 4 +#define SSL3_MT_NEW_SESSION_TICKET 4 +#define SSL3_MT_HELLO_RETRY_REQUEST 6 +#define SSL3_MT_ENCRYPTED_EXTENSIONS 8 #define SSL3_MT_CERTIFICATE 11 #define SSL3_MT_SERVER_KEY_EXCHANGE 12 #define SSL3_MT_CERTIFICATE_REQUEST 13 -#define SSL3_MT_SERVER_DONE 14 +#define SSL3_MT_SERVER_HELLO_DONE 14 #define SSL3_MT_CERTIFICATE_VERIFY 15 #define SSL3_MT_CLIENT_KEY_EXCHANGE 16 #define SSL3_MT_FINISHED 20 #define SSL3_MT_CERTIFICATE_STATUS 22 #define SSL3_MT_SUPPLEMENTAL_DATA 23 +#define SSL3_MT_KEY_UPDATE 24 #define SSL3_MT_NEXT_PROTO 67 -#define SSL3_MT_ENCRYPTED_EXTENSIONS 203 +#define SSL3_MT_CHANNEL_ID 203 #define DTLS1_MT_HELLO_VERIFY_REQUEST 3 +/* The following are legacy aliases for consumers which use + * |SSL_CTX_set_msg_callback|. */ +#define SSL3_MT_SERVER_DONE SSL3_MT_SERVER_HELLO_DONE +#define SSL3_MT_NEWSESSION_TICKET SSL3_MT_NEW_SESSION_TICKET + #define SSL3_MT_CCS 1 diff --git a/Sources/BoringSSL/include/openssl/stack.h b/Sources/BoringSSL/include/openssl/stack.h index 16b9f4f66..c0cd0f6f5 100644 --- a/Sources/BoringSSL/include/openssl/stack.h +++ b/Sources/BoringSSL/include/openssl/stack.h @@ -100,7 +100,7 @@ typedef struct stack_st { void **data; /* sorted is non-zero if the values pointed to by |data| are in ascending * order, based on |comp|. */ - size_t sorted; + int sorted; /* num_alloc contains the number of pointers allocated in the buffer pointed * to by |data|, which may be larger than |num|. */ size_t num_alloc; @@ -129,6 +129,7 @@ typedef struct stack_st { * STACK_OF:BY_DIR_ENTRY * STACK_OF:BY_DIR_HASH * STACK_OF:CONF_VALUE + * STACK_OF:CRYPTO_BUFFER * STACK_OF:CRYPTO_EX_DATA_FUNCS * STACK_OF:DIST_POINT * STACK_OF:GENERAL_NAME @@ -180,14 +181,12 @@ typedef struct stack_st { typedef char *OPENSSL_STRING; DEFINE_SPECIAL_STACK_OF(OPENSSL_STRING, char) -DEFINE_SPECIAL_STACK_OF(OPENSSL_BLOCK, uint8_t) /* The make_macros.sh script in this directory parses the following lines and * generates the stack_macros.h file that contains macros for the following * types of stacks: * - * SPECIAL_STACK_OF:OPENSSL_STRING - * SPECIAL_STACK_OF:OPENSSL_BLOCK */ + * SPECIAL_STACK_OF:OPENSSL_STRING */ #define IN_STACK_H #include diff --git a/Sources/BoringSSL/include/openssl/stack_macros.h b/Sources/BoringSSL/include/openssl/stack_macros.h index 809424c72..a5f36fb64 100644 --- a/Sources/BoringSSL/include/openssl/stack_macros.h +++ b/Sources/BoringSSL/include/openssl/stack_macros.h @@ -27,14 +27,15 @@ ((STACK_OF(ACCESS_DESCRIPTION) *)sk_new_null()) #define sk_ACCESS_DESCRIPTION_num(sk) \ - sk_num(CHECKED_CAST(_STACK *, STACK_OF(ACCESS_DESCRIPTION) *, sk)) + sk_num(CHECKED_CAST(const _STACK *, const STACK_OF(ACCESS_DESCRIPTION) *, sk)) #define sk_ACCESS_DESCRIPTION_zero(sk) \ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(ACCESS_DESCRIPTION) *, sk)); -#define sk_ACCESS_DESCRIPTION_value(sk, i) \ - ((ACCESS_DESCRIPTION *)sk_value( \ - CHECKED_CAST(_STACK *, const STACK_OF(ACCESS_DESCRIPTION) *, sk), (i))) +#define sk_ACCESS_DESCRIPTION_value(sk, i) \ + ((ACCESS_DESCRIPTION *)sk_value( \ + CHECKED_CAST(const _STACK *, const STACK_OF(ACCESS_DESCRIPTION) *, sk), \ + (i))) #define sk_ACCESS_DESCRIPTION_set(sk, i, p) \ ((ACCESS_DESCRIPTION *)sk_set( \ @@ -80,13 +81,14 @@ #define sk_ACCESS_DESCRIPTION_dup(sk) \ ((STACK_OF(ACCESS_DESCRIPTION) *)sk_dup( \ - CHECKED_CAST(_STACK *, const STACK_OF(ACCESS_DESCRIPTION) *, sk))) + CHECKED_CAST(const _STACK *, const STACK_OF(ACCESS_DESCRIPTION) *, sk))) #define sk_ACCESS_DESCRIPTION_sort(sk) \ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(ACCESS_DESCRIPTION) *, sk)) #define sk_ACCESS_DESCRIPTION_is_sorted(sk) \ - sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(ACCESS_DESCRIPTION) *, sk)) + sk_is_sorted( \ + CHECKED_CAST(const _STACK *, const STACK_OF(ACCESS_DESCRIPTION) *, sk)) #define sk_ACCESS_DESCRIPTION_set_cmp_func(sk, comp) \ ((int (*)(const ACCESS_DESCRIPTION **a, const ACCESS_DESCRIPTION **b)) \ @@ -113,14 +115,15 @@ #define sk_ASN1_ADB_TABLE_new_null() ((STACK_OF(ASN1_ADB_TABLE) *)sk_new_null()) #define sk_ASN1_ADB_TABLE_num(sk) \ - sk_num(CHECKED_CAST(_STACK *, STACK_OF(ASN1_ADB_TABLE) *, sk)) + sk_num(CHECKED_CAST(const _STACK *, const STACK_OF(ASN1_ADB_TABLE) *, sk)) #define sk_ASN1_ADB_TABLE_zero(sk) \ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(ASN1_ADB_TABLE) *, sk)); -#define sk_ASN1_ADB_TABLE_value(sk, i) \ - ((ASN1_ADB_TABLE *)sk_value( \ - CHECKED_CAST(_STACK *, const STACK_OF(ASN1_ADB_TABLE) *, sk), (i))) +#define sk_ASN1_ADB_TABLE_value(sk, i) \ + ((ASN1_ADB_TABLE *)sk_value( \ + CHECKED_CAST(const _STACK *, const STACK_OF(ASN1_ADB_TABLE) *, sk), \ + (i))) #define sk_ASN1_ADB_TABLE_set(sk, i, p) \ ((ASN1_ADB_TABLE *)sk_set( \ @@ -166,13 +169,14 @@ #define sk_ASN1_ADB_TABLE_dup(sk) \ ((STACK_OF(ASN1_ADB_TABLE) *)sk_dup( \ - CHECKED_CAST(_STACK *, const STACK_OF(ASN1_ADB_TABLE) *, sk))) + CHECKED_CAST(const _STACK *, const STACK_OF(ASN1_ADB_TABLE) *, sk))) #define sk_ASN1_ADB_TABLE_sort(sk) \ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(ASN1_ADB_TABLE) *, sk)) #define sk_ASN1_ADB_TABLE_is_sorted(sk) \ - sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(ASN1_ADB_TABLE) *, sk)) + sk_is_sorted( \ + CHECKED_CAST(const _STACK *, const STACK_OF(ASN1_ADB_TABLE) *, sk)) #define sk_ASN1_ADB_TABLE_set_cmp_func(sk, comp) \ ((int (*)(const ASN1_ADB_TABLE **a, const ASN1_ADB_TABLE **b)) \ @@ -200,14 +204,15 @@ ((STACK_OF(ASN1_GENERALSTRING) *)sk_new_null()) #define sk_ASN1_GENERALSTRING_num(sk) \ - sk_num(CHECKED_CAST(_STACK *, STACK_OF(ASN1_GENERALSTRING) *, sk)) + sk_num(CHECKED_CAST(const _STACK *, const STACK_OF(ASN1_GENERALSTRING) *, sk)) #define sk_ASN1_GENERALSTRING_zero(sk) \ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(ASN1_GENERALSTRING) *, sk)); -#define sk_ASN1_GENERALSTRING_value(sk, i) \ - ((ASN1_GENERALSTRING *)sk_value( \ - CHECKED_CAST(_STACK *, const STACK_OF(ASN1_GENERALSTRING) *, sk), (i))) +#define sk_ASN1_GENERALSTRING_value(sk, i) \ + ((ASN1_GENERALSTRING *)sk_value( \ + CHECKED_CAST(const _STACK *, const STACK_OF(ASN1_GENERALSTRING) *, sk), \ + (i))) #define sk_ASN1_GENERALSTRING_set(sk, i, p) \ ((ASN1_GENERALSTRING *)sk_set( \ @@ -253,13 +258,14 @@ #define sk_ASN1_GENERALSTRING_dup(sk) \ ((STACK_OF(ASN1_GENERALSTRING) *)sk_dup( \ - CHECKED_CAST(_STACK *, const STACK_OF(ASN1_GENERALSTRING) *, sk))) + CHECKED_CAST(const _STACK *, const STACK_OF(ASN1_GENERALSTRING) *, sk))) #define sk_ASN1_GENERALSTRING_sort(sk) \ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(ASN1_GENERALSTRING) *, sk)) #define sk_ASN1_GENERALSTRING_is_sorted(sk) \ - sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(ASN1_GENERALSTRING) *, sk)) + sk_is_sorted( \ + CHECKED_CAST(const _STACK *, const STACK_OF(ASN1_GENERALSTRING) *, sk)) #define sk_ASN1_GENERALSTRING_set_cmp_func(sk, comp) \ ((int (*)(const ASN1_GENERALSTRING **a, const ASN1_GENERALSTRING **b)) \ @@ -286,14 +292,14 @@ #define sk_ASN1_INTEGER_new_null() ((STACK_OF(ASN1_INTEGER) *)sk_new_null()) #define sk_ASN1_INTEGER_num(sk) \ - sk_num(CHECKED_CAST(_STACK *, STACK_OF(ASN1_INTEGER) *, sk)) + sk_num(CHECKED_CAST(const _STACK *, const STACK_OF(ASN1_INTEGER) *, sk)) #define sk_ASN1_INTEGER_zero(sk) \ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(ASN1_INTEGER) *, sk)); #define sk_ASN1_INTEGER_value(sk, i) \ ((ASN1_INTEGER *)sk_value( \ - CHECKED_CAST(_STACK *, const STACK_OF(ASN1_INTEGER) *, sk), (i))) + CHECKED_CAST(const _STACK *, const STACK_OF(ASN1_INTEGER) *, sk), (i))) #define sk_ASN1_INTEGER_set(sk, i, p) \ ((ASN1_INTEGER *)sk_set( \ @@ -338,13 +344,13 @@ #define sk_ASN1_INTEGER_dup(sk) \ ((STACK_OF(ASN1_INTEGER) *)sk_dup( \ - CHECKED_CAST(_STACK *, const STACK_OF(ASN1_INTEGER) *, sk))) + CHECKED_CAST(const _STACK *, const STACK_OF(ASN1_INTEGER) *, sk))) #define sk_ASN1_INTEGER_sort(sk) \ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(ASN1_INTEGER) *, sk)) #define sk_ASN1_INTEGER_is_sorted(sk) \ - sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(ASN1_INTEGER) *, sk)) + sk_is_sorted(CHECKED_CAST(const _STACK *, const STACK_OF(ASN1_INTEGER) *, sk)) #define sk_ASN1_INTEGER_set_cmp_func(sk, comp) \ ((int (*)(const ASN1_INTEGER **a, const ASN1_INTEGER **b))sk_set_cmp_func( \ @@ -369,14 +375,14 @@ #define sk_ASN1_OBJECT_new_null() ((STACK_OF(ASN1_OBJECT) *)sk_new_null()) #define sk_ASN1_OBJECT_num(sk) \ - sk_num(CHECKED_CAST(_STACK *, STACK_OF(ASN1_OBJECT) *, sk)) + sk_num(CHECKED_CAST(const _STACK *, const STACK_OF(ASN1_OBJECT) *, sk)) #define sk_ASN1_OBJECT_zero(sk) \ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(ASN1_OBJECT) *, sk)); #define sk_ASN1_OBJECT_value(sk, i) \ ((ASN1_OBJECT *)sk_value( \ - CHECKED_CAST(_STACK *, const STACK_OF(ASN1_OBJECT) *, sk), (i))) + CHECKED_CAST(const _STACK *, const STACK_OF(ASN1_OBJECT) *, sk), (i))) #define sk_ASN1_OBJECT_set(sk, i, p) \ ((ASN1_OBJECT *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(ASN1_OBJECT) *, sk), \ @@ -419,13 +425,13 @@ #define sk_ASN1_OBJECT_dup(sk) \ ((STACK_OF(ASN1_OBJECT) *)sk_dup( \ - CHECKED_CAST(_STACK *, const STACK_OF(ASN1_OBJECT) *, sk))) + CHECKED_CAST(const _STACK *, const STACK_OF(ASN1_OBJECT) *, sk))) #define sk_ASN1_OBJECT_sort(sk) \ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(ASN1_OBJECT) *, sk)) #define sk_ASN1_OBJECT_is_sorted(sk) \ - sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(ASN1_OBJECT) *, sk)) + sk_is_sorted(CHECKED_CAST(const _STACK *, const STACK_OF(ASN1_OBJECT) *, sk)) #define sk_ASN1_OBJECT_set_cmp_func(sk, comp) \ ((int (*)(const ASN1_OBJECT **a, const ASN1_OBJECT **b))sk_set_cmp_func( \ @@ -452,14 +458,15 @@ ((STACK_OF(ASN1_STRING_TABLE) *)sk_new_null()) #define sk_ASN1_STRING_TABLE_num(sk) \ - sk_num(CHECKED_CAST(_STACK *, STACK_OF(ASN1_STRING_TABLE) *, sk)) + sk_num(CHECKED_CAST(const _STACK *, const STACK_OF(ASN1_STRING_TABLE) *, sk)) #define sk_ASN1_STRING_TABLE_zero(sk) \ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(ASN1_STRING_TABLE) *, sk)); -#define sk_ASN1_STRING_TABLE_value(sk, i) \ - ((ASN1_STRING_TABLE *)sk_value( \ - CHECKED_CAST(_STACK *, const STACK_OF(ASN1_STRING_TABLE) *, sk), (i))) +#define sk_ASN1_STRING_TABLE_value(sk, i) \ + ((ASN1_STRING_TABLE *)sk_value( \ + CHECKED_CAST(const _STACK *, const STACK_OF(ASN1_STRING_TABLE) *, sk), \ + (i))) #define sk_ASN1_STRING_TABLE_set(sk, i, p) \ ((ASN1_STRING_TABLE *)sk_set( \ @@ -505,13 +512,14 @@ #define sk_ASN1_STRING_TABLE_dup(sk) \ ((STACK_OF(ASN1_STRING_TABLE) *)sk_dup( \ - CHECKED_CAST(_STACK *, const STACK_OF(ASN1_STRING_TABLE) *, sk))) + CHECKED_CAST(const _STACK *, const STACK_OF(ASN1_STRING_TABLE) *, sk))) #define sk_ASN1_STRING_TABLE_sort(sk) \ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(ASN1_STRING_TABLE) *, sk)) #define sk_ASN1_STRING_TABLE_is_sorted(sk) \ - sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(ASN1_STRING_TABLE) *, sk)) + sk_is_sorted( \ + CHECKED_CAST(const _STACK *, const STACK_OF(ASN1_STRING_TABLE) *, sk)) #define sk_ASN1_STRING_TABLE_set_cmp_func(sk, comp) \ ((int (*)(const ASN1_STRING_TABLE **a, const ASN1_STRING_TABLE **b)) \ @@ -538,14 +546,14 @@ #define sk_ASN1_TYPE_new_null() ((STACK_OF(ASN1_TYPE) *)sk_new_null()) #define sk_ASN1_TYPE_num(sk) \ - sk_num(CHECKED_CAST(_STACK *, STACK_OF(ASN1_TYPE) *, sk)) + sk_num(CHECKED_CAST(const _STACK *, const STACK_OF(ASN1_TYPE) *, sk)) #define sk_ASN1_TYPE_zero(sk) \ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(ASN1_TYPE) *, sk)); #define sk_ASN1_TYPE_value(sk, i) \ ((ASN1_TYPE *)sk_value( \ - CHECKED_CAST(_STACK *, const STACK_OF(ASN1_TYPE) *, sk), (i))) + CHECKED_CAST(const _STACK *, const STACK_OF(ASN1_TYPE) *, sk), (i))) #define sk_ASN1_TYPE_set(sk, i, p) \ ((ASN1_TYPE *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(ASN1_TYPE) *, sk), (i), \ @@ -588,13 +596,13 @@ #define sk_ASN1_TYPE_dup(sk) \ ((STACK_OF(ASN1_TYPE) *)sk_dup( \ - CHECKED_CAST(_STACK *, const STACK_OF(ASN1_TYPE) *, sk))) + CHECKED_CAST(const _STACK *, const STACK_OF(ASN1_TYPE) *, sk))) #define sk_ASN1_TYPE_sort(sk) \ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(ASN1_TYPE) *, sk)) #define sk_ASN1_TYPE_is_sorted(sk) \ - sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(ASN1_TYPE) *, sk)) + sk_is_sorted(CHECKED_CAST(const _STACK *, const STACK_OF(ASN1_TYPE) *, sk)) #define sk_ASN1_TYPE_set_cmp_func(sk, comp) \ ((int (*)(const ASN1_TYPE **a, const ASN1_TYPE **b))sk_set_cmp_func( \ @@ -617,14 +625,14 @@ #define sk_ASN1_VALUE_new_null() ((STACK_OF(ASN1_VALUE) *)sk_new_null()) #define sk_ASN1_VALUE_num(sk) \ - sk_num(CHECKED_CAST(_STACK *, STACK_OF(ASN1_VALUE) *, sk)) + sk_num(CHECKED_CAST(const _STACK *, const STACK_OF(ASN1_VALUE) *, sk)) #define sk_ASN1_VALUE_zero(sk) \ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(ASN1_VALUE) *, sk)); #define sk_ASN1_VALUE_value(sk, i) \ ((ASN1_VALUE *)sk_value( \ - CHECKED_CAST(_STACK *, const STACK_OF(ASN1_VALUE) *, sk), (i))) + CHECKED_CAST(const _STACK *, const STACK_OF(ASN1_VALUE) *, sk), (i))) #define sk_ASN1_VALUE_set(sk, i, p) \ ((ASN1_VALUE *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(ASN1_VALUE) *, sk), \ @@ -667,13 +675,13 @@ #define sk_ASN1_VALUE_dup(sk) \ ((STACK_OF(ASN1_VALUE) *)sk_dup( \ - CHECKED_CAST(_STACK *, const STACK_OF(ASN1_VALUE) *, sk))) + CHECKED_CAST(const _STACK *, const STACK_OF(ASN1_VALUE) *, sk))) #define sk_ASN1_VALUE_sort(sk) \ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(ASN1_VALUE) *, sk)) #define sk_ASN1_VALUE_is_sorted(sk) \ - sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(ASN1_VALUE) *, sk)) + sk_is_sorted(CHECKED_CAST(const _STACK *, const STACK_OF(ASN1_VALUE) *, sk)) #define sk_ASN1_VALUE_set_cmp_func(sk, comp) \ ((int (*)(const ASN1_VALUE **a, const ASN1_VALUE **b))sk_set_cmp_func( \ @@ -696,12 +704,14 @@ #define sk_BIO_new_null() ((STACK_OF(BIO) *)sk_new_null()) -#define sk_BIO_num(sk) sk_num(CHECKED_CAST(_STACK *, STACK_OF(BIO) *, sk)) +#define sk_BIO_num(sk) \ + sk_num(CHECKED_CAST(const _STACK *, const STACK_OF(BIO) *, sk)) #define sk_BIO_zero(sk) sk_zero(CHECKED_CAST(_STACK *, STACK_OF(BIO) *, sk)); -#define sk_BIO_value(sk, i) \ - ((BIO *)sk_value(CHECKED_CAST(_STACK *, const STACK_OF(BIO) *, sk), (i))) +#define sk_BIO_value(sk, i) \ + ((BIO *)sk_value(CHECKED_CAST(const _STACK *, const STACK_OF(BIO) *, sk), \ + (i))) #define sk_BIO_set(sk, i, p) \ ((BIO *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(BIO) *, sk), (i), \ @@ -738,13 +748,14 @@ #define sk_BIO_pop(sk) \ ((BIO *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(BIO) *, sk))) -#define sk_BIO_dup(sk) \ - ((STACK_OF(BIO) *)sk_dup(CHECKED_CAST(_STACK *, const STACK_OF(BIO) *, sk))) +#define sk_BIO_dup(sk) \ + ((STACK_OF(BIO) *)sk_dup( \ + CHECKED_CAST(const _STACK *, const STACK_OF(BIO) *, sk))) #define sk_BIO_sort(sk) sk_sort(CHECKED_CAST(_STACK *, STACK_OF(BIO) *, sk)) #define sk_BIO_is_sorted(sk) \ - sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(BIO) *, sk)) + sk_is_sorted(CHECKED_CAST(const _STACK *, const STACK_OF(BIO) *, sk)) #define sk_BIO_set_cmp_func(sk, comp) \ ((int (*)(const BIO **a, const BIO **b))sk_set_cmp_func( \ @@ -767,14 +778,14 @@ #define sk_BY_DIR_ENTRY_new_null() ((STACK_OF(BY_DIR_ENTRY) *)sk_new_null()) #define sk_BY_DIR_ENTRY_num(sk) \ - sk_num(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_ENTRY) *, sk)) + sk_num(CHECKED_CAST(const _STACK *, const STACK_OF(BY_DIR_ENTRY) *, sk)) #define sk_BY_DIR_ENTRY_zero(sk) \ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_ENTRY) *, sk)); #define sk_BY_DIR_ENTRY_value(sk, i) \ ((BY_DIR_ENTRY *)sk_value( \ - CHECKED_CAST(_STACK *, const STACK_OF(BY_DIR_ENTRY) *, sk), (i))) + CHECKED_CAST(const _STACK *, const STACK_OF(BY_DIR_ENTRY) *, sk), (i))) #define sk_BY_DIR_ENTRY_set(sk, i, p) \ ((BY_DIR_ENTRY *)sk_set( \ @@ -819,13 +830,13 @@ #define sk_BY_DIR_ENTRY_dup(sk) \ ((STACK_OF(BY_DIR_ENTRY) *)sk_dup( \ - CHECKED_CAST(_STACK *, const STACK_OF(BY_DIR_ENTRY) *, sk))) + CHECKED_CAST(const _STACK *, const STACK_OF(BY_DIR_ENTRY) *, sk))) #define sk_BY_DIR_ENTRY_sort(sk) \ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_ENTRY) *, sk)) #define sk_BY_DIR_ENTRY_is_sorted(sk) \ - sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(BY_DIR_ENTRY) *, sk)) + sk_is_sorted(CHECKED_CAST(const _STACK *, const STACK_OF(BY_DIR_ENTRY) *, sk)) #define sk_BY_DIR_ENTRY_set_cmp_func(sk, comp) \ ((int (*)(const BY_DIR_ENTRY **a, const BY_DIR_ENTRY **b))sk_set_cmp_func( \ @@ -850,14 +861,14 @@ #define sk_BY_DIR_HASH_new_null() ((STACK_OF(BY_DIR_HASH) *)sk_new_null()) #define sk_BY_DIR_HASH_num(sk) \ - sk_num(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_HASH) *, sk)) + sk_num(CHECKED_CAST(const _STACK *, const STACK_OF(BY_DIR_HASH) *, sk)) #define sk_BY_DIR_HASH_zero(sk) \ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_HASH) *, sk)); #define sk_BY_DIR_HASH_value(sk, i) \ ((BY_DIR_HASH *)sk_value( \ - CHECKED_CAST(_STACK *, const STACK_OF(BY_DIR_HASH) *, sk), (i))) + CHECKED_CAST(const _STACK *, const STACK_OF(BY_DIR_HASH) *, sk), (i))) #define sk_BY_DIR_HASH_set(sk, i, p) \ ((BY_DIR_HASH *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_HASH) *, sk), \ @@ -900,13 +911,13 @@ #define sk_BY_DIR_HASH_dup(sk) \ ((STACK_OF(BY_DIR_HASH) *)sk_dup( \ - CHECKED_CAST(_STACK *, const STACK_OF(BY_DIR_HASH) *, sk))) + CHECKED_CAST(const _STACK *, const STACK_OF(BY_DIR_HASH) *, sk))) #define sk_BY_DIR_HASH_sort(sk) \ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_HASH) *, sk)) #define sk_BY_DIR_HASH_is_sorted(sk) \ - sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(BY_DIR_HASH) *, sk)) + sk_is_sorted(CHECKED_CAST(const _STACK *, const STACK_OF(BY_DIR_HASH) *, sk)) #define sk_BY_DIR_HASH_set_cmp_func(sk, comp) \ ((int (*)(const BY_DIR_HASH **a, const BY_DIR_HASH **b))sk_set_cmp_func( \ @@ -931,14 +942,14 @@ #define sk_CONF_VALUE_new_null() ((STACK_OF(CONF_VALUE) *)sk_new_null()) #define sk_CONF_VALUE_num(sk) \ - sk_num(CHECKED_CAST(_STACK *, STACK_OF(CONF_VALUE) *, sk)) + sk_num(CHECKED_CAST(const _STACK *, const STACK_OF(CONF_VALUE) *, sk)) #define sk_CONF_VALUE_zero(sk) \ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(CONF_VALUE) *, sk)); #define sk_CONF_VALUE_value(sk, i) \ ((CONF_VALUE *)sk_value( \ - CHECKED_CAST(_STACK *, const STACK_OF(CONF_VALUE) *, sk), (i))) + CHECKED_CAST(const _STACK *, const STACK_OF(CONF_VALUE) *, sk), (i))) #define sk_CONF_VALUE_set(sk, i, p) \ ((CONF_VALUE *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(CONF_VALUE) *, sk), \ @@ -981,13 +992,13 @@ #define sk_CONF_VALUE_dup(sk) \ ((STACK_OF(CONF_VALUE) *)sk_dup( \ - CHECKED_CAST(_STACK *, const STACK_OF(CONF_VALUE) *, sk))) + CHECKED_CAST(const _STACK *, const STACK_OF(CONF_VALUE) *, sk))) #define sk_CONF_VALUE_sort(sk) \ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(CONF_VALUE) *, sk)) #define sk_CONF_VALUE_is_sorted(sk) \ - sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(CONF_VALUE) *, sk)) + sk_is_sorted(CHECKED_CAST(const _STACK *, const STACK_OF(CONF_VALUE) *, sk)) #define sk_CONF_VALUE_set_cmp_func(sk, comp) \ ((int (*)(const CONF_VALUE **a, const CONF_VALUE **b))sk_set_cmp_func( \ @@ -1003,6 +1014,91 @@ copy_func), \ CHECKED_CAST(void (*)(void *), void (*)(CONF_VALUE *), free_func))) +/* CRYPTO_BUFFER */ +#define sk_CRYPTO_BUFFER_new(comp) \ + ((STACK_OF(CRYPTO_BUFFER) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, \ + int (*)(const CRYPTO_BUFFER **a, const CRYPTO_BUFFER **b), comp))) + +#define sk_CRYPTO_BUFFER_new_null() ((STACK_OF(CRYPTO_BUFFER) *)sk_new_null()) + +#define sk_CRYPTO_BUFFER_num(sk) \ + sk_num(CHECKED_CAST(const _STACK *, const STACK_OF(CRYPTO_BUFFER) *, sk)) + +#define sk_CRYPTO_BUFFER_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_BUFFER) *, sk)); + +#define sk_CRYPTO_BUFFER_value(sk, i) \ + ((CRYPTO_BUFFER *)sk_value( \ + CHECKED_CAST(const _STACK *, const STACK_OF(CRYPTO_BUFFER) *, sk), (i))) + +#define sk_CRYPTO_BUFFER_set(sk, i, p) \ + ((CRYPTO_BUFFER *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_BUFFER) *, sk), (i), \ + CHECKED_CAST(void *, CRYPTO_BUFFER *, p))) + +#define sk_CRYPTO_BUFFER_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_BUFFER) *, sk)) + +#define sk_CRYPTO_BUFFER_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_BUFFER) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(CRYPTO_BUFFER *), free_func)) + +#define sk_CRYPTO_BUFFER_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_BUFFER) *, sk), \ + CHECKED_CAST(void *, CRYPTO_BUFFER *, p), (where)) + +#define sk_CRYPTO_BUFFER_delete(sk, where) \ + ((CRYPTO_BUFFER *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_BUFFER) *, sk), (where))) + +#define sk_CRYPTO_BUFFER_delete_ptr(sk, p) \ + ((CRYPTO_BUFFER *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_BUFFER) *, sk), \ + CHECKED_CAST(void *, CRYPTO_BUFFER *, p))) + +#define sk_CRYPTO_BUFFER_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_BUFFER) *, sk), (out_index), \ + CHECKED_CAST(void *, CRYPTO_BUFFER *, p)) + +#define sk_CRYPTO_BUFFER_shift(sk) \ + ((CRYPTO_BUFFER *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_BUFFER) *, sk))) + +#define sk_CRYPTO_BUFFER_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_BUFFER) *, sk), \ + CHECKED_CAST(void *, CRYPTO_BUFFER *, p)) + +#define sk_CRYPTO_BUFFER_pop(sk) \ + ((CRYPTO_BUFFER *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_BUFFER) *, sk))) + +#define sk_CRYPTO_BUFFER_dup(sk) \ + ((STACK_OF(CRYPTO_BUFFER) *)sk_dup( \ + CHECKED_CAST(const _STACK *, const STACK_OF(CRYPTO_BUFFER) *, sk))) + +#define sk_CRYPTO_BUFFER_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_BUFFER) *, sk)) + +#define sk_CRYPTO_BUFFER_is_sorted(sk) \ + sk_is_sorted( \ + CHECKED_CAST(const _STACK *, const STACK_OF(CRYPTO_BUFFER) *, sk)) + +#define sk_CRYPTO_BUFFER_set_cmp_func(sk, comp) \ + ((int (*)(const CRYPTO_BUFFER **a, const CRYPTO_BUFFER **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_BUFFER) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const CRYPTO_BUFFER **a, const CRYPTO_BUFFER **b), \ + comp))) + +#define sk_CRYPTO_BUFFER_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(CRYPTO_BUFFER) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(CRYPTO_BUFFER) *, sk), \ + CHECKED_CAST(void *(*)(void *), CRYPTO_BUFFER *(*)(CRYPTO_BUFFER *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(CRYPTO_BUFFER *), free_func))) + /* CRYPTO_EX_DATA_FUNCS */ #define sk_CRYPTO_EX_DATA_FUNCS_new(comp) \ ((STACK_OF(CRYPTO_EX_DATA_FUNCS) *)sk_new(CHECKED_CAST( \ @@ -1013,15 +1109,17 @@ #define sk_CRYPTO_EX_DATA_FUNCS_new_null() \ ((STACK_OF(CRYPTO_EX_DATA_FUNCS) *)sk_new_null()) -#define sk_CRYPTO_EX_DATA_FUNCS_num(sk) \ - sk_num(CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk)) +#define sk_CRYPTO_EX_DATA_FUNCS_num(sk) \ + sk_num(CHECKED_CAST(const _STACK *, const STACK_OF(CRYPTO_EX_DATA_FUNCS) *, \ + sk)) #define sk_CRYPTO_EX_DATA_FUNCS_zero(sk) \ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk)); -#define sk_CRYPTO_EX_DATA_FUNCS_value(sk, i) \ - ((CRYPTO_EX_DATA_FUNCS *)sk_value( \ - CHECKED_CAST(_STACK *, const STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk), \ +#define sk_CRYPTO_EX_DATA_FUNCS_value(sk, i) \ + ((CRYPTO_EX_DATA_FUNCS *)sk_value( \ + CHECKED_CAST(const _STACK *, const STACK_OF(CRYPTO_EX_DATA_FUNCS) *, \ + sk), \ (i))) #define sk_CRYPTO_EX_DATA_FUNCS_set(sk, i, p) \ @@ -1066,16 +1164,16 @@ ((CRYPTO_EX_DATA_FUNCS *)sk_pop( \ CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk))) -#define sk_CRYPTO_EX_DATA_FUNCS_dup(sk) \ - ((STACK_OF(CRYPTO_EX_DATA_FUNCS) *)sk_dup( \ - CHECKED_CAST(_STACK *, const STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk))) +#define sk_CRYPTO_EX_DATA_FUNCS_dup(sk) \ + ((STACK_OF(CRYPTO_EX_DATA_FUNCS) *)sk_dup(CHECKED_CAST( \ + const _STACK *, const STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk))) #define sk_CRYPTO_EX_DATA_FUNCS_sort(sk) \ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk)) #define sk_CRYPTO_EX_DATA_FUNCS_is_sorted(sk) \ - sk_is_sorted( \ - CHECKED_CAST(_STACK *, const STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk)) + sk_is_sorted(CHECKED_CAST(const _STACK *, \ + const STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk)) #define sk_CRYPTO_EX_DATA_FUNCS_set_cmp_func(sk, comp) \ ((int (*)(const CRYPTO_EX_DATA_FUNCS **a, const CRYPTO_EX_DATA_FUNCS **b)) \ @@ -1105,14 +1203,14 @@ #define sk_DIST_POINT_new_null() ((STACK_OF(DIST_POINT) *)sk_new_null()) #define sk_DIST_POINT_num(sk) \ - sk_num(CHECKED_CAST(_STACK *, STACK_OF(DIST_POINT) *, sk)) + sk_num(CHECKED_CAST(const _STACK *, const STACK_OF(DIST_POINT) *, sk)) #define sk_DIST_POINT_zero(sk) \ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(DIST_POINT) *, sk)); #define sk_DIST_POINT_value(sk, i) \ ((DIST_POINT *)sk_value( \ - CHECKED_CAST(_STACK *, const STACK_OF(DIST_POINT) *, sk), (i))) + CHECKED_CAST(const _STACK *, const STACK_OF(DIST_POINT) *, sk), (i))) #define sk_DIST_POINT_set(sk, i, p) \ ((DIST_POINT *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(DIST_POINT) *, sk), \ @@ -1155,13 +1253,13 @@ #define sk_DIST_POINT_dup(sk) \ ((STACK_OF(DIST_POINT) *)sk_dup( \ - CHECKED_CAST(_STACK *, const STACK_OF(DIST_POINT) *, sk))) + CHECKED_CAST(const _STACK *, const STACK_OF(DIST_POINT) *, sk))) #define sk_DIST_POINT_sort(sk) \ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(DIST_POINT) *, sk)) #define sk_DIST_POINT_is_sorted(sk) \ - sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(DIST_POINT) *, sk)) + sk_is_sorted(CHECKED_CAST(const _STACK *, const STACK_OF(DIST_POINT) *, sk)) #define sk_DIST_POINT_set_cmp_func(sk, comp) \ ((int (*)(const DIST_POINT **a, const DIST_POINT **b))sk_set_cmp_func( \ @@ -1186,14 +1284,14 @@ #define sk_GENERAL_NAME_new_null() ((STACK_OF(GENERAL_NAME) *)sk_new_null()) #define sk_GENERAL_NAME_num(sk) \ - sk_num(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAME) *, sk)) + sk_num(CHECKED_CAST(const _STACK *, const STACK_OF(GENERAL_NAME) *, sk)) #define sk_GENERAL_NAME_zero(sk) \ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAME) *, sk)); #define sk_GENERAL_NAME_value(sk, i) \ ((GENERAL_NAME *)sk_value( \ - CHECKED_CAST(_STACK *, const STACK_OF(GENERAL_NAME) *, sk), (i))) + CHECKED_CAST(const _STACK *, const STACK_OF(GENERAL_NAME) *, sk), (i))) #define sk_GENERAL_NAME_set(sk, i, p) \ ((GENERAL_NAME *)sk_set( \ @@ -1238,13 +1336,13 @@ #define sk_GENERAL_NAME_dup(sk) \ ((STACK_OF(GENERAL_NAME) *)sk_dup( \ - CHECKED_CAST(_STACK *, const STACK_OF(GENERAL_NAME) *, sk))) + CHECKED_CAST(const _STACK *, const STACK_OF(GENERAL_NAME) *, sk))) #define sk_GENERAL_NAME_sort(sk) \ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAME) *, sk)) #define sk_GENERAL_NAME_is_sorted(sk) \ - sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(GENERAL_NAME) *, sk)) + sk_is_sorted(CHECKED_CAST(const _STACK *, const STACK_OF(GENERAL_NAME) *, sk)) #define sk_GENERAL_NAME_set_cmp_func(sk, comp) \ ((int (*)(const GENERAL_NAME **a, const GENERAL_NAME **b))sk_set_cmp_func( \ @@ -1269,14 +1367,14 @@ #define sk_GENERAL_NAMES_new_null() ((STACK_OF(GENERAL_NAMES) *)sk_new_null()) #define sk_GENERAL_NAMES_num(sk) \ - sk_num(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAMES) *, sk)) + sk_num(CHECKED_CAST(const _STACK *, const STACK_OF(GENERAL_NAMES) *, sk)) #define sk_GENERAL_NAMES_zero(sk) \ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAMES) *, sk)); #define sk_GENERAL_NAMES_value(sk, i) \ ((GENERAL_NAMES *)sk_value( \ - CHECKED_CAST(_STACK *, const STACK_OF(GENERAL_NAMES) *, sk), (i))) + CHECKED_CAST(const _STACK *, const STACK_OF(GENERAL_NAMES) *, sk), (i))) #define sk_GENERAL_NAMES_set(sk, i, p) \ ((GENERAL_NAMES *)sk_set( \ @@ -1322,13 +1420,14 @@ #define sk_GENERAL_NAMES_dup(sk) \ ((STACK_OF(GENERAL_NAMES) *)sk_dup( \ - CHECKED_CAST(_STACK *, const STACK_OF(GENERAL_NAMES) *, sk))) + CHECKED_CAST(const _STACK *, const STACK_OF(GENERAL_NAMES) *, sk))) #define sk_GENERAL_NAMES_sort(sk) \ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAMES) *, sk)) #define sk_GENERAL_NAMES_is_sorted(sk) \ - sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(GENERAL_NAMES) *, sk)) + sk_is_sorted( \ + CHECKED_CAST(const _STACK *, const STACK_OF(GENERAL_NAMES) *, sk)) #define sk_GENERAL_NAMES_set_cmp_func(sk, comp) \ ((int (*)(const GENERAL_NAMES **a, const GENERAL_NAMES **b))sk_set_cmp_func( \ @@ -1354,14 +1453,15 @@ ((STACK_OF(GENERAL_SUBTREE) *)sk_new_null()) #define sk_GENERAL_SUBTREE_num(sk) \ - sk_num(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_SUBTREE) *, sk)) + sk_num(CHECKED_CAST(const _STACK *, const STACK_OF(GENERAL_SUBTREE) *, sk)) #define sk_GENERAL_SUBTREE_zero(sk) \ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_SUBTREE) *, sk)); -#define sk_GENERAL_SUBTREE_value(sk, i) \ - ((GENERAL_SUBTREE *)sk_value( \ - CHECKED_CAST(_STACK *, const STACK_OF(GENERAL_SUBTREE) *, sk), (i))) +#define sk_GENERAL_SUBTREE_value(sk, i) \ + ((GENERAL_SUBTREE *)sk_value( \ + CHECKED_CAST(const _STACK *, const STACK_OF(GENERAL_SUBTREE) *, sk), \ + (i))) #define sk_GENERAL_SUBTREE_set(sk, i, p) \ ((GENERAL_SUBTREE *)sk_set( \ @@ -1407,13 +1507,14 @@ #define sk_GENERAL_SUBTREE_dup(sk) \ ((STACK_OF(GENERAL_SUBTREE) *)sk_dup( \ - CHECKED_CAST(_STACK *, const STACK_OF(GENERAL_SUBTREE) *, sk))) + CHECKED_CAST(const _STACK *, const STACK_OF(GENERAL_SUBTREE) *, sk))) #define sk_GENERAL_SUBTREE_sort(sk) \ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_SUBTREE) *, sk)) #define sk_GENERAL_SUBTREE_is_sorted(sk) \ - sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(GENERAL_SUBTREE) *, sk)) + sk_is_sorted( \ + CHECKED_CAST(const _STACK *, const STACK_OF(GENERAL_SUBTREE) *, sk)) #define sk_GENERAL_SUBTREE_set_cmp_func(sk, comp) \ ((int (*)(const GENERAL_SUBTREE **a, const GENERAL_SUBTREE **b)) \ @@ -1439,14 +1540,14 @@ #define sk_POLICYINFO_new_null() ((STACK_OF(POLICYINFO) *)sk_new_null()) #define sk_POLICYINFO_num(sk) \ - sk_num(CHECKED_CAST(_STACK *, STACK_OF(POLICYINFO) *, sk)) + sk_num(CHECKED_CAST(const _STACK *, const STACK_OF(POLICYINFO) *, sk)) #define sk_POLICYINFO_zero(sk) \ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(POLICYINFO) *, sk)); #define sk_POLICYINFO_value(sk, i) \ ((POLICYINFO *)sk_value( \ - CHECKED_CAST(_STACK *, const STACK_OF(POLICYINFO) *, sk), (i))) + CHECKED_CAST(const _STACK *, const STACK_OF(POLICYINFO) *, sk), (i))) #define sk_POLICYINFO_set(sk, i, p) \ ((POLICYINFO *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(POLICYINFO) *, sk), \ @@ -1489,13 +1590,13 @@ #define sk_POLICYINFO_dup(sk) \ ((STACK_OF(POLICYINFO) *)sk_dup( \ - CHECKED_CAST(_STACK *, const STACK_OF(POLICYINFO) *, sk))) + CHECKED_CAST(const _STACK *, const STACK_OF(POLICYINFO) *, sk))) #define sk_POLICYINFO_sort(sk) \ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(POLICYINFO) *, sk)) #define sk_POLICYINFO_is_sorted(sk) \ - sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(POLICYINFO) *, sk)) + sk_is_sorted(CHECKED_CAST(const _STACK *, const STACK_OF(POLICYINFO) *, sk)) #define sk_POLICYINFO_set_cmp_func(sk, comp) \ ((int (*)(const POLICYINFO **a, const POLICYINFO **b))sk_set_cmp_func( \ @@ -1520,14 +1621,15 @@ #define sk_POLICYQUALINFO_new_null() ((STACK_OF(POLICYQUALINFO) *)sk_new_null()) #define sk_POLICYQUALINFO_num(sk) \ - sk_num(CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk)) + sk_num(CHECKED_CAST(const _STACK *, const STACK_OF(POLICYQUALINFO) *, sk)) #define sk_POLICYQUALINFO_zero(sk) \ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk)); -#define sk_POLICYQUALINFO_value(sk, i) \ - ((POLICYQUALINFO *)sk_value( \ - CHECKED_CAST(_STACK *, const STACK_OF(POLICYQUALINFO) *, sk), (i))) +#define sk_POLICYQUALINFO_value(sk, i) \ + ((POLICYQUALINFO *)sk_value( \ + CHECKED_CAST(const _STACK *, const STACK_OF(POLICYQUALINFO) *, sk), \ + (i))) #define sk_POLICYQUALINFO_set(sk, i, p) \ ((POLICYQUALINFO *)sk_set( \ @@ -1573,13 +1675,14 @@ #define sk_POLICYQUALINFO_dup(sk) \ ((STACK_OF(POLICYQUALINFO) *)sk_dup( \ - CHECKED_CAST(_STACK *, const STACK_OF(POLICYQUALINFO) *, sk))) + CHECKED_CAST(const _STACK *, const STACK_OF(POLICYQUALINFO) *, sk))) #define sk_POLICYQUALINFO_sort(sk) \ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk)) #define sk_POLICYQUALINFO_is_sorted(sk) \ - sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(POLICYQUALINFO) *, sk)) + sk_is_sorted( \ + CHECKED_CAST(const _STACK *, const STACK_OF(POLICYQUALINFO) *, sk)) #define sk_POLICYQUALINFO_set_cmp_func(sk, comp) \ ((int (*)(const POLICYQUALINFO **a, const POLICYQUALINFO **b)) \ @@ -1605,14 +1708,15 @@ #define sk_POLICY_MAPPING_new_null() ((STACK_OF(POLICY_MAPPING) *)sk_new_null()) #define sk_POLICY_MAPPING_num(sk) \ - sk_num(CHECKED_CAST(_STACK *, STACK_OF(POLICY_MAPPING) *, sk)) + sk_num(CHECKED_CAST(const _STACK *, const STACK_OF(POLICY_MAPPING) *, sk)) #define sk_POLICY_MAPPING_zero(sk) \ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(POLICY_MAPPING) *, sk)); -#define sk_POLICY_MAPPING_value(sk, i) \ - ((POLICY_MAPPING *)sk_value( \ - CHECKED_CAST(_STACK *, const STACK_OF(POLICY_MAPPING) *, sk), (i))) +#define sk_POLICY_MAPPING_value(sk, i) \ + ((POLICY_MAPPING *)sk_value( \ + CHECKED_CAST(const _STACK *, const STACK_OF(POLICY_MAPPING) *, sk), \ + (i))) #define sk_POLICY_MAPPING_set(sk, i, p) \ ((POLICY_MAPPING *)sk_set( \ @@ -1658,13 +1762,14 @@ #define sk_POLICY_MAPPING_dup(sk) \ ((STACK_OF(POLICY_MAPPING) *)sk_dup( \ - CHECKED_CAST(_STACK *, const STACK_OF(POLICY_MAPPING) *, sk))) + CHECKED_CAST(const _STACK *, const STACK_OF(POLICY_MAPPING) *, sk))) #define sk_POLICY_MAPPING_sort(sk) \ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(POLICY_MAPPING) *, sk)) #define sk_POLICY_MAPPING_is_sorted(sk) \ - sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(POLICY_MAPPING) *, sk)) + sk_is_sorted( \ + CHECKED_CAST(const _STACK *, const STACK_OF(POLICY_MAPPING) *, sk)) #define sk_POLICY_MAPPING_set_cmp_func(sk, comp) \ ((int (*)(const POLICY_MAPPING **a, const POLICY_MAPPING **b)) \ @@ -1691,15 +1796,17 @@ #define sk_RSA_additional_prime_new_null() \ ((STACK_OF(RSA_additional_prime) *)sk_new_null()) -#define sk_RSA_additional_prime_num(sk) \ - sk_num(CHECKED_CAST(_STACK *, STACK_OF(RSA_additional_prime) *, sk)) +#define sk_RSA_additional_prime_num(sk) \ + sk_num(CHECKED_CAST(const _STACK *, const STACK_OF(RSA_additional_prime) *, \ + sk)) #define sk_RSA_additional_prime_zero(sk) \ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(RSA_additional_prime) *, sk)); -#define sk_RSA_additional_prime_value(sk, i) \ - ((RSA_additional_prime *)sk_value( \ - CHECKED_CAST(_STACK *, const STACK_OF(RSA_additional_prime) *, sk), \ +#define sk_RSA_additional_prime_value(sk, i) \ + ((RSA_additional_prime *)sk_value( \ + CHECKED_CAST(const _STACK *, const STACK_OF(RSA_additional_prime) *, \ + sk), \ (i))) #define sk_RSA_additional_prime_set(sk, i, p) \ @@ -1744,16 +1851,16 @@ ((RSA_additional_prime *)sk_pop( \ CHECKED_CAST(_STACK *, STACK_OF(RSA_additional_prime) *, sk))) -#define sk_RSA_additional_prime_dup(sk) \ - ((STACK_OF(RSA_additional_prime) *)sk_dup( \ - CHECKED_CAST(_STACK *, const STACK_OF(RSA_additional_prime) *, sk))) +#define sk_RSA_additional_prime_dup(sk) \ + ((STACK_OF(RSA_additional_prime) *)sk_dup(CHECKED_CAST( \ + const _STACK *, const STACK_OF(RSA_additional_prime) *, sk))) #define sk_RSA_additional_prime_sort(sk) \ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(RSA_additional_prime) *, sk)) #define sk_RSA_additional_prime_is_sorted(sk) \ - sk_is_sorted( \ - CHECKED_CAST(_STACK *, const STACK_OF(RSA_additional_prime) *, sk)) + sk_is_sorted(CHECKED_CAST(const _STACK *, \ + const STACK_OF(RSA_additional_prime) *, sk)) #define sk_RSA_additional_prime_set_cmp_func(sk, comp) \ ((int (*)(const RSA_additional_prime **a, const RSA_additional_prime **b)) \ @@ -1782,14 +1889,14 @@ #define sk_SSL_COMP_new_null() ((STACK_OF(SSL_COMP) *)sk_new_null()) #define sk_SSL_COMP_num(sk) \ - sk_num(CHECKED_CAST(_STACK *, STACK_OF(SSL_COMP) *, sk)) + sk_num(CHECKED_CAST(const _STACK *, const STACK_OF(SSL_COMP) *, sk)) #define sk_SSL_COMP_zero(sk) \ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(SSL_COMP) *, sk)); #define sk_SSL_COMP_value(sk, i) \ ((SSL_COMP *)sk_value( \ - CHECKED_CAST(_STACK *, const STACK_OF(SSL_COMP) *, sk), (i))) + CHECKED_CAST(const _STACK *, const STACK_OF(SSL_COMP) *, sk), (i))) #define sk_SSL_COMP_set(sk, i, p) \ ((SSL_COMP *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(SSL_COMP) *, sk), (i), \ @@ -1830,13 +1937,13 @@ #define sk_SSL_COMP_dup(sk) \ ((STACK_OF(SSL_COMP) *)sk_dup( \ - CHECKED_CAST(_STACK *, const STACK_OF(SSL_COMP) *, sk))) + CHECKED_CAST(const _STACK *, const STACK_OF(SSL_COMP) *, sk))) #define sk_SSL_COMP_sort(sk) \ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(SSL_COMP) *, sk)) #define sk_SSL_COMP_is_sorted(sk) \ - sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(SSL_COMP) *, sk)) + sk_is_sorted(CHECKED_CAST(const _STACK *, const STACK_OF(SSL_COMP) *, sk)) #define sk_SSL_COMP_set_cmp_func(sk, comp) \ ((int (*)(const SSL_COMP **a, const SSL_COMP **b))sk_set_cmp_func( \ @@ -1860,15 +1967,17 @@ #define sk_SSL_CUSTOM_EXTENSION_new_null() \ ((STACK_OF(SSL_CUSTOM_EXTENSION) *)sk_new_null()) -#define sk_SSL_CUSTOM_EXTENSION_num(sk) \ - sk_num(CHECKED_CAST(_STACK *, STACK_OF(SSL_CUSTOM_EXTENSION) *, sk)) +#define sk_SSL_CUSTOM_EXTENSION_num(sk) \ + sk_num(CHECKED_CAST(const _STACK *, const STACK_OF(SSL_CUSTOM_EXTENSION) *, \ + sk)) #define sk_SSL_CUSTOM_EXTENSION_zero(sk) \ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(SSL_CUSTOM_EXTENSION) *, sk)); -#define sk_SSL_CUSTOM_EXTENSION_value(sk, i) \ - ((SSL_CUSTOM_EXTENSION *)sk_value( \ - CHECKED_CAST(_STACK *, const STACK_OF(SSL_CUSTOM_EXTENSION) *, sk), \ +#define sk_SSL_CUSTOM_EXTENSION_value(sk, i) \ + ((SSL_CUSTOM_EXTENSION *)sk_value( \ + CHECKED_CAST(const _STACK *, const STACK_OF(SSL_CUSTOM_EXTENSION) *, \ + sk), \ (i))) #define sk_SSL_CUSTOM_EXTENSION_set(sk, i, p) \ @@ -1913,16 +2022,16 @@ ((SSL_CUSTOM_EXTENSION *)sk_pop( \ CHECKED_CAST(_STACK *, STACK_OF(SSL_CUSTOM_EXTENSION) *, sk))) -#define sk_SSL_CUSTOM_EXTENSION_dup(sk) \ - ((STACK_OF(SSL_CUSTOM_EXTENSION) *)sk_dup( \ - CHECKED_CAST(_STACK *, const STACK_OF(SSL_CUSTOM_EXTENSION) *, sk))) +#define sk_SSL_CUSTOM_EXTENSION_dup(sk) \ + ((STACK_OF(SSL_CUSTOM_EXTENSION) *)sk_dup(CHECKED_CAST( \ + const _STACK *, const STACK_OF(SSL_CUSTOM_EXTENSION) *, sk))) #define sk_SSL_CUSTOM_EXTENSION_sort(sk) \ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(SSL_CUSTOM_EXTENSION) *, sk)) #define sk_SSL_CUSTOM_EXTENSION_is_sorted(sk) \ - sk_is_sorted( \ - CHECKED_CAST(_STACK *, const STACK_OF(SSL_CUSTOM_EXTENSION) *, sk)) + sk_is_sorted(CHECKED_CAST(const _STACK *, \ + const STACK_OF(SSL_CUSTOM_EXTENSION) *, sk)) #define sk_SSL_CUSTOM_EXTENSION_set_cmp_func(sk, comp) \ ((int (*)(const SSL_CUSTOM_EXTENSION **a, const SSL_CUSTOM_EXTENSION **b)) \ @@ -1954,14 +2063,16 @@ ((STACK_OF(STACK_OF_X509_NAME_ENTRY) *)sk_new_null()) #define sk_STACK_OF_X509_NAME_ENTRY_num(sk) \ - sk_num(CHECKED_CAST(_STACK *, STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk)) + sk_num(CHECKED_CAST(const _STACK *, \ + const STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk)) #define sk_STACK_OF_X509_NAME_ENTRY_zero(sk) \ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk)); -#define sk_STACK_OF_X509_NAME_ENTRY_value(sk, i) \ - ((STACK_OF_X509_NAME_ENTRY *)sk_value( \ - CHECKED_CAST(_STACK *, const STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk), \ +#define sk_STACK_OF_X509_NAME_ENTRY_value(sk, i) \ + ((STACK_OF_X509_NAME_ENTRY *)sk_value( \ + CHECKED_CAST(const _STACK *, const STACK_OF(STACK_OF_X509_NAME_ENTRY) *, \ + sk), \ (i))) #define sk_STACK_OF_X509_NAME_ENTRY_set(sk, i, p) \ @@ -2008,16 +2119,16 @@ ((STACK_OF_X509_NAME_ENTRY *)sk_pop( \ CHECKED_CAST(_STACK *, STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk))) -#define sk_STACK_OF_X509_NAME_ENTRY_dup(sk) \ - ((STACK_OF(STACK_OF_X509_NAME_ENTRY) *)sk_dup( \ - CHECKED_CAST(_STACK *, const STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk))) +#define sk_STACK_OF_X509_NAME_ENTRY_dup(sk) \ + ((STACK_OF(STACK_OF_X509_NAME_ENTRY) *)sk_dup(CHECKED_CAST( \ + const _STACK *, const STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk))) #define sk_STACK_OF_X509_NAME_ENTRY_sort(sk) \ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk)) #define sk_STACK_OF_X509_NAME_ENTRY_is_sorted(sk) \ - sk_is_sorted( \ - CHECKED_CAST(_STACK *, const STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk)) + sk_is_sorted(CHECKED_CAST(const _STACK *, \ + const STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk)) #define sk_STACK_OF_X509_NAME_ENTRY_set_cmp_func(sk, comp) \ ((int (*)(const STACK_OF_X509_NAME_ENTRY **a, \ @@ -2047,14 +2158,14 @@ #define sk_SXNETID_new_null() ((STACK_OF(SXNETID) *)sk_new_null()) #define sk_SXNETID_num(sk) \ - sk_num(CHECKED_CAST(_STACK *, STACK_OF(SXNETID) *, sk)) + sk_num(CHECKED_CAST(const _STACK *, const STACK_OF(SXNETID) *, sk)) #define sk_SXNETID_zero(sk) \ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(SXNETID) *, sk)); -#define sk_SXNETID_value(sk, i) \ - ((SXNETID *)sk_value(CHECKED_CAST(_STACK *, const STACK_OF(SXNETID) *, sk), \ - (i))) +#define sk_SXNETID_value(sk, i) \ + ((SXNETID *)sk_value( \ + CHECKED_CAST(const _STACK *, const STACK_OF(SXNETID) *, sk), (i))) #define sk_SXNETID_set(sk, i, p) \ ((SXNETID *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(SXNETID) *, sk), (i), \ @@ -2095,13 +2206,13 @@ #define sk_SXNETID_dup(sk) \ ((STACK_OF(SXNETID) *)sk_dup( \ - CHECKED_CAST(_STACK *, const STACK_OF(SXNETID) *, sk))) + CHECKED_CAST(const _STACK *, const STACK_OF(SXNETID) *, sk))) #define sk_SXNETID_sort(sk) \ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(SXNETID) *, sk)) #define sk_SXNETID_is_sorted(sk) \ - sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(SXNETID) *, sk)) + sk_is_sorted(CHECKED_CAST(const _STACK *, const STACK_OF(SXNETID) *, sk)) #define sk_SXNETID_set_cmp_func(sk, comp) \ ((int (*)(const SXNETID **a, const SXNETID **b))sk_set_cmp_func( \ @@ -2122,12 +2233,14 @@ #define sk_X509_new_null() ((STACK_OF(X509) *)sk_new_null()) -#define sk_X509_num(sk) sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509) *, sk)) +#define sk_X509_num(sk) \ + sk_num(CHECKED_CAST(const _STACK *, const STACK_OF(X509) *, sk)) #define sk_X509_zero(sk) sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509) *, sk)); -#define sk_X509_value(sk, i) \ - ((X509 *)sk_value(CHECKED_CAST(_STACK *, const STACK_OF(X509) *, sk), (i))) +#define sk_X509_value(sk, i) \ + ((X509 *)sk_value(CHECKED_CAST(const _STACK *, const STACK_OF(X509) *, sk), \ + (i))) #define sk_X509_set(sk, i, p) \ ((X509 *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(X509) *, sk), (i), \ @@ -2164,13 +2277,14 @@ #define sk_X509_pop(sk) \ ((X509 *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(X509) *, sk))) -#define sk_X509_dup(sk) \ - ((STACK_OF(X509) *)sk_dup(CHECKED_CAST(_STACK *, const STACK_OF(X509) *, sk))) +#define sk_X509_dup(sk) \ + ((STACK_OF(X509) *)sk_dup( \ + CHECKED_CAST(const _STACK *, const STACK_OF(X509) *, sk))) #define sk_X509_sort(sk) sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509) *, sk)) #define sk_X509_is_sorted(sk) \ - sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509) *, sk)) + sk_is_sorted(CHECKED_CAST(const _STACK *, const STACK_OF(X509) *, sk)) #define sk_X509_set_cmp_func(sk, comp) \ ((int (*)(const X509 **a, const X509 **b))sk_set_cmp_func( \ @@ -2195,14 +2309,15 @@ ((STACK_OF(X509V3_EXT_METHOD) *)sk_new_null()) #define sk_X509V3_EXT_METHOD_num(sk) \ - sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509V3_EXT_METHOD) *, sk)) + sk_num(CHECKED_CAST(const _STACK *, const STACK_OF(X509V3_EXT_METHOD) *, sk)) #define sk_X509V3_EXT_METHOD_zero(sk) \ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509V3_EXT_METHOD) *, sk)); -#define sk_X509V3_EXT_METHOD_value(sk, i) \ - ((X509V3_EXT_METHOD *)sk_value( \ - CHECKED_CAST(_STACK *, const STACK_OF(X509V3_EXT_METHOD) *, sk), (i))) +#define sk_X509V3_EXT_METHOD_value(sk, i) \ + ((X509V3_EXT_METHOD *)sk_value( \ + CHECKED_CAST(const _STACK *, const STACK_OF(X509V3_EXT_METHOD) *, sk), \ + (i))) #define sk_X509V3_EXT_METHOD_set(sk, i, p) \ ((X509V3_EXT_METHOD *)sk_set( \ @@ -2248,13 +2363,14 @@ #define sk_X509V3_EXT_METHOD_dup(sk) \ ((STACK_OF(X509V3_EXT_METHOD) *)sk_dup( \ - CHECKED_CAST(_STACK *, const STACK_OF(X509V3_EXT_METHOD) *, sk))) + CHECKED_CAST(const _STACK *, const STACK_OF(X509V3_EXT_METHOD) *, sk))) #define sk_X509V3_EXT_METHOD_sort(sk) \ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509V3_EXT_METHOD) *, sk)) #define sk_X509V3_EXT_METHOD_is_sorted(sk) \ - sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509V3_EXT_METHOD) *, sk)) + sk_is_sorted( \ + CHECKED_CAST(const _STACK *, const STACK_OF(X509V3_EXT_METHOD) *, sk)) #define sk_X509V3_EXT_METHOD_set_cmp_func(sk, comp) \ ((int (*)(const X509V3_EXT_METHOD **a, const X509V3_EXT_METHOD **b)) \ @@ -2281,14 +2397,14 @@ #define sk_X509_ALGOR_new_null() ((STACK_OF(X509_ALGOR) *)sk_new_null()) #define sk_X509_ALGOR_num(sk) \ - sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk)) + sk_num(CHECKED_CAST(const _STACK *, const STACK_OF(X509_ALGOR) *, sk)) #define sk_X509_ALGOR_zero(sk) \ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk)); #define sk_X509_ALGOR_value(sk, i) \ ((X509_ALGOR *)sk_value( \ - CHECKED_CAST(_STACK *, const STACK_OF(X509_ALGOR) *, sk), (i))) + CHECKED_CAST(const _STACK *, const STACK_OF(X509_ALGOR) *, sk), (i))) #define sk_X509_ALGOR_set(sk, i, p) \ ((X509_ALGOR *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk), \ @@ -2331,13 +2447,13 @@ #define sk_X509_ALGOR_dup(sk) \ ((STACK_OF(X509_ALGOR) *)sk_dup( \ - CHECKED_CAST(_STACK *, const STACK_OF(X509_ALGOR) *, sk))) + CHECKED_CAST(const _STACK *, const STACK_OF(X509_ALGOR) *, sk))) #define sk_X509_ALGOR_sort(sk) \ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk)) #define sk_X509_ALGOR_is_sorted(sk) \ - sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_ALGOR) *, sk)) + sk_is_sorted(CHECKED_CAST(const _STACK *, const STACK_OF(X509_ALGOR) *, sk)) #define sk_X509_ALGOR_set_cmp_func(sk, comp) \ ((int (*)(const X509_ALGOR **a, const X509_ALGOR **b))sk_set_cmp_func( \ @@ -2362,14 +2478,15 @@ #define sk_X509_ATTRIBUTE_new_null() ((STACK_OF(X509_ATTRIBUTE) *)sk_new_null()) #define sk_X509_ATTRIBUTE_num(sk) \ - sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk)) + sk_num(CHECKED_CAST(const _STACK *, const STACK_OF(X509_ATTRIBUTE) *, sk)) #define sk_X509_ATTRIBUTE_zero(sk) \ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk)); -#define sk_X509_ATTRIBUTE_value(sk, i) \ - ((X509_ATTRIBUTE *)sk_value( \ - CHECKED_CAST(_STACK *, const STACK_OF(X509_ATTRIBUTE) *, sk), (i))) +#define sk_X509_ATTRIBUTE_value(sk, i) \ + ((X509_ATTRIBUTE *)sk_value( \ + CHECKED_CAST(const _STACK *, const STACK_OF(X509_ATTRIBUTE) *, sk), \ + (i))) #define sk_X509_ATTRIBUTE_set(sk, i, p) \ ((X509_ATTRIBUTE *)sk_set( \ @@ -2415,13 +2532,14 @@ #define sk_X509_ATTRIBUTE_dup(sk) \ ((STACK_OF(X509_ATTRIBUTE) *)sk_dup( \ - CHECKED_CAST(_STACK *, const STACK_OF(X509_ATTRIBUTE) *, sk))) + CHECKED_CAST(const _STACK *, const STACK_OF(X509_ATTRIBUTE) *, sk))) #define sk_X509_ATTRIBUTE_sort(sk) \ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk)) #define sk_X509_ATTRIBUTE_is_sorted(sk) \ - sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_ATTRIBUTE) *, sk)) + sk_is_sorted( \ + CHECKED_CAST(const _STACK *, const STACK_OF(X509_ATTRIBUTE) *, sk)) #define sk_X509_ATTRIBUTE_set_cmp_func(sk, comp) \ ((int (*)(const X509_ATTRIBUTE **a, const X509_ATTRIBUTE **b)) \ @@ -2446,14 +2564,14 @@ #define sk_X509_CRL_new_null() ((STACK_OF(X509_CRL) *)sk_new_null()) #define sk_X509_CRL_num(sk) \ - sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk)) + sk_num(CHECKED_CAST(const _STACK *, const STACK_OF(X509_CRL) *, sk)) #define sk_X509_CRL_zero(sk) \ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk)); #define sk_X509_CRL_value(sk, i) \ ((X509_CRL *)sk_value( \ - CHECKED_CAST(_STACK *, const STACK_OF(X509_CRL) *, sk), (i))) + CHECKED_CAST(const _STACK *, const STACK_OF(X509_CRL) *, sk), (i))) #define sk_X509_CRL_set(sk, i, p) \ ((X509_CRL *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk), (i), \ @@ -2494,13 +2612,13 @@ #define sk_X509_CRL_dup(sk) \ ((STACK_OF(X509_CRL) *)sk_dup( \ - CHECKED_CAST(_STACK *, const STACK_OF(X509_CRL) *, sk))) + CHECKED_CAST(const _STACK *, const STACK_OF(X509_CRL) *, sk))) #define sk_X509_CRL_sort(sk) \ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk)) #define sk_X509_CRL_is_sorted(sk) \ - sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_CRL) *, sk)) + sk_is_sorted(CHECKED_CAST(const _STACK *, const STACK_OF(X509_CRL) *, sk)) #define sk_X509_CRL_set_cmp_func(sk, comp) \ ((int (*)(const X509_CRL **a, const X509_CRL **b))sk_set_cmp_func( \ @@ -2523,14 +2641,15 @@ #define sk_X509_EXTENSION_new_null() ((STACK_OF(X509_EXTENSION) *)sk_new_null()) #define sk_X509_EXTENSION_num(sk) \ - sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk)) + sk_num(CHECKED_CAST(const _STACK *, const STACK_OF(X509_EXTENSION) *, sk)) #define sk_X509_EXTENSION_zero(sk) \ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk)); -#define sk_X509_EXTENSION_value(sk, i) \ - ((X509_EXTENSION *)sk_value( \ - CHECKED_CAST(_STACK *, const STACK_OF(X509_EXTENSION) *, sk), (i))) +#define sk_X509_EXTENSION_value(sk, i) \ + ((X509_EXTENSION *)sk_value( \ + CHECKED_CAST(const _STACK *, const STACK_OF(X509_EXTENSION) *, sk), \ + (i))) #define sk_X509_EXTENSION_set(sk, i, p) \ ((X509_EXTENSION *)sk_set( \ @@ -2576,13 +2695,14 @@ #define sk_X509_EXTENSION_dup(sk) \ ((STACK_OF(X509_EXTENSION) *)sk_dup( \ - CHECKED_CAST(_STACK *, const STACK_OF(X509_EXTENSION) *, sk))) + CHECKED_CAST(const _STACK *, const STACK_OF(X509_EXTENSION) *, sk))) #define sk_X509_EXTENSION_sort(sk) \ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk)) #define sk_X509_EXTENSION_is_sorted(sk) \ - sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_EXTENSION) *, sk)) + sk_is_sorted( \ + CHECKED_CAST(const _STACK *, const STACK_OF(X509_EXTENSION) *, sk)) #define sk_X509_EXTENSION_set_cmp_func(sk, comp) \ ((int (*)(const X509_EXTENSION **a, const X509_EXTENSION **b)) \ @@ -2608,14 +2728,14 @@ #define sk_X509_INFO_new_null() ((STACK_OF(X509_INFO) *)sk_new_null()) #define sk_X509_INFO_num(sk) \ - sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk)) + sk_num(CHECKED_CAST(const _STACK *, const STACK_OF(X509_INFO) *, sk)) #define sk_X509_INFO_zero(sk) \ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk)); #define sk_X509_INFO_value(sk, i) \ ((X509_INFO *)sk_value( \ - CHECKED_CAST(_STACK *, const STACK_OF(X509_INFO) *, sk), (i))) + CHECKED_CAST(const _STACK *, const STACK_OF(X509_INFO) *, sk), (i))) #define sk_X509_INFO_set(sk, i, p) \ ((X509_INFO *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk), (i), \ @@ -2658,13 +2778,13 @@ #define sk_X509_INFO_dup(sk) \ ((STACK_OF(X509_INFO) *)sk_dup( \ - CHECKED_CAST(_STACK *, const STACK_OF(X509_INFO) *, sk))) + CHECKED_CAST(const _STACK *, const STACK_OF(X509_INFO) *, sk))) #define sk_X509_INFO_sort(sk) \ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk)) #define sk_X509_INFO_is_sorted(sk) \ - sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_INFO) *, sk)) + sk_is_sorted(CHECKED_CAST(const _STACK *, const STACK_OF(X509_INFO) *, sk)) #define sk_X509_INFO_set_cmp_func(sk, comp) \ ((int (*)(const X509_INFO **a, const X509_INFO **b))sk_set_cmp_func( \ @@ -2687,14 +2807,14 @@ #define sk_X509_LOOKUP_new_null() ((STACK_OF(X509_LOOKUP) *)sk_new_null()) #define sk_X509_LOOKUP_num(sk) \ - sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk)) + sk_num(CHECKED_CAST(const _STACK *, const STACK_OF(X509_LOOKUP) *, sk)) #define sk_X509_LOOKUP_zero(sk) \ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk)); #define sk_X509_LOOKUP_value(sk, i) \ ((X509_LOOKUP *)sk_value( \ - CHECKED_CAST(_STACK *, const STACK_OF(X509_LOOKUP) *, sk), (i))) + CHECKED_CAST(const _STACK *, const STACK_OF(X509_LOOKUP) *, sk), (i))) #define sk_X509_LOOKUP_set(sk, i, p) \ ((X509_LOOKUP *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk), \ @@ -2737,13 +2857,13 @@ #define sk_X509_LOOKUP_dup(sk) \ ((STACK_OF(X509_LOOKUP) *)sk_dup( \ - CHECKED_CAST(_STACK *, const STACK_OF(X509_LOOKUP) *, sk))) + CHECKED_CAST(const _STACK *, const STACK_OF(X509_LOOKUP) *, sk))) #define sk_X509_LOOKUP_sort(sk) \ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk)) #define sk_X509_LOOKUP_is_sorted(sk) \ - sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_LOOKUP) *, sk)) + sk_is_sorted(CHECKED_CAST(const _STACK *, const STACK_OF(X509_LOOKUP) *, sk)) #define sk_X509_LOOKUP_set_cmp_func(sk, comp) \ ((int (*)(const X509_LOOKUP **a, const X509_LOOKUP **b))sk_set_cmp_func( \ @@ -2768,14 +2888,14 @@ #define sk_X509_NAME_new_null() ((STACK_OF(X509_NAME) *)sk_new_null()) #define sk_X509_NAME_num(sk) \ - sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk)) + sk_num(CHECKED_CAST(const _STACK *, const STACK_OF(X509_NAME) *, sk)) #define sk_X509_NAME_zero(sk) \ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk)); #define sk_X509_NAME_value(sk, i) \ ((X509_NAME *)sk_value( \ - CHECKED_CAST(_STACK *, const STACK_OF(X509_NAME) *, sk), (i))) + CHECKED_CAST(const _STACK *, const STACK_OF(X509_NAME) *, sk), (i))) #define sk_X509_NAME_set(sk, i, p) \ ((X509_NAME *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk), (i), \ @@ -2818,13 +2938,13 @@ #define sk_X509_NAME_dup(sk) \ ((STACK_OF(X509_NAME) *)sk_dup( \ - CHECKED_CAST(_STACK *, const STACK_OF(X509_NAME) *, sk))) + CHECKED_CAST(const _STACK *, const STACK_OF(X509_NAME) *, sk))) #define sk_X509_NAME_sort(sk) \ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk)) #define sk_X509_NAME_is_sorted(sk) \ - sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_NAME) *, sk)) + sk_is_sorted(CHECKED_CAST(const _STACK *, const STACK_OF(X509_NAME) *, sk)) #define sk_X509_NAME_set_cmp_func(sk, comp) \ ((int (*)(const X509_NAME **a, const X509_NAME **b))sk_set_cmp_func( \ @@ -2848,14 +2968,15 @@ ((STACK_OF(X509_NAME_ENTRY) *)sk_new_null()) #define sk_X509_NAME_ENTRY_num(sk) \ - sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk)) + sk_num(CHECKED_CAST(const _STACK *, const STACK_OF(X509_NAME_ENTRY) *, sk)) #define sk_X509_NAME_ENTRY_zero(sk) \ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk)); -#define sk_X509_NAME_ENTRY_value(sk, i) \ - ((X509_NAME_ENTRY *)sk_value( \ - CHECKED_CAST(_STACK *, const STACK_OF(X509_NAME_ENTRY) *, sk), (i))) +#define sk_X509_NAME_ENTRY_value(sk, i) \ + ((X509_NAME_ENTRY *)sk_value( \ + CHECKED_CAST(const _STACK *, const STACK_OF(X509_NAME_ENTRY) *, sk), \ + (i))) #define sk_X509_NAME_ENTRY_set(sk, i, p) \ ((X509_NAME_ENTRY *)sk_set( \ @@ -2901,13 +3022,14 @@ #define sk_X509_NAME_ENTRY_dup(sk) \ ((STACK_OF(X509_NAME_ENTRY) *)sk_dup( \ - CHECKED_CAST(_STACK *, const STACK_OF(X509_NAME_ENTRY) *, sk))) + CHECKED_CAST(const _STACK *, const STACK_OF(X509_NAME_ENTRY) *, sk))) #define sk_X509_NAME_ENTRY_sort(sk) \ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk)) #define sk_X509_NAME_ENTRY_is_sorted(sk) \ - sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_NAME_ENTRY) *, sk)) + sk_is_sorted( \ + CHECKED_CAST(const _STACK *, const STACK_OF(X509_NAME_ENTRY) *, sk)) #define sk_X509_NAME_ENTRY_set_cmp_func(sk, comp) \ ((int (*)(const X509_NAME_ENTRY **a, const X509_NAME_ENTRY **b)) \ @@ -2933,14 +3055,14 @@ #define sk_X509_OBJECT_new_null() ((STACK_OF(X509_OBJECT) *)sk_new_null()) #define sk_X509_OBJECT_num(sk) \ - sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk)) + sk_num(CHECKED_CAST(const _STACK *, const STACK_OF(X509_OBJECT) *, sk)) #define sk_X509_OBJECT_zero(sk) \ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk)); #define sk_X509_OBJECT_value(sk, i) \ ((X509_OBJECT *)sk_value( \ - CHECKED_CAST(_STACK *, const STACK_OF(X509_OBJECT) *, sk), (i))) + CHECKED_CAST(const _STACK *, const STACK_OF(X509_OBJECT) *, sk), (i))) #define sk_X509_OBJECT_set(sk, i, p) \ ((X509_OBJECT *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk), \ @@ -2983,13 +3105,13 @@ #define sk_X509_OBJECT_dup(sk) \ ((STACK_OF(X509_OBJECT) *)sk_dup( \ - CHECKED_CAST(_STACK *, const STACK_OF(X509_OBJECT) *, sk))) + CHECKED_CAST(const _STACK *, const STACK_OF(X509_OBJECT) *, sk))) #define sk_X509_OBJECT_sort(sk) \ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk)) #define sk_X509_OBJECT_is_sorted(sk) \ - sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_OBJECT) *, sk)) + sk_is_sorted(CHECKED_CAST(const _STACK *, const STACK_OF(X509_OBJECT) *, sk)) #define sk_X509_OBJECT_set_cmp_func(sk, comp) \ ((int (*)(const X509_OBJECT **a, const X509_OBJECT **b))sk_set_cmp_func( \ @@ -3015,14 +3137,15 @@ ((STACK_OF(X509_POLICY_DATA) *)sk_new_null()) #define sk_X509_POLICY_DATA_num(sk) \ - sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk)) + sk_num(CHECKED_CAST(const _STACK *, const STACK_OF(X509_POLICY_DATA) *, sk)) #define sk_X509_POLICY_DATA_zero(sk) \ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk)); -#define sk_X509_POLICY_DATA_value(sk, i) \ - ((X509_POLICY_DATA *)sk_value( \ - CHECKED_CAST(_STACK *, const STACK_OF(X509_POLICY_DATA) *, sk), (i))) +#define sk_X509_POLICY_DATA_value(sk, i) \ + ((X509_POLICY_DATA *)sk_value( \ + CHECKED_CAST(const _STACK *, const STACK_OF(X509_POLICY_DATA) *, sk), \ + (i))) #define sk_X509_POLICY_DATA_set(sk, i, p) \ ((X509_POLICY_DATA *)sk_set( \ @@ -3068,13 +3191,14 @@ #define sk_X509_POLICY_DATA_dup(sk) \ ((STACK_OF(X509_POLICY_DATA) *)sk_dup( \ - CHECKED_CAST(_STACK *, const STACK_OF(X509_POLICY_DATA) *, sk))) + CHECKED_CAST(const _STACK *, const STACK_OF(X509_POLICY_DATA) *, sk))) #define sk_X509_POLICY_DATA_sort(sk) \ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk)) #define sk_X509_POLICY_DATA_is_sorted(sk) \ - sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_POLICY_DATA) *, sk)) + sk_is_sorted( \ + CHECKED_CAST(const _STACK *, const STACK_OF(X509_POLICY_DATA) *, sk)) #define sk_X509_POLICY_DATA_set_cmp_func(sk, comp) \ ((int (*)(const X509_POLICY_DATA **a, const X509_POLICY_DATA **b)) \ @@ -3102,14 +3226,15 @@ ((STACK_OF(X509_POLICY_NODE) *)sk_new_null()) #define sk_X509_POLICY_NODE_num(sk) \ - sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk)) + sk_num(CHECKED_CAST(const _STACK *, const STACK_OF(X509_POLICY_NODE) *, sk)) #define sk_X509_POLICY_NODE_zero(sk) \ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk)); -#define sk_X509_POLICY_NODE_value(sk, i) \ - ((X509_POLICY_NODE *)sk_value( \ - CHECKED_CAST(_STACK *, const STACK_OF(X509_POLICY_NODE) *, sk), (i))) +#define sk_X509_POLICY_NODE_value(sk, i) \ + ((X509_POLICY_NODE *)sk_value( \ + CHECKED_CAST(const _STACK *, const STACK_OF(X509_POLICY_NODE) *, sk), \ + (i))) #define sk_X509_POLICY_NODE_set(sk, i, p) \ ((X509_POLICY_NODE *)sk_set( \ @@ -3155,13 +3280,14 @@ #define sk_X509_POLICY_NODE_dup(sk) \ ((STACK_OF(X509_POLICY_NODE) *)sk_dup( \ - CHECKED_CAST(_STACK *, const STACK_OF(X509_POLICY_NODE) *, sk))) + CHECKED_CAST(const _STACK *, const STACK_OF(X509_POLICY_NODE) *, sk))) #define sk_X509_POLICY_NODE_sort(sk) \ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk)) #define sk_X509_POLICY_NODE_is_sorted(sk) \ - sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_POLICY_NODE) *, sk)) + sk_is_sorted( \ + CHECKED_CAST(const _STACK *, const STACK_OF(X509_POLICY_NODE) *, sk)) #define sk_X509_POLICY_NODE_set_cmp_func(sk, comp) \ ((int (*)(const X509_POLICY_NODE **a, const X509_POLICY_NODE **b)) \ @@ -3188,14 +3314,14 @@ #define sk_X509_PURPOSE_new_null() ((STACK_OF(X509_PURPOSE) *)sk_new_null()) #define sk_X509_PURPOSE_num(sk) \ - sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk)) + sk_num(CHECKED_CAST(const _STACK *, const STACK_OF(X509_PURPOSE) *, sk)) #define sk_X509_PURPOSE_zero(sk) \ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk)); #define sk_X509_PURPOSE_value(sk, i) \ ((X509_PURPOSE *)sk_value( \ - CHECKED_CAST(_STACK *, const STACK_OF(X509_PURPOSE) *, sk), (i))) + CHECKED_CAST(const _STACK *, const STACK_OF(X509_PURPOSE) *, sk), (i))) #define sk_X509_PURPOSE_set(sk, i, p) \ ((X509_PURPOSE *)sk_set( \ @@ -3240,13 +3366,13 @@ #define sk_X509_PURPOSE_dup(sk) \ ((STACK_OF(X509_PURPOSE) *)sk_dup( \ - CHECKED_CAST(_STACK *, const STACK_OF(X509_PURPOSE) *, sk))) + CHECKED_CAST(const _STACK *, const STACK_OF(X509_PURPOSE) *, sk))) #define sk_X509_PURPOSE_sort(sk) \ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk)) #define sk_X509_PURPOSE_is_sorted(sk) \ - sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_PURPOSE) *, sk)) + sk_is_sorted(CHECKED_CAST(const _STACK *, const STACK_OF(X509_PURPOSE) *, sk)) #define sk_X509_PURPOSE_set_cmp_func(sk, comp) \ ((int (*)(const X509_PURPOSE **a, const X509_PURPOSE **b))sk_set_cmp_func( \ @@ -3271,14 +3397,14 @@ #define sk_X509_REVOKED_new_null() ((STACK_OF(X509_REVOKED) *)sk_new_null()) #define sk_X509_REVOKED_num(sk) \ - sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk)) + sk_num(CHECKED_CAST(const _STACK *, const STACK_OF(X509_REVOKED) *, sk)) #define sk_X509_REVOKED_zero(sk) \ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk)); #define sk_X509_REVOKED_value(sk, i) \ ((X509_REVOKED *)sk_value( \ - CHECKED_CAST(_STACK *, const STACK_OF(X509_REVOKED) *, sk), (i))) + CHECKED_CAST(const _STACK *, const STACK_OF(X509_REVOKED) *, sk), (i))) #define sk_X509_REVOKED_set(sk, i, p) \ ((X509_REVOKED *)sk_set( \ @@ -3323,13 +3449,13 @@ #define sk_X509_REVOKED_dup(sk) \ ((STACK_OF(X509_REVOKED) *)sk_dup( \ - CHECKED_CAST(_STACK *, const STACK_OF(X509_REVOKED) *, sk))) + CHECKED_CAST(const _STACK *, const STACK_OF(X509_REVOKED) *, sk))) #define sk_X509_REVOKED_sort(sk) \ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk)) #define sk_X509_REVOKED_is_sorted(sk) \ - sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_REVOKED) *, sk)) + sk_is_sorted(CHECKED_CAST(const _STACK *, const STACK_OF(X509_REVOKED) *, sk)) #define sk_X509_REVOKED_set_cmp_func(sk, comp) \ ((int (*)(const X509_REVOKED **a, const X509_REVOKED **b))sk_set_cmp_func( \ @@ -3354,14 +3480,14 @@ #define sk_X509_TRUST_new_null() ((STACK_OF(X509_TRUST) *)sk_new_null()) #define sk_X509_TRUST_num(sk) \ - sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk)) + sk_num(CHECKED_CAST(const _STACK *, const STACK_OF(X509_TRUST) *, sk)) #define sk_X509_TRUST_zero(sk) \ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk)); #define sk_X509_TRUST_value(sk, i) \ ((X509_TRUST *)sk_value( \ - CHECKED_CAST(_STACK *, const STACK_OF(X509_TRUST) *, sk), (i))) + CHECKED_CAST(const _STACK *, const STACK_OF(X509_TRUST) *, sk), (i))) #define sk_X509_TRUST_set(sk, i, p) \ ((X509_TRUST *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk), \ @@ -3404,13 +3530,13 @@ #define sk_X509_TRUST_dup(sk) \ ((STACK_OF(X509_TRUST) *)sk_dup( \ - CHECKED_CAST(_STACK *, const STACK_OF(X509_TRUST) *, sk))) + CHECKED_CAST(const _STACK *, const STACK_OF(X509_TRUST) *, sk))) #define sk_X509_TRUST_sort(sk) \ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk)) #define sk_X509_TRUST_is_sorted(sk) \ - sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_TRUST) *, sk)) + sk_is_sorted(CHECKED_CAST(const _STACK *, const STACK_OF(X509_TRUST) *, sk)) #define sk_X509_TRUST_set_cmp_func(sk, comp) \ ((int (*)(const X509_TRUST **a, const X509_TRUST **b))sk_set_cmp_func( \ @@ -3437,14 +3563,15 @@ ((STACK_OF(X509_VERIFY_PARAM) *)sk_new_null()) #define sk_X509_VERIFY_PARAM_num(sk) \ - sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_VERIFY_PARAM) *, sk)) + sk_num(CHECKED_CAST(const _STACK *, const STACK_OF(X509_VERIFY_PARAM) *, sk)) #define sk_X509_VERIFY_PARAM_zero(sk) \ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_VERIFY_PARAM) *, sk)); -#define sk_X509_VERIFY_PARAM_value(sk, i) \ - ((X509_VERIFY_PARAM *)sk_value( \ - CHECKED_CAST(_STACK *, const STACK_OF(X509_VERIFY_PARAM) *, sk), (i))) +#define sk_X509_VERIFY_PARAM_value(sk, i) \ + ((X509_VERIFY_PARAM *)sk_value( \ + CHECKED_CAST(const _STACK *, const STACK_OF(X509_VERIFY_PARAM) *, sk), \ + (i))) #define sk_X509_VERIFY_PARAM_set(sk, i, p) \ ((X509_VERIFY_PARAM *)sk_set( \ @@ -3490,13 +3617,14 @@ #define sk_X509_VERIFY_PARAM_dup(sk) \ ((STACK_OF(X509_VERIFY_PARAM) *)sk_dup( \ - CHECKED_CAST(_STACK *, const STACK_OF(X509_VERIFY_PARAM) *, sk))) + CHECKED_CAST(const _STACK *, const STACK_OF(X509_VERIFY_PARAM) *, sk))) #define sk_X509_VERIFY_PARAM_sort(sk) \ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_VERIFY_PARAM) *, sk)) #define sk_X509_VERIFY_PARAM_is_sorted(sk) \ - sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_VERIFY_PARAM) *, sk)) + sk_is_sorted( \ + CHECKED_CAST(const _STACK *, const STACK_OF(X509_VERIFY_PARAM) *, sk)) #define sk_X509_VERIFY_PARAM_set_cmp_func(sk, comp) \ ((int (*)(const X509_VERIFY_PARAM **a, const X509_VERIFY_PARAM **b)) \ @@ -3515,21 +3643,23 @@ free_func))) /* void */ -#define sk_void_new(comp) \ - ((STACK_OF(void)*)sk_new(CHECKED_CAST( \ +#define sk_void_new(comp) \ + ((STACK_OF(void) *)sk_new(CHECKED_CAST( \ stack_cmp_func, int (*)(const void **a, const void **b), comp))) -#define sk_void_new_null() ((STACK_OF(void)*)sk_new_null()) +#define sk_void_new_null() ((STACK_OF(void) *)sk_new_null()) -#define sk_void_num(sk) sk_num(CHECKED_CAST(_STACK *, STACK_OF(void) *, sk)) +#define sk_void_num(sk) \ + sk_num(CHECKED_CAST(const _STACK *, const STACK_OF(void) *, sk)) #define sk_void_zero(sk) sk_zero(CHECKED_CAST(_STACK *, STACK_OF(void) *, sk)); -#define sk_void_value(sk, i) \ - ((void *)sk_value(CHECKED_CAST(_STACK *, const STACK_OF(void) *, sk), (i))) +#define sk_void_value(sk, i) \ + ((void *)sk_value(CHECKED_CAST(const _STACK *, const STACK_OF(void) *, sk), \ + (i))) -#define sk_void_set(sk, i, p) \ - ((void *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(void)*, sk), (i), \ +#define sk_void_set(sk, i, p) \ + ((void *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(void) *, sk), (i), \ CHECKED_CAST(void *, void *, p))) #define sk_void_free(sk) sk_free(CHECKED_CAST(_STACK *, STACK_OF(void) *, sk)) @@ -3543,10 +3673,10 @@ CHECKED_CAST(void *, void *, p), (where)) #define sk_void_delete(sk, where) \ - ((void *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(void)*, sk), (where))) + ((void *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(void) *, sk), (where))) -#define sk_void_delete_ptr(sk, p) \ - ((void *)sk_delete_ptr(CHECKED_CAST(_STACK *, STACK_OF(void)*, sk), \ +#define sk_void_delete_ptr(sk, p) \ + ((void *)sk_delete_ptr(CHECKED_CAST(_STACK *, STACK_OF(void) *, sk), \ CHECKED_CAST(void *, void *, p))) #define sk_void_find(sk, out_index, p) \ @@ -3554,31 +3684,32 @@ CHECKED_CAST(void *, void *, p)) #define sk_void_shift(sk) \ - ((void *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(void)*, sk))) + ((void *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(void) *, sk))) #define sk_void_push(sk, p) \ sk_push(CHECKED_CAST(_STACK *, STACK_OF(void) *, sk), \ CHECKED_CAST(void *, void *, p)) #define sk_void_pop(sk) \ - ((void *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(void)*, sk))) + ((void *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(void) *, sk))) -#define sk_void_dup(sk) \ - ((STACK_OF(void)*)sk_dup(CHECKED_CAST(_STACK *, const STACK_OF(void) *, sk))) +#define sk_void_dup(sk) \ + ((STACK_OF(void) *)sk_dup( \ + CHECKED_CAST(const _STACK *, const STACK_OF(void) *, sk))) #define sk_void_sort(sk) sk_sort(CHECKED_CAST(_STACK *, STACK_OF(void) *, sk)) #define sk_void_is_sorted(sk) \ - sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(void) *, sk)) + sk_is_sorted(CHECKED_CAST(const _STACK *, const STACK_OF(void) *, sk)) #define sk_void_set_cmp_func(sk, comp) \ ((int (*)(const void **a, const void **b))sk_set_cmp_func( \ - CHECKED_CAST(_STACK *, STACK_OF(void)*, sk), \ + CHECKED_CAST(_STACK *, STACK_OF(void) *, sk), \ CHECKED_CAST(stack_cmp_func, int (*)(const void **a, const void **b), \ comp))) #define sk_void_deep_copy(sk, copy_func, free_func) \ - ((STACK_OF(void)*)sk_deep_copy( \ + ((STACK_OF(void) *)sk_deep_copy( \ CHECKED_CAST(const _STACK *, const STACK_OF(void) *, sk), \ CHECKED_CAST(void *(*)(void *), void *(*)(void *), copy_func), \ CHECKED_CAST(void (*)(void *), void (*)(void *), free_func))) @@ -3594,14 +3725,16 @@ ((STACK_OF(SRTP_PROTECTION_PROFILE) *)sk_new_null()) #define sk_SRTP_PROTECTION_PROFILE_num(sk) \ - sk_num(CHECKED_CAST(_STACK *, STACK_OF(SRTP_PROTECTION_PROFILE) *, sk)) + sk_num(CHECKED_CAST(const _STACK *, \ + const STACK_OF(SRTP_PROTECTION_PROFILE) *, sk)) #define sk_SRTP_PROTECTION_PROFILE_zero(sk) \ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(SRTP_PROTECTION_PROFILE) *, sk)); -#define sk_SRTP_PROTECTION_PROFILE_value(sk, i) \ - ((const SRTP_PROTECTION_PROFILE *)sk_value( \ - CHECKED_CAST(_STACK *, const STACK_OF(SRTP_PROTECTION_PROFILE) *, sk), \ +#define sk_SRTP_PROTECTION_PROFILE_value(sk, i) \ + ((const SRTP_PROTECTION_PROFILE *)sk_value( \ + CHECKED_CAST(const _STACK *, const STACK_OF(SRTP_PROTECTION_PROFILE) *, \ + sk), \ (i))) #define sk_SRTP_PROTECTION_PROFILE_set(sk, i, p) \ @@ -3649,16 +3782,16 @@ ((const SRTP_PROTECTION_PROFILE *)sk_pop( \ CHECKED_CAST(_STACK *, STACK_OF(SRTP_PROTECTION_PROFILE) *, sk))) -#define sk_SRTP_PROTECTION_PROFILE_dup(sk) \ - ((STACK_OF(SRTP_PROTECTION_PROFILE) *)sk_dup( \ - CHECKED_CAST(_STACK *, const STACK_OF(SRTP_PROTECTION_PROFILE) *, sk))) +#define sk_SRTP_PROTECTION_PROFILE_dup(sk) \ + ((STACK_OF(SRTP_PROTECTION_PROFILE) *)sk_dup(CHECKED_CAST( \ + const _STACK *, const STACK_OF(SRTP_PROTECTION_PROFILE) *, sk))) #define sk_SRTP_PROTECTION_PROFILE_sort(sk) \ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(SRTP_PROTECTION_PROFILE) *, sk)) #define sk_SRTP_PROTECTION_PROFILE_is_sorted(sk) \ - sk_is_sorted( \ - CHECKED_CAST(_STACK *, const STACK_OF(SRTP_PROTECTION_PROFILE) *, sk)) + sk_is_sorted(CHECKED_CAST(const _STACK *, \ + const STACK_OF(SRTP_PROTECTION_PROFILE) *, sk)) #define sk_SRTP_PROTECTION_PROFILE_set_cmp_func(sk, comp) \ ((int (*)(const SRTP_PROTECTION_PROFILE **a, \ @@ -3670,14 +3803,15 @@ const SRTP_PROTECTION_PROFILE **b), \ comp))) -#define sk_SRTP_PROTECTION_PROFILE_deep_copy(sk, copy_func, free_func) \ - ((STACK_OF(SRTP_PROTECTION_PROFILE) *)sk_deep_copy( \ - CHECKED_CAST(const _STACK *, const STACK_OF(SRTP_PROTECTION_PROFILE) *, \ - sk), \ - CHECKED_CAST(void *(*)(void *), const SRTP_PROTECTION_PROFILE *(*)( \ - const SRTP_PROTECTION_PROFILE *), \ - copy_func), \ - CHECKED_CAST(void (*)(void *), \ +#define sk_SRTP_PROTECTION_PROFILE_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(SRTP_PROTECTION_PROFILE) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(SRTP_PROTECTION_PROFILE) *, \ + sk), \ + CHECKED_CAST( \ + void *(*)(void *), \ + const SRTP_PROTECTION_PROFILE *(*)(const SRTP_PROTECTION_PROFILE *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), \ void (*)(const SRTP_PROTECTION_PROFILE *), free_func))) /* SSL_CIPHER */ @@ -3689,14 +3823,14 @@ #define sk_SSL_CIPHER_new_null() ((STACK_OF(SSL_CIPHER) *)sk_new_null()) #define sk_SSL_CIPHER_num(sk) \ - sk_num(CHECKED_CAST(_STACK *, STACK_OF(SSL_CIPHER) *, sk)) + sk_num(CHECKED_CAST(const _STACK *, const STACK_OF(SSL_CIPHER) *, sk)) #define sk_SSL_CIPHER_zero(sk) \ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(SSL_CIPHER) *, sk)); #define sk_SSL_CIPHER_value(sk, i) \ ((const SSL_CIPHER *)sk_value( \ - CHECKED_CAST(_STACK *, const STACK_OF(SSL_CIPHER) *, sk), (i))) + CHECKED_CAST(const _STACK *, const STACK_OF(SSL_CIPHER) *, sk), (i))) #define sk_SSL_CIPHER_set(sk, i, p) \ ((const SSL_CIPHER *)sk_set( \ @@ -3742,13 +3876,13 @@ #define sk_SSL_CIPHER_dup(sk) \ ((STACK_OF(SSL_CIPHER) *)sk_dup( \ - CHECKED_CAST(_STACK *, const STACK_OF(SSL_CIPHER) *, sk))) + CHECKED_CAST(const _STACK *, const STACK_OF(SSL_CIPHER) *, sk))) #define sk_SSL_CIPHER_sort(sk) \ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(SSL_CIPHER) *, sk)) #define sk_SSL_CIPHER_is_sorted(sk) \ - sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(SSL_CIPHER) *, sk)) + sk_is_sorted(CHECKED_CAST(const _STACK *, const STACK_OF(SSL_CIPHER) *, sk)) #define sk_SSL_CIPHER_set_cmp_func(sk, comp) \ ((int (*)(const SSL_CIPHER **a, const SSL_CIPHER **b))sk_set_cmp_func( \ @@ -3774,14 +3908,15 @@ #define sk_OPENSSL_STRING_new_null() ((STACK_OF(OPENSSL_STRING) *)sk_new_null()) #define sk_OPENSSL_STRING_num(sk) \ - sk_num(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_STRING) *, sk)) + sk_num(CHECKED_CAST(const _STACK *, const STACK_OF(OPENSSL_STRING) *, sk)) #define sk_OPENSSL_STRING_zero(sk) \ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_STRING) *, sk)); -#define sk_OPENSSL_STRING_value(sk, i) \ - ((OPENSSL_STRING)sk_value( \ - CHECKED_CAST(_STACK *, const STACK_OF(OPENSSL_STRING) *, sk), (i))) +#define sk_OPENSSL_STRING_value(sk, i) \ + ((OPENSSL_STRING)sk_value( \ + CHECKED_CAST(const _STACK *, const STACK_OF(OPENSSL_STRING) *, sk), \ + (i))) #define sk_OPENSSL_STRING_set(sk, i, p) \ ((OPENSSL_STRING)sk_set( \ @@ -3827,13 +3962,14 @@ #define sk_OPENSSL_STRING_dup(sk) \ ((STACK_OF(OPENSSL_STRING) *)sk_dup( \ - CHECKED_CAST(_STACK *, const STACK_OF(OPENSSL_STRING) *, sk))) + CHECKED_CAST(const _STACK *, const STACK_OF(OPENSSL_STRING) *, sk))) #define sk_OPENSSL_STRING_sort(sk) \ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_STRING) *, sk)) #define sk_OPENSSL_STRING_is_sorted(sk) \ - sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(OPENSSL_STRING) *, sk)) + sk_is_sorted( \ + CHECKED_CAST(const _STACK *, const STACK_OF(OPENSSL_STRING) *, sk)) #define sk_OPENSSL_STRING_set_cmp_func(sk, comp) \ ((int (*)(const OPENSSL_STRING **a, const OPENSSL_STRING **b)) \ @@ -3849,86 +3985,3 @@ CHECKED_CAST(void *(*)(void *), OPENSSL_STRING (*)(OPENSSL_STRING), \ copy_func), \ CHECKED_CAST(void (*)(void *), void (*)(OPENSSL_STRING), free_func))) - -/* OPENSSL_BLOCK */ -#define sk_OPENSSL_BLOCK_new(comp) \ - ((STACK_OF(OPENSSL_BLOCK) *)sk_new(CHECKED_CAST( \ - stack_cmp_func, int (*)(const OPENSSL_BLOCK *a, const OPENSSL_BLOCK *b), \ - comp))) - -#define sk_OPENSSL_BLOCK_new_null() ((STACK_OF(OPENSSL_BLOCK) *)sk_new_null()) - -#define sk_OPENSSL_BLOCK_num(sk) \ - sk_num(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk)) - -#define sk_OPENSSL_BLOCK_zero(sk) \ - sk_zero(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk)); - -#define sk_OPENSSL_BLOCK_value(sk, i) \ - ((OPENSSL_BLOCK)sk_value( \ - CHECKED_CAST(_STACK *, const STACK_OF(OPENSSL_BLOCK) *, sk), (i))) - -#define sk_OPENSSL_BLOCK_set(sk, i, p) \ - ((OPENSSL_BLOCK)sk_set( \ - CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk), (i), \ - CHECKED_CAST(void *, OPENSSL_BLOCK, p))) - -#define sk_OPENSSL_BLOCK_free(sk) \ - sk_free(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk)) - -#define sk_OPENSSL_BLOCK_pop_free(sk, free_func) \ - sk_pop_free( \ - CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk), \ - CHECKED_CAST(void (*)(void *), void (*)(OPENSSL_BLOCK), free_func)) - -#define sk_OPENSSL_BLOCK_insert(sk, p, where) \ - sk_insert(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk), \ - CHECKED_CAST(void *, OPENSSL_BLOCK, p), (where)) - -#define sk_OPENSSL_BLOCK_delete(sk, where) \ - ((OPENSSL_BLOCK)sk_delete( \ - CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk), (where))) - -#define sk_OPENSSL_BLOCK_delete_ptr(sk, p) \ - ((OPENSSL_BLOCK)sk_delete_ptr( \ - CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk), \ - CHECKED_CAST(void *, OPENSSL_BLOCK, p))) - -#define sk_OPENSSL_BLOCK_find(sk, out_index, p) \ - sk_find(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk), (out_index), \ - CHECKED_CAST(void *, OPENSSL_BLOCK, p)) - -#define sk_OPENSSL_BLOCK_shift(sk) \ - ((OPENSSL_BLOCK)sk_shift( \ - CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk))) - -#define sk_OPENSSL_BLOCK_push(sk, p) \ - sk_push(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk), \ - CHECKED_CAST(void *, OPENSSL_BLOCK, p)) - -#define sk_OPENSSL_BLOCK_pop(sk) \ - ((OPENSSL_BLOCK)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk))) - -#define sk_OPENSSL_BLOCK_dup(sk) \ - ((STACK_OF(OPENSSL_BLOCK) *)sk_dup( \ - CHECKED_CAST(_STACK *, const STACK_OF(OPENSSL_BLOCK) *, sk))) - -#define sk_OPENSSL_BLOCK_sort(sk) \ - sk_sort(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk)) - -#define sk_OPENSSL_BLOCK_is_sorted(sk) \ - sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(OPENSSL_BLOCK) *, sk)) - -#define sk_OPENSSL_BLOCK_set_cmp_func(sk, comp) \ - ((int (*)(const OPENSSL_BLOCK **a, const OPENSSL_BLOCK **b))sk_set_cmp_func( \ - CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk), \ - CHECKED_CAST(stack_cmp_func, \ - int (*)(const OPENSSL_BLOCK **a, const OPENSSL_BLOCK **b), \ - comp))) - -#define sk_OPENSSL_BLOCK_deep_copy(sk, copy_func, free_func) \ - ((STACK_OF(OPENSSL_BLOCK) *)sk_deep_copy( \ - CHECKED_CAST(const _STACK *, const STACK_OF(OPENSSL_BLOCK) *, sk), \ - CHECKED_CAST(void *(*)(void *), OPENSSL_BLOCK (*)(OPENSSL_BLOCK), \ - copy_func), \ - CHECKED_CAST(void (*)(void *), void (*)(OPENSSL_BLOCK), free_func))) diff --git a/Sources/BoringSSL/include/openssl/thread.h b/Sources/BoringSSL/include/openssl/thread.h index 568a85833..815148477 100644 --- a/Sources/BoringSSL/include/openssl/thread.h +++ b/Sources/BoringSSL/include/openssl/thread.h @@ -67,14 +67,15 @@ extern "C" { #if defined(OPENSSL_NO_THREADS) -typedef struct crypto_mutex_st {} CRYPTO_MUTEX; +typedef struct crypto_mutex_st { + char padding; /* Empty structs have different sizes in C and C++. */ +} CRYPTO_MUTEX; #elif defined(OPENSSL_WINDOWS) /* CRYPTO_MUTEX can appear in public header files so we really don't want to * pull in windows.h. It's statically asserted that this structure is large - * enough to contain a Windows CRITICAL_SECTION by thread_win.c. */ + * enough to contain a Windows SRWLOCK by thread_win.c. */ typedef union crypto_mutex_st { - double alignment; - uint8_t padding[4*sizeof(void*) + 2*sizeof(int)]; + void *handle; } CRYPTO_MUTEX; #elif defined(__MACH__) && defined(__APPLE__) typedef pthread_rwlock_t CRYPTO_MUTEX; @@ -100,7 +101,11 @@ typedef union crypto_mutex_st { typedef uint32_t CRYPTO_refcount_t; -/* Deprecated functions */ +/* Deprecated functions. + * + * Historically, OpenSSL required callers to provide locking callbacks. + * BoringSSL is thread-safe by default, but some old code calls these functions + * and so no-op implementations are provided. */ /* These defines do nothing but are provided to make old code easier to * compile. */ @@ -122,6 +127,11 @@ OPENSSL_EXPORT void CRYPTO_set_locking_callback( OPENSSL_EXPORT void CRYPTO_set_add_lock_callback(int (*func)( int *num, int amount, int lock_num, const char *file, int line)); +/* CRYPTO_get_locking_callback returns NULL. */ +OPENSSL_EXPORT void (*CRYPTO_get_locking_callback(void))(int mode, int lock_num, + const char *file, + int line); + /* CRYPTO_get_lock_name returns a fixed, dummy string. */ OPENSSL_EXPORT const char *CRYPTO_get_lock_name(int lock_num); @@ -139,14 +149,7 @@ OPENSSL_EXPORT void CRYPTO_THREADID_set_pointer(CRYPTO_THREADID *id, void *ptr); /* CRYPTO_THREADID_current does nothing. */ OPENSSL_EXPORT void CRYPTO_THREADID_current(CRYPTO_THREADID *id); - -/* Private functions. - * - * Some old code calls these functions and so no-op implementations are - * provided. - * - * TODO(fork): cleanup callers and remove. */ - +/* CRYPTO_set_id_callback does nothing. */ OPENSSL_EXPORT void CRYPTO_set_id_callback(unsigned long (*func)(void)); typedef struct { @@ -154,17 +157,32 @@ typedef struct { struct CRYPTO_dynlock_value *data; } CRYPTO_dynlock; +/* CRYPTO_set_dynlock_create_callback does nothing. */ OPENSSL_EXPORT void CRYPTO_set_dynlock_create_callback( struct CRYPTO_dynlock_value *(*dyn_create_function)(const char *file, int line)); +/* CRYPTO_set_dynlock_lock_callback does nothing. */ OPENSSL_EXPORT void CRYPTO_set_dynlock_lock_callback(void (*dyn_lock_function)( int mode, struct CRYPTO_dynlock_value *l, const char *file, int line)); +/* CRYPTO_set_dynlock_destroy_callback does nothing. */ OPENSSL_EXPORT void CRYPTO_set_dynlock_destroy_callback( void (*dyn_destroy_function)(struct CRYPTO_dynlock_value *l, const char *file, int line)); +/* CRYPTO_get_dynlock_create_callback returns NULL. */ +OPENSSL_EXPORT struct CRYPTO_dynlock_value *( + *CRYPTO_get_dynlock_create_callback(void))(const char *file, int line); + +/* CRYPTO_get_dynlock_lock_callback returns NULL. */ +OPENSSL_EXPORT void (*CRYPTO_get_dynlock_lock_callback(void))( + int mode, struct CRYPTO_dynlock_value *l, const char *file, int line); + +/* CRYPTO_get_dynlock_destroy_callback returns NULL. */ +OPENSSL_EXPORT void (*CRYPTO_get_dynlock_destroy_callback(void))( + struct CRYPTO_dynlock_value *l, const char *file, int line); + #if defined(__cplusplus) } /* extern C */ diff --git a/Sources/BoringSSL/include/openssl/time_support.h b/Sources/BoringSSL/include/openssl/time_support.h deleted file mode 100644 index cec430d32..000000000 --- a/Sources/BoringSSL/include/openssl/time_support.h +++ /dev/null @@ -1,90 +0,0 @@ -/* Written by Richard Levitte (richard@levitte.org) for the OpenSSL - * project 2001. - * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL - * project 2008. - */ -/* ==================================================================== - * Copyright (c) 2001 The OpenSSL Project. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the OpenSSL Project - * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" - * - * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to - * endorse or promote products derived from this software without - * prior written permission. For written permission, please contact - * licensing@OpenSSL.org. - * - * 5. Products derived from this software may not be called "OpenSSL" - * nor may "OpenSSL" appear in their names without prior written - * permission of the OpenSSL Project. - * - * 6. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the OpenSSL Project - * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" - * - * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This product includes cryptographic software written by Eric Young - * (eay@cryptsoft.com). This product includes software written by Tim - * Hudson (tjh@cryptsoft.com). */ - -#ifndef OPENSSL_HEADER_TIME_SUPPORT_H -#define OPENSSL_HEADER_TIME_SUPPORT_H - -#include - - -#if defined(__cplusplus) -extern "C" { -#endif - - -/* Wrapper functions for time functions. */ - - -/* OPENSSL_gmtime wraps |gmtime_r|. See the manual page for that function. */ -struct tm *OPENSSL_gmtime(const time_t *timer, struct tm *result); - -/* OPENSSL_gmtime_adj updates |tm| by adding |offset_day| days and |offset_sec| - * seconds. */ -int OPENSSL_gmtime_adj(struct tm *tm, int offset_day, long offset_sec); - -/* OPENSSL_gmtime_diff calculates the difference between |from| and |to| and - * outputs the difference as a number of days and seconds in |*out_days| and - * |*out_secs|. */ -int OPENSSL_gmtime_diff(int *out_days, int *out_secs, const struct tm *from, - const struct tm *to); - - -#if defined(__cplusplus) -} /* extern C */ -#endif - -#endif /* OPENSSL_HEADER_TIME_SUPPORT_H */ diff --git a/Sources/BoringSSL/include/openssl/tls1.h b/Sources/BoringSSL/include/openssl/tls1.h index e0f13997f..260197420 100644 --- a/Sources/BoringSSL/include/openssl/tls1.h +++ b/Sources/BoringSSL/include/openssl/tls1.h @@ -157,61 +157,42 @@ extern "C" { #endif -#define TLS1_ALLOW_EXPERIMENTAL_CIPHERSUITES 0 - +#define TLS1_AD_END_OF_EARLY_DATA 1 #define TLS1_AD_DECRYPTION_FAILED 21 #define TLS1_AD_RECORD_OVERFLOW 22 -#define TLS1_AD_UNKNOWN_CA 48 /* fatal */ -#define TLS1_AD_ACCESS_DENIED 49 /* fatal */ -#define TLS1_AD_DECODE_ERROR 50 /* fatal */ +#define TLS1_AD_UNKNOWN_CA 48 +#define TLS1_AD_ACCESS_DENIED 49 +#define TLS1_AD_DECODE_ERROR 50 #define TLS1_AD_DECRYPT_ERROR 51 -#define TLS1_AD_EXPORT_RESTRICTION 60 /* fatal */ -#define TLS1_AD_PROTOCOL_VERSION 70 /* fatal */ -#define TLS1_AD_INSUFFICIENT_SECURITY 71 /* fatal */ -#define TLS1_AD_INTERNAL_ERROR 80 /* fatal */ +#define TLS1_AD_EXPORT_RESTRICTION 60 +#define TLS1_AD_PROTOCOL_VERSION 70 +#define TLS1_AD_INSUFFICIENT_SECURITY 71 +#define TLS1_AD_INTERNAL_ERROR 80 #define TLS1_AD_USER_CANCELLED 90 #define TLS1_AD_NO_RENEGOTIATION 100 +#define TLS1_AD_MISSING_EXTENSION 109 /* codes 110-114 are from RFC3546 */ #define TLS1_AD_UNSUPPORTED_EXTENSION 110 #define TLS1_AD_CERTIFICATE_UNOBTAINABLE 111 #define TLS1_AD_UNRECOGNIZED_NAME 112 #define TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE 113 #define TLS1_AD_BAD_CERTIFICATE_HASH_VALUE 114 -#define TLS1_AD_UNKNOWN_PSK_IDENTITY 115 /* fatal */ +#define TLS1_AD_UNKNOWN_PSK_IDENTITY 115 +#define TLS1_AD_CERTIFICATE_REQUIRED 116 -/* ExtensionType values from RFC3546 / RFC4366 / RFC6066 */ +/* ExtensionType values from RFC6066 */ #define TLSEXT_TYPE_server_name 0 -#define TLSEXT_TYPE_max_fragment_length 1 -#define TLSEXT_TYPE_client_certificate_url 2 -#define TLSEXT_TYPE_trusted_ca_keys 3 -#define TLSEXT_TYPE_truncated_hmac 4 #define TLSEXT_TYPE_status_request 5 -/* ExtensionType values from RFC4681 */ -#define TLSEXT_TYPE_user_mapping 6 - -/* ExtensionType values from RFC5878 */ -#define TLSEXT_TYPE_client_authz 7 -#define TLSEXT_TYPE_server_authz 8 - -/* ExtensionType values from RFC6091 */ -#define TLSEXT_TYPE_cert_type 9 /* ExtensionType values from RFC4492 */ -#define TLSEXT_TYPE_elliptic_curves 10 #define TLSEXT_TYPE_ec_point_formats 11 -/* ExtensionType value from RFC5054 */ -#define TLSEXT_TYPE_srp 12 - /* ExtensionType values from RFC5246 */ #define TLSEXT_TYPE_signature_algorithms 13 /* ExtensionType value from RFC5764 */ #define TLSEXT_TYPE_srtp 14 -/* ExtensionType value from RFC5620 */ -#define TLSEXT_TYPE_heartbeat 15 - /* ExtensionType value from RFC7301 */ #define TLSEXT_TYPE_application_layer_protocol_negotiation 16 @@ -224,6 +205,16 @@ extern "C" { /* ExtensionType value from RFC4507 */ #define TLSEXT_TYPE_session_ticket 35 +/* ExtensionType values from draft-ietf-tls-tls13-18 */ +#define TLSEXT_TYPE_supported_groups 10 +#define TLSEXT_TYPE_key_share 40 +#define TLSEXT_TYPE_pre_shared_key 41 +#define TLSEXT_TYPE_early_data 42 +#define TLSEXT_TYPE_supported_versions 43 +#define TLSEXT_TYPE_cookie 44 +#define TLSEXT_TYPE_psk_key_exchange_modes 45 +#define TLSEXT_TYPE_ticket_early_data_info 46 + /* ExtensionType value from RFC5746 */ #define TLSEXT_TYPE_renegotiate 0xff01 @@ -236,13 +227,15 @@ extern "C" { /* This is not an IANA defined extension number */ #define TLSEXT_TYPE_channel_id 30032 +/* This is not an IANA defined extension number */ +#define TLSEXT_TYPE_short_header 27463 + /* status request value from RFC 3546 */ #define TLSEXT_STATUSTYPE_ocsp 1 /* ECPointFormat values from RFC 4492 */ #define TLSEXT_ECPOINTFORMAT_uncompressed 0 #define TLSEXT_ECPOINTFORMAT_ansiX962_compressed_prime 1 -#define TLSEXT_ECPOINTFORMAT_ansiX962_compressed_char2 2 /* Signature and hash algorithms from RFC 5246 */ @@ -259,15 +252,6 @@ extern "C" { #define TLSEXT_hash_sha384 5 #define TLSEXT_hash_sha512 6 -/* Flag set for unrecognised algorithms */ -#define TLSEXT_nid_unknown 0x1000000 - -/* ECC curves */ - -#define TLSEXT_curve_P_256 23 -#define TLSEXT_curve_P_384 24 - - #define TLSEXT_MAXLEN_host_name 255 /* PSK ciphersuites from 4279 */ @@ -427,17 +411,15 @@ extern "C" { #define TLS1_CK_ECDH_RSA_WITH_AES_128_GCM_SHA256 0x0300C031 #define TLS1_CK_ECDH_RSA_WITH_AES_256_GCM_SHA384 0x0300C032 -#define TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305_OLD 0x0300CC13 -#define TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305_OLD 0x0300CC14 - +/* ChaCha20-Poly1305 cipher suites from RFC 7905. */ #define TLS1_CK_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 0x0300CCA8 #define TLS1_CK_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 0x0300CCA9 #define TLS1_CK_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256 0x0300CCAC -/* TODO(davidben): Remove this. Historically, the CK names for CHACHA20_POLY1305 - * were missing 'WITH' and 'SHA256'. */ -#define TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305 \ - TLS1_CK_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 +/* TLS 1.3 ciphersuites from draft-ietf-tls-tls13-16 */ +#define TLS1_CK_AES_128_GCM_SHA256 0x03001301 +#define TLS1_CK_AES_256_GCM_SHA384 0x03001302 +#define TLS1_CK_CHACHA20_POLY1305_SHA256 0x03001303 /* XXX * Inconsistency alert: @@ -599,14 +581,6 @@ extern "C" { #define TLS1_TXT_ECDH_RSA_WITH_AES_128_GCM_SHA256 "ECDH-RSA-AES128-GCM-SHA256" #define TLS1_TXT_ECDH_RSA_WITH_AES_256_GCM_SHA384 "ECDH-RSA-AES256-GCM-SHA384" -/* For convenience, the old and new CHACHA20_POLY1305 ciphers have the same - * name. In cipher strings, both will be selected. This is temporary and will be - * removed when the pre-standard construction is removed. */ -#define TLS1_TXT_ECDHE_RSA_WITH_CHACHA20_POLY1305_OLD \ - "ECDHE-RSA-CHACHA20-POLY1305" -#define TLS1_TXT_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_OLD \ - "ECDHE-ECDSA-CHACHA20-POLY1305" - #define TLS1_TXT_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 \ "ECDHE-RSA-CHACHA20-POLY1305" #define TLS1_TXT_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 \ @@ -614,10 +588,11 @@ extern "C" { #define TLS1_TXT_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256 \ "ECDHE-PSK-CHACHA20-POLY1305" -/* TODO(davidben): Remove this. Historically, the TXT names for CHACHA20_POLY1305 - * were missing 'SHA256'. */ -#define TLS1_TXT_ECDHE_RSA_WITH_CHACHA20_POLY1305 \ - TLS1_TXT_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 +/* TLS 1.3 ciphersuites from draft-ietf-tls-tls13-16 */ +#define TLS1_TXT_AES_128_GCM_SHA256 "AEAD-AES128-GCM-SHA256" +#define TLS1_TXT_AES_256_GCM_SHA384 "AEAD-AES256-GCM-SHA384" +#define TLS1_TXT_CHACHA20_POLY1305_SHA256 "AEAD-CHACHA20-POLY1305-SHA256" + #define TLS_CT_RSA_SIGN 1 #define TLS_CT_DSS_SIGN 2 diff --git a/Sources/BoringSSL/include/openssl/type_check.h b/Sources/BoringSSL/include/openssl/type_check.h index 674913a35..7e70918b3 100644 --- a/Sources/BoringSSL/include/openssl/type_check.h +++ b/Sources/BoringSSL/include/openssl/type_check.h @@ -78,6 +78,10 @@ extern "C" { #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L #define OPENSSL_COMPILE_ASSERT(cond, msg) _Static_assert(cond, #msg) +#elif defined(__GNUC__) +#define OPENSSL_COMPILE_ASSERT(cond, msg) \ + typedef char OPENSSL_COMPILE_ASSERT_##msg[((cond) ? 1 : -1)] \ + __attribute__((unused)) #else #define OPENSSL_COMPILE_ASSERT(cond, msg) \ typedef char OPENSSL_COMPILE_ASSERT_##msg[((cond) ? 1 : -1)] diff --git a/Sources/BoringSSL/include/openssl/x509.h b/Sources/BoringSSL/include/openssl/x509.h index a5aaf31b9..88455ddb4 100644 --- a/Sources/BoringSSL/include/openssl/x509.h +++ b/Sources/BoringSSL/include/openssl/x509.h @@ -76,6 +76,8 @@ #include #include #include +#include +#include #include #include #include @@ -242,7 +244,6 @@ struct x509_st X509_CINF *cert_info; X509_ALGOR *sig_alg; ASN1_BIT_STRING *signature; - int valid; CRYPTO_refcount_t references; char *name; CRYPTO_EX_DATA ex_data; @@ -261,6 +262,8 @@ struct x509_st NAME_CONSTRAINTS *nc; unsigned char sha1_hash[SHA_DIGEST_LENGTH]; X509_CERT_AUX *aux; + CRYPTO_BUFFER *buf; + CRYPTO_MUTEX lock; } /* X509 */; DECLARE_STACK_OF(X509) @@ -286,7 +289,7 @@ struct x509_cert_pair_st { /* standard trust ids */ -#define X509_TRUST_DEFAULT -1 /* Only valid in purpose settings */ +#define X509_TRUST_DEFAULT (-1) /* Only valid in purpose settings */ #define X509_TRUST_COMPAT 1 #define X509_TRUST_SSL_CLIENT 2 @@ -506,28 +509,6 @@ typedef struct CBCParameter_st } CBC_PARAM; */ -/* Password based encryption structure */ - -struct PBEPARAM_st { -ASN1_OCTET_STRING *salt; -ASN1_INTEGER *iter; -} /* PBEPARAM */; - -/* Password based encryption V2 structures */ - -struct PBE2PARAM_st { -X509_ALGOR *keyfunc; -X509_ALGOR *encryption; -} /* PBE2PARAM */; - -struct PBKDF2PARAM_st { -ASN1_TYPE *salt; /* Usually OCTET STRING but could be anything */ -ASN1_INTEGER *iter; -ASN1_INTEGER *keylength; -X509_ALGOR *prf; -} /* PBKDF2PARAM */; - - /* PKCS#8 private key info structure */ struct pkcs8_priv_key_info_st @@ -636,6 +617,12 @@ OPENSSL_EXPORT int X509_NAME_digest(const X509_NAME *data,const EVP_MD *type, unsigned char *md, unsigned int *len); #endif +/* X509_parse_from_buffer parses an X.509 structure from |buf| and returns a + * fresh X509 or NULL on error. There must not be any trailing data in |buf|. + * The returned structure (if any) holds a reference to |buf| rather than + * copying parts of it as a normal |d2i_X509| call would do. */ +OPENSSL_EXPORT X509 *X509_parse_from_buffer(CRYPTO_BUFFER *buf); + #ifndef OPENSSL_NO_FP_API OPENSSL_EXPORT X509 *d2i_X509_fp(FILE *fp, X509 **x509); OPENSSL_EXPORT int i2d_X509_fp(FILE *fp,X509 *x509); @@ -781,9 +768,8 @@ DECLARE_ASN1_FUNCTIONS(X509_CERT_AUX) DECLARE_ASN1_FUNCTIONS(X509_CERT_PAIR) -/* X509_up_ref adds one to the reference count of |x| and returns - * |x|. */ -OPENSSL_EXPORT X509 *X509_up_ref(X509 *x); +/* X509_up_ref adds one to the reference count of |x| and returns one. */ +OPENSSL_EXPORT int X509_up_ref(X509 *x); OPENSSL_EXPORT int X509_get_ex_new_index(long argl, void *argp, CRYPTO_EX_unused *unused, CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func); @@ -858,6 +844,7 @@ OPENSSL_EXPORT int X509_set_pubkey(X509 *x, EVP_PKEY *pkey); OPENSSL_EXPORT EVP_PKEY * X509_get_pubkey(X509 *x); OPENSSL_EXPORT ASN1_BIT_STRING * X509_get0_pubkey_bitstr(const X509 *x); OPENSSL_EXPORT int X509_certificate_type(X509 *x,EVP_PKEY *pubkey /* optional */); +OPENSSL_EXPORT STACK_OF(X509_EXTENSION) *X509_get0_extensions(const X509 *x); OPENSSL_EXPORT int X509_REQ_set_version(X509_REQ *x,long version); OPENSSL_EXPORT int X509_REQ_set_subject_name(X509_REQ *req,X509_NAME *name); @@ -893,7 +880,7 @@ OPENSSL_EXPORT int X509_CRL_set_issuer_name(X509_CRL *x, X509_NAME *name); OPENSSL_EXPORT int X509_CRL_set_lastUpdate(X509_CRL *x, const ASN1_TIME *tm); OPENSSL_EXPORT int X509_CRL_set_nextUpdate(X509_CRL *x, const ASN1_TIME *tm); OPENSSL_EXPORT int X509_CRL_sort(X509_CRL *crl); -OPENSSL_EXPORT void X509_CRL_up_ref(X509_CRL *crl); +OPENSSL_EXPORT int X509_CRL_up_ref(X509_CRL *crl); OPENSSL_EXPORT int X509_REVOKED_set_serialNumber(X509_REVOKED *x, ASN1_INTEGER *serial); OPENSSL_EXPORT int X509_REVOKED_set_revocationDate(X509_REVOKED *r, ASN1_TIME *tm); @@ -1074,24 +1061,6 @@ OPENSSL_EXPORT int X509_ATTRIBUTE_count(X509_ATTRIBUTE *attr); OPENSSL_EXPORT ASN1_OBJECT *X509_ATTRIBUTE_get0_object(X509_ATTRIBUTE *attr); OPENSSL_EXPORT ASN1_TYPE *X509_ATTRIBUTE_get0_type(X509_ATTRIBUTE *attr, int idx); -OPENSSL_EXPORT int EVP_PKEY_get_attr_count(const EVP_PKEY *key); -OPENSSL_EXPORT int EVP_PKEY_get_attr_by_NID(const EVP_PKEY *key, int nid, - int lastpos); -OPENSSL_EXPORT int EVP_PKEY_get_attr_by_OBJ(const EVP_PKEY *key, ASN1_OBJECT *obj, - int lastpos); -OPENSSL_EXPORT X509_ATTRIBUTE *EVP_PKEY_get_attr(const EVP_PKEY *key, int loc); -OPENSSL_EXPORT X509_ATTRIBUTE *EVP_PKEY_delete_attr(EVP_PKEY *key, int loc); -OPENSSL_EXPORT int EVP_PKEY_add1_attr(EVP_PKEY *key, X509_ATTRIBUTE *attr); -OPENSSL_EXPORT int EVP_PKEY_add1_attr_by_OBJ(EVP_PKEY *key, - const ASN1_OBJECT *obj, int type, - const unsigned char *bytes, int len); -OPENSSL_EXPORT int EVP_PKEY_add1_attr_by_NID(EVP_PKEY *key, - int nid, int type, - const unsigned char *bytes, int len); -OPENSSL_EXPORT int EVP_PKEY_add1_attr_by_txt(EVP_PKEY *key, - const char *attrname, int type, - const unsigned char *bytes, int len); - OPENSSL_EXPORT int X509_verify_cert(X509_STORE_CTX *ctx); /* lookup a cert from a X509 STACK */ @@ -1099,24 +1068,6 @@ OPENSSL_EXPORT X509 *X509_find_by_issuer_and_serial(STACK_OF(X509) *sk,X509_NAME ASN1_INTEGER *serial); OPENSSL_EXPORT X509 *X509_find_by_subject(STACK_OF(X509) *sk,X509_NAME *name); -DECLARE_ASN1_FUNCTIONS(PBEPARAM) -DECLARE_ASN1_FUNCTIONS(PBE2PARAM) -DECLARE_ASN1_FUNCTIONS(PBKDF2PARAM) - -OPENSSL_EXPORT int PKCS5_pbe_set0_algor(X509_ALGOR *algor, int alg, int iter, - const unsigned char *salt, int saltlen); - -OPENSSL_EXPORT X509_ALGOR *PKCS5_pbe_set(int alg, int iter, - const unsigned char *salt, int saltlen); -OPENSSL_EXPORT X509_ALGOR *PKCS5_pbe2_set(const EVP_CIPHER *cipher, int iter, - unsigned char *salt, int saltlen); -OPENSSL_EXPORT X509_ALGOR *PKCS5_pbe2_set_iv(const EVP_CIPHER *cipher, int iter, - unsigned char *salt, int saltlen, - unsigned char *aiv, int prf_nid); - -OPENSSL_EXPORT X509_ALGOR *PKCS5_pbkdf2_set(int iter, unsigned char *salt, int saltlen, - int prf_nid, int keylen); - /* PKCS#8 utilities */ DECLARE_ASN1_FUNCTIONS(PKCS8_PRIV_KEY_INFO) @@ -1153,6 +1104,17 @@ OPENSSL_EXPORT int X509_TRUST_get_flags(X509_TRUST *xp); OPENSSL_EXPORT char *X509_TRUST_get0_name(X509_TRUST *xp); OPENSSL_EXPORT int X509_TRUST_get_trust(X509_TRUST *xp); + +typedef struct rsa_pss_params_st { + X509_ALGOR *hashAlgorithm; + X509_ALGOR *maskGenAlgorithm; + ASN1_INTEGER *saltLength; + ASN1_INTEGER *trailerField; +} RSA_PSS_PARAMS; + +DECLARE_ASN1_FUNCTIONS(RSA_PSS_PARAMS) + + /* PKCS7_get_certificates parses a PKCS#7, SignedData structure from |cbs| and * appends the included certificates to |out_certs|. It returns one on success * and zero on error. */ @@ -1213,6 +1175,39 @@ OPENSSL_EXPORT int PKCS7_get_PEM_CRLs(STACK_OF(X509_CRL) *out_crls, #ifdef __cplusplus } + +extern "C++" { + +namespace bssl { + +BORINGSSL_MAKE_STACK_DELETER(X509, X509_free) +BORINGSSL_MAKE_STACK_DELETER(X509_CRL, X509_CRL_free) +BORINGSSL_MAKE_STACK_DELETER(X509_EXTENSION, X509_EXTENSION_free) +BORINGSSL_MAKE_STACK_DELETER(X509_NAME, X509_NAME_free) + +BORINGSSL_MAKE_DELETER(NETSCAPE_SPKI, NETSCAPE_SPKI_free) +BORINGSSL_MAKE_DELETER(X509, X509_free) +BORINGSSL_MAKE_DELETER(X509_ALGOR, X509_ALGOR_free) +BORINGSSL_MAKE_DELETER(X509_CRL, X509_CRL_free) +BORINGSSL_MAKE_DELETER(X509_CRL_METHOD, X509_CRL_METHOD_free) +BORINGSSL_MAKE_DELETER(X509_EXTENSION, X509_EXTENSION_free) +BORINGSSL_MAKE_DELETER(X509_INFO, X509_INFO_free) +BORINGSSL_MAKE_DELETER(X509_LOOKUP, X509_LOOKUP_free) +BORINGSSL_MAKE_DELETER(X509_NAME, X509_NAME_free) +BORINGSSL_MAKE_DELETER(X509_NAME_ENTRY, X509_NAME_ENTRY_free) +BORINGSSL_MAKE_DELETER(X509_PKEY, X509_PKEY_free) +BORINGSSL_MAKE_DELETER(X509_POLICY_TREE, X509_policy_tree_free) +BORINGSSL_MAKE_DELETER(X509_REQ, X509_REQ_free) +BORINGSSL_MAKE_DELETER(X509_REVOKED, X509_REVOKED_free) +BORINGSSL_MAKE_DELETER(X509_SIG, X509_SIG_free) +BORINGSSL_MAKE_DELETER(X509_STORE, X509_STORE_free) +BORINGSSL_MAKE_DELETER(X509_STORE_CTX, X509_STORE_CTX_free) +BORINGSSL_MAKE_DELETER(X509_VERIFY_PARAM, X509_VERIFY_PARAM_free) + +} // namespace bssl + +} /* extern C++ */ + #endif #define X509_R_AKID_MISMATCH 100 @@ -1227,30 +1222,29 @@ OPENSSL_EXPORT int PKCS7_get_PEM_CRLs(STACK_OF(X509_CRL) *out_crls, #define X509_R_INVALID_BIT_STRING_BITS_LEFT 109 #define X509_R_INVALID_DIRECTORY 110 #define X509_R_INVALID_FIELD_NAME 111 -#define X509_R_INVALID_TRUST 112 -#define X509_R_ISSUER_MISMATCH 113 -#define X509_R_KEY_TYPE_MISMATCH 114 -#define X509_R_KEY_VALUES_MISMATCH 115 -#define X509_R_LOADING_CERT_DIR 116 -#define X509_R_LOADING_DEFAULTS 117 -#define X509_R_METHOD_NOT_SUPPORTED 118 +#define X509_R_INVALID_PSS_PARAMETERS 112 +#define X509_R_INVALID_TRUST 113 +#define X509_R_ISSUER_MISMATCH 114 +#define X509_R_KEY_TYPE_MISMATCH 115 +#define X509_R_KEY_VALUES_MISMATCH 116 +#define X509_R_LOADING_CERT_DIR 117 +#define X509_R_LOADING_DEFAULTS 118 #define X509_R_NEWER_CRL_NOT_NEWER 119 #define X509_R_NOT_PKCS7_SIGNED_DATA 120 #define X509_R_NO_CERTIFICATES_INCLUDED 121 #define X509_R_NO_CERT_SET_FOR_US_TO_VERIFY 122 -#define X509_R_NO_CRL_NUMBER 123 -#define X509_R_PUBLIC_KEY_DECODE_ERROR 124 -#define X509_R_PUBLIC_KEY_ENCODE_ERROR 125 -#define X509_R_SHOULD_RETRY 126 -#define X509_R_UNABLE_TO_FIND_PARAMETERS_IN_CHAIN 127 -#define X509_R_UNABLE_TO_GET_CERTS_PUBLIC_KEY 128 -#define X509_R_UNKNOWN_KEY_TYPE 129 -#define X509_R_UNKNOWN_NID 130 -#define X509_R_UNKNOWN_PURPOSE_ID 131 -#define X509_R_UNKNOWN_TRUST_ID 132 -#define X509_R_UNSUPPORTED_ALGORITHM 133 -#define X509_R_WRONG_LOOKUP_TYPE 134 -#define X509_R_WRONG_TYPE 135 -#define X509_R_NO_CRLS_INCLUDED 136 +#define X509_R_NO_CRLS_INCLUDED 123 +#define X509_R_NO_CRL_NUMBER 124 +#define X509_R_PUBLIC_KEY_DECODE_ERROR 125 +#define X509_R_PUBLIC_KEY_ENCODE_ERROR 126 +#define X509_R_SHOULD_RETRY 127 +#define X509_R_UNKNOWN_KEY_TYPE 128 +#define X509_R_UNKNOWN_NID 129 +#define X509_R_UNKNOWN_PURPOSE_ID 130 +#define X509_R_UNKNOWN_TRUST_ID 131 +#define X509_R_UNSUPPORTED_ALGORITHM 132 +#define X509_R_WRONG_LOOKUP_TYPE 133 +#define X509_R_WRONG_TYPE 134 +#define X509_R_NAME_TOO_LONG 135 #endif diff --git a/Sources/BoringSSL/include/openssl/x509_vfy.h b/Sources/BoringSSL/include/openssl/x509_vfy.h index bd7ded760..f069cb2ce 100644 --- a/Sources/BoringSSL/include/openssl/x509_vfy.h +++ b/Sources/BoringSSL/include/openssl/x509_vfy.h @@ -109,8 +109,10 @@ The X509_STORE then calls a function to actually verify the certificate chain. */ -#define X509_LU_RETRY -1 +/* The following are legacy constants that should not be used. */ +#define X509_LU_RETRY (-1) #define X509_LU_FAIL 0 + #define X509_LU_X509 1 #define X509_LU_CRL 2 #define X509_LU_PKEY 3 @@ -127,8 +129,6 @@ typedef struct x509_object_st } data; } X509_OBJECT; -typedef struct x509_lookup_st X509_LOOKUP; - DECLARE_STACK_OF(X509_LOOKUP) DECLARE_STACK_OF(X509_OBJECT) @@ -160,7 +160,7 @@ typedef struct X509_VERIFY_PARAM_ID_st X509_VERIFY_PARAM_ID; * parameters used can be customized */ -typedef struct X509_VERIFY_PARAM_st +struct X509_VERIFY_PARAM_st { char *name; time_t check_time; /* Time to use */ @@ -171,7 +171,7 @@ typedef struct X509_VERIFY_PARAM_st int depth; /* Verify depth */ STACK_OF(ASN1_OBJECT) *policies; /* Permissible policies */ X509_VERIFY_PARAM_ID *id; /* opaque ID data */ - } X509_VERIFY_PARAM; + }; DECLARE_STACK_OF(X509_VERIFY_PARAM) @@ -184,6 +184,7 @@ struct x509_store_st int cache; /* if true, stash any hits */ STACK_OF(X509_OBJECT) *objs; /* Cache of all objects */ CRYPTO_MUTEX objs_lock; + STACK_OF(X509) *additional_untrusted; /* These are external lookup methods */ STACK_OF(X509_LOOKUP) *get_cert_methods; @@ -228,7 +229,6 @@ struct x509_lookup_st struct x509_store_ctx_st /* X509_STORE_CTX */ { X509_STORE *ctx; - int current_method; /* used when looking up certs */ /* The following are set by the caller */ X509 *cert; /* The cert to check */ @@ -292,7 +292,7 @@ OPENSSL_EXPORT void X509_STORE_CTX_set_depth(X509_STORE_CTX *ctx, int depth); X509_LOOKUP_ctrl((x),X509_L_ADD_DIR,(name),(long)(type),NULL) #define X509_V_OK 0 -/* illegal error (for uninitialized values, to avoid X509_V_OK): 1 */ +#define X509_V_ERR_UNSPECIFIED 1 #define X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT 2 #define X509_V_ERR_UNABLE_TO_GET_CRL 3 @@ -347,6 +347,7 @@ OPENSSL_EXPORT void X509_STORE_CTX_set_depth(X509_STORE_CTX *ctx, int depth); #define X509_V_ERR_PERMITTED_VIOLATION 47 #define X509_V_ERR_EXCLUDED_VIOLATION 48 #define X509_V_ERR_SUBTREE_MINMAX 49 +#define X509_V_ERR_APPLICATION_VERIFICATION 50 #define X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE 51 #define X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX 52 #define X509_V_ERR_UNSUPPORTED_NAME_SYNTAX 53 @@ -365,8 +366,10 @@ OPENSSL_EXPORT void X509_STORE_CTX_set_depth(X509_STORE_CTX *ctx, int depth); #define X509_V_ERR_EMAIL_MISMATCH 63 #define X509_V_ERR_IP_ADDRESS_MISMATCH 64 -/* The application is not happy */ -#define X509_V_ERR_APPLICATION_VERIFICATION 50 +/* Caller error */ +#define X509_V_ERR_INVALID_CALL 65 +/* Issuer lookup error */ +#define X509_V_ERR_STORE_LOOKUP 66 /* Certificate verify flags */ @@ -433,9 +436,10 @@ OPENSSL_EXPORT int X509_OBJECT_idx_by_subject(STACK_OF(X509_OBJECT) *h, int type X509_NAME *name); OPENSSL_EXPORT X509_OBJECT *X509_OBJECT_retrieve_by_subject(STACK_OF(X509_OBJECT) *h,int type,X509_NAME *name); OPENSSL_EXPORT X509_OBJECT *X509_OBJECT_retrieve_match(STACK_OF(X509_OBJECT) *h, X509_OBJECT *x); -OPENSSL_EXPORT void X509_OBJECT_up_ref_count(X509_OBJECT *a); +OPENSSL_EXPORT int X509_OBJECT_up_ref_count(X509_OBJECT *a); OPENSSL_EXPORT void X509_OBJECT_free_contents(X509_OBJECT *a); OPENSSL_EXPORT X509_STORE *X509_STORE_new(void ); +OPENSSL_EXPORT int X509_STORE_up_ref(X509_STORE *store); OPENSSL_EXPORT void X509_STORE_free(X509_STORE *v); OPENSSL_EXPORT STACK_OF(X509)* X509_STORE_get1_certs(X509_STORE_CTX *st, X509_NAME *nm); @@ -444,6 +448,11 @@ OPENSSL_EXPORT int X509_STORE_set_flags(X509_STORE *ctx, unsigned long flags); OPENSSL_EXPORT int X509_STORE_set_purpose(X509_STORE *ctx, int purpose); OPENSSL_EXPORT int X509_STORE_set_trust(X509_STORE *ctx, int trust); OPENSSL_EXPORT int X509_STORE_set1_param(X509_STORE *ctx, X509_VERIFY_PARAM *pm); +/* X509_STORE_set0_additional_untrusted sets a stack of additional, untrusted + * certificates that are available for chain building. This function does not + * take ownership of the stack. */ +OPENSSL_EXPORT void X509_STORE_set0_additional_untrusted( + X509_STORE *ctx, STACK_OF(X509) *untrusted); OPENSSL_EXPORT void X509_STORE_set_verify_cb(X509_STORE *ctx, int (*verify_cb)(int, X509_STORE_CTX *)); @@ -613,4 +622,3 @@ OPENSSL_EXPORT const X509_POLICY_NODE * } #endif #endif - diff --git a/Sources/BoringSSL/include/openssl/x509v3.h b/Sources/BoringSSL/include/openssl/x509v3.h index b7b8ba716..4754f71bf 100644 --- a/Sources/BoringSSL/include/openssl/x509v3.h +++ b/Sources/BoringSSL/include/openssl/x509v3.h @@ -146,10 +146,10 @@ DECLARE_STACK_OF(X509V3_EXT_METHOD) typedef BIT_STRING_BITNAME ENUMERATED_NAMES; -typedef struct BASIC_CONSTRAINTS_st { +struct BASIC_CONSTRAINTS_st { int ca; ASN1_INTEGER *pathlen; -} BASIC_CONSTRAINTS; +}; typedef struct PKEY_USAGE_PERIOD_st { @@ -230,7 +230,7 @@ X509_NAME *dpname; /* All existing reasons */ #define CRLDP_ALL_REASONS 0x807f -#define CRL_REASON_NONE -1 +#define CRL_REASON_NONE (-1) #define CRL_REASON_UNSPECIFIED 0 #define CRL_REASON_KEY_COMPROMISE 1 #define CRL_REASON_CA_COMPROMISE 2 @@ -376,8 +376,8 @@ struct ISSUING_DIST_POINT_st /* onlysomereasons present */ #define IDP_REASONS 0x40 -#define X509V3_conf_err(val) ERR_add_error_data(6, "section:", val->section, \ -",name:", val->name, ",value:", val->value); +#define X509V3_conf_err(val) ERR_add_error_data(6, "section:", (val)->section, \ +",name:", (val)->name, ",value:", (val)->value); #define X509V3_set_ctx_test(ctx) \ X509V3_set_ctx(ctx, NULL, NULL, NULL, NULL, CTX_TEST) @@ -389,7 +389,7 @@ struct ISSUING_DIST_POINT_st (X509V3_EXT_I2V)i2v_ASN1_BIT_STRING, \ (X509V3_EXT_V2I)v2i_ASN1_BIT_STRING, \ NULL, NULL, \ - (void *)table} + (void *)(table)} #define EXT_IA5STRING(nid) { nid, 0, ASN1_ITEM_ref(ASN1_IA5STRING), \ 0,0,0,0, \ @@ -600,6 +600,7 @@ OPENSSL_EXPORT GENERAL_NAME *v2i_GENERAL_NAME_ex(GENERAL_NAME *out, X509V3_CTX *ctx, CONF_VALUE *cnf, int is_nc); OPENSSL_EXPORT void X509V3_conf_free(CONF_VALUE *val); +OPENSSL_EXPORT X509_EXTENSION *X509V3_EXT_conf_nid(LHASH_OF(CONF_VALUE) *conf, X509V3_CTX *ctx, int ext_nid, char *value); OPENSSL_EXPORT X509_EXTENSION *X509V3_EXT_nconf_nid(CONF *conf, X509V3_CTX *ctx, int ext_nid, char *value); OPENSSL_EXPORT X509_EXTENSION *X509V3_EXT_nconf(CONF *conf, X509V3_CTX *ctx, char *name, char *value); OPENSSL_EXPORT int X509V3_EXT_add_nconf_sk(CONF *conf, X509V3_CTX *ctx, char *section, STACK_OF(X509_EXTENSION) **sk); @@ -646,6 +647,7 @@ OPENSSL_EXPORT int X509V3_add_standard_extensions(void); OPENSSL_EXPORT STACK_OF(CONF_VALUE) *X509V3_parse_list(const char *line); OPENSSL_EXPORT void *X509V3_EXT_d2i(X509_EXTENSION *ext); OPENSSL_EXPORT void *X509V3_get_d2i(STACK_OF(X509_EXTENSION) *x, int nid, int *crit, int *idx); +OPENSSL_EXPORT int X509V3_EXT_free(int nid, void *ext_data); OPENSSL_EXPORT X509_EXTENSION *X509V3_EXT_i2d(int ext_nid, int crit, void *ext_struc); @@ -730,7 +732,26 @@ void ERR_load_X509V3_strings(void); #ifdef __cplusplus } + +extern "C++" { + +namespace bssl { + +BORINGSSL_MAKE_STACK_DELETER(DIST_POINT, DIST_POINT_free) +BORINGSSL_MAKE_STACK_DELETER(GENERAL_NAME, GENERAL_NAME_free) +// A STACK_OF(POLICYINFO) is also known as a CERTIFICATEPOLICIES. +BORINGSSL_MAKE_STACK_DELETER(POLICYINFO, POLICYINFO_free) + +BORINGSSL_MAKE_DELETER(AUTHORITY_KEYID, AUTHORITY_KEYID_free) +BORINGSSL_MAKE_DELETER(BASIC_CONSTRAINTS, BASIC_CONSTRAINTS_free) +BORINGSSL_MAKE_DELETER(DIST_POINT, DIST_POINT_free) +BORINGSSL_MAKE_DELETER(GENERAL_NAME, GENERAL_NAME_free) + +} // namespace bssl + +} /* extern C++ */ #endif + #define X509V3_R_BAD_IP_ADDRESS 100 #define X509V3_R_BAD_OBJECT 101 #define X509V3_R_BN_DEC2BN_ERROR 102 diff --git a/Sources/BoringSSL/ssl/bio_ssl.c b/Sources/BoringSSL/ssl/bio_ssl.c new file mode 100644 index 000000000..ad8f5d8ff --- /dev/null +++ b/Sources/BoringSSL/ssl/bio_ssl.c @@ -0,0 +1,175 @@ +/* + * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include + +#include + + +static int ssl_read(BIO *bio, char *out, int outl) { + SSL *ssl = bio->ptr; + if (ssl == NULL) { + return 0; + } + + BIO_clear_retry_flags(bio); + + const int ret = SSL_read(ssl, out, outl); + + switch (SSL_get_error(ssl, ret)) { + case SSL_ERROR_WANT_READ: + BIO_set_retry_read(bio); + break; + + case SSL_ERROR_WANT_WRITE: + BIO_set_retry_write(bio); + break; + + case SSL_ERROR_WANT_ACCEPT: + BIO_set_retry_special(bio); + bio->retry_reason = BIO_RR_ACCEPT; + break; + + case SSL_ERROR_WANT_CONNECT: + BIO_set_retry_special(bio); + bio->retry_reason = BIO_RR_CONNECT; + break; + + case SSL_ERROR_NONE: + case SSL_ERROR_SYSCALL: + case SSL_ERROR_SSL: + case SSL_ERROR_ZERO_RETURN: + default: + break; + } + + return ret; +} + +static int ssl_write(BIO *bio, const char *out, int outl) { + SSL *ssl = bio->ptr; + if (ssl == NULL) { + return 0; + } + + BIO_clear_retry_flags(bio); + + const int ret = SSL_write(ssl, out, outl); + + switch (SSL_get_error(ssl, ret)) { + case SSL_ERROR_WANT_WRITE: + BIO_set_retry_write(bio); + break; + + case SSL_ERROR_WANT_READ: + BIO_set_retry_read(bio); + break; + + case SSL_ERROR_WANT_CONNECT: + BIO_set_retry_special(bio); + bio->retry_reason = BIO_RR_CONNECT; + break; + + case SSL_ERROR_NONE: + case SSL_ERROR_SYSCALL: + case SSL_ERROR_SSL: + default: + break; + } + + return ret; +} + +static long ssl_ctrl(BIO *bio, int cmd, long num, void *ptr) { + SSL *ssl = bio->ptr; + if (ssl == NULL && cmd != BIO_C_SET_SSL) { + return 0; + } + + switch (cmd) { + case BIO_C_SET_SSL: + bio->shutdown = num; + bio->ptr = ptr; + bio->init = 1; + return 1; + + case BIO_CTRL_GET_CLOSE: + return bio->shutdown; + + case BIO_CTRL_SET_CLOSE: + bio->shutdown = num; + return 1; + + case BIO_CTRL_WPENDING: + return BIO_ctrl(SSL_get_wbio(ssl), cmd, num, ptr); + + case BIO_CTRL_PENDING: + return SSL_pending(ssl); + + case BIO_CTRL_FLUSH: { + BIO_clear_retry_flags(bio); + long ret = BIO_ctrl(SSL_get_wbio(ssl), cmd, num, ptr); + BIO_copy_next_retry(bio); + return ret; + } + + case BIO_CTRL_PUSH: + case BIO_CTRL_POP: + case BIO_CTRL_DUP: + return -1; + + default: + return BIO_ctrl(SSL_get_rbio(ssl), cmd, num, ptr); + } +} + +static int ssl_new(BIO *bio) { + return 1; +} + +static int ssl_free(BIO *bio) { + SSL *ssl = bio->ptr; + + if (ssl == NULL) { + return 1; + } + + SSL_shutdown(ssl); + if (bio->shutdown) { + SSL_free(ssl); + } + + return 1; +} + +static long ssl_callback_ctrl(BIO *bio, int cmd, bio_info_cb fp) { + SSL *ssl = bio->ptr; + if (ssl == NULL) { + return 0; + } + + switch (cmd) { + case BIO_CTRL_SET_CALLBACK: + return -1; + + default: + return BIO_callback_ctrl(SSL_get_rbio(ssl), cmd, fp); + } +} + +static const BIO_METHOD ssl_method = { + BIO_TYPE_SSL, "SSL", ssl_write, ssl_read, NULL, + NULL, ssl_ctrl, ssl_new, ssl_free, ssl_callback_ctrl, +}; + +const BIO_METHOD *BIO_f_ssl(void) { return &ssl_method; } + +long BIO_set_ssl(BIO *bio, SSL *ssl, int take_owership) { + return BIO_ctrl(bio, BIO_C_SET_SSL, take_owership, ssl); +} diff --git a/Sources/BoringSSL/ssl/custom_extensions.c b/Sources/BoringSSL/ssl/custom_extensions.c index c94543d88..10fbfc8f0 100644 --- a/Sources/BoringSSL/ssl/custom_extensions.c +++ b/Sources/BoringSSL/ssl/custom_extensions.c @@ -32,8 +32,7 @@ void SSL_CUSTOM_EXTENSION_free(SSL_CUSTOM_EXTENSION *custom_extension) { static const SSL_CUSTOM_EXTENSION *custom_ext_find( STACK_OF(SSL_CUSTOM_EXTENSION) *stack, unsigned *out_index, uint16_t value) { - size_t i; - for (i = 0; i < sk_SSL_CUSTOM_EXTENSION_num(stack); i++) { + for (size_t i = 0; i < sk_SSL_CUSTOM_EXTENSION_num(stack); i++) { const SSL_CUSTOM_EXTENSION *ext = sk_SSL_CUSTOM_EXTENSION_value(stack, i); if (ext->value == value) { if (out_index != NULL) { @@ -59,7 +58,8 @@ static int default_add_callback(SSL *ssl, unsigned extension_value, return 1; } -static int custom_ext_add_hello(SSL *ssl, CBB *extensions) { +static int custom_ext_add_hello(SSL_HANDSHAKE *hs, CBB *extensions) { + SSL *const ssl = hs->ssl; STACK_OF(SSL_CUSTOM_EXTENSION) *stack = ssl->ctx->client_custom_extensions; if (ssl->server) { stack = ssl->ctx->server_custom_extensions; @@ -69,12 +69,11 @@ static int custom_ext_add_hello(SSL *ssl, CBB *extensions) { return 1; } - size_t i; - for (i = 0; i < sk_SSL_CUSTOM_EXTENSION_num(stack); i++) { + for (size_t i = 0; i < sk_SSL_CUSTOM_EXTENSION_num(stack); i++) { const SSL_CUSTOM_EXTENSION *ext = sk_SSL_CUSTOM_EXTENSION_value(stack, i); if (ssl->server && - !(ssl->s3->tmp.custom_extensions.received & (1u << i))) { + !(hs->custom_extensions.received & (1u << i))) { /* Servers cannot echo extensions that the client didn't send. */ continue; } @@ -92,7 +91,7 @@ static int custom_ext_add_hello(SSL *ssl, CBB *extensions) { !CBB_add_bytes(&contents_cbb, contents, contents_len) || !CBB_flush(extensions)) { OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - ERR_add_error_dataf("extension: %u", (unsigned) ext->value); + ERR_add_error_dataf("extension %u", (unsigned) ext->value); if (ext->free_callback && 0 < contents_len) { ext->free_callback(ssl, ext->value, contents, ext->add_arg); } @@ -104,8 +103,8 @@ static int custom_ext_add_hello(SSL *ssl, CBB *extensions) { } if (!ssl->server) { - assert((ssl->s3->tmp.custom_extensions.sent & (1u << i)) == 0); - ssl->s3->tmp.custom_extensions.sent |= (1u << i); + assert((hs->custom_extensions.sent & (1u << i)) == 0); + hs->custom_extensions.sent |= (1u << i); } break; @@ -115,7 +114,7 @@ static int custom_ext_add_hello(SSL *ssl, CBB *extensions) { default: ssl3_send_alert(ssl, SSL3_AL_FATAL, alert); OPENSSL_PUT_ERROR(SSL, SSL_R_CUSTOM_EXTENSION_ERROR); - ERR_add_error_dataf("extension: %u", (unsigned) ext->value); + ERR_add_error_dataf("extension %u", (unsigned) ext->value); return 0; } } @@ -123,12 +122,13 @@ static int custom_ext_add_hello(SSL *ssl, CBB *extensions) { return 1; } -int custom_ext_add_clienthello(SSL *ssl, CBB *extensions) { - return custom_ext_add_hello(ssl, extensions); +int custom_ext_add_clienthello(SSL_HANDSHAKE *hs, CBB *extensions) { + return custom_ext_add_hello(hs, extensions); } -int custom_ext_parse_serverhello(SSL *ssl, int *out_alert, uint16_t value, - const CBS *extension) { +int custom_ext_parse_serverhello(SSL_HANDSHAKE *hs, int *out_alert, + uint16_t value, const CBS *extension) { + SSL *const ssl = hs->ssl; unsigned index; const SSL_CUSTOM_EXTENSION *ext = custom_ext_find(ssl->ctx->client_custom_extensions, &index, value); @@ -136,10 +136,10 @@ int custom_ext_parse_serverhello(SSL *ssl, int *out_alert, uint16_t value, if (/* Unknown extensions are not allowed in a ServerHello. */ ext == NULL || /* Also, if we didn't send the extension, that's also unacceptable. */ - !(ssl->s3->tmp.custom_extensions.sent & (1u << index))) { + !(hs->custom_extensions.sent & (1u << index))) { OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION); - ERR_add_error_dataf("extension: %u", (unsigned)value); - *out_alert = SSL_AD_DECODE_ERROR; + ERR_add_error_dataf("extension %u", (unsigned)value); + *out_alert = SSL_AD_UNSUPPORTED_EXTENSION; return 0; } @@ -147,15 +147,16 @@ int custom_ext_parse_serverhello(SSL *ssl, int *out_alert, uint16_t value, !ext->parse_callback(ssl, value, CBS_data(extension), CBS_len(extension), out_alert, ext->parse_arg)) { OPENSSL_PUT_ERROR(SSL, SSL_R_CUSTOM_EXTENSION_ERROR); - ERR_add_error_dataf("extension: %u", (unsigned)ext->value); + ERR_add_error_dataf("extension %u", (unsigned)ext->value); return 0; } return 1; } -int custom_ext_parse_clienthello(SSL *ssl, int *out_alert, uint16_t value, - const CBS *extension) { +int custom_ext_parse_clienthello(SSL_HANDSHAKE *hs, int *out_alert, + uint16_t value, const CBS *extension) { + SSL *const ssl = hs->ssl; unsigned index; const SSL_CUSTOM_EXTENSION *ext = custom_ext_find(ssl->ctx->server_custom_extensions, &index, value); @@ -164,29 +165,29 @@ int custom_ext_parse_clienthello(SSL *ssl, int *out_alert, uint16_t value, return 1; } - assert((ssl->s3->tmp.custom_extensions.received & (1u << index)) == 0); - ssl->s3->tmp.custom_extensions.received |= (1u << index); + assert((hs->custom_extensions.received & (1u << index)) == 0); + hs->custom_extensions.received |= (1u << index); if (ext->parse_callback && !ext->parse_callback(ssl, value, CBS_data(extension), CBS_len(extension), out_alert, ext->parse_arg)) { OPENSSL_PUT_ERROR(SSL, SSL_R_CUSTOM_EXTENSION_ERROR); - ERR_add_error_dataf("extension: %u", (unsigned)ext->value); + ERR_add_error_dataf("extension %u", (unsigned)ext->value); return 0; } return 1; } -int custom_ext_add_serverhello(SSL *ssl, CBB *extensions) { - return custom_ext_add_hello(ssl, extensions); +int custom_ext_add_serverhello(SSL_HANDSHAKE *hs, CBB *extensions) { + return custom_ext_add_hello(hs, extensions); } /* MAX_NUM_CUSTOM_EXTENSIONS is the maximum number of custom extensions that * can be set on an |SSL_CTX|. It's determined by the size of the bitset used * to track when an extension has been sent. */ #define MAX_NUM_CUSTOM_EXTENSIONS \ - (sizeof(((struct ssl3_state_st *)NULL)->tmp.custom_extensions.sent) * 8) + (sizeof(((SSL_HANDSHAKE *)NULL)->custom_extensions.sent) * 8) static int custom_ext_append(STACK_OF(SSL_CUSTOM_EXTENSION) **stack, unsigned extension_value, diff --git a/Sources/BoringSSL/ssl/d1_both.c b/Sources/BoringSSL/ssl/d1_both.c index ee4cbc9ea..b864e426f 100644 --- a/Sources/BoringSSL/ssl/d1_both.c +++ b/Sources/BoringSSL/ssl/d1_both.c @@ -115,17 +115,17 @@ #include #include -#include #include #include #include #include #include -#include #include +#include #include +#include "../crypto/internal.h" #include "internal.h" @@ -141,41 +141,63 @@ static const unsigned int kMinMTU = 256 - 28; * the underlying BIO supplies one. */ static const unsigned int kDefaultMTU = 1500 - 28; -/* kMaxHandshakeBuffer is the maximum number of handshake messages ahead of the - * current one to buffer. */ -static const unsigned int kHandshakeBufferSize = 10; -static hm_fragment *dtls1_hm_fragment_new(size_t frag_len, int reassembly) { +/* Receiving handshake messages. */ + +static void dtls1_hm_fragment_free(hm_fragment *frag) { + if (frag == NULL) { + return; + } + OPENSSL_free(frag->data); + OPENSSL_free(frag->reassembly); + OPENSSL_free(frag); +} + +static hm_fragment *dtls1_hm_fragment_new(const struct hm_header_st *msg_hdr) { hm_fragment *frag = OPENSSL_malloc(sizeof(hm_fragment)); if (frag == NULL) { OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); return NULL; } - memset(frag, 0, sizeof(hm_fragment)); + OPENSSL_memset(frag, 0, sizeof(hm_fragment)); + frag->type = msg_hdr->type; + frag->seq = msg_hdr->seq; + frag->msg_len = msg_hdr->msg_len; - /* If the handshake message is empty, |frag->fragment| and |frag->reassembly| - * are NULL. */ - if (frag_len > 0) { - frag->fragment = OPENSSL_malloc(frag_len); - if (frag->fragment == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + /* Allocate space for the reassembled message and fill in the header. */ + frag->data = OPENSSL_malloc(DTLS1_HM_HEADER_LENGTH + msg_hdr->msg_len); + if (frag->data == NULL) { + OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + goto err; + } + + CBB cbb; + if (!CBB_init_fixed(&cbb, frag->data, DTLS1_HM_HEADER_LENGTH) || + !CBB_add_u8(&cbb, msg_hdr->type) || + !CBB_add_u24(&cbb, msg_hdr->msg_len) || + !CBB_add_u16(&cbb, msg_hdr->seq) || + !CBB_add_u24(&cbb, 0 /* frag_off */) || + !CBB_add_u24(&cbb, msg_hdr->msg_len) || + !CBB_finish(&cbb, NULL, NULL)) { + CBB_cleanup(&cbb); + OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + goto err; + } + + /* If the handshake message is empty, |frag->reassembly| is NULL. */ + if (msg_hdr->msg_len > 0) { + /* Initialize reassembly bitmask. */ + if (msg_hdr->msg_len + 7 < msg_hdr->msg_len) { + OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW); goto err; } - - if (reassembly) { - /* Initialize reassembly bitmask. */ - if (frag_len + 7 < frag_len) { - OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW); - goto err; - } - size_t bitmask_len = (frag_len + 7) / 8; - frag->reassembly = OPENSSL_malloc(bitmask_len); - if (frag->reassembly == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; - } - memset(frag->reassembly, 0, bitmask_len); + size_t bitmask_len = (msg_hdr->msg_len + 7) / 8; + frag->reassembly = OPENSSL_malloc(bitmask_len); + if (frag->reassembly == NULL) { + OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + goto err; } + OPENSSL_memset(frag->reassembly, 0, bitmask_len); } return frag; @@ -185,22 +207,9 @@ static hm_fragment *dtls1_hm_fragment_new(size_t frag_len, int reassembly) { return NULL; } -void dtls1_hm_fragment_free(hm_fragment *frag) { - if (frag == NULL) { - return; - } - OPENSSL_free(frag->fragment); - OPENSSL_free(frag->reassembly); - OPENSSL_free(frag); -} - -#if !defined(inline) -#define inline __inline -#endif - /* bit_range returns a |uint8_t| with bits |start|, inclusive, to |end|, * exclusive, set. */ -static inline uint8_t bit_range(size_t start, size_t end) { +static uint8_t bit_range(size_t start, size_t end) { return (uint8_t)(~((1u << start) - 1) & ((1u << end) - 1)); } @@ -210,8 +219,7 @@ static inline uint8_t bit_range(size_t start, size_t end) { * and |frag->reassembly| must not be NULL. */ static void dtls1_hm_fragment_mark(hm_fragment *frag, size_t start, size_t end) { - size_t i; - size_t msg_len = frag->msg_header.msg_len; + size_t msg_len = frag->msg_len; if (frag->reassembly == NULL || start > end || end > msg_len) { assert(0); @@ -224,7 +232,7 @@ static void dtls1_hm_fragment_mark(hm_fragment *frag, size_t start, frag->reassembly[start >> 3] |= bit_range(start & 7, end & 7); } else { frag->reassembly[start >> 3] |= bit_range(start & 7, 8); - for (i = (start >> 3) + 1; i < (end >> 3); i++) { + for (size_t i = (start >> 3) + 1; i < (end >> 3); i++) { frag->reassembly[i] = 0xff; } if ((end & 7) != 0) { @@ -233,7 +241,7 @@ static void dtls1_hm_fragment_mark(hm_fragment *frag, size_t start, } /* Check if the fragment is complete. */ - for (i = 0; i < (msg_len >> 3); i++) { + for (size_t i = 0; i < (msg_len >> 3); i++) { if (frag->reassembly[i] != 0xff) { return; } @@ -247,635 +255,561 @@ static void dtls1_hm_fragment_mark(hm_fragment *frag, size_t start, frag->reassembly = NULL; } -static void dtls1_update_mtu(SSL *ssl) { - /* TODO(davidben): What is this code doing and do we need it? */ - if (ssl->d1->mtu < dtls1_min_mtu() && - !(SSL_get_options(ssl) & SSL_OP_NO_QUERY_MTU)) { - long mtu = BIO_ctrl(SSL_get_wbio(ssl), BIO_CTRL_DGRAM_QUERY_MTU, 0, NULL); - if (mtu >= 0 && mtu <= (1 << 30) && (unsigned)mtu >= dtls1_min_mtu()) { - ssl->d1->mtu = (unsigned)mtu; - } else { - ssl->d1->mtu = kDefaultMTU; - BIO_ctrl(SSL_get_wbio(ssl), BIO_CTRL_DGRAM_SET_MTU, ssl->d1->mtu, NULL); - } - } - - /* The MTU should be above the minimum now. */ - assert(ssl->d1->mtu >= dtls1_min_mtu()); +/* dtls1_is_current_message_complete returns one if the current handshake + * message is complete and zero otherwise. */ +static int dtls1_is_current_message_complete(const SSL *ssl) { + hm_fragment *frag = ssl->d1->incoming_messages[ssl->d1->handshake_read_seq % + SSL_MAX_HANDSHAKE_FLIGHT]; + return frag != NULL && frag->reassembly == NULL; } -/* dtls1_max_record_size returns the maximum record body length that may be - * written without exceeding the MTU. It accounts for any buffering installed on - * the write BIO. If no record may be written, it returns zero. */ -static size_t dtls1_max_record_size(SSL *ssl) { - size_t ret = ssl->d1->mtu; - - size_t overhead = ssl_max_seal_overhead(ssl); - if (ret <= overhead) { - return 0; +/* dtls1_get_incoming_message returns the incoming message corresponding to + * |msg_hdr|. If none exists, it creates a new one and inserts it in the + * queue. Otherwise, it checks |msg_hdr| is consistent with the existing one. It + * returns NULL on failure. The caller does not take ownership of the result. */ +static hm_fragment *dtls1_get_incoming_message( + SSL *ssl, const struct hm_header_st *msg_hdr) { + if (msg_hdr->seq < ssl->d1->handshake_read_seq || + msg_hdr->seq - ssl->d1->handshake_read_seq >= SSL_MAX_HANDSHAKE_FLIGHT) { + return NULL; } - ret -= overhead; - size_t pending = BIO_wpending(SSL_get_wbio(ssl)); - if (ret <= pending) { - return 0; + size_t idx = msg_hdr->seq % SSL_MAX_HANDSHAKE_FLIGHT; + hm_fragment *frag = ssl->d1->incoming_messages[idx]; + if (frag != NULL) { + assert(frag->seq == msg_hdr->seq); + /* The new fragment must be compatible with the previous fragments from this + * message. */ + if (frag->type != msg_hdr->type || + frag->msg_len != msg_hdr->msg_len) { + OPENSSL_PUT_ERROR(SSL, SSL_R_FRAGMENT_MISMATCH); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER); + return NULL; + } + return frag; } - ret -= pending; - return ret; + /* This is the first fragment from this message. */ + frag = dtls1_hm_fragment_new(msg_hdr); + if (frag == NULL) { + return NULL; + } + ssl->d1->incoming_messages[idx] = frag; + return frag; } -static int dtls1_write_change_cipher_spec(SSL *ssl, - enum dtls1_use_epoch_t use_epoch) { - dtls1_update_mtu(ssl); +/* dtls1_process_handshake_record reads a handshake record and processes it. It + * returns one if the record was successfully processed and 0 or -1 on error. */ +static int dtls1_process_handshake_record(SSL *ssl) { + SSL3_RECORD *rr = &ssl->s3->rrec; - /* During the handshake, wbio is buffered to pack messages together. Flush the - * buffer if the ChangeCipherSpec would not fit in a packet. */ - if (dtls1_max_record_size(ssl) == 0) { - ssl->rwstate = SSL_WRITING; - int ret = BIO_flush(SSL_get_wbio(ssl)); +start: + if (rr->length == 0) { + int ret = dtls1_get_record(ssl); if (ret <= 0) { return ret; } - ssl->rwstate = SSL_NOTHING; - } - - static const uint8_t kChangeCipherSpec[1] = {SSL3_MT_CCS}; - int ret = - dtls1_write_bytes(ssl, SSL3_RT_CHANGE_CIPHER_SPEC, kChangeCipherSpec, - sizeof(kChangeCipherSpec), use_epoch); - if (ret <= 0) { - return ret; - } - - if (ssl->msg_callback != NULL) { - ssl->msg_callback(1 /* write */, ssl->version, SSL3_RT_CHANGE_CIPHER_SPEC, - kChangeCipherSpec, sizeof(kChangeCipherSpec), ssl, - ssl->msg_callback_arg); } - return 1; -} - -int dtls1_do_handshake_write(SSL *ssl, enum dtls1_use_epoch_t use_epoch) { - dtls1_update_mtu(ssl); - - int ret = -1; - CBB cbb; - CBB_zero(&cbb); - /* Allocate a temporary buffer to hold the message fragments to avoid - * clobbering the message. */ - uint8_t *buf = OPENSSL_malloc(ssl->d1->mtu); - if (buf == NULL) { - goto err; + /* Cross-epoch records are discarded, but we may receive out-of-order + * application data between ChangeCipherSpec and Finished or a + * ChangeCipherSpec before the appropriate point in the handshake. Those must + * be silently discarded. + * + * However, only allow the out-of-order records in the correct epoch. + * Application data must come in the encrypted epoch, and ChangeCipherSpec in + * the unencrypted epoch (we never renegotiate). Other cases fall through and + * fail with a fatal error. */ + if ((rr->type == SSL3_RT_APPLICATION_DATA && + ssl->s3->aead_read_ctx != NULL) || + (rr->type == SSL3_RT_CHANGE_CIPHER_SPEC && + ssl->s3->aead_read_ctx == NULL)) { + rr->length = 0; + goto start; + } + + if (rr->type != SSL3_RT_HANDSHAKE) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE); + OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_RECORD); + return -1; } - /* Consume the message header. Fragments will have different headers - * prepended. */ - if (ssl->init_off == 0) { - ssl->init_off += DTLS1_HM_HEADER_LENGTH; - ssl->init_num -= DTLS1_HM_HEADER_LENGTH; - } - assert(ssl->init_off >= DTLS1_HM_HEADER_LENGTH); + CBS cbs; + CBS_init(&cbs, rr->data, rr->length); - do { - /* During the handshake, wbio is buffered to pack messages together. Flush - * the buffer if there isn't enough room to make progress. */ - if (dtls1_max_record_size(ssl) < DTLS1_HM_HEADER_LENGTH + 1) { - ssl->rwstate = SSL_WRITING; - int flush_ret = BIO_flush(SSL_get_wbio(ssl)); - if (flush_ret <= 0) { - ret = flush_ret; - goto err; - } - ssl->rwstate = SSL_NOTHING; - assert(BIO_wpending(SSL_get_wbio(ssl)) == 0); + while (CBS_len(&cbs) > 0) { + /* Read a handshake fragment. */ + struct hm_header_st msg_hdr; + CBS body; + if (!dtls1_parse_fragment(&cbs, &msg_hdr, &body)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_HANDSHAKE_RECORD); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); + return -1; } - size_t todo = dtls1_max_record_size(ssl); - if (todo < DTLS1_HM_HEADER_LENGTH + 1) { - /* To make forward progress, the MTU must, at minimum, fit the handshake - * header and one byte of handshake body. */ - OPENSSL_PUT_ERROR(SSL, SSL_R_MTU_TOO_SMALL); - goto err; + const size_t frag_off = msg_hdr.frag_off; + const size_t frag_len = msg_hdr.frag_len; + const size_t msg_len = msg_hdr.msg_len; + if (frag_off > msg_len || frag_off + frag_len < frag_off || + frag_off + frag_len > msg_len || + msg_len > ssl_max_handshake_message_len(ssl)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_EXCESSIVE_MESSAGE_SIZE); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER); + return -1; } - todo -= DTLS1_HM_HEADER_LENGTH; - if (todo > (size_t)ssl->init_num) { - todo = ssl->init_num; + /* The encrypted epoch in DTLS has only one handshake message. */ + if (ssl->d1->r_epoch == 1 && msg_hdr.seq != ssl->d1->handshake_read_seq) { + OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_RECORD); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE); + return -1; } - if (todo >= (1u << 24)) { - todo = (1u << 24) - 1; + + if (msg_hdr.seq < ssl->d1->handshake_read_seq || + msg_hdr.seq > + (unsigned)ssl->d1->handshake_read_seq + SSL_MAX_HANDSHAKE_FLIGHT) { + /* Ignore fragments from the past, or ones too far in the future. */ + continue; } - size_t len; - if (!CBB_init_fixed(&cbb, buf, ssl->d1->mtu) || - !CBB_add_u8(&cbb, ssl->d1->w_msg_hdr.type) || - !CBB_add_u24(&cbb, ssl->d1->w_msg_hdr.msg_len) || - !CBB_add_u16(&cbb, ssl->d1->w_msg_hdr.seq) || - !CBB_add_u24(&cbb, ssl->init_off - DTLS1_HM_HEADER_LENGTH) || - !CBB_add_u24(&cbb, todo) || - !CBB_add_bytes( - &cbb, (const uint8_t *)ssl->init_buf->data + ssl->init_off, todo) || - !CBB_finish(&cbb, NULL, &len)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - goto err; + hm_fragment *frag = dtls1_get_incoming_message(ssl, &msg_hdr); + if (frag == NULL) { + return -1; } + assert(frag->msg_len == msg_len); - int write_ret = dtls1_write_bytes(ssl, SSL3_RT_HANDSHAKE, buf, len, - use_epoch); - if (write_ret <= 0) { - ret = write_ret; - goto err; + if (frag->reassembly == NULL) { + /* The message is already assembled. */ + continue; } - ssl->init_off += todo; - ssl->init_num -= todo; - } while (ssl->init_num > 0); + assert(msg_len > 0); - if (ssl->msg_callback != NULL) { - ssl->msg_callback( - 1 /* write */, ssl->version, SSL3_RT_HANDSHAKE, ssl->init_buf->data, - (size_t)(ssl->init_off + ssl->init_num), ssl, ssl->msg_callback_arg); + /* Copy the body into the fragment. */ + OPENSSL_memcpy(frag->data + DTLS1_HM_HEADER_LENGTH + frag_off, + CBS_data(&body), CBS_len(&body)); + dtls1_hm_fragment_mark(frag, frag_off, frag_off + frag_len); } - ssl->init_off = 0; - ssl->init_num = 0; + rr->length = 0; + ssl_read_buffer_discard(ssl); + return 1; +} - ret = 1; +int dtls1_get_message(SSL *ssl) { + if (ssl->s3->tmp.reuse_message) { + /* There must be a current message. */ + assert(ssl->init_msg != NULL); + ssl->s3->tmp.reuse_message = 0; + } else { + dtls1_release_current_message(ssl, 0 /* don't free buffer */); + } -err: - CBB_cleanup(&cbb); - OPENSSL_free(buf); - return ret; + /* Process handshake records until the current message is ready. */ + while (!dtls1_is_current_message_complete(ssl)) { + int ret = dtls1_process_handshake_record(ssl); + if (ret <= 0) { + return ret; + } + } + + hm_fragment *frag = ssl->d1->incoming_messages[ssl->d1->handshake_read_seq % + SSL_MAX_HANDSHAKE_FLIGHT]; + assert(frag != NULL); + assert(frag->reassembly == NULL); + assert(ssl->d1->handshake_read_seq == frag->seq); + + /* TODO(davidben): This function has a lot of implicit outputs. Simplify the + * |ssl_get_message| API. */ + ssl->s3->tmp.message_type = frag->type; + ssl->init_msg = frag->data + DTLS1_HM_HEADER_LENGTH; + ssl->init_num = frag->msg_len; + + ssl_do_msg_callback(ssl, 0 /* read */, SSL3_RT_HANDSHAKE, frag->data, + ssl->init_num + DTLS1_HM_HEADER_LENGTH); + return 1; } -/* dtls1_is_next_message_complete returns one if the next handshake message is - * complete and zero otherwise. */ -static int dtls1_is_next_message_complete(SSL *ssl) { - pitem *item = pqueue_peek(ssl->d1->buffered_messages); - if (item == NULL) { - return 0; +void dtls1_get_current_message(const SSL *ssl, CBS *out) { + assert(dtls1_is_current_message_complete(ssl)); + + hm_fragment *frag = ssl->d1->incoming_messages[ssl->d1->handshake_read_seq % + SSL_MAX_HANDSHAKE_FLIGHT]; + CBS_init(out, frag->data, DTLS1_HM_HEADER_LENGTH + frag->msg_len); +} + +void dtls1_release_current_message(SSL *ssl, int free_buffer) { + if (ssl->init_msg == NULL) { + return; } - hm_fragment *frag = (hm_fragment *)item->data; - assert(ssl->d1->handshake_read_seq <= frag->msg_header.seq); + assert(dtls1_is_current_message_complete(ssl)); + size_t index = ssl->d1->handshake_read_seq % SSL_MAX_HANDSHAKE_FLIGHT; + dtls1_hm_fragment_free(ssl->d1->incoming_messages[index]); + ssl->d1->incoming_messages[index] = NULL; + ssl->d1->handshake_read_seq++; - return ssl->d1->handshake_read_seq == frag->msg_header.seq && - frag->reassembly == NULL; + ssl->init_msg = NULL; + ssl->init_num = 0; } -/* dtls1_discard_fragment_body discards a handshake fragment body of length - * |frag_len|. It returns one on success and zero on error. - * - * TODO(davidben): This function will go away when ssl_read_bytes is gone from - * the DTLS side. */ -static int dtls1_discard_fragment_body(SSL *ssl, size_t frag_len) { - uint8_t discard[256]; - while (frag_len > 0) { - size_t chunk = frag_len < sizeof(discard) ? frag_len : sizeof(discard); - int ret = dtls1_read_bytes(ssl, SSL3_RT_HANDSHAKE, discard, chunk, 0); - if (ret != (int) chunk) { - return 0; - } - frag_len -= chunk; +void dtls_clear_incoming_messages(SSL *ssl) { + for (size_t i = 0; i < SSL_MAX_HANDSHAKE_FLIGHT; i++) { + dtls1_hm_fragment_free(ssl->d1->incoming_messages[i]); + ssl->d1->incoming_messages[i] = NULL; } - return 1; } -/* dtls1_get_buffered_message returns the buffered message corresponding to - * |msg_hdr|. If none exists, it creates a new one and inserts it in the - * queue. Otherwise, it checks |msg_hdr| is consistent with the existing one. It - * returns NULL on failure. The caller does not take ownership of the result. */ -static hm_fragment *dtls1_get_buffered_message( - SSL *ssl, const struct hm_header_st *msg_hdr) { - uint8_t seq64be[8]; - memset(seq64be, 0, sizeof(seq64be)); - seq64be[6] = (uint8_t)(msg_hdr->seq >> 8); - seq64be[7] = (uint8_t)msg_hdr->seq; - pitem *item = pqueue_find(ssl->d1->buffered_messages, seq64be); - - hm_fragment *frag; - if (item == NULL) { - /* This is the first fragment from this message. */ - frag = dtls1_hm_fragment_new(msg_hdr->msg_len, - 1 /* reassembly buffer needed */); - if (frag == NULL) { - return NULL; - } - memcpy(&frag->msg_header, msg_hdr, sizeof(*msg_hdr)); - item = pitem_new(seq64be, frag); - if (item == NULL) { - dtls1_hm_fragment_free(frag); - return NULL; +int dtls_has_incoming_messages(const SSL *ssl) { + size_t current = ssl->d1->handshake_read_seq % SSL_MAX_HANDSHAKE_FLIGHT; + for (size_t i = 0; i < SSL_MAX_HANDSHAKE_FLIGHT; i++) { + /* Skip the current message. */ + if (ssl->init_msg != NULL && i == current) { + assert(dtls1_is_current_message_complete(ssl)); + continue; } - item = pqueue_insert(ssl->d1->buffered_messages, item); - /* |pqueue_insert| fails iff a duplicate item is inserted, but |item| cannot - * be a duplicate. */ - assert(item != NULL); - } else { - frag = item->data; - assert(frag->msg_header.seq == msg_hdr->seq); - if (frag->msg_header.type != msg_hdr->type || - frag->msg_header.msg_len != msg_hdr->msg_len) { - /* The new fragment must be compatible with the previous fragments from - * this message. */ - OPENSSL_PUT_ERROR(SSL, SSL_R_FRAGMENT_MISMATCH); - ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER); - return NULL; + if (ssl->d1->incoming_messages[i] != NULL) { + return 1; } } - return frag; + return 0; } -/* dtls1_max_handshake_message_len returns the maximum number of bytes - * permitted in a DTLS handshake message for |ssl|. The minimum is 16KB, but may - * be greater if the maximum certificate list size requires it. */ -static size_t dtls1_max_handshake_message_len(const SSL *ssl) { - size_t max_len = DTLS1_HM_HEADER_LENGTH + SSL3_RT_MAX_ENCRYPTED_LENGTH; - if (max_len < ssl->max_cert_list) { - return ssl->max_cert_list; +int dtls1_parse_fragment(CBS *cbs, struct hm_header_st *out_hdr, + CBS *out_body) { + OPENSSL_memset(out_hdr, 0x00, sizeof(struct hm_header_st)); + + if (!CBS_get_u8(cbs, &out_hdr->type) || + !CBS_get_u24(cbs, &out_hdr->msg_len) || + !CBS_get_u16(cbs, &out_hdr->seq) || + !CBS_get_u24(cbs, &out_hdr->frag_off) || + !CBS_get_u24(cbs, &out_hdr->frag_len) || + !CBS_get_bytes(cbs, out_body, out_hdr->frag_len)) { + return 0; } - return max_len; + + return 1; } -/* dtls1_process_fragment reads a handshake fragment and processes it. It - * returns one if a fragment was successfully processed and 0 or -1 on error. */ -static int dtls1_process_fragment(SSL *ssl) { - /* Read handshake message header. */ - uint8_t header[DTLS1_HM_HEADER_LENGTH]; - int ret = dtls1_read_bytes(ssl, SSL3_RT_HANDSHAKE, header, - DTLS1_HM_HEADER_LENGTH, 0); - if (ret <= 0) { - return ret; - } - if (ret != DTLS1_HM_HEADER_LENGTH) { - OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_MESSAGE); - ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE); - return -1; - } - /* Parse the message fragment header. */ - struct hm_header_st msg_hdr; - dtls1_get_message_header(header, &msg_hdr); - - /* TODO(davidben): dtls1_read_bytes is the wrong abstraction for DTLS. There - * should be no need to reach into |ssl->s3->rrec.length|. */ - const size_t frag_off = msg_hdr.frag_off; - const size_t frag_len = msg_hdr.frag_len; - const size_t msg_len = msg_hdr.msg_len; - if (frag_off > msg_len || frag_off + frag_len < frag_off || - frag_off + frag_len > msg_len || - msg_len > dtls1_max_handshake_message_len(ssl) || - frag_len > ssl->s3->rrec.length) { - OPENSSL_PUT_ERROR(SSL, SSL_R_EXCESSIVE_MESSAGE_SIZE); - ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER); - return -1; - } +/* Sending handshake messages. */ - if (msg_hdr.seq < ssl->d1->handshake_read_seq || - msg_hdr.seq > (unsigned)ssl->d1->handshake_read_seq + - kHandshakeBufferSize) { - /* Ignore fragments from the past, or ones too far in the future. */ - if (!dtls1_discard_fragment_body(ssl, frag_len)) { - return -1; - } - return 1; +void dtls_clear_outgoing_messages(SSL *ssl) { + for (size_t i = 0; i < ssl->d1->outgoing_messages_len; i++) { + OPENSSL_free(ssl->d1->outgoing_messages[i].data); + ssl->d1->outgoing_messages[i].data = NULL; } + ssl->d1->outgoing_messages_len = 0; + ssl->d1->outgoing_written = 0; + ssl->d1->outgoing_offset = 0; +} - hm_fragment *frag = dtls1_get_buffered_message(ssl, &msg_hdr); - if (frag == NULL) { - return -1; +int dtls1_init_message(SSL *ssl, CBB *cbb, CBB *body, uint8_t type) { + /* Pick a modest size hint to save most of the |realloc| calls. */ + if (!CBB_init(cbb, 64) || + !CBB_add_u8(cbb, type) || + !CBB_add_u24(cbb, 0 /* length (filled in later) */) || + !CBB_add_u16(cbb, ssl->d1->handshake_write_seq) || + !CBB_add_u24(cbb, 0 /* offset */) || + !CBB_add_u24_length_prefixed(cbb, body)) { + return 0; } - assert(frag->msg_header.msg_len == msg_len); - if (frag->reassembly == NULL) { - /* The message is already assembled. */ - if (!dtls1_discard_fragment_body(ssl, frag_len)) { - return -1; - } - return 1; - } - assert(msg_len > 0); + return 1; +} - /* Read the body of the fragment. */ - ret = dtls1_read_bytes(ssl, SSL3_RT_HANDSHAKE, frag->fragment + frag_off, - frag_len, 0); - if (ret != (int) frag_len) { +int dtls1_finish_message(SSL *ssl, CBB *cbb, uint8_t **out_msg, + size_t *out_len) { + *out_msg = NULL; + if (!CBB_finish(cbb, out_msg, out_len) || + *out_len < DTLS1_HM_HEADER_LENGTH) { OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); - return -1; + OPENSSL_free(*out_msg); + return 0; } - dtls1_hm_fragment_mark(frag, frag_off, frag_off + frag_len); + /* Fix up the header. Copy the fragment length into the total message + * length. */ + OPENSSL_memcpy(*out_msg + 1, *out_msg + DTLS1_HM_HEADER_LENGTH - 3, 3); return 1; } -/* dtls1_get_message reads a handshake message of message type |msg_type| (any - * if |msg_type| == -1), maximum acceptable body length |max|. Read an entire - * handshake message. Handshake messages arrive in fragments. */ -long dtls1_get_message(SSL *ssl, int st1, int stn, int msg_type, long max, - enum ssl_hash_message_t hash_message, int *ok) { - pitem *item = NULL; - hm_fragment *frag = NULL; - int al; - - /* s3->tmp is used to store messages that are unexpected, caused - * by the absence of an optional handshake message */ - if (ssl->s3->tmp.reuse_message) { - /* A ssl_dont_hash_message call cannot be combined with reuse_message; the - * ssl_dont_hash_message would have to have been applied to the previous - * call. */ - assert(hash_message == ssl_hash_message); - ssl->s3->tmp.reuse_message = 0; - if (msg_type >= 0 && ssl->s3->tmp.message_type != msg_type) { - al = SSL_AD_UNEXPECTED_MESSAGE; - OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_MESSAGE); - goto f_err; - } - *ok = 1; - ssl->init_msg = (uint8_t *)ssl->init_buf->data + DTLS1_HM_HEADER_LENGTH; - ssl->init_num = (int)ssl->s3->tmp.message_size; - return ssl->init_num; +/* add_outgoing adds a new handshake message or ChangeCipherSpec to the current + * outgoing flight. It returns one on success and zero on error. In both cases, + * it takes ownership of |data| and releases it with |OPENSSL_free| when + * done. */ +static int add_outgoing(SSL *ssl, int is_ccs, uint8_t *data, size_t len) { + OPENSSL_COMPILE_ASSERT(SSL_MAX_HANDSHAKE_FLIGHT < + (1 << 8 * sizeof(ssl->d1->outgoing_messages_len)), + outgoing_messages_len_is_too_small); + if (ssl->d1->outgoing_messages_len >= SSL_MAX_HANDSHAKE_FLIGHT) { + assert(0); + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + OPENSSL_free(data); + return 0; } - /* Process fragments until one is found. */ - while (!dtls1_is_next_message_complete(ssl)) { - int ret = dtls1_process_fragment(ssl); - if (ret <= 0) { - *ok = 0; - return ret; + if (!is_ccs) { + /* TODO(svaldez): Move this up a layer to fix abstraction for SSL_TRANSCRIPT + * on hs. */ + if (ssl->s3->hs != NULL && + !SSL_TRANSCRIPT_update(&ssl->s3->hs->transcript, data, len)) { + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + OPENSSL_free(data); + return 0; } + ssl->d1->handshake_write_seq++; } - /* Read out the next complete handshake message. */ - item = pqueue_pop(ssl->d1->buffered_messages); - assert(item != NULL); - frag = (hm_fragment *)item->data; - assert(ssl->d1->handshake_read_seq == frag->msg_header.seq); - assert(frag->reassembly == NULL); - - if (frag->msg_header.msg_len > (size_t)max) { - OPENSSL_PUT_ERROR(SSL, SSL_R_EXCESSIVE_MESSAGE_SIZE); - goto err; - } - - /* Reconstruct the assembled message. */ - size_t len; - CBB cbb; - CBB_zero(&cbb); - if (!BUF_MEM_grow(ssl->init_buf, (size_t)frag->msg_header.msg_len + - DTLS1_HM_HEADER_LENGTH) || - !CBB_init_fixed(&cbb, (uint8_t *)ssl->init_buf->data, - ssl->init_buf->max) || - !CBB_add_u8(&cbb, frag->msg_header.type) || - !CBB_add_u24(&cbb, frag->msg_header.msg_len) || - !CBB_add_u16(&cbb, frag->msg_header.seq) || - !CBB_add_u24(&cbb, 0 /* frag_off */) || - !CBB_add_u24(&cbb, frag->msg_header.msg_len) || - !CBB_add_bytes(&cbb, frag->fragment, frag->msg_header.msg_len) || - !CBB_finish(&cbb, NULL, &len)) { - CBB_cleanup(&cbb); - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; - } - assert(len == (size_t)frag->msg_header.msg_len + DTLS1_HM_HEADER_LENGTH); - - ssl->d1->handshake_read_seq++; + DTLS_OUTGOING_MESSAGE *msg = + &ssl->d1->outgoing_messages[ssl->d1->outgoing_messages_len]; + msg->data = data; + msg->len = len; + msg->epoch = ssl->d1->w_epoch; + msg->is_ccs = is_ccs; - /* TODO(davidben): This function has a lot of implicit outputs. Simplify the - * |ssl_get_message| API. */ - ssl->s3->tmp.message_type = frag->msg_header.type; - ssl->s3->tmp.message_size = frag->msg_header.msg_len; - ssl->init_msg = (uint8_t *)ssl->init_buf->data + DTLS1_HM_HEADER_LENGTH; - ssl->init_num = frag->msg_header.msg_len; - - if (msg_type >= 0 && ssl->s3->tmp.message_type != msg_type) { - al = SSL_AD_UNEXPECTED_MESSAGE; - OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_MESSAGE); - goto f_err; - } - if (hash_message == ssl_hash_message && !ssl3_hash_current_message(ssl)) { - goto err; - } - if (ssl->msg_callback) { - ssl->msg_callback(0, ssl->version, SSL3_RT_HANDSHAKE, ssl->init_buf->data, - ssl->init_num + DTLS1_HM_HEADER_LENGTH, ssl, - ssl->msg_callback_arg); - } - - pitem_free(item); - dtls1_hm_fragment_free(frag); - - ssl->state = stn; - *ok = 1; - return ssl->init_num; + ssl->d1->outgoing_messages_len++; + return 1; +} -f_err: - ssl3_send_alert(ssl, SSL3_AL_FATAL, al); -err: - pitem_free(item); - dtls1_hm_fragment_free(frag); - *ok = 0; - return -1; +int dtls1_add_message(SSL *ssl, uint8_t *data, size_t len) { + return add_outgoing(ssl, 0 /* handshake */, data, len); } -int dtls1_read_failed(SSL *ssl, int code) { - if (code > 0) { - assert(0); - return 1; - } +int dtls1_add_change_cipher_spec(SSL *ssl) { + return add_outgoing(ssl, 1 /* ChangeCipherSpec */, NULL, 0); +} - if (!dtls1_is_timer_expired(ssl)) { - /* not a timeout, none of our business, let higher layers handle this. In - * fact, it's probably an error */ - return code; - } +int dtls1_add_alert(SSL *ssl, uint8_t level, uint8_t desc) { + /* The |add_alert| path is only used for warning alerts for now, which DTLS + * never sends. This will be implemented later once closure alerts are + * converted. */ + assert(0); + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + return 0; +} - if (!SSL_in_init(ssl)) { - /* done, no need to send a retransmit */ - BIO_set_flags(SSL_get_rbio(ssl), BIO_FLAGS_READ); - return code; +/* dtls1_update_mtu updates the current MTU from the BIO, ensuring it is above + * the minimum. */ +static void dtls1_update_mtu(SSL *ssl) { + /* TODO(davidben): No consumer implements |BIO_CTRL_DGRAM_SET_MTU| and the + * only |BIO_CTRL_DGRAM_QUERY_MTU| implementation could use + * |SSL_set_mtu|. Does this need to be so complex? */ + if (ssl->d1->mtu < dtls1_min_mtu() && + !(SSL_get_options(ssl) & SSL_OP_NO_QUERY_MTU)) { + long mtu = BIO_ctrl(ssl->wbio, BIO_CTRL_DGRAM_QUERY_MTU, 0, NULL); + if (mtu >= 0 && mtu <= (1 << 30) && (unsigned)mtu >= dtls1_min_mtu()) { + ssl->d1->mtu = (unsigned)mtu; + } else { + ssl->d1->mtu = kDefaultMTU; + BIO_ctrl(ssl->wbio, BIO_CTRL_DGRAM_SET_MTU, ssl->d1->mtu, NULL); + } } - return DTLSv1_handle_timeout(ssl); + /* The MTU should be above the minimum now. */ + assert(ssl->d1->mtu >= dtls1_min_mtu()); } -static uint16_t dtls1_get_queue_priority(uint16_t seq, int is_ccs) { - assert(seq * 2 >= seq); - - /* The index of the retransmission queue actually is the message sequence - * number, since the queue only contains messages of a single handshake. - * However, the ChangeCipherSpec has no message sequence number and so using - * only the sequence will result in the CCS and Finished having the same - * index. To prevent this, the sequence number is multiplied by 2. In case of - * a CCS 1 is subtracted. This does not only differ CSS and Finished, it also - * maintains the order of the index (important for priority queues) and fits - * in the unsigned short variable. */ - return seq * 2 - is_ccs; -} +enum seal_result_t { + seal_error, + seal_no_progress, + seal_partial, + seal_success, +}; + +/* seal_next_message seals |msg|, which must be the next message, to |out|. If + * progress was made, it returns |seal_partial| or |seal_success| and sets + * |*out_len| to the number of bytes written. */ +static enum seal_result_t seal_next_message(SSL *ssl, uint8_t *out, + size_t *out_len, size_t max_out, + const DTLS_OUTGOING_MESSAGE *msg) { + assert(ssl->d1->outgoing_written < ssl->d1->outgoing_messages_len); + assert(msg == &ssl->d1->outgoing_messages[ssl->d1->outgoing_written]); -static int dtls1_retransmit_message(SSL *ssl, hm_fragment *frag) { /* DTLS renegotiation is unsupported, so only epochs 0 (NULL cipher) and 1 * (negotiated cipher) exist. */ assert(ssl->d1->w_epoch == 0 || ssl->d1->w_epoch == 1); - assert(frag->msg_header.epoch <= ssl->d1->w_epoch); + assert(msg->epoch <= ssl->d1->w_epoch); enum dtls1_use_epoch_t use_epoch = dtls1_use_current_epoch; - if (ssl->d1->w_epoch == 1 && frag->msg_header.epoch == 0) { + if (ssl->d1->w_epoch == 1 && msg->epoch == 0) { use_epoch = dtls1_use_previous_epoch; } + size_t overhead = dtls_max_seal_overhead(ssl, use_epoch); + size_t prefix = dtls_seal_prefix_len(ssl, use_epoch); - /* TODO(davidben): This cannot handle non-blocking writes. */ - int ret; - if (frag->msg_header.is_ccs) { - ret = dtls1_write_change_cipher_spec(ssl, use_epoch); - } else { - /* Restore the message body. - * TODO(davidben): Make this less stateful. */ - memcpy(ssl->init_buf->data, frag->fragment, - frag->msg_header.msg_len + DTLS1_HM_HEADER_LENGTH); - ssl->init_num = frag->msg_header.msg_len + DTLS1_HM_HEADER_LENGTH; + if (msg->is_ccs) { + /* Check there is room for the ChangeCipherSpec. */ + static const uint8_t kChangeCipherSpec[1] = {SSL3_MT_CCS}; + if (max_out < sizeof(kChangeCipherSpec) + overhead) { + return seal_no_progress; + } - dtls1_set_message_header(ssl, frag->msg_header.type, - frag->msg_header.msg_len, frag->msg_header.seq, - 0, frag->msg_header.frag_len); - ret = dtls1_do_handshake_write(ssl, use_epoch); + if (!dtls_seal_record(ssl, out, out_len, max_out, + SSL3_RT_CHANGE_CIPHER_SPEC, kChangeCipherSpec, + sizeof(kChangeCipherSpec), use_epoch)) { + return seal_error; + } + + ssl_do_msg_callback(ssl, 1 /* write */, SSL3_RT_CHANGE_CIPHER_SPEC, + kChangeCipherSpec, sizeof(kChangeCipherSpec)); + return seal_success; + } + + /* DTLS messages are serialized as a single fragment in |msg|. */ + CBS cbs, body; + struct hm_header_st hdr; + CBS_init(&cbs, msg->data, msg->len); + if (!dtls1_parse_fragment(&cbs, &hdr, &body) || + hdr.frag_off != 0 || + hdr.frag_len != CBS_len(&body) || + hdr.msg_len != CBS_len(&body) || + !CBS_skip(&body, ssl->d1->outgoing_offset) || + CBS_len(&cbs) != 0) { + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + return seal_error; } - /* TODO(davidben): Check return value? */ - (void)BIO_flush(SSL_get_wbio(ssl)); - return ret; -} + /* Determine how much progress can be made. */ + if (max_out < DTLS1_HM_HEADER_LENGTH + 1 + overhead || max_out < prefix) { + return seal_no_progress; + } + size_t todo = CBS_len(&body); + if (todo > max_out - DTLS1_HM_HEADER_LENGTH - overhead) { + todo = max_out - DTLS1_HM_HEADER_LENGTH - overhead; + } + + /* Assemble a fragment, to be sealed in-place. */ + CBB cbb; + uint8_t *frag = out + prefix; + size_t max_frag = max_out - prefix, frag_len; + if (!CBB_init_fixed(&cbb, frag, max_frag) || + !CBB_add_u8(&cbb, hdr.type) || + !CBB_add_u24(&cbb, hdr.msg_len) || + !CBB_add_u16(&cbb, hdr.seq) || + !CBB_add_u24(&cbb, ssl->d1->outgoing_offset) || + !CBB_add_u24(&cbb, todo) || + !CBB_add_bytes(&cbb, CBS_data(&body), todo) || + !CBB_finish(&cbb, NULL, &frag_len)) { + CBB_cleanup(&cbb); + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + return seal_error; + } + ssl_do_msg_callback(ssl, 1 /* write */, SSL3_RT_HANDSHAKE, frag, frag_len); -int dtls1_retransmit_buffered_messages(SSL *ssl) { - pqueue sent = ssl->d1->sent_messages; - piterator iter = pqueue_iterator(sent); - pitem *item; + if (!dtls_seal_record(ssl, out, out_len, max_out, SSL3_RT_HANDSHAKE, + out + prefix, frag_len, use_epoch)) { + return seal_error; + } - for (item = pqueue_next(&iter); item != NULL; item = pqueue_next(&iter)) { - hm_fragment *frag = (hm_fragment *)item->data; - if (dtls1_retransmit_message(ssl, frag) <= 0) { - return -1; - } + if (todo == CBS_len(&body)) { + /* The next message is complete. */ + ssl->d1->outgoing_offset = 0; + return seal_success; } - return 1; + ssl->d1->outgoing_offset += todo; + return seal_partial; } -/* dtls1_buffer_change_cipher_spec adds a ChangeCipherSpec to the current - * handshake flight, ordered just before the handshake message numbered - * |seq|. */ -static int dtls1_buffer_change_cipher_spec(SSL *ssl, uint16_t seq) { - hm_fragment *frag = dtls1_hm_fragment_new(0 /* frag_len */, - 0 /* no reassembly */); - if (frag == NULL) { - return 0; +/* seal_next_packet writes as much of the next flight as possible to |out| and + * advances |ssl->d1->outgoing_written| and |ssl->d1->outgoing_offset| as + * appropriate. */ +static int seal_next_packet(SSL *ssl, uint8_t *out, size_t *out_len, + size_t max_out) { + int made_progress = 0; + size_t total = 0; + assert(ssl->d1->outgoing_written < ssl->d1->outgoing_messages_len); + for (; ssl->d1->outgoing_written < ssl->d1->outgoing_messages_len; + ssl->d1->outgoing_written++) { + const DTLS_OUTGOING_MESSAGE *msg = + &ssl->d1->outgoing_messages[ssl->d1->outgoing_written]; + size_t len; + enum seal_result_t ret = seal_next_message(ssl, out, &len, max_out, msg); + switch (ret) { + case seal_error: + return 0; + + case seal_no_progress: + goto packet_full; + + case seal_partial: + case seal_success: + out += len; + max_out -= len; + total += len; + made_progress = 1; + + if (ret == seal_partial) { + goto packet_full; + } + break; + } } - frag->msg_header.is_ccs = 1; - frag->msg_header.epoch = ssl->d1->w_epoch; - - uint16_t priority = dtls1_get_queue_priority(seq, 1 /* is_ccs */); - uint8_t seq64be[8]; - memset(seq64be, 0, sizeof(seq64be)); - seq64be[6] = (uint8_t)(priority >> 8); - seq64be[7] = (uint8_t)priority; - pitem *item = pitem_new(seq64be, frag); - if (item == NULL) { - dtls1_hm_fragment_free(frag); +packet_full: + /* The MTU was too small to make any progress. */ + if (!made_progress) { + OPENSSL_PUT_ERROR(SSL, SSL_R_MTU_TOO_SMALL); return 0; } - pqueue_insert(ssl->d1->sent_messages, item); + *out_len = total; return 1; } -int dtls1_buffer_message(SSL *ssl) { - /* this function is called immediately after a message has - * been serialized */ - assert(ssl->init_off == 0); +int dtls1_flush_flight(SSL *ssl) { + dtls1_update_mtu(ssl); - hm_fragment *frag = dtls1_hm_fragment_new(ssl->init_num, 0); - if (!frag) { - return 0; + int ret = -1; + uint8_t *packet = OPENSSL_malloc(ssl->d1->mtu); + if (packet == NULL) { + OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + goto err; } - memcpy(frag->fragment, ssl->init_buf->data, ssl->init_num); - - assert(ssl->d1->w_msg_hdr.msg_len + DTLS1_HM_HEADER_LENGTH == - (unsigned int)ssl->init_num); + while (ssl->d1->outgoing_written < ssl->d1->outgoing_messages_len) { + uint8_t old_written = ssl->d1->outgoing_written; + uint32_t old_offset = ssl->d1->outgoing_offset; - frag->msg_header.msg_len = ssl->d1->w_msg_hdr.msg_len; - frag->msg_header.seq = ssl->d1->w_msg_hdr.seq; - frag->msg_header.type = ssl->d1->w_msg_hdr.type; - frag->msg_header.frag_off = 0; - frag->msg_header.frag_len = ssl->d1->w_msg_hdr.msg_len; - frag->msg_header.is_ccs = 0; - frag->msg_header.epoch = ssl->d1->w_epoch; - - uint16_t priority = dtls1_get_queue_priority(frag->msg_header.seq, - 0 /* handshake */); - uint8_t seq64be[8]; - memset(seq64be, 0, sizeof(seq64be)); - seq64be[6] = (uint8_t)(priority >> 8); - seq64be[7] = (uint8_t)priority; + size_t packet_len; + if (!seal_next_packet(ssl, packet, &packet_len, ssl->d1->mtu)) { + goto err; + } - pitem *item = pitem_new(seq64be, frag); - if (item == NULL) { - dtls1_hm_fragment_free(frag); - return 0; + int bio_ret = BIO_write(ssl->wbio, packet, packet_len); + if (bio_ret <= 0) { + /* Retry this packet the next time around. */ + ssl->d1->outgoing_written = old_written; + ssl->d1->outgoing_offset = old_offset; + ssl->rwstate = SSL_WRITING; + ret = bio_ret; + goto err; + } } - pqueue_insert(ssl->d1->sent_messages, item); - return 1; -} - -int dtls1_send_change_cipher_spec(SSL *ssl, int a, int b) { - if (ssl->state == a) { - /* Buffer the message to handle retransmits. */ - ssl->d1->handshake_write_seq = ssl->d1->next_handshake_write_seq; - dtls1_buffer_change_cipher_spec(ssl, ssl->d1->handshake_write_seq); - ssl->state = b; + if (BIO_flush(ssl->wbio) <= 0) { + ssl->rwstate = SSL_WRITING; + goto err; } - return dtls1_write_change_cipher_spec(ssl, dtls1_use_current_epoch); -} - -/* call this function when the buffered messages are no longer needed */ -void dtls1_clear_record_buffer(SSL *ssl) { - pitem *item; + ret = 1; - for (item = pqueue_pop(ssl->d1->sent_messages); item != NULL; - item = pqueue_pop(ssl->d1->sent_messages)) { - dtls1_hm_fragment_free((hm_fragment *)item->data); - pitem_free(item); - } +err: + OPENSSL_free(packet); + return ret; } -/* don't actually do the writing, wait till the MTU has been retrieved */ -void dtls1_set_message_header(SSL *ssl, uint8_t mt, unsigned long len, - unsigned short seq_num, unsigned long frag_off, - unsigned long frag_len) { - struct hm_header_st *msg_hdr = &ssl->d1->w_msg_hdr; - - msg_hdr->type = mt; - msg_hdr->msg_len = len; - msg_hdr->seq = seq_num; - msg_hdr->frag_off = frag_off; - msg_hdr->frag_len = frag_len; +int dtls1_retransmit_outgoing_messages(SSL *ssl) { + /* Rewind to the start of the flight and write it again. + * + * TODO(davidben): This does not allow retransmits to be resumed on + * non-blocking write. */ + ssl->d1->outgoing_written = 0; + ssl->d1->outgoing_offset = 0; + + return dtls1_flush_flight(ssl); } unsigned int dtls1_min_mtu(void) { return kMinMTU; } - -void dtls1_get_message_header(uint8_t *data, - struct hm_header_st *msg_hdr) { - memset(msg_hdr, 0x00, sizeof(struct hm_header_st)); - msg_hdr->type = *(data++); - n2l3(data, msg_hdr->msg_len); - - n2s(data, msg_hdr->seq); - n2l3(data, msg_hdr->frag_off); - n2l3(data, msg_hdr->frag_len); -} diff --git a/Sources/BoringSSL/ssl/d1_clnt.c b/Sources/BoringSSL/ssl/d1_clnt.c deleted file mode 100644 index 7b311d621..000000000 --- a/Sources/BoringSSL/ssl/d1_clnt.c +++ /dev/null @@ -1,561 +0,0 @@ -/* - * DTLS implementation written by Nagendra Modadugu - * (nagendra@cs.stanford.edu) for the OpenSSL project 2005. - */ -/* ==================================================================== - * Copyright (c) 1999-2007 The OpenSSL Project. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the OpenSSL Project - * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" - * - * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to - * endorse or promote products derived from this software without - * prior written permission. For written permission, please contact - * openssl-core@OpenSSL.org. - * - * 5. Products derived from this software may not be called "OpenSSL" - * nor may "OpenSSL" appear in their names without prior written - * permission of the OpenSSL Project. - * - * 6. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the OpenSSL Project - * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" - * - * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This product includes cryptographic software written by Eric Young - * (eay@cryptsoft.com). This product includes software written by Tim - * Hudson (tjh@cryptsoft.com). - * - */ -/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) - * All rights reserved. - * - * This package is an SSL implementation written - * by Eric Young (eay@cryptsoft.com). - * The implementation was written so as to conform with Netscapes SSL. - * - * This library is free for commercial and non-commercial use as long as - * the following conditions are aheared to. The following conditions - * apply to all code found in this distribution, be it the RC4, RSA, - * lhash, DES, etc., code; not just the SSL code. The SSL documentation - * included with this distribution is covered by the same copyright terms - * except that the holder is Tim Hudson (tjh@cryptsoft.com). - * - * Copyright remains Eric Young's, and as such any Copyright notices in - * the code are not to be removed. - * If this package is used in a product, Eric Young should be given attribution - * as the author of the parts of the library used. - * This can be in the form of a textual message at program startup or - * in documentation (online or textual) provided with the package. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * "This product includes cryptographic software written by - * Eric Young (eay@cryptsoft.com)" - * The word 'cryptographic' can be left out if the rouines from the library - * being used are not cryptographic related :-). - * 4. If you include any Windows specific code (or a derivative thereof) from - * the apps directory (application code) you must include an acknowledgement: - * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" - * - * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * The licence and distribution terms for any publically available version or - * derivative of this code cannot be changed. i.e. this code cannot simply be - * copied and put under another distribution licence - * [including the GNU Public Licence.] - */ - -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "internal.h" - - -static int dtls1_get_hello_verify(SSL *ssl); - -int dtls1_connect(SSL *ssl) { - BUF_MEM *buf = NULL; - void (*cb)(const SSL *ssl, int type, int value) = NULL; - int ret = -1; - int new_state, state, skip = 0; - - assert(ssl->handshake_func == dtls1_connect); - assert(!ssl->server); - assert(SSL_IS_DTLS(ssl)); - - ERR_clear_error(); - ERR_clear_system_error(); - - if (ssl->info_callback != NULL) { - cb = ssl->info_callback; - } else if (ssl->ctx->info_callback != NULL) { - cb = ssl->ctx->info_callback; - } - - ssl->in_handshake++; - - for (;;) { - state = ssl->state; - - switch (ssl->state) { - case SSL_ST_CONNECT: - if (cb != NULL) { - cb(ssl, SSL_CB_HANDSHAKE_START, 1); - } - - if (ssl->init_buf == NULL) { - buf = BUF_MEM_new(); - if (buf == NULL || - !BUF_MEM_grow(buf, SSL3_RT_MAX_PLAIN_LENGTH)) { - ret = -1; - goto end; - } - ssl->init_buf = buf; - buf = NULL; - } - - if (!ssl_init_wbio_buffer(ssl, 0)) { - ret = -1; - goto end; - } - - /* don't push the buffering BIO quite yet */ - - ssl->state = SSL3_ST_CW_CLNT_HELLO_A; - ssl->init_num = 0; - ssl->d1->send_cookie = 0; - ssl->hit = 0; - break; - - case SSL3_ST_CW_CLNT_HELLO_A: - case SSL3_ST_CW_CLNT_HELLO_B: - ssl->shutdown = 0; - dtls1_start_timer(ssl); - ret = ssl3_send_client_hello(ssl); - if (ret <= 0) { - goto end; - } - - if (ssl->d1->send_cookie) { - ssl->state = SSL3_ST_CW_FLUSH; - ssl->s3->tmp.next_state = SSL3_ST_CR_SRVR_HELLO_A; - } else { - ssl->state = DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A; - } - - ssl->init_num = 0; - /* turn on buffering for the next lot of output */ - if (ssl->bbio != ssl->wbio) { - ssl->wbio = BIO_push(ssl->bbio, ssl->wbio); - } - - break; - - case DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A: - case DTLS1_ST_CR_HELLO_VERIFY_REQUEST_B: - ret = dtls1_get_hello_verify(ssl); - if (ret <= 0) { - goto end; - } - if (ssl->d1->send_cookie) { - /* start again, with a cookie */ - dtls1_stop_timer(ssl); - ssl->state = SSL3_ST_CW_CLNT_HELLO_A; - } else { - ssl->state = SSL3_ST_CR_SRVR_HELLO_A; - } - ssl->init_num = 0; - break; - - case SSL3_ST_CR_SRVR_HELLO_A: - case SSL3_ST_CR_SRVR_HELLO_B: - ret = ssl3_get_server_hello(ssl); - if (ret <= 0) { - goto end; - } - - if (ssl->hit) { - ssl->state = SSL3_ST_CR_CHANGE; - if (ssl->tlsext_ticket_expected) { - /* receive renewed session ticket */ - ssl->state = SSL3_ST_CR_SESSION_TICKET_A; - } - } else { - ssl->state = SSL3_ST_CR_CERT_A; - } - ssl->init_num = 0; - break; - - case SSL3_ST_CR_CERT_A: - case SSL3_ST_CR_CERT_B: - if (ssl_cipher_has_server_public_key(ssl->s3->tmp.new_cipher)) { - ret = ssl3_get_server_certificate(ssl); - if (ret <= 0) { - goto end; - } - if (ssl->s3->tmp.certificate_status_expected) { - ssl->state = SSL3_ST_CR_CERT_STATUS_A; - } else { - ssl->state = SSL3_ST_VERIFY_SERVER_CERT; - } - } else { - skip = 1; - ssl->state = SSL3_ST_CR_KEY_EXCH_A; - } - ssl->init_num = 0; - break; - - case SSL3_ST_VERIFY_SERVER_CERT: - ret = ssl3_verify_server_cert(ssl); - if (ret <= 0) { - goto end; - } - - ssl->state = SSL3_ST_CR_KEY_EXCH_A; - ssl->init_num = 0; - break; - - case SSL3_ST_CR_KEY_EXCH_A: - case SSL3_ST_CR_KEY_EXCH_B: - ret = ssl3_get_server_key_exchange(ssl); - if (ret <= 0) { - goto end; - } - ssl->state = SSL3_ST_CR_CERT_REQ_A; - ssl->init_num = 0; - break; - - case SSL3_ST_CR_CERT_REQ_A: - case SSL3_ST_CR_CERT_REQ_B: - ret = ssl3_get_certificate_request(ssl); - if (ret <= 0) { - goto end; - } - ssl->state = SSL3_ST_CR_SRVR_DONE_A; - ssl->init_num = 0; - break; - - case SSL3_ST_CR_SRVR_DONE_A: - case SSL3_ST_CR_SRVR_DONE_B: - ret = ssl3_get_server_done(ssl); - if (ret <= 0) { - goto end; - } - dtls1_stop_timer(ssl); - if (ssl->s3->tmp.cert_req) { - ssl->s3->tmp.next_state = SSL3_ST_CW_CERT_A; - } else { - ssl->s3->tmp.next_state = SSL3_ST_CW_KEY_EXCH_A; - } - ssl->init_num = 0; - ssl->state = ssl->s3->tmp.next_state; - break; - - case SSL3_ST_CW_CERT_A: - case SSL3_ST_CW_CERT_B: - case SSL3_ST_CW_CERT_C: - case SSL3_ST_CW_CERT_D: - dtls1_start_timer(ssl); - ret = ssl3_send_client_certificate(ssl); - if (ret <= 0) { - goto end; - } - ssl->state = SSL3_ST_CW_KEY_EXCH_A; - ssl->init_num = 0; - break; - - case SSL3_ST_CW_KEY_EXCH_A: - case SSL3_ST_CW_KEY_EXCH_B: - dtls1_start_timer(ssl); - ret = ssl3_send_client_key_exchange(ssl); - if (ret <= 0) { - goto end; - } - /* For TLS, cert_req is set to 2, so a cert chain - * of nothing is sent, but no verify packet is sent */ - if (ssl->s3->tmp.cert_req == 1) { - ssl->state = SSL3_ST_CW_CERT_VRFY_A; - } else { - ssl->state = SSL3_ST_CW_CHANGE_A; - } - - ssl->init_num = 0; - break; - - case SSL3_ST_CW_CERT_VRFY_A: - case SSL3_ST_CW_CERT_VRFY_B: - case SSL3_ST_CW_CERT_VRFY_C: - dtls1_start_timer(ssl); - ret = ssl3_send_cert_verify(ssl); - if (ret <= 0) { - goto end; - } - ssl->state = SSL3_ST_CW_CHANGE_A; - ssl->init_num = 0; - break; - - case SSL3_ST_CW_CHANGE_A: - case SSL3_ST_CW_CHANGE_B: - if (!ssl->hit) { - dtls1_start_timer(ssl); - } - ret = dtls1_send_change_cipher_spec(ssl, SSL3_ST_CW_CHANGE_A, - SSL3_ST_CW_CHANGE_B); - if (ret <= 0) { - goto end; - } - - ssl->state = SSL3_ST_CW_FINISHED_A; - ssl->init_num = 0; - - if (!tls1_change_cipher_state(ssl, SSL3_CHANGE_CIPHER_CLIENT_WRITE)) { - ret = -1; - goto end; - } - break; - - case SSL3_ST_CW_FINISHED_A: - case SSL3_ST_CW_FINISHED_B: - if (!ssl->hit) { - dtls1_start_timer(ssl); - } - - ret = ssl3_send_finished(ssl, SSL3_ST_CW_FINISHED_A, - SSL3_ST_CW_FINISHED_B); - if (ret <= 0) { - goto end; - } - ssl->state = SSL3_ST_CW_FLUSH; - - if (ssl->hit) { - ssl->s3->tmp.next_state = SSL_ST_OK; - } else { - /* Allow NewSessionTicket if ticket expected */ - if (ssl->tlsext_ticket_expected) { - ssl->s3->tmp.next_state = SSL3_ST_CR_SESSION_TICKET_A; - } else { - ssl->s3->tmp.next_state = SSL3_ST_CR_CHANGE; - } - } - ssl->init_num = 0; - break; - - case SSL3_ST_CR_SESSION_TICKET_A: - case SSL3_ST_CR_SESSION_TICKET_B: - ret = ssl3_get_new_session_ticket(ssl); - if (ret <= 0) { - goto end; - } - ssl->state = SSL3_ST_CR_CHANGE; - ssl->init_num = 0; - break; - - case SSL3_ST_CR_CERT_STATUS_A: - case SSL3_ST_CR_CERT_STATUS_B: - ret = ssl3_get_cert_status(ssl); - if (ret <= 0) { - goto end; - } - ssl->state = SSL3_ST_VERIFY_SERVER_CERT; - ssl->init_num = 0; - break; - - case SSL3_ST_CR_CHANGE: - ret = ssl->method->ssl_read_change_cipher_spec(ssl); - if (ret <= 0) { - goto end; - } - - if (!tls1_change_cipher_state(ssl, SSL3_CHANGE_CIPHER_CLIENT_READ)) { - ret = -1; - goto end; - } - ssl->state = SSL3_ST_CR_FINISHED_A; - break; - - case SSL3_ST_CR_FINISHED_A: - case SSL3_ST_CR_FINISHED_B: - ret = - ssl3_get_finished(ssl, SSL3_ST_CR_FINISHED_A, SSL3_ST_CR_FINISHED_B); - if (ret <= 0) { - goto end; - } - dtls1_stop_timer(ssl); - - if (ssl->hit) { - ssl->state = SSL3_ST_CW_CHANGE_A; - } else { - ssl->state = SSL_ST_OK; - } - - ssl->init_num = 0; - break; - - case SSL3_ST_CW_FLUSH: - ssl->rwstate = SSL_WRITING; - if (BIO_flush(ssl->wbio) <= 0) { - ret = -1; - goto end; - } - ssl->rwstate = SSL_NOTHING; - ssl->state = ssl->s3->tmp.next_state; - break; - - case SSL_ST_OK: - /* clean a few things up */ - ssl3_cleanup_key_block(ssl); - - /* Remove write buffering now. */ - ssl_free_wbio_buffer(ssl); - - ssl->init_num = 0; - ssl->s3->initial_handshake_complete = 1; - - ssl_update_cache(ssl, SSL_SESS_CACHE_CLIENT); - - ret = 1; - - if (cb != NULL) { - cb(ssl, SSL_CB_HANDSHAKE_DONE, 1); - } - - /* done with handshaking */ - ssl->d1->handshake_read_seq = 0; - ssl->d1->next_handshake_write_seq = 0; - goto end; - - default: - OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_STATE); - ret = -1; - goto end; - } - - /* did we do anything? */ - if (!ssl->s3->tmp.reuse_message && !skip) { - if ((cb != NULL) && (ssl->state != state)) { - new_state = ssl->state; - ssl->state = state; - cb(ssl, SSL_CB_CONNECT_LOOP, 1); - ssl->state = new_state; - } - } - skip = 0; - } - -end: - ssl->in_handshake--; - - BUF_MEM_free(buf); - if (cb != NULL) { - cb(ssl, SSL_CB_CONNECT_EXIT, ret); - } - return ret; -} - -static int dtls1_get_hello_verify(SSL *ssl) { - long n; - int al, ok = 0; - CBS hello_verify_request, cookie; - uint16_t server_version; - - n = ssl->method->ssl_get_message( - ssl, DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A, - DTLS1_ST_CR_HELLO_VERIFY_REQUEST_B, -1, - /* Use the same maximum size as ssl3_get_server_hello. */ - 20000, ssl_hash_message, &ok); - - if (!ok) { - return n; - } - - if (ssl->s3->tmp.message_type != DTLS1_MT_HELLO_VERIFY_REQUEST) { - ssl->d1->send_cookie = 0; - ssl->s3->tmp.reuse_message = 1; - return 1; - } - - CBS_init(&hello_verify_request, ssl->init_msg, n); - - if (!CBS_get_u16(&hello_verify_request, &server_version) || - !CBS_get_u8_length_prefixed(&hello_verify_request, &cookie) || - CBS_len(&hello_verify_request) != 0) { - al = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); - goto f_err; - } - - if (CBS_len(&cookie) > sizeof(ssl->d1->cookie)) { - al = SSL_AD_ILLEGAL_PARAMETER; - goto f_err; - } - - memcpy(ssl->d1->cookie, CBS_data(&cookie), CBS_len(&cookie)); - ssl->d1->cookie_len = CBS_len(&cookie); - - ssl->d1->send_cookie = 1; - return 1; - -f_err: - ssl3_send_alert(ssl, SSL3_AL_FATAL, al); - return -1; -} diff --git a/Sources/BoringSSL/ssl/d1_lib.c b/Sources/BoringSSL/ssl/d1_lib.c index 81079f485..258e9ab29 100644 --- a/Sources/BoringSSL/ssl/d1_lib.c +++ b/Sources/BoringSSL/ssl/d1_lib.c @@ -56,22 +56,17 @@ #include +#include #include -#include #include #include #include -#include +#include +#include "../crypto/internal.h" #include "internal.h" -#if defined(OPENSSL_WINDOWS) -#include -#else -#include -#include -#endif /* DTLS1_MTU_TIMEOUTS is the maximum number of timeouts to expire @@ -82,8 +77,6 @@ * before failing the DTLS handshake. */ #define DTLS1_MAX_TIMEOUTS 12 -static void get_current_time(const SSL *ssl, struct timeval *out_clock); - int dtls1_new(SSL *ssl) { DTLS1_STATE *d1; @@ -95,18 +88,7 @@ int dtls1_new(SSL *ssl) { ssl3_free(ssl); return 0; } - memset(d1, 0, sizeof *d1); - - d1->buffered_messages = pqueue_new(); - d1->sent_messages = pqueue_new(); - - if (!d1->buffered_messages || !d1->sent_messages) { - pqueue_free(d1->buffered_messages); - pqueue_free(d1->sent_messages); - OPENSSL_free(d1); - ssl3_free(ssl); - return 0; - } + OPENSSL_memset(d1, 0, sizeof *d1); ssl->d1 = d1; @@ -119,23 +101,6 @@ int dtls1_new(SSL *ssl) { return 1; } -static void dtls1_clear_queues(SSL *ssl) { - pitem *item = NULL; - hm_fragment *frag = NULL; - - while ((item = pqueue_pop(ssl->d1->buffered_messages)) != NULL) { - frag = (hm_fragment *)item->data; - dtls1_hm_fragment_free(frag); - pitem_free(item); - } - - while ((item = pqueue_pop(ssl->d1->sent_messages)) != NULL) { - frag = (hm_fragment *)item->data; - dtls1_hm_fragment_free(frag); - pitem_free(item); - } -} - void dtls1_free(SSL *ssl) { ssl3_free(ssl); @@ -143,38 +108,39 @@ void dtls1_free(SSL *ssl) { return; } - dtls1_clear_queues(ssl); - - pqueue_free(ssl->d1->buffered_messages); - pqueue_free(ssl->d1->sent_messages); + dtls_clear_incoming_messages(ssl); + dtls_clear_outgoing_messages(ssl); OPENSSL_free(ssl->d1); ssl->d1 = NULL; } -int dtls1_supports_cipher(const SSL_CIPHER *cipher) { - /* DTLS does not support stream ciphers. The NULL cipher is rejected because - * it's not needed. */ - return cipher->algorithm_enc != SSL_RC4 && cipher->algorithm_enc != SSL_eNULL; +void DTLSv1_set_initial_timeout_duration(SSL *ssl, unsigned int duration_ms) { + ssl->initial_timeout_duration_ms = duration_ms; } void dtls1_start_timer(SSL *ssl) { - /* If timer is not set, initialize duration with 1 second */ + /* If timer is not set, initialize duration (by default, 1 second) */ if (ssl->d1->next_timeout.tv_sec == 0 && ssl->d1->next_timeout.tv_usec == 0) { - ssl->d1->timeout_duration = 1; + ssl->d1->timeout_duration_ms = ssl->initial_timeout_duration_ms; } /* Set timeout to current time */ - get_current_time(ssl, &ssl->d1->next_timeout); + ssl_get_current_time(ssl, &ssl->d1->next_timeout); /* Add duration to current time */ - ssl->d1->next_timeout.tv_sec += ssl->d1->timeout_duration; - BIO_ctrl(SSL_get_rbio(ssl), BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT, 0, + ssl->d1->next_timeout.tv_sec += ssl->d1->timeout_duration_ms / 1000; + ssl->d1->next_timeout.tv_usec += (ssl->d1->timeout_duration_ms % 1000) * 1000; + if (ssl->d1->next_timeout.tv_usec >= 1000000) { + ssl->d1->next_timeout.tv_sec++; + ssl->d1->next_timeout.tv_usec -= 1000000; + } + BIO_ctrl(ssl->rbio, BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT, 0, &ssl->d1->next_timeout); } int DTLSv1_get_timeout(const SSL *ssl, struct timeval *out) { - if (!SSL_IS_DTLS(ssl)) { + if (!SSL_is_dtls(ssl)) { return 0; } @@ -183,20 +149,19 @@ int DTLSv1_get_timeout(const SSL *ssl, struct timeval *out) { return 0; } - /* Get current time */ struct timeval timenow; - get_current_time(ssl, &timenow); + ssl_get_current_time(ssl, &timenow); /* If timer already expired, set remaining time to 0 */ if (ssl->d1->next_timeout.tv_sec < timenow.tv_sec || (ssl->d1->next_timeout.tv_sec == timenow.tv_sec && ssl->d1->next_timeout.tv_usec <= timenow.tv_usec)) { - memset(out, 0, sizeof(struct timeval)); + OPENSSL_memset(out, 0, sizeof(struct timeval)); return 1; } /* Calculate time left until timer expires */ - memcpy(out, &ssl->d1->next_timeout, sizeof(struct timeval)); + OPENSSL_memcpy(out, &ssl->d1->next_timeout, sizeof(struct timeval)); out->tv_sec -= timenow.tv_sec; out->tv_usec -= timenow.tv_usec; if (out->tv_usec < 0) { @@ -207,7 +172,7 @@ int DTLSv1_get_timeout(const SSL *ssl, struct timeval *out) { /* If remaining time is less than 15 ms, set it to 0 to prevent issues * because of small devergences with socket timeouts. */ if (out->tv_sec == 0 && out->tv_usec < 15000) { - memset(out, 0, sizeof(struct timeval)); + OPENSSL_memset(out, 0, sizeof(struct timeval)); } return 1; @@ -231,9 +196,9 @@ int dtls1_is_timer_expired(SSL *ssl) { } void dtls1_double_timeout(SSL *ssl) { - ssl->d1->timeout_duration *= 2; - if (ssl->d1->timeout_duration > 60) { - ssl->d1->timeout_duration = 60; + ssl->d1->timeout_duration_ms *= 2; + if (ssl->d1->timeout_duration_ms > 60000) { + ssl->d1->timeout_duration_ms = 60000; } dtls1_start_timer(ssl); } @@ -241,12 +206,12 @@ void dtls1_double_timeout(SSL *ssl) { void dtls1_stop_timer(SSL *ssl) { /* Reset everything */ ssl->d1->num_timeouts = 0; - memset(&ssl->d1->next_timeout, 0, sizeof(struct timeval)); - ssl->d1->timeout_duration = 1; - BIO_ctrl(SSL_get_rbio(ssl), BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT, 0, + OPENSSL_memset(&ssl->d1->next_timeout, 0, sizeof(struct timeval)); + ssl->d1->timeout_duration_ms = ssl->initial_timeout_duration_ms; + BIO_ctrl(ssl->rbio, BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT, 0, &ssl->d1->next_timeout); /* Clear retransmission buffer */ - dtls1_clear_record_buffer(ssl); + dtls_clear_outgoing_messages(ssl); } int dtls1_check_timeout_num(SSL *ssl) { @@ -255,8 +220,7 @@ int dtls1_check_timeout_num(SSL *ssl) { /* Reduce MTU after 2 unsuccessful retransmissions */ if (ssl->d1->num_timeouts > DTLS1_MTU_TIMEOUTS && !(SSL_get_options(ssl) & SSL_OP_NO_QUERY_MTU)) { - long mtu = BIO_ctrl(SSL_get_wbio(ssl), BIO_CTRL_DGRAM_GET_FALLBACK_MTU, 0, - NULL); + long mtu = BIO_ctrl(ssl->wbio, BIO_CTRL_DGRAM_GET_FALLBACK_MTU, 0, NULL); if (mtu >= 0 && mtu <= (1 << 30) && (unsigned)mtu >= dtls1_min_mtu()) { ssl->d1->mtu = (unsigned)mtu; } @@ -272,7 +236,9 @@ int dtls1_check_timeout_num(SSL *ssl) { } int DTLSv1_handle_timeout(SSL *ssl) { - if (!SSL_IS_DTLS(ssl)) { + ssl_reset_error_state(ssl); + + if (!SSL_is_dtls(ssl)) { return -1; } @@ -288,54 +254,5 @@ int DTLSv1_handle_timeout(SSL *ssl) { } dtls1_start_timer(ssl); - return dtls1_retransmit_buffered_messages(ssl); -} - -static void get_current_time(const SSL *ssl, struct timeval *out_clock) { - if (ssl->ctx->current_time_cb != NULL) { - ssl->ctx->current_time_cb(ssl, out_clock); - return; - } - -#if defined(OPENSSL_WINDOWS) - struct _timeb time; - _ftime(&time); - out_clock->tv_sec = time.time; - out_clock->tv_usec = time.millitm * 1000; -#else - gettimeofday(out_clock, NULL); -#endif -} - -int dtls1_set_handshake_header(SSL *ssl, int htype, unsigned long len) { - uint8_t *message = (uint8_t *)ssl->init_buf->data; - const struct hm_header_st *msg_hdr = &ssl->d1->w_msg_hdr; - uint8_t serialised_header[DTLS1_HM_HEADER_LENGTH]; - uint8_t *p = serialised_header; - - ssl->d1->handshake_write_seq = ssl->d1->next_handshake_write_seq; - ssl->d1->next_handshake_write_seq++; - - dtls1_set_message_header(ssl, htype, len, ssl->d1->handshake_write_seq, 0, - len); - ssl->init_num = (int)len + DTLS1_HM_HEADER_LENGTH; - ssl->init_off = 0; - - /* Buffer the message to handle re-xmits */ - dtls1_buffer_message(ssl); - - /* Add the new message to the handshake hash. Serialize the message - * header as if it were a single fragment. */ - *p++ = msg_hdr->type; - l2n3(msg_hdr->msg_len, p); - s2n(msg_hdr->seq, p); - l2n3(0, p); - l2n3(msg_hdr->msg_len, p); - return ssl3_update_handshake_hash(ssl, serialised_header, - sizeof(serialised_header)) && - ssl3_update_handshake_hash(ssl, message + DTLS1_HM_HEADER_LENGTH, len); -} - -int dtls1_handshake_write(SSL *ssl) { - return dtls1_do_handshake_write(ssl, dtls1_use_current_epoch); + return dtls1_retransmit_outgoing_messages(ssl); } diff --git a/Sources/BoringSSL/ssl/d1_pkt.c b/Sources/BoringSSL/ssl/d1_pkt.c index 7b7b2b0fa..27b2763ac 100644 --- a/Sources/BoringSSL/ssl/d1_pkt.c +++ b/Sources/BoringSSL/ssl/d1_pkt.c @@ -112,72 +112,85 @@ #include #include -#include #include +#include #include +#include #include #include #include #include +#include "../crypto/internal.h" #include "internal.h" -static int do_dtls1_write(SSL *ssl, int type, const uint8_t *buf, - unsigned int len, enum dtls1_use_epoch_t use_epoch); - -/* dtls1_get_record reads a new input record. On success, it places it in - * |ssl->s3->rrec| and returns one. Otherwise it returns <= 0 on error or if - * more data is needed. */ -static int dtls1_get_record(SSL *ssl) { +int dtls1_get_record(SSL *ssl) { again: + switch (ssl->s3->recv_shutdown) { + case ssl_shutdown_none: + break; + case ssl_shutdown_fatal_alert: + OPENSSL_PUT_ERROR(SSL, SSL_R_PROTOCOL_IS_SHUTDOWN); + return -1; + case ssl_shutdown_close_notify: + return 0; + } + /* Read a new packet if there is no unconsumed one. */ if (ssl_read_buffer_len(ssl) == 0) { - int ret = ssl_read_buffer_extend_to(ssl, 0 /* unused */); - if (ret <= 0) { - return ret; + int read_ret = ssl_read_buffer_extend_to(ssl, 0 /* unused */); + if (read_ret < 0 && dtls1_is_timer_expired(ssl)) { + /* For blocking BIOs, retransmits must be handled internally. */ + int timeout_ret = DTLSv1_handle_timeout(ssl); + if (timeout_ret <= 0) { + return timeout_ret; + } + goto again; + } + if (read_ret <= 0) { + return read_ret; } } assert(ssl_read_buffer_len(ssl) > 0); - /* Ensure the packet is large enough to decrypt in-place. */ - if (ssl_read_buffer_len(ssl) < ssl_record_prefix_len(ssl)) { - ssl_read_buffer_clear(ssl); - goto again; - } - - uint8_t *out = ssl_read_buffer(ssl) + ssl_record_prefix_len(ssl); - size_t max_out = ssl_read_buffer_len(ssl) - ssl_record_prefix_len(ssl); + CBS body; uint8_t type, alert; - size_t len, consumed; - switch (dtls_open_record(ssl, &type, out, &len, &consumed, &alert, max_out, - ssl_read_buffer(ssl), ssl_read_buffer_len(ssl))) { - case ssl_open_record_success: - ssl_read_buffer_consume(ssl, consumed); + size_t consumed; + enum ssl_open_record_t open_ret = + dtls_open_record(ssl, &type, &body, &consumed, &alert, + ssl_read_buffer(ssl), ssl_read_buffer_len(ssl)); + ssl_read_buffer_consume(ssl, consumed); + switch (open_ret) { + case ssl_open_record_partial: + /* Impossible in DTLS. */ + break; - if (len > 0xffff) { + case ssl_open_record_success: + if (CBS_len(&body) > 0xffff) { OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW); return -1; } SSL3_RECORD *rr = &ssl->s3->rrec; rr->type = type; - rr->length = (uint16_t)len; - rr->data = out; + rr->length = (uint16_t)CBS_len(&body); + rr->data = (uint8_t *)CBS_data(&body); return 1; case ssl_open_record_discard: - ssl_read_buffer_consume(ssl, consumed); goto again; + case ssl_open_record_close_notify: + return 0; + + case ssl_open_record_fatal_alert: + return -1; + case ssl_open_record_error: ssl3_send_alert(ssl, SSL3_AL_FATAL, alert); return -1; - - case ssl_open_record_partial: - /* Impossible in DTLS. */ - break; } assert(0); @@ -185,253 +198,36 @@ static int dtls1_get_record(SSL *ssl) { return -1; } -int dtls1_read_app_data(SSL *ssl, uint8_t *buf, int len, int peek) { - return dtls1_read_bytes(ssl, SSL3_RT_APPLICATION_DATA, buf, len, peek); -} - -int dtls1_read_change_cipher_spec(SSL *ssl) { - uint8_t byte; - int ret = dtls1_read_bytes(ssl, SSL3_RT_CHANGE_CIPHER_SPEC, &byte, - 1 /* len */, 0 /* no peek */); - if (ret <= 0) { - return ret; - } - assert(ret == 1); - - if (ssl->s3->rrec.length != 0 || byte != SSL3_MT_CCS) { - OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_CHANGE_CIPHER_SPEC); - ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER); - return -1; - } - - if (ssl->msg_callback != NULL) { - ssl->msg_callback(0, ssl->version, SSL3_RT_CHANGE_CIPHER_SPEC, &byte, 1, - ssl, ssl->msg_callback_arg); - } - - return 1; -} +int dtls1_read_app_data(SSL *ssl, int *out_got_handshake, uint8_t *buf, int len, + int peek) { + assert(!SSL_in_init(ssl)); -void dtls1_read_close_notify(SSL *ssl) { - /* Bidirectional shutdown doesn't make sense for an unordered transport. DTLS - * alerts also aren't delivered reliably, so we may even time out because the - * peer never received our close_notify. Report to the caller that the channel - * has fully shut down. */ - ssl->shutdown |= SSL_RECEIVED_SHUTDOWN; -} + *out_got_handshake = 0; + SSL3_RECORD *rr = &ssl->s3->rrec; -/* Return up to 'len' payload bytes received in 'type' records. - * 'type' is one of the following: - * - * - SSL3_RT_HANDSHAKE (when dtls1_get_message calls us) - * - SSL3_RT_CHANGE_CIPHER_SPEC (when dtls1_read_change_cipher_spec calls us) - * - SSL3_RT_APPLICATION_DATA (when dtls1_read_app_data calls us) - * - * If we don't have stored data to work from, read a DTLS record first (possibly - * multiple records if we still don't have anything to return). - * - * This function must handle any surprises the peer may have for us, such as - * Alert records (e.g. close_notify) and out of records. */ -int dtls1_read_bytes(SSL *ssl, int type, unsigned char *buf, int len, int peek) { - int al, i, ret; - unsigned int n; - SSL3_RECORD *rr; - void (*cb)(const SSL *ssl, int type, int value) = NULL; - - if ((type != SSL3_RT_APPLICATION_DATA && type != SSL3_RT_HANDSHAKE && - type != SSL3_RT_CHANGE_CIPHER_SPEC) || - (peek && type != SSL3_RT_APPLICATION_DATA)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - return -1; - } - - if (!ssl->in_handshake && SSL_in_init(ssl)) { - /* type == SSL3_RT_APPLICATION_DATA */ - i = ssl->handshake_func(ssl); - if (i < 0) { - return i; - } - if (i == 0) { - OPENSSL_PUT_ERROR(SSL, SSL_R_SSL_HANDSHAKE_FAILURE); - return -1; - } - } - -start: - ssl->rwstate = SSL_NOTHING; - - /* ssl->s3->rrec.type - is the type of record - * ssl->s3->rrec.data - data - * ssl->s3->rrec.off - offset into 'data' for next read - * ssl->s3->rrec.length - number of bytes. */ - rr = &ssl->s3->rrec; - - /* Check for timeout */ - if (DTLSv1_handle_timeout(ssl) > 0) { - goto start; - } - - /* get new packet if necessary */ +again: if (rr->length == 0) { - ret = dtls1_get_record(ssl); + int ret = dtls1_get_record(ssl); if (ret <= 0) { - ret = dtls1_read_failed(ssl, ret); - /* anything other than a timeout is an error */ - if (ret <= 0) { - return ret; - } else { - goto start; - } - } - } - - /* we now have a packet which can be read and processed */ - - /* If the other end has shut down, throw anything we read away (even in - * 'peek' mode) */ - if (ssl->shutdown & SSL_RECEIVED_SHUTDOWN) { - rr->length = 0; - ssl->rwstate = SSL_NOTHING; - return 0; - } - - - if (type == rr->type) { - /* Make sure that we are not getting application data when we - * are doing a handshake for the first time. */ - if (SSL_in_init(ssl) && (type == SSL3_RT_APPLICATION_DATA) && - (ssl->s3->aead_read_ctx == NULL)) { - /* TODO(davidben): Is this check redundant with the handshake_func - * check? */ - al = SSL_AD_UNEXPECTED_MESSAGE; - OPENSSL_PUT_ERROR(SSL, SSL_R_APP_DATA_IN_HANDSHAKE); - goto f_err; - } - - /* Discard empty records. */ - if (rr->length == 0) { - goto start; - } - - if (len <= 0) { - return len; - } - - if ((unsigned int)len > rr->length) { - n = rr->length; - } else { - n = (unsigned int)len; - } - - memcpy(buf, rr->data, n); - if (!peek) { - rr->length -= n; - rr->data += n; - if (rr->length == 0) { - /* The record has been consumed, so we may now clear the buffer. */ - ssl_read_buffer_discard(ssl); - } - } - - return n; - } - - /* If we get here, then type != rr->type. */ - - /* If an alert record, process one alert out of the record. Note that we allow - * a single record to contain multiple alerts. */ - if (rr->type == SSL3_RT_ALERT) { - /* Alerts may not be fragmented. */ - if (rr->length < 2) { - al = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ALERT); - goto f_err; - } - - if (ssl->msg_callback) { - ssl->msg_callback(0, ssl->version, SSL3_RT_ALERT, rr->data, 2, ssl, - ssl->msg_callback_arg); - } - const uint8_t alert_level = rr->data[0]; - const uint8_t alert_descr = rr->data[1]; - rr->length -= 2; - rr->data += 2; - - if (ssl->info_callback != NULL) { - cb = ssl->info_callback; - } else if (ssl->ctx->info_callback != NULL) { - cb = ssl->ctx->info_callback; - } - - if (cb != NULL) { - uint16_t alert = (alert_level << 8) | alert_descr; - cb(ssl, SSL_CB_READ_ALERT, alert); - } - - if (alert_level == SSL3_AL_WARNING) { - ssl->s3->warn_alert = alert_descr; - if (alert_descr == SSL_AD_CLOSE_NOTIFY) { - ssl->shutdown |= SSL_RECEIVED_SHUTDOWN; - return 0; - } - } else if (alert_level == SSL3_AL_FATAL) { - char tmp[16]; - - ssl->rwstate = SSL_NOTHING; - ssl->s3->fatal_alert = alert_descr; - OPENSSL_PUT_ERROR(SSL, SSL_AD_REASON_OFFSET + alert_descr); - BIO_snprintf(tmp, sizeof tmp, "%d", alert_descr); - ERR_add_error_data(2, "SSL alert number ", tmp); - ssl->shutdown |= SSL_RECEIVED_SHUTDOWN; - SSL_CTX_remove_session(ssl->ctx, ssl->session); - return 0; - } else { - al = SSL_AD_ILLEGAL_PARAMETER; - OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_ALERT_TYPE); - goto f_err; + return ret; } - - goto start; - } - - /* Cross-epoch records are discarded, but we may receive out-of-order - * application data between ChangeCipherSpec and Finished or a ChangeCipherSpec - * before the appropriate point in the handshake. Those must be silently - * discarded. - * - * However, only allow the out-of-order records in the correct epoch. - * Application data must come in the encrypted epoch, and ChangeCipherSpec in - * the unencrypted epoch (we never renegotiate). Other cases fall through and - * fail with a fatal error. */ - if ((rr->type == SSL3_RT_APPLICATION_DATA && - ssl->s3->aead_read_ctx != NULL) || - (rr->type == SSL3_RT_CHANGE_CIPHER_SPEC && - ssl->s3->aead_read_ctx == NULL)) { - rr->length = 0; - goto start; } if (rr->type == SSL3_RT_HANDSHAKE) { - if (type != SSL3_RT_APPLICATION_DATA) { - /* Out-of-order handshake record while looking for ChangeCipherSpec. Drop - * it silently. */ - assert(type == SSL3_RT_CHANGE_CIPHER_SPEC); - rr->length = 0; - goto start; - } - /* Parse the first fragment header to determine if this is a pre-CCS or * post-CCS handshake record. DTLS resets handshake message numbers on each * handshake, so renegotiations and retransmissions are ambiguous. */ - if (rr->length < DTLS1_HM_HEADER_LENGTH) { - al = SSL_AD_DECODE_ERROR; + CBS cbs, body; + struct hm_header_st msg_hdr; + CBS_init(&cbs, rr->data, rr->length); + if (!dtls1_parse_fragment(&cbs, &msg_hdr, &body)) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_HANDSHAKE_RECORD); - goto f_err; + return -1; } - struct hm_header_st msg_hdr; - dtls1_get_message_header(rr->data, &msg_hdr); - if (msg_hdr.type == SSL3_MT_FINISHED) { + if (msg_hdr.type == SSL3_MT_FINISHED && + msg_hdr.seq == ssl->d1->handshake_read_seq - 1) { if (msg_hdr.frag_off == 0) { /* Retransmit our last flight of messages. If the peer sends the second * Finished, they may not have received ours. Only do this for the @@ -440,87 +236,140 @@ int dtls1_read_bytes(SSL *ssl, int type, unsigned char *buf, int len, int peek) return -1; } - dtls1_retransmit_buffered_messages(ssl); + dtls1_retransmit_outgoing_messages(ssl); } rr->length = 0; - goto start; + goto again; } /* Otherwise, this is a pre-CCS handshake message from an unsupported * renegotiation attempt. Fall through to the error path. */ } - al = SSL_AD_UNEXPECTED_MESSAGE; - OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_RECORD); + if (rr->type != SSL3_RT_APPLICATION_DATA) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE); + OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_RECORD); + return -1; + } -f_err: - ssl3_send_alert(ssl, SSL3_AL_FATAL, al); - return -1; -} + /* Discard empty records. */ + if (rr->length == 0) { + goto again; + } + + if (len <= 0) { + return len; + } -int dtls1_write_app_data(SSL *ssl, const void *buf_, int len) { - int i; + if ((unsigned)len > rr->length) { + len = rr->length; + } - if (SSL_in_init(ssl) && !ssl->in_handshake) { - i = ssl->handshake_func(ssl); - if (i < 0) { - return i; + OPENSSL_memcpy(buf, rr->data, len); + if (!peek) { + /* TODO(davidben): Should the record be truncated instead? This is a + * datagram transport. See https://crbug.com/boringssl/65. */ + rr->length -= len; + rr->data += len; + if (rr->length == 0) { + /* The record has been consumed, so we may now clear the buffer. */ + ssl_read_buffer_discard(ssl); } - if (i == 0) { - OPENSSL_PUT_ERROR(SSL, SSL_R_SSL_HANDSHAKE_FAILURE); - return -1; + } + + return len; +} + +int dtls1_read_change_cipher_spec(SSL *ssl) { + SSL3_RECORD *rr = &ssl->s3->rrec; + +again: + if (rr->length == 0) { + int ret = dtls1_get_record(ssl); + if (ret <= 0) { + return ret; } } + /* Drop handshake records silently. The epochs match, so this must be a + * retransmit of a message we already received. */ + if (rr->type == SSL3_RT_HANDSHAKE) { + rr->length = 0; + goto again; + } + + /* Other record types are illegal in this epoch. Note all application data + * records come in the encrypted epoch. */ + if (rr->type != SSL3_RT_CHANGE_CIPHER_SPEC) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE); + OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_RECORD); + return -1; + } + + if (rr->length != 1 || rr->data[0] != SSL3_MT_CCS) { + OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_CHANGE_CIPHER_SPEC); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER); + return -1; + } + + ssl_do_msg_callback(ssl, 0 /* read */, SSL3_RT_CHANGE_CIPHER_SPEC, rr->data, + rr->length); + + rr->length = 0; + ssl_read_buffer_discard(ssl); + return 1; +} + +void dtls1_read_close_notify(SSL *ssl) { + /* Bidirectional shutdown doesn't make sense for an unordered transport. DTLS + * alerts also aren't delivered reliably, so we may even time out because the + * peer never received our close_notify. Report to the caller that the channel + * has fully shut down. */ + if (ssl->s3->recv_shutdown == ssl_shutdown_none) { + ssl->s3->recv_shutdown = ssl_shutdown_close_notify; + } +} + +int dtls1_write_app_data(SSL *ssl, const uint8_t *buf, int len) { + assert(!SSL_in_init(ssl)); + if (len > SSL3_RT_MAX_PLAIN_LENGTH) { OPENSSL_PUT_ERROR(SSL, SSL_R_DTLS_MESSAGE_TOO_BIG); return -1; } - i = dtls1_write_bytes(ssl, SSL3_RT_APPLICATION_DATA, buf_, len, - dtls1_use_current_epoch); - return i; -} + if (len < 0) { + OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_LENGTH); + return -1; + } -/* Call this to write data in records of type 'type' It will return <= 0 if not - * all data has been sent or non-blocking IO. */ -int dtls1_write_bytes(SSL *ssl, int type, const void *buf, int len, - enum dtls1_use_epoch_t use_epoch) { - int i; + if (len == 0) { + return 0; + } - assert(len <= SSL3_RT_MAX_PLAIN_LENGTH); - ssl->rwstate = SSL_NOTHING; - i = do_dtls1_write(ssl, type, buf, len, use_epoch); - return i; + int ret = dtls1_write_record(ssl, SSL3_RT_APPLICATION_DATA, buf, (size_t)len, + dtls1_use_current_epoch); + if (ret <= 0) { + return ret; + } + return len; } -static int do_dtls1_write(SSL *ssl, int type, const uint8_t *buf, - unsigned int len, enum dtls1_use_epoch_t use_epoch) { +int dtls1_write_record(SSL *ssl, int type, const uint8_t *buf, size_t len, + enum dtls1_use_epoch_t use_epoch) { + assert(len <= SSL3_RT_MAX_PLAIN_LENGTH); /* There should never be a pending write buffer in DTLS. One can't write half * a datagram, so the write buffer is always dropped in * |ssl_write_buffer_flush|. */ assert(!ssl_write_buffer_is_pending(ssl)); - /* If we have an alert to send, lets send it */ - if (ssl->s3->alert_dispatch) { - int ret = ssl->method->ssl_dispatch_alert(ssl); - if (ret <= 0) { - return ret; - } - /* if it went, fall through and send more stuff */ - } - if (len > SSL3_RT_MAX_PLAIN_LENGTH) { OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); return -1; } - if (len == 0) { - return 0; - } - - size_t max_out = len + ssl_max_seal_overhead(ssl); + size_t max_out = len + SSL_max_seal_overhead(ssl); uint8_t *out; size_t ciphertext_len; if (!ssl_write_buffer_init(ssl, &out, max_out) || @@ -535,46 +384,27 @@ static int do_dtls1_write(SSL *ssl, int type, const uint8_t *buf, if (ret <= 0) { return ret; } - return (int)len; + return 1; } int dtls1_dispatch_alert(SSL *ssl) { - int i, j; - void (*cb)(const SSL *ssl, int type, int value) = NULL; - uint8_t buf[DTLS1_AL_HEADER_LENGTH]; - uint8_t *ptr = &buf[0]; - + int ret = dtls1_write_record(ssl, SSL3_RT_ALERT, &ssl->s3->send_alert[0], 2, + dtls1_use_current_epoch); + if (ret <= 0) { + return ret; + } ssl->s3->alert_dispatch = 0; - memset(buf, 0x00, sizeof(buf)); - *ptr++ = ssl->s3->send_alert[0]; - *ptr++ = ssl->s3->send_alert[1]; - - i = do_dtls1_write(ssl, SSL3_RT_ALERT, &buf[0], sizeof(buf), - dtls1_use_current_epoch); - if (i <= 0) { - ssl->s3->alert_dispatch = 1; - } else { - if (ssl->s3->send_alert[0] == SSL3_AL_FATAL) { - (void)BIO_flush(ssl->wbio); - } - - if (ssl->msg_callback) { - ssl->msg_callback(1, ssl->version, SSL3_RT_ALERT, ssl->s3->send_alert, 2, - ssl, ssl->msg_callback_arg); - } + /* If the alert is fatal, flush the BIO now. */ + if (ssl->s3->send_alert[0] == SSL3_AL_FATAL) { + BIO_flush(ssl->wbio); + } - if (ssl->info_callback != NULL) { - cb = ssl->info_callback; - } else if (ssl->ctx->info_callback != NULL) { - cb = ssl->ctx->info_callback; - } + ssl_do_msg_callback(ssl, 1 /* write */, SSL3_RT_ALERT, ssl->s3->send_alert, + 2); - if (cb != NULL) { - j = (ssl->s3->send_alert[0] << 8) | ssl->s3->send_alert[1]; - cb(ssl, SSL_CB_WRITE_ALERT, j); - } - } + int alert = (ssl->s3->send_alert[0] << 8) | ssl->s3->send_alert[1]; + ssl_do_info_callback(ssl, SSL_CB_WRITE_ALERT, alert); - return i; + return 1; } diff --git a/Sources/BoringSSL/ssl/d1_srtp.c b/Sources/BoringSSL/ssl/d1_srtp.c index 5dba8ef8e..108537777 100644 --- a/Sources/BoringSSL/ssl/d1_srtp.c +++ b/Sources/BoringSSL/ssl/d1_srtp.c @@ -116,17 +116,15 @@ #include -#include #include #include #include -#include #include "internal.h" -const SRTP_PROTECTION_PROFILE kSRTPProfiles[] = { +static const SRTP_PROTECTION_PROFILE kSRTPProfiles[] = { { "SRTP_AES128_CM_SHA1_80", SRTP_AES128_CM_SHA1_80, }, @@ -162,27 +160,27 @@ static int find_profile_by_name(const char *profile_name, static int ssl_ctx_make_profiles(const char *profiles_string, STACK_OF(SRTP_PROTECTION_PROFILE) **out) { - STACK_OF(SRTP_PROTECTION_PROFILE) *profiles; - - const char *col; - const char *ptr = profiles_string; - - profiles = sk_SRTP_PROTECTION_PROFILE_new_null(); + STACK_OF(SRTP_PROTECTION_PROFILE) *profiles = + sk_SRTP_PROTECTION_PROFILE_new_null(); if (profiles == NULL) { OPENSSL_PUT_ERROR(SSL, SSL_R_SRTP_COULD_NOT_ALLOCATE_PROFILES); return 0; } + const char *col; + const char *ptr = profiles_string; do { - const SRTP_PROTECTION_PROFILE *p; - col = strchr(ptr, ':'); - if (find_profile_by_name(ptr, &p, - col ? (size_t)(col - ptr) : strlen(ptr))) { - sk_SRTP_PROTECTION_PROFILE_push(profiles, p); - } else { + + const SRTP_PROTECTION_PROFILE *profile; + if (!find_profile_by_name(ptr, &profile, + col ? (size_t)(col - ptr) : strlen(ptr))) { OPENSSL_PUT_ERROR(SSL, SSL_R_SRTP_UNKNOWN_PROTECTION_PROFILE); - return 0; + goto err; + } + + if (!sk_SRTP_PROTECTION_PROFILE_push(profiles, profile)) { + goto err; } if (col) { @@ -190,9 +188,13 @@ static int ssl_ctx_make_profiles(const char *profiles_string, } } while (col); + sk_SRTP_PROTECTION_PROFILE_free(*out); *out = profiles; - return 1; + +err: + sk_SRTP_PROTECTION_PROFILE_free(profiles); + return 0; } int SSL_CTX_set_srtp_profiles(SSL_CTX *ctx, const char *profiles) { @@ -212,7 +214,7 @@ STACK_OF(SRTP_PROTECTION_PROFILE) *SSL_get_srtp_profiles(SSL *ssl) { return ssl->srtp_profiles; } - if (ssl->ctx != NULL && ssl->ctx->srtp_profiles != NULL) { + if (ssl->ctx->srtp_profiles != NULL) { return ssl->ctx->srtp_profiles; } diff --git a/Sources/BoringSSL/ssl/d1_srvr.c b/Sources/BoringSSL/ssl/d1_srvr.c deleted file mode 100644 index 5c9624a3c..000000000 --- a/Sources/BoringSSL/ssl/d1_srvr.c +++ /dev/null @@ -1,476 +0,0 @@ -/* - * DTLS implementation written by Nagendra Modadugu - * (nagendra@cs.stanford.edu) for the OpenSSL project 2005. - */ -/* ==================================================================== - * Copyright (c) 1999-2007 The OpenSSL Project. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the OpenSSL Project - * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" - * - * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to - * endorse or promote products derived from this software without - * prior written permission. For written permission, please contact - * openssl-core@OpenSSL.org. - * - * 5. Products derived from this software may not be called "OpenSSL" - * nor may "OpenSSL" appear in their names without prior written - * permission of the OpenSSL Project. - * - * 6. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the OpenSSL Project - * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" - * - * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This product includes cryptographic software written by Eric Young - * (eay@cryptsoft.com). This product includes software written by Tim - * Hudson (tjh@cryptsoft.com). - * - */ -/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) - * All rights reserved. - * - * This package is an SSL implementation written - * by Eric Young (eay@cryptsoft.com). - * The implementation was written so as to conform with Netscapes SSL. - * - * This library is free for commercial and non-commercial use as long as - * the following conditions are aheared to. The following conditions - * apply to all code found in this distribution, be it the RC4, RSA, - * lhash, DES, etc., code; not just the SSL code. The SSL documentation - * included with this distribution is covered by the same copyright terms - * except that the holder is Tim Hudson (tjh@cryptsoft.com). - * - * Copyright remains Eric Young's, and as such any Copyright notices in - * the code are not to be removed. - * If this package is used in a product, Eric Young should be given attribution - * as the author of the parts of the library used. - * This can be in the form of a textual message at program startup or - * in documentation (online or textual) provided with the package. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * "This product includes cryptographic software written by - * Eric Young (eay@cryptsoft.com)" - * The word 'cryptographic' can be left out if the rouines from the library - * being used are not cryptographic related :-). - * 4. If you include any Windows specific code (or a derivative thereof) from - * the apps directory (application code) you must include an acknowledgement: - * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" - * - * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * The licence and distribution terms for any publically available version or - * derivative of this code cannot be changed. i.e. this code cannot simply be - * copied and put under another distribution licence - * [including the GNU Public Licence.] - */ - -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "internal.h" - - -int dtls1_accept(SSL *ssl) { - BUF_MEM *buf = NULL; - void (*cb)(const SSL *ssl, int type, int value) = NULL; - uint32_t alg_a; - int ret = -1; - int new_state, state, skip = 0; - - assert(ssl->handshake_func == dtls1_accept); - assert(ssl->server); - assert(SSL_IS_DTLS(ssl)); - - ERR_clear_error(); - ERR_clear_system_error(); - - if (ssl->info_callback != NULL) { - cb = ssl->info_callback; - } else if (ssl->ctx->info_callback != NULL) { - cb = ssl->ctx->info_callback; - } - - ssl->in_handshake++; - - for (;;) { - state = ssl->state; - - switch (ssl->state) { - case SSL_ST_ACCEPT: - if (cb != NULL) { - cb(ssl, SSL_CB_HANDSHAKE_START, 1); - } - - if (ssl->init_buf == NULL) { - buf = BUF_MEM_new(); - if (buf == NULL || !BUF_MEM_grow(buf, SSL3_RT_MAX_PLAIN_LENGTH)) { - ret = -1; - goto end; - } - ssl->init_buf = buf; - buf = NULL; - } - - ssl->init_num = 0; - - if (!ssl_init_wbio_buffer(ssl, 1)) { - ret = -1; - goto end; - } - - if (!ssl3_init_handshake_buffer(ssl)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - ret = -1; - goto end; - } - - ssl->state = SSL3_ST_SR_CLNT_HELLO_A; - break; - - case SSL3_ST_SR_CLNT_HELLO_A: - case SSL3_ST_SR_CLNT_HELLO_B: - case SSL3_ST_SR_CLNT_HELLO_C: - case SSL3_ST_SR_CLNT_HELLO_D: - ssl->shutdown = 0; - ret = ssl3_get_client_hello(ssl); - if (ret <= 0) { - goto end; - } - dtls1_stop_timer(ssl); - ssl->state = SSL3_ST_SW_SRVR_HELLO_A; - ssl->init_num = 0; - break; - - case SSL3_ST_SW_SRVR_HELLO_A: - case SSL3_ST_SW_SRVR_HELLO_B: - dtls1_start_timer(ssl); - ret = ssl3_send_server_hello(ssl); - if (ret <= 0) { - goto end; - } - - if (ssl->hit) { - if (ssl->tlsext_ticket_expected) { - ssl->state = SSL3_ST_SW_SESSION_TICKET_A; - } else { - ssl->state = SSL3_ST_SW_CHANGE_A; - } - } else { - ssl->state = SSL3_ST_SW_CERT_A; - } - ssl->init_num = 0; - break; - - case SSL3_ST_SW_CERT_A: - case SSL3_ST_SW_CERT_B: - if (ssl_cipher_has_server_public_key(ssl->s3->tmp.new_cipher)) { - dtls1_start_timer(ssl); - ret = ssl3_send_server_certificate(ssl); - if (ret <= 0) { - goto end; - } - if (ssl->s3->tmp.certificate_status_expected) { - ssl->state = SSL3_ST_SW_CERT_STATUS_A; - } else { - ssl->state = SSL3_ST_SW_KEY_EXCH_A; - } - } else { - skip = 1; - ssl->state = SSL3_ST_SW_KEY_EXCH_A; - } - ssl->init_num = 0; - break; - - case SSL3_ST_SW_CERT_STATUS_A: - case SSL3_ST_SW_CERT_STATUS_B: - ret = ssl3_send_certificate_status(ssl); - if (ret <= 0) { - goto end; - } - ssl->state = SSL3_ST_SW_KEY_EXCH_A; - ssl->init_num = 0; - break; - - case SSL3_ST_SW_KEY_EXCH_A: - case SSL3_ST_SW_KEY_EXCH_B: - case SSL3_ST_SW_KEY_EXCH_C: - alg_a = ssl->s3->tmp.new_cipher->algorithm_auth; - - /* Send a ServerKeyExchange message if: - * - The key exchange is ephemeral or anonymous - * Diffie-Hellman. - * - There is a PSK identity hint. - * - * TODO(davidben): This logic is currently duplicated - * in s3_srvr.c. Fix this. In the meantime, keep them - * in sync. */ - if (ssl_cipher_requires_server_key_exchange(ssl->s3->tmp.new_cipher) || - ((alg_a & SSL_aPSK) && ssl->psk_identity_hint)) { - dtls1_start_timer(ssl); - ret = ssl3_send_server_key_exchange(ssl); - if (ret <= 0) { - goto end; - } - } else { - skip = 1; - } - - ssl->state = SSL3_ST_SW_CERT_REQ_A; - ssl->init_num = 0; - break; - - case SSL3_ST_SW_CERT_REQ_A: - case SSL3_ST_SW_CERT_REQ_B: - if (ssl->s3->tmp.cert_request) { - dtls1_start_timer(ssl); - ret = ssl3_send_certificate_request(ssl); - if (ret <= 0) { - goto end; - } - } else { - skip = 1; - } - ssl->state = SSL3_ST_SW_SRVR_DONE_A; - ssl->init_num = 0; - break; - - case SSL3_ST_SW_SRVR_DONE_A: - case SSL3_ST_SW_SRVR_DONE_B: - dtls1_start_timer(ssl); - ret = ssl3_send_server_done(ssl); - if (ret <= 0) { - goto end; - } - ssl->s3->tmp.next_state = SSL3_ST_SR_CERT_A; - ssl->state = SSL3_ST_SW_FLUSH; - ssl->init_num = 0; - break; - - case SSL3_ST_SW_FLUSH: - ssl->rwstate = SSL_WRITING; - if (BIO_flush(ssl->wbio) <= 0) { - ret = -1; - goto end; - } - ssl->rwstate = SSL_NOTHING; - ssl->state = ssl->s3->tmp.next_state; - break; - - case SSL3_ST_SR_CERT_A: - case SSL3_ST_SR_CERT_B: - if (ssl->s3->tmp.cert_request) { - ret = ssl3_get_client_certificate(ssl); - if (ret <= 0) { - goto end; - } - } - ssl->init_num = 0; - ssl->state = SSL3_ST_SR_KEY_EXCH_A; - break; - - case SSL3_ST_SR_KEY_EXCH_A: - case SSL3_ST_SR_KEY_EXCH_B: - case SSL3_ST_SR_KEY_EXCH_C: - ret = ssl3_get_client_key_exchange(ssl); - if (ret <= 0) { - goto end; - } - ssl->state = SSL3_ST_SR_CERT_VRFY_A; - ssl->init_num = 0; - break; - - case SSL3_ST_SR_CERT_VRFY_A: - case SSL3_ST_SR_CERT_VRFY_B: - ret = ssl3_get_cert_verify(ssl); - if (ret <= 0) { - goto end; - } - ssl->state = SSL3_ST_SR_CHANGE; - ssl->init_num = 0; - break; - - case SSL3_ST_SR_CHANGE: - ret = ssl->method->ssl_read_change_cipher_spec(ssl); - if (ret <= 0) { - goto end; - } - - if (!tls1_change_cipher_state(ssl, SSL3_CHANGE_CIPHER_SERVER_READ)) { - ret = -1; - goto end; - } - - ssl->state = SSL3_ST_SR_FINISHED_A; - break; - - case SSL3_ST_SR_FINISHED_A: - case SSL3_ST_SR_FINISHED_B: - ret = ssl3_get_finished(ssl, SSL3_ST_SR_FINISHED_A, - SSL3_ST_SR_FINISHED_B); - if (ret <= 0) { - goto end; - } - dtls1_stop_timer(ssl); - if (ssl->hit) { - ssl->state = SSL_ST_OK; - } else if (ssl->tlsext_ticket_expected) { - ssl->state = SSL3_ST_SW_SESSION_TICKET_A; - } else { - ssl->state = SSL3_ST_SW_CHANGE_A; - } - ssl->init_num = 0; - break; - - case SSL3_ST_SW_SESSION_TICKET_A: - case SSL3_ST_SW_SESSION_TICKET_B: - ret = ssl3_send_new_session_ticket(ssl); - if (ret <= 0) { - goto end; - } - ssl->state = SSL3_ST_SW_CHANGE_A; - ssl->init_num = 0; - break; - - case SSL3_ST_SW_CHANGE_A: - case SSL3_ST_SW_CHANGE_B: - ret = dtls1_send_change_cipher_spec(ssl, SSL3_ST_SW_CHANGE_A, - SSL3_ST_SW_CHANGE_B); - - if (ret <= 0) { - goto end; - } - - ssl->state = SSL3_ST_SW_FINISHED_A; - ssl->init_num = 0; - - if (!tls1_change_cipher_state(ssl, SSL3_CHANGE_CIPHER_SERVER_WRITE)) { - ret = -1; - goto end; - } - break; - - case SSL3_ST_SW_FINISHED_A: - case SSL3_ST_SW_FINISHED_B: - ret = ssl3_send_finished(ssl, SSL3_ST_SW_FINISHED_A, - SSL3_ST_SW_FINISHED_B); - if (ret <= 0) { - goto end; - } - ssl->state = SSL3_ST_SW_FLUSH; - if (ssl->hit) { - ssl->s3->tmp.next_state = SSL3_ST_SR_CHANGE; - } else { - ssl->s3->tmp.next_state = SSL_ST_OK; - } - ssl->init_num = 0; - break; - - case SSL_ST_OK: - ssl3_cleanup_key_block(ssl); - - /* remove buffering on output */ - ssl_free_wbio_buffer(ssl); - - ssl->init_num = 0; - ssl->s3->initial_handshake_complete = 1; - - ssl_update_cache(ssl, SSL_SESS_CACHE_SERVER); - - if (cb != NULL) { - cb(ssl, SSL_CB_HANDSHAKE_DONE, 1); - } - - ret = 1; - - /* done handshaking, next message is client hello */ - ssl->d1->handshake_read_seq = 0; - /* next message is server hello */ - ssl->d1->handshake_write_seq = 0; - ssl->d1->next_handshake_write_seq = 0; - goto end; - - default: - OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_STATE); - ret = -1; - goto end; - } - - if (!ssl->s3->tmp.reuse_message && !skip) { - if (cb != NULL && ssl->state != state) { - new_state = ssl->state; - ssl->state = state; - cb(ssl, SSL_CB_ACCEPT_LOOP, 1); - ssl->state = new_state; - } - } - skip = 0; - } - -end: - ssl->in_handshake--; - BUF_MEM_free(buf); - if (cb != NULL) { - cb(ssl, SSL_CB_ACCEPT_EXIT, ret); - } - return ret; -} diff --git a/Sources/BoringSSL/ssl/d1_meth.c b/Sources/BoringSSL/ssl/dtls_method.c similarity index 56% rename from Sources/BoringSSL/ssl/d1_meth.c rename to Sources/BoringSSL/ssl/dtls_method.c index 49a2595e5..60847895a 100644 --- a/Sources/BoringSSL/ssl/d1_meth.c +++ b/Sources/BoringSSL/ssl/dtls_method.c @@ -56,51 +56,138 @@ #include +#include +#include + +#include +#include + +#include "../crypto/internal.h" #include "internal.h" -static const SSL_PROTOCOL_METHOD DTLS_protocol_method = { +static int dtls1_version_from_wire(uint16_t *out_version, + uint16_t wire_version) { + switch (wire_version) { + case DTLS1_VERSION: + /* DTLS 1.0 maps to TLS 1.1, not TLS 1.0. */ + *out_version = TLS1_1_VERSION; + return 1; + case DTLS1_2_VERSION: + *out_version = TLS1_2_VERSION; + return 1; + } + + return 0; +} + +static uint16_t dtls1_version_to_wire(uint16_t version) { + switch (version) { + case TLS1_1_VERSION: + /* DTLS 1.0 maps to TLS 1.1, not TLS 1.0. */ + return DTLS1_VERSION; + case TLS1_2_VERSION: + return DTLS1_2_VERSION; + } + + /* It is an error to use this function with an invalid version. */ + assert(0); + return 0; +} + +static int dtls1_supports_cipher(const SSL_CIPHER *cipher) { + return cipher->algorithm_enc != SSL_eNULL; +} + +static void dtls1_expect_flight(SSL *ssl) { dtls1_start_timer(ssl); } + +static void dtls1_received_flight(SSL *ssl) { dtls1_stop_timer(ssl); } + +static int dtls1_set_read_state(SSL *ssl, SSL_AEAD_CTX *aead_ctx) { + /* Cipher changes are illegal when there are buffered incoming messages. */ + if (dtls_has_incoming_messages(ssl)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFERED_MESSAGES_ON_CIPHER_CHANGE); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE); + SSL_AEAD_CTX_free(aead_ctx); + return 0; + } + + ssl->d1->r_epoch++; + OPENSSL_memset(&ssl->d1->bitmap, 0, sizeof(ssl->d1->bitmap)); + OPENSSL_memset(ssl->s3->read_sequence, 0, sizeof(ssl->s3->read_sequence)); + + SSL_AEAD_CTX_free(ssl->s3->aead_read_ctx); + ssl->s3->aead_read_ctx = aead_ctx; + return 1; +} + +static int dtls1_set_write_state(SSL *ssl, SSL_AEAD_CTX *aead_ctx) { + ssl->d1->w_epoch++; + OPENSSL_memcpy(ssl->d1->last_write_sequence, ssl->s3->write_sequence, + sizeof(ssl->s3->write_sequence)); + OPENSSL_memset(ssl->s3->write_sequence, 0, sizeof(ssl->s3->write_sequence)); + + SSL_AEAD_CTX_free(ssl->s3->aead_write_ctx); + ssl->s3->aead_write_ctx = aead_ctx; + return 1; +} + +static const SSL_PROTOCOL_METHOD kDTLSProtocolMethod = { 1 /* is_dtls */, + TLS1_1_VERSION, + TLS1_2_VERSION, + dtls1_version_from_wire, + dtls1_version_to_wire, dtls1_new, dtls1_free, - dtls1_accept, - dtls1_connect, dtls1_get_message, + dtls1_get_current_message, + dtls1_release_current_message, dtls1_read_app_data, dtls1_read_change_cipher_spec, dtls1_read_close_notify, dtls1_write_app_data, dtls1_dispatch_alert, dtls1_supports_cipher, - DTLS1_HM_HEADER_LENGTH, - dtls1_set_handshake_header, - dtls1_handshake_write, + dtls1_init_message, + dtls1_finish_message, + dtls1_add_message, + dtls1_add_change_cipher_spec, + dtls1_add_alert, + dtls1_flush_flight, + dtls1_expect_flight, + dtls1_received_flight, + dtls1_set_read_state, + dtls1_set_write_state, }; const SSL_METHOD *DTLS_method(void) { - static const SSL_METHOD method = { + static const SSL_METHOD kMethod = { 0, - &DTLS_protocol_method, + &kDTLSProtocolMethod, + &ssl_crypto_x509_method, }; - return &method; + return &kMethod; } /* Legacy version-locked methods. */ const SSL_METHOD *DTLSv1_2_method(void) { - static const SSL_METHOD method = { + static const SSL_METHOD kMethod = { DTLS1_2_VERSION, - &DTLS_protocol_method, + &kDTLSProtocolMethod, + &ssl_crypto_x509_method, }; - return &method; + return &kMethod; } const SSL_METHOD *DTLSv1_method(void) { - static const SSL_METHOD method = { + static const SSL_METHOD kMethod = { DTLS1_VERSION, - &DTLS_protocol_method, + &kDTLSProtocolMethod, + &ssl_crypto_x509_method, }; - return &method; + return &kMethod; } /* Legacy side-specific methods. */ diff --git a/Sources/BoringSSL/ssl/dtls_record.c b/Sources/BoringSSL/ssl/dtls_record.c index eaf6df76d..879706dfc 100644 --- a/Sources/BoringSSL/ssl/dtls_record.c +++ b/Sources/BoringSSL/ssl/dtls_record.c @@ -118,6 +118,7 @@ #include #include "internal.h" +#include "../crypto/internal.h" /* to_u64_be treats |in| as a 8-byte big-endian integer and returns the value as @@ -171,10 +172,12 @@ static void dtls1_bitmap_record(DTLS1_BITMAP *bitmap, } } -enum ssl_open_record_t dtls_open_record( - SSL *ssl, uint8_t *out_type, uint8_t *out, size_t *out_len, - size_t *out_consumed, uint8_t *out_alert, size_t max_out, const uint8_t *in, - size_t in_len) { +enum ssl_open_record_t dtls_open_record(SSL *ssl, uint8_t *out_type, CBS *out, + size_t *out_consumed, + uint8_t *out_alert, uint8_t *in, + size_t in_len) { + *out_consumed = 0; + CBS cbs; CBS_init(&cbs, in, in_len); @@ -195,10 +198,8 @@ enum ssl_open_record_t dtls_open_record( return ssl_open_record_discard; } - if (ssl->msg_callback != NULL) { - ssl->msg_callback(0 /* read */, 0, SSL3_RT_HEADER, in, - DTLS1_RT_HEADER_LENGTH, ssl, ssl->msg_callback_arg); - } + ssl_do_msg_callback(ssl, 0 /* read */, SSL3_RT_HEADER, in, + DTLS1_RT_HEADER_LENGTH); uint16_t epoch = (((uint16_t)sequence[0]) << 8) | sequence[1]; if (epoch != ssl->d1->r_epoch || @@ -211,11 +212,9 @@ enum ssl_open_record_t dtls_open_record( return ssl_open_record_discard; } - /* Decrypt the body. */ - size_t plaintext_len; - if (!SSL_AEAD_CTX_open(ssl->s3->aead_read_ctx, out, &plaintext_len, max_out, - type, version, sequence, CBS_data(&body), - CBS_len(&body))) { + /* Decrypt the body in-place. */ + if (!SSL_AEAD_CTX_open(ssl->s3->aead_read_ctx, out, type, version, sequence, + (uint8_t *)CBS_data(&body), CBS_len(&body))) { /* Bad packets are silently dropped in DTLS. See section 4.2.1 of RFC 6347. * Clear the error queue of any errors decryption may have added. Drop the * entire packet as it must not have come from the peer. @@ -226,9 +225,10 @@ enum ssl_open_record_t dtls_open_record( *out_consumed = in_len - CBS_len(&cbs); return ssl_open_record_discard; } + *out_consumed = in_len - CBS_len(&cbs); /* Check the plaintext length. */ - if (plaintext_len > SSL3_RT_MAX_PLAIN_LENGTH) { + if (CBS_len(out) > SSL3_RT_MAX_PLAIN_LENGTH) { OPENSSL_PUT_ERROR(SSL, SSL_R_DATA_LENGTH_TOO_LONG); *out_alert = SSL_AD_RECORD_OVERFLOW; return ssl_open_record_error; @@ -239,15 +239,49 @@ enum ssl_open_record_t dtls_open_record( /* TODO(davidben): Limit the number of empty records as in TLS? This is only * useful if we also limit discarded packets. */ + if (type == SSL3_RT_ALERT) { + return ssl_process_alert(ssl, out_alert, CBS_data(out), CBS_len(out)); + } + + ssl->s3->warning_alert_count = 0; + *out_type = type; - *out_len = plaintext_len; - *out_consumed = in_len - CBS_len(&cbs); return ssl_open_record_success; } +static const SSL_AEAD_CTX *get_write_aead(const SSL *ssl, + enum dtls1_use_epoch_t use_epoch) { + if (use_epoch == dtls1_use_previous_epoch) { + /* DTLS renegotiation is unsupported, so only epochs 0 (NULL cipher) and 1 + * (negotiated cipher) exist. */ + assert(ssl->d1->w_epoch == 1); + return NULL; + } + + return ssl->s3->aead_write_ctx; +} + +size_t dtls_max_seal_overhead(const SSL *ssl, + enum dtls1_use_epoch_t use_epoch) { + return DTLS1_RT_HEADER_LENGTH + + SSL_AEAD_CTX_max_overhead(get_write_aead(ssl, use_epoch)); +} + +size_t dtls_seal_prefix_len(const SSL *ssl, enum dtls1_use_epoch_t use_epoch) { + return DTLS1_RT_HEADER_LENGTH + + SSL_AEAD_CTX_explicit_nonce_len(get_write_aead(ssl, use_epoch)); +} + int dtls_seal_record(SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out, uint8_t type, const uint8_t *in, size_t in_len, enum dtls1_use_epoch_t use_epoch) { + const size_t prefix = dtls_seal_prefix_len(ssl, use_epoch); + if (buffers_alias(in, in_len, out, max_out) && + (max_out < prefix || out + prefix != in)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_OUTPUT_ALIASES_INPUT); + return 0; + } + /* Determine the parameters for the current epoch. */ uint16_t epoch = ssl->d1->w_epoch; SSL_AEAD_CTX *aead = ssl->s3->aead_write_ctx; @@ -265,12 +299,6 @@ int dtls_seal_record(SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out, OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFER_TOO_SMALL); return 0; } - /* Check the record header does not alias any part of the input. - * |SSL_AEAD_CTX_seal| will internally enforce other aliasing requirements. */ - if (in < out + DTLS1_RT_HEADER_LENGTH && out < in + in_len) { - OPENSSL_PUT_ERROR(SSL, SSL_R_OUTPUT_ALIASES_INPUT); - return 0; - } out[0] = type; @@ -280,7 +308,7 @@ int dtls_seal_record(SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out, out[3] = epoch >> 8; out[4] = epoch & 0xff; - memcpy(&out[5], &seq[2], 6); + OPENSSL_memcpy(&out[5], &seq[2], 6); size_t ciphertext_len; if (!SSL_AEAD_CTX_seal(aead, out + DTLS1_RT_HEADER_LENGTH, &ciphertext_len, @@ -299,10 +327,8 @@ int dtls_seal_record(SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out, *out_len = DTLS1_RT_HEADER_LENGTH + ciphertext_len; - if (ssl->msg_callback) { - ssl->msg_callback(1 /* write */, 0, SSL3_RT_HEADER, out, - DTLS1_RT_HEADER_LENGTH, ssl, ssl->msg_callback_arg); - } + ssl_do_msg_callback(ssl, 1 /* write */, SSL3_RT_HEADER, out, + DTLS1_RT_HEADER_LENGTH); return 1; } diff --git a/Sources/BoringSSL/ssl/handshake_client.c b/Sources/BoringSSL/ssl/handshake_client.c new file mode 100644 index 000000000..c4f5e8e9f --- /dev/null +++ b/Sources/BoringSSL/ssl/handshake_client.c @@ -0,0 +1,1883 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright (c) 1998-2007 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * + * Portions of the attached software ("Contribution") are developed by + * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project. + * + * The Contribution is licensed pursuant to the OpenSSL open source + * license provided above. + * + * ECC cipher suite support in OpenSSL originally written by + * Vipul Gupta and Sumit Gupta of Sun Microsystems Laboratories. + * + */ +/* ==================================================================== + * Copyright 2005 Nokia. All rights reserved. + * + * The portions of the attached software ("Contribution") is developed by + * Nokia Corporation and is licensed pursuant to the OpenSSL open source + * license. + * + * The Contribution, originally written by Mika Kousa and Pasi Eronen of + * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites + * support (see RFC 4279) to OpenSSL. + * + * No patent licenses or other rights except those expressly stated in + * the OpenSSL open source license shall be deemed granted or received + * expressly, by implication, estoppel, or otherwise. + * + * No assurances are provided by Nokia that the Contribution does not + * infringe the patent or other intellectual property rights of any third + * party or that the license provides you with all the necessary rights + * to make use of the Contribution. + * + * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN + * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA + * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY + * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR + * OTHERWISE. + */ + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../crypto/internal.h" +#include "internal.h" + + +static int ssl3_send_client_hello(SSL_HANDSHAKE *hs); +static int dtls1_get_hello_verify(SSL_HANDSHAKE *hs); +static int ssl3_get_server_hello(SSL_HANDSHAKE *hs); +static int ssl3_get_server_certificate(SSL_HANDSHAKE *hs); +static int ssl3_get_cert_status(SSL_HANDSHAKE *hs); +static int ssl3_verify_server_cert(SSL_HANDSHAKE *hs); +static int ssl3_get_server_key_exchange(SSL_HANDSHAKE *hs); +static int ssl3_get_certificate_request(SSL_HANDSHAKE *hs); +static int ssl3_get_server_hello_done(SSL_HANDSHAKE *hs); +static int ssl3_send_client_certificate(SSL_HANDSHAKE *hs); +static int ssl3_send_client_key_exchange(SSL_HANDSHAKE *hs); +static int ssl3_send_cert_verify(SSL_HANDSHAKE *hs); +static int ssl3_send_next_proto(SSL_HANDSHAKE *hs); +static int ssl3_send_channel_id(SSL_HANDSHAKE *hs); +static int ssl3_get_new_session_ticket(SSL_HANDSHAKE *hs); + +int ssl3_connect(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + int ret = -1; + + assert(ssl->handshake_func == ssl3_connect); + assert(!ssl->server); + + for (;;) { + int state = hs->state; + + switch (hs->state) { + case SSL_ST_INIT: + ssl_do_info_callback(ssl, SSL_CB_HANDSHAKE_START, 1); + hs->state = SSL3_ST_CW_CLNT_HELLO_A; + break; + + case SSL3_ST_CW_CLNT_HELLO_A: + ret = ssl3_send_client_hello(hs); + if (ret <= 0) { + goto end; + } + + if (!SSL_is_dtls(ssl) || ssl->d1->send_cookie) { + hs->next_state = SSL3_ST_CR_SRVR_HELLO_A; + } else { + hs->next_state = DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A; + } + hs->state = SSL3_ST_CW_FLUSH; + break; + + case DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A: + assert(SSL_is_dtls(ssl)); + ret = dtls1_get_hello_verify(hs); + if (ret <= 0) { + goto end; + } + if (ssl->d1->send_cookie) { + ssl->method->received_flight(ssl); + hs->state = SSL3_ST_CW_CLNT_HELLO_A; + } else { + hs->state = SSL3_ST_CR_SRVR_HELLO_A; + } + break; + + case SSL3_ST_CR_SRVR_HELLO_A: + ret = ssl3_get_server_hello(hs); + if (hs->state == SSL_ST_TLS13) { + break; + } + if (ret <= 0) { + goto end; + } + + if (ssl->session != NULL) { + hs->state = SSL3_ST_CR_SESSION_TICKET_A; + } else { + hs->state = SSL3_ST_CR_CERT_A; + } + break; + + case SSL3_ST_CR_CERT_A: + if (ssl_cipher_uses_certificate_auth(hs->new_cipher)) { + ret = ssl3_get_server_certificate(hs); + if (ret <= 0) { + goto end; + } + } + hs->state = SSL3_ST_CR_CERT_STATUS_A; + break; + + case SSL3_ST_CR_CERT_STATUS_A: + if (hs->certificate_status_expected) { + ret = ssl3_get_cert_status(hs); + if (ret <= 0) { + goto end; + } + } + hs->state = SSL3_ST_VERIFY_SERVER_CERT; + break; + + case SSL3_ST_VERIFY_SERVER_CERT: + if (ssl_cipher_uses_certificate_auth(hs->new_cipher)) { + ret = ssl3_verify_server_cert(hs); + if (ret <= 0) { + goto end; + } + } + hs->state = SSL3_ST_CR_KEY_EXCH_A; + break; + + case SSL3_ST_CR_KEY_EXCH_A: + ret = ssl3_get_server_key_exchange(hs); + if (ret <= 0) { + goto end; + } + hs->state = SSL3_ST_CR_CERT_REQ_A; + break; + + case SSL3_ST_CR_CERT_REQ_A: + if (ssl_cipher_uses_certificate_auth(hs->new_cipher)) { + ret = ssl3_get_certificate_request(hs); + if (ret <= 0) { + goto end; + } + } + hs->state = SSL3_ST_CR_SRVR_DONE_A; + break; + + case SSL3_ST_CR_SRVR_DONE_A: + ret = ssl3_get_server_hello_done(hs); + if (ret <= 0) { + goto end; + } + ssl->method->received_flight(ssl); + hs->state = SSL3_ST_CW_CERT_A; + break; + + case SSL3_ST_CW_CERT_A: + if (hs->cert_request) { + ret = ssl3_send_client_certificate(hs); + if (ret <= 0) { + goto end; + } + } + hs->state = SSL3_ST_CW_KEY_EXCH_A; + break; + + case SSL3_ST_CW_KEY_EXCH_A: + ret = ssl3_send_client_key_exchange(hs); + if (ret <= 0) { + goto end; + } + hs->state = SSL3_ST_CW_CERT_VRFY_A; + break; + + case SSL3_ST_CW_CERT_VRFY_A: + case SSL3_ST_CW_CERT_VRFY_B: + if (hs->cert_request && ssl_has_certificate(ssl)) { + ret = ssl3_send_cert_verify(hs); + if (ret <= 0) { + goto end; + } + } + hs->state = SSL3_ST_CW_CHANGE; + break; + + case SSL3_ST_CW_CHANGE: + if (!ssl->method->add_change_cipher_spec(ssl) || + !tls1_change_cipher_state(hs, SSL3_CHANGE_CIPHER_CLIENT_WRITE)) { + ret = -1; + goto end; + } + + hs->state = SSL3_ST_CW_NEXT_PROTO_A; + break; + + case SSL3_ST_CW_NEXT_PROTO_A: + if (hs->next_proto_neg_seen) { + ret = ssl3_send_next_proto(hs); + if (ret <= 0) { + goto end; + } + } + hs->state = SSL3_ST_CW_CHANNEL_ID_A; + break; + + case SSL3_ST_CW_CHANNEL_ID_A: + if (ssl->s3->tlsext_channel_id_valid) { + ret = ssl3_send_channel_id(hs); + if (ret <= 0) { + goto end; + } + } + hs->state = SSL3_ST_CW_FINISHED_A; + break; + + case SSL3_ST_CW_FINISHED_A: + ret = ssl3_send_finished(hs); + if (ret <= 0) { + goto end; + } + hs->state = SSL3_ST_CW_FLUSH; + + if (ssl->session != NULL) { + hs->next_state = SSL3_ST_FINISH_CLIENT_HANDSHAKE; + } else { + /* This is a non-resumption handshake. If it involves ChannelID, then + * record the handshake hashes at this point in the session so that + * any resumption of this session with ChannelID can sign those + * hashes. */ + ret = tls1_record_handshake_hashes_for_channel_id(hs); + if (ret <= 0) { + goto end; + } + if ((SSL_get_mode(ssl) & SSL_MODE_ENABLE_FALSE_START) && + ssl3_can_false_start(ssl) && + /* No False Start on renegotiation (would complicate the state + * machine). */ + !ssl->s3->initial_handshake_complete) { + hs->next_state = SSL3_ST_FALSE_START; + } else { + hs->next_state = SSL3_ST_CR_SESSION_TICKET_A; + } + } + break; + + case SSL3_ST_FALSE_START: + hs->state = SSL3_ST_CR_SESSION_TICKET_A; + hs->in_false_start = 1; + ret = 1; + goto end; + + case SSL3_ST_CR_SESSION_TICKET_A: + if (hs->ticket_expected) { + ret = ssl3_get_new_session_ticket(hs); + if (ret <= 0) { + goto end; + } + } + hs->state = SSL3_ST_CR_CHANGE; + break; + + case SSL3_ST_CR_CHANGE: + ret = ssl->method->read_change_cipher_spec(ssl); + if (ret <= 0) { + goto end; + } + + if (!tls1_change_cipher_state(hs, SSL3_CHANGE_CIPHER_CLIENT_READ)) { + ret = -1; + goto end; + } + hs->state = SSL3_ST_CR_FINISHED_A; + break; + + case SSL3_ST_CR_FINISHED_A: + ret = ssl3_get_finished(hs); + if (ret <= 0) { + goto end; + } + ssl->method->received_flight(ssl); + + if (ssl->session != NULL) { + hs->state = SSL3_ST_CW_CHANGE; + } else { + hs->state = SSL3_ST_FINISH_CLIENT_HANDSHAKE; + } + break; + + case SSL3_ST_CW_FLUSH: + ret = ssl->method->flush_flight(ssl); + if (ret <= 0) { + goto end; + } + hs->state = hs->next_state; + if (hs->state != SSL3_ST_FINISH_CLIENT_HANDSHAKE) { + ssl->method->expect_flight(ssl); + } + break; + + case SSL_ST_TLS13: + ret = tls13_handshake(hs); + if (ret <= 0) { + goto end; + } + hs->state = SSL3_ST_FINISH_CLIENT_HANDSHAKE; + break; + + case SSL3_ST_FINISH_CLIENT_HANDSHAKE: + ssl->method->release_current_message(ssl, 1 /* free_buffer */); + + SSL_SESSION_free(ssl->s3->established_session); + if (ssl->session != NULL) { + SSL_SESSION_up_ref(ssl->session); + ssl->s3->established_session = ssl->session; + } else { + /* We make a copy of the session in order to maintain the immutability + * of the new established_session due to False Start. The caller may + * have taken a reference to the temporary session. */ + ssl->s3->established_session = + SSL_SESSION_dup(hs->new_session, SSL_SESSION_DUP_ALL); + if (ssl->s3->established_session == NULL) { + ret = -1; + goto end; + } + ssl->s3->established_session->not_resumable = 0; + + SSL_SESSION_free(hs->new_session); + hs->new_session = NULL; + } + + hs->state = SSL_ST_OK; + break; + + case SSL_ST_OK: { + const int is_initial_handshake = !ssl->s3->initial_handshake_complete; + ssl->s3->initial_handshake_complete = 1; + if (is_initial_handshake) { + /* Renegotiations do not participate in session resumption. */ + ssl_update_cache(hs, SSL_SESS_CACHE_CLIENT); + } + + ret = 1; + ssl_do_info_callback(ssl, SSL_CB_HANDSHAKE_DONE, 1); + goto end; + } + + default: + OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_STATE); + ret = -1; + goto end; + } + + if (hs->state != state) { + ssl_do_info_callback(ssl, SSL_CB_CONNECT_LOOP, 1); + } + } + +end: + ssl_do_info_callback(ssl, SSL_CB_CONNECT_EXIT, ret); + return ret; +} + +uint16_t ssl_get_grease_value(const SSL *ssl, enum ssl_grease_index_t index) { + /* Use the client_random for entropy. This both avoids calling |RAND_bytes| on + * a single byte repeatedly and ensures the values are deterministic. This + * allows the same ClientHello be sent twice for a HelloRetryRequest or the + * same group be advertised in both supported_groups and key_shares. */ + uint16_t ret = ssl->s3->client_random[index]; + /* This generates a random value of the form 0xωaωa, for all 0 ≤ ω < 16. */ + ret = (ret & 0xf0) | 0x0a; + ret |= ret << 8; + return ret; +} + +/* ssl_get_client_disabled sets |*out_mask_a| and |*out_mask_k| to masks of + * disabled algorithms. */ +static void ssl_get_client_disabled(SSL *ssl, uint32_t *out_mask_a, + uint32_t *out_mask_k) { + int have_rsa = 0, have_ecdsa = 0; + *out_mask_a = 0; + *out_mask_k = 0; + + /* Now go through all signature algorithms seeing if we support any for RSA or + * ECDSA. Do this for all versions not just TLS 1.2. */ + const uint16_t *sigalgs; + size_t num_sigalgs = tls12_get_verify_sigalgs(ssl, &sigalgs); + for (size_t i = 0; i < num_sigalgs; i++) { + switch (sigalgs[i]) { + case SSL_SIGN_RSA_PSS_SHA512: + case SSL_SIGN_RSA_PSS_SHA384: + case SSL_SIGN_RSA_PSS_SHA256: + case SSL_SIGN_RSA_PKCS1_SHA512: + case SSL_SIGN_RSA_PKCS1_SHA384: + case SSL_SIGN_RSA_PKCS1_SHA256: + case SSL_SIGN_RSA_PKCS1_SHA1: + have_rsa = 1; + break; + + case SSL_SIGN_ECDSA_SECP521R1_SHA512: + case SSL_SIGN_ECDSA_SECP384R1_SHA384: + case SSL_SIGN_ECDSA_SECP256R1_SHA256: + case SSL_SIGN_ECDSA_SHA1: + have_ecdsa = 1; + break; + } + } + + /* Disable auth if we don't include any appropriate signature algorithms. */ + if (!have_rsa) { + *out_mask_a |= SSL_aRSA; + } + if (!have_ecdsa) { + *out_mask_a |= SSL_aECDSA; + } + + /* PSK requires a client callback. */ + if (ssl->psk_client_callback == NULL) { + *out_mask_a |= SSL_aPSK; + *out_mask_k |= SSL_kPSK; + } +} + +static int ssl_write_client_cipher_list(SSL *ssl, CBB *out, + uint16_t min_version, + uint16_t max_version) { + uint32_t mask_a, mask_k; + ssl_get_client_disabled(ssl, &mask_a, &mask_k); + + CBB child; + if (!CBB_add_u16_length_prefixed(out, &child)) { + return 0; + } + + /* Add a fake cipher suite. See draft-davidben-tls-grease-01. */ + if (ssl->ctx->grease_enabled && + !CBB_add_u16(&child, ssl_get_grease_value(ssl, ssl_grease_cipher))) { + return 0; + } + + /* Add TLS 1.3 ciphers. Order ChaCha20-Poly1305 relative to AES-GCM based on + * hardware support. */ + if (max_version >= TLS1_3_VERSION) { + if (!EVP_has_aes_hardware() && + !CBB_add_u16(&child, TLS1_CK_CHACHA20_POLY1305_SHA256 & 0xffff)) { + return 0; + } + if (!CBB_add_u16(&child, TLS1_CK_AES_128_GCM_SHA256 & 0xffff) || + !CBB_add_u16(&child, TLS1_CK_AES_256_GCM_SHA384 & 0xffff)) { + return 0; + } + if (EVP_has_aes_hardware() && + !CBB_add_u16(&child, TLS1_CK_CHACHA20_POLY1305_SHA256 & 0xffff)) { + return 0; + } + } + + if (min_version < TLS1_3_VERSION) { + STACK_OF(SSL_CIPHER) *ciphers = SSL_get_ciphers(ssl); + int any_enabled = 0; + for (size_t i = 0; i < sk_SSL_CIPHER_num(ciphers); i++) { + const SSL_CIPHER *cipher = sk_SSL_CIPHER_value(ciphers, i); + /* Skip disabled ciphers */ + if ((cipher->algorithm_mkey & mask_k) || + (cipher->algorithm_auth & mask_a)) { + continue; + } + if (SSL_CIPHER_get_min_version(cipher) > max_version || + SSL_CIPHER_get_max_version(cipher) < min_version) { + continue; + } + any_enabled = 1; + if (!CBB_add_u16(&child, ssl_cipher_get_value(cipher))) { + return 0; + } + } + + /* If all ciphers were disabled, return the error to the caller. */ + if (!any_enabled && max_version < TLS1_3_VERSION) { + OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CIPHERS_AVAILABLE); + return 0; + } + } + + /* For SSLv3, the SCSV is added. Otherwise the renegotiation extension is + * added. */ + if (max_version == SSL3_VERSION && + !ssl->s3->initial_handshake_complete) { + if (!CBB_add_u16(&child, SSL3_CK_SCSV & 0xffff)) { + return 0; + } + } + + if (ssl->mode & SSL_MODE_SEND_FALLBACK_SCSV) { + if (!CBB_add_u16(&child, SSL3_CK_FALLBACK_SCSV & 0xffff)) { + return 0; + } + } + + return CBB_flush(out); +} + +int ssl_write_client_hello(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + uint16_t min_version, max_version; + if (!ssl_get_version_range(ssl, &min_version, &max_version)) { + return 0; + } + + CBB cbb, body; + if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_CLIENT_HELLO)) { + goto err; + } + + /* Renegotiations do not participate in session resumption. */ + int has_session = ssl->session != NULL && + !ssl->s3->initial_handshake_complete; + + CBB child; + if (!CBB_add_u16(&body, hs->client_version) || + !CBB_add_bytes(&body, ssl->s3->client_random, SSL3_RANDOM_SIZE) || + !CBB_add_u8_length_prefixed(&body, &child) || + (has_session && + !CBB_add_bytes(&child, ssl->session->session_id, + ssl->session->session_id_length))) { + goto err; + } + + if (SSL_is_dtls(ssl)) { + if (!CBB_add_u8_length_prefixed(&body, &child) || + !CBB_add_bytes(&child, ssl->d1->cookie, ssl->d1->cookie_len)) { + goto err; + } + } + + size_t header_len = + SSL_is_dtls(ssl) ? DTLS1_HM_HEADER_LENGTH : SSL3_HM_HEADER_LENGTH; + if (!ssl_write_client_cipher_list(ssl, &body, min_version, max_version) || + !CBB_add_u8(&body, 1 /* one compression method */) || + !CBB_add_u8(&body, 0 /* null compression */) || + !ssl_add_clienthello_tlsext(hs, &body, header_len + CBB_len(&body))) { + goto err; + } + + uint8_t *msg = NULL; + size_t len; + if (!ssl->method->finish_message(ssl, &cbb, &msg, &len)) { + goto err; + } + + /* Now that the length prefixes have been computed, fill in the placeholder + * PSK binder. */ + if (hs->needs_psk_binder && + !tls13_write_psk_binder(hs, msg, len)) { + OPENSSL_free(msg); + goto err; + } + + return ssl->method->add_message(ssl, msg, len); + + err: + CBB_cleanup(&cbb); + return 0; +} + +static int ssl3_send_client_hello(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + /* The handshake buffer is reset on every ClientHello. Notably, in DTLS, we + * may send multiple ClientHellos if we receive HelloVerifyRequest. */ + if (!SSL_TRANSCRIPT_init(&hs->transcript)) { + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + return -1; + } + + uint16_t min_version, max_version; + if (!ssl_get_version_range(ssl, &min_version, &max_version)) { + return -1; + } + + uint16_t max_wire_version = ssl->method->version_to_wire(max_version); + assert(hs->state == SSL3_ST_CW_CLNT_HELLO_A); + if (!ssl->s3->have_version) { + ssl->version = max_wire_version; + } + + /* Always advertise the ClientHello version from the original maximum version, + * even on renegotiation. The static RSA key exchange uses this field, and + * some servers fail when it changes across handshakes. */ + hs->client_version = max_wire_version; + if (max_version >= TLS1_3_VERSION) { + hs->client_version = ssl->method->version_to_wire(TLS1_2_VERSION); + } + + /* If the configured session has expired or was created at a disabled + * version, drop it. */ + if (ssl->session != NULL) { + uint16_t session_version; + if (ssl->session->is_server || + !ssl->method->version_from_wire(&session_version, + ssl->session->ssl_version) || + (session_version < TLS1_3_VERSION && + ssl->session->session_id_length == 0) || + ssl->session->not_resumable || + !ssl_session_is_time_valid(ssl, ssl->session) || + session_version < min_version || session_version > max_version) { + ssl_set_session(ssl, NULL); + } + } + + /* If resending the ClientHello in DTLS after a HelloVerifyRequest, don't + * renegerate the client_random. The random must be reused. */ + if ((!SSL_is_dtls(ssl) || !ssl->d1->send_cookie) && + !RAND_bytes(ssl->s3->client_random, sizeof(ssl->s3->client_random))) { + return -1; + } + + if (!ssl_write_client_hello(hs)) { + return -1; + } + + return 1; +} + +static int dtls1_get_hello_verify(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + int al; + CBS hello_verify_request, cookie; + uint16_t server_version; + + int ret = ssl->method->ssl_get_message(ssl); + if (ret <= 0) { + return ret; + } + + if (ssl->s3->tmp.message_type != DTLS1_MT_HELLO_VERIFY_REQUEST) { + ssl->d1->send_cookie = 0; + ssl->s3->tmp.reuse_message = 1; + return 1; + } + + CBS_init(&hello_verify_request, ssl->init_msg, ssl->init_num); + if (!CBS_get_u16(&hello_verify_request, &server_version) || + !CBS_get_u8_length_prefixed(&hello_verify_request, &cookie) || + CBS_len(&hello_verify_request) != 0) { + al = SSL_AD_DECODE_ERROR; + OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + goto f_err; + } + + if (CBS_len(&cookie) > sizeof(ssl->d1->cookie)) { + al = SSL_AD_ILLEGAL_PARAMETER; + goto f_err; + } + + OPENSSL_memcpy(ssl->d1->cookie, CBS_data(&cookie), CBS_len(&cookie)); + ssl->d1->cookie_len = CBS_len(&cookie); + + ssl->d1->send_cookie = 1; + return 1; + +f_err: + ssl3_send_alert(ssl, SSL3_AL_FATAL, al); + return -1; +} + +static int ssl3_get_server_hello(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + int al = SSL_AD_INTERNAL_ERROR; + CBS server_hello, server_random, session_id; + uint16_t server_wire_version, cipher_suite; + uint8_t compression_method; + + int ret = ssl->method->ssl_get_message(ssl); + if (ret <= 0) { + uint32_t err = ERR_peek_error(); + if (ERR_GET_LIB(err) == ERR_LIB_SSL && + ERR_GET_REASON(err) == SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE) { + /* Add a dedicated error code to the queue for a handshake_failure alert + * in response to ClientHello. This matches NSS's client behavior and + * gives a better error on a (probable) failure to negotiate initial + * parameters. Note: this error code comes after the original one. + * + * See https://crbug.com/446505. */ + OPENSSL_PUT_ERROR(SSL, SSL_R_HANDSHAKE_FAILURE_ON_CLIENT_HELLO); + } + return ret; + } + + if (ssl->s3->tmp.message_type != SSL3_MT_SERVER_HELLO && + ssl->s3->tmp.message_type != SSL3_MT_HELLO_RETRY_REQUEST) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE); + OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_MESSAGE); + return -1; + } + + CBS_init(&server_hello, ssl->init_msg, ssl->init_num); + + if (!CBS_get_u16(&server_hello, &server_wire_version)) { + al = SSL_AD_DECODE_ERROR; + OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + goto f_err; + } + + uint16_t min_version, max_version, server_version; + if (!ssl_get_version_range(ssl, &min_version, &max_version) || + !ssl->method->version_from_wire(&server_version, server_wire_version) || + server_version < min_version || server_version > max_version) { + OPENSSL_PUT_ERROR(SSL, SSL_R_UNSUPPORTED_PROTOCOL); + al = SSL_AD_PROTOCOL_VERSION; + goto f_err; + } + + assert(ssl->s3->have_version == ssl->s3->initial_handshake_complete); + if (!ssl->s3->have_version) { + ssl->version = server_wire_version; + /* At this point, the connection's version is known and ssl->version is + * fixed. Begin enforcing the record-layer version. */ + ssl->s3->have_version = 1; + } else if (server_wire_version != ssl->version) { + OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_SSL_VERSION); + al = SSL_AD_PROTOCOL_VERSION; + goto f_err; + } + + if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) { + hs->state = SSL_ST_TLS13; + hs->do_tls13_handshake = tls13_client_handshake; + return 1; + } + + ssl_clear_tls13_state(hs); + + if (!ssl_check_message_type(ssl, SSL3_MT_SERVER_HELLO)) { + return -1; + } + + if (!CBS_get_bytes(&server_hello, &server_random, SSL3_RANDOM_SIZE) || + !CBS_get_u8_length_prefixed(&server_hello, &session_id) || + CBS_len(&session_id) > SSL3_SESSION_ID_SIZE || + !CBS_get_u16(&server_hello, &cipher_suite) || + !CBS_get_u8(&server_hello, &compression_method)) { + al = SSL_AD_DECODE_ERROR; + OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + goto f_err; + } + + /* Copy over the server random. */ + OPENSSL_memcpy(ssl->s3->server_random, CBS_data(&server_random), SSL3_RANDOM_SIZE); + + /* TODO(davidben): Implement the TLS 1.1 and 1.2 downgrade sentinels once TLS + * 1.3 is finalized and we are not implementing a draft version. */ + + if (!ssl->s3->initial_handshake_complete && ssl->session != NULL && + ssl->session->session_id_length != 0 && + CBS_mem_equal(&session_id, ssl->session->session_id, + ssl->session->session_id_length)) { + ssl->s3->session_reused = 1; + } else { + /* The session wasn't resumed. Create a fresh SSL_SESSION to + * fill out. */ + ssl_set_session(ssl, NULL); + if (!ssl_get_new_session(hs, 0 /* client */)) { + goto f_err; + } + /* Note: session_id could be empty. */ + hs->new_session->session_id_length = CBS_len(&session_id); + OPENSSL_memcpy(hs->new_session->session_id, CBS_data(&session_id), + CBS_len(&session_id)); + } + + const SSL_CIPHER *c = SSL_get_cipher_by_value(cipher_suite); + if (c == NULL) { + /* unknown cipher */ + al = SSL_AD_ILLEGAL_PARAMETER; + OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_CIPHER_RETURNED); + goto f_err; + } + + /* The cipher must be allowed in the selected version and enabled. */ + uint32_t mask_a, mask_k; + ssl_get_client_disabled(ssl, &mask_a, &mask_k); + if ((c->algorithm_mkey & mask_k) || (c->algorithm_auth & mask_a) || + SSL_CIPHER_get_min_version(c) > ssl3_protocol_version(ssl) || + SSL_CIPHER_get_max_version(c) < ssl3_protocol_version(ssl) || + !sk_SSL_CIPHER_find(SSL_get_ciphers(ssl), NULL, c)) { + al = SSL_AD_ILLEGAL_PARAMETER; + OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CIPHER_RETURNED); + goto f_err; + } + + if (ssl->session != NULL) { + if (ssl->session->ssl_version != ssl->version) { + al = SSL_AD_ILLEGAL_PARAMETER; + OPENSSL_PUT_ERROR(SSL, SSL_R_OLD_SESSION_VERSION_NOT_RETURNED); + goto f_err; + } + if (ssl->session->cipher != c) { + al = SSL_AD_ILLEGAL_PARAMETER; + OPENSSL_PUT_ERROR(SSL, SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED); + goto f_err; + } + if (!ssl_session_is_context_valid(ssl, ssl->session)) { + /* This is actually a client application bug. */ + al = SSL_AD_ILLEGAL_PARAMETER; + OPENSSL_PUT_ERROR(SSL, + SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT); + goto f_err; + } + } else { + hs->new_session->cipher = c; + } + hs->new_cipher = c; + + /* Now that the cipher is known, initialize the handshake hash and hash the + * ServerHello. */ + if (!SSL_TRANSCRIPT_init_hash(&hs->transcript, ssl3_protocol_version(ssl), + c->algorithm_prf) || + !ssl_hash_current_message(hs)) { + goto f_err; + } + + /* If doing a full handshake, the server may request a client certificate + * which requires hashing the handshake transcript. Otherwise, the handshake + * buffer may be released. */ + if (ssl->session != NULL || + !ssl_cipher_uses_certificate_auth(hs->new_cipher)) { + SSL_TRANSCRIPT_free_buffer(&hs->transcript); + } + + /* Only the NULL compression algorithm is supported. */ + if (compression_method != 0) { + al = SSL_AD_ILLEGAL_PARAMETER; + OPENSSL_PUT_ERROR(SSL, SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM); + goto f_err; + } + + /* TLS extensions */ + if (!ssl_parse_serverhello_tlsext(hs, &server_hello)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_PARSE_TLSEXT); + goto err; + } + + /* There should be nothing left over in the record. */ + if (CBS_len(&server_hello) != 0) { + /* wrong packet length */ + al = SSL_AD_DECODE_ERROR; + OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + goto f_err; + } + + if (ssl->session != NULL && + hs->extended_master_secret != ssl->session->extended_master_secret) { + al = SSL_AD_HANDSHAKE_FAILURE; + if (ssl->session->extended_master_secret) { + OPENSSL_PUT_ERROR(SSL, SSL_R_RESUMED_EMS_SESSION_WITHOUT_EMS_EXTENSION); + } else { + OPENSSL_PUT_ERROR(SSL, SSL_R_RESUMED_NON_EMS_SESSION_WITH_EMS_EXTENSION); + } + goto f_err; + } + + return 1; + +f_err: + ssl3_send_alert(ssl, SSL3_AL_FATAL, al); +err: + return -1; +} + +static int ssl3_get_server_certificate(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + int ret = ssl->method->ssl_get_message(ssl); + if (ret <= 0) { + return ret; + } + + if (!ssl_check_message_type(ssl, SSL3_MT_CERTIFICATE) || + !ssl_hash_current_message(hs)) { + return -1; + } + + CBS cbs; + CBS_init(&cbs, ssl->init_msg, ssl->init_num); + + uint8_t alert = SSL_AD_DECODE_ERROR; + sk_CRYPTO_BUFFER_pop_free(hs->new_session->certs, CRYPTO_BUFFER_free); + EVP_PKEY_free(hs->peer_pubkey); + hs->peer_pubkey = NULL; + hs->new_session->certs = ssl_parse_cert_chain(&alert, &hs->peer_pubkey, NULL, + &cbs, ssl->ctx->pool); + if (hs->new_session->certs == NULL) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, alert); + return -1; + } + + if (sk_CRYPTO_BUFFER_num(hs->new_session->certs) == 0 || + CBS_len(&cbs) != 0 || + !ssl->ctx->x509_method->session_cache_objects(hs->new_session)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); + return -1; + } + + if (!ssl_check_leaf_certificate( + hs, hs->peer_pubkey, + sk_CRYPTO_BUFFER_value(hs->new_session->certs, 0))) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER); + return -1; + } + + return 1; +} + +static int ssl3_get_cert_status(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + int al; + CBS certificate_status, ocsp_response; + uint8_t status_type; + + int ret = ssl->method->ssl_get_message(ssl); + if (ret <= 0) { + return ret; + } + + if (ssl->s3->tmp.message_type != SSL3_MT_CERTIFICATE_STATUS) { + /* A server may send status_request in ServerHello and then change + * its mind about sending CertificateStatus. */ + ssl->s3->tmp.reuse_message = 1; + return 1; + } + + if (!ssl_hash_current_message(hs)) { + return -1; + } + + CBS_init(&certificate_status, ssl->init_msg, ssl->init_num); + if (!CBS_get_u8(&certificate_status, &status_type) || + status_type != TLSEXT_STATUSTYPE_ocsp || + !CBS_get_u24_length_prefixed(&certificate_status, &ocsp_response) || + CBS_len(&ocsp_response) == 0 || + CBS_len(&certificate_status) != 0) { + al = SSL_AD_DECODE_ERROR; + OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + goto f_err; + } + + if (!CBS_stow(&ocsp_response, &hs->new_session->ocsp_response, + &hs->new_session->ocsp_response_length)) { + al = SSL_AD_INTERNAL_ERROR; + OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + goto f_err; + } + return 1; + +f_err: + ssl3_send_alert(ssl, SSL3_AL_FATAL, al); + return -1; +} + +static int ssl3_verify_server_cert(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + if (!ssl_verify_cert_chain(ssl, &hs->new_session->verify_result, + hs->new_session->x509_chain)) { + return -1; + } + + return 1; +} + +static int ssl3_get_server_key_exchange(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + int al; + DH *dh = NULL; + EC_KEY *ecdh = NULL; + EC_POINT *srvr_ecpoint = NULL; + + int ret = ssl->method->ssl_get_message(ssl); + if (ret <= 0) { + return ret; + } + + if (ssl->s3->tmp.message_type != SSL3_MT_SERVER_KEY_EXCHANGE) { + /* Some ciphers (pure PSK) have an optional ServerKeyExchange message. */ + if (ssl_cipher_requires_server_key_exchange(hs->new_cipher)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_MESSAGE); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE); + return -1; + } + + ssl->s3->tmp.reuse_message = 1; + return 1; + } + + if (!ssl_hash_current_message(hs)) { + return -1; + } + + /* Retain a copy of the original CBS to compute the signature over. */ + CBS server_key_exchange; + CBS_init(&server_key_exchange, ssl->init_msg, ssl->init_num); + CBS server_key_exchange_orig = server_key_exchange; + + uint32_t alg_k = hs->new_cipher->algorithm_mkey; + uint32_t alg_a = hs->new_cipher->algorithm_auth; + + if (alg_a & SSL_aPSK) { + CBS psk_identity_hint; + + /* Each of the PSK key exchanges begins with a psk_identity_hint. */ + if (!CBS_get_u16_length_prefixed(&server_key_exchange, + &psk_identity_hint)) { + al = SSL_AD_DECODE_ERROR; + OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + goto f_err; + } + + /* Store PSK identity hint for later use, hint is used in + * ssl3_send_client_key_exchange. Assume that the maximum length of a PSK + * identity hint can be as long as the maximum length of a PSK identity. + * Also do not allow NULL characters; identities are saved as C strings. + * + * TODO(davidben): Should invalid hints be ignored? It's a hint rather than + * a specific identity. */ + if (CBS_len(&psk_identity_hint) > PSK_MAX_IDENTITY_LEN || + CBS_contains_zero_byte(&psk_identity_hint)) { + al = SSL_AD_HANDSHAKE_FAILURE; + OPENSSL_PUT_ERROR(SSL, SSL_R_DATA_LENGTH_TOO_LONG); + goto f_err; + } + + /* Save non-empty identity hints as a C string. Empty identity hints we + * treat as missing. Plain PSK makes it possible to send either no hint + * (omit ServerKeyExchange) or an empty hint, while ECDHE_PSK can only spell + * empty hint. Having different capabilities is odd, so we interpret empty + * and missing as identical. */ + if (CBS_len(&psk_identity_hint) != 0 && + !CBS_strdup(&psk_identity_hint, &hs->peer_psk_identity_hint)) { + al = SSL_AD_INTERNAL_ERROR; + OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + goto f_err; + } + } + + if (alg_k & SSL_kDHE) { + CBS dh_p, dh_g, dh_Ys; + if (!CBS_get_u16_length_prefixed(&server_key_exchange, &dh_p) || + CBS_len(&dh_p) == 0 || + !CBS_get_u16_length_prefixed(&server_key_exchange, &dh_g) || + CBS_len(&dh_g) == 0 || + !CBS_get_u16_length_prefixed(&server_key_exchange, &dh_Ys) || + CBS_len(&dh_Ys) == 0) { + al = SSL_AD_DECODE_ERROR; + OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + goto f_err; + } + + dh = DH_new(); + if (dh == NULL) { + goto err; + } + + dh->p = BN_bin2bn(CBS_data(&dh_p), CBS_len(&dh_p), NULL); + dh->g = BN_bin2bn(CBS_data(&dh_g), CBS_len(&dh_g), NULL); + if (dh->p == NULL || dh->g == NULL) { + goto err; + } + + unsigned bits = DH_num_bits(dh); + if (bits < 1024) { + OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_DH_P_LENGTH); + goto err; + } else if (bits > 4096) { + /* Overly large DHE groups are prohibitively expensive, so enforce a limit + * to prevent a server from causing us to perform too expensive of a + * computation. */ + OPENSSL_PUT_ERROR(SSL, SSL_R_DH_P_TOO_LONG); + goto err; + } + + SSL_ECDH_CTX_init_for_dhe(&hs->ecdh_ctx, dh); + dh = NULL; + + /* Save the peer public key for later. */ + if (!CBS_stow(&dh_Ys, &hs->peer_key, &hs->peer_key_len)) { + goto err; + } + } else if (alg_k & SSL_kECDHE) { + /* Parse the server parameters. */ + uint8_t group_type; + uint16_t group_id; + CBS point; + if (!CBS_get_u8(&server_key_exchange, &group_type) || + group_type != NAMED_CURVE_TYPE || + !CBS_get_u16(&server_key_exchange, &group_id) || + !CBS_get_u8_length_prefixed(&server_key_exchange, &point)) { + al = SSL_AD_DECODE_ERROR; + OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + goto f_err; + } + hs->new_session->group_id = group_id; + + /* Ensure the group is consistent with preferences. */ + if (!tls1_check_group_id(ssl, group_id)) { + al = SSL_AD_ILLEGAL_PARAMETER; + OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CURVE); + goto f_err; + } + + /* Initialize ECDH and save the peer public key for later. */ + if (!SSL_ECDH_CTX_init(&hs->ecdh_ctx, group_id) || + !CBS_stow(&point, &hs->peer_key, &hs->peer_key_len)) { + goto err; + } + } else if (!(alg_k & SSL_kPSK)) { + al = SSL_AD_UNEXPECTED_MESSAGE; + OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_MESSAGE); + goto f_err; + } + + /* At this point, |server_key_exchange| contains the signature, if any, while + * |server_key_exchange_orig| contains the entire message. From that, derive + * a CBS containing just the parameter. */ + CBS parameter; + CBS_init(¶meter, CBS_data(&server_key_exchange_orig), + CBS_len(&server_key_exchange_orig) - CBS_len(&server_key_exchange)); + + /* ServerKeyExchange should be signed by the server's public key. */ + if (ssl_cipher_uses_certificate_auth(hs->new_cipher)) { + uint16_t signature_algorithm = 0; + if (ssl3_protocol_version(ssl) >= TLS1_2_VERSION) { + if (!CBS_get_u16(&server_key_exchange, &signature_algorithm)) { + al = SSL_AD_DECODE_ERROR; + OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + goto f_err; + } + if (!tls12_check_peer_sigalg(ssl, &al, signature_algorithm)) { + goto f_err; + } + hs->new_session->peer_signature_algorithm = signature_algorithm; + } else if (hs->peer_pubkey->type == EVP_PKEY_RSA) { + signature_algorithm = SSL_SIGN_RSA_PKCS1_MD5_SHA1; + } else if (hs->peer_pubkey->type == EVP_PKEY_EC) { + signature_algorithm = SSL_SIGN_ECDSA_SHA1; + } else { + al = SSL_AD_UNSUPPORTED_CERTIFICATE; + OPENSSL_PUT_ERROR(SSL, SSL_R_PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE); + goto f_err; + } + + /* The last field in |server_key_exchange| is the signature. */ + CBS signature; + if (!CBS_get_u16_length_prefixed(&server_key_exchange, &signature) || + CBS_len(&server_key_exchange) != 0) { + al = SSL_AD_DECODE_ERROR; + OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + goto f_err; + } + + CBB transcript; + uint8_t *transcript_data; + size_t transcript_len; + if (!CBB_init(&transcript, 2*SSL3_RANDOM_SIZE + CBS_len(¶meter)) || + !CBB_add_bytes(&transcript, ssl->s3->client_random, SSL3_RANDOM_SIZE) || + !CBB_add_bytes(&transcript, ssl->s3->server_random, SSL3_RANDOM_SIZE) || + !CBB_add_bytes(&transcript, CBS_data(¶meter), CBS_len(¶meter)) || + !CBB_finish(&transcript, &transcript_data, &transcript_len)) { + CBB_cleanup(&transcript); + al = SSL_AD_INTERNAL_ERROR; + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + goto f_err; + } + + int sig_ok = ssl_public_key_verify( + ssl, CBS_data(&signature), CBS_len(&signature), signature_algorithm, + hs->peer_pubkey, transcript_data, transcript_len); + OPENSSL_free(transcript_data); + +#if defined(BORINGSSL_UNSAFE_FUZZER_MODE) + sig_ok = 1; + ERR_clear_error(); +#endif + if (!sig_ok) { + /* bad signature */ + al = SSL_AD_DECRYPT_ERROR; + OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SIGNATURE); + goto f_err; + } + } else { + /* PSK ciphers are the only supported certificate-less ciphers. */ + assert(alg_a == SSL_aPSK); + + if (CBS_len(&server_key_exchange) > 0) { + al = SSL_AD_DECODE_ERROR; + OPENSSL_PUT_ERROR(SSL, SSL_R_EXTRA_DATA_IN_MESSAGE); + goto f_err; + } + } + return 1; + +f_err: + ssl3_send_alert(ssl, SSL3_AL_FATAL, al); +err: + DH_free(dh); + EC_POINT_free(srvr_ecpoint); + EC_KEY_free(ecdh); + return -1; +} + +static int ssl3_get_certificate_request(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + int msg_ret = ssl->method->ssl_get_message(ssl); + if (msg_ret <= 0) { + return msg_ret; + } + + if (ssl->s3->tmp.message_type == SSL3_MT_SERVER_HELLO_DONE) { + ssl->s3->tmp.reuse_message = 1; + /* If we get here we don't need the handshake buffer as we won't be doing + * client auth. */ + SSL_TRANSCRIPT_free_buffer(&hs->transcript); + return 1; + } + + if (!ssl_check_message_type(ssl, SSL3_MT_CERTIFICATE_REQUEST) || + !ssl_hash_current_message(hs)) { + return -1; + } + + CBS cbs; + CBS_init(&cbs, ssl->init_msg, ssl->init_num); + + /* Get the certificate types. */ + CBS certificate_types; + if (!CBS_get_u8_length_prefixed(&cbs, &certificate_types)) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); + OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + return -1; + } + + if (!CBS_stow(&certificate_types, &hs->certificate_types, + &hs->num_certificate_types)) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); + return -1; + } + + if (ssl3_protocol_version(ssl) >= TLS1_2_VERSION) { + CBS supported_signature_algorithms; + if (!CBS_get_u16_length_prefixed(&cbs, &supported_signature_algorithms) || + !tls1_parse_peer_sigalgs(hs, &supported_signature_algorithms)) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); + OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + return -1; + } + } + + uint8_t alert = SSL_AD_DECODE_ERROR; + STACK_OF(X509_NAME) *ca_sk = ssl_parse_client_CA_list(ssl, &alert, &cbs); + if (ca_sk == NULL) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, alert); + return -1; + } + + if (CBS_len(&cbs) != 0) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); + sk_X509_NAME_pop_free(ca_sk, X509_NAME_free); + OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + return -1; + } + + hs->cert_request = 1; + sk_X509_NAME_pop_free(hs->ca_names, X509_NAME_free); + hs->ca_names = ca_sk; + return 1; +} + +static int ssl3_get_server_hello_done(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + int ret = ssl->method->ssl_get_message(ssl); + if (ret <= 0) { + return ret; + } + + if (!ssl_check_message_type(ssl, SSL3_MT_SERVER_HELLO_DONE) || + !ssl_hash_current_message(hs)) { + return -1; + } + + /* ServerHelloDone is empty. */ + if (ssl->init_num > 0) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); + OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + return -1; + } + + return 1; +} + +static int ssl3_send_client_certificate(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + /* Call cert_cb to update the certificate. */ + if (ssl->cert->cert_cb) { + int ret = ssl->cert->cert_cb(ssl, ssl->cert->cert_cb_arg); + if (ret < 0) { + ssl->rwstate = SSL_X509_LOOKUP; + return -1; + } + if (ret == 0) { + OPENSSL_PUT_ERROR(SSL, SSL_R_CERT_CB_ERROR); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); + return -1; + } + } + + if (!ssl_has_certificate(ssl)) { + /* Without a client certificate, the handshake buffer may be released. */ + SSL_TRANSCRIPT_free_buffer(&hs->transcript); + + /* In SSL 3.0, the Certificate message is replaced with a warning alert. */ + if (ssl->version == SSL3_VERSION) { + if (!ssl->method->add_alert(ssl, SSL3_AL_WARNING, + SSL_AD_NO_CERTIFICATE)) { + return -1; + } + return 1; + } + } + + if (!ssl_auto_chain_if_needed(ssl) || + !ssl3_output_cert_chain(ssl)) { + return -1; + } + return 1; +} + +OPENSSL_COMPILE_ASSERT(sizeof(size_t) >= sizeof(unsigned), + SIZE_T_IS_SMALLER_THAN_UNSIGNED); + +static int ssl3_send_client_key_exchange(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + uint8_t *pms = NULL; + size_t pms_len = 0; + CBB cbb, body; + if (!ssl->method->init_message(ssl, &cbb, &body, + SSL3_MT_CLIENT_KEY_EXCHANGE)) { + goto err; + } + + uint32_t alg_k = hs->new_cipher->algorithm_mkey; + uint32_t alg_a = hs->new_cipher->algorithm_auth; + + /* If using a PSK key exchange, prepare the pre-shared key. */ + unsigned psk_len = 0; + uint8_t psk[PSK_MAX_PSK_LEN]; + if (alg_a & SSL_aPSK) { + if (ssl->psk_client_callback == NULL) { + OPENSSL_PUT_ERROR(SSL, SSL_R_PSK_NO_CLIENT_CB); + goto err; + } + + char identity[PSK_MAX_IDENTITY_LEN + 1]; + OPENSSL_memset(identity, 0, sizeof(identity)); + psk_len = + ssl->psk_client_callback(ssl, hs->peer_psk_identity_hint, identity, + sizeof(identity), psk, sizeof(psk)); + if (psk_len == 0) { + OPENSSL_PUT_ERROR(SSL, SSL_R_PSK_IDENTITY_NOT_FOUND); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE); + goto err; + } + assert(psk_len <= PSK_MAX_PSK_LEN); + + OPENSSL_free(hs->new_session->psk_identity); + hs->new_session->psk_identity = BUF_strdup(identity); + if (hs->new_session->psk_identity == NULL) { + OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + goto err; + } + + /* Write out psk_identity. */ + CBB child; + if (!CBB_add_u16_length_prefixed(&body, &child) || + !CBB_add_bytes(&child, (const uint8_t *)identity, + OPENSSL_strnlen(identity, sizeof(identity))) || + !CBB_flush(&body)) { + goto err; + } + } + + /* Depending on the key exchange method, compute |pms| and |pms_len|. */ + if (alg_k & SSL_kRSA) { + pms_len = SSL_MAX_MASTER_KEY_LENGTH; + pms = OPENSSL_malloc(pms_len); + if (pms == NULL) { + OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + goto err; + } + + RSA *rsa = EVP_PKEY_get0_RSA(hs->peer_pubkey); + if (rsa == NULL) { + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + goto err; + } + + pms[0] = hs->client_version >> 8; + pms[1] = hs->client_version & 0xff; + if (!RAND_bytes(&pms[2], SSL_MAX_MASTER_KEY_LENGTH - 2)) { + goto err; + } + + CBB child, *enc_pms = &body; + size_t enc_pms_len; + /* In TLS, there is a length prefix. */ + if (ssl->version > SSL3_VERSION) { + if (!CBB_add_u16_length_prefixed(&body, &child)) { + goto err; + } + enc_pms = &child; + } + + uint8_t *ptr; + if (!CBB_reserve(enc_pms, &ptr, RSA_size(rsa)) || + !RSA_encrypt(rsa, &enc_pms_len, ptr, RSA_size(rsa), pms, pms_len, + RSA_PKCS1_PADDING) || + !CBB_did_write(enc_pms, enc_pms_len) || + !CBB_flush(&body)) { + goto err; + } + } else if (alg_k & (SSL_kECDHE|SSL_kDHE)) { + /* Generate a keypair and serialize the public half. */ + CBB child; + if (!SSL_ECDH_CTX_add_key(&hs->ecdh_ctx, &body, &child)) { + goto err; + } + + /* Compute the premaster. */ + uint8_t alert = SSL_AD_DECODE_ERROR; + if (!SSL_ECDH_CTX_accept(&hs->ecdh_ctx, &child, &pms, &pms_len, &alert, + hs->peer_key, hs->peer_key_len)) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, alert); + goto err; + } + if (!CBB_flush(&body)) { + goto err; + } + + /* The key exchange state may now be discarded. */ + SSL_ECDH_CTX_cleanup(&hs->ecdh_ctx); + OPENSSL_free(hs->peer_key); + hs->peer_key = NULL; + hs->peer_key_len = 0; + } else if (alg_k & SSL_kPSK) { + /* For plain PSK, other_secret is a block of 0s with the same length as + * the pre-shared key. */ + pms_len = psk_len; + pms = OPENSSL_malloc(pms_len); + if (pms == NULL) { + OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + goto err; + } + OPENSSL_memset(pms, 0, pms_len); + } else { + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE); + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + goto err; + } + + /* For a PSK cipher suite, other_secret is combined with the pre-shared + * key. */ + if (alg_a & SSL_aPSK) { + CBB pms_cbb, child; + uint8_t *new_pms; + size_t new_pms_len; + + CBB_zero(&pms_cbb); + if (!CBB_init(&pms_cbb, 2 + psk_len + 2 + pms_len) || + !CBB_add_u16_length_prefixed(&pms_cbb, &child) || + !CBB_add_bytes(&child, pms, pms_len) || + !CBB_add_u16_length_prefixed(&pms_cbb, &child) || + !CBB_add_bytes(&child, psk, psk_len) || + !CBB_finish(&pms_cbb, &new_pms, &new_pms_len)) { + CBB_cleanup(&pms_cbb); + OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + goto err; + } + OPENSSL_cleanse(pms, pms_len); + OPENSSL_free(pms); + pms = new_pms; + pms_len = new_pms_len; + } + + /* The message must be added to the finished hash before calculating the + * master secret. */ + if (!ssl_add_message_cbb(ssl, &cbb)) { + goto err; + } + + hs->new_session->master_key_length = tls1_generate_master_secret( + hs, hs->new_session->master_key, pms, pms_len); + if (hs->new_session->master_key_length == 0) { + goto err; + } + hs->new_session->extended_master_secret = hs->extended_master_secret; + OPENSSL_cleanse(pms, pms_len); + OPENSSL_free(pms); + + return 1; + +err: + CBB_cleanup(&cbb); + if (pms != NULL) { + OPENSSL_cleanse(pms, pms_len); + OPENSSL_free(pms); + } + return -1; +} + +static int ssl3_send_cert_verify(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + assert(ssl_has_private_key(ssl)); + + CBB cbb, body, child; + if (!ssl->method->init_message(ssl, &cbb, &body, + SSL3_MT_CERTIFICATE_VERIFY)) { + goto err; + } + + uint16_t signature_algorithm; + if (!tls1_choose_signature_algorithm(hs, &signature_algorithm)) { + goto err; + } + if (ssl3_protocol_version(ssl) >= TLS1_2_VERSION) { + /* Write out the digest type in TLS 1.2. */ + if (!CBB_add_u16(&body, signature_algorithm)) { + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + goto err; + } + } + + /* Set aside space for the signature. */ + const size_t max_sig_len = ssl_private_key_max_signature_len(ssl); + uint8_t *ptr; + if (!CBB_add_u16_length_prefixed(&body, &child) || + !CBB_reserve(&child, &ptr, max_sig_len)) { + goto err; + } + + size_t sig_len = max_sig_len; + enum ssl_private_key_result_t sign_result; + if (hs->state == SSL3_ST_CW_CERT_VRFY_A) { + /* The SSL3 construction for CertificateVerify does not decompose into a + * single final digest and signature, and must be special-cased. */ + if (ssl3_protocol_version(ssl) == SSL3_VERSION) { + if (ssl->cert->key_method != NULL) { + OPENSSL_PUT_ERROR(SSL, SSL_R_UNSUPPORTED_PROTOCOL_FOR_CUSTOM_KEY); + goto err; + } + + uint8_t digest[EVP_MAX_MD_SIZE]; + size_t digest_len; + if (!SSL_TRANSCRIPT_ssl3_cert_verify_hash(&hs->transcript, digest, + &digest_len, hs->new_session, + signature_algorithm)) { + goto err; + } + + sign_result = ssl_private_key_success; + + EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new(ssl->cert->privatekey, NULL); + if (pctx == NULL || + !EVP_PKEY_sign_init(pctx) || + !EVP_PKEY_sign(pctx, ptr, &sig_len, digest, digest_len)) { + EVP_PKEY_CTX_free(pctx); + sign_result = ssl_private_key_failure; + goto err; + } + EVP_PKEY_CTX_free(pctx); + } else { + sign_result = ssl_private_key_sign( + ssl, ptr, &sig_len, max_sig_len, signature_algorithm, + (const uint8_t *)hs->transcript.buffer->data, + hs->transcript.buffer->length); + } + + /* The handshake buffer is no longer necessary. */ + SSL_TRANSCRIPT_free_buffer(&hs->transcript); + } else { + assert(hs->state == SSL3_ST_CW_CERT_VRFY_B); + sign_result = ssl_private_key_complete(ssl, ptr, &sig_len, max_sig_len); + } + + switch (sign_result) { + case ssl_private_key_success: + break; + case ssl_private_key_failure: + goto err; + case ssl_private_key_retry: + ssl->rwstate = SSL_PRIVATE_KEY_OPERATION; + hs->state = SSL3_ST_CW_CERT_VRFY_B; + goto err; + } + + if (!CBB_did_write(&child, sig_len) || + !ssl_add_message_cbb(ssl, &cbb)) { + goto err; + } + + return 1; + +err: + CBB_cleanup(&cbb); + return -1; +} + +static int ssl3_send_next_proto(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + static const uint8_t kZero[32] = {0}; + size_t padding_len = 32 - ((ssl->s3->next_proto_negotiated_len + 2) % 32); + + CBB cbb, body, child; + if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_NEXT_PROTO) || + !CBB_add_u8_length_prefixed(&body, &child) || + !CBB_add_bytes(&child, ssl->s3->next_proto_negotiated, + ssl->s3->next_proto_negotiated_len) || + !CBB_add_u8_length_prefixed(&body, &child) || + !CBB_add_bytes(&child, kZero, padding_len) || + !ssl_add_message_cbb(ssl, &cbb)) { + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + CBB_cleanup(&cbb); + return -1; + } + + return 1; +} + +static int ssl3_send_channel_id(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + if (!ssl_do_channel_id_callback(ssl)) { + return -1; + } + + if (ssl->tlsext_channel_id_private == NULL) { + ssl->rwstate = SSL_CHANNEL_ID_LOOKUP; + return -1; + } + + CBB cbb, body; + if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_CHANNEL_ID) || + !tls1_write_channel_id(hs, &body) || + !ssl_add_message_cbb(ssl, &cbb)) { + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + CBB_cleanup(&cbb); + return -1; + } + + return 1; +} + +static int ssl3_get_new_session_ticket(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + int ret = ssl->method->ssl_get_message(ssl); + if (ret <= 0) { + return ret; + } + + if (!ssl_check_message_type(ssl, SSL3_MT_NEW_SESSION_TICKET) || + !ssl_hash_current_message(hs)) { + return -1; + } + + CBS new_session_ticket, ticket; + uint32_t tlsext_tick_lifetime_hint; + CBS_init(&new_session_ticket, ssl->init_msg, ssl->init_num); + if (!CBS_get_u32(&new_session_ticket, &tlsext_tick_lifetime_hint) || + !CBS_get_u16_length_prefixed(&new_session_ticket, &ticket) || + CBS_len(&new_session_ticket) != 0) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); + OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + return -1; + } + + if (CBS_len(&ticket) == 0) { + /* RFC 5077 allows a server to change its mind and send no ticket after + * negotiating the extension. The value of |ticket_expected| is checked in + * |ssl_update_cache| so is cleared here to avoid an unnecessary update. */ + hs->ticket_expected = 0; + return 1; + } + + int session_renewed = ssl->session != NULL; + SSL_SESSION *session = hs->new_session; + if (session_renewed) { + /* The server is sending a new ticket for an existing session. Sessions are + * immutable once established, so duplicate all but the ticket of the + * existing session. */ + session = SSL_SESSION_dup(ssl->session, SSL_SESSION_INCLUDE_NONAUTH); + if (session == NULL) { + /* This should never happen. */ + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + goto err; + } + } + + /* |tlsext_tick_lifetime_hint| is measured from when the ticket was issued. */ + ssl_session_rebase_time(ssl, session); + + if (!CBS_stow(&ticket, &session->tlsext_tick, &session->tlsext_ticklen)) { + OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + goto err; + } + session->tlsext_tick_lifetime_hint = tlsext_tick_lifetime_hint; + + /* Generate a session ID for this session based on the session ticket. We use + * the session ID mechanism for detecting ticket resumption. This also fits in + * with assumptions elsewhere in OpenSSL.*/ + if (!EVP_Digest(CBS_data(&ticket), CBS_len(&ticket), + session->session_id, &session->session_id_length, + EVP_sha256(), NULL)) { + goto err; + } + + if (session_renewed) { + session->not_resumable = 0; + SSL_SESSION_free(ssl->session); + ssl->session = session; + } + + return 1; + +err: + if (session_renewed) { + SSL_SESSION_free(session); + } + return -1; +} diff --git a/Sources/BoringSSL/ssl/handshake_server.c b/Sources/BoringSSL/ssl/handshake_server.c new file mode 100644 index 000000000..51338e224 --- /dev/null +++ b/Sources/BoringSSL/ssl/handshake_server.c @@ -0,0 +1,1950 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright (c) 1998-2007 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * + * Portions of the attached software ("Contribution") are developed by + * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project. + * + * The Contribution is licensed pursuant to the OpenSSL open source + * license provided above. + * + * ECC cipher suite support in OpenSSL originally written by + * Vipul Gupta and Sumit Gupta of Sun Microsystems Laboratories. + * + */ +/* ==================================================================== + * Copyright 2005 Nokia. All rights reserved. + * + * The portions of the attached software ("Contribution") is developed by + * Nokia Corporation and is licensed pursuant to the OpenSSL open source + * license. + * + * The Contribution, originally written by Mika Kousa and Pasi Eronen of + * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites + * support (see RFC 4279) to OpenSSL. + * + * No patent licenses or other rights except those expressly stated in + * the OpenSSL open source license shall be deemed granted or received + * expressly, by implication, estoppel, or otherwise. + * + * No assurances are provided by Nokia that the Contribution does not + * infringe the patent or other intellectual property rights of any third + * party or that the license provides you with all the necessary rights + * to make use of the Contribution. + * + * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN + * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA + * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY + * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR + * OTHERWISE. */ + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "internal.h" +#include "../crypto/internal.h" + + +static int ssl3_process_client_hello(SSL_HANDSHAKE *hs); +static int ssl3_select_certificate(SSL_HANDSHAKE *hs); +static int ssl3_select_parameters(SSL_HANDSHAKE *hs); +static int ssl3_send_server_hello(SSL_HANDSHAKE *hs); +static int ssl3_send_server_certificate(SSL_HANDSHAKE *hs); +static int ssl3_send_certificate_status(SSL_HANDSHAKE *hs); +static int ssl3_send_server_key_exchange(SSL_HANDSHAKE *hs); +static int ssl3_send_certificate_request(SSL_HANDSHAKE *hs); +static int ssl3_send_server_hello_done(SSL_HANDSHAKE *hs); +static int ssl3_get_client_certificate(SSL_HANDSHAKE *hs); +static int ssl3_get_client_key_exchange(SSL_HANDSHAKE *hs); +static int ssl3_get_cert_verify(SSL_HANDSHAKE *hs); +static int ssl3_get_next_proto(SSL_HANDSHAKE *hs); +static int ssl3_get_channel_id(SSL_HANDSHAKE *hs); +static int ssl3_send_new_session_ticket(SSL_HANDSHAKE *hs); + +static struct CRYPTO_STATIC_MUTEX g_v2clienthello_lock = + CRYPTO_STATIC_MUTEX_INIT; +static uint64_t g_v2clienthello_count = 0; + +uint64_t SSL_get_v2clienthello_count(void) { + CRYPTO_STATIC_MUTEX_lock_read(&g_v2clienthello_lock); + uint64_t ret = g_v2clienthello_count; + CRYPTO_STATIC_MUTEX_unlock_read(&g_v2clienthello_lock); + return ret; +} + +int ssl3_accept(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + uint32_t alg_a; + int ret = -1; + + assert(ssl->handshake_func == ssl3_accept); + assert(ssl->server); + + for (;;) { + int state = hs->state; + + switch (hs->state) { + case SSL_ST_INIT: + ssl_do_info_callback(ssl, SSL_CB_HANDSHAKE_START, 1); + hs->state = SSL3_ST_SR_CLNT_HELLO_A; + break; + + case SSL3_ST_SR_CLNT_HELLO_A: + ret = ssl->method->ssl_get_message(ssl); + if (ret <= 0) { + goto end; + } + hs->state = SSL3_ST_SR_CLNT_HELLO_B; + break; + + case SSL3_ST_SR_CLNT_HELLO_B: + ret = ssl3_process_client_hello(hs); + if (ret <= 0) { + goto end; + } + hs->state = SSL3_ST_SR_CLNT_HELLO_C; + break; + + case SSL3_ST_SR_CLNT_HELLO_C: + ret = ssl3_select_certificate(hs); + if (ret <= 0) { + goto end; + } + if (hs->state != SSL_ST_TLS13) { + hs->state = SSL3_ST_SR_CLNT_HELLO_D; + } + break; + + case SSL3_ST_SR_CLNT_HELLO_D: + ret = ssl3_select_parameters(hs); + if (ret <= 0) { + goto end; + } + ssl->method->received_flight(ssl); + hs->state = SSL3_ST_SW_SRVR_HELLO_A; + break; + + case SSL3_ST_SW_SRVR_HELLO_A: + ret = ssl3_send_server_hello(hs); + if (ret <= 0) { + goto end; + } + if (ssl->session != NULL) { + hs->state = SSL3_ST_SW_SESSION_TICKET_A; + } else { + hs->state = SSL3_ST_SW_CERT_A; + } + break; + + case SSL3_ST_SW_CERT_A: + if (ssl_cipher_uses_certificate_auth(hs->new_cipher)) { + ret = ssl3_send_server_certificate(hs); + if (ret <= 0) { + goto end; + } + } + hs->state = SSL3_ST_SW_CERT_STATUS_A; + break; + + case SSL3_ST_SW_CERT_STATUS_A: + if (hs->certificate_status_expected) { + ret = ssl3_send_certificate_status(hs); + if (ret <= 0) { + goto end; + } + } + hs->state = SSL3_ST_SW_KEY_EXCH_A; + break; + + case SSL3_ST_SW_KEY_EXCH_A: + case SSL3_ST_SW_KEY_EXCH_B: + alg_a = hs->new_cipher->algorithm_auth; + + /* PSK ciphers send ServerKeyExchange if there is an identity hint. */ + if (ssl_cipher_requires_server_key_exchange(hs->new_cipher) || + ((alg_a & SSL_aPSK) && ssl->psk_identity_hint)) { + ret = ssl3_send_server_key_exchange(hs); + if (ret <= 0) { + goto end; + } + } + + hs->state = SSL3_ST_SW_CERT_REQ_A; + break; + + case SSL3_ST_SW_CERT_REQ_A: + if (hs->cert_request) { + ret = ssl3_send_certificate_request(hs); + if (ret <= 0) { + goto end; + } + } + hs->state = SSL3_ST_SW_SRVR_DONE_A; + break; + + case SSL3_ST_SW_SRVR_DONE_A: + ret = ssl3_send_server_hello_done(hs); + if (ret <= 0) { + goto end; + } + hs->next_state = SSL3_ST_SR_CERT_A; + hs->state = SSL3_ST_SW_FLUSH; + break; + + case SSL3_ST_SR_CERT_A: + if (hs->cert_request) { + ret = ssl3_get_client_certificate(hs); + if (ret <= 0) { + goto end; + } + } + hs->state = SSL3_ST_SR_KEY_EXCH_A; + break; + + case SSL3_ST_SR_KEY_EXCH_A: + case SSL3_ST_SR_KEY_EXCH_B: + ret = ssl3_get_client_key_exchange(hs); + if (ret <= 0) { + goto end; + } + hs->state = SSL3_ST_SR_CERT_VRFY_A; + break; + + case SSL3_ST_SR_CERT_VRFY_A: + ret = ssl3_get_cert_verify(hs); + if (ret <= 0) { + goto end; + } + + hs->state = SSL3_ST_SR_CHANGE; + break; + + case SSL3_ST_SR_CHANGE: + ret = ssl->method->read_change_cipher_spec(ssl); + if (ret <= 0) { + goto end; + } + + if (!tls1_change_cipher_state(hs, SSL3_CHANGE_CIPHER_SERVER_READ)) { + ret = -1; + goto end; + } + + hs->state = SSL3_ST_SR_NEXT_PROTO_A; + break; + + case SSL3_ST_SR_NEXT_PROTO_A: + if (hs->next_proto_neg_seen) { + ret = ssl3_get_next_proto(hs); + if (ret <= 0) { + goto end; + } + } + hs->state = SSL3_ST_SR_CHANNEL_ID_A; + break; + + case SSL3_ST_SR_CHANNEL_ID_A: + if (ssl->s3->tlsext_channel_id_valid) { + ret = ssl3_get_channel_id(hs); + if (ret <= 0) { + goto end; + } + } + hs->state = SSL3_ST_SR_FINISHED_A; + break; + + case SSL3_ST_SR_FINISHED_A: + ret = ssl3_get_finished(hs); + if (ret <= 0) { + goto end; + } + + ssl->method->received_flight(ssl); + if (ssl->session != NULL) { + hs->state = SSL_ST_OK; + } else { + hs->state = SSL3_ST_SW_SESSION_TICKET_A; + } + + /* If this is a full handshake with ChannelID then record the handshake + * hashes in |hs->new_session| in case we need them to verify a + * ChannelID signature on a resumption of this session in the future. */ + if (ssl->session == NULL && ssl->s3->tlsext_channel_id_valid) { + ret = tls1_record_handshake_hashes_for_channel_id(hs); + if (ret <= 0) { + goto end; + } + } + break; + + case SSL3_ST_SW_SESSION_TICKET_A: + if (hs->ticket_expected) { + ret = ssl3_send_new_session_ticket(hs); + if (ret <= 0) { + goto end; + } + } + hs->state = SSL3_ST_SW_CHANGE; + break; + + case SSL3_ST_SW_CHANGE: + if (!ssl->method->add_change_cipher_spec(ssl) || + !tls1_change_cipher_state(hs, SSL3_CHANGE_CIPHER_SERVER_WRITE)) { + ret = -1; + goto end; + } + + hs->state = SSL3_ST_SW_FINISHED_A; + break; + + case SSL3_ST_SW_FINISHED_A: + ret = ssl3_send_finished(hs); + if (ret <= 0) { + goto end; + } + hs->state = SSL3_ST_SW_FLUSH; + if (ssl->session != NULL) { + hs->next_state = SSL3_ST_SR_CHANGE; + } else { + hs->next_state = SSL_ST_OK; + } + break; + + case SSL3_ST_SW_FLUSH: + ret = ssl->method->flush_flight(ssl); + if (ret <= 0) { + goto end; + } + + hs->state = hs->next_state; + if (hs->state != SSL_ST_OK) { + ssl->method->expect_flight(ssl); + } + break; + + case SSL_ST_TLS13: + ret = tls13_handshake(hs); + if (ret <= 0) { + goto end; + } + hs->state = SSL_ST_OK; + break; + + case SSL_ST_OK: + ssl->method->release_current_message(ssl, 1 /* free_buffer */); + + /* If we aren't retaining peer certificates then we can discard it + * now. */ + if (hs->new_session != NULL && + ssl->retain_only_sha256_of_client_certs) { + sk_CRYPTO_BUFFER_pop_free(hs->new_session->certs, CRYPTO_BUFFER_free); + hs->new_session->certs = NULL; + ssl->ctx->x509_method->session_clear(hs->new_session); + } + + SSL_SESSION_free(ssl->s3->established_session); + if (ssl->session != NULL) { + SSL_SESSION_up_ref(ssl->session); + ssl->s3->established_session = ssl->session; + } else { + ssl->s3->established_session = hs->new_session; + ssl->s3->established_session->not_resumable = 0; + hs->new_session = NULL; + } + + if (hs->v2_clienthello) { + CRYPTO_STATIC_MUTEX_lock_write(&g_v2clienthello_lock); + g_v2clienthello_count++; + CRYPTO_STATIC_MUTEX_unlock_write(&g_v2clienthello_lock); + } + + ssl->s3->initial_handshake_complete = 1; + ssl_update_cache(hs, SSL_SESS_CACHE_SERVER); + + ssl_do_info_callback(ssl, SSL_CB_HANDSHAKE_DONE, 1); + ret = 1; + goto end; + + default: + OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_STATE); + ret = -1; + goto end; + } + + if (hs->state != state) { + ssl_do_info_callback(ssl, SSL_CB_ACCEPT_LOOP, 1); + } + } + +end: + ssl_do_info_callback(ssl, SSL_CB_ACCEPT_EXIT, ret); + return ret; +} + +int ssl_client_cipher_list_contains_cipher(const SSL_CLIENT_HELLO *client_hello, + uint16_t id) { + CBS cipher_suites; + CBS_init(&cipher_suites, client_hello->cipher_suites, + client_hello->cipher_suites_len); + + while (CBS_len(&cipher_suites) > 0) { + uint16_t got_id; + if (!CBS_get_u16(&cipher_suites, &got_id)) { + return 0; + } + + if (got_id == id) { + return 1; + } + } + + return 0; +} + +static int negotiate_version(SSL_HANDSHAKE *hs, uint8_t *out_alert, + const SSL_CLIENT_HELLO *client_hello) { + SSL *const ssl = hs->ssl; + assert(!ssl->s3->have_version); + uint16_t min_version, max_version; + if (!ssl_get_version_range(ssl, &min_version, &max_version)) { + *out_alert = SSL_AD_PROTOCOL_VERSION; + return 0; + } + + uint16_t version = 0; + /* Check supported_versions extension if it is present. */ + CBS supported_versions; + if (ssl_client_hello_get_extension(client_hello, &supported_versions, + TLSEXT_TYPE_supported_versions)) { + CBS versions; + if (!CBS_get_u8_length_prefixed(&supported_versions, &versions) || + CBS_len(&supported_versions) != 0 || + CBS_len(&versions) == 0) { + OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + *out_alert = SSL_AD_DECODE_ERROR; + return 0; + } + + /* Choose the newest commonly-supported version advertised by the client. + * The client orders the versions according to its preferences, but we're + * not required to honor the client's preferences. */ + int found_version = 0; + while (CBS_len(&versions) != 0) { + uint16_t ext_version; + if (!CBS_get_u16(&versions, &ext_version)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + *out_alert = SSL_AD_DECODE_ERROR; + return 0; + } + if (!ssl->method->version_from_wire(&ext_version, ext_version)) { + continue; + } + if (min_version <= ext_version && + ext_version <= max_version && + (!found_version || version < ext_version)) { + version = ext_version; + found_version = 1; + } + } + + if (!found_version) { + goto unsupported_protocol; + } + } else { + /* Process ClientHello.version instead. Note that versions beyond (D)TLS 1.2 + * do not use this mechanism. */ + if (SSL_is_dtls(ssl)) { + if (client_hello->version <= DTLS1_2_VERSION) { + version = TLS1_2_VERSION; + } else if (client_hello->version <= DTLS1_VERSION) { + version = TLS1_1_VERSION; + } else { + goto unsupported_protocol; + } + } else { + if (client_hello->version >= TLS1_2_VERSION) { + version = TLS1_2_VERSION; + } else if (client_hello->version >= TLS1_1_VERSION) { + version = TLS1_1_VERSION; + } else if (client_hello->version >= TLS1_VERSION) { + version = TLS1_VERSION; + } else if (client_hello->version >= SSL3_VERSION) { + version = SSL3_VERSION; + } else { + goto unsupported_protocol; + } + } + + /* Apply our minimum and maximum version. */ + if (version > max_version) { + version = max_version; + } + + if (version < min_version) { + goto unsupported_protocol; + } + } + + /* Handle FALLBACK_SCSV. */ + if (ssl_client_cipher_list_contains_cipher(client_hello, + SSL3_CK_FALLBACK_SCSV & 0xffff) && + version < max_version) { + OPENSSL_PUT_ERROR(SSL, SSL_R_INAPPROPRIATE_FALLBACK); + *out_alert = SSL3_AD_INAPPROPRIATE_FALLBACK; + return 0; + } + + hs->client_version = client_hello->version; + ssl->version = ssl->method->version_to_wire(version); + + /* At this point, the connection's version is known and |ssl->version| is + * fixed. Begin enforcing the record-layer version. */ + ssl->s3->have_version = 1; + + return 1; + +unsupported_protocol: + OPENSSL_PUT_ERROR(SSL, SSL_R_UNSUPPORTED_PROTOCOL); + *out_alert = SSL_AD_PROTOCOL_VERSION; + return 0; +} + +static STACK_OF(SSL_CIPHER) * + ssl_parse_client_cipher_list(const SSL_CLIENT_HELLO *client_hello) { + CBS cipher_suites; + CBS_init(&cipher_suites, client_hello->cipher_suites, + client_hello->cipher_suites_len); + + STACK_OF(SSL_CIPHER) *sk = sk_SSL_CIPHER_new_null(); + if (sk == NULL) { + OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + goto err; + } + + while (CBS_len(&cipher_suites) > 0) { + uint16_t cipher_suite; + + if (!CBS_get_u16(&cipher_suites, &cipher_suite)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST); + goto err; + } + + const SSL_CIPHER *c = SSL_get_cipher_by_value(cipher_suite); + if (c != NULL && !sk_SSL_CIPHER_push(sk, c)) { + OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + goto err; + } + } + + return sk; + +err: + sk_SSL_CIPHER_free(sk); + return NULL; +} + +/* ssl_get_compatible_server_ciphers determines the key exchange and + * authentication cipher suite masks compatible with the server configuration + * and current ClientHello parameters of |hs|. It sets |*out_mask_k| to the key + * exchange mask and |*out_mask_a| to the authentication mask. */ +static void ssl_get_compatible_server_ciphers(SSL_HANDSHAKE *hs, + uint32_t *out_mask_k, + uint32_t *out_mask_a) { + SSL *const ssl = hs->ssl; + if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) { + *out_mask_k = SSL_kGENERIC; + *out_mask_a = SSL_aGENERIC; + return; + } + + uint32_t mask_k = 0; + uint32_t mask_a = 0; + + if (ssl_has_certificate(ssl)) { + int type = ssl_private_key_type(ssl); + if (type == NID_rsaEncryption) { + mask_k |= SSL_kRSA; + mask_a |= SSL_aRSA; + } else if (ssl_is_ecdsa_key_type(type)) { + mask_a |= SSL_aECDSA; + } + } + + if (ssl->cert->dh_tmp != NULL || ssl->cert->dh_tmp_cb != NULL) { + mask_k |= SSL_kDHE; + } + + /* Check for a shared group to consider ECDHE ciphers. */ + uint16_t unused; + if (tls1_get_shared_group(hs, &unused)) { + mask_k |= SSL_kECDHE; + } + + /* PSK requires a server callback. */ + if (ssl->psk_server_callback != NULL) { + mask_k |= SSL_kPSK; + mask_a |= SSL_aPSK; + } + + *out_mask_k = mask_k; + *out_mask_a = mask_a; +} + +static const SSL_CIPHER *ssl3_choose_cipher( + SSL_HANDSHAKE *hs, const SSL_CLIENT_HELLO *client_hello, + const struct ssl_cipher_preference_list_st *server_pref) { + SSL *const ssl = hs->ssl; + const SSL_CIPHER *c, *ret = NULL; + STACK_OF(SSL_CIPHER) *srvr = server_pref->ciphers, *prio, *allow; + int ok; + size_t cipher_index; + uint32_t alg_k, alg_a, mask_k, mask_a; + /* in_group_flags will either be NULL, or will point to an array of bytes + * which indicate equal-preference groups in the |prio| stack. See the + * comment about |in_group_flags| in the |ssl_cipher_preference_list_st| + * struct. */ + const uint8_t *in_group_flags; + /* group_min contains the minimal index so far found in a group, or -1 if no + * such value exists yet. */ + int group_min = -1; + + STACK_OF(SSL_CIPHER) *clnt = ssl_parse_client_cipher_list(client_hello); + if (clnt == NULL) { + return NULL; + } + + if (ssl->options & SSL_OP_CIPHER_SERVER_PREFERENCE) { + prio = srvr; + in_group_flags = server_pref->in_group_flags; + allow = clnt; + } else { + prio = clnt; + in_group_flags = NULL; + allow = srvr; + } + + ssl_get_compatible_server_ciphers(hs, &mask_k, &mask_a); + + for (size_t i = 0; i < sk_SSL_CIPHER_num(prio); i++) { + c = sk_SSL_CIPHER_value(prio, i); + + ok = 1; + + /* Check the TLS version. */ + if (SSL_CIPHER_get_min_version(c) > ssl3_protocol_version(ssl) || + SSL_CIPHER_get_max_version(c) < ssl3_protocol_version(ssl)) { + ok = 0; + } + + alg_k = c->algorithm_mkey; + alg_a = c->algorithm_auth; + + ok = ok && (alg_k & mask_k) && (alg_a & mask_a); + + if (ok && sk_SSL_CIPHER_find(allow, &cipher_index, c)) { + if (in_group_flags != NULL && in_group_flags[i] == 1) { + /* This element of |prio| is in a group. Update the minimum index found + * so far and continue looking. */ + if (group_min == -1 || (size_t)group_min > cipher_index) { + group_min = cipher_index; + } + } else { + if (group_min != -1 && (size_t)group_min < cipher_index) { + cipher_index = group_min; + } + ret = sk_SSL_CIPHER_value(allow, cipher_index); + break; + } + } + + if (in_group_flags != NULL && in_group_flags[i] == 0 && group_min != -1) { + /* We are about to leave a group, but we found a match in it, so that's + * our answer. */ + ret = sk_SSL_CIPHER_value(allow, group_min); + break; + } + } + + sk_SSL_CIPHER_free(clnt); + return ret; +} + +static int ssl3_process_client_hello(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + if (!ssl_check_message_type(ssl, SSL3_MT_CLIENT_HELLO)) { + return -1; + } + + SSL_CLIENT_HELLO client_hello; + if (!ssl_client_hello_init(ssl, &client_hello, ssl->init_msg, + ssl->init_num)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); + return -1; + } + + /* Run the early callback. */ + if (ssl->ctx->select_certificate_cb != NULL) { + switch (ssl->ctx->select_certificate_cb(&client_hello)) { + case 0: + ssl->rwstate = SSL_CERTIFICATE_SELECTION_PENDING; + return -1; + + case -1: + /* Connection rejected. */ + OPENSSL_PUT_ERROR(SSL, SSL_R_CONNECTION_REJECTED); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE); + return -1; + + default: + /* fallthrough */; + } + } + + uint8_t alert = SSL_AD_DECODE_ERROR; + if (!negotiate_version(hs, &alert, &client_hello)) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, alert); + return -1; + } + + /* Load the client random. */ + if (client_hello.random_len != SSL3_RANDOM_SIZE) { + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + return -1; + } + OPENSSL_memcpy(ssl->s3->client_random, client_hello.random, + client_hello.random_len); + + /* Only null compression is supported. TLS 1.3 further requires the peer + * advertise no other compression. */ + if (OPENSSL_memchr(client_hello.compression_methods, 0, + client_hello.compression_methods_len) == NULL || + (ssl3_protocol_version(ssl) >= TLS1_3_VERSION && + client_hello.compression_methods_len != 1)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_COMPRESSION_LIST); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER); + return -1; + } + + /* TLS extensions. */ + if (!ssl_parse_clienthello_tlsext(hs, &client_hello)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_PARSE_TLSEXT); + return -1; + } + + return 1; +} + +static int ssl3_select_certificate(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + /* Call |cert_cb| to update server certificates if required. */ + if (ssl->cert->cert_cb != NULL) { + int rv = ssl->cert->cert_cb(ssl, ssl->cert->cert_cb_arg); + if (rv == 0) { + OPENSSL_PUT_ERROR(SSL, SSL_R_CERT_CB_ERROR); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); + return -1; + } + if (rv < 0) { + ssl->rwstate = SSL_X509_LOOKUP; + return -1; + } + } + + if (!ssl_auto_chain_if_needed(ssl)) { + return -1; + } + + if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) { + /* Jump to the TLS 1.3 state machine. */ + hs->state = SSL_ST_TLS13; + hs->do_tls13_handshake = tls13_server_handshake; + return 1; + } + + SSL_CLIENT_HELLO client_hello; + if (!ssl_client_hello_init(ssl, &client_hello, ssl->init_msg, + ssl->init_num)) { + return -1; + } + + /* Negotiate the cipher suite. This must be done after |cert_cb| so the + * certificate is finalized. */ + hs->new_cipher = + ssl3_choose_cipher(hs, &client_hello, ssl_get_cipher_preferences(ssl)); + if (hs->new_cipher == NULL) { + OPENSSL_PUT_ERROR(SSL, SSL_R_NO_SHARED_CIPHER); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE); + return -1; + } + + return 1; +} + +static int ssl3_select_parameters(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + uint8_t al = SSL_AD_INTERNAL_ERROR; + int ret = -1; + SSL_SESSION *session = NULL; + + SSL_CLIENT_HELLO client_hello; + if (!ssl_client_hello_init(ssl, &client_hello, ssl->init_msg, + ssl->init_num)) { + return -1; + } + + /* Determine whether we are doing session resumption. */ + int tickets_supported = 0, renew_ticket = 0; + switch (ssl_get_prev_session(ssl, &session, &tickets_supported, &renew_ticket, + &client_hello)) { + case ssl_session_success: + break; + case ssl_session_error: + goto err; + case ssl_session_retry: + ssl->rwstate = SSL_PENDING_SESSION; + goto err; + } + + if (session != NULL) { + if (session->extended_master_secret && !hs->extended_master_secret) { + /* A ClientHello without EMS that attempts to resume a session with EMS + * is fatal to the connection. */ + al = SSL_AD_HANDSHAKE_FAILURE; + OPENSSL_PUT_ERROR(SSL, SSL_R_RESUMED_EMS_SESSION_WITHOUT_EMS_EXTENSION); + goto f_err; + } + + if (!ssl_session_is_resumable(hs, session) || + /* If the client offers the EMS extension, but the previous session + * didn't use it, then negotiate a new session. */ + hs->extended_master_secret != session->extended_master_secret) { + SSL_SESSION_free(session); + session = NULL; + } + } + + if (session != NULL) { + /* Use the old session. */ + hs->ticket_expected = renew_ticket; + ssl->session = session; + session = NULL; + ssl->s3->session_reused = 1; + } else { + hs->ticket_expected = tickets_supported; + ssl_set_session(ssl, NULL); + if (!ssl_get_new_session(hs, 1 /* server */)) { + goto err; + } + + /* Clear the session ID if we want the session to be single-use. */ + if (!(ssl->ctx->session_cache_mode & SSL_SESS_CACHE_SERVER)) { + hs->new_session->session_id_length = 0; + } + } + + if (ssl->ctx->dos_protection_cb != NULL && + ssl->ctx->dos_protection_cb(&client_hello) == 0) { + /* Connection rejected for DOS reasons. */ + al = SSL_AD_INTERNAL_ERROR; + OPENSSL_PUT_ERROR(SSL, SSL_R_CONNECTION_REJECTED); + goto f_err; + } + + if (ssl->session == NULL) { + hs->new_session->cipher = hs->new_cipher; + + /* On new sessions, stash the SNI value in the session. */ + if (hs->hostname != NULL) { + OPENSSL_free(hs->new_session->tlsext_hostname); + hs->new_session->tlsext_hostname = BUF_strdup(hs->hostname); + if (hs->new_session->tlsext_hostname == NULL) { + al = SSL_AD_INTERNAL_ERROR; + goto f_err; + } + } + + /* Determine whether to request a client certificate. */ + hs->cert_request = !!(ssl->verify_mode & SSL_VERIFY_PEER); + /* Only request a certificate if Channel ID isn't negotiated. */ + if ((ssl->verify_mode & SSL_VERIFY_PEER_IF_NO_OBC) && + ssl->s3->tlsext_channel_id_valid) { + hs->cert_request = 0; + } + /* CertificateRequest may only be sent in certificate-based ciphers. */ + if (!ssl_cipher_uses_certificate_auth(hs->new_cipher)) { + hs->cert_request = 0; + } + + if (!hs->cert_request) { + /* OpenSSL returns X509_V_OK when no certificates are requested. This is + * classed by them as a bug, but it's assumed by at least NGINX. */ + hs->new_session->verify_result = X509_V_OK; + } + } + + /* HTTP/2 negotiation depends on the cipher suite, so ALPN negotiation was + * deferred. Complete it now. */ + if (!ssl_negotiate_alpn(hs, &al, &client_hello)) { + goto f_err; + } + + /* Now that all parameters are known, initialize the handshake hash and hash + * the ClientHello. */ + if (!SSL_TRANSCRIPT_init_hash(&hs->transcript, ssl3_protocol_version(ssl), + hs->new_cipher->algorithm_prf) || + !ssl_hash_current_message(hs)) { + goto f_err; + } + + /* Release the handshake buffer if client authentication isn't required. */ + if (!hs->cert_request) { + SSL_TRANSCRIPT_free_buffer(&hs->transcript); + } + + ret = 1; + + if (0) { + f_err: + ssl3_send_alert(ssl, SSL3_AL_FATAL, al); + } + +err: + SSL_SESSION_free(session); + return ret; +} + +static int ssl3_send_server_hello(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + + /* We only accept ChannelIDs on connections with ECDHE in order to avoid a + * known attack while we fix ChannelID itself. */ + if (ssl->s3->tlsext_channel_id_valid && + (hs->new_cipher->algorithm_mkey & SSL_kECDHE) == 0) { + ssl->s3->tlsext_channel_id_valid = 0; + } + + /* If this is a resumption and the original handshake didn't support + * ChannelID then we didn't record the original handshake hashes in the + * session and so cannot resume with ChannelIDs. */ + if (ssl->session != NULL && + ssl->session->original_handshake_hash_len == 0) { + ssl->s3->tlsext_channel_id_valid = 0; + } + + struct timeval now; + ssl_get_current_time(ssl, &now); + ssl->s3->server_random[0] = now.tv_sec >> 24; + ssl->s3->server_random[1] = now.tv_sec >> 16; + ssl->s3->server_random[2] = now.tv_sec >> 8; + ssl->s3->server_random[3] = now.tv_sec; + if (!RAND_bytes(ssl->s3->server_random + 4, SSL3_RANDOM_SIZE - 4)) { + return -1; + } + + /* TODO(davidben): Implement the TLS 1.1 and 1.2 downgrade sentinels once TLS + * 1.3 is finalized and we are not implementing a draft version. */ + + const SSL_SESSION *session = hs->new_session; + if (ssl->session != NULL) { + session = ssl->session; + } + + CBB cbb, body, session_id; + if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_SERVER_HELLO) || + !CBB_add_u16(&body, ssl->version) || + !CBB_add_bytes(&body, ssl->s3->server_random, SSL3_RANDOM_SIZE) || + !CBB_add_u8_length_prefixed(&body, &session_id) || + !CBB_add_bytes(&session_id, session->session_id, + session->session_id_length) || + !CBB_add_u16(&body, ssl_cipher_get_value(hs->new_cipher)) || + !CBB_add_u8(&body, 0 /* no compression */) || + !ssl_add_serverhello_tlsext(hs, &body) || + !ssl_add_message_cbb(ssl, &cbb)) { + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + CBB_cleanup(&cbb); + return -1; + } + + return 1; +} + +static int ssl3_send_server_certificate(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + if (!ssl_has_certificate(ssl)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CERTIFICATE_SET); + return -1; + } + + if (!ssl3_output_cert_chain(ssl)) { + return -1; + } + return 1; +} + +static int ssl3_send_certificate_status(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + CBB cbb, body, ocsp_response; + if (!ssl->method->init_message(ssl, &cbb, &body, + SSL3_MT_CERTIFICATE_STATUS) || + !CBB_add_u8(&body, TLSEXT_STATUSTYPE_ocsp) || + !CBB_add_u24_length_prefixed(&body, &ocsp_response) || + !CBB_add_bytes(&ocsp_response, + CRYPTO_BUFFER_data(ssl->cert->ocsp_response), + CRYPTO_BUFFER_len(ssl->cert->ocsp_response)) || + !ssl_add_message_cbb(ssl, &cbb)) { + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + CBB_cleanup(&cbb); + return -1; + } + + return 1; +} + +static int ssl3_send_server_key_exchange(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + CBB cbb, child; + CBB_zero(&cbb); + + /* Put together the parameters. */ + if (hs->state == SSL3_ST_SW_KEY_EXCH_A) { + uint32_t alg_k = hs->new_cipher->algorithm_mkey; + uint32_t alg_a = hs->new_cipher->algorithm_auth; + + /* Pre-allocate enough room to comfortably fit an ECDHE public key. */ + if (!CBB_init(&cbb, 128)) { + goto err; + } + + /* PSK ciphers begin with an identity hint. */ + if (alg_a & SSL_aPSK) { + size_t len = + (ssl->psk_identity_hint == NULL) ? 0 : strlen(ssl->psk_identity_hint); + if (!CBB_add_u16_length_prefixed(&cbb, &child) || + !CBB_add_bytes(&child, (const uint8_t *)ssl->psk_identity_hint, + len)) { + goto err; + } + } + + if (alg_k & SSL_kDHE) { + /* Determine the group to use. */ + DH *params = ssl->cert->dh_tmp; + if (params == NULL && ssl->cert->dh_tmp_cb != NULL) { + params = ssl->cert->dh_tmp_cb(ssl, 0, 1024); + } + if (params == NULL) { + OPENSSL_PUT_ERROR(SSL, SSL_R_MISSING_TMP_DH_KEY); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE); + goto err; + } + + /* Set up DH, generate a key, and emit the public half. */ + DH *dh = DHparams_dup(params); + if (dh == NULL) { + goto err; + } + + SSL_ECDH_CTX_init_for_dhe(&hs->ecdh_ctx, dh); + if (!CBB_add_u16_length_prefixed(&cbb, &child) || + !BN_bn2cbb_padded(&child, BN_num_bytes(params->p), params->p) || + !CBB_add_u16_length_prefixed(&cbb, &child) || + !BN_bn2cbb_padded(&child, BN_num_bytes(params->g), params->g) || + !CBB_add_u16_length_prefixed(&cbb, &child) || + !SSL_ECDH_CTX_offer(&hs->ecdh_ctx, &child)) { + goto err; + } + } else if (alg_k & SSL_kECDHE) { + /* Determine the group to use. */ + uint16_t group_id; + if (!tls1_get_shared_group(hs, &group_id)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_MISSING_TMP_ECDH_KEY); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE); + goto err; + } + hs->new_session->group_id = group_id; + + /* Set up ECDH, generate a key, and emit the public half. */ + if (!SSL_ECDH_CTX_init(&hs->ecdh_ctx, group_id) || + !CBB_add_u8(&cbb, NAMED_CURVE_TYPE) || + !CBB_add_u16(&cbb, group_id) || + !CBB_add_u8_length_prefixed(&cbb, &child) || + !SSL_ECDH_CTX_offer(&hs->ecdh_ctx, &child)) { + goto err; + } + } else { + assert(alg_k & SSL_kPSK); + } + + if (!CBB_finish(&cbb, &hs->server_params, &hs->server_params_len)) { + goto err; + } + } + + /* Assemble the message. */ + CBB body; + if (!ssl->method->init_message(ssl, &cbb, &body, + SSL3_MT_SERVER_KEY_EXCHANGE) || + !CBB_add_bytes(&body, hs->server_params, hs->server_params_len)) { + goto err; + } + + /* Add a signature. */ + if (ssl_cipher_uses_certificate_auth(hs->new_cipher)) { + if (!ssl_has_private_key(ssl)) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); + goto err; + } + + /* Determine the signature algorithm. */ + uint16_t signature_algorithm; + if (!tls1_choose_signature_algorithm(hs, &signature_algorithm)) { + goto err; + } + if (ssl3_protocol_version(ssl) >= TLS1_2_VERSION) { + if (!CBB_add_u16(&body, signature_algorithm)) { + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); + goto err; + } + } + + /* Add space for the signature. */ + const size_t max_sig_len = ssl_private_key_max_signature_len(ssl); + uint8_t *ptr; + if (!CBB_add_u16_length_prefixed(&body, &child) || + !CBB_reserve(&child, &ptr, max_sig_len)) { + goto err; + } + + size_t sig_len; + enum ssl_private_key_result_t sign_result; + if (hs->state == SSL3_ST_SW_KEY_EXCH_A) { + CBB transcript; + uint8_t *transcript_data; + size_t transcript_len; + if (!CBB_init(&transcript, + 2 * SSL3_RANDOM_SIZE + hs->server_params_len) || + !CBB_add_bytes(&transcript, ssl->s3->client_random, + SSL3_RANDOM_SIZE) || + !CBB_add_bytes(&transcript, ssl->s3->server_random, + SSL3_RANDOM_SIZE) || + !CBB_add_bytes(&transcript, hs->server_params, + hs->server_params_len) || + !CBB_finish(&transcript, &transcript_data, &transcript_len)) { + CBB_cleanup(&transcript); + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); + goto err; + } + + sign_result = ssl_private_key_sign(ssl, ptr, &sig_len, max_sig_len, + signature_algorithm, transcript_data, + transcript_len); + OPENSSL_free(transcript_data); + } else { + assert(hs->state == SSL3_ST_SW_KEY_EXCH_B); + sign_result = ssl_private_key_complete(ssl, ptr, &sig_len, max_sig_len); + } + + switch (sign_result) { + case ssl_private_key_success: + if (!CBB_did_write(&child, sig_len)) { + goto err; + } + break; + case ssl_private_key_failure: + goto err; + case ssl_private_key_retry: + ssl->rwstate = SSL_PRIVATE_KEY_OPERATION; + hs->state = SSL3_ST_SW_KEY_EXCH_B; + goto err; + } + } + + if (!ssl_add_message_cbb(ssl, &cbb)) { + goto err; + } + + OPENSSL_free(hs->server_params); + hs->server_params = NULL; + hs->server_params_len = 0; + + return 1; + +err: + CBB_cleanup(&cbb); + return -1; +} + +static int add_cert_types(SSL *ssl, CBB *cbb) { + /* Get configured signature algorithms. */ + int have_rsa_sign = 0; + int have_ecdsa_sign = 0; + const uint16_t *sig_algs; + size_t num_sig_algs = tls12_get_verify_sigalgs(ssl, &sig_algs); + for (size_t i = 0; i < num_sig_algs; i++) { + switch (sig_algs[i]) { + case SSL_SIGN_RSA_PKCS1_SHA512: + case SSL_SIGN_RSA_PKCS1_SHA384: + case SSL_SIGN_RSA_PKCS1_SHA256: + case SSL_SIGN_RSA_PKCS1_SHA1: + have_rsa_sign = 1; + break; + + case SSL_SIGN_ECDSA_SECP521R1_SHA512: + case SSL_SIGN_ECDSA_SECP384R1_SHA384: + case SSL_SIGN_ECDSA_SECP256R1_SHA256: + case SSL_SIGN_ECDSA_SHA1: + have_ecdsa_sign = 1; + break; + } + } + + if (have_rsa_sign && !CBB_add_u8(cbb, SSL3_CT_RSA_SIGN)) { + return 0; + } + + /* ECDSA certs can be used with RSA cipher suites as well so we don't need to + * check for SSL_kECDH or SSL_kECDHE. */ + if (ssl->version >= TLS1_VERSION && have_ecdsa_sign && + !CBB_add_u8(cbb, TLS_CT_ECDSA_SIGN)) { + return 0; + } + + return 1; +} + +static int ssl3_send_certificate_request(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + CBB cbb, body, cert_types, sigalgs_cbb; + if (!ssl->method->init_message(ssl, &cbb, &body, + SSL3_MT_CERTIFICATE_REQUEST) || + !CBB_add_u8_length_prefixed(&body, &cert_types) || + !add_cert_types(ssl, &cert_types)) { + goto err; + } + + if (ssl3_protocol_version(ssl) >= TLS1_2_VERSION) { + const uint16_t *sigalgs; + size_t num_sigalgs = tls12_get_verify_sigalgs(ssl, &sigalgs); + if (!CBB_add_u16_length_prefixed(&body, &sigalgs_cbb)) { + goto err; + } + + for (size_t i = 0; i < num_sigalgs; i++) { + if (!CBB_add_u16(&sigalgs_cbb, sigalgs[i])) { + goto err; + } + } + } + + if (!ssl_add_client_CA_list(ssl, &body) || + !ssl_add_message_cbb(ssl, &cbb)) { + goto err; + } + + return 1; + +err: + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + CBB_cleanup(&cbb); + return -1; +} + +static int ssl3_send_server_hello_done(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + CBB cbb, body; + if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_SERVER_HELLO_DONE) || + !ssl_add_message_cbb(ssl, &cbb)) { + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + CBB_cleanup(&cbb); + return -1; + } + + return 1; +} + +static int ssl3_get_client_certificate(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + assert(hs->cert_request); + + int msg_ret = ssl->method->ssl_get_message(ssl); + if (msg_ret <= 0) { + return msg_ret; + } + + if (ssl->s3->tmp.message_type != SSL3_MT_CERTIFICATE) { + if (ssl->version == SSL3_VERSION && + ssl->s3->tmp.message_type == SSL3_MT_CLIENT_KEY_EXCHANGE) { + /* In SSL 3.0, the Certificate message is omitted to signal no + * certificate. */ + if (ssl->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) { + OPENSSL_PUT_ERROR(SSL, SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE); + return -1; + } + + /* OpenSSL returns X509_V_OK when no certificates are received. This is + * classed by them as a bug, but it's assumed by at least NGINX. */ + hs->new_session->verify_result = X509_V_OK; + ssl->s3->tmp.reuse_message = 1; + return 1; + } + + OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_MESSAGE); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE); + return -1; + } + + if (!ssl_hash_current_message(hs)) { + return -1; + } + + CBS certificate_msg; + CBS_init(&certificate_msg, ssl->init_msg, ssl->init_num); + + sk_CRYPTO_BUFFER_pop_free(hs->new_session->certs, CRYPTO_BUFFER_free); + EVP_PKEY_free(hs->peer_pubkey); + hs->peer_pubkey = NULL; + uint8_t alert = SSL_AD_DECODE_ERROR; + hs->new_session->certs = ssl_parse_cert_chain( + &alert, &hs->peer_pubkey, + ssl->retain_only_sha256_of_client_certs ? hs->new_session->peer_sha256 + : NULL, + &certificate_msg, ssl->ctx->pool); + if (hs->new_session->certs == NULL) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, alert); + return -1; + } + + if (CBS_len(&certificate_msg) != 0 || + !ssl->ctx->x509_method->session_cache_objects(hs->new_session)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); + return -1; + } + + if (sk_CRYPTO_BUFFER_num(hs->new_session->certs) == 0) { + /* No client certificate so the handshake buffer may be discarded. */ + SSL_TRANSCRIPT_free_buffer(&hs->transcript); + + /* In SSL 3.0, sending no certificate is signaled by omitting the + * Certificate message. */ + if (ssl->version == SSL3_VERSION) { + OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CERTIFICATES_RETURNED); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE); + return -1; + } + + if (ssl->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) { + /* Fail for TLS only if we required a certificate */ + OPENSSL_PUT_ERROR(SSL, SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE); + return -1; + } + + /* OpenSSL returns X509_V_OK when no certificates are received. This is + * classed by them as a bug, but it's assumed by at least NGINX. */ + hs->new_session->verify_result = X509_V_OK; + return 1; + } + + /* The hash will have been filled in. */ + if (ssl->retain_only_sha256_of_client_certs) { + hs->new_session->peer_sha256_valid = 1; + } + + if (!ssl_verify_cert_chain(ssl, &hs->new_session->verify_result, + hs->new_session->x509_chain)) { + return -1; + } + return 1; +} + +static int ssl3_get_client_key_exchange(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + int al; + CBS client_key_exchange; + uint32_t alg_k; + uint32_t alg_a; + uint8_t *premaster_secret = NULL; + size_t premaster_secret_len = 0; + uint8_t *decrypt_buf = NULL; + + unsigned psk_len = 0; + uint8_t psk[PSK_MAX_PSK_LEN]; + + if (hs->state == SSL3_ST_SR_KEY_EXCH_A) { + int ret = ssl->method->ssl_get_message(ssl); + if (ret <= 0) { + return ret; + } + + if (!ssl_check_message_type(ssl, SSL3_MT_CLIENT_KEY_EXCHANGE) || + !ssl_hash_current_message(hs)) { + return -1; + } + } + + CBS_init(&client_key_exchange, ssl->init_msg, ssl->init_num); + alg_k = hs->new_cipher->algorithm_mkey; + alg_a = hs->new_cipher->algorithm_auth; + + /* If using a PSK key exchange, prepare the pre-shared key. */ + if (alg_a & SSL_aPSK) { + CBS psk_identity; + + /* If using PSK, the ClientKeyExchange contains a psk_identity. If PSK, + * then this is the only field in the message. */ + if (!CBS_get_u16_length_prefixed(&client_key_exchange, &psk_identity) || + ((alg_k & SSL_kPSK) && CBS_len(&client_key_exchange) != 0)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + al = SSL_AD_DECODE_ERROR; + goto f_err; + } + + if (ssl->psk_server_callback == NULL) { + OPENSSL_PUT_ERROR(SSL, SSL_R_PSK_NO_SERVER_CB); + al = SSL_AD_INTERNAL_ERROR; + goto f_err; + } + + if (CBS_len(&psk_identity) > PSK_MAX_IDENTITY_LEN || + CBS_contains_zero_byte(&psk_identity)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_DATA_LENGTH_TOO_LONG); + al = SSL_AD_ILLEGAL_PARAMETER; + goto f_err; + } + + if (!CBS_strdup(&psk_identity, &hs->new_session->psk_identity)) { + al = SSL_AD_INTERNAL_ERROR; + OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + goto f_err; + } + + /* Look up the key for the identity. */ + psk_len = ssl->psk_server_callback(ssl, hs->new_session->psk_identity, psk, + sizeof(psk)); + if (psk_len > PSK_MAX_PSK_LEN) { + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + al = SSL_AD_INTERNAL_ERROR; + goto f_err; + } else if (psk_len == 0) { + /* PSK related to the given identity not found */ + OPENSSL_PUT_ERROR(SSL, SSL_R_PSK_IDENTITY_NOT_FOUND); + al = SSL_AD_UNKNOWN_PSK_IDENTITY; + goto f_err; + } + } + + /* Depending on the key exchange method, compute |premaster_secret| and + * |premaster_secret_len|. */ + if (alg_k & SSL_kRSA) { + /* Allocate a buffer large enough for an RSA decryption. */ + const size_t rsa_size = ssl_private_key_max_signature_len(ssl); + decrypt_buf = OPENSSL_malloc(rsa_size); + if (decrypt_buf == NULL) { + OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + goto err; + } + + enum ssl_private_key_result_t decrypt_result; + size_t decrypt_len; + if (hs->state == SSL3_ST_SR_KEY_EXCH_A) { + if (!ssl_has_private_key(ssl) || + ssl_private_key_type(ssl) != NID_rsaEncryption) { + al = SSL_AD_HANDSHAKE_FAILURE; + OPENSSL_PUT_ERROR(SSL, SSL_R_MISSING_RSA_CERTIFICATE); + goto f_err; + } + CBS encrypted_premaster_secret; + if (ssl->version > SSL3_VERSION) { + if (!CBS_get_u16_length_prefixed(&client_key_exchange, + &encrypted_premaster_secret) || + CBS_len(&client_key_exchange) != 0) { + al = SSL_AD_DECODE_ERROR; + OPENSSL_PUT_ERROR(SSL, + SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG); + goto f_err; + } + } else { + encrypted_premaster_secret = client_key_exchange; + } + + /* Decrypt with no padding. PKCS#1 padding will be removed as part of the + * timing-sensitive code below. */ + decrypt_result = ssl_private_key_decrypt( + ssl, decrypt_buf, &decrypt_len, rsa_size, + CBS_data(&encrypted_premaster_secret), + CBS_len(&encrypted_premaster_secret)); + } else { + assert(hs->state == SSL3_ST_SR_KEY_EXCH_B); + /* Complete async decrypt. */ + decrypt_result = + ssl_private_key_complete(ssl, decrypt_buf, &decrypt_len, rsa_size); + } + + switch (decrypt_result) { + case ssl_private_key_success: + break; + case ssl_private_key_failure: + goto err; + case ssl_private_key_retry: + ssl->rwstate = SSL_PRIVATE_KEY_OPERATION; + hs->state = SSL3_ST_SR_KEY_EXCH_B; + goto err; + } + + if (decrypt_len != rsa_size) { + al = SSL_AD_DECRYPT_ERROR; + OPENSSL_PUT_ERROR(SSL, SSL_R_DECRYPTION_FAILED); + goto f_err; + } + + /* Prepare a random premaster, to be used on invalid padding. See RFC 5246, + * section 7.4.7.1. */ + premaster_secret_len = SSL_MAX_MASTER_KEY_LENGTH; + premaster_secret = OPENSSL_malloc(premaster_secret_len); + if (premaster_secret == NULL) { + OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + goto err; + } + if (!RAND_bytes(premaster_secret, premaster_secret_len)) { + goto err; + } + + /* The smallest padded premaster is 11 bytes of overhead. Small keys are + * publicly invalid. */ + if (decrypt_len < 11 + premaster_secret_len) { + al = SSL_AD_DECRYPT_ERROR; + OPENSSL_PUT_ERROR(SSL, SSL_R_DECRYPTION_FAILED); + goto f_err; + } + + /* Check the padding. See RFC 3447, section 7.2.2. */ + size_t padding_len = decrypt_len - premaster_secret_len; + uint8_t good = constant_time_eq_int_8(decrypt_buf[0], 0) & + constant_time_eq_int_8(decrypt_buf[1], 2); + for (size_t i = 2; i < padding_len - 1; i++) { + good &= ~constant_time_is_zero_8(decrypt_buf[i]); + } + good &= constant_time_is_zero_8(decrypt_buf[padding_len - 1]); + + /* The premaster secret must begin with |client_version|. This too must be + * checked in constant time (http://eprint.iacr.org/2003/052/). */ + good &= constant_time_eq_8(decrypt_buf[padding_len], + (unsigned)(hs->client_version >> 8)); + good &= constant_time_eq_8(decrypt_buf[padding_len + 1], + (unsigned)(hs->client_version & 0xff)); + + /* Select, in constant time, either the decrypted premaster or the random + * premaster based on |good|. */ + for (size_t i = 0; i < premaster_secret_len; i++) { + premaster_secret[i] = constant_time_select_8( + good, decrypt_buf[padding_len + i], premaster_secret[i]); + } + + OPENSSL_free(decrypt_buf); + decrypt_buf = NULL; + } else if (alg_k & (SSL_kECDHE|SSL_kDHE)) { + /* Parse the ClientKeyExchange. */ + CBS peer_key; + if (!SSL_ECDH_CTX_get_key(&hs->ecdh_ctx, &client_key_exchange, &peer_key) || + CBS_len(&client_key_exchange) != 0) { + al = SSL_AD_DECODE_ERROR; + OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + goto f_err; + } + + /* Compute the premaster. */ + uint8_t alert = SSL_AD_DECODE_ERROR; + if (!SSL_ECDH_CTX_finish(&hs->ecdh_ctx, &premaster_secret, + &premaster_secret_len, &alert, CBS_data(&peer_key), + CBS_len(&peer_key))) { + al = alert; + goto f_err; + } + + /* The key exchange state may now be discarded. */ + SSL_ECDH_CTX_cleanup(&hs->ecdh_ctx); + } else if (alg_k & SSL_kPSK) { + /* For plain PSK, other_secret is a block of 0s with the same length as the + * pre-shared key. */ + premaster_secret_len = psk_len; + premaster_secret = OPENSSL_malloc(premaster_secret_len); + if (premaster_secret == NULL) { + OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + goto err; + } + OPENSSL_memset(premaster_secret, 0, premaster_secret_len); + } else { + al = SSL_AD_HANDSHAKE_FAILURE; + OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_CIPHER_TYPE); + goto f_err; + } + + /* For a PSK cipher suite, the actual pre-master secret is combined with the + * pre-shared key. */ + if (alg_a & SSL_aPSK) { + CBB new_premaster, child; + uint8_t *new_data; + size_t new_len; + + CBB_zero(&new_premaster); + if (!CBB_init(&new_premaster, 2 + psk_len + 2 + premaster_secret_len) || + !CBB_add_u16_length_prefixed(&new_premaster, &child) || + !CBB_add_bytes(&child, premaster_secret, premaster_secret_len) || + !CBB_add_u16_length_prefixed(&new_premaster, &child) || + !CBB_add_bytes(&child, psk, psk_len) || + !CBB_finish(&new_premaster, &new_data, &new_len)) { + OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + CBB_cleanup(&new_premaster); + goto err; + } + + OPENSSL_cleanse(premaster_secret, premaster_secret_len); + OPENSSL_free(premaster_secret); + premaster_secret = new_data; + premaster_secret_len = new_len; + } + + /* Compute the master secret */ + hs->new_session->master_key_length = tls1_generate_master_secret( + hs, hs->new_session->master_key, premaster_secret, premaster_secret_len); + if (hs->new_session->master_key_length == 0) { + goto err; + } + hs->new_session->extended_master_secret = hs->extended_master_secret; + + OPENSSL_cleanse(premaster_secret, premaster_secret_len); + OPENSSL_free(premaster_secret); + return 1; + +f_err: + ssl3_send_alert(ssl, SSL3_AL_FATAL, al); +err: + if (premaster_secret != NULL) { + OPENSSL_cleanse(premaster_secret, premaster_secret_len); + OPENSSL_free(premaster_secret); + } + OPENSSL_free(decrypt_buf); + + return -1; +} + +static int ssl3_get_cert_verify(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + int al; + CBS certificate_verify, signature; + + /* Only RSA and ECDSA client certificates are supported, so a + * CertificateVerify is required if and only if there's a client certificate. + * */ + if (hs->peer_pubkey == NULL) { + SSL_TRANSCRIPT_free_buffer(&hs->transcript); + return 1; + } + + int msg_ret = ssl->method->ssl_get_message(ssl); + if (msg_ret <= 0) { + return msg_ret; + } + + if (!ssl_check_message_type(ssl, SSL3_MT_CERTIFICATE_VERIFY)) { + return -1; + } + + CBS_init(&certificate_verify, ssl->init_msg, ssl->init_num); + + /* Determine the digest type if needbe. */ + uint16_t signature_algorithm = 0; + if (ssl3_protocol_version(ssl) >= TLS1_2_VERSION) { + if (!CBS_get_u16(&certificate_verify, &signature_algorithm)) { + al = SSL_AD_DECODE_ERROR; + OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + goto f_err; + } + if (!tls12_check_peer_sigalg(ssl, &al, signature_algorithm)) { + goto f_err; + } + hs->new_session->peer_signature_algorithm = signature_algorithm; + } else if (hs->peer_pubkey->type == EVP_PKEY_RSA) { + signature_algorithm = SSL_SIGN_RSA_PKCS1_MD5_SHA1; + } else if (hs->peer_pubkey->type == EVP_PKEY_EC) { + signature_algorithm = SSL_SIGN_ECDSA_SHA1; + } else { + al = SSL_AD_UNSUPPORTED_CERTIFICATE; + OPENSSL_PUT_ERROR(SSL, SSL_R_PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE); + goto f_err; + } + + /* Parse and verify the signature. */ + if (!CBS_get_u16_length_prefixed(&certificate_verify, &signature) || + CBS_len(&certificate_verify) != 0) { + al = SSL_AD_DECODE_ERROR; + OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + goto f_err; + } + + int sig_ok; + /* The SSL3 construction for CertificateVerify does not decompose into a + * single final digest and signature, and must be special-cased. */ + if (ssl3_protocol_version(ssl) == SSL3_VERSION) { + uint8_t digest[EVP_MAX_MD_SIZE]; + size_t digest_len; + if (!SSL_TRANSCRIPT_ssl3_cert_verify_hash(&hs->transcript, digest, + &digest_len, hs->new_session, + signature_algorithm)) { + goto err; + } + + EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new(hs->peer_pubkey, NULL); + sig_ok = pctx != NULL && + EVP_PKEY_verify_init(pctx) && + EVP_PKEY_verify(pctx, CBS_data(&signature), CBS_len(&signature), + digest, digest_len); + EVP_PKEY_CTX_free(pctx); + } else { + sig_ok = ssl_public_key_verify( + ssl, CBS_data(&signature), CBS_len(&signature), signature_algorithm, + hs->peer_pubkey, (const uint8_t *)hs->transcript.buffer->data, + hs->transcript.buffer->length); + } + +#if defined(BORINGSSL_UNSAFE_FUZZER_MODE) + sig_ok = 1; + ERR_clear_error(); +#endif + if (!sig_ok) { + al = SSL_AD_DECRYPT_ERROR; + OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SIGNATURE); + goto f_err; + } + + /* The handshake buffer is no longer necessary, and we may hash the current + * message.*/ + SSL_TRANSCRIPT_free_buffer(&hs->transcript); + if (!ssl_hash_current_message(hs)) { + goto err; + } + + return 1; + +f_err: + ssl3_send_alert(ssl, SSL3_AL_FATAL, al); +err: + return 0; +} + +/* ssl3_get_next_proto reads a Next Protocol Negotiation handshake message. It + * sets the next_proto member in s if found */ +static int ssl3_get_next_proto(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + int ret = ssl->method->ssl_get_message(ssl); + if (ret <= 0) { + return ret; + } + + if (!ssl_check_message_type(ssl, SSL3_MT_NEXT_PROTO) || + !ssl_hash_current_message(hs)) { + return -1; + } + + CBS next_protocol, selected_protocol, padding; + CBS_init(&next_protocol, ssl->init_msg, ssl->init_num); + if (!CBS_get_u8_length_prefixed(&next_protocol, &selected_protocol) || + !CBS_get_u8_length_prefixed(&next_protocol, &padding) || + CBS_len(&next_protocol) != 0) { + OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); + return 0; + } + + if (!CBS_stow(&selected_protocol, &ssl->s3->next_proto_negotiated, + &ssl->s3->next_proto_negotiated_len)) { + return 0; + } + + return 1; +} + +/* ssl3_get_channel_id reads and verifies a ClientID handshake message. */ +static int ssl3_get_channel_id(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + int msg_ret = ssl->method->ssl_get_message(ssl); + if (msg_ret <= 0) { + return msg_ret; + } + + if (!ssl_check_message_type(ssl, SSL3_MT_CHANNEL_ID) || + !tls1_verify_channel_id(hs) || + !ssl_hash_current_message(hs)) { + return -1; + } + return 1; +} + +static int ssl3_send_new_session_ticket(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + const SSL_SESSION *session; + SSL_SESSION *session_copy = NULL; + if (ssl->session == NULL) { + /* Fix the timeout to measure from the ticket issuance time. */ + ssl_session_rebase_time(ssl, hs->new_session); + session = hs->new_session; + } else { + /* We are renewing an existing session. Duplicate the session to adjust the + * timeout. */ + session_copy = SSL_SESSION_dup(ssl->session, SSL_SESSION_INCLUDE_NONAUTH); + if (session_copy == NULL) { + return -1; + } + + ssl_session_rebase_time(ssl, session_copy); + session = session_copy; + } + + CBB cbb, body, ticket; + int ok = + ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_NEW_SESSION_TICKET) && + CBB_add_u32(&body, session->timeout) && + CBB_add_u16_length_prefixed(&body, &ticket) && + ssl_encrypt_ticket(ssl, &ticket, session) && + ssl_add_message_cbb(ssl, &cbb); + + SSL_SESSION_free(session_copy); + CBB_cleanup(&cbb); + + if (!ok) { + return -1; + } + + return 1; +} diff --git a/Sources/BoringSSL/ssl/internal.h b/Sources/BoringSSL/ssl/internal.h index 032406132..a6dfad51d 100644 --- a/Sources/BoringSSL/ssl/internal.h +++ b/Sources/BoringSSL/ssl/internal.h @@ -145,19 +145,23 @@ #include #include -#include #include #include + #if defined(OPENSSL_WINDOWS) /* Windows defines struct timeval in winsock2.h. */ -#pragma warning(push, 3) +OPENSSL_MSVC_PRAGMA(warning(push, 3)) #include -#pragma warning(pop) +OPENSSL_MSVC_PRAGMA(warning(pop)) #else #include #endif +#if defined(__cplusplus) +extern "C" { +#endif + /* Cipher suites. */ @@ -167,33 +171,34 @@ #define SSL_kECDHE 0x00000004L /* SSL_kPSK is only set for plain PSK, not ECDHE_PSK. */ #define SSL_kPSK 0x00000008L +#define SSL_kGENERIC 0x00000010L /* Bits for |algorithm_auth| (server authentication). */ #define SSL_aRSA 0x00000001L #define SSL_aECDSA 0x00000002L /* SSL_aPSK is set for both PSK and ECDHE_PSK. */ #define SSL_aPSK 0x00000004L +#define SSL_aGENERIC 0x00000008L + +#define SSL_aCERT (SSL_aRSA | SSL_aECDSA) /* Bits for |algorithm_enc| (symmetric encryption). */ -#define SSL_3DES 0x00000001L -#define SSL_RC4 0x00000002L -#define SSL_AES128 0x00000004L -#define SSL_AES256 0x00000008L -#define SSL_AES128GCM 0x00000010L -#define SSL_AES256GCM 0x00000020L -#define SSL_CHACHA20POLY1305_OLD 0x00000040L -#define SSL_eNULL 0x00000080L -#define SSL_CHACHA20POLY1305 0x00000100L +#define SSL_3DES 0x00000001L +#define SSL_AES128 0x00000002L +#define SSL_AES256 0x00000004L +#define SSL_AES128GCM 0x00000008L +#define SSL_AES256GCM 0x00000010L +#define SSL_eNULL 0x00000020L +#define SSL_CHACHA20POLY1305 0x00000040L #define SSL_AES (SSL_AES128 | SSL_AES256 | SSL_AES128GCM | SSL_AES256GCM) /* Bits for |algorithm_mac| (symmetric authentication). */ -#define SSL_MD5 0x00000001L -#define SSL_SHA1 0x00000002L -#define SSL_SHA256 0x00000004L -#define SSL_SHA384 0x00000008L +#define SSL_SHA1 0x00000001L +#define SSL_SHA256 0x00000002L +#define SSL_SHA384 0x00000004L /* SSL_AEAD is set for all AEADs. */ -#define SSL_AEAD 0x00000010L +#define SSL_AEAD 0x00000008L /* Bits for |algorithm_prf| (handshake digest). */ #define SSL_HANDSHAKE_MAC_DEFAULT 0x1 @@ -215,22 +220,20 @@ int ssl_cipher_get_evp_aead(const EVP_AEAD **out_aead, const SSL_CIPHER *cipher, uint16_t version); /* ssl_get_handshake_digest returns the |EVP_MD| corresponding to - * |algorithm_prf|. It returns SHA-1 for |SSL_HANDSHAKE_DEFAULT|. The caller is - * responsible for maintaining the additional MD5 digest and switching to - * SHA-256 in TLS 1.2. */ -const EVP_MD *ssl_get_handshake_digest(uint32_t algorithm_prf); + * |algorithm_prf| and the |version|. */ +const EVP_MD *ssl_get_handshake_digest(uint32_t algorithm_prf, + uint16_t version); /* ssl_create_cipher_list evaluates |rule_str| according to the ciphers in * |ssl_method|. It sets |*out_cipher_list| to a newly-allocated - * |ssl_cipher_preference_list_st| containing the result. - * |*out_cipher_list_by_id| is set to a list of selected ciphers sorted by - * id. It returns |(*out_cipher_list)->ciphers| on success and NULL on - * failure. */ + * |ssl_cipher_preference_list_st| containing the result. It returns + * |(*out_cipher_list)->ciphers| on success and NULL on failure. If |strict| is + * true, nonsense will be rejected. If false, nonsense will be silently + * ignored. */ STACK_OF(SSL_CIPHER) * ssl_create_cipher_list(const SSL_PROTOCOL_METHOD *ssl_method, struct ssl_cipher_preference_list_st **out_cipher_list, - STACK_OF(SSL_CIPHER) **out_cipher_list_by_id, - const char *rule_str); + const char *rule_str, int strict); /* ssl_cipher_get_value returns the cipher suite id of |cipher|. */ uint16_t ssl_cipher_get_value(const SSL_CIPHER *cipher); @@ -239,17 +242,16 @@ uint16_t ssl_cipher_get_value(const SSL_CIPHER *cipher); * server key used in |cipher| or |EVP_PKEY_NONE| if there is none. */ int ssl_cipher_get_key_type(const SSL_CIPHER *cipher); -/* ssl_cipher_has_server_public_key returns 1 if |cipher| involves a server - * public key in the key exchange, sent in a server Certificate message. - * Otherwise it returns 0. */ -int ssl_cipher_has_server_public_key(const SSL_CIPHER *cipher); +/* ssl_cipher_uses_certificate_auth returns one if |cipher| authenticates the + * server and, optionally, the client with a certificate. Otherwise it returns + * zero. */ +int ssl_cipher_uses_certificate_auth(const SSL_CIPHER *cipher); /* ssl_cipher_requires_server_key_exchange returns 1 if |cipher| requires a * ServerKeyExchange message. Otherwise it returns 0. * - * Unlike |ssl_cipher_has_server_public_key|, this function may return zero - * while still allowing |cipher| an optional ServerKeyExchange. This is the - * case for plain PSK ciphers. */ + * This function may return zero while still allowing |cipher| an optional + * ServerKeyExchange. This is the case for plain PSK ciphers. */ int ssl_cipher_requires_server_key_exchange(const SSL_CIPHER *cipher); /* ssl_cipher_get_record_split_len, for TLS 1.0 CBC mode ciphers, returns the @@ -258,11 +260,92 @@ int ssl_cipher_requires_server_key_exchange(const SSL_CIPHER *cipher); size_t ssl_cipher_get_record_split_len(const SSL_CIPHER *cipher); +/* Transcript layer. */ + +/* SSL_TRANSCRIPT maintains the handshake transcript as a combination of a + * buffer and running hash. */ +typedef struct ssl_transcript_st { + /* buffer, if non-NULL, contains the handshake transcript. */ + BUF_MEM *buffer; + /* hash, if initialized with an |EVP_MD|, maintains the handshake hash. For + * TLS 1.1 and below, it is the SHA-1 half. */ + EVP_MD_CTX hash; + /* md5, if initialized with an |EVP_MD|, maintains the MD5 half of the + * handshake hash for TLS 1.1 and below. */ + EVP_MD_CTX md5; +} SSL_TRANSCRIPT; + +/* SSL_TRANSCRIPT_init initializes the handshake transcript. If called on an + * existing transcript, it resets the transcript and hash. It returns one on + * success and zero on failure. */ +int SSL_TRANSCRIPT_init(SSL_TRANSCRIPT *transcript); + +/* SSL_TRANSCRIPT_init_hash initializes the handshake hash based on the PRF and + * contents of the handshake transcript. Subsequent calls to + * |SSL_TRANSCRIPT_update| will update the rolling hash. It returns one on + * success and zero on failure. It is an error to call this function after the + * handshake buffer is released. */ +int SSL_TRANSCRIPT_init_hash(SSL_TRANSCRIPT *transcript, uint16_t version, + int algorithm_prf); + +/* SSL_TRANSCRIPT_cleanup cleans up the hash and transcript. */ +void SSL_TRANSCRIPT_cleanup(SSL_TRANSCRIPT *transcript); + +/* SSL_TRANSCRIPT_free_buffer releases the handshake buffer. Subsequent calls to + * |SSL_TRANSCRIPT_update| will not update the handshake buffer. */ +void SSL_TRANSCRIPT_free_buffer(SSL_TRANSCRIPT *transcript); + +/* SSL_TRANSCRIPT_digest_len returns the length of the PRF hash. */ +size_t SSL_TRANSCRIPT_digest_len(const SSL_TRANSCRIPT *transcript); + +/* SSL_TRANSCRIPT_md returns the PRF hash. For TLS 1.1 and below, this is + * |EVP_md5_sha1|. */ +const EVP_MD *SSL_TRANSCRIPT_md(const SSL_TRANSCRIPT *transcript); + +/* SSL_TRANSCRIPT_update adds |in| to the handshake buffer and handshake hash, + * whichever is enabled. It returns one on success and zero on failure. */ +int SSL_TRANSCRIPT_update(SSL_TRANSCRIPT *transcript, const uint8_t *in, + size_t in_len); + +/* SSL_TRANSCRIPT_get_hash writes the handshake hash to |out| which must have + * room for at least |SSL_TRANSCRIPT_digest_len| bytes. On success, it returns + * one and sets |*out_len| to the number of bytes written. Otherwise, it returns + * zero. */ +int SSL_TRANSCRIPT_get_hash(const SSL_TRANSCRIPT *transcript, uint8_t *out, + size_t *out_len); + +/* SSL_TRANSCRIPT_ssl3_cert_verify_hash writes the SSL 3.0 CertificateVerify + * hash into the bytes pointed to by |out| and writes the number of bytes to + * |*out_len|. |out| must have room for |EVP_MAX_MD_SIZE| bytes. It returns one + * on success and zero on failure. */ +int SSL_TRANSCRIPT_ssl3_cert_verify_hash(SSL_TRANSCRIPT *transcript, + uint8_t *out, size_t *out_len, + const SSL_SESSION *session, + int signature_algorithm); + +/* SSL_TRANSCRIPT_finish_mac computes the MAC for the Finished message into the + * bytes pointed by |out| and writes the number of bytes to |*out_len|. |out| + * must have room for |EVP_MAX_MD_SIZE| bytes. It returns one on success and + * zero on failure. */ +int SSL_TRANSCRIPT_finish_mac(SSL_TRANSCRIPT *transcript, uint8_t *out, + size_t *out_len, const SSL_SESSION *session, + int from_server, uint16_t version); + +/* tls1_prf computes the PRF function for |ssl|. It writes |out_len| bytes to + * |out|, using |secret| as the secret and |label| as the label. |seed1| and + * |seed2| are concatenated to form the seed parameter. It returns one on + * success and zero on failure. */ +int tls1_prf(const EVP_MD *digest, uint8_t *out, size_t out_len, + const uint8_t *secret, size_t secret_len, const char *label, + size_t label_len, const uint8_t *seed1, size_t seed1_len, + const uint8_t *seed2, size_t seed2_len); + + /* Encryption layer. */ /* SSL_AEAD_CTX contains information about an AEAD that is being used to encrypt * an SSL connection. */ -struct ssl_aead_ctx_st { +typedef struct ssl_aead_ctx_st { const SSL_CIPHER *cipher; EVP_AEAD_CTX ctx; /* fixed_nonce contains any bytes of the nonce that are fixed for all @@ -271,21 +354,23 @@ struct ssl_aead_ctx_st { uint8_t fixed_nonce_len, variable_nonce_len; /* variable_nonce_included_in_record is non-zero if the variable nonce * for a record is included as a prefix before the ciphertext. */ - char variable_nonce_included_in_record; + unsigned variable_nonce_included_in_record : 1; /* random_variable_nonce is non-zero if the variable nonce is * randomly generated, rather than derived from the sequence * number. */ - char random_variable_nonce; + unsigned random_variable_nonce : 1; /* omit_length_in_ad is non-zero if the length should be omitted in the * AEAD's ad parameter. */ - char omit_length_in_ad; + unsigned omit_length_in_ad : 1; /* omit_version_in_ad is non-zero if the version should be omitted * in the AEAD's ad parameter. */ - char omit_version_in_ad; + unsigned omit_version_in_ad : 1; + /* omit_ad is non-zero if the AEAD's ad parameter should be omitted. */ + unsigned omit_ad : 1; /* xor_fixed_nonce is non-zero if the fixed nonce should be XOR'd into the * variable nonce rather than prepended. */ - char xor_fixed_nonce; -} /* SSL_AEAD_CTX */; + unsigned xor_fixed_nonce : 1; +} SSL_AEAD_CTX; /* SSL_AEAD_CTX_new creates a newly-allocated |SSL_AEAD_CTX| using the supplied * key material. It returns NULL on error. Only one of |SSL_AEAD_CTX_open| or @@ -303,27 +388,25 @@ void SSL_AEAD_CTX_free(SSL_AEAD_CTX *ctx); /* SSL_AEAD_CTX_explicit_nonce_len returns the length of the explicit nonce for * |ctx|, if any. |ctx| may be NULL to denote the null cipher. */ -size_t SSL_AEAD_CTX_explicit_nonce_len(SSL_AEAD_CTX *ctx); +size_t SSL_AEAD_CTX_explicit_nonce_len(const SSL_AEAD_CTX *ctx); /* SSL_AEAD_CTX_max_overhead returns the maximum overhead of calling * |SSL_AEAD_CTX_seal|. |ctx| may be NULL to denote the null cipher. */ -size_t SSL_AEAD_CTX_max_overhead(SSL_AEAD_CTX *ctx); +size_t SSL_AEAD_CTX_max_overhead(const SSL_AEAD_CTX *ctx); -/* SSL_AEAD_CTX_open authenticates and decrypts |in_len| bytes from |in| and - * writes the result to |out|. It returns one on success and zero on - * error. |ctx| may be NULL to denote the null cipher. - * - * If |in| and |out| alias then |out| must be <= |in| + |explicit_nonce_len|. */ -int SSL_AEAD_CTX_open(SSL_AEAD_CTX *ctx, uint8_t *out, size_t *out_len, - size_t max_out, uint8_t type, uint16_t wire_version, - const uint8_t seqnum[8], const uint8_t *in, - size_t in_len); +/* SSL_AEAD_CTX_open authenticates and decrypts |in_len| bytes from |in| + * in-place. On success, it sets |*out| to the plaintext in |in| and returns + * one. Otherwise, it returns zero. |ctx| may be NULL to denote the null cipher. + * The output will always be |explicit_nonce_len| bytes ahead of |in|. */ +int SSL_AEAD_CTX_open(SSL_AEAD_CTX *ctx, CBS *out, uint8_t type, + uint16_t wire_version, const uint8_t seqnum[8], + uint8_t *in, size_t in_len); /* SSL_AEAD_CTX_seal encrypts and authenticates |in_len| bytes from |in| and * writes the result to |out|. It returns one on success and zero on * error. |ctx| may be NULL to denote the null cipher. * - * If |in| and |out| alias then |out| + |explicit_nonce_len| must be <= |in| */ + * If |in| and |out| alias then |out| + |explicit_nonce_len| must be == |in|. */ int SSL_AEAD_CTX_seal(SSL_AEAD_CTX *ctx, uint8_t *out, size_t *out_len, size_t max_out, uint8_t type, uint16_t wire_version, const uint8_t seqnum[8], const uint8_t *in, @@ -361,67 +444,68 @@ enum ssl_open_record_t { ssl_open_record_success, ssl_open_record_discard, ssl_open_record_partial, + ssl_open_record_close_notify, + ssl_open_record_fatal_alert, ssl_open_record_error, }; -/* tls_open_record decrypts a record from |in|. - * - * On success, it returns |ssl_open_record_success|. It sets |*out_type| to the - * record type, |*out_len| to the plaintext length, and writes the record body - * to |out|. It sets |*out_consumed| to the number of bytes of |in| consumed. - * Note that |*out_len| may be zero. - * - * If a record was successfully processed but should be discarded, it returns - * |ssl_open_record_discard| and sets |*out_consumed| to the number of bytes - * consumed. +/* tls_open_record decrypts a record from |in| in-place. * * If the input did not contain a complete record, it returns * |ssl_open_record_partial|. It sets |*out_consumed| to the total number of * bytes necessary. It is guaranteed that a successful call to |tls_open_record| * will consume at least that many bytes. * - * On failure, it returns |ssl_open_record_error| and sets |*out_alert| to an - * alert to emit. + * Otherwise, it sets |*out_consumed| to the number of bytes of input + * consumed. Note that input may be consumed on all return codes if a record was + * decrypted. + * + * On success, it returns |ssl_open_record_success|. It sets |*out_type| to the + * record type and |*out| to the record body in |in|. Note that |*out| may be + * empty. + * + * If a record was successfully processed but should be discarded, it returns + * |ssl_open_record_discard|. + * + * If a record was successfully processed but is a close_notify or fatal alert, + * it returns |ssl_open_record_close_notify| or |ssl_open_record_fatal_alert|. * - * If |in| and |out| alias, |out| must be <= |in| + |ssl_record_prefix_len|. */ -enum ssl_open_record_t tls_open_record( - SSL *ssl, uint8_t *out_type, uint8_t *out, size_t *out_len, - size_t *out_consumed, uint8_t *out_alert, size_t max_out, const uint8_t *in, - size_t in_len); + * On failure, it returns |ssl_open_record_error| and sets |*out_alert| to an + * alert to emit. */ +enum ssl_open_record_t tls_open_record(SSL *ssl, uint8_t *out_type, CBS *out, + size_t *out_consumed, uint8_t *out_alert, + uint8_t *in, size_t in_len); /* dtls_open_record implements |tls_open_record| for DTLS. It never returns * |ssl_open_record_partial| but otherwise behaves analogously. */ -enum ssl_open_record_t dtls_open_record( - SSL *ssl, uint8_t *out_type, uint8_t *out, size_t *out_len, - size_t *out_consumed, uint8_t *out_alert, size_t max_out, const uint8_t *in, - size_t in_len); - -/* ssl_seal_prefix_len returns the length of the prefix before the ciphertext - * when sealing a record with |ssl|. Note that this value may differ from - * |ssl_record_prefix_len| when TLS 1.0 CBC record-splitting is enabled. Sealing - * a small record may also result in a smaller output than this value. +enum ssl_open_record_t dtls_open_record(SSL *ssl, uint8_t *out_type, CBS *out, + size_t *out_consumed, + uint8_t *out_alert, uint8_t *in, + size_t in_len); + +/* ssl_seal_align_prefix_len returns the length of the prefix before the start + * of the bulk of the ciphertext when sealing a record with |ssl|. Callers may + * use this to align buffers. * - * TODO(davidben): Expose this as part of public API once the high-level - * buffer-free APIs are available. */ -size_t ssl_seal_prefix_len(const SSL *ssl); - -/* ssl_max_seal_overhead returns the maximum overhead of sealing a record with - * |ssl|. This includes |ssl_seal_prefix_len|. + * Note when TLS 1.0 CBC record-splitting is enabled, this includes the one byte + * record and is the offset into second record's ciphertext. Thus sealing a + * small record may result in a smaller output than this value. * - * TODO(davidben): Expose this as part of public API once the high-level - * buffer-free APIs are available. */ -size_t ssl_max_seal_overhead(const SSL *ssl); + * TODO(davidben): Is this alignment valuable? Record-splitting makes this a + * mess. */ +size_t ssl_seal_align_prefix_len(const SSL *ssl); /* tls_seal_record seals a new record of type |type| and body |in| and writes it * to |out|. At most |max_out| bytes will be written. It returns one on success * and zero on error. If enabled, |tls_seal_record| implements TLS 1.0 CBC 1/n-1 * record splitting and may write two records concatenated. * - * For a large record, the ciphertext will begin |ssl_seal_prefix_len| bytes - * into out. Aligning |out| appropriately may improve performance. It writes at - * most |in_len| + |ssl_max_seal_overhead| bytes to |out|. + * For a large record, the bulk of the ciphertext will begin + * |ssl_seal_align_prefix_len| bytes into out. Aligning |out| appropriately may + * improve performance. It writes at most |in_len| + |SSL_max_seal_overhead| + * bytes to |out|. * - * If |in| and |out| alias, |out| + |ssl_seal_prefix_len| must be <= |in|. */ + * |in| and |out| may not alias. */ int tls_seal_record(SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out, uint8_t type, const uint8_t *in, size_t in_len); @@ -430,26 +514,39 @@ enum dtls1_use_epoch_t { dtls1_use_current_epoch, }; +/* dtls_max_seal_overhead returns the maximum overhead, in bytes, of sealing a + * record. */ +size_t dtls_max_seal_overhead(const SSL *ssl, enum dtls1_use_epoch_t use_epoch); + +/* dtls_seal_prefix_len returns the number of bytes of prefix to reserve in + * front of the plaintext when sealing a record in-place. */ +size_t dtls_seal_prefix_len(const SSL *ssl, enum dtls1_use_epoch_t use_epoch); + /* dtls_seal_record implements |tls_seal_record| for DTLS. |use_epoch| selects - * which epoch's cipher state to use. */ + * which epoch's cipher state to use. Unlike |tls_seal_record|, |in| and |out| + * may alias but, if they do, |in| must be exactly |dtls_seal_prefix_len| bytes + * ahead of |out|. */ int dtls_seal_record(SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out, uint8_t type, const uint8_t *in, size_t in_len, enum dtls1_use_epoch_t use_epoch); -/* ssl_set_read_state sets |ssl|'s read cipher state to |aead_ctx|. It takes - * ownership of |aead_ctx|. */ -void ssl_set_read_state(SSL *ssl, SSL_AEAD_CTX *aead_ctx); - -/* ssl_set_write_state sets |ssl|'s write cipher state to |aead_ctx|. It takes - * ownership of |aead_ctx|. */ -void ssl_set_write_state(SSL *ssl, SSL_AEAD_CTX *aead_ctx); +/* ssl_process_alert processes |in| as an alert and updates |ssl|'s shutdown + * state. It returns one of |ssl_open_record_discard|, |ssl_open_record_error|, + * |ssl_open_record_close_notify|, or |ssl_open_record_fatal_alert| as + * appropriate. */ +enum ssl_open_record_t ssl_process_alert(SSL *ssl, uint8_t *out_alert, + const uint8_t *in, size_t in_len); /* Private key operations. */ /* ssl_has_private_key returns one if |ssl| has a private key * configured and zero otherwise. */ -int ssl_has_private_key(SSL *ssl); +int ssl_has_private_key(const SSL *ssl); + +/* ssl_is_ecdsa_key_type returns one if |type| is an ECDSA key type and zero + * otherwise. */ +int ssl_is_ecdsa_key_type(int type); /* ssl_private_key_* call the corresponding function on the * |SSL_PRIVATE_KEY_METHOD| for |ssl|, if configured. Otherwise, they implement @@ -460,22 +557,34 @@ int ssl_private_key_type(SSL *ssl); size_t ssl_private_key_max_signature_len(SSL *ssl); enum ssl_private_key_result_t ssl_private_key_sign( - SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out, const EVP_MD *md, - const uint8_t *in, size_t in_len); - -enum ssl_private_key_result_t ssl_private_key_sign_complete( - SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out); + SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out, + uint16_t signature_algorithm, const uint8_t *in, size_t in_len); enum ssl_private_key_result_t ssl_private_key_decrypt( SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out, const uint8_t *in, size_t in_len); -enum ssl_private_key_result_t ssl_private_key_decrypt_complete( - SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out); +enum ssl_private_key_result_t ssl_private_key_complete(SSL *ssl, uint8_t *out, + size_t *out_len, + size_t max_out); + +/* ssl_private_key_supports_signature_algorithm returns one if |ssl|'s private + * key supports |signature_algorithm| and zero otherwise. */ +int ssl_private_key_supports_signature_algorithm(SSL *ssl, + uint16_t signature_algorithm); + +/* ssl_public_key_verify verifies that the |signature| is valid for the public + * key |pkey| and input |in|, using the |signature_algorithm| specified. */ +int ssl_public_key_verify( + SSL *ssl, const uint8_t *signature, size_t signature_len, + uint16_t signature_algorithm, EVP_PKEY *pkey, + const uint8_t *in, size_t in_len); /* Custom extensions */ +typedef struct ssl_handshake_st SSL_HANDSHAKE; + /* ssl_custom_extension (a.k.a. SSL_CUSTOM_EXTENSION) is a structure that * contains information about custom-extension callbacks. */ struct ssl_custom_extension { @@ -489,82 +598,80 @@ struct ssl_custom_extension { void SSL_CUSTOM_EXTENSION_free(SSL_CUSTOM_EXTENSION *custom_extension); -int custom_ext_add_clienthello(SSL *ssl, CBB *extensions); -int custom_ext_parse_serverhello(SSL *ssl, int *out_alert, uint16_t value, - const CBS *extension); -int custom_ext_parse_clienthello(SSL *ssl, int *out_alert, uint16_t value, - const CBS *extension); -int custom_ext_add_serverhello(SSL *ssl, CBB *extensions); +int custom_ext_add_clienthello(SSL_HANDSHAKE *hs, CBB *extensions); +int custom_ext_parse_serverhello(SSL_HANDSHAKE *hs, int *out_alert, + uint16_t value, const CBS *extension); +int custom_ext_parse_clienthello(SSL_HANDSHAKE *hs, int *out_alert, + uint16_t value, const CBS *extension); +int custom_ext_add_serverhello(SSL_HANDSHAKE *hs, CBB *extensions); -/* Handshake hash. - * - * The TLS handshake maintains a transcript of all handshake messages. At - * various points in the protocol, this is either a handshake buffer, a rolling - * hash (selected by cipher suite) or both. */ - -/* ssl3_init_handshake_buffer initializes the handshake buffer and resets the - * handshake hash. It returns one success and zero on failure. */ -int ssl3_init_handshake_buffer(SSL *ssl); - -/* ssl3_init_handshake_hash initializes the handshake hash based on the pending - * cipher and the contents of the handshake buffer. Subsequent calls to - * |ssl3_update_handshake_hash| will update the rolling hash. It returns one on - * success and zero on failure. It is an error to call this function after the - * handshake buffer is released. */ -int ssl3_init_handshake_hash(SSL *ssl); - -/* ssl3_free_handshake_buffer releases the handshake buffer. Subsequent calls - * to |ssl3_update_handshake_hash| will not update the handshake buffer. */ -void ssl3_free_handshake_buffer(SSL *ssl); - -/* ssl3_free_handshake_hash releases the handshake hash. */ -void ssl3_free_handshake_hash(SSL *ssl); - -/* ssl3_update_handshake_hash adds |in| to the handshake buffer and handshake - * hash, whichever is enabled. It returns one on success and zero on failure. */ -int ssl3_update_handshake_hash(SSL *ssl, const uint8_t *in, size_t in_len); - +/* ECDH groups. */ -/* ECDH curves. */ - -#define SSL_CURVE_SECP256R1 23 -#define SSL_CURVE_SECP384R1 24 -#define SSL_CURVE_SECP521R1 25 -#define SSL_CURVE_X25519 29 +typedef struct ssl_ecdh_ctx_st SSL_ECDH_CTX; /* An SSL_ECDH_METHOD is an implementation of ECDH-like key exchanges for * TLS. */ -struct ssl_ecdh_method_st { +typedef struct ssl_ecdh_method_st { int nid; - uint16_t curve_id; + uint16_t group_id; const char name[8]; /* cleanup releases state in |ctx|. */ void (*cleanup)(SSL_ECDH_CTX *ctx); - /* generate_keypair generates a keypair and writes the public value to + /* offer generates a keypair and writes the public value to * |out_public_key|. It returns one on success and zero on error. */ - int (*generate_keypair)(SSL_ECDH_CTX *ctx, CBB *out_public_key); - - /* compute_secret performs a key exchange against |peer_key| and, on - * success, returns one and sets |*out_secret| and |*out_secret_len| to - * a newly-allocated buffer containing the shared secret. The caller must - * release this buffer with |OPENSSL_free|. Otherwise, it returns zero and - * sets |*out_alert| to an alert to send to the peer. */ - int (*compute_secret)(SSL_ECDH_CTX *ctx, uint8_t **out_secret, - size_t *out_secret_len, uint8_t *out_alert, - const uint8_t *peer_key, size_t peer_key_len); -} /* SSL_ECDH_METHOD */; + int (*offer)(SSL_ECDH_CTX *ctx, CBB *out_public_key); + + /* accept performs a key exchange against the |peer_key| generated by |offer|. + * On success, it returns one, writes the public value to |out_public_key|, + * and sets |*out_secret| and |*out_secret_len| to a newly-allocated buffer + * containing the shared secret. The caller must release this buffer with + * |OPENSSL_free|. On failure, it returns zero and sets |*out_alert| to an + * alert to send to the peer. */ + int (*accept)(SSL_ECDH_CTX *ctx, CBB *out_public_key, uint8_t **out_secret, + size_t *out_secret_len, uint8_t *out_alert, + const uint8_t *peer_key, size_t peer_key_len); + + /* finish performs a key exchange against the |peer_key| generated by + * |accept|. On success, it returns one and sets |*out_secret| and + * |*out_secret_len| to a newly-allocated buffer containing the shared + * secret. The caller must release this buffer with |OPENSSL_free|. On + * failure, it returns zero and sets |*out_alert| to an alert to send to the + * peer. */ + int (*finish)(SSL_ECDH_CTX *ctx, uint8_t **out_secret, size_t *out_secret_len, + uint8_t *out_alert, const uint8_t *peer_key, + size_t peer_key_len); + + /* get_key initializes |out| with a length-prefixed key from |cbs|. It returns + * one on success and zero on error. */ + int (*get_key)(CBS *cbs, CBS *out); + + /* add_key initializes |out_contents| to receive a key. Typically it will then + * be passed to |offer| or |accept|. It returns one on success and zero on + * error. */ + int (*add_key)(CBB *cbb, CBB *out_contents); +} SSL_ECDH_METHOD; + +struct ssl_ecdh_ctx_st { + const SSL_ECDH_METHOD *method; + void *data; +}; -/* ssl_nid_to_curve_id looks up the curve corresponding to |nid|. On success, it - * sets |*out_curve_id| to the curve ID and returns one. Otherwise, it returns +/* ssl_nid_to_group_id looks up the group corresponding to |nid|. On success, it + * sets |*out_group_id| to the group ID and returns one. Otherwise, it returns * zero. */ -int ssl_nid_to_curve_id(uint16_t *out_curve_id, int nid); +int ssl_nid_to_group_id(uint16_t *out_group_id, int nid); + +/* ssl_name_to_group_id looks up the group corresponding to the |name| string + * of length |len|. On success, it sets |*out_group_id| to the group ID and + * returns one. Otherwise, it returns zero. */ +int ssl_name_to_group_id(uint16_t *out_group_id, const char *name, size_t len); -/* SSL_ECDH_CTX_init sets up |ctx| for use with curve |curve_id|. It returns one +/* SSL_ECDH_CTX_init sets up |ctx| for use with curve |group_id|. It returns one * on success and zero on error. */ -int SSL_ECDH_CTX_init(SSL_ECDH_CTX *ctx, uint16_t curve_id); +int SSL_ECDH_CTX_init(SSL_ECDH_CTX *ctx, uint16_t group_id); /* SSL_ECDH_CTX_init_for_dhe sets up |ctx| for use with legacy DHE-based ciphers * where the server specifies a group. It takes ownership of |params|. */ @@ -574,12 +681,67 @@ void SSL_ECDH_CTX_init_for_dhe(SSL_ECDH_CTX *ctx, DH *params); * call it in the zero state. */ void SSL_ECDH_CTX_cleanup(SSL_ECDH_CTX *ctx); -/* The following functions call the corresponding method of - * |SSL_ECDH_METHOD|. */ -int SSL_ECDH_CTX_generate_keypair(SSL_ECDH_CTX *ctx, CBB *out_public_key); -int SSL_ECDH_CTX_compute_secret(SSL_ECDH_CTX *ctx, uint8_t **out_secret, - size_t *out_secret_len, uint8_t *out_alert, - const uint8_t *peer_key, size_t peer_key_len); +/* SSL_ECDH_CTX_get_id returns the group ID for |ctx|. */ +uint16_t SSL_ECDH_CTX_get_id(const SSL_ECDH_CTX *ctx); + +/* SSL_ECDH_CTX_get_key calls the |get_key| method of |SSL_ECDH_METHOD|. */ +int SSL_ECDH_CTX_get_key(SSL_ECDH_CTX *ctx, CBS *cbs, CBS *out); + +/* SSL_ECDH_CTX_add_key calls the |add_key| method of |SSL_ECDH_METHOD|. */ +int SSL_ECDH_CTX_add_key(SSL_ECDH_CTX *ctx, CBB *cbb, CBB *out_contents); + +/* SSL_ECDH_CTX_offer calls the |offer| method of |SSL_ECDH_METHOD|. */ +int SSL_ECDH_CTX_offer(SSL_ECDH_CTX *ctx, CBB *out_public_key); + +/* SSL_ECDH_CTX_accept calls the |accept| method of |SSL_ECDH_METHOD|. */ +int SSL_ECDH_CTX_accept(SSL_ECDH_CTX *ctx, CBB *out_public_key, + uint8_t **out_secret, size_t *out_secret_len, + uint8_t *out_alert, const uint8_t *peer_key, + size_t peer_key_len); + +/* SSL_ECDH_CTX_finish the |finish| method of |SSL_ECDH_METHOD|. */ +int SSL_ECDH_CTX_finish(SSL_ECDH_CTX *ctx, uint8_t **out_secret, + size_t *out_secret_len, uint8_t *out_alert, + const uint8_t *peer_key, size_t peer_key_len); + +/* Handshake messages. */ + +/* SSL_MAX_HANDSHAKE_FLIGHT is the number of messages, including + * ChangeCipherSpec, in the longest handshake flight. Currently this is the + * client's second leg in a full handshake when client certificates, NPN, and + * Channel ID, are all enabled. */ +#define SSL_MAX_HANDSHAKE_FLIGHT 7 + +/* ssl_max_handshake_message_len returns the maximum number of bytes permitted + * in a handshake message for |ssl|. */ +size_t ssl_max_handshake_message_len(const SSL *ssl); + +/* dtls_clear_incoming_messages releases all buffered incoming messages. */ +void dtls_clear_incoming_messages(SSL *ssl); + +/* dtls_has_incoming_messages returns one if there are buffered incoming + * messages ahead of the current message and zero otherwise. */ +int dtls_has_incoming_messages(const SSL *ssl); + +typedef struct dtls_outgoing_message_st { + uint8_t *data; + uint32_t len; + uint16_t epoch; + char is_ccs; +} DTLS_OUTGOING_MESSAGE; + +/* dtls_clear_outgoing_messages releases all buffered outgoing messages. */ +void dtls_clear_outgoing_messages(SSL *ssl); + + +/* Callbacks. */ + +/* ssl_do_info_callback calls |ssl|'s info callback, if set. */ +void ssl_do_info_callback(const SSL *ssl, int type, int value); + +/* ssl_do_msg_callback calls |ssl|'s message callback, if set. */ +void ssl_do_msg_callback(SSL *ssl, int is_write, int content_type, + const void *buf, size_t len); /* Transport buffers. */ @@ -637,163 +799,529 @@ int ssl_write_buffer_flush(SSL *ssl); void ssl_write_buffer_clear(SSL *ssl); -/* Underdocumented functions. +/* Certificate functions. */ + +/* ssl_has_certificate returns one if a certificate and private key are + * configured and zero otherwise. */ +int ssl_has_certificate(const SSL *ssl); + +/* ssl_parse_cert_chain parses a certificate list from |cbs| in the format used + * by a TLS Certificate message. On success, it returns a newly-allocated + * |CRYPTO_BUFFER| list and advances |cbs|. Otherwise, it returns NULL and sets + * |*out_alert| to an alert to send to the peer. * - * Functions below here haven't been touched up and may be underdocumented. */ + * If the list is non-empty then |*out_pubkey| will be set to a freshly + * allocated public-key from the leaf certificate. + * + * If the list is non-empty and |out_leaf_sha256| is non-NULL, it writes the + * SHA-256 hash of the leaf to |out_leaf_sha256|. */ +STACK_OF(CRYPTO_BUFFER) *ssl_parse_cert_chain(uint8_t *out_alert, + EVP_PKEY **out_pubkey, + uint8_t *out_leaf_sha256, + CBS *cbs, + CRYPTO_BUFFER_POOL *pool); + +/* ssl_add_cert_chain adds |ssl|'s certificate chain to |cbb| in the format used + * by a TLS Certificate message. If there is no certificate chain, it emits an + * empty certificate list. It returns one on success and zero on error. */ +int ssl_add_cert_chain(SSL *ssl, CBB *cbb); + +/* ssl_auto_chain_if_needed runs the deprecated auto-chaining logic if + * necessary. On success, it updates |ssl|'s certificate configuration as needed + * and returns one. Otherwise, it returns zero. */ +int ssl_auto_chain_if_needed(SSL *ssl); + +/* ssl_cert_check_digital_signature_key_usage parses the DER-encoded, X.509 + * certificate in |in| and returns one if doesn't specify a key usage or, if it + * does, if it includes digitalSignature. Otherwise it pushes to the error + * queue and returns zero. */ +int ssl_cert_check_digital_signature_key_usage(const CBS *in); + +/* ssl_cert_parse_pubkey extracts the public key from the DER-encoded, X.509 + * certificate in |in|. It returns an allocated |EVP_PKEY| or else returns NULL + * and pushes to the error queue. */ +EVP_PKEY *ssl_cert_parse_pubkey(const CBS *in); + +/* ssl_parse_client_CA_list parses a CA list from |cbs| in the format used by a + * TLS CertificateRequest message. On success, it returns a newly-allocated + * |X509_NAME| list and advances |cbs|. Otherwise, it returns NULL and sets + * |*out_alert| to an alert to send to the peer. */ +STACK_OF(X509_NAME) * + ssl_parse_client_CA_list(SSL *ssl, uint8_t *out_alert, CBS *cbs); + +/* ssl_add_client_CA_list adds the configured CA list to |cbb| in the format + * used by a TLS CertificateRequest message. It returns one on success and zero + * on error. */ +int ssl_add_client_CA_list(SSL *ssl, CBB *cbb); + +/* ssl_check_leaf_certificate returns one if |pkey| and |leaf| are suitable as + * a server's leaf certificate for |hs|. Otherwise, it returns zero and pushes + * an error on the error queue. */ +int ssl_check_leaf_certificate(SSL_HANDSHAKE *hs, EVP_PKEY *pkey, + const CRYPTO_BUFFER *leaf); + + +/* TLS 1.3 key derivation. */ + +/* tls13_init_key_schedule initializes the handshake hash and key derivation + * state. The cipher suite and PRF hash must have been selected at this point. + * It returns one on success and zero on error. */ +int tls13_init_key_schedule(SSL_HANDSHAKE *hs); + +/* tls13_advance_key_schedule incorporates |in| into the key schedule with + * HKDF-Extract. It returns one on success and zero on error. */ +int tls13_advance_key_schedule(SSL_HANDSHAKE *hs, const uint8_t *in, + size_t len); + +/* tls13_set_traffic_key sets the read or write traffic keys to + * |traffic_secret|. It returns one on success and zero on error. */ +int tls13_set_traffic_key(SSL *ssl, enum evp_aead_direction_t direction, + const uint8_t *traffic_secret, + size_t traffic_secret_len); + +/* tls13_derive_handshake_secrets derives the handshake traffic secret. It + * returns one on success and zero on error. */ +int tls13_derive_handshake_secrets(SSL_HANDSHAKE *hs); + +/* tls13_rotate_traffic_key derives the next read or write traffic secret. It + * returns one on success and zero on error. */ +int tls13_rotate_traffic_key(SSL *ssl, enum evp_aead_direction_t direction); + +/* tls13_derive_application_secrets derives the initial application data traffic + * and exporter secrets based on the handshake transcripts and |master_secret|. + * It returns one on success and zero on error. */ +int tls13_derive_application_secrets(SSL_HANDSHAKE *hs); + +/* tls13_derive_resumption_secret derives the |resumption_secret|. */ +int tls13_derive_resumption_secret(SSL_HANDSHAKE *hs); + +/* tls13_export_keying_material provides an exporter interface to use the + * |exporter_secret|. */ +int tls13_export_keying_material(SSL *ssl, uint8_t *out, size_t out_len, + const char *label, size_t label_len, + const uint8_t *context, size_t context_len, + int use_context); + +/* tls13_finished_mac calculates the MAC of the handshake transcript to verify + * the integrity of the Finished message, and stores the result in |out| and + * length in |out_len|. |is_server| is 1 if this is for the Server Finished and + * 0 for the Client Finished. */ +int tls13_finished_mac(SSL_HANDSHAKE *hs, uint8_t *out, + size_t *out_len, int is_server); + +/* tls13_write_psk_binder calculates the PSK binder value and replaces the last + * bytes of |msg| with the resulting value. It returns 1 on success, and 0 on + * failure. */ +int tls13_write_psk_binder(SSL_HANDSHAKE *hs, uint8_t *msg, size_t len); + +/* tls13_verify_psk_binder verifies that the handshake transcript, truncated + * up to the binders has a valid signature using the value of |session|'s + * resumption secret. It returns 1 on success, and 0 on failure. */ +int tls13_verify_psk_binder(SSL_HANDSHAKE *hs, SSL_SESSION *session, + CBS *binders); + + +/* Handshake functions. */ + +enum ssl_hs_wait_t { + ssl_hs_error, + ssl_hs_ok, + ssl_hs_read_message, + ssl_hs_flush, + ssl_hs_flush_and_read_message, + ssl_hs_x509_lookup, + ssl_hs_channel_id_lookup, + ssl_hs_private_key_operation, +}; -#define c2l(c, l) \ - (l = ((unsigned long)(*((c)++))), l |= (((unsigned long)(*((c)++))) << 8), \ - l |= (((unsigned long)(*((c)++))) << 16), \ - l |= (((unsigned long)(*((c)++))) << 24)) - -/* NOTE - c is not incremented as per c2l */ -#define c2ln(c, l1, l2, n) \ - { \ - c += n; \ - l1 = l2 = 0; \ - switch (n) { \ - case 8: \ - l2 = ((unsigned long)(*(--(c)))) << 24; \ - case 7: \ - l2 |= ((unsigned long)(*(--(c)))) << 16; \ - case 6: \ - l2 |= ((unsigned long)(*(--(c)))) << 8; \ - case 5: \ - l2 |= ((unsigned long)(*(--(c)))); \ - case 4: \ - l1 = ((unsigned long)(*(--(c)))) << 24; \ - case 3: \ - l1 |= ((unsigned long)(*(--(c)))) << 16; \ - case 2: \ - l1 |= ((unsigned long)(*(--(c)))) << 8; \ - case 1: \ - l1 |= ((unsigned long)(*(--(c)))); \ - } \ - } - -#define l2c(l, c) \ - (*((c)++) = (uint8_t)(((l)) & 0xff), \ - *((c)++) = (uint8_t)(((l) >> 8) & 0xff), \ - *((c)++) = (uint8_t)(((l) >> 16) & 0xff), \ - *((c)++) = (uint8_t)(((l) >> 24) & 0xff)) - -#define n2l(c, l) \ - (l = ((unsigned long)(*((c)++))) << 24, \ - l |= ((unsigned long)(*((c)++))) << 16, \ - l |= ((unsigned long)(*((c)++))) << 8, l |= ((unsigned long)(*((c)++)))) - -#define l2n(l, c) \ - (*((c)++) = (uint8_t)(((l) >> 24) & 0xff), \ - *((c)++) = (uint8_t)(((l) >> 16) & 0xff), \ - *((c)++) = (uint8_t)(((l) >> 8) & 0xff), \ - *((c)++) = (uint8_t)(((l)) & 0xff)) - -#define l2n8(l, c) \ - (*((c)++) = (uint8_t)(((l) >> 56) & 0xff), \ - *((c)++) = (uint8_t)(((l) >> 48) & 0xff), \ - *((c)++) = (uint8_t)(((l) >> 40) & 0xff), \ - *((c)++) = (uint8_t)(((l) >> 32) & 0xff), \ - *((c)++) = (uint8_t)(((l) >> 24) & 0xff), \ - *((c)++) = (uint8_t)(((l) >> 16) & 0xff), \ - *((c)++) = (uint8_t)(((l) >> 8) & 0xff), \ - *((c)++) = (uint8_t)(((l)) & 0xff)) - -/* NOTE - c is not incremented as per l2c */ -#define l2cn(l1, l2, c, n) \ - { \ - c += n; \ - switch (n) { \ - case 8: \ - *(--(c)) = (uint8_t)(((l2) >> 24) & 0xff); \ - case 7: \ - *(--(c)) = (uint8_t)(((l2) >> 16) & 0xff); \ - case 6: \ - *(--(c)) = (uint8_t)(((l2) >> 8) & 0xff); \ - case 5: \ - *(--(c)) = (uint8_t)(((l2)) & 0xff); \ - case 4: \ - *(--(c)) = (uint8_t)(((l1) >> 24) & 0xff); \ - case 3: \ - *(--(c)) = (uint8_t)(((l1) >> 16) & 0xff); \ - case 2: \ - *(--(c)) = (uint8_t)(((l1) >> 8) & 0xff); \ - case 1: \ - *(--(c)) = (uint8_t)(((l1)) & 0xff); \ - } \ - } - -#define n2s(c, s) \ - ((s = (((unsigned int)(c[0])) << 8) | (((unsigned int)(c[1])))), c += 2) - -#define s2n(s, c) \ - ((c[0] = (uint8_t)(((s) >> 8) & 0xff), \ - c[1] = (uint8_t)(((s)) & 0xff)), \ - c += 2) - -#define n2l3(c, l) \ - ((l = (((unsigned long)(c[0])) << 16) | (((unsigned long)(c[1])) << 8) | \ - (((unsigned long)(c[2])))), \ - c += 3) - -#define l2n3(l, c) \ - ((c[0] = (uint8_t)(((l) >> 16) & 0xff), \ - c[1] = (uint8_t)(((l) >> 8) & 0xff), \ - c[2] = (uint8_t)(((l)) & 0xff)), \ - c += 3) - -/* LOCAL STUFF */ +struct ssl_handshake_st { + /* ssl is a non-owning pointer to the parent |SSL| object. */ + SSL *ssl; + + /* do_tls13_handshake runs the TLS 1.3 handshake. On completion, it returns + * |ssl_hs_ok|. Otherwise, it returns a value corresponding to what operation + * is needed to progress. */ + enum ssl_hs_wait_t (*do_tls13_handshake)(SSL_HANDSHAKE *hs); + + /* wait contains the operation |do_tls13_handshake| is currently blocking on + * or |ssl_hs_ok| if none. */ + enum ssl_hs_wait_t wait; + + /* state contains one of the SSL3_ST_* values. */ + int state; + + /* next_state is used when SSL_ST_FLUSH_DATA is entered */ + int next_state; + + /* tls13_state is the internal state for the TLS 1.3 handshake. Its values + * depend on |do_tls13_handshake| but the starting state is always zero. */ + int tls13_state; + + size_t hash_len; + uint8_t secret[EVP_MAX_MD_SIZE]; + uint8_t client_handshake_secret[EVP_MAX_MD_SIZE]; + uint8_t server_handshake_secret[EVP_MAX_MD_SIZE]; + uint8_t client_traffic_secret_0[EVP_MAX_MD_SIZE]; + uint8_t server_traffic_secret_0[EVP_MAX_MD_SIZE]; + + union { + /* sent is a bitset where the bits correspond to elements of kExtensions + * in t1_lib.c. Each bit is set if that extension was sent in a + * ClientHello. It's not used by servers. */ + uint32_t sent; + /* received is a bitset, like |sent|, but is used by servers to record + * which extensions were received from a client. */ + uint32_t received; + } extensions; + + union { + /* sent is a bitset where the bits correspond to elements of + * |client_custom_extensions| in the |SSL_CTX|. Each bit is set if that + * extension was sent in a ClientHello. It's not used by servers. */ + uint16_t sent; + /* received is a bitset, like |sent|, but is used by servers to record + * which custom extensions were received from a client. The bits here + * correspond to |server_custom_extensions|. */ + uint16_t received; + } custom_extensions; + + /* retry_group is the group ID selected by the server in HelloRetryRequest in + * TLS 1.3. */ + uint16_t retry_group; + + /* ecdh_ctx is the current ECDH instance. */ + SSL_ECDH_CTX ecdh_ctx; + + /* transcript is the current handshake transcript. */ + SSL_TRANSCRIPT transcript; + + /* cookie is the value of the cookie received from the server, if any. */ + uint8_t *cookie; + size_t cookie_len; -#define TLSEXT_CHANNEL_ID_SIZE 128 + /* key_share_bytes is the value of the previously sent KeyShare extension by + * the client in TLS 1.3. */ + uint8_t *key_share_bytes; + size_t key_share_bytes_len; -/* Check if an SSL structure is using DTLS */ -#define SSL_IS_DTLS(ssl) (ssl->method->is_dtls) + /* public_key, for servers, is the key share to be sent to the client in TLS + * 1.3. */ + uint8_t *public_key; + size_t public_key_len; -/* From RFC4492, used in encoding the curve type in ECParameters */ -#define NAMED_CURVE_TYPE 3 + /* peer_sigalgs are the signature algorithms that the peer supports. These are + * taken from the contents of the signature algorithms extension for a server + * or from the CertificateRequest for a client. */ + uint16_t *peer_sigalgs; + /* num_peer_sigalgs is the number of entries in |peer_sigalgs|. */ + size_t num_peer_sigalgs; + + /* peer_supported_group_list contains the supported group IDs advertised by + * the peer. This is only set on the server's end. The server does not + * advertise this extension to the client. */ + uint16_t *peer_supported_group_list; + size_t peer_supported_group_list_len; + + /* peer_key is the peer's ECDH key for a TLS 1.2 client. */ + uint8_t *peer_key; + size_t peer_key_len; + + /* server_params, in TLS 1.2, stores the ServerKeyExchange parameters to be + * signed while the signature is being computed. */ + uint8_t *server_params; + size_t server_params_len; + + /* peer_psk_identity_hint, on the client, is the psk_identity_hint sent by the + * server when using a TLS 1.2 PSK key exchange. */ + char *peer_psk_identity_hint; + + /* ca_names, on the client, contains the list of CAs received in a + * CertificateRequest message. */ + STACK_OF(X509_NAME) *ca_names; + + /* certificate_types, on the client, contains the set of certificate types + * received in a CertificateRequest message. */ + uint8_t *certificate_types; + size_t num_certificate_types; + + /* hostname, on the server, is the value of the SNI extension. */ + char *hostname; + + /* peer_pubkey is the public key parsed from the peer's leaf certificate. */ + EVP_PKEY *peer_pubkey; -enum ssl_hash_message_t { - ssl_dont_hash_message, - ssl_hash_message, + /* new_session is the new mutable session being established by the current + * handshake. It should not be cached. */ + SSL_SESSION *new_session; + + /* new_cipher is the cipher being negotiated in this handshake. */ + const SSL_CIPHER *new_cipher; + + /* key_block is the record-layer key block for TLS 1.2 and earlier. */ + uint8_t *key_block; + uint8_t key_block_len; + + /* session_tickets_sent, in TLS 1.3, is the number of tickets the server has + * sent. */ + uint8_t session_tickets_sent; + + /* scts_requested is one if the SCT extension is in the ClientHello. */ + unsigned scts_requested:1; + + /* needs_psk_binder if the ClientHello has a placeholder PSK binder to be + * filled in. */ + unsigned needs_psk_binder:1; + + unsigned received_hello_retry_request:1; + + /* accept_psk_mode stores whether the client's PSK mode is compatible with our + * preferences. */ + unsigned accept_psk_mode:1; + + /* cert_request is one if a client certificate was requested and zero + * otherwise. */ + unsigned cert_request:1; + + /* certificate_status_expected is one if OCSP stapling was negotiated and the + * server is expected to send a CertificateStatus message. (This is used on + * both the client and server sides.) */ + unsigned certificate_status_expected:1; + + /* ocsp_stapling_requested is one if a client requested OCSP stapling. */ + unsigned ocsp_stapling_requested:1; + + /* should_ack_sni is used by a server and indicates that the SNI extension + * should be echoed in the ServerHello. */ + unsigned should_ack_sni:1; + + /* in_false_start is one if there is a pending client handshake in False + * Start. The client may write data at this point. */ + unsigned in_false_start:1; + + /* next_proto_neg_seen is one of NPN was negotiated. */ + unsigned next_proto_neg_seen:1; + + /* ticket_expected is one if a TLS 1.2 NewSessionTicket message is to be sent + * or received. */ + unsigned ticket_expected:1; + + /* v2_clienthello is one if we received a V2ClientHello. */ + unsigned v2_clienthello:1; + + /* extended_master_secret is one if the extended master secret extension is + * negotiated in this handshake. */ + unsigned extended_master_secret:1; + + /* client_version is the value sent or received in the ClientHello version. */ + uint16_t client_version; +} /* SSL_HANDSHAKE */; + +SSL_HANDSHAKE *ssl_handshake_new(SSL *ssl); + +/* ssl_handshake_free releases all memory associated with |hs|. */ +void ssl_handshake_free(SSL_HANDSHAKE *hs); + +/* ssl_check_message_type checks if the current message has type |type|. If so + * it returns one. Otherwise, it sends an alert and returns zero. */ +int ssl_check_message_type(SSL *ssl, int type); + +/* tls13_handshake runs the TLS 1.3 handshake. It returns one on success and <= + * 0 on error. */ +int tls13_handshake(SSL_HANDSHAKE *hs); + +/* The following are implementations of |do_tls13_handshake| for the client and + * server. */ +enum ssl_hs_wait_t tls13_client_handshake(SSL_HANDSHAKE *hs); +enum ssl_hs_wait_t tls13_server_handshake(SSL_HANDSHAKE *hs); + +/* tls13_post_handshake processes a post-handshake message. It returns one on + * success and zero on failure. */ +int tls13_post_handshake(SSL *ssl); + +int tls13_process_certificate(SSL_HANDSHAKE *hs, int allow_anonymous); +int tls13_process_certificate_verify(SSL_HANDSHAKE *hs); +int tls13_process_finished(SSL_HANDSHAKE *hs); + +int tls13_add_certificate(SSL_HANDSHAKE *hs); +enum ssl_private_key_result_t tls13_add_certificate_verify(SSL_HANDSHAKE *hs, + int is_first_run); +int tls13_add_finished(SSL_HANDSHAKE *hs); +int tls13_process_new_session_ticket(SSL *ssl); + +int ssl_ext_key_share_parse_serverhello(SSL_HANDSHAKE *hs, uint8_t **out_secret, + size_t *out_secret_len, + uint8_t *out_alert, CBS *contents); +int ssl_ext_key_share_parse_clienthello(SSL_HANDSHAKE *hs, int *out_found, + uint8_t **out_secret, + size_t *out_secret_len, + uint8_t *out_alert, CBS *contents); +int ssl_ext_key_share_add_serverhello(SSL_HANDSHAKE *hs, CBB *out); + +int ssl_ext_pre_shared_key_parse_serverhello(SSL_HANDSHAKE *hs, + uint8_t *out_alert, CBS *contents); +int ssl_ext_pre_shared_key_parse_clienthello(SSL_HANDSHAKE *hs, + SSL_SESSION **out_session, + CBS *out_binders, + uint8_t *out_alert, CBS *contents); +int ssl_ext_pre_shared_key_add_serverhello(SSL_HANDSHAKE *hs, CBB *out); + +/* ssl_is_sct_list_valid does a shallow parse of the SCT list in |contents| and + * returns one iff it's valid. */ +int ssl_is_sct_list_valid(const CBS *contents); + +int ssl_write_client_hello(SSL_HANDSHAKE *hs); + +/* ssl_clear_tls13_state releases client state only needed for TLS 1.3. It + * should be called once the version is known to be TLS 1.2 or earlier. */ +void ssl_clear_tls13_state(SSL_HANDSHAKE *hs); + +enum ssl_cert_verify_context_t { + ssl_cert_verify_server, + ssl_cert_verify_client, + ssl_cert_verify_channel_id, }; -/* Structure containing decoded values of signature algorithms extension */ -typedef struct tls_sigalgs_st { - uint8_t rsign; - uint8_t rhash; -} TLS_SIGALGS; +/* tls13_get_cert_verify_signature_input generates the message to be signed for + * TLS 1.3's CertificateVerify message. |cert_verify_context| determines the + * type of signature. It sets |*out| and |*out_len| to a newly allocated buffer + * containing the result. The caller must free it with |OPENSSL_free| to release + * it. This function returns one on success and zero on failure. */ +int tls13_get_cert_verify_signature_input( + SSL_HANDSHAKE *hs, uint8_t **out, size_t *out_len, + enum ssl_cert_verify_context_t cert_verify_context); + +/* ssl_negotiate_alpn negotiates the ALPN extension, if applicable. It returns + * one on successful negotiation or if nothing was negotiated. It returns zero + * and sets |*out_alert| to an alert on error. */ +int ssl_negotiate_alpn(SSL_HANDSHAKE *hs, uint8_t *out_alert, + const SSL_CLIENT_HELLO *client_hello); + +typedef struct { + uint16_t type; + int *out_present; + CBS *out_data; +} SSL_EXTENSION_TYPE; + +/* ssl_parse_extensions parses a TLS extensions block out of |cbs| and advances + * it. It writes the parsed extensions to pointers denoted by |ext_types|. On + * success, it fills in the |out_present| and |out_data| fields and returns one. + * Otherwise, it sets |*out_alert| to an alert to send and returns zero. Unknown + * extensions are rejected unless |ignore_unknown| is 1. */ +int ssl_parse_extensions(const CBS *cbs, uint8_t *out_alert, + const SSL_EXTENSION_TYPE *ext_types, + size_t num_ext_types, int ignore_unknown); + + +/* SSLKEYLOGFILE functions. */ + +/* ssl_log_secret logs |secret| with label |label|, if logging is enabled for + * |ssl|. It returns one on success and zero on failure. */ +int ssl_log_secret(const SSL *ssl, const char *label, const uint8_t *secret, + size_t secret_len); + + +/* ClientHello functions. */ + +int ssl_client_hello_init(SSL *ssl, SSL_CLIENT_HELLO *out, const uint8_t *in, + size_t in_len); + +int ssl_client_hello_get_extension(const SSL_CLIENT_HELLO *client_hello, + CBS *out, uint16_t extension_type); + +int ssl_client_cipher_list_contains_cipher(const SSL_CLIENT_HELLO *client_hello, + uint16_t id); + + +/* GREASE. */ + +enum ssl_grease_index_t { + ssl_grease_cipher = 0, + ssl_grease_group, + ssl_grease_extension1, + ssl_grease_extension2, + ssl_grease_version, + ssl_grease_ticket_extension, +}; + +/* ssl_get_grease_value returns a GREASE value for |ssl|. For a given + * connection, the values for each index will be deterministic. This allows the + * same ClientHello be sent twice for a HelloRetryRequest or the same group be + * advertised in both supported_groups and key_shares. */ +uint16_t ssl_get_grease_value(const SSL *ssl, enum ssl_grease_index_t index); + + +/* Signature algorithms. */ + +/* tls1_parse_peer_sigalgs parses |sigalgs| as the list of peer signature + * algorithms and saves them on |hs|. It returns one on success and zero on + * error. */ +int tls1_parse_peer_sigalgs(SSL_HANDSHAKE *hs, const CBS *sigalgs); + +/* tls1_choose_signature_algorithm sets |*out| to a signature algorithm for use + * with |hs|'s private key based on the peer's preferences and the algorithms + * supported. It returns one on success and zero on error. */ +int tls1_choose_signature_algorithm(SSL_HANDSHAKE *hs, uint16_t *out); + +/* tls12_get_verify_sigalgs sets |*out| to the signature algorithms acceptable + * for the peer signature and returns the length of the list. */ +size_t tls12_get_verify_sigalgs(const SSL *ssl, const uint16_t **out); + +/* tls12_check_peer_sigalg checks if |sigalg| is acceptable for the peer + * signature. It returns one on success and zero on error, setting |*out_alert| + * to an alert to send. */ +int tls12_check_peer_sigalg(SSL *ssl, int *out_alert, uint16_t sigalg); + + +/* Underdocumented functions. + * + * Functions below here haven't been touched up and may be underdocumented. */ + +#define TLSEXT_CHANNEL_ID_SIZE 128 + +/* From RFC4492, used in encoding the curve type in ECParameters */ +#define NAMED_CURVE_TYPE 3 typedef struct cert_st { - X509 *x509; EVP_PKEY *privatekey; - /* Chain for this certificate */ - STACK_OF(X509) *chain; + + /* chain contains the certificate chain, with the leaf at the beginning. The + * first element of |chain| may be NULL to indicate that the leaf certificate + * has not yet been set. + * If |chain| != NULL -> len(chain) >= 1 + * If |chain[0]| == NULL -> len(chain) >= 2. + * |chain[1..]| != NULL */ + STACK_OF(CRYPTO_BUFFER) *chain; + + /* x509_chain may contain a parsed copy of |chain[1..]|. This is only used as + * a cache in order to implement “get0” functions that return a non-owning + * pointer to the certificate chain. */ + STACK_OF(X509) *x509_chain; + + /* x509_leaf may contain a parsed copy of the first element of |chain|. This + * is only used as a cache in order to implement “get0” functions that return + * a non-owning pointer to the certificate chain. */ + X509 *x509_leaf; + + /* x509_stash contains the last |X509| object append to the chain. This is a + * workaround for some third-party code that continue to use an |X509| object + * even after passing ownership with an “add0” function. */ + X509 *x509_stash; /* key_method, if non-NULL, is a set of callbacks to call for private key * operations. */ const SSL_PRIVATE_KEY_METHOD *key_method; - /* For clients the following masks are of *disabled* key and auth algorithms - * based on the current configuration. - * - * TODO(davidben): Remove these. They get checked twice: when sending the - * ClientHello and when processing the ServerHello. */ - uint32_t mask_k; - uint32_t mask_a; + /* x509_method contains pointers to functions that might deal with |X509| + * compatibility, or might be a no-op, depending on the application. */ + const SSL_X509_METHOD *x509_method; DH *dh_tmp; DH *(*dh_tmp_cb)(SSL *ssl, int is_export, int keysize); - /* peer_sigalgs are the algorithm/hash pairs that the peer supports. These - * are taken from the contents of signature algorithms extension for a server - * or from the CertificateRequest for a client. */ - TLS_SIGALGS *peer_sigalgs; - /* peer_sigalgslen is the number of entries in |peer_sigalgs|. */ - size_t peer_sigalgslen; - - /* digest_nids, if non-NULL, is the set of digests supported by |privatekey| - * in decreasing order of preference. */ - int *digest_nids; - size_t num_digest_nids; + /* sigalgs, if non-NULL, is the set of signature algorithms supported by + * |privatekey| in decreasing order of preference. */ + uint16_t *sigalgs; + size_t num_sigalgs; /* Certificate setup callback: if set is called whenever a * certificate may be required (client or server). the callback @@ -803,6 +1331,21 @@ typedef struct cert_st { * supported signature algorithms or curves. */ int (*cert_cb)(SSL *ssl, void *arg); void *cert_cb_arg; + + /* Optional X509_STORE for certificate validation. If NULL the parent SSL_CTX + * store is used instead. */ + X509_STORE *verify_store; + + /* Signed certificate timestamp list to be sent to the client, if requested */ + CRYPTO_BUFFER *signed_cert_timestamp_list; + + /* OCSP response to be sent to the client, if requested. */ + CRYPTO_BUFFER *ocsp_response; + + /* sid_ctx partitions the session space within a shared session cache or + * ticket key. Only sessions with a matching value will be accepted. */ + uint8_t sid_ctx_length; + uint8_t sid_ctx[SSL_MAX_SID_CTX_LENGTH]; } CERT; /* SSL_METHOD is a compatibility structure to support the legacy version-locked @@ -814,56 +1357,304 @@ struct ssl_method_st { /* method is the underlying SSL_PROTOCOL_METHOD that initializes the * SSL_CTX. */ const SSL_PROTOCOL_METHOD *method; + /* x509_method contains pointers to functions that might deal with |X509| + * compatibility, or might be a no-op, depending on the application. */ + const SSL_X509_METHOD *x509_method; }; /* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */ struct ssl_protocol_method_st { /* is_dtls is one if the protocol is DTLS and zero otherwise. */ char is_dtls; + /* min_version is the minimum implemented version. */ + uint16_t min_version; + /* max_version is the maximum implemented version. */ + uint16_t max_version; + /* version_from_wire maps |wire_version| to a protocol version. On success, it + * sets |*out_version| to the result and returns one. If the version is + * unknown, it returns zero. */ + int (*version_from_wire)(uint16_t *out_version, uint16_t wire_version); + /* version_to_wire maps |version| to the wire representation. It is an error + * to call it with an invalid version. */ + uint16_t (*version_to_wire)(uint16_t version); int (*ssl_new)(SSL *ssl); void (*ssl_free)(SSL *ssl); - int (*ssl_accept)(SSL *ssl); - int (*ssl_connect)(SSL *ssl); - long (*ssl_get_message)(SSL *ssl, int header_state, int body_state, - int msg_type, long max, - enum ssl_hash_message_t hash_message, int *ok); - int (*ssl_read_app_data)(SSL *ssl, uint8_t *buf, int len, int peek); - int (*ssl_read_change_cipher_spec)(SSL *ssl); - void (*ssl_read_close_notify)(SSL *ssl); - int (*ssl_write_app_data)(SSL *ssl, const void *buf_, int len); - int (*ssl_dispatch_alert)(SSL *ssl); + /* ssl_get_message reads the next handshake message. On success, it returns + * one and sets |ssl->s3->tmp.message_type|, |ssl->init_msg|, and + * |ssl->init_num|. Otherwise, it returns <= 0. */ + int (*ssl_get_message)(SSL *ssl); + /* get_current_message sets |*out| to the current handshake message. This + * includes the protocol-specific message header. */ + void (*get_current_message)(const SSL *ssl, CBS *out); + /* release_current_message is called to release the current handshake message. + * If |free_buffer| is one, buffers will also be released. */ + void (*release_current_message)(SSL *ssl, int free_buffer); + /* read_app_data reads up to |len| bytes of application data into |buf|. On + * success, it returns the number of bytes read. Otherwise, it returns <= 0 + * and sets |*out_got_handshake| to whether the failure was due to a + * post-handshake handshake message. If so, it fills in the current message as + * in |ssl_get_message|. */ + int (*read_app_data)(SSL *ssl, int *out_got_handshake, uint8_t *buf, int len, + int peek); + int (*read_change_cipher_spec)(SSL *ssl); + void (*read_close_notify)(SSL *ssl); + int (*write_app_data)(SSL *ssl, const uint8_t *buf, int len); + int (*dispatch_alert)(SSL *ssl); /* supports_cipher returns one if |cipher| is supported by this protocol and * zero otherwise. */ int (*supports_cipher)(const SSL_CIPHER *cipher); - /* Handshake header length */ - unsigned int hhlen; - /* Set the handshake header */ - int (*set_handshake_header)(SSL *ssl, int type, unsigned long len); - /* Write out handshake message */ - int (*do_write)(SSL *ssl); + /* init_message begins a new handshake message of type |type|. |cbb| is the + * root CBB to be passed into |finish_message|. |*body| is set to a child CBB + * the caller should write to. It returns one on success and zero on error. */ + int (*init_message)(SSL *ssl, CBB *cbb, CBB *body, uint8_t type); + /* finish_message finishes a handshake message. It sets |*out_msg| to a + * newly-allocated buffer with the serialized message. The caller must + * release it with |OPENSSL_free| when done. It returns one on success and + * zero on error. */ + int (*finish_message)(SSL *ssl, CBB *cbb, uint8_t **out_msg, size_t *out_len); + /* add_message adds a handshake message to the pending flight. It returns one + * on success and zero on error. In either case, it takes ownership of |msg| + * and releases it with |OPENSSL_free| when done. */ + int (*add_message)(SSL *ssl, uint8_t *msg, size_t len); + /* add_change_cipher_spec adds a ChangeCipherSpec record to the pending + * flight. It returns one on success and zero on error. */ + int (*add_change_cipher_spec)(SSL *ssl); + /* add_alert adds an alert to the pending flight. It returns one on success + * and zero on error. */ + int (*add_alert)(SSL *ssl, uint8_t level, uint8_t desc); + /* flush_flight flushes the pending flight to the transport. It returns one on + * success and <= 0 on error. */ + int (*flush_flight)(SSL *ssl); + /* expect_flight is called when the handshake expects a flight of messages from + * the peer. */ + void (*expect_flight)(SSL *ssl); + /* received_flight is called when the handshake has received a flight of + * messages from the peer. */ + void (*received_flight)(SSL *ssl); + /* set_read_state sets |ssl|'s read cipher state to |aead_ctx|. It takes + * ownership of |aead_ctx|. It returns one on success and zero if changing the + * read state is forbidden at this point. */ + int (*set_read_state)(SSL *ssl, SSL_AEAD_CTX *aead_ctx); + /* set_write_state sets |ssl|'s write cipher state to |aead_ctx|. It takes + * ownership of |aead_ctx|. It returns one on success and zero if changing the + * write state is forbidden at this point. */ + int (*set_write_state)(SSL *ssl, SSL_AEAD_CTX *aead_ctx); }; -/* This is for the SSLv3/TLSv1.0 differences in crypto/hash stuff It is a bit - * of a mess of functions, but hell, think of it as an opaque structure. */ -struct ssl3_enc_method { - /* prf computes the PRF function for |ssl|. It writes |out_len| bytes to - * |out|, using |secret| as the secret and |label| as the label. |seed1| and - * |seed2| are concatenated to form the seed parameter. It returns one on - * success and zero on failure. */ - int (*prf)(const SSL *ssl, uint8_t *out, size_t out_len, - const uint8_t *secret, size_t secret_len, const char *label, - size_t label_len, const uint8_t *seed1, size_t seed1_len, - const uint8_t *seed2, size_t seed2_len); - int (*final_finish_mac)(SSL *ssl, int from_server, uint8_t *out); - int (*cert_verify_mac)(SSL *, int, uint8_t *); +struct ssl_x509_method_st { + /* cert_clear frees and NULLs all X509-related state. */ + void (*cert_clear)(CERT *cert); + /* cert_flush_cached_chain drops any cached |X509|-based certificate chain + * from |cert|. */ + void (*cert_flush_cached_chain)(CERT *cert); + /* cert_flush_cached_chain drops any cached |X509|-based leaf certificate + * from |cert|. */ + void (*cert_flush_cached_leaf)(CERT *cert); + + /* session_cache_objects fills out |sess->x509_peer| and |sess->x509_chain| + * from |sess->certs| and erases |sess->x509_chain_without_leaf|. It returns + * one on success or zero on error. */ + int (*session_cache_objects)(SSL_SESSION *session); + /* session_dup duplicates any needed fields from |session| to |new_session|. + * It returns one on success or zero on error. */ + int (*session_dup)(SSL_SESSION *new_session, const SSL_SESSION *session); + /* session_clear frees any X509-related state from |session|. */ + void (*session_clear)(SSL_SESSION *session); }; -#define SSL_HM_HEADER_LENGTH(ssl) ssl->method->hhlen -#define ssl_handshake_start(ssl) \ - (((uint8_t *)ssl->init_buf->data) + ssl->method->hhlen) -#define ssl_set_handshake_header(ssl, htype, len) \ - ssl->method->set_handshake_header(ssl, htype, len) -#define ssl_do_write(ssl) ssl->method->do_write(ssl) +/* ssl_noop_x509_method is implements the |ssl_x509_method_st| functions by + * doing nothing. */ +extern const struct ssl_x509_method_st ssl_noop_x509_method; + +/* ssl_crypto_x509_method provides the |ssl_x509_method_st| functions using + * crypto/x509. */ +extern const struct ssl_x509_method_st ssl_crypto_x509_method; + +typedef struct ssl3_record_st { + /* type is the record type. */ + uint8_t type; + /* length is the number of unconsumed bytes in the record. */ + uint16_t length; + /* data is a non-owning pointer to the first unconsumed byte of the record. */ + uint8_t *data; +} SSL3_RECORD; + +typedef struct ssl3_buffer_st { + /* buf is the memory allocated for this buffer. */ + uint8_t *buf; + /* offset is the offset into |buf| which the buffer contents start at. */ + uint16_t offset; + /* len is the length of the buffer contents from |buf| + |offset|. */ + uint16_t len; + /* cap is how much memory beyond |buf| + |offset| is available. */ + uint16_t cap; +} SSL3_BUFFER; + +/* An ssl_shutdown_t describes the shutdown state of one end of the connection, + * whether it is alive or has been shutdown via close_notify or fatal alert. */ +enum ssl_shutdown_t { + ssl_shutdown_none = 0, + ssl_shutdown_close_notify = 1, + ssl_shutdown_fatal_alert = 2, +}; + +typedef struct ssl3_state_st { + uint8_t read_sequence[8]; + uint8_t write_sequence[8]; + + uint8_t server_random[SSL3_RANDOM_SIZE]; + uint8_t client_random[SSL3_RANDOM_SIZE]; + + /* read_buffer holds data from the transport to be processed. */ + SSL3_BUFFER read_buffer; + /* write_buffer holds data to be written to the transport. */ + SSL3_BUFFER write_buffer; + + SSL3_RECORD rrec; /* each decoded record goes in here */ + + /* partial write - check the numbers match */ + unsigned int wnum; /* number of bytes sent so far */ + int wpend_tot; /* number bytes written */ + int wpend_type; + int wpend_ret; /* number of bytes submitted */ + const uint8_t *wpend_buf; + + /* recv_shutdown is the shutdown state for the receive half of the + * connection. */ + enum ssl_shutdown_t recv_shutdown; + + /* recv_shutdown is the shutdown state for the send half of the connection. */ + enum ssl_shutdown_t send_shutdown; + + int alert_dispatch; + + int total_renegotiations; + + /* early_data_skipped is the amount of early data that has been skipped by the + * record layer. */ + uint16_t early_data_skipped; + + /* empty_record_count is the number of consecutive empty records received. */ + uint8_t empty_record_count; + + /* warning_alert_count is the number of consecutive warning alerts + * received. */ + uint8_t warning_alert_count; + + /* key_update_count is the number of consecutive KeyUpdates received. */ + uint8_t key_update_count; + + /* skip_early_data instructs the record layer to skip unexpected early data + * messages when 0RTT is rejected. */ + unsigned skip_early_data:1; + + /* have_version is true if the connection's final version is known. Otherwise + * the version has not been negotiated yet. */ + unsigned have_version:1; + + /* v2_hello_done is true if the peer's V2ClientHello, if any, has been handled + * and future messages should use the record layer. */ + unsigned v2_hello_done:1; + + /* is_v2_hello is true if the current handshake message was derived from a + * V2ClientHello rather than received from the peer directly. */ + unsigned is_v2_hello:1; + + /* initial_handshake_complete is true if the initial handshake has + * completed. */ + unsigned initial_handshake_complete:1; + + /* session_reused indicates whether a session was resumed. */ + unsigned session_reused:1; + + unsigned send_connection_binding:1; + + /* In a client, this means that the server supported Channel ID and that a + * Channel ID was sent. In a server it means that we echoed support for + * Channel IDs and that tlsext_channel_id will be valid after the + * handshake. */ + unsigned tlsext_channel_id_valid:1; + + /* short_header is one if https://github.com/tlswg/tls13-spec/pull/762 has + * been negotiated. */ + unsigned short_header:1; + + uint8_t send_alert[2]; + + /* pending_flight is the pending outgoing flight. This is used to flush each + * handshake flight in a single write. */ + BUF_MEM *pending_flight; + + /* pending_flight_offset is the number of bytes of |pending_flight| which have + * been successfully written. */ + uint32_t pending_flight_offset; + + /* aead_read_ctx is the current read cipher state. */ + SSL_AEAD_CTX *aead_read_ctx; + + /* aead_write_ctx is the current write cipher state. */ + SSL_AEAD_CTX *aead_write_ctx; + + /* hs is the handshake state for the current handshake or NULL if there isn't + * one. */ + SSL_HANDSHAKE *hs; + + uint8_t write_traffic_secret[EVP_MAX_MD_SIZE]; + uint8_t read_traffic_secret[EVP_MAX_MD_SIZE]; + uint8_t exporter_secret[EVP_MAX_MD_SIZE]; + uint8_t write_traffic_secret_len; + uint8_t read_traffic_secret_len; + uint8_t exporter_secret_len; + + /* Connection binding to prevent renegotiation attacks */ + uint8_t previous_client_finished[12]; + uint8_t previous_client_finished_len; + uint8_t previous_server_finished_len; + uint8_t previous_server_finished[12]; + + /* State pertaining to the pending handshake. + * + * TODO(davidben): Move everything not needed after the handshake completes to + * |hs| and remove this. */ + struct { + int message_type; + + int reuse_message; + + uint8_t new_mac_secret_len; + uint8_t new_key_len; + uint8_t new_fixed_iv_len; + } tmp; + + /* established_session is the session established by the connection. This + * session is only filled upon the completion of the handshake and is + * immutable. */ + SSL_SESSION *established_session; + + /* Next protocol negotiation. For the client, this is the protocol that we + * sent in NextProtocol and is set when handling ServerHello extensions. + * + * For a server, this is the client's selected_protocol from NextProtocol and + * is set when handling the NextProtocol message, before the Finished + * message. */ + uint8_t *next_proto_negotiated; + size_t next_proto_negotiated_len; + + /* ALPN information + * (we are in the process of transitioning from NPN to ALPN.) */ + + /* In a server these point to the selected ALPN protocol after the + * ClientHello has been processed. In a client these contain the protocol + * that the server selected once the ServerHello has been processed. */ + uint8_t *alpn_selected; + size_t alpn_selected_len; + + /* For a server: + * If |tlsext_channel_id_valid| is true, then this contains the + * verified Channel ID from the client: a P256 point, (x,y), where + * each are big-endian values. */ + uint8_t tlsext_channel_id[64]; +} SSL3_STATE; /* lengths of messages */ #define DTLS1_COOKIE_LENGTH 256 @@ -876,27 +1667,27 @@ struct ssl3_enc_method { #define DTLS1_AL_HEADER_LENGTH 2 -/* TODO(davidben): This structure is used for both incoming messages and - * outgoing messages. |is_ccs| and |epoch| are only used in the latter and - * should be moved elsewhere. */ struct hm_header_st { uint8_t type; uint32_t msg_len; uint16_t seq; uint32_t frag_off; uint32_t frag_len; - int is_ccs; - /* epoch, for buffered outgoing messages, is the epoch the message was - * originally sent in. */ - uint16_t epoch; }; -/* TODO(davidben): This structure is used for both incoming messages and - * outgoing messages. |fragment| and |reassembly| are only used in the former - * and should be moved elsewhere. */ +/* An hm_fragment is an incoming DTLS message, possibly not yet assembled. */ typedef struct hm_fragment_st { - struct hm_header_st msg_header; - uint8_t *fragment; + /* type is the type of the message. */ + uint8_t type; + /* seq is the sequence number of this message. */ + uint16_t seq; + /* msg_len is the length of the message body. */ + uint32_t msg_len; + /* data is a pointer to the message, including message header. It has length + * |DTLS1_HM_HEADER_LENGTH| + |msg_len|. */ + uint8_t *data; + /* reassembly is a bitmask of |msg_len| bits corresponding to which parts of + * the message have been received. It is NULL if the message is complete. */ uint8_t *reassembly; } hm_fragment; @@ -916,33 +1707,31 @@ typedef struct dtls1_state_st { /* records being received in the current epoch */ DTLS1_BITMAP bitmap; - /* handshake message numbers. - * TODO(davidben): It doesn't make much sense to store both of these. Only - * store one. */ uint16_t handshake_write_seq; - uint16_t next_handshake_write_seq; - uint16_t handshake_read_seq; /* save last sequence number for retransmissions */ uint8_t last_write_sequence[8]; - /* buffered_messages is a priority queue of incoming handshake messages that - * have yet to be processed. - * - * TODO(davidben): This data structure may as well be a ring buffer of fixed - * size. */ - pqueue buffered_messages; + /* incoming_messages is a ring buffer of incoming handshake messages that have + * yet to be processed. The front of the ring buffer is message number + * |handshake_read_seq|, at position |handshake_read_seq| % + * |SSL_MAX_HANDSHAKE_FLIGHT|. */ + hm_fragment *incoming_messages[SSL_MAX_HANDSHAKE_FLIGHT]; - /* send_messages is a priority queue of outgoing handshake messages sent in - * the most recent handshake flight. - * - * TODO(davidben): This data structure may as well be a STACK_OF(T). */ - pqueue sent_messages; + /* outgoing_messages is the queue of outgoing messages from the last handshake + * flight. */ + DTLS_OUTGOING_MESSAGE outgoing_messages[SSL_MAX_HANDSHAKE_FLIGHT]; + uint8_t outgoing_messages_len; - unsigned int mtu; /* max DTLS packet size */ + /* outgoing_written is the number of outgoing messages that have been + * written. */ + uint8_t outgoing_written; + /* outgoing_offset is the number of bytes of the next outgoing message have + * been written. */ + uint32_t outgoing_offset; - struct hm_header_st w_msg_hdr; + unsigned int mtu; /* max DTLS packet size */ /* num_timeouts is the number of times the retransmit timer has fired since * the last time it was reset. */ @@ -952,20 +1741,209 @@ typedef struct dtls1_state_st { * timeout. */ struct timeval next_timeout; - /* Timeout duration */ - unsigned short timeout_duration; + /* timeout_duration_ms is the timeout duration in milliseconds. */ + unsigned timeout_duration_ms; } DTLS1_STATE; -extern const SSL3_ENC_METHOD TLSv1_enc_data; -extern const SSL3_ENC_METHOD SSLv3_enc_data; -extern const SRTP_PROTECTION_PROFILE kSRTPProfiles[]; +struct ssl_st { + /* method is the method table corresponding to the current protocol (DTLS or + * TLS). */ + const SSL_PROTOCOL_METHOD *method; + + /* version is the protocol version. */ + int version; -int ssl_clear_bad_session(SSL *ssl); -CERT *ssl_cert_new(void); + /* max_version is the maximum acceptable protocol version. Note this version + * is normalized in DTLS. */ + uint16_t max_version; + + /* min_version is the minimum acceptable protocol version. Note this version + * is normalized in DTLS. */ + uint16_t min_version; + + uint16_t max_send_fragment; + + /* There are 2 BIO's even though they are normally both the same. This is so + * data can be read and written to different handlers */ + + BIO *rbio; /* used by SSL_read */ + BIO *wbio; /* used by SSL_write */ + + int (*handshake_func)(SSL_HANDSHAKE *hs); + + BUF_MEM *init_buf; /* buffer used during init */ + + /* init_msg is a pointer to the current handshake message body. */ + const uint8_t *init_msg; + /* init_num is the length of the current handshake message body. */ + uint32_t init_num; + + struct ssl3_state_st *s3; /* SSLv3 variables */ + struct dtls1_state_st *d1; /* DTLSv1 variables */ + + /* callback that allows applications to peek at protocol messages */ + void (*msg_callback)(int write_p, int version, int content_type, + const void *buf, size_t len, SSL *ssl, void *arg); + void *msg_callback_arg; + + X509_VERIFY_PARAM *param; + + /* crypto */ + struct ssl_cipher_preference_list_st *cipher_list; + + /* session info */ + + /* client cert? */ + /* This is used to hold the server certificate used */ + struct cert_st /* CERT */ *cert; + + /* This holds a variable that indicates what we were doing when a 0 or -1 is + * returned. This is needed for non-blocking IO so we know what request + * needs re-doing when in SSL_accept or SSL_connect */ + int rwstate; + + /* initial_timeout_duration_ms is the default DTLS timeout duration in + * milliseconds. It's used to initialize the timer any time it's restarted. */ + unsigned initial_timeout_duration_ms; + + /* session is the configured session to be offered by the client. This session + * is immutable. */ + SSL_SESSION *session; + + int (*verify_callback)(int ok, + X509_STORE_CTX *ctx); /* fail if callback returns 0 */ + + void (*info_callback)(const SSL *ssl, int type, int value); + + /* Server-only: psk_identity_hint is the identity hint to send in + * PSK-based key exchanges. */ + char *psk_identity_hint; + + unsigned int (*psk_client_callback)(SSL *ssl, const char *hint, + char *identity, + unsigned int max_identity_len, + uint8_t *psk, unsigned int max_psk_len); + unsigned int (*psk_server_callback)(SSL *ssl, const char *identity, + uint8_t *psk, unsigned int max_psk_len); + + SSL_CTX *ctx; + + /* extra application data */ + CRYPTO_EX_DATA ex_data; + + /* for server side, keep the list of CA_dn we can use */ + STACK_OF(X509_NAME) *client_CA; + + uint32_t options; /* protocol behaviour */ + uint32_t mode; /* API behaviour */ + uint32_t max_cert_list; + char *tlsext_hostname; + size_t supported_group_list_len; + uint16_t *supported_group_list; /* our list */ + + SSL_CTX *initial_ctx; /* initial ctx, used to store sessions */ + + /* srtp_profiles is the list of configured SRTP protection profiles for + * DTLS-SRTP. */ + STACK_OF(SRTP_PROTECTION_PROFILE) *srtp_profiles; + + /* srtp_profile is the selected SRTP protection profile for + * DTLS-SRTP. */ + const SRTP_PROTECTION_PROFILE *srtp_profile; + + /* The client's Channel ID private key. */ + EVP_PKEY *tlsext_channel_id_private; + + /* For a client, this contains the list of supported protocols in wire + * format. */ + uint8_t *alpn_client_proto_list; + unsigned alpn_client_proto_list_len; + + /* renegotiate_mode controls how peer renegotiation attempts are handled. */ + enum ssl_renegotiate_mode_t renegotiate_mode; + + /* verify_mode is a bitmask of |SSL_VERIFY_*| values. */ + uint8_t verify_mode; + + /* server is true iff the this SSL* is the server half. Note: before the SSL* + * is initialized by either SSL_set_accept_state or SSL_set_connect_state, + * the side is not determined. In this state, server is always false. */ + unsigned server:1; + + /* quiet_shutdown is true if the connection should not send a close_notify on + * shutdown. */ + unsigned quiet_shutdown:1; + + /* Enable signed certificate time stamps. Currently client only. */ + unsigned signed_cert_timestamps_enabled:1; + + /* ocsp_stapling_enabled is only used by client connections and indicates + * whether OCSP stapling will be requested. */ + unsigned ocsp_stapling_enabled:1; + + /* tlsext_channel_id_enabled is copied from the |SSL_CTX|. For a server, + * means that we'll accept Channel IDs from clients. For a client, means that + * we'll advertise support. */ + unsigned tlsext_channel_id_enabled:1; + + /* retain_only_sha256_of_client_certs is true if we should compute the SHA256 + * hash of the peer's certificate and then discard it to save memory and + * session space. Only effective on the server side. */ + unsigned retain_only_sha256_of_client_certs:1; +}; + +/* From draft-ietf-tls-tls13-18, used in determining PSK modes. */ +#define SSL_PSK_KE 0x0 +#define SSL_PSK_DHE_KE 0x1 + +/* From draft-ietf-tls-tls13-16, used in determining whether to respond with a + * KeyUpdate. */ +#define SSL_KEY_UPDATE_NOT_REQUESTED 0 +#define SSL_KEY_UPDATE_REQUESTED 1 + +CERT *ssl_cert_new(const SSL_X509_METHOD *x509_method); CERT *ssl_cert_dup(CERT *cert); void ssl_cert_clear_certs(CERT *c); void ssl_cert_free(CERT *c); -int ssl_get_new_session(SSL *ssl, int is_server); +int ssl_set_cert(CERT *cert, CRYPTO_BUFFER *buffer); +int ssl_is_key_type_supported(int key_type); +/* ssl_compare_public_and_private_key returns one if |pubkey| is the public + * counterpart to |privkey|. Otherwise it returns zero and pushes a helpful + * message on the error queue. */ +int ssl_compare_public_and_private_key(const EVP_PKEY *pubkey, + const EVP_PKEY *privkey); +int ssl_cert_check_private_key(const CERT *cert, const EVP_PKEY *privkey); +int ssl_get_new_session(SSL_HANDSHAKE *hs, int is_server); +int ssl_encrypt_ticket(SSL *ssl, CBB *out, const SSL_SESSION *session); + +/* ssl_session_new returns a newly-allocated blank |SSL_SESSION| or NULL on + * error. */ +SSL_SESSION *ssl_session_new(const SSL_X509_METHOD *x509_method); + +/* SSL_SESSION_parse parses an |SSL_SESSION| from |cbs| and advances |cbs| over + * the parsed data. */ +SSL_SESSION *SSL_SESSION_parse(CBS *cbs, const SSL_X509_METHOD *x509_method, + CRYPTO_BUFFER_POOL *pool); + +/* ssl_session_is_context_valid returns one if |session|'s session ID context + * matches the one set on |ssl| and zero otherwise. */ +int ssl_session_is_context_valid(const SSL *ssl, const SSL_SESSION *session); + +/* ssl_session_is_time_valid returns one if |session| is still valid and zero if + * it has expired. */ +int ssl_session_is_time_valid(const SSL *ssl, const SSL_SESSION *session); + +/* ssl_session_is_resumable returns one if |session| is resumable for |hs| and + * zero otherwise. */ +int ssl_session_is_resumable(const SSL_HANDSHAKE *hs, + const SSL_SESSION *session); + +/* SSL_SESSION_get_digest returns the digest used in |session|. If the digest is + * invalid, it returns NULL. */ +const EVP_MD *SSL_SESSION_get_digest(const SSL_SESSION *session, + const SSL *ssl); + +void ssl_set_session(SSL *ssl, SSL_SESSION *session); enum ssl_session_result_t { ssl_session_success, @@ -973,207 +1951,178 @@ enum ssl_session_result_t { ssl_session_retry, }; -/* ssl_get_prev_session looks up the previous session based on |ctx|. On - * success, it sets |*out_session| to the session or NULL if none was found. It - * sets |*out_send_ticket| to whether a ticket should be sent at the end of the - * handshake. If the session could not be looked up synchronously, it returns +/* ssl_get_prev_session looks up the previous session based on |client_hello|. + * On success, it sets |*out_session| to the session or NULL if none was found. + * If the session could not be looked up synchronously, it returns * |ssl_session_retry| and should be called again. Otherwise, it returns * |ssl_session_error|. */ enum ssl_session_result_t ssl_get_prev_session( - SSL *ssl, SSL_SESSION **out_session, int *out_send_ticket, - const struct ssl_early_callback_ctx *ctx); + SSL *ssl, SSL_SESSION **out_session, int *out_tickets_supported, + int *out_renew_ticket, const SSL_CLIENT_HELLO *client_hello); + +/* The following flags determine which parts of the session are duplicated. */ +#define SSL_SESSION_DUP_AUTH_ONLY 0x0 +#define SSL_SESSION_INCLUDE_TICKET 0x1 +#define SSL_SESSION_INCLUDE_NONAUTH 0x2 +#define SSL_SESSION_DUP_ALL \ + (SSL_SESSION_INCLUDE_TICKET | SSL_SESSION_INCLUDE_NONAUTH) + +/* SSL_SESSION_dup returns a newly-allocated |SSL_SESSION| with a copy of the + * fields in |session| or NULL on error. The new session is non-resumable and + * must be explicitly marked resumable once it has been filled in. */ +OPENSSL_EXPORT SSL_SESSION *SSL_SESSION_dup(SSL_SESSION *session, + int dup_flags); + +/* ssl_session_rebase_time updates |session|'s start time to the current time, + * adjusting the timeout so the expiration time is unchanged. */ +void ssl_session_rebase_time(SSL *ssl, SSL_SESSION *session); + +/* ssl_session_renew_timeout calls |ssl_session_rebase_time| and renews + * |session|'s timeout to |timeout| (measured from the current time). The + * renewal is clamped to the session's auth_timeout. */ +void ssl_session_renew_timeout(SSL *ssl, SSL_SESSION *session, long timeout); -STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *ssl, const CBS *cbs); void ssl_cipher_preference_list_free( struct ssl_cipher_preference_list_st *cipher_list); -struct ssl_cipher_preference_list_st *ssl_get_cipher_preferences(SSL *ssl); - -int ssl_cert_set0_chain(CERT *cert, STACK_OF(X509) *chain); -int ssl_cert_set1_chain(CERT *cert, STACK_OF(X509) *chain); -int ssl_cert_add0_chain_cert(CERT *cert, X509 *x509); -int ssl_cert_add1_chain_cert(CERT *cert, X509 *x509); -void ssl_cert_set_cert_cb(CERT *cert, - int (*cb)(SSL *ssl, void *arg), void *arg); - -int ssl_verify_cert_chain(SSL *ssl, STACK_OF(X509) *cert_chain); -int ssl_add_cert_chain(SSL *ssl, unsigned long *l); -void ssl_update_cache(SSL *ssl, int mode); - -/* ssl_get_compatible_server_ciphers determines the key exchange and - * authentication cipher suite masks compatible with the server configuration - * and current ClientHello parameters of |ssl|. It sets |*out_mask_k| to the key - * exchange mask and |*out_mask_a| to the authentication mask. */ -void ssl_get_compatible_server_ciphers(SSL *ssl, uint32_t *out_mask_k, - uint32_t *out_mask_a); - -STACK_OF(SSL_CIPHER) *ssl_get_ciphers_by_id(SSL *ssl); -int ssl_verify_alarm_type(long type); -/* ssl_fill_hello_random fills a client_random or server_random field of length - * |len|. It returns one on success and zero on failure. */ -int ssl_fill_hello_random(uint8_t *out, size_t len, int is_server); - -int ssl3_send_server_certificate(SSL *ssl); -int ssl3_send_new_session_ticket(SSL *ssl); -int ssl3_send_certificate_status(SSL *ssl); -int ssl3_get_finished(SSL *ssl, int state_a, int state_b); -int ssl3_send_change_cipher_spec(SSL *ssl, int state_a, int state_b); -void ssl3_cleanup_key_block(SSL *ssl); -int ssl3_do_write(SSL *ssl, int type); -int ssl3_send_alert(SSL *ssl, int level, int desc); -int ssl3_get_req_cert_type(SSL *ssl, uint8_t *p); -long ssl3_get_message(SSL *ssl, int header_state, int body_state, int msg_type, - long max, enum ssl_hash_message_t hash_message, int *ok); +/* ssl_get_cipher_preferences returns the cipher preference list for TLS 1.2 and + * below. */ +const struct ssl_cipher_preference_list_st *ssl_get_cipher_preferences( + const SSL *ssl); -/* ssl3_hash_current_message incorporates the current handshake message into the - * handshake hash. It returns one on success and zero on allocation failure. */ -int ssl3_hash_current_message(SSL *ssl); +int ssl_verify_cert_chain(SSL *ssl, long *out_verify_result, + STACK_OF(X509) *cert_chain); +void ssl_update_cache(SSL_HANDSHAKE *hs, int mode); -/* ssl3_cert_verify_hash writes the CertificateVerify hash into the bytes - * pointed to by |out| and writes the number of bytes to |*out_len|. |out| must - * have room for EVP_MAX_MD_SIZE bytes. For TLS 1.2 and up, |*out_md| is used - * for the hash function, otherwise the hash function depends on |pkey_type| - * and is written to |*out_md|. It returns one on success and zero on - * failure. */ -int ssl3_cert_verify_hash(SSL *ssl, uint8_t *out, size_t *out_len, - const EVP_MD **out_md, int pkey_type); +int ssl_verify_alarm_type(long type); -int ssl3_send_finished(SSL *ssl, int a, int b); -int ssl3_supports_cipher(const SSL_CIPHER *cipher); +int ssl3_get_finished(SSL_HANDSHAKE *hs); +int ssl3_send_alert(SSL *ssl, int level, int desc); +int ssl3_get_message(SSL *ssl); +void ssl3_get_current_message(const SSL *ssl, CBS *out); +void ssl3_release_current_message(SSL *ssl, int free_buffer); + +int ssl3_send_finished(SSL_HANDSHAKE *hs); int ssl3_dispatch_alert(SSL *ssl); -int ssl3_read_app_data(SSL *ssl, uint8_t *buf, int len, int peek); +int ssl3_read_app_data(SSL *ssl, int *out_got_handshake, uint8_t *buf, int len, + int peek); int ssl3_read_change_cipher_spec(SSL *ssl); void ssl3_read_close_notify(SSL *ssl); -int ssl3_read_bytes(SSL *ssl, int type, uint8_t *buf, int len, int peek); -int ssl3_write_app_data(SSL *ssl, const void *buf, int len); -int ssl3_write_bytes(SSL *ssl, int type, const void *buf, int len); +int ssl3_read_handshake_bytes(SSL *ssl, uint8_t *buf, int len); +int ssl3_write_app_data(SSL *ssl, const uint8_t *buf, int len); int ssl3_output_cert_chain(SSL *ssl); -const SSL_CIPHER *ssl3_choose_cipher( - SSL *ssl, STACK_OF(SSL_CIPHER) *clnt, - struct ssl_cipher_preference_list_st *srvr); int ssl3_new(SSL *ssl); void ssl3_free(SSL *ssl); -int ssl3_accept(SSL *ssl); -int ssl3_connect(SSL *ssl); +int ssl3_accept(SSL_HANDSHAKE *hs); +int ssl3_connect(SSL_HANDSHAKE *hs); + +int ssl3_init_message(SSL *ssl, CBB *cbb, CBB *body, uint8_t type); +int ssl3_finish_message(SSL *ssl, CBB *cbb, uint8_t **out_msg, size_t *out_len); +int ssl3_add_message(SSL *ssl, uint8_t *msg, size_t len); +int ssl3_add_change_cipher_spec(SSL *ssl); +int ssl3_add_alert(SSL *ssl, uint8_t level, uint8_t desc); +int ssl3_flush_flight(SSL *ssl); + +int dtls1_init_message(SSL *ssl, CBB *cbb, CBB *body, uint8_t type); +int dtls1_finish_message(SSL *ssl, CBB *cbb, uint8_t **out_msg, + size_t *out_len); +int dtls1_add_message(SSL *ssl, uint8_t *msg, size_t len); +int dtls1_add_change_cipher_spec(SSL *ssl); +int dtls1_add_alert(SSL *ssl, uint8_t level, uint8_t desc); +int dtls1_flush_flight(SSL *ssl); + +/* ssl_add_message_cbb finishes the handshake message in |cbb| and adds it to + * the pending flight. It returns one on success and zero on error. */ +int ssl_add_message_cbb(SSL *ssl, CBB *cbb); + +/* ssl_hash_current_message incorporates the current handshake message into the + * handshake hash. It returns one on success and zero on allocation failure. */ +int ssl_hash_current_message(SSL_HANDSHAKE *hs); -int ssl3_set_handshake_header(SSL *ssl, int htype, unsigned long len); -int ssl3_handshake_write(SSL *ssl); +/* dtls1_get_record reads a new input record. On success, it places it in + * |ssl->s3->rrec| and returns one. Otherwise it returns <= 0 on error or if + * more data is needed. */ +int dtls1_get_record(SSL *ssl); -int dtls1_do_handshake_write(SSL *ssl, enum dtls1_use_epoch_t use_epoch); -int dtls1_read_app_data(SSL *ssl, uint8_t *buf, int len, int peek); +int dtls1_read_app_data(SSL *ssl, int *out_got_handshake, uint8_t *buf, int len, + int peek); int dtls1_read_change_cipher_spec(SSL *ssl); void dtls1_read_close_notify(SSL *ssl); -int dtls1_read_bytes(SSL *ssl, int type, uint8_t *buf, int len, int peek); -void dtls1_set_message_header(SSL *ssl, uint8_t mt, unsigned long len, - unsigned short seq_num, unsigned long frag_off, - unsigned long frag_len); -int dtls1_write_app_data(SSL *ssl, const void *buf, int len); -int dtls1_write_bytes(SSL *ssl, int type, const void *buf, int len, - enum dtls1_use_epoch_t use_epoch); +int dtls1_write_app_data(SSL *ssl, const uint8_t *buf, int len); + +/* dtls1_write_record sends a record. It returns one on success and <= 0 on + * error. */ +int dtls1_write_record(SSL *ssl, int type, const uint8_t *buf, size_t len, + enum dtls1_use_epoch_t use_epoch); -int dtls1_send_change_cipher_spec(SSL *ssl, int a, int b); int dtls1_send_finished(SSL *ssl, int a, int b, const char *sender, int slen); -int dtls1_read_failed(SSL *ssl, int code); -int dtls1_buffer_message(SSL *ssl); -int dtls1_retransmit_buffered_messages(SSL *ssl); +int dtls1_retransmit_outgoing_messages(SSL *ssl); void dtls1_clear_record_buffer(SSL *ssl); -void dtls1_get_message_header(uint8_t *data, struct hm_header_st *msg_hdr); +int dtls1_parse_fragment(CBS *cbs, struct hm_header_st *out_hdr, + CBS *out_body); int dtls1_check_timeout_num(SSL *ssl); -int dtls1_set_handshake_header(SSL *ssl, int type, unsigned long len); int dtls1_handshake_write(SSL *ssl); -int dtls1_supports_cipher(const SSL_CIPHER *cipher); void dtls1_start_timer(SSL *ssl); void dtls1_stop_timer(SSL *ssl); int dtls1_is_timer_expired(SSL *ssl); void dtls1_double_timeout(SSL *ssl); unsigned int dtls1_min_mtu(void); -void dtls1_hm_fragment_free(hm_fragment *frag); - -/* some client-only functions */ -int ssl3_send_client_hello(SSL *ssl); -int ssl3_get_server_hello(SSL *ssl); -int ssl3_get_certificate_request(SSL *ssl); -int ssl3_get_new_session_ticket(SSL *ssl); -int ssl3_get_cert_status(SSL *ssl); -int ssl3_get_server_done(SSL *ssl); -int ssl3_send_cert_verify(SSL *ssl); -int ssl3_send_client_certificate(SSL *ssl); -int ssl_do_client_cert_cb(SSL *ssl, X509 **px509, EVP_PKEY **ppkey); -int ssl3_send_client_key_exchange(SSL *ssl); -int ssl3_get_server_key_exchange(SSL *ssl); -int ssl3_get_server_certificate(SSL *ssl); -int ssl3_send_next_proto(SSL *ssl); -int ssl3_send_channel_id(SSL *ssl); -int ssl3_verify_server_cert(SSL *ssl); - -/* some server-only functions */ -int ssl3_get_initial_bytes(SSL *ssl); -int ssl3_get_v2_client_hello(SSL *ssl); -int ssl3_get_client_hello(SSL *ssl); -int ssl3_send_server_hello(SSL *ssl); -int ssl3_send_server_key_exchange(SSL *ssl); -int ssl3_send_certificate_request(SSL *ssl); -int ssl3_send_server_done(SSL *ssl); -int ssl3_get_client_certificate(SSL *ssl); -int ssl3_get_client_key_exchange(SSL *ssl); -int ssl3_get_cert_verify(SSL *ssl); -int ssl3_get_next_proto(SSL *ssl); -int ssl3_get_channel_id(SSL *ssl); int dtls1_new(SSL *ssl); int dtls1_accept(SSL *ssl); int dtls1_connect(SSL *ssl); void dtls1_free(SSL *ssl); -long dtls1_get_message(SSL *ssl, int st1, int stn, int mt, long max, - enum ssl_hash_message_t hash_message, int *ok); +int dtls1_get_message(SSL *ssl); +void dtls1_get_current_message(const SSL *ssl, CBS *out); +void dtls1_release_current_message(SSL *ssl, int free_buffer); int dtls1_dispatch_alert(SSL *ssl); -int ssl_init_wbio_buffer(SSL *ssl, int push); -void ssl_free_wbio_buffer(SSL *ssl); - -int tls1_change_cipher_state(SSL *ssl, int which); -int tls1_setup_key_block(SSL *ssl); -int tls1_handshake_digest(SSL *ssl, uint8_t *out, size_t out_len); -int tls1_generate_master_secret(SSL *ssl, uint8_t *out, const uint8_t *premaster, - size_t premaster_len); +int tls1_change_cipher_state(SSL_HANDSHAKE *hs, int which); +int tls1_generate_master_secret(SSL_HANDSHAKE *hs, uint8_t *out, + const uint8_t *premaster, size_t premaster_len); -char ssl_early_callback_init(struct ssl_early_callback_ctx *ctx); +/* tls1_get_grouplist sets |*out_group_ids| and |*out_group_ids_len| to the + * locally-configured group preference list. */ +void tls1_get_grouplist(SSL *ssl, const uint16_t **out_group_ids, + size_t *out_group_ids_len); -/* tls1_check_curve_id returns one if |curve_id| is consistent with both our - * and the peer's curve preferences. Note: if called as the client, only our - * preferences are checked; the peer (the server) does not send preferences. */ -int tls1_check_curve_id(SSL *ssl, uint16_t curve_id); +/* tls1_check_group_id returns one if |group_id| is consistent with + * locally-configured group preferences. */ +int tls1_check_group_id(SSL *ssl, uint16_t group_id); -/* tls1_get_shared_curve sets |*out_curve_id| to the first preferred shared - * curve between client and server preferences and returns one. If none may be +/* tls1_get_shared_group sets |*out_group_id| to the first preferred shared + * group between client and server preferences and returns one. If none may be * found, it returns zero. */ -int tls1_get_shared_curve(SSL *ssl, uint16_t *out_curve_id); +int tls1_get_shared_group(SSL_HANDSHAKE *hs, uint16_t *out_group_id); /* tls1_set_curves converts the array of |ncurves| NIDs pointed to by |curves| - * into a newly allocated array of TLS curve IDs. On success, the function - * returns one and writes the array to |*out_curve_ids| and its size to - * |*out_curve_ids_len|. Otherwise, it returns zero. */ -int tls1_set_curves(uint16_t **out_curve_ids, size_t *out_curve_ids_len, + * into a newly allocated array of TLS group IDs. On success, the function + * returns one and writes the array to |*out_group_ids| and its size to + * |*out_group_ids_len|. Otherwise, it returns zero. */ +int tls1_set_curves(uint16_t **out_group_ids, size_t *out_group_ids_len, const int *curves, size_t ncurves); -/* tls1_check_ec_cert returns one if |x| is an ECC certificate with curve and - * point format compatible with the client's preferences. Otherwise it returns - * zero. */ -int tls1_check_ec_cert(SSL *ssl, X509 *x); +/* tls1_set_curves_list converts the string of curves pointed to by |curves| + * into a newly allocated array of TLS group IDs. On success, the function + * returns one and writes the array to |*out_group_ids| and its size to + * |*out_group_ids_len|. Otherwise, it returns zero. */ +int tls1_set_curves_list(uint16_t **out_group_ids, size_t *out_group_ids_len, + const char *curves); /* ssl_add_clienthello_tlsext writes ClientHello extensions to |out|. It * returns one on success and zero on failure. The |header_len| argument is the * length of the ClientHello written so far and is used to compute the padding * length. (It does not include the record header.) */ -int ssl_add_clienthello_tlsext(SSL *ssl, CBB *out, size_t header_len); +int ssl_add_clienthello_tlsext(SSL_HANDSHAKE *hs, CBB *out, size_t header_len); -int ssl_add_serverhello_tlsext(SSL *ssl, CBB *out); -int ssl_parse_clienthello_tlsext(SSL *ssl, CBS *cbs); -int ssl_parse_serverhello_tlsext(SSL *ssl, CBS *cbs); +int ssl_add_serverhello_tlsext(SSL_HANDSHAKE *hs, CBB *out); +int ssl_parse_clienthello_tlsext(SSL_HANDSHAKE *hs, + const SSL_CLIENT_HELLO *client_hello); +int ssl_parse_serverhello_tlsext(SSL_HANDSHAKE *hs, CBS *cbs); #define tlsext_tick_md EVP_sha256 @@ -1187,92 +2136,50 @@ int tls_process_ticket(SSL *ssl, SSL_SESSION **out_session, size_t ticket_len, const uint8_t *session_id, size_t session_id_len); -/* tls12_add_sigandhash assembles the SignatureAndHashAlgorithm corresponding to - * |ssl|'s private key and |md|. The two-byte value is written to |out|. It - * returns one on success and zero on failure. */ -int tls12_add_sigandhash(SSL *ssl, CBB *out, const EVP_MD *md); +/* tls1_verify_channel_id processes the current message as a Channel ID message, + * and verifies the signature. If the key is valid, it saves the Channel ID and + * returns one. Otherwise, it returns zero. */ +int tls1_verify_channel_id(SSL_HANDSHAKE *hs); -int tls12_get_sigid(int pkey_type); -const EVP_MD *tls12_get_hash(uint8_t hash_alg); +/* tls1_write_channel_id generates a Channel ID message and puts the output in + * |cbb|. |ssl->tlsext_channel_id_private| must already be set before calling. + * This function returns one on success and zero on error. */ +int tls1_write_channel_id(SSL_HANDSHAKE *hs, CBB *cbb); /* tls1_channel_id_hash computes the hash to be signed by Channel ID and writes * it to |out|, which must contain at least |EVP_MAX_MD_SIZE| bytes. It returns * one on success and zero on failure. */ -int tls1_channel_id_hash(SSL *ssl, uint8_t *out, size_t *out_len); - -int tls1_record_handshake_hashes_for_channel_id(SSL *ssl); - -/* ssl_log_rsa_client_key_exchange logs |premaster|, if logging is enabled for - * |ssl|. It returns one on success and zero on failure. The entry is identified - * by the first 8 bytes of |encrypted_premaster|. */ -int ssl_log_rsa_client_key_exchange(const SSL *ssl, - const uint8_t *encrypted_premaster, - size_t encrypted_premaster_len, - const uint8_t *premaster, - size_t premaster_len); - -/* ssl_log_master_secret logs |master|, if logging is enabled for |ssl|. It - * returns one on success and zero on failure. The entry is identified by - * |client_random|. */ -int ssl_log_master_secret(const SSL *ssl, const uint8_t *client_random, - size_t client_random_len, const uint8_t *master, - size_t master_len); +int tls1_channel_id_hash(SSL_HANDSHAKE *hs, uint8_t *out, size_t *out_len); + +int tls1_record_handshake_hashes_for_channel_id(SSL_HANDSHAKE *hs); + +/* ssl_do_channel_id_callback checks runs |ssl->ctx->channel_id_cb| if + * necessary. It returns one on success and zero on fatal error. Note that, on + * success, |ssl->tlsext_channel_id_private| may be unset, in which case the + * operation should be retried later. */ +int ssl_do_channel_id_callback(SSL *ssl); /* ssl3_can_false_start returns one if |ssl| is allowed to False Start and zero * otherwise. */ int ssl3_can_false_start(const SSL *ssl); -/* ssl3_get_enc_method returns the SSL3_ENC_METHOD corresponding to - * |version|. */ -const SSL3_ENC_METHOD *ssl3_get_enc_method(uint16_t version); - -/* ssl3_get_max_server_version returns the maximum SSL/TLS version number - * supported by |ssl| as a server, or zero if all versions are disabled. */ -uint16_t ssl3_get_max_server_version(const SSL *ssl); - -/* ssl3_get_mutual_version selects the protocol version on |ssl| for a client - * which advertises |client_version|. If no suitable version exists, it returns - * zero. */ -uint16_t ssl3_get_mutual_version(SSL *ssl, uint16_t client_version); - -/* ssl3_get_max_client_version returns the maximum protocol version configured - * for the client. It is guaranteed that the set of allowed versions at or below - * this maximum version is contiguous. If all versions are disabled, it returns - * zero. */ -uint16_t ssl3_get_max_client_version(SSL *ssl); - -/* ssl3_is_version_enabled returns one if |version| is an enabled protocol - * version for |ssl| and zero otherwise. */ -int ssl3_is_version_enabled(SSL *ssl, uint16_t version); - -/* ssl3_version_from_wire maps |wire_version| to a protocol version. For - * SSLv3/TLS, the version is returned as-is. For DTLS, the corresponding TLS - * version is used. Note that this mapping is not injective but preserves - * comparisons. - * - * TODO(davidben): To normalize some DTLS-specific code, move away from using - * the wire version except at API boundaries. */ -uint16_t ssl3_version_from_wire(const SSL *ssl, uint16_t wire_version); +/* ssl_get_version_range sets |*out_min_version| and |*out_max_version| to the + * minimum and maximum enabled protocol versions, respectively. */ +int ssl_get_version_range(const SSL *ssl, uint16_t *out_min_version, + uint16_t *out_max_version); /* ssl3_protocol_version returns |ssl|'s protocol version. It is an error to * call this function before the version is determined. */ uint16_t ssl3_protocol_version(const SSL *ssl); -uint32_t ssl_get_algorithm_prf(const SSL *ssl); -int tls1_parse_peer_sigalgs(SSL *ssl, const CBS *sigalgs); +void ssl_get_current_time(const SSL *ssl, struct timeval *out_clock); -/* tls1_choose_signing_digest returns a digest for use with |ssl|'s private key - * based on the peer's preferences the digests supported. */ -const EVP_MD *tls1_choose_signing_digest(SSL *ssl); +/* ssl_reset_error_state resets state for |SSL_get_error|. */ +void ssl_reset_error_state(SSL *ssl); -size_t tls12_get_psigalgs(SSL *ssl, const uint8_t **psigs); -/* tls12_check_peer_sigalg checks that |hash| and |signature| are consistent - * with |pkey| and |ssl|'s sent, supported signature algorithms and, if so, - * writes the relevant digest into |*out_md| and returns 1. Otherwise it - * returns 0 and writes an alert into |*out_alert|. */ -int tls12_check_peer_sigalg(SSL *ssl, const EVP_MD **out_md, int *out_alert, - uint8_t hash, uint8_t signature, EVP_PKEY *pkey); -void ssl_set_client_disabled(SSL *ssl); +#if defined(__cplusplus) +} /* extern C */ +#endif #endif /* OPENSSL_HEADER_SSL_INTERNAL_H */ diff --git a/Sources/BoringSSL/ssl/pqueue/pqueue.c b/Sources/BoringSSL/ssl/pqueue/pqueue.c deleted file mode 100644 index e68976118..000000000 --- a/Sources/BoringSSL/ssl/pqueue/pqueue.c +++ /dev/null @@ -1,197 +0,0 @@ -/* - * DTLS implementation written by Nagendra Modadugu - * (nagendra@cs.stanford.edu) for the OpenSSL project 2005. - */ -/* ==================================================================== - * Copyright (c) 1999-2005 The OpenSSL Project. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the OpenSSL Project - * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" - * - * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to - * endorse or promote products derived from this software without - * prior written permission. For written permission, please contact - * openssl-core@OpenSSL.org. - * - * 5. Products derived from this software may not be called "OpenSSL" - * nor may "OpenSSL" appear in their names without prior written - * permission of the OpenSSL Project. - * - * 6. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the OpenSSL Project - * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" - * - * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This product includes cryptographic software written by Eric Young - * (eay@cryptsoft.com). This product includes software written by Tim - * Hudson (tjh@cryptsoft.com). */ - -#include - -#include -#include - -#include - - -typedef struct _pqueue { - pitem *items; - unsigned count; -} pqueue_s; - - -pitem *pitem_new(uint8_t prio64be[8], void *data) { - pitem *item = OPENSSL_malloc(sizeof(pitem)); - if (item == NULL) { - return NULL; - } - - memcpy(item->priority, prio64be, sizeof(item->priority)); - - item->data = data; - item->next = NULL; - - return item; -} - -void pitem_free(pitem *item) { - if (item == NULL) { - return; - } - - OPENSSL_free(item); -} - -pqueue pqueue_new(void) { - pqueue_s *pq = OPENSSL_malloc(sizeof(pqueue_s)); - if (pq == NULL) { - return NULL; - } - - memset(pq, 0, sizeof(pqueue_s)); - return pq; -} - -void pqueue_free(pqueue_s *pq) { - if (pq == NULL) { - return; - } - - /* The queue must be empty. */ - assert(pq->items == NULL); - OPENSSL_free(pq); -} - -pitem *pqueue_peek(pqueue_s *pq) { return pq->items; } - -pitem *pqueue_find(pqueue_s *pq, uint8_t *prio64be) { - pitem *curr; - - for (curr = pq->items; curr; curr = curr->next) { - if (memcmp(curr->priority, prio64be, sizeof(curr->priority)) == 0) { - return curr; - } - } - - return NULL; -} - -size_t pqueue_size(pqueue_s *pq) { - pitem *item = pq->items; - size_t count = 0; - - while (item != NULL) { - count++; - item = item->next; - } - return count; -} - -piterator pqueue_iterator(pqueue_s *pq) { return pq->items; } - -pitem *pqueue_next(piterator *item) { - pitem *ret; - - if (item == NULL || *item == NULL) { - return NULL; - } - - ret = *item; - *item = (*item)->next; - - return ret; -} - -pitem *pqueue_insert(pqueue_s *pq, pitem *item) { - pitem *curr, *next; - - if (pq->items == NULL) { - pq->items = item; - return item; - } - - for (curr = NULL, next = pq->items; next != NULL; - curr = next, next = next->next) { - /* we can compare 64-bit value in big-endian encoding with memcmp. */ - int cmp = memcmp(next->priority, item->priority, sizeof(item->priority)); - if (cmp > 0) { - /* next > item */ - item->next = next; - - if (curr == NULL) { - pq->items = item; - } else { - curr->next = item; - } - - return item; - } else if (cmp == 0) { - /* duplicates not allowed */ - return NULL; - } - } - - item->next = NULL; - curr->next = item; - - return item; -} - - -pitem *pqueue_pop(pqueue_s *pq) { - pitem *item = pq->items; - - if (pq->items != NULL) { - pq->items = pq->items->next; - } - - return item; -} diff --git a/Sources/BoringSSL/ssl/s3_both.c b/Sources/BoringSSL/ssl/s3_both.c index 725c4f533..7fd09c654 100644 --- a/Sources/BoringSSL/ssl/s3_both.c +++ b/Sources/BoringSSL/ssl/s3_both.c @@ -114,362 +114,661 @@ #include #include -#include #include #include +#include #include #include #include #include -#include +#include #include #include #include +#include "../crypto/internal.h" #include "internal.h" -/* ssl3_do_write sends |ssl->init_buf| in records of type 'type' - * (SSL3_RT_HANDSHAKE or SSL3_RT_CHANGE_CIPHER_SPEC). It returns -1 on error, 1 - * on success or zero if the transmission is still incomplete. */ -int ssl3_do_write(SSL *ssl, int type) { - int n; +SSL_HANDSHAKE *ssl_handshake_new(SSL *ssl) { + SSL_HANDSHAKE *hs = OPENSSL_malloc(sizeof(SSL_HANDSHAKE)); + if (hs == NULL) { + OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + return NULL; + } + OPENSSL_memset(hs, 0, sizeof(SSL_HANDSHAKE)); + hs->ssl = ssl; + hs->wait = ssl_hs_ok; + hs->state = SSL_ST_INIT; + if (!SSL_TRANSCRIPT_init(&hs->transcript)) { + ssl_handshake_free(hs); + return NULL; + } + return hs; +} - n = ssl3_write_bytes(ssl, type, &ssl->init_buf->data[ssl->init_off], - ssl->init_num); - if (n < 0) { - return -1; +void ssl_handshake_free(SSL_HANDSHAKE *hs) { + if (hs == NULL) { + return; } - if (n == ssl->init_num) { - if (ssl->msg_callback) { - ssl->msg_callback(1, ssl->version, type, ssl->init_buf->data, - (size_t)(ssl->init_off + ssl->init_num), ssl, - ssl->msg_callback_arg); - } - return 1; + OPENSSL_cleanse(hs->secret, sizeof(hs->secret)); + OPENSSL_cleanse(hs->client_handshake_secret, + sizeof(hs->client_handshake_secret)); + OPENSSL_cleanse(hs->server_handshake_secret, + sizeof(hs->server_handshake_secret)); + OPENSSL_cleanse(hs->client_traffic_secret_0, + sizeof(hs->client_traffic_secret_0)); + OPENSSL_cleanse(hs->server_traffic_secret_0, + sizeof(hs->server_traffic_secret_0)); + SSL_ECDH_CTX_cleanup(&hs->ecdh_ctx); + SSL_TRANSCRIPT_cleanup(&hs->transcript); + OPENSSL_free(hs->cookie); + OPENSSL_free(hs->key_share_bytes); + OPENSSL_free(hs->public_key); + SSL_SESSION_free(hs->new_session); + OPENSSL_free(hs->peer_sigalgs); + OPENSSL_free(hs->peer_supported_group_list); + OPENSSL_free(hs->peer_key); + OPENSSL_free(hs->server_params); + OPENSSL_free(hs->peer_psk_identity_hint); + sk_X509_NAME_pop_free(hs->ca_names, X509_NAME_free); + OPENSSL_free(hs->certificate_types); + + if (hs->key_block != NULL) { + OPENSSL_cleanse(hs->key_block, hs->key_block_len); + OPENSSL_free(hs->key_block); } - ssl->init_off += n; - ssl->init_num -= n; - return 0; + OPENSSL_free(hs->hostname); + EVP_PKEY_free(hs->peer_pubkey); + OPENSSL_free(hs); } -int ssl3_send_finished(SSL *ssl, int a, int b) { - uint8_t *p; - int n; +int ssl_check_message_type(SSL *ssl, int type) { + if (ssl->s3->tmp.message_type != type) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE); + OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_MESSAGE); + ERR_add_error_dataf("got type %d, wanted type %d", + ssl->s3->tmp.message_type, type); + return 0; + } - if (ssl->state == a) { - p = ssl_handshake_start(ssl); + return 1; +} - n = ssl->s3->enc_method->final_finish_mac(ssl, ssl->server, - ssl->s3->tmp.finish_md); - if (n == 0) { - return 0; - } - ssl->s3->tmp.finish_md_len = n; - memcpy(p, ssl->s3->tmp.finish_md, n); +static int add_record_to_flight(SSL *ssl, uint8_t type, const uint8_t *in, + size_t in_len) { + /* We'll never add a flight while in the process of writing it out. */ + assert(ssl->s3->pending_flight_offset == 0); - /* Log the master secret, if logging is enabled. */ - if (!ssl_log_master_secret(ssl, ssl->s3->client_random, SSL3_RANDOM_SIZE, - ssl->session->master_key, - ssl->session->master_key_length)) { + if (ssl->s3->pending_flight == NULL) { + ssl->s3->pending_flight = BUF_MEM_new(); + if (ssl->s3->pending_flight == NULL) { return 0; } + } - /* Copy the finished so we can use it for renegotiation checks */ - if (ssl->server) { - assert(n <= EVP_MAX_MD_SIZE); - memcpy(ssl->s3->previous_server_finished, ssl->s3->tmp.finish_md, n); - ssl->s3->previous_server_finished_len = n; - } else { - assert(n <= EVP_MAX_MD_SIZE); - memcpy(ssl->s3->previous_client_finished, ssl->s3->tmp.finish_md, n); - ssl->s3->previous_client_finished_len = n; + size_t max_out = in_len + SSL_max_seal_overhead(ssl); + size_t new_cap = ssl->s3->pending_flight->length + max_out; + if (max_out < in_len || new_cap < max_out) { + OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW); + return 0; + } + + size_t len; + if (!BUF_MEM_reserve(ssl->s3->pending_flight, new_cap) || + !tls_seal_record(ssl, (uint8_t *)ssl->s3->pending_flight->data + + ssl->s3->pending_flight->length, + &len, max_out, type, in, in_len)) { + return 0; + } + + ssl->s3->pending_flight->length += len; + return 1; +} + +int ssl3_init_message(SSL *ssl, CBB *cbb, CBB *body, uint8_t type) { + /* Pick a modest size hint to save most of the |realloc| calls. */ + if (!CBB_init(cbb, 64) || + !CBB_add_u8(cbb, type) || + !CBB_add_u24_length_prefixed(cbb, body)) { + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + CBB_cleanup(cbb); + return 0; + } + + return 1; +} + +int ssl3_finish_message(SSL *ssl, CBB *cbb, uint8_t **out_msg, + size_t *out_len) { + if (!CBB_finish(cbb, out_msg, out_len)) { + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + return 0; + } + + return 1; +} + +int ssl3_add_message(SSL *ssl, uint8_t *msg, size_t len) { + /* Add the message to the current flight, splitting into several records if + * needed. */ + int ret = 0; + size_t added = 0; + do { + size_t todo = len - added; + if (todo > ssl->max_send_fragment) { + todo = ssl->max_send_fragment; } - if (!ssl_set_handshake_header(ssl, SSL3_MT_FINISHED, n)) { - return 0; + if (!add_record_to_flight(ssl, SSL3_RT_HANDSHAKE, msg + added, todo)) { + goto err; } - ssl->state = b; + added += todo; + } while (added < len); + + ssl_do_msg_callback(ssl, 1 /* write */, SSL3_RT_HANDSHAKE, msg, len); + /* TODO(svaldez): Move this up a layer to fix abstraction for SSL_TRANSCRIPT + * on hs. */ + if (ssl->s3->hs != NULL && + !SSL_TRANSCRIPT_update(&ssl->s3->hs->transcript, msg, len)) { + goto err; } + ret = 1; - /* SSL3_ST_SEND_xxxxxx_HELLO_B */ - return ssl_do_write(ssl); +err: + OPENSSL_free(msg); + return ret; } -/* ssl3_take_mac calculates the Finished MAC for the handshakes messages seen - * so far. */ -static void ssl3_take_mac(SSL *ssl) { - /* If no new cipher setup then return immediately: other functions will set - * the appropriate error. */ - if (ssl->s3->tmp.new_cipher == NULL) { - return; +int ssl3_add_change_cipher_spec(SSL *ssl) { + static const uint8_t kChangeCipherSpec[1] = {SSL3_MT_CCS}; + + if (!add_record_to_flight(ssl, SSL3_RT_CHANGE_CIPHER_SPEC, kChangeCipherSpec, + sizeof(kChangeCipherSpec))) { + return 0; } - ssl->s3->tmp.peer_finish_md_len = ssl->s3->enc_method->final_finish_mac( - ssl, !ssl->server, ssl->s3->tmp.peer_finish_md); + ssl_do_msg_callback(ssl, 1 /* write */, SSL3_RT_CHANGE_CIPHER_SPEC, + kChangeCipherSpec, sizeof(kChangeCipherSpec)); + return 1; } -int ssl3_get_finished(SSL *ssl, int a, int b) { - int al, finished_len, ok; - long message_len; - uint8_t *p; +int ssl3_add_alert(SSL *ssl, uint8_t level, uint8_t desc) { + uint8_t alert[2] = {level, desc}; + if (!add_record_to_flight(ssl, SSL3_RT_ALERT, alert, sizeof(alert))) { + return 0; + } - message_len = ssl->method->ssl_get_message( - ssl, a, b, SSL3_MT_FINISHED, EVP_MAX_MD_SIZE, ssl_dont_hash_message, &ok); + ssl_do_msg_callback(ssl, 1 /* write */, SSL3_RT_ALERT, alert, sizeof(alert)); + ssl_do_info_callback(ssl, SSL_CB_WRITE_ALERT, ((int)level << 8) | desc); + return 1; +} - if (!ok) { - return message_len; +int ssl_add_message_cbb(SSL *ssl, CBB *cbb) { + uint8_t *msg; + size_t len; + if (!ssl->method->finish_message(ssl, cbb, &msg, &len) || + !ssl->method->add_message(ssl, msg, len)) { + return 0; } - /* Snapshot the finished hash before incorporating the new message. */ - ssl3_take_mac(ssl); - if (!ssl3_hash_current_message(ssl)) { - goto err; + return 1; +} + +int ssl3_flush_flight(SSL *ssl) { + if (ssl->s3->pending_flight == NULL) { + return 1; } - p = ssl->init_msg; - finished_len = ssl->s3->tmp.peer_finish_md_len; + if (ssl->s3->pending_flight->length > 0xffffffff || + ssl->s3->pending_flight->length > INT_MAX) { + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + return -1; + } - if (finished_len != message_len) { - al = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_DIGEST_LENGTH); - goto f_err; + /* The handshake flight buffer is mutually exclusive with application data. + * + * TODO(davidben): This will not be true when closure alerts use this. */ + if (ssl_write_buffer_is_pending(ssl)) { + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + return -1; } - if (CRYPTO_memcmp(p, ssl->s3->tmp.peer_finish_md, finished_len) != 0) { - al = SSL_AD_DECRYPT_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_DIGEST_CHECK_FAILED); - goto f_err; + /* Write the pending flight. */ + while (ssl->s3->pending_flight_offset < ssl->s3->pending_flight->length) { + int ret = BIO_write( + ssl->wbio, + ssl->s3->pending_flight->data + ssl->s3->pending_flight_offset, + ssl->s3->pending_flight->length - ssl->s3->pending_flight_offset); + if (ret <= 0) { + ssl->rwstate = SSL_WRITING; + return ret; + } + + ssl->s3->pending_flight_offset += ret; } - /* Copy the finished so we can use it for renegotiation checks */ - if (ssl->server) { - assert(finished_len <= EVP_MAX_MD_SIZE); - memcpy(ssl->s3->previous_client_finished, ssl->s3->tmp.peer_finish_md, - finished_len); - ssl->s3->previous_client_finished_len = finished_len; - } else { - assert(finished_len <= EVP_MAX_MD_SIZE); - memcpy(ssl->s3->previous_server_finished, ssl->s3->tmp.peer_finish_md, - finished_len); - ssl->s3->previous_server_finished_len = finished_len; + if (BIO_flush(ssl->wbio) <= 0) { + ssl->rwstate = SSL_WRITING; + return -1; } + BUF_MEM_free(ssl->s3->pending_flight); + ssl->s3->pending_flight = NULL; + ssl->s3->pending_flight_offset = 0; return 1; +} -f_err: - ssl3_send_alert(ssl, SSL3_AL_FATAL, al); -err: - return 0; +int ssl3_send_finished(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + const SSL_SESSION *session = SSL_get_session(ssl); + + uint8_t finished[EVP_MAX_MD_SIZE]; + size_t finished_len; + if (!SSL_TRANSCRIPT_finish_mac(&hs->transcript, finished, &finished_len, + session, ssl->server, + ssl3_protocol_version(ssl))) { + return 0; + } + + /* Log the master secret, if logging is enabled. */ + if (!ssl_log_secret(ssl, "CLIENT_RANDOM", + session->master_key, + session->master_key_length)) { + return 0; + } + + /* Copy the Finished so we can use it for renegotiation checks. */ + if (ssl->version != SSL3_VERSION) { + if (finished_len > sizeof(ssl->s3->previous_client_finished) || + finished_len > sizeof(ssl->s3->previous_server_finished)) { + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + return -1; + } + + if (ssl->server) { + OPENSSL_memcpy(ssl->s3->previous_server_finished, finished, finished_len); + ssl->s3->previous_server_finished_len = finished_len; + } else { + OPENSSL_memcpy(ssl->s3->previous_client_finished, finished, finished_len); + ssl->s3->previous_client_finished_len = finished_len; + } + } + + CBB cbb, body; + if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_FINISHED) || + !CBB_add_bytes(&body, finished, finished_len) || + !ssl_add_message_cbb(ssl, &cbb)) { + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + CBB_cleanup(&cbb); + return -1; + } + + return 1; } -int ssl3_send_change_cipher_spec(SSL *ssl, int a, int b) { - if (ssl->state == a) { - *((uint8_t *)ssl->init_buf->data) = SSL3_MT_CCS; - ssl->init_num = 1; - ssl->init_off = 0; +int ssl3_get_finished(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + int ret = ssl->method->ssl_get_message(ssl); + if (ret <= 0) { + return ret; + } - ssl->state = b; + if (!ssl_check_message_type(ssl, SSL3_MT_FINISHED)) { + return -1; + } + + /* Snapshot the finished hash before incorporating the new message. */ + uint8_t finished[EVP_MAX_MD_SIZE]; + size_t finished_len; + if (!SSL_TRANSCRIPT_finish_mac(&hs->transcript, finished, &finished_len, + SSL_get_session(ssl), !ssl->server, + ssl3_protocol_version(ssl)) || + !ssl_hash_current_message(hs)) { + return -1; } - /* SSL3_ST_CW_CHANGE_B */ - return ssl3_do_write(ssl, SSL3_RT_CHANGE_CIPHER_SPEC); + int finished_ok = ssl->init_num == finished_len && + CRYPTO_memcmp(ssl->init_msg, finished, finished_len) == 0; +#if defined(BORINGSSL_UNSAFE_FUZZER_MODE) + finished_ok = 1; +#endif + if (!finished_ok) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECRYPT_ERROR); + OPENSSL_PUT_ERROR(SSL, SSL_R_DIGEST_CHECK_FAILED); + return -1; + } + + /* Copy the Finished so we can use it for renegotiation checks. */ + if (ssl->version != SSL3_VERSION) { + if (finished_len > sizeof(ssl->s3->previous_client_finished) || + finished_len > sizeof(ssl->s3->previous_server_finished)) { + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + return -1; + } + + if (ssl->server) { + OPENSSL_memcpy(ssl->s3->previous_client_finished, finished, finished_len); + ssl->s3->previous_client_finished_len = finished_len; + } else { + OPENSSL_memcpy(ssl->s3->previous_server_finished, finished, finished_len); + ssl->s3->previous_server_finished_len = finished_len; + } + } + + return 1; } int ssl3_output_cert_chain(SSL *ssl) { - uint8_t *p; - unsigned long l = 3 + SSL_HM_HEADER_LENGTH(ssl); - - if (!ssl_add_cert_chain(ssl, &l)) { + CBB cbb, body; + if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_CERTIFICATE) || + !ssl_add_cert_chain(ssl, &body) || + !ssl_add_message_cbb(ssl, &cbb)) { + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + CBB_cleanup(&cbb); return 0; } - l -= 3 + SSL_HM_HEADER_LENGTH(ssl); - p = ssl_handshake_start(ssl); - l2n3(l, p); - l += 3; - return ssl_set_handshake_header(ssl, SSL3_MT_CERTIFICATE, l); + return 1; } -/* Obtain handshake message of message type |msg_type| (any if |msg_type| == -1), - * maximum acceptable body length |max|. The first four bytes (msg_type and - * length) are read in state |header_state|, the body is read in state - * |body_state|. */ -long ssl3_get_message(SSL *ssl, int header_state, int body_state, int msg_type, - long max, enum ssl_hash_message_t hash_message, int *ok) { - uint8_t *p; - unsigned long l; - long n; - int al; +size_t ssl_max_handshake_message_len(const SSL *ssl) { + /* kMaxMessageLen is the default maximum message size for handshakes which do + * not accept peer certificate chains. */ + static const size_t kMaxMessageLen = 16384; - if (ssl->s3->tmp.reuse_message) { - /* A ssl_dont_hash_message call cannot be combined with reuse_message; the - * ssl_dont_hash_message would have to have been applied to the previous - * call. */ - assert(hash_message == ssl_hash_message); - ssl->s3->tmp.reuse_message = 0; - if (msg_type >= 0 && ssl->s3->tmp.message_type != msg_type) { - al = SSL_AD_UNEXPECTED_MESSAGE; - OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_MESSAGE); - goto f_err; + if (SSL_in_init(ssl)) { + if ((!ssl->server || (ssl->verify_mode & SSL_VERIFY_PEER)) && + kMaxMessageLen < ssl->max_cert_list) { + return ssl->max_cert_list; } - *ok = 1; - ssl->state = body_state; - ssl->init_msg = (uint8_t *)ssl->init_buf->data + 4; - ssl->init_num = (int)ssl->s3->tmp.message_size; - return ssl->init_num; - } - - p = (uint8_t *)ssl->init_buf->data; - - if (ssl->state == header_state) { - assert(ssl->init_num < 4); - - for (;;) { - while (ssl->init_num < 4) { - int bytes_read = ssl3_read_bytes( - ssl, SSL3_RT_HANDSHAKE, &p[ssl->init_num], 4 - ssl->init_num, 0); - if (bytes_read <= 0) { - *ok = 0; - return bytes_read; - } - ssl->init_num += bytes_read; - } + return kMaxMessageLen; + } - static const uint8_t kHelloRequest[4] = {SSL3_MT_HELLO_REQUEST, 0, 0, 0}; - if (ssl->server || memcmp(p, kHelloRequest, sizeof(kHelloRequest)) != 0) { - break; - } + if (ssl3_protocol_version(ssl) < TLS1_3_VERSION) { + /* In TLS 1.2 and below, the largest acceptable post-handshake message is + * a HelloRequest. */ + return 0; + } - /* The server may always send 'Hello Request' messages -- we are doing - * a handshake anyway now, so ignore them if their format is correct. - * Does not count for 'Finished' MAC. */ - ssl->init_num = 0; + if (ssl->server) { + /* The largest acceptable post-handshake message for a server is a + * KeyUpdate. We will never initiate post-handshake auth. */ + return 1; + } - if (ssl->msg_callback) { - ssl->msg_callback(0, ssl->version, SSL3_RT_HANDSHAKE, p, 4, ssl, - ssl->msg_callback_arg); - } + /* Clients must accept NewSessionTicket and CertificateRequest, so allow the + * default size. */ + return kMaxMessageLen; +} + +static int extend_handshake_buffer(SSL *ssl, size_t length) { + if (!BUF_MEM_reserve(ssl->init_buf, length)) { + return -1; + } + while (ssl->init_buf->length < length) { + int ret = ssl3_read_handshake_bytes( + ssl, (uint8_t *)ssl->init_buf->data + ssl->init_buf->length, + length - ssl->init_buf->length); + if (ret <= 0) { + return ret; } + ssl->init_buf->length += (size_t)ret; + } + return 1; +} + +static int read_v2_client_hello(SSL *ssl) { + /* Read the first 5 bytes, the size of the TLS record header. This is + * sufficient to detect a V2ClientHello and ensures that we never read beyond + * the first record. */ + int ret = ssl_read_buffer_extend_to(ssl, SSL3_RT_HEADER_LENGTH); + if (ret <= 0) { + return ret; + } + const uint8_t *p = ssl_read_buffer(ssl); + + /* Some dedicated error codes for protocol mixups should the application wish + * to interpret them differently. (These do not overlap with ClientHello or + * V2ClientHello.) */ + if (strncmp("GET ", (const char *)p, 4) == 0 || + strncmp("POST ", (const char *)p, 5) == 0 || + strncmp("HEAD ", (const char *)p, 5) == 0 || + strncmp("PUT ", (const char *)p, 4) == 0) { + OPENSSL_PUT_ERROR(SSL, SSL_R_HTTP_REQUEST); + return -1; + } + if (strncmp("CONNE", (const char *)p, 5) == 0) { + OPENSSL_PUT_ERROR(SSL, SSL_R_HTTPS_PROXY_REQUEST); + return -1; + } - /* ssl->init_num == 4 */ + if ((p[0] & 0x80) == 0 || p[2] != SSL2_MT_CLIENT_HELLO || + p[3] != SSL3_VERSION_MAJOR) { + /* Not a V2ClientHello. */ + return 1; + } - if (msg_type >= 0 && *p != msg_type) { - al = SSL_AD_UNEXPECTED_MESSAGE; - OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_MESSAGE); - goto f_err; - } - ssl->s3->tmp.message_type = *(p++); + /* Determine the length of the V2ClientHello. */ + size_t msg_length = ((p[0] & 0x7f) << 8) | p[1]; + if (msg_length > (1024 * 4)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_RECORD_TOO_LARGE); + return -1; + } + if (msg_length < SSL3_RT_HEADER_LENGTH - 2) { + /* Reject lengths that are too short early. We have already read + * |SSL3_RT_HEADER_LENGTH| bytes, so we should not attempt to process an + * (invalid) V2ClientHello which would be shorter than that. */ + OPENSSL_PUT_ERROR(SSL, SSL_R_RECORD_LENGTH_MISMATCH); + return -1; + } - n2l3(p, l); - if (l > (unsigned long)max) { - al = SSL_AD_ILLEGAL_PARAMETER; - OPENSSL_PUT_ERROR(SSL, SSL_R_EXCESSIVE_MESSAGE_SIZE); - goto f_err; - } + /* Read the remainder of the V2ClientHello. */ + ret = ssl_read_buffer_extend_to(ssl, 2 + msg_length); + if (ret <= 0) { + return ret; + } - if (l && !BUF_MEM_grow_clean(ssl->init_buf, l + 4)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB); - goto err; - } - ssl->s3->tmp.message_size = l; - ssl->state = body_state; + CBS v2_client_hello; + CBS_init(&v2_client_hello, ssl_read_buffer(ssl) + 2, msg_length); - ssl->init_msg = (uint8_t *)ssl->init_buf->data + 4; - ssl->init_num = 0; + /* The V2ClientHello without the length is incorporated into the handshake + * hash. This is only ever called at the start of the handshake, so hs is + * guaranteed to be non-NULL. */ + if (!SSL_TRANSCRIPT_update(&ssl->s3->hs->transcript, + CBS_data(&v2_client_hello), + CBS_len(&v2_client_hello))) { + return -1; } - /* next state (body_state) */ - p = ssl->init_msg; - n = ssl->s3->tmp.message_size - ssl->init_num; - while (n > 0) { - int bytes_read = - ssl3_read_bytes(ssl, SSL3_RT_HANDSHAKE, &p[ssl->init_num], n, 0); - if (bytes_read <= 0) { - ssl->rwstate = SSL_READING; - *ok = 0; - return bytes_read; - } - ssl->init_num += bytes_read; - n -= bytes_read; + ssl_do_msg_callback(ssl, 0 /* read */, 0 /* V2ClientHello */, + CBS_data(&v2_client_hello), CBS_len(&v2_client_hello)); + + uint8_t msg_type; + uint16_t version, cipher_spec_length, session_id_length, challenge_length; + CBS cipher_specs, session_id, challenge; + if (!CBS_get_u8(&v2_client_hello, &msg_type) || + !CBS_get_u16(&v2_client_hello, &version) || + !CBS_get_u16(&v2_client_hello, &cipher_spec_length) || + !CBS_get_u16(&v2_client_hello, &session_id_length) || + !CBS_get_u16(&v2_client_hello, &challenge_length) || + !CBS_get_bytes(&v2_client_hello, &cipher_specs, cipher_spec_length) || + !CBS_get_bytes(&v2_client_hello, &session_id, session_id_length) || + !CBS_get_bytes(&v2_client_hello, &challenge, challenge_length) || + CBS_len(&v2_client_hello) != 0) { + OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + return -1; } - /* Feed this message into MAC computation. */ - if (hash_message == ssl_hash_message && !ssl3_hash_current_message(ssl)) { - goto err; + /* msg_type has already been checked. */ + assert(msg_type == SSL2_MT_CLIENT_HELLO); + + /* The client_random is the V2ClientHello challenge. Truncate or + * left-pad with zeros as needed. */ + size_t rand_len = CBS_len(&challenge); + if (rand_len > SSL3_RANDOM_SIZE) { + rand_len = SSL3_RANDOM_SIZE; } - if (ssl->msg_callback) { - ssl->msg_callback(0, ssl->version, SSL3_RT_HANDSHAKE, ssl->init_buf->data, - (size_t)ssl->init_num + 4, ssl, ssl->msg_callback_arg); + uint8_t random[SSL3_RANDOM_SIZE]; + OPENSSL_memset(random, 0, SSL3_RANDOM_SIZE); + OPENSSL_memcpy(random + (SSL3_RANDOM_SIZE - rand_len), CBS_data(&challenge), + rand_len); + + /* Write out an equivalent SSLv3 ClientHello. */ + size_t max_v3_client_hello = SSL3_HM_HEADER_LENGTH + 2 /* version */ + + SSL3_RANDOM_SIZE + 1 /* session ID length */ + + 2 /* cipher list length */ + + CBS_len(&cipher_specs) / 3 * 2 + + 1 /* compression length */ + 1 /* compression */; + CBB client_hello, hello_body, cipher_suites; + CBB_zero(&client_hello); + if (!BUF_MEM_reserve(ssl->init_buf, max_v3_client_hello) || + !CBB_init_fixed(&client_hello, (uint8_t *)ssl->init_buf->data, + ssl->init_buf->max) || + !CBB_add_u8(&client_hello, SSL3_MT_CLIENT_HELLO) || + !CBB_add_u24_length_prefixed(&client_hello, &hello_body) || + !CBB_add_u16(&hello_body, version) || + !CBB_add_bytes(&hello_body, random, SSL3_RANDOM_SIZE) || + /* No session id. */ + !CBB_add_u8(&hello_body, 0) || + !CBB_add_u16_length_prefixed(&hello_body, &cipher_suites)) { + CBB_cleanup(&client_hello); + OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + return -1; } - *ok = 1; - return ssl->init_num; -f_err: - ssl3_send_alert(ssl, SSL3_AL_FATAL, al); + /* Copy the cipher suites. */ + while (CBS_len(&cipher_specs) > 0) { + uint32_t cipher_spec; + if (!CBS_get_u24(&cipher_specs, &cipher_spec)) { + CBB_cleanup(&client_hello); + OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + return -1; + } -err: - *ok = 0; - return -1; -} + /* Skip SSLv2 ciphers. */ + if ((cipher_spec & 0xff0000) != 0) { + continue; + } + if (!CBB_add_u16(&cipher_suites, cipher_spec)) { + CBB_cleanup(&client_hello); + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + return -1; + } + } + + /* Add the null compression scheme and finish. */ + if (!CBB_add_u8(&hello_body, 1) || !CBB_add_u8(&hello_body, 0) || + !CBB_finish(&client_hello, NULL, &ssl->init_buf->length)) { + CBB_cleanup(&client_hello); + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + return -1; + } -int ssl3_hash_current_message(SSL *ssl) { - /* The handshake header (different size between DTLS and TLS) is included in - * the hash. */ - size_t header_len = ssl->init_msg - (uint8_t *)ssl->init_buf->data; - return ssl3_update_handshake_hash(ssl, (uint8_t *)ssl->init_buf->data, - ssl->init_num + header_len); + /* Consume and discard the V2ClientHello. */ + ssl_read_buffer_consume(ssl, 2 + msg_length); + ssl_read_buffer_discard(ssl); + + ssl->s3->is_v2_hello = 1; + /* This is the first message, so hs must be non-NULL. */ + ssl->s3->hs->v2_clienthello = 1; + return 1; } -/* ssl3_cert_verify_hash is documented as needing EVP_MAX_MD_SIZE because that - * is sufficient pre-TLS1.2 as well. */ -OPENSSL_COMPILE_ASSERT(EVP_MAX_MD_SIZE > MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH, - combined_tls_hash_fits_in_max); - -int ssl3_cert_verify_hash(SSL *ssl, uint8_t *out, size_t *out_len, - const EVP_MD **out_md, int pkey_type) { - /* For TLS v1.2 send signature algorithm and signature using - * agreed digest and cached handshake records. Otherwise, use - * SHA1 or MD5 + SHA1 depending on key type. */ - if (ssl3_protocol_version(ssl) >= TLS1_2_VERSION) { - EVP_MD_CTX mctx; - unsigned len; - - EVP_MD_CTX_init(&mctx); - if (!EVP_DigestInit_ex(&mctx, *out_md, NULL) || - !EVP_DigestUpdate(&mctx, ssl->s3->handshake_buffer->data, - ssl->s3->handshake_buffer->length) || - !EVP_DigestFinal(&mctx, out, &len)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_EVP_LIB); - EVP_MD_CTX_cleanup(&mctx); - return 0; - } - *out_len = len; - } else if (pkey_type == EVP_PKEY_RSA) { - if (ssl->s3->enc_method->cert_verify_mac(ssl, NID_md5, out) == 0 || - ssl->s3->enc_method->cert_verify_mac(ssl, NID_sha1, - out + MD5_DIGEST_LENGTH) == 0) { - return 0; +int ssl3_get_message(SSL *ssl) { + /* Re-create the handshake buffer if needed. */ + if (ssl->init_buf == NULL) { + ssl->init_buf = BUF_MEM_new(); + if (ssl->init_buf == NULL) { + return -1; } - *out_len = MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH; - *out_md = EVP_md5_sha1(); - } else if (pkey_type == EVP_PKEY_EC) { - if (ssl->s3->enc_method->cert_verify_mac(ssl, NID_sha1, out) == 0) { - return 0; + } + + if (ssl->server && !ssl->s3->v2_hello_done) { + /* Bypass the record layer for the first message to handle V2ClientHello. */ + int ret = read_v2_client_hello(ssl); + if (ret <= 0) { + return ret; } - *out_len = SHA_DIGEST_LENGTH; - *out_md = EVP_sha1(); + ssl->s3->v2_hello_done = 1; + } + + if (ssl->s3->tmp.reuse_message) { + /* There must be a current message. */ + assert(ssl->init_msg != NULL); + ssl->s3->tmp.reuse_message = 0; } else { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - return 0; + ssl3_release_current_message(ssl, 0 /* don't free buffer */); + } + + /* Read the message header, if we haven't yet. */ + int ret = extend_handshake_buffer(ssl, SSL3_HM_HEADER_LENGTH); + if (ret <= 0) { + return ret; + } + + /* Parse out the length. Cap it so the peer cannot force us to buffer up to + * 2^24 bytes. */ + const uint8_t *p = (uint8_t *)ssl->init_buf->data; + size_t msg_len = (((uint32_t)p[1]) << 16) | (((uint32_t)p[2]) << 8) | p[3]; + if (msg_len > ssl_max_handshake_message_len(ssl)) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER); + OPENSSL_PUT_ERROR(SSL, SSL_R_EXCESSIVE_MESSAGE_SIZE); + return -1; } + /* Read the message body, if we haven't yet. */ + ret = extend_handshake_buffer(ssl, SSL3_HM_HEADER_LENGTH + msg_len); + if (ret <= 0) { + return ret; + } + + /* We have now received a complete message. */ + ssl_do_msg_callback(ssl, 0 /* read */, SSL3_RT_HANDSHAKE, ssl->init_buf->data, + ssl->init_buf->length); + + ssl->s3->tmp.message_type = ((const uint8_t *)ssl->init_buf->data)[0]; + ssl->init_msg = (uint8_t*)ssl->init_buf->data + SSL3_HM_HEADER_LENGTH; + ssl->init_num = ssl->init_buf->length - SSL3_HM_HEADER_LENGTH; return 1; } +void ssl3_get_current_message(const SSL *ssl, CBS *out) { + CBS_init(out, (uint8_t *)ssl->init_buf->data, ssl->init_buf->length); +} + +int ssl_hash_current_message(SSL_HANDSHAKE *hs) { + /* V2ClientHellos are hashed implicitly. */ + if (hs->ssl->s3->is_v2_hello) { + return 1; + } + + CBS cbs; + hs->ssl->method->get_current_message(hs->ssl, &cbs); + return SSL_TRANSCRIPT_update(&hs->transcript, CBS_data(&cbs), CBS_len(&cbs)); +} + +void ssl3_release_current_message(SSL *ssl, int free_buffer) { + if (ssl->init_msg != NULL) { + /* |init_buf| never contains data beyond the current message. */ + assert(SSL3_HM_HEADER_LENGTH + ssl->init_num == ssl->init_buf->length); + + /* Clear the current message. */ + ssl->init_msg = NULL; + ssl->init_num = 0; + ssl->init_buf->length = 0; + ssl->s3->is_v2_hello = 0; + } + + if (free_buffer) { + BUF_MEM_free(ssl->init_buf); + ssl->init_buf = NULL; + } +} + int ssl_verify_alarm_type(long type) { int al; @@ -491,6 +790,9 @@ int ssl_verify_alarm_type(long type) { case X509_V_ERR_CRL_NOT_YET_VALID: case X509_V_ERR_CERT_UNTRUSTED: case X509_V_ERR_CERT_REJECTED: + case X509_V_ERR_HOSTNAME_MISMATCH: + case X509_V_ERR_EMAIL_MISMATCH: + case X509_V_ERR_IP_ADDRESS_MISMATCH: al = SSL_AD_BAD_CERTIFICATE; break; @@ -508,7 +810,10 @@ int ssl_verify_alarm_type(long type) { al = SSL_AD_CERTIFICATE_REVOKED; break; + case X509_V_ERR_UNSPECIFIED: case X509_V_ERR_OUT_OF_MEM: + case X509_V_ERR_INVALID_CALL: + case X509_V_ERR_STORE_LOOKUP: al = SSL_AD_INTERNAL_ERROR; break; @@ -538,20 +843,53 @@ int ssl_verify_alarm_type(long type) { return al; } -int ssl_fill_hello_random(uint8_t *out, size_t len, int is_server) { - if (is_server) { - const uint32_t current_time = time(NULL); - uint8_t *p = out; +int ssl_parse_extensions(const CBS *cbs, uint8_t *out_alert, + const SSL_EXTENSION_TYPE *ext_types, + size_t num_ext_types, int ignore_unknown) { + /* Reset everything. */ + for (size_t i = 0; i < num_ext_types; i++) { + *ext_types[i].out_present = 0; + CBS_init(ext_types[i].out_data, NULL, 0); + } - if (len < 4) { + CBS copy = *cbs; + while (CBS_len(©) != 0) { + uint16_t type; + CBS data; + if (!CBS_get_u16(©, &type) || + !CBS_get_u16_length_prefixed(©, &data)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_PARSE_TLSEXT); + *out_alert = SSL_AD_DECODE_ERROR; return 0; } - p[0] = current_time >> 24; - p[1] = current_time >> 16; - p[2] = current_time >> 8; - p[3] = current_time; - return RAND_bytes(p + 4, len - 4); - } else { - return RAND_bytes(out, len); + + const SSL_EXTENSION_TYPE *ext_type = NULL; + for (size_t i = 0; i < num_ext_types; i++) { + if (type == ext_types[i].type) { + ext_type = &ext_types[i]; + break; + } + } + + if (ext_type == NULL) { + if (ignore_unknown) { + continue; + } + OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION); + *out_alert = SSL_AD_UNSUPPORTED_EXTENSION; + return 0; + } + + /* Duplicate ext_types are forbidden. */ + if (*ext_type->out_present) { + OPENSSL_PUT_ERROR(SSL, SSL_R_DUPLICATE_EXTENSION); + *out_alert = SSL_AD_ILLEGAL_PARAMETER; + return 0; + } + + *ext_type->out_present = 1; + *ext_type->out_data = data; } + + return 1; } diff --git a/Sources/BoringSSL/ssl/s3_clnt.c b/Sources/BoringSSL/ssl/s3_clnt.c deleted file mode 100644 index 09e527a05..000000000 --- a/Sources/BoringSSL/ssl/s3_clnt.c +++ /dev/null @@ -1,2090 +0,0 @@ -/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) - * All rights reserved. - * - * This package is an SSL implementation written - * by Eric Young (eay@cryptsoft.com). - * The implementation was written so as to conform with Netscapes SSL. - * - * This library is free for commercial and non-commercial use as long as - * the following conditions are aheared to. The following conditions - * apply to all code found in this distribution, be it the RC4, RSA, - * lhash, DES, etc., code; not just the SSL code. The SSL documentation - * included with this distribution is covered by the same copyright terms - * except that the holder is Tim Hudson (tjh@cryptsoft.com). - * - * Copyright remains Eric Young's, and as such any Copyright notices in - * the code are not to be removed. - * If this package is used in a product, Eric Young should be given attribution - * as the author of the parts of the library used. - * This can be in the form of a textual message at program startup or - * in documentation (online or textual) provided with the package. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * "This product includes cryptographic software written by - * Eric Young (eay@cryptsoft.com)" - * The word 'cryptographic' can be left out if the rouines from the library - * being used are not cryptographic related :-). - * 4. If you include any Windows specific code (or a derivative thereof) from - * the apps directory (application code) you must include an acknowledgement: - * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" - * - * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * The licence and distribution terms for any publically available version or - * derivative of this code cannot be changed. i.e. this code cannot simply be - * copied and put under another distribution licence - * [including the GNU Public Licence.] - */ -/* ==================================================================== - * Copyright (c) 1998-2007 The OpenSSL Project. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the OpenSSL Project - * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" - * - * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to - * endorse or promote products derived from this software without - * prior written permission. For written permission, please contact - * openssl-core@openssl.org. - * - * 5. Products derived from this software may not be called "OpenSSL" - * nor may "OpenSSL" appear in their names without prior written - * permission of the OpenSSL Project. - * - * 6. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the OpenSSL Project - * for use in the OpenSSL Toolkit (http://www.openssl.org/)" - * - * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This product includes cryptographic software written by Eric Young - * (eay@cryptsoft.com). This product includes software written by Tim - * Hudson (tjh@cryptsoft.com). - * - */ -/* ==================================================================== - * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. - * - * Portions of the attached software ("Contribution") are developed by - * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project. - * - * The Contribution is licensed pursuant to the OpenSSL open source - * license provided above. - * - * ECC cipher suite support in OpenSSL originally written by - * Vipul Gupta and Sumit Gupta of Sun Microsystems Laboratories. - * - */ -/* ==================================================================== - * Copyright 2005 Nokia. All rights reserved. - * - * The portions of the attached software ("Contribution") is developed by - * Nokia Corporation and is licensed pursuant to the OpenSSL open source - * license. - * - * The Contribution, originally written by Mika Kousa and Pasi Eronen of - * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites - * support (see RFC 4279) to OpenSSL. - * - * No patent licenses or other rights except those expressly stated in - * the OpenSSL open source license shall be deemed granted or received - * expressly, by implication, estoppel, or otherwise. - * - * No assurances are provided by Nokia that the Contribution does not - * infringe the patent or other intellectual property rights of any third - * party or that the license provides you with all the necessary rights - * to make use of the Contribution. - * - * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN - * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA - * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY - * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR - * OTHERWISE. - */ - -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "internal.h" -#include "../crypto/dh/internal.h" - - -int ssl3_connect(SSL *ssl) { - BUF_MEM *buf = NULL; - void (*cb)(const SSL *ssl, int type, int value) = NULL; - int ret = -1; - int new_state, state, skip = 0; - - assert(ssl->handshake_func == ssl3_connect); - assert(!ssl->server); - assert(!SSL_IS_DTLS(ssl)); - - ERR_clear_error(); - ERR_clear_system_error(); - - if (ssl->info_callback != NULL) { - cb = ssl->info_callback; - } else if (ssl->ctx->info_callback != NULL) { - cb = ssl->ctx->info_callback; - } - - ssl->in_handshake++; - - for (;;) { - state = ssl->state; - - switch (ssl->state) { - case SSL_ST_CONNECT: - if (cb != NULL) { - cb(ssl, SSL_CB_HANDSHAKE_START, 1); - } - - if (ssl->init_buf == NULL) { - buf = BUF_MEM_new(); - if (buf == NULL || - !BUF_MEM_grow(buf, SSL3_RT_MAX_PLAIN_LENGTH)) { - ret = -1; - goto end; - } - - ssl->init_buf = buf; - buf = NULL; - } - - if (!ssl_init_wbio_buffer(ssl, 0)) { - ret = -1; - goto end; - } - - /* don't push the buffering BIO quite yet */ - - if (!ssl3_init_handshake_buffer(ssl)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - ret = -1; - goto end; - } - - ssl->state = SSL3_ST_CW_CLNT_HELLO_A; - ssl->init_num = 0; - break; - - case SSL3_ST_CW_CLNT_HELLO_A: - case SSL3_ST_CW_CLNT_HELLO_B: - ssl->shutdown = 0; - ret = ssl3_send_client_hello(ssl); - if (ret <= 0) { - goto end; - } - ssl->state = SSL3_ST_CR_SRVR_HELLO_A; - ssl->init_num = 0; - - /* turn on buffering for the next lot of output */ - if (ssl->bbio != ssl->wbio) { - ssl->wbio = BIO_push(ssl->bbio, ssl->wbio); - } - - break; - - case SSL3_ST_CR_SRVR_HELLO_A: - case SSL3_ST_CR_SRVR_HELLO_B: - ret = ssl3_get_server_hello(ssl); - if (ret <= 0) { - goto end; - } - - if (ssl->hit) { - ssl->state = SSL3_ST_CR_CHANGE; - if (ssl->tlsext_ticket_expected) { - /* receive renewed session ticket */ - ssl->state = SSL3_ST_CR_SESSION_TICKET_A; - } - } else { - ssl->state = SSL3_ST_CR_CERT_A; - } - ssl->init_num = 0; - break; - - case SSL3_ST_CR_CERT_A: - case SSL3_ST_CR_CERT_B: - if (ssl_cipher_has_server_public_key(ssl->s3->tmp.new_cipher)) { - ret = ssl3_get_server_certificate(ssl); - if (ret <= 0) { - goto end; - } - if (ssl->s3->tmp.certificate_status_expected) { - ssl->state = SSL3_ST_CR_CERT_STATUS_A; - } else { - ssl->state = SSL3_ST_VERIFY_SERVER_CERT; - } - } else { - skip = 1; - ssl->state = SSL3_ST_CR_KEY_EXCH_A; - } - ssl->init_num = 0; - break; - - case SSL3_ST_VERIFY_SERVER_CERT: - ret = ssl3_verify_server_cert(ssl); - if (ret <= 0) { - goto end; - } - - ssl->state = SSL3_ST_CR_KEY_EXCH_A; - ssl->init_num = 0; - break; - - case SSL3_ST_CR_KEY_EXCH_A: - case SSL3_ST_CR_KEY_EXCH_B: - ret = ssl3_get_server_key_exchange(ssl); - if (ret <= 0) { - goto end; - } - ssl->state = SSL3_ST_CR_CERT_REQ_A; - ssl->init_num = 0; - break; - - case SSL3_ST_CR_CERT_REQ_A: - case SSL3_ST_CR_CERT_REQ_B: - ret = ssl3_get_certificate_request(ssl); - if (ret <= 0) { - goto end; - } - ssl->state = SSL3_ST_CR_SRVR_DONE_A; - ssl->init_num = 0; - break; - - case SSL3_ST_CR_SRVR_DONE_A: - case SSL3_ST_CR_SRVR_DONE_B: - ret = ssl3_get_server_done(ssl); - if (ret <= 0) { - goto end; - } - if (ssl->s3->tmp.cert_req) { - ssl->state = SSL3_ST_CW_CERT_A; - } else { - ssl->state = SSL3_ST_CW_KEY_EXCH_A; - } - ssl->init_num = 0; - - break; - - case SSL3_ST_CW_CERT_A: - case SSL3_ST_CW_CERT_B: - case SSL3_ST_CW_CERT_C: - case SSL3_ST_CW_CERT_D: - ret = ssl3_send_client_certificate(ssl); - if (ret <= 0) { - goto end; - } - ssl->state = SSL3_ST_CW_KEY_EXCH_A; - ssl->init_num = 0; - break; - - case SSL3_ST_CW_KEY_EXCH_A: - case SSL3_ST_CW_KEY_EXCH_B: - ret = ssl3_send_client_key_exchange(ssl); - if (ret <= 0) { - goto end; - } - /* For TLS, cert_req is set to 2, so a cert chain - * of nothing is sent, but no verify packet is sent */ - if (ssl->s3->tmp.cert_req == 1) { - ssl->state = SSL3_ST_CW_CERT_VRFY_A; - } else { - ssl->state = SSL3_ST_CW_CHANGE_A; - } - - ssl->init_num = 0; - break; - - case SSL3_ST_CW_CERT_VRFY_A: - case SSL3_ST_CW_CERT_VRFY_B: - case SSL3_ST_CW_CERT_VRFY_C: - ret = ssl3_send_cert_verify(ssl); - if (ret <= 0) { - goto end; - } - ssl->state = SSL3_ST_CW_CHANGE_A; - ssl->init_num = 0; - break; - - case SSL3_ST_CW_CHANGE_A: - case SSL3_ST_CW_CHANGE_B: - ret = ssl3_send_change_cipher_spec(ssl, SSL3_ST_CW_CHANGE_A, - SSL3_ST_CW_CHANGE_B); - if (ret <= 0) { - goto end; - } - - ssl->state = SSL3_ST_CW_FINISHED_A; - if (ssl->s3->tlsext_channel_id_valid) { - ssl->state = SSL3_ST_CW_CHANNEL_ID_A; - } - if (ssl->s3->next_proto_neg_seen) { - ssl->state = SSL3_ST_CW_NEXT_PROTO_A; - } - ssl->init_num = 0; - - if (!tls1_change_cipher_state(ssl, SSL3_CHANGE_CIPHER_CLIENT_WRITE)) { - ret = -1; - goto end; - } - - break; - - case SSL3_ST_CW_NEXT_PROTO_A: - case SSL3_ST_CW_NEXT_PROTO_B: - ret = ssl3_send_next_proto(ssl); - if (ret <= 0) { - goto end; - } - - if (ssl->s3->tlsext_channel_id_valid) { - ssl->state = SSL3_ST_CW_CHANNEL_ID_A; - } else { - ssl->state = SSL3_ST_CW_FINISHED_A; - } - break; - - case SSL3_ST_CW_CHANNEL_ID_A: - case SSL3_ST_CW_CHANNEL_ID_B: - ret = ssl3_send_channel_id(ssl); - if (ret <= 0) { - goto end; - } - ssl->state = SSL3_ST_CW_FINISHED_A; - break; - - case SSL3_ST_CW_FINISHED_A: - case SSL3_ST_CW_FINISHED_B: - ret = ssl3_send_finished(ssl, SSL3_ST_CW_FINISHED_A, - SSL3_ST_CW_FINISHED_B); - if (ret <= 0) { - goto end; - } - ssl->state = SSL3_ST_CW_FLUSH; - - if (ssl->hit) { - ssl->s3->tmp.next_state = SSL_ST_OK; - } else { - /* This is a non-resumption handshake. If it involves ChannelID, then - * record the handshake hashes at this point in the session so that - * any resumption of this session with ChannelID can sign those - * hashes. */ - ret = tls1_record_handshake_hashes_for_channel_id(ssl); - if (ret <= 0) { - goto end; - } - if ((SSL_get_mode(ssl) & SSL_MODE_ENABLE_FALSE_START) && - ssl3_can_false_start(ssl) && - /* No False Start on renegotiation (would complicate the state - * machine). */ - !ssl->s3->initial_handshake_complete) { - ssl->s3->tmp.next_state = SSL3_ST_FALSE_START; - } else { - /* Allow NewSessionTicket if ticket expected */ - if (ssl->tlsext_ticket_expected) { - ssl->s3->tmp.next_state = SSL3_ST_CR_SESSION_TICKET_A; - } else { - ssl->s3->tmp.next_state = SSL3_ST_CR_CHANGE; - } - } - } - ssl->init_num = 0; - break; - - case SSL3_ST_CR_SESSION_TICKET_A: - case SSL3_ST_CR_SESSION_TICKET_B: - ret = ssl3_get_new_session_ticket(ssl); - if (ret <= 0) { - goto end; - } - ssl->state = SSL3_ST_CR_CHANGE; - ssl->init_num = 0; - break; - - case SSL3_ST_CR_CERT_STATUS_A: - case SSL3_ST_CR_CERT_STATUS_B: - ret = ssl3_get_cert_status(ssl); - if (ret <= 0) { - goto end; - } - ssl->state = SSL3_ST_VERIFY_SERVER_CERT; - ssl->init_num = 0; - break; - - case SSL3_ST_CR_CHANGE: - ret = ssl->method->ssl_read_change_cipher_spec(ssl); - if (ret <= 0) { - goto end; - } - - if (!tls1_change_cipher_state(ssl, SSL3_CHANGE_CIPHER_CLIENT_READ)) { - ret = -1; - goto end; - } - ssl->state = SSL3_ST_CR_FINISHED_A; - break; - - case SSL3_ST_CR_FINISHED_A: - case SSL3_ST_CR_FINISHED_B: - ret = ssl3_get_finished(ssl, SSL3_ST_CR_FINISHED_A, - SSL3_ST_CR_FINISHED_B); - if (ret <= 0) { - goto end; - } - - if (ssl->hit) { - ssl->state = SSL3_ST_CW_CHANGE_A; - } else { - ssl->state = SSL_ST_OK; - } - ssl->init_num = 0; - break; - - case SSL3_ST_CW_FLUSH: - ssl->rwstate = SSL_WRITING; - if (BIO_flush(ssl->wbio) <= 0) { - ret = -1; - goto end; - } - ssl->rwstate = SSL_NOTHING; - ssl->state = ssl->s3->tmp.next_state; - break; - - case SSL3_ST_FALSE_START: - /* Allow NewSessionTicket if ticket expected */ - if (ssl->tlsext_ticket_expected) { - ssl->state = SSL3_ST_CR_SESSION_TICKET_A; - } else { - ssl->state = SSL3_ST_CR_CHANGE; - } - ssl->s3->tmp.in_false_start = 1; - - ssl_free_wbio_buffer(ssl); - ret = 1; - goto end; - - case SSL_ST_OK: - /* clean a few things up */ - ssl3_cleanup_key_block(ssl); - - BUF_MEM_free(ssl->init_buf); - ssl->init_buf = NULL; - - /* Remove write buffering now. */ - ssl_free_wbio_buffer(ssl); - - const int is_initial_handshake = !ssl->s3->initial_handshake_complete; - - ssl->init_num = 0; - ssl->s3->tmp.in_false_start = 0; - ssl->s3->initial_handshake_complete = 1; - - if (is_initial_handshake) { - /* Renegotiations do not participate in session resumption. */ - ssl_update_cache(ssl, SSL_SESS_CACHE_CLIENT); - } - - ret = 1; - /* ssl->server=0; */ - - if (cb != NULL) { - cb(ssl, SSL_CB_HANDSHAKE_DONE, 1); - } - - goto end; - - default: - OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_STATE); - ret = -1; - goto end; - } - - if (!ssl->s3->tmp.reuse_message && !skip) { - if (cb != NULL && ssl->state != state) { - new_state = ssl->state; - ssl->state = state; - cb(ssl, SSL_CB_CONNECT_LOOP, 1); - ssl->state = new_state; - } - } - skip = 0; - } - -end: - ssl->in_handshake--; - BUF_MEM_free(buf); - if (cb != NULL) { - cb(ssl, SSL_CB_CONNECT_EXIT, ret); - } - return ret; -} - -static int ssl3_write_client_cipher_list(SSL *ssl, CBB *out) { - /* Prepare disabled cipher masks. */ - ssl_set_client_disabled(ssl); - - CBB child; - if (!CBB_add_u16_length_prefixed(out, &child)) { - return 0; - } - - STACK_OF(SSL_CIPHER) *ciphers = SSL_get_ciphers(ssl); - - int any_enabled = 0; - size_t i; - for (i = 0; i < sk_SSL_CIPHER_num(ciphers); i++) { - const SSL_CIPHER *cipher = sk_SSL_CIPHER_value(ciphers, i); - /* Skip disabled ciphers */ - if ((cipher->algorithm_mkey & ssl->cert->mask_k) || - (cipher->algorithm_auth & ssl->cert->mask_a)) { - continue; - } - if (SSL_CIPHER_get_min_version(cipher) > - ssl3_version_from_wire(ssl, ssl->client_version)) { - continue; - } - any_enabled = 1; - if (!CBB_add_u16(&child, ssl_cipher_get_value(cipher))) { - return 0; - } - } - - /* If all ciphers were disabled, return the error to the caller. */ - if (!any_enabled) { - OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CIPHERS_AVAILABLE); - return 0; - } - - /* For SSLv3, the SCSV is added. Otherwise the renegotiation extension is - * added. */ - if (ssl->client_version == SSL3_VERSION && - !ssl->s3->initial_handshake_complete) { - if (!CBB_add_u16(&child, SSL3_CK_SCSV & 0xffff)) { - return 0; - } - /* The renegotiation extension is required to be at index zero. */ - ssl->s3->tmp.extensions.sent |= (1u << 0); - } - - if ((ssl->mode & SSL_MODE_SEND_FALLBACK_SCSV) && - !CBB_add_u16(&child, SSL3_CK_FALLBACK_SCSV & 0xffff)) { - return 0; - } - - return CBB_flush(out); -} - -int ssl3_send_client_hello(SSL *ssl) { - if (ssl->state == SSL3_ST_CW_CLNT_HELLO_B) { - return ssl_do_write(ssl); - } - - /* In DTLS, reset the handshake buffer each time a new ClientHello is - * assembled. We may send multiple if we receive HelloVerifyRequest. */ - if (SSL_IS_DTLS(ssl) && !ssl3_init_handshake_buffer(ssl)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - return -1; - } - - CBB cbb; - CBB_zero(&cbb); - - assert(ssl->state == SSL3_ST_CW_CLNT_HELLO_A); - if (!ssl->s3->have_version) { - uint16_t max_version = ssl3_get_max_client_version(ssl); - /* Disabling all versions is silly: return an error. */ - if (max_version == 0) { - OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_SSL_VERSION); - goto err; - } - - ssl->version = max_version; - /* Only set |ssl->client_version| on the initial handshake. Renegotiations, - * although locked to a version, reuse the value. When using the plain RSA - * key exchange, the ClientHello version is checked in the premaster secret. - * Some servers fail when this value changes. */ - ssl->client_version = max_version; - } - - /* If the configured session has expired or was created at a version higher - * than our maximum version, drop it. */ - if (ssl->session != NULL && - (ssl->session->session_id_length == 0 || ssl->session->not_resumable || - ssl->session->timeout < (long)(time(NULL) - ssl->session->time) || - (!SSL_IS_DTLS(ssl) && ssl->session->ssl_version > ssl->version) || - (SSL_IS_DTLS(ssl) && ssl->session->ssl_version < ssl->version))) { - SSL_set_session(ssl, NULL); - } - - /* If resending the ClientHello in DTLS after a HelloVerifyRequest, don't - * renegerate the client_random. The random must be reused. */ - if ((!SSL_IS_DTLS(ssl) || !ssl->d1->send_cookie) && - !ssl_fill_hello_random(ssl->s3->client_random, - sizeof(ssl->s3->client_random), 0 /* client */)) { - goto err; - } - - /* Renegotiations do not participate in session resumption. */ - int has_session = ssl->session != NULL && - !ssl->s3->initial_handshake_complete; - - CBB child; - if (!CBB_init_fixed(&cbb, ssl_handshake_start(ssl), - ssl->init_buf->max - SSL_HM_HEADER_LENGTH(ssl)) || - !CBB_add_u16(&cbb, ssl->client_version) || - !CBB_add_bytes(&cbb, ssl->s3->client_random, SSL3_RANDOM_SIZE) || - !CBB_add_u8_length_prefixed(&cbb, &child) || - (has_session && - !CBB_add_bytes(&child, ssl->session->session_id, - ssl->session->session_id_length))) { - goto err; - } - - if (SSL_IS_DTLS(ssl)) { - if (!CBB_add_u8_length_prefixed(&cbb, &child) || - !CBB_add_bytes(&child, ssl->d1->cookie, ssl->d1->cookie_len)) { - goto err; - } - } - - size_t length; - if (!ssl3_write_client_cipher_list(ssl, &cbb) || - !CBB_add_u8(&cbb, 1 /* one compression method */) || - !CBB_add_u8(&cbb, 0 /* null compression */) || - !ssl_add_clienthello_tlsext(ssl, &cbb, - CBB_len(&cbb) + SSL_HM_HEADER_LENGTH(ssl)) || - !CBB_finish(&cbb, NULL, &length) || - !ssl_set_handshake_header(ssl, SSL3_MT_CLIENT_HELLO, length)) { - goto err; - } - - ssl->state = SSL3_ST_CW_CLNT_HELLO_B; - return ssl_do_write(ssl); - -err: - CBB_cleanup(&cbb); - return -1; -} - -int ssl3_get_server_hello(SSL *ssl) { - STACK_OF(SSL_CIPHER) *sk; - const SSL_CIPHER *c; - CERT *ct = ssl->cert; - int al = SSL_AD_INTERNAL_ERROR, ok; - long n; - CBS server_hello, server_random, session_id; - uint16_t server_version, cipher_suite; - uint8_t compression_method; - - n = ssl->method->ssl_get_message(ssl, SSL3_ST_CR_SRVR_HELLO_A, - SSL3_ST_CR_SRVR_HELLO_B, SSL3_MT_SERVER_HELLO, - 20000, /* ?? */ - ssl_hash_message, &ok); - - if (!ok) { - uint32_t err = ERR_peek_error(); - if (ERR_GET_LIB(err) == ERR_LIB_SSL && - ERR_GET_REASON(err) == SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE) { - /* Add a dedicated error code to the queue for a handshake_failure alert - * in response to ClientHello. This matches NSS's client behavior and - * gives a better error on a (probable) failure to negotiate initial - * parameters. Note: this error code comes after the original one. - * - * See https://crbug.com/446505. */ - OPENSSL_PUT_ERROR(SSL, SSL_R_HANDSHAKE_FAILURE_ON_CLIENT_HELLO); - } - return n; - } - - CBS_init(&server_hello, ssl->init_msg, n); - - if (!CBS_get_u16(&server_hello, &server_version) || - !CBS_get_bytes(&server_hello, &server_random, SSL3_RANDOM_SIZE) || - !CBS_get_u8_length_prefixed(&server_hello, &session_id) || - CBS_len(&session_id) > SSL3_SESSION_ID_SIZE || - !CBS_get_u16(&server_hello, &cipher_suite) || - !CBS_get_u8(&server_hello, &compression_method)) { - al = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); - goto f_err; - } - - assert(ssl->s3->have_version == ssl->s3->initial_handshake_complete); - if (!ssl->s3->have_version) { - if (!ssl3_is_version_enabled(ssl, server_version)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_UNSUPPORTED_PROTOCOL); - ssl->version = server_version; - /* Mark the version as fixed so the record-layer version is not clamped - * to TLS 1.0. */ - ssl->s3->have_version = 1; - al = SSL_AD_PROTOCOL_VERSION; - goto f_err; - } - ssl->version = server_version; - ssl->s3->enc_method = ssl3_get_enc_method(server_version); - assert(ssl->s3->enc_method != NULL); - /* At this point, the connection's version is known and ssl->version is - * fixed. Begin enforcing the record-layer version. */ - ssl->s3->have_version = 1; - } else if (server_version != ssl->version) { - OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_SSL_VERSION); - al = SSL_AD_PROTOCOL_VERSION; - goto f_err; - } - - /* Copy over the server random. */ - memcpy(ssl->s3->server_random, CBS_data(&server_random), SSL3_RANDOM_SIZE); - - assert(ssl->session == NULL || ssl->session->session_id_length > 0); - if (!ssl->s3->initial_handshake_complete && ssl->session != NULL && - CBS_mem_equal(&session_id, ssl->session->session_id, - ssl->session->session_id_length)) { - if (ssl->sid_ctx_length != ssl->session->sid_ctx_length || - memcmp(ssl->session->sid_ctx, ssl->sid_ctx, ssl->sid_ctx_length)) { - /* actually a client application bug */ - al = SSL_AD_ILLEGAL_PARAMETER; - OPENSSL_PUT_ERROR(SSL, - SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT); - goto f_err; - } - ssl->hit = 1; - } else { - /* The session wasn't resumed. Create a fresh SSL_SESSION to - * fill out. */ - ssl->hit = 0; - if (!ssl_get_new_session(ssl, 0 /* client */)) { - goto f_err; - } - /* Note: session_id could be empty. */ - ssl->session->session_id_length = CBS_len(&session_id); - memcpy(ssl->session->session_id, CBS_data(&session_id), - CBS_len(&session_id)); - } - - c = SSL_get_cipher_by_value(cipher_suite); - if (c == NULL) { - /* unknown cipher */ - al = SSL_AD_ILLEGAL_PARAMETER; - OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_CIPHER_RETURNED); - goto f_err; - } - /* If the cipher is disabled then we didn't sent it in the ClientHello, so if - * the server selected it, it's an error. */ - if ((c->algorithm_mkey & ct->mask_k) || (c->algorithm_auth & ct->mask_a) || - SSL_CIPHER_get_min_version(c) > ssl3_protocol_version(ssl)) { - al = SSL_AD_ILLEGAL_PARAMETER; - OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CIPHER_RETURNED); - goto f_err; - } - - sk = ssl_get_ciphers_by_id(ssl); - if (!sk_SSL_CIPHER_find(sk, NULL, c)) { - /* we did not say we would use this cipher */ - al = SSL_AD_ILLEGAL_PARAMETER; - OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CIPHER_RETURNED); - goto f_err; - } - - if (ssl->hit) { - if (ssl->session->cipher != c) { - al = SSL_AD_ILLEGAL_PARAMETER; - OPENSSL_PUT_ERROR(SSL, SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED); - goto f_err; - } - if (ssl->session->ssl_version != ssl->version) { - al = SSL_AD_ILLEGAL_PARAMETER; - OPENSSL_PUT_ERROR(SSL, SSL_R_OLD_SESSION_VERSION_NOT_RETURNED); - goto f_err; - } - } else { - ssl->session->cipher = c; - } - ssl->s3->tmp.new_cipher = c; - - /* Now that the cipher is known, initialize the handshake hash. */ - if (!ssl3_init_handshake_hash(ssl)) { - goto f_err; - } - - /* If doing a full handshake with TLS 1.2, the server may request a client - * certificate which requires hashing the handshake transcript under a - * different hash. Otherwise, the handshake buffer may be released. */ - if (ssl->hit || ssl3_protocol_version(ssl) < TLS1_2_VERSION) { - ssl3_free_handshake_buffer(ssl); - } - - /* Only the NULL compression algorithm is supported. */ - if (compression_method != 0) { - al = SSL_AD_ILLEGAL_PARAMETER; - OPENSSL_PUT_ERROR(SSL, SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM); - goto f_err; - } - - /* TLS extensions */ - if (!ssl_parse_serverhello_tlsext(ssl, &server_hello)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_PARSE_TLSEXT); - goto err; - } - - /* There should be nothing left over in the record. */ - if (CBS_len(&server_hello) != 0) { - /* wrong packet length */ - al = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_PACKET_LENGTH); - goto f_err; - } - - if (ssl->hit && - ssl->s3->tmp.extended_master_secret != - ssl->session->extended_master_secret) { - al = SSL_AD_HANDSHAKE_FAILURE; - if (ssl->session->extended_master_secret) { - OPENSSL_PUT_ERROR(SSL, SSL_R_RESUMED_EMS_SESSION_WITHOUT_EMS_EXTENSION); - } else { - OPENSSL_PUT_ERROR(SSL, SSL_R_RESUMED_NON_EMS_SESSION_WITH_EMS_EXTENSION); - } - goto f_err; - } - - return 1; - -f_err: - ssl3_send_alert(ssl, SSL3_AL_FATAL, al); -err: - return -1; -} - -/* ssl3_check_leaf_certificate returns one if |leaf| is a suitable leaf server - * certificate for |ssl|. Otherwise, it returns zero and pushes an error on the - * error queue. */ -static int ssl3_check_leaf_certificate(SSL *ssl, X509 *leaf) { - int ret = 0; - EVP_PKEY *pkey = X509_get_pubkey(leaf); - if (pkey == NULL) { - goto err; - } - - /* Check the certificate's type matches the cipher. */ - const SSL_CIPHER *cipher = ssl->s3->tmp.new_cipher; - int expected_type = ssl_cipher_get_key_type(cipher); - assert(expected_type != EVP_PKEY_NONE); - if (pkey->type != expected_type) { - OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CERTIFICATE_TYPE); - goto err; - } - - if (cipher->algorithm_auth & SSL_aECDSA) { - /* TODO(davidben): This behavior is preserved from upstream. Should key - * usages be checked in other cases as well? */ - /* This call populates the ex_flags field correctly */ - X509_check_purpose(leaf, -1, 0); - if ((leaf->ex_flags & EXFLAG_KUSAGE) && - !(leaf->ex_kusage & X509v3_KU_DIGITAL_SIGNATURE)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_ECC_CERT_NOT_FOR_SIGNING); - goto err; - } - - if (!tls1_check_ec_cert(ssl, leaf)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECC_CERT); - goto err; - } - } - - ret = 1; - -err: - EVP_PKEY_free(pkey); - return ret; -} - -int ssl3_get_server_certificate(SSL *ssl) { - int al, ok, ret = -1; - unsigned long n; - X509 *x = NULL; - STACK_OF(X509) *sk = NULL; - EVP_PKEY *pkey = NULL; - CBS cbs, certificate_list; - const uint8_t *data; - - n = ssl->method->ssl_get_message(ssl, SSL3_ST_CR_CERT_A, SSL3_ST_CR_CERT_B, - SSL3_MT_CERTIFICATE, (long)ssl->max_cert_list, - ssl_hash_message, &ok); - - if (!ok) { - return n; - } - - CBS_init(&cbs, ssl->init_msg, n); - - sk = sk_X509_new_null(); - if (sk == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; - } - - if (!CBS_get_u24_length_prefixed(&cbs, &certificate_list) || - CBS_len(&certificate_list) == 0 || - CBS_len(&cbs) != 0) { - al = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); - goto f_err; - } - - while (CBS_len(&certificate_list) > 0) { - CBS certificate; - if (!CBS_get_u24_length_prefixed(&certificate_list, &certificate)) { - al = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_CERT_LENGTH_MISMATCH); - goto f_err; - } - /* A u24 length cannot overflow a long. */ - data = CBS_data(&certificate); - x = d2i_X509(NULL, &data, (long)CBS_len(&certificate)); - if (x == NULL) { - al = SSL_AD_BAD_CERTIFICATE; - OPENSSL_PUT_ERROR(SSL, ERR_R_ASN1_LIB); - goto f_err; - } - if (data != CBS_data(&certificate) + CBS_len(&certificate)) { - al = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_CERT_LENGTH_MISMATCH); - goto f_err; - } - if (!sk_X509_push(sk, x)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; - } - x = NULL; - } - - X509 *leaf = sk_X509_value(sk, 0); - if (!ssl3_check_leaf_certificate(ssl, leaf)) { - al = SSL_AD_ILLEGAL_PARAMETER; - goto f_err; - } - - /* NOTE: Unlike the server half, the client's copy of |cert_chain| includes - * the leaf. */ - sk_X509_pop_free(ssl->session->cert_chain, X509_free); - ssl->session->cert_chain = sk; - sk = NULL; - - X509_free(ssl->session->peer); - ssl->session->peer = X509_up_ref(leaf); - - ssl->session->verify_result = ssl->verify_result; - - ret = 1; - - if (0) { - f_err: - ssl3_send_alert(ssl, SSL3_AL_FATAL, al); - } - -err: - EVP_PKEY_free(pkey); - X509_free(x); - sk_X509_pop_free(sk, X509_free); - return ret; -} - -int ssl3_get_server_key_exchange(SSL *ssl) { - EVP_MD_CTX md_ctx; - int al, ok; - EVP_PKEY *pkey = NULL; - DH *dh = NULL; - EC_KEY *ecdh = NULL; - EC_POINT *srvr_ecpoint = NULL; - - /* use same message size as in ssl3_get_certificate_request() as - * ServerKeyExchange message may be skipped */ - long n = ssl->method->ssl_get_message( - ssl, SSL3_ST_CR_KEY_EXCH_A, SSL3_ST_CR_KEY_EXCH_B, -1, ssl->max_cert_list, - ssl_hash_message, &ok); - if (!ok) { - return n; - } - - if (ssl->s3->tmp.message_type != SSL3_MT_SERVER_KEY_EXCHANGE) { - if (ssl_cipher_requires_server_key_exchange(ssl->s3->tmp.new_cipher)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_MESSAGE); - ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE); - return -1; - } - - /* In plain PSK ciphersuite, ServerKeyExchange may be omitted to send no - * identity hint. */ - if (ssl->s3->tmp.new_cipher->algorithm_auth & SSL_aPSK) { - /* TODO(davidben): This should be reset in one place with the rest of the - * handshake state. */ - OPENSSL_free(ssl->s3->tmp.peer_psk_identity_hint); - ssl->s3->tmp.peer_psk_identity_hint = NULL; - } - ssl->s3->tmp.reuse_message = 1; - return 1; - } - - /* Retain a copy of the original CBS to compute the signature over. */ - CBS server_key_exchange; - CBS_init(&server_key_exchange, ssl->init_msg, n); - CBS server_key_exchange_orig = server_key_exchange; - - uint32_t alg_k = ssl->s3->tmp.new_cipher->algorithm_mkey; - uint32_t alg_a = ssl->s3->tmp.new_cipher->algorithm_auth; - EVP_MD_CTX_init(&md_ctx); - - if (alg_a & SSL_aPSK) { - CBS psk_identity_hint; - - /* Each of the PSK key exchanges begins with a psk_identity_hint. */ - if (!CBS_get_u16_length_prefixed(&server_key_exchange, - &psk_identity_hint)) { - al = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); - goto f_err; - } - - /* Store PSK identity hint for later use, hint is used in - * ssl3_send_client_key_exchange. Assume that the maximum length of a PSK - * identity hint can be as long as the maximum length of a PSK identity. - * Also do not allow NULL characters; identities are saved as C strings. - * - * TODO(davidben): Should invalid hints be ignored? It's a hint rather than - * a specific identity. */ - if (CBS_len(&psk_identity_hint) > PSK_MAX_IDENTITY_LEN || - CBS_contains_zero_byte(&psk_identity_hint)) { - al = SSL_AD_HANDSHAKE_FAILURE; - OPENSSL_PUT_ERROR(SSL, SSL_R_DATA_LENGTH_TOO_LONG); - goto f_err; - } - - /* Save the identity hint as a C string. */ - if (!CBS_strdup(&psk_identity_hint, &ssl->s3->tmp.peer_psk_identity_hint)) { - al = SSL_AD_INTERNAL_ERROR; - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto f_err; - } - } - - if (alg_k & SSL_kDHE) { - CBS dh_p, dh_g, dh_Ys; - if (!CBS_get_u16_length_prefixed(&server_key_exchange, &dh_p) || - CBS_len(&dh_p) == 0 || - !CBS_get_u16_length_prefixed(&server_key_exchange, &dh_g) || - CBS_len(&dh_g) == 0 || - !CBS_get_u16_length_prefixed(&server_key_exchange, &dh_Ys) || - CBS_len(&dh_Ys) == 0) { - al = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); - goto f_err; - } - - dh = DH_new(); - if (dh == NULL) { - goto err; - } - - dh->p = BN_bin2bn(CBS_data(&dh_p), CBS_len(&dh_p), NULL); - dh->g = BN_bin2bn(CBS_data(&dh_g), CBS_len(&dh_g), NULL); - if (dh->p == NULL || dh->g == NULL) { - goto err; - } - - ssl->session->key_exchange_info = DH_num_bits(dh); - if (ssl->session->key_exchange_info < 1024) { - OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_DH_P_LENGTH); - goto err; - } else if (ssl->session->key_exchange_info > 4096) { - /* Overly large DHE groups are prohibitively expensive, so enforce a limit - * to prevent a server from causing us to perform too expensive of a - * computation. */ - OPENSSL_PUT_ERROR(SSL, SSL_R_DH_P_TOO_LONG); - goto err; - } - - SSL_ECDH_CTX_init_for_dhe(&ssl->s3->tmp.ecdh_ctx, dh); - dh = NULL; - - /* Save the peer public key for later. */ - size_t peer_key_len; - if (!CBS_stow(&dh_Ys, &ssl->s3->tmp.peer_key, &peer_key_len)) { - goto err; - } - /* |dh_Ys| has a u16 length prefix, so this fits in a |uint16_t|. */ - assert(sizeof(ssl->s3->tmp.peer_key_len) == 2 && peer_key_len <= 0xffff); - ssl->s3->tmp.peer_key_len = (uint16_t)peer_key_len; - } else if (alg_k & SSL_kECDHE) { - /* Parse the server parameters. */ - uint8_t curve_type; - uint16_t curve_id; - CBS point; - if (!CBS_get_u8(&server_key_exchange, &curve_type) || - curve_type != NAMED_CURVE_TYPE || - !CBS_get_u16(&server_key_exchange, &curve_id) || - !CBS_get_u8_length_prefixed(&server_key_exchange, &point)) { - al = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); - goto f_err; - } - ssl->session->key_exchange_info = curve_id; - - /* Ensure the curve is consistent with preferences. */ - if (!tls1_check_curve_id(ssl, curve_id)) { - al = SSL_AD_ILLEGAL_PARAMETER; - OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CURVE); - goto f_err; - } - - /* Initialize ECDH and save the peer public key for later. */ - size_t peer_key_len; - if (!SSL_ECDH_CTX_init(&ssl->s3->tmp.ecdh_ctx, curve_id) || - !CBS_stow(&point, &ssl->s3->tmp.peer_key, &peer_key_len)) { - goto err; - } - /* |point| has a u8 length prefix, so this fits in a |uint16_t|. */ - assert(sizeof(ssl->s3->tmp.peer_key_len) == 2 && peer_key_len <= 0xffff); - ssl->s3->tmp.peer_key_len = (uint16_t)peer_key_len; - } else if (!(alg_k & SSL_kPSK)) { - al = SSL_AD_UNEXPECTED_MESSAGE; - OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_MESSAGE); - goto f_err; - } - - /* At this point, |server_key_exchange| contains the signature, if any, while - * |server_key_exchange_orig| contains the entire message. From that, derive - * a CBS containing just the parameter. */ - CBS parameter; - CBS_init(¶meter, CBS_data(&server_key_exchange_orig), - CBS_len(&server_key_exchange_orig) - CBS_len(&server_key_exchange)); - - /* ServerKeyExchange should be signed by the server's public key. */ - if (ssl_cipher_has_server_public_key(ssl->s3->tmp.new_cipher)) { - pkey = X509_get_pubkey(ssl->session->peer); - if (pkey == NULL) { - goto err; - } - - const EVP_MD *md = NULL; - if (ssl3_protocol_version(ssl) >= TLS1_2_VERSION) { - uint8_t hash, signature; - if (!CBS_get_u8(&server_key_exchange, &hash) || - !CBS_get_u8(&server_key_exchange, &signature)) { - al = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); - goto f_err; - } - if (!tls12_check_peer_sigalg(ssl, &md, &al, hash, signature, pkey)) { - goto f_err; - } - ssl->s3->tmp.server_key_exchange_hash = hash; - } else if (pkey->type == EVP_PKEY_RSA) { - md = EVP_md5_sha1(); - } else { - md = EVP_sha1(); - } - - /* The last field in |server_key_exchange| is the signature. */ - CBS signature; - if (!CBS_get_u16_length_prefixed(&server_key_exchange, &signature) || - CBS_len(&server_key_exchange) != 0) { - al = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); - goto f_err; - } - - if (!EVP_DigestVerifyInit(&md_ctx, NULL, md, NULL, pkey) || - !EVP_DigestVerifyUpdate(&md_ctx, ssl->s3->client_random, - SSL3_RANDOM_SIZE) || - !EVP_DigestVerifyUpdate(&md_ctx, ssl->s3->server_random, - SSL3_RANDOM_SIZE) || - !EVP_DigestVerifyUpdate(&md_ctx, CBS_data(¶meter), - CBS_len(¶meter)) || - !EVP_DigestVerifyFinal(&md_ctx, CBS_data(&signature), - CBS_len(&signature))) { - /* bad signature */ - al = SSL_AD_DECRYPT_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SIGNATURE); - goto f_err; - } - } else { - /* PSK ciphers are the only supported certificate-less ciphers. */ - assert(alg_a == SSL_aPSK); - - if (CBS_len(&server_key_exchange) > 0) { - al = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_EXTRA_DATA_IN_MESSAGE); - goto f_err; - } - } - EVP_PKEY_free(pkey); - EVP_MD_CTX_cleanup(&md_ctx); - return 1; - -f_err: - ssl3_send_alert(ssl, SSL3_AL_FATAL, al); -err: - EVP_PKEY_free(pkey); - DH_free(dh); - EC_POINT_free(srvr_ecpoint); - EC_KEY_free(ecdh); - EVP_MD_CTX_cleanup(&md_ctx); - return -1; -} - -static int ca_dn_cmp(const X509_NAME **a, const X509_NAME **b) { - return X509_NAME_cmp(*a, *b); -} - -int ssl3_get_certificate_request(SSL *ssl) { - int ok, ret = 0; - unsigned long n; - X509_NAME *xn = NULL; - STACK_OF(X509_NAME) *ca_sk = NULL; - CBS cbs; - CBS certificate_types; - CBS certificate_authorities; - const uint8_t *data; - - n = ssl->method->ssl_get_message(ssl, SSL3_ST_CR_CERT_REQ_A, - SSL3_ST_CR_CERT_REQ_B, -1, ssl->max_cert_list, - ssl_hash_message, &ok); - - if (!ok) { - return n; - } - - ssl->s3->tmp.cert_req = 0; - - if (ssl->s3->tmp.message_type == SSL3_MT_SERVER_DONE) { - ssl->s3->tmp.reuse_message = 1; - /* If we get here we don't need the handshake buffer as we won't be doing - * client auth. */ - ssl3_free_handshake_buffer(ssl); - return 1; - } - - if (ssl->s3->tmp.message_type != SSL3_MT_CERTIFICATE_REQUEST) { - ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE); - OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_MESSAGE_TYPE); - goto err; - } - - CBS_init(&cbs, ssl->init_msg, n); - - ca_sk = sk_X509_NAME_new(ca_dn_cmp); - if (ca_sk == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; - } - - /* get the certificate types */ - if (!CBS_get_u8_length_prefixed(&cbs, &certificate_types)) { - ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); - OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); - goto err; - } - - if (!CBS_stow(&certificate_types, &ssl->s3->tmp.certificate_types, - &ssl->s3->tmp.num_certificate_types)) { - ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); - goto err; - } - - if (ssl3_protocol_version(ssl) >= TLS1_2_VERSION) { - CBS supported_signature_algorithms; - if (!CBS_get_u16_length_prefixed(&cbs, &supported_signature_algorithms) || - !tls1_parse_peer_sigalgs(ssl, &supported_signature_algorithms)) { - ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); - OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); - goto err; - } - } - - /* get the CA RDNs */ - if (!CBS_get_u16_length_prefixed(&cbs, &certificate_authorities)) { - ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); - OPENSSL_PUT_ERROR(SSL, SSL_R_LENGTH_MISMATCH); - goto err; - } - - while (CBS_len(&certificate_authorities) > 0) { - CBS distinguished_name; - if (!CBS_get_u16_length_prefixed(&certificate_authorities, - &distinguished_name)) { - ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); - OPENSSL_PUT_ERROR(SSL, SSL_R_CA_DN_TOO_LONG); - goto err; - } - - data = CBS_data(&distinguished_name); - - /* A u16 length cannot overflow a long. */ - xn = d2i_X509_NAME(NULL, &data, (long)CBS_len(&distinguished_name)); - if (xn == NULL) { - ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); - OPENSSL_PUT_ERROR(SSL, ERR_R_ASN1_LIB); - goto err; - } - - if (!CBS_skip(&distinguished_name, data - CBS_data(&distinguished_name))) { - ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - goto err; - } - - if (CBS_len(&distinguished_name) != 0) { - ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); - OPENSSL_PUT_ERROR(SSL, SSL_R_CA_DN_LENGTH_MISMATCH); - goto err; - } - - if (!sk_X509_NAME_push(ca_sk, xn)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; - } - } - - /* we should setup a certificate to return.... */ - ssl->s3->tmp.cert_req = 1; - sk_X509_NAME_pop_free(ssl->s3->tmp.ca_names, X509_NAME_free); - ssl->s3->tmp.ca_names = ca_sk; - ca_sk = NULL; - - ret = 1; - -err: - sk_X509_NAME_pop_free(ca_sk, X509_NAME_free); - return ret; -} - -int ssl3_get_new_session_ticket(SSL *ssl) { - int ok, al; - long n = ssl->method->ssl_get_message( - ssl, SSL3_ST_CR_SESSION_TICKET_A, SSL3_ST_CR_SESSION_TICKET_B, - SSL3_MT_NEWSESSION_TICKET, 16384, ssl_hash_message, &ok); - - if (!ok) { - return n; - } - - CBS new_session_ticket, ticket; - uint32_t ticket_lifetime_hint; - CBS_init(&new_session_ticket, ssl->init_msg, n); - if (!CBS_get_u32(&new_session_ticket, &ticket_lifetime_hint) || - !CBS_get_u16_length_prefixed(&new_session_ticket, &ticket) || - CBS_len(&new_session_ticket) != 0) { - al = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); - goto f_err; - } - - if (CBS_len(&ticket) == 0) { - /* RFC 5077 allows a server to change its mind and send no ticket after - * negotiating the extension. The value of |tlsext_ticket_expected| is - * checked in |ssl_update_cache| so is cleared here to avoid an unnecessary - * update. */ - ssl->tlsext_ticket_expected = 0; - return 1; - } - - if (ssl->hit) { - /* The server is sending a new ticket for an existing session. Sessions are - * immutable once established, so duplicate all but the ticket of the - * existing session. */ - uint8_t *bytes; - size_t bytes_len; - if (!SSL_SESSION_to_bytes_for_ticket(ssl->session, &bytes, &bytes_len)) { - goto err; - } - SSL_SESSION *new_session = SSL_SESSION_from_bytes(bytes, bytes_len); - OPENSSL_free(bytes); - if (new_session == NULL) { - /* This should never happen. */ - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - goto err; - } - - SSL_SESSION_free(ssl->session); - ssl->session = new_session; - } - - if (!CBS_stow(&ticket, &ssl->session->tlsext_tick, - &ssl->session->tlsext_ticklen)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; - } - ssl->session->tlsext_tick_lifetime_hint = ticket_lifetime_hint; - - /* Generate a session ID for this session based on the session ticket. We use - * the session ID mechanism for detecting ticket resumption. This also fits in - * with assumptions elsewhere in OpenSSL.*/ - if (!EVP_Digest(CBS_data(&ticket), CBS_len(&ticket), ssl->session->session_id, - &ssl->session->session_id_length, EVP_sha256(), NULL)) { - goto err; - } - - return 1; - -f_err: - ssl3_send_alert(ssl, SSL3_AL_FATAL, al); -err: - return -1; -} - -int ssl3_get_cert_status(SSL *ssl) { - int ok, al; - long n; - CBS certificate_status, ocsp_response; - uint8_t status_type; - - n = ssl->method->ssl_get_message( - ssl, SSL3_ST_CR_CERT_STATUS_A, SSL3_ST_CR_CERT_STATUS_B, - -1, 16384, ssl_hash_message, &ok); - - if (!ok) { - return n; - } - - if (ssl->s3->tmp.message_type != SSL3_MT_CERTIFICATE_STATUS) { - /* A server may send status_request in ServerHello and then change - * its mind about sending CertificateStatus. */ - ssl->s3->tmp.reuse_message = 1; - return 1; - } - - CBS_init(&certificate_status, ssl->init_msg, n); - if (!CBS_get_u8(&certificate_status, &status_type) || - status_type != TLSEXT_STATUSTYPE_ocsp || - !CBS_get_u24_length_prefixed(&certificate_status, &ocsp_response) || - CBS_len(&ocsp_response) == 0 || - CBS_len(&certificate_status) != 0) { - al = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); - goto f_err; - } - - if (!CBS_stow(&ocsp_response, &ssl->session->ocsp_response, - &ssl->session->ocsp_response_length)) { - al = SSL_AD_INTERNAL_ERROR; - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto f_err; - } - return 1; - -f_err: - ssl3_send_alert(ssl, SSL3_AL_FATAL, al); - return -1; -} - -int ssl3_get_server_done(SSL *ssl) { - int ok; - long n; - - n = ssl->method->ssl_get_message(ssl, SSL3_ST_CR_SRVR_DONE_A, - SSL3_ST_CR_SRVR_DONE_B, SSL3_MT_SERVER_DONE, - 30, /* should be very small, like 0 :-) */ - ssl_hash_message, &ok); - - if (!ok) { - return n; - } - - if (n > 0) { - /* should contain no data */ - ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); - OPENSSL_PUT_ERROR(SSL, SSL_R_LENGTH_MISMATCH); - return -1; - } - - return 1; -} - -OPENSSL_COMPILE_ASSERT(sizeof(size_t) >= sizeof(unsigned), - SIZE_T_IS_SMALLER_THAN_UNSIGNED); - -int ssl3_send_client_key_exchange(SSL *ssl) { - if (ssl->state == SSL3_ST_CW_KEY_EXCH_B) { - return ssl_do_write(ssl); - } - assert(ssl->state == SSL3_ST_CW_KEY_EXCH_A); - - uint8_t *pms = NULL; - size_t pms_len = 0; - CBB cbb; - if (!CBB_init_fixed(&cbb, ssl_handshake_start(ssl), - ssl->init_buf->max - SSL_HM_HEADER_LENGTH(ssl))) { - goto err; - } - - uint32_t alg_k = ssl->s3->tmp.new_cipher->algorithm_mkey; - uint32_t alg_a = ssl->s3->tmp.new_cipher->algorithm_auth; - - /* If using a PSK key exchange, prepare the pre-shared key. */ - unsigned psk_len = 0; - uint8_t psk[PSK_MAX_PSK_LEN]; - if (alg_a & SSL_aPSK) { - if (ssl->psk_client_callback == NULL) { - OPENSSL_PUT_ERROR(SSL, SSL_R_PSK_NO_CLIENT_CB); - goto err; - } - - char identity[PSK_MAX_IDENTITY_LEN + 1]; - memset(identity, 0, sizeof(identity)); - psk_len = ssl->psk_client_callback( - ssl, ssl->s3->tmp.peer_psk_identity_hint, identity, sizeof(identity), - psk, sizeof(psk)); - if (psk_len == 0) { - OPENSSL_PUT_ERROR(SSL, SSL_R_PSK_IDENTITY_NOT_FOUND); - ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE); - goto err; - } - assert(psk_len <= PSK_MAX_PSK_LEN); - - OPENSSL_free(ssl->session->psk_identity); - ssl->session->psk_identity = BUF_strdup(identity); - if (ssl->session->psk_identity == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; - } - - /* Write out psk_identity. */ - CBB child; - if (!CBB_add_u16_length_prefixed(&cbb, &child) || - !CBB_add_bytes(&child, (const uint8_t *)identity, - OPENSSL_strnlen(identity, sizeof(identity))) || - !CBB_flush(&cbb)) { - goto err; - } - } - - /* Depending on the key exchange method, compute |pms| and |pms_len|. */ - if (alg_k & SSL_kRSA) { - pms_len = SSL_MAX_MASTER_KEY_LENGTH; - pms = OPENSSL_malloc(pms_len); - if (pms == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; - } - - EVP_PKEY *pkey = X509_get_pubkey(ssl->session->peer); - if (pkey == NULL) { - goto err; - } - - RSA *rsa = EVP_PKEY_get0_RSA(pkey); - if (rsa == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - EVP_PKEY_free(pkey); - goto err; - } - - ssl->session->key_exchange_info = EVP_PKEY_bits(pkey); - EVP_PKEY_free(pkey); - - pms[0] = ssl->client_version >> 8; - pms[1] = ssl->client_version & 0xff; - if (!RAND_bytes(&pms[2], SSL_MAX_MASTER_KEY_LENGTH - 2)) { - goto err; - } - - CBB child, *enc_pms = &cbb; - size_t enc_pms_len; - /* In TLS, there is a length prefix. */ - if (ssl->version > SSL3_VERSION) { - if (!CBB_add_u16_length_prefixed(&cbb, &child)) { - goto err; - } - enc_pms = &child; - } - - uint8_t *ptr; - if (!CBB_reserve(enc_pms, &ptr, RSA_size(rsa)) || - !RSA_encrypt(rsa, &enc_pms_len, ptr, RSA_size(rsa), pms, pms_len, - RSA_PKCS1_PADDING) || - /* Log the premaster secret, if logging is enabled. */ - !ssl_log_rsa_client_key_exchange(ssl, ptr, enc_pms_len, pms, pms_len) || - !CBB_did_write(enc_pms, enc_pms_len) || - !CBB_flush(&cbb)) { - goto err; - } - } else if (alg_k & (SSL_kECDHE|SSL_kDHE)) { - /* Generate a keypair and serialize the public half. ECDHE uses a u8 length - * prefix while DHE uses u16. */ - CBB child; - int child_ok; - if (alg_k & SSL_kECDHE) { - child_ok = CBB_add_u8_length_prefixed(&cbb, &child); - } else { - child_ok = CBB_add_u16_length_prefixed(&cbb, &child); - } - - if (!child_ok || - !SSL_ECDH_CTX_generate_keypair(&ssl->s3->tmp.ecdh_ctx, &child) || - !CBB_flush(&cbb)) { - goto err; - } - - /* Compute the premaster. */ - uint8_t alert; - if (!SSL_ECDH_CTX_compute_secret(&ssl->s3->tmp.ecdh_ctx, &pms, &pms_len, - &alert, ssl->s3->tmp.peer_key, - ssl->s3->tmp.peer_key_len)) { - ssl3_send_alert(ssl, SSL3_AL_FATAL, alert); - goto err; - } - - /* The key exchange state may now be discarded. */ - SSL_ECDH_CTX_cleanup(&ssl->s3->tmp.ecdh_ctx); - OPENSSL_free(ssl->s3->tmp.peer_key); - ssl->s3->tmp.peer_key = NULL; - } else if (alg_k & SSL_kPSK) { - /* For plain PSK, other_secret is a block of 0s with the same length as - * the pre-shared key. */ - pms_len = psk_len; - pms = OPENSSL_malloc(pms_len); - if (pms == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; - } - memset(pms, 0, pms_len); - } else { - ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE); - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - goto err; - } - - /* For a PSK cipher suite, other_secret is combined with the pre-shared - * key. */ - if (alg_a & SSL_aPSK) { - CBB pms_cbb, child; - uint8_t *new_pms; - size_t new_pms_len; - - CBB_zero(&pms_cbb); - if (!CBB_init(&pms_cbb, 2 + psk_len + 2 + pms_len) || - !CBB_add_u16_length_prefixed(&pms_cbb, &child) || - !CBB_add_bytes(&child, pms, pms_len) || - !CBB_add_u16_length_prefixed(&pms_cbb, &child) || - !CBB_add_bytes(&child, psk, psk_len) || - !CBB_finish(&pms_cbb, &new_pms, &new_pms_len)) { - CBB_cleanup(&pms_cbb); - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; - } - OPENSSL_cleanse(pms, pms_len); - OPENSSL_free(pms); - pms = new_pms; - pms_len = new_pms_len; - } - - /* The message must be added to the finished hash before calculating the - * master secret. */ - size_t length; - if (!CBB_finish(&cbb, NULL, &length) || - !ssl_set_handshake_header(ssl, SSL3_MT_CLIENT_KEY_EXCHANGE, length)) { - goto err; - } - ssl->state = SSL3_ST_CW_KEY_EXCH_B; - - ssl->session->master_key_length = - tls1_generate_master_secret(ssl, ssl->session->master_key, pms, pms_len); - if (ssl->session->master_key_length == 0) { - goto err; - } - ssl->session->extended_master_secret = ssl->s3->tmp.extended_master_secret; - OPENSSL_cleanse(pms, pms_len); - OPENSSL_free(pms); - - /* SSL3_ST_CW_KEY_EXCH_B */ - return ssl_do_write(ssl); - -err: - if (pms != NULL) { - OPENSSL_cleanse(pms, pms_len); - OPENSSL_free(pms); - } - return -1; -} - -int ssl3_send_cert_verify(SSL *ssl) { - if (ssl->state == SSL3_ST_CW_CERT_VRFY_C) { - return ssl_do_write(ssl); - } - - CBB cbb, child; - if (!CBB_init_fixed(&cbb, ssl_handshake_start(ssl), - ssl->init_buf->max - SSL_HM_HEADER_LENGTH(ssl))) { - goto err; - } - - assert(ssl_has_private_key(ssl)); - - const size_t max_sig_len = ssl_private_key_max_signature_len(ssl); - size_t sig_len; - enum ssl_private_key_result_t sign_result; - if (ssl->state == SSL3_ST_CW_CERT_VRFY_A) { - /* Select and write out the digest type in TLS 1.2. */ - const EVP_MD *md = NULL; - if (ssl3_protocol_version(ssl) >= TLS1_2_VERSION) { - md = tls1_choose_signing_digest(ssl); - if (!tls12_add_sigandhash(ssl, &cbb, md)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - goto err; - } - } - - /* Compute the digest. In TLS 1.1 and below, the digest type is also - * selected here. */ - uint8_t digest[EVP_MAX_MD_SIZE]; - size_t digest_len; - if (!ssl3_cert_verify_hash(ssl, digest, &digest_len, &md, - ssl_private_key_type(ssl))) { - goto err; - } - - /* The handshake buffer is no longer necessary. */ - ssl3_free_handshake_buffer(ssl); - - /* Sign the digest. */ - uint8_t *ptr; - if (!CBB_add_u16_length_prefixed(&cbb, &child) || - !CBB_reserve(&child, &ptr, max_sig_len)) { - goto err; - } - sign_result = ssl_private_key_sign(ssl, ptr, &sig_len, max_sig_len, md, - digest, digest_len); - } else { - assert(ssl->state == SSL3_ST_CW_CERT_VRFY_B); - - /* Skip over the already written signature algorithm and retry the - * signature. */ - uint8_t *ptr; - if ((ssl3_protocol_version(ssl) >= TLS1_2_VERSION && - !CBB_did_write(&cbb, 2)) || - !CBB_add_u16_length_prefixed(&cbb, &child) || - !CBB_reserve(&child, &ptr, max_sig_len)) { - goto err; - } - sign_result = - ssl_private_key_sign_complete(ssl, ptr, &sig_len, max_sig_len); - } - - switch (sign_result) { - case ssl_private_key_success: - ssl->rwstate = SSL_NOTHING; - break; - case ssl_private_key_failure: - ssl->rwstate = SSL_NOTHING; - goto err; - case ssl_private_key_retry: - ssl->rwstate = SSL_PRIVATE_KEY_OPERATION; - ssl->state = SSL3_ST_CW_CERT_VRFY_B; - goto err; - } - - size_t length; - if (!CBB_did_write(&child, sig_len) || - !CBB_finish(&cbb, NULL, &length) || - !ssl_set_handshake_header(ssl, SSL3_MT_CERTIFICATE_VERIFY, length)) { - goto err; - } - - ssl->state = SSL3_ST_CW_CERT_VRFY_C; - return ssl_do_write(ssl); - -err: - CBB_cleanup(&cbb); - return -1; -} - -/* ssl3_has_client_certificate returns true if a client certificate is - * configured. */ -static int ssl3_has_client_certificate(SSL *ssl) { - return ssl->cert && ssl->cert->x509 && ssl_has_private_key(ssl); -} - -int ssl3_send_client_certificate(SSL *ssl) { - X509 *x509 = NULL; - EVP_PKEY *pkey = NULL; - int i; - - if (ssl->state == SSL3_ST_CW_CERT_A) { - /* Let cert callback update client certificates if required */ - if (ssl->cert->cert_cb) { - i = ssl->cert->cert_cb(ssl, ssl->cert->cert_cb_arg); - if (i < 0) { - ssl->rwstate = SSL_X509_LOOKUP; - return -1; - } - if (i == 0) { - ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); - return 0; - } - ssl->rwstate = SSL_NOTHING; - } - - if (ssl3_has_client_certificate(ssl)) { - ssl->state = SSL3_ST_CW_CERT_C; - } else { - ssl->state = SSL3_ST_CW_CERT_B; - } - } - - /* We need to get a client cert */ - if (ssl->state == SSL3_ST_CW_CERT_B) { - /* If we get an error, we need to: - * ssl->rwstate=SSL_X509_LOOKUP; return(-1); - * We then get retried later */ - i = ssl_do_client_cert_cb(ssl, &x509, &pkey); - if (i < 0) { - ssl->rwstate = SSL_X509_LOOKUP; - return -1; - } - ssl->rwstate = SSL_NOTHING; - if (i == 1 && pkey != NULL && x509 != NULL) { - ssl->state = SSL3_ST_CW_CERT_B; - if (!SSL_use_certificate(ssl, x509) || !SSL_use_PrivateKey(ssl, pkey)) { - i = 0; - } - } else if (i == 1) { - i = 0; - OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_DATA_RETURNED_BY_CALLBACK); - } - - X509_free(x509); - EVP_PKEY_free(pkey); - if (i && !ssl3_has_client_certificate(ssl)) { - i = 0; - } - if (i == 0) { - if (ssl->version == SSL3_VERSION) { - ssl->s3->tmp.cert_req = 0; - ssl3_send_alert(ssl, SSL3_AL_WARNING, SSL_AD_NO_CERTIFICATE); - return 1; - } else { - ssl->s3->tmp.cert_req = 2; - /* There is no client certificate, so the handshake buffer may be - * released. */ - ssl3_free_handshake_buffer(ssl); - } - } - - /* Ok, we have a cert */ - ssl->state = SSL3_ST_CW_CERT_C; - } - - if (ssl->state == SSL3_ST_CW_CERT_C) { - if (ssl->s3->tmp.cert_req == 2) { - /* Send an empty Certificate message. */ - uint8_t *p = ssl_handshake_start(ssl); - l2n3(0, p); - if (!ssl_set_handshake_header(ssl, SSL3_MT_CERTIFICATE, 3)) { - return -1; - } - } else if (!ssl3_output_cert_chain(ssl)) { - return -1; - } - ssl->state = SSL3_ST_CW_CERT_D; - } - - /* SSL3_ST_CW_CERT_D */ - return ssl_do_write(ssl); -} - -int ssl3_send_next_proto(SSL *ssl) { - if (ssl->state == SSL3_ST_CW_NEXT_PROTO_B) { - return ssl_do_write(ssl); - } - - assert(ssl->state == SSL3_ST_CW_NEXT_PROTO_A); - - static const uint8_t kZero[32] = {0}; - size_t padding_len = 32 - ((ssl->s3->next_proto_negotiated_len + 2) % 32); - - CBB cbb, child; - size_t length; - CBB_zero(&cbb); - if (!CBB_init_fixed(&cbb, ssl_handshake_start(ssl), - ssl->init_buf->max - SSL_HM_HEADER_LENGTH(ssl)) || - !CBB_add_u8_length_prefixed(&cbb, &child) || - !CBB_add_bytes(&child, ssl->s3->next_proto_negotiated, - ssl->s3->next_proto_negotiated_len) || - !CBB_add_u8_length_prefixed(&cbb, &child) || - !CBB_add_bytes(&child, kZero, padding_len) || - !CBB_finish(&cbb, NULL, &length) || - !ssl_set_handshake_header(ssl, SSL3_MT_NEXT_PROTO, length)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - CBB_cleanup(&cbb); - return -1; - } - - ssl->state = SSL3_ST_CW_NEXT_PROTO_B; - return ssl_do_write(ssl); -} - -int ssl3_send_channel_id(SSL *ssl) { - if (ssl->state == SSL3_ST_CW_CHANNEL_ID_B) { - return ssl_do_write(ssl); - } - - assert(ssl->state == SSL3_ST_CW_CHANNEL_ID_A); - - if (ssl->tlsext_channel_id_private == NULL && - ssl->ctx->channel_id_cb != NULL) { - EVP_PKEY *key = NULL; - ssl->ctx->channel_id_cb(ssl, &key); - if (key != NULL && - !SSL_set1_tls_channel_id(ssl, key)) { - EVP_PKEY_free(key); - return -1; - } - EVP_PKEY_free(key); - } - - if (ssl->tlsext_channel_id_private == NULL) { - ssl->rwstate = SSL_CHANNEL_ID_LOOKUP; - return -1; - } - ssl->rwstate = SSL_NOTHING; - - EC_KEY *ec_key = EVP_PKEY_get0_EC_KEY(ssl->tlsext_channel_id_private); - if (ec_key == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - return -1; - } - - int ret = -1; - BIGNUM *x = BN_new(); - BIGNUM *y = BN_new(); - ECDSA_SIG *sig = NULL; - if (x == NULL || y == NULL || - !EC_POINT_get_affine_coordinates_GFp(EC_KEY_get0_group(ec_key), - EC_KEY_get0_public_key(ec_key), - x, y, NULL)) { - goto err; - } - - uint8_t digest[EVP_MAX_MD_SIZE]; - size_t digest_len; - if (!tls1_channel_id_hash(ssl, digest, &digest_len)) { - goto err; - } - - sig = ECDSA_do_sign(digest, digest_len, ec_key); - if (sig == NULL) { - goto err; - } - - CBB cbb, child; - size_t length; - CBB_zero(&cbb); - if (!CBB_init_fixed(&cbb, ssl_handshake_start(ssl), - ssl->init_buf->max - SSL_HM_HEADER_LENGTH(ssl)) || - !CBB_add_u16(&cbb, TLSEXT_TYPE_channel_id) || - !CBB_add_u16_length_prefixed(&cbb, &child) || - !BN_bn2cbb_padded(&child, 32, x) || - !BN_bn2cbb_padded(&child, 32, y) || - !BN_bn2cbb_padded(&child, 32, sig->r) || - !BN_bn2cbb_padded(&child, 32, sig->s) || - !CBB_finish(&cbb, NULL, &length) || - !ssl_set_handshake_header(ssl, SSL3_MT_ENCRYPTED_EXTENSIONS, length)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - CBB_cleanup(&cbb); - goto err; - } - - ssl->state = SSL3_ST_CW_CHANNEL_ID_B; - ret = ssl_do_write(ssl); - -err: - BN_free(x); - BN_free(y); - ECDSA_SIG_free(sig); - return ret; -} - -int ssl_do_client_cert_cb(SSL *ssl, X509 **out_x509, EVP_PKEY **out_pkey) { - if (ssl->ctx->client_cert_cb == NULL) { - return 0; - } - return ssl->ctx->client_cert_cb(ssl, out_x509, out_pkey); -} - -int ssl3_verify_server_cert(SSL *ssl) { - int ret = ssl_verify_cert_chain(ssl, ssl->session->cert_chain); - if (ssl->verify_mode != SSL_VERIFY_NONE && ret <= 0) { - int al = ssl_verify_alarm_type(ssl->verify_result); - ssl3_send_alert(ssl, SSL3_AL_FATAL, al); - OPENSSL_PUT_ERROR(SSL, SSL_R_CERTIFICATE_VERIFY_FAILED); - } else { - ret = 1; - ERR_clear_error(); /* but we keep ssl->verify_result */ - } - - return ret; -} diff --git a/Sources/BoringSSL/ssl/s3_lib.c b/Sources/BoringSSL/ssl/s3_lib.c index b036b6419..57a27c707 100644 --- a/Sources/BoringSSL/ssl/s3_lib.c +++ b/Sources/BoringSSL/ssl/s3_lib.c @@ -149,7 +149,6 @@ #include #include -#include #include #include @@ -158,42 +157,26 @@ #include #include #include -#include +#include +#include "../crypto/internal.h" #include "internal.h" -int ssl3_supports_cipher(const SSL_CIPHER *cipher) { - return 1; -} - -int ssl3_set_handshake_header(SSL *ssl, int htype, unsigned long len) { - uint8_t *p = (uint8_t *)ssl->init_buf->data; - *(p++) = htype; - l2n3(len, p); - ssl->init_num = (int)len + SSL3_HM_HEADER_LENGTH; - ssl->init_off = 0; - - /* Add the message to the handshake hash. */ - return ssl3_update_handshake_hash(ssl, (uint8_t *)ssl->init_buf->data, - ssl->init_num); -} - -int ssl3_handshake_write(SSL *ssl) { - return ssl3_do_write(ssl, SSL3_RT_HANDSHAKE); -} - int ssl3_new(SSL *ssl) { SSL3_STATE *s3; s3 = OPENSSL_malloc(sizeof *s3); if (s3 == NULL) { - goto err; + return 0; } - memset(s3, 0, sizeof *s3); + OPENSSL_memset(s3, 0, sizeof *s3); - EVP_MD_CTX_init(&s3->handshake_hash); - EVP_MD_CTX_init(&s3->handshake_md5); + s3->hs = ssl_handshake_new(ssl); + if (s3->hs == NULL) { + OPENSSL_free(s3); + return 0; + } ssl->s3 = s3; @@ -204,8 +187,6 @@ int ssl3_new(SSL *ssl) { * at the API boundary rather than in internal state. */ ssl->version = TLS1_2_VERSION; return 1; -err: - return 0; } void ssl3_free(SSL *ssl) { @@ -213,369 +194,27 @@ void ssl3_free(SSL *ssl) { return; } - ssl3_cleanup_key_block(ssl); ssl_read_buffer_clear(ssl); ssl_write_buffer_clear(ssl); - SSL_ECDH_CTX_cleanup(&ssl->s3->tmp.ecdh_ctx); - OPENSSL_free(ssl->s3->tmp.peer_key); - sk_X509_NAME_pop_free(ssl->s3->tmp.ca_names, X509_NAME_free); - OPENSSL_free(ssl->s3->tmp.certificate_types); - OPENSSL_free(ssl->s3->tmp.peer_ellipticcurvelist); - OPENSSL_free(ssl->s3->tmp.peer_psk_identity_hint); - ssl3_free_handshake_buffer(ssl); - ssl3_free_handshake_hash(ssl); + SSL_SESSION_free(ssl->s3->established_session); + ssl_handshake_free(ssl->s3->hs); OPENSSL_free(ssl->s3->next_proto_negotiated); OPENSSL_free(ssl->s3->alpn_selected); SSL_AEAD_CTX_free(ssl->s3->aead_read_ctx); SSL_AEAD_CTX_free(ssl->s3->aead_write_ctx); + BUF_MEM_free(ssl->s3->pending_flight); OPENSSL_cleanse(ssl->s3, sizeof *ssl->s3); OPENSSL_free(ssl->s3); ssl->s3 = NULL; } -int SSL_session_reused(const SSL *ssl) { - return ssl->hit; -} - -int SSL_total_renegotiations(const SSL *ssl) { - return ssl->s3->total_renegotiations; -} - -int SSL_num_renegotiations(const SSL *ssl) { - return SSL_total_renegotiations(ssl); -} - -int SSL_CTX_need_tmp_RSA(const SSL_CTX *ctx) { - return 0; -} - -int SSL_need_rsa(const SSL *ssl) { - return 0; -} - -int SSL_CTX_set_tmp_rsa(SSL_CTX *ctx, const RSA *rsa) { - return 1; -} - -int SSL_set_tmp_rsa(SSL *ssl, const RSA *rsa) { - return 1; -} - -int SSL_CTX_set_tmp_dh(SSL_CTX *ctx, const DH *dh) { - DH_free(ctx->cert->dh_tmp); - ctx->cert->dh_tmp = DHparams_dup(dh); - if (ctx->cert->dh_tmp == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_DH_LIB); - return 0; - } - return 1; -} - -int SSL_set_tmp_dh(SSL *ssl, const DH *dh) { - DH_free(ssl->cert->dh_tmp); - ssl->cert->dh_tmp = DHparams_dup(dh); - if (ssl->cert->dh_tmp == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_DH_LIB); - return 0; - } - return 1; -} - -int SSL_CTX_set_tmp_ecdh(SSL_CTX *ctx, const EC_KEY *ec_key) { - if (ec_key == NULL || EC_KEY_get0_group(ec_key) == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_PASSED_NULL_PARAMETER); - return 0; - } - int nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec_key)); - return SSL_CTX_set1_curves(ctx, &nid, 1); -} - -int SSL_set_tmp_ecdh(SSL *ssl, const EC_KEY *ec_key) { - if (ec_key == NULL || EC_KEY_get0_group(ec_key) == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_PASSED_NULL_PARAMETER); - return 0; - } - int nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec_key)); - return SSL_set1_curves(ssl, &nid, 1); -} - -int SSL_CTX_enable_tls_channel_id(SSL_CTX *ctx) { - ctx->tlsext_channel_id_enabled = 1; - return 1; -} - -int SSL_enable_tls_channel_id(SSL *ssl) { - ssl->tlsext_channel_id_enabled = 1; - return 1; -} - -static int is_p256_key(EVP_PKEY *private_key) { - const EC_KEY *ec_key = EVP_PKEY_get0_EC_KEY(private_key); - return ec_key != NULL && - EC_GROUP_get_curve_name(EC_KEY_get0_group(ec_key)) == - NID_X9_62_prime256v1; -} - -int SSL_CTX_set1_tls_channel_id(SSL_CTX *ctx, EVP_PKEY *private_key) { - if (!is_p256_key(private_key)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_CHANNEL_ID_NOT_P256); - return 0; - } - - EVP_PKEY_free(ctx->tlsext_channel_id_private); - ctx->tlsext_channel_id_private = EVP_PKEY_up_ref(private_key); - ctx->tlsext_channel_id_enabled = 1; - - return 1; -} - -int SSL_set1_tls_channel_id(SSL *ssl, EVP_PKEY *private_key) { - if (!is_p256_key(private_key)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_CHANNEL_ID_NOT_P256); - return 0; - } - - EVP_PKEY_free(ssl->tlsext_channel_id_private); - ssl->tlsext_channel_id_private = EVP_PKEY_up_ref(private_key); - ssl->tlsext_channel_id_enabled = 1; - - return 1; -} - -size_t SSL_get_tls_channel_id(SSL *ssl, uint8_t *out, size_t max_out) { - if (!ssl->s3->tlsext_channel_id_valid) { - return 0; - } - memcpy(out, ssl->s3->tlsext_channel_id, (max_out < 64) ? max_out : 64); - return 64; -} - -int SSL_set_tlsext_host_name(SSL *ssl, const char *name) { - OPENSSL_free(ssl->tlsext_hostname); - ssl->tlsext_hostname = NULL; - - if (name == NULL) { - return 1; - } - if (strlen(name) > TLSEXT_MAXLEN_host_name) { - OPENSSL_PUT_ERROR(SSL, SSL_R_SSL3_EXT_INVALID_SERVERNAME); - return 0; - } - ssl->tlsext_hostname = BUF_strdup(name); - if (ssl->tlsext_hostname == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - return 0; - } - return 1; -} - -size_t SSL_get0_certificate_types(SSL *ssl, const uint8_t **out_types) { - if (ssl->server || !ssl->s3->tmp.cert_req) { - *out_types = NULL; - return 0; - } - *out_types = ssl->s3->tmp.certificate_types; - return ssl->s3->tmp.num_certificate_types; -} - -int SSL_CTX_set1_curves(SSL_CTX *ctx, const int *curves, size_t curves_len) { - return tls1_set_curves(&ctx->tlsext_ellipticcurvelist, - &ctx->tlsext_ellipticcurvelist_length, curves, - curves_len); -} - -int SSL_set1_curves(SSL *ssl, const int *curves, size_t curves_len) { - return tls1_set_curves(&ssl->tlsext_ellipticcurvelist, - &ssl->tlsext_ellipticcurvelist_length, curves, - curves_len); -} - -int SSL_CTX_set_tlsext_servername_callback( - SSL_CTX *ctx, int (*callback)(SSL *ssl, int *out_alert, void *arg)) { - ctx->tlsext_servername_callback = callback; - return 1; -} - -int SSL_CTX_set_tlsext_servername_arg(SSL_CTX *ctx, void *arg) { - ctx->tlsext_servername_arg = arg; - return 1; -} - -int SSL_CTX_get_tlsext_ticket_keys(SSL_CTX *ctx, void *out, size_t len) { - if (out == NULL) { - return 48; - } - if (len != 48) { - OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_TICKET_KEYS_LENGTH); - return 0; - } - uint8_t *out_bytes = out; - memcpy(out_bytes, ctx->tlsext_tick_key_name, 16); - memcpy(out_bytes + 16, ctx->tlsext_tick_hmac_key, 16); - memcpy(out_bytes + 32, ctx->tlsext_tick_aes_key, 16); - return 1; -} - -int SSL_CTX_set_tlsext_ticket_keys(SSL_CTX *ctx, const void *in, size_t len) { - if (in == NULL) { - return 48; - } - if (len != 48) { - OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_TICKET_KEYS_LENGTH); - return 0; - } - const uint8_t *in_bytes = in; - memcpy(ctx->tlsext_tick_key_name, in_bytes, 16); - memcpy(ctx->tlsext_tick_hmac_key, in_bytes + 16, 16); - memcpy(ctx->tlsext_tick_aes_key, in_bytes + 32, 16); - return 1; -} - -int SSL_CTX_set_tlsext_ticket_key_cb( - SSL_CTX *ctx, int (*callback)(SSL *ssl, uint8_t *key_name, uint8_t *iv, - EVP_CIPHER_CTX *ctx, HMAC_CTX *hmac_ctx, - int encrypt)) { - ctx->tlsext_ticket_key_cb = callback; - return 1; -} - -struct ssl_cipher_preference_list_st *ssl_get_cipher_preferences(SSL *ssl) { +const struct ssl_cipher_preference_list_st *ssl_get_cipher_preferences( + const SSL *ssl) { if (ssl->cipher_list != NULL) { return ssl->cipher_list; } - if (ssl->version >= TLS1_1_VERSION && ssl->ctx != NULL && - ssl->ctx->cipher_list_tls11 != NULL) { - return ssl->ctx->cipher_list_tls11; - } - - if (ssl->version >= TLS1_VERSION && ssl->ctx != NULL && - ssl->ctx->cipher_list_tls10 != NULL) { - return ssl->ctx->cipher_list_tls10; - } - - if (ssl->ctx != NULL && ssl->ctx->cipher_list != NULL) { - return ssl->ctx->cipher_list; - } - - return NULL; -} - -const SSL_CIPHER *ssl3_choose_cipher( - SSL *ssl, STACK_OF(SSL_CIPHER) *clnt, - struct ssl_cipher_preference_list_st *server_pref) { - const SSL_CIPHER *c, *ret = NULL; - STACK_OF(SSL_CIPHER) *srvr = server_pref->ciphers, *prio, *allow; - size_t i; - int ok; - size_t cipher_index; - uint32_t alg_k, alg_a, mask_k, mask_a; - /* in_group_flags will either be NULL, or will point to an array of bytes - * which indicate equal-preference groups in the |prio| stack. See the - * comment about |in_group_flags| in the |ssl_cipher_preference_list_st| - * struct. */ - const uint8_t *in_group_flags; - /* group_min contains the minimal index so far found in a group, or -1 if no - * such value exists yet. */ - int group_min = -1; - - if (ssl->options & SSL_OP_CIPHER_SERVER_PREFERENCE) { - prio = srvr; - in_group_flags = server_pref->in_group_flags; - allow = clnt; - } else { - prio = clnt; - in_group_flags = NULL; - allow = srvr; - } - - ssl_get_compatible_server_ciphers(ssl, &mask_k, &mask_a); - - for (i = 0; i < sk_SSL_CIPHER_num(prio); i++) { - c = sk_SSL_CIPHER_value(prio, i); - - ok = 1; - - /* Check the TLS version. */ - if (SSL_CIPHER_get_min_version(c) > ssl3_protocol_version(ssl)) { - ok = 0; - } - - alg_k = c->algorithm_mkey; - alg_a = c->algorithm_auth; - - ok = ok && (alg_k & mask_k) && (alg_a & mask_a); - - if (ok && sk_SSL_CIPHER_find(allow, &cipher_index, c)) { - if (in_group_flags != NULL && in_group_flags[i] == 1) { - /* This element of |prio| is in a group. Update the minimum index found - * so far and continue looking. */ - if (group_min == -1 || (size_t)group_min > cipher_index) { - group_min = cipher_index; - } - } else { - if (group_min != -1 && (size_t)group_min < cipher_index) { - cipher_index = group_min; - } - ret = sk_SSL_CIPHER_value(allow, cipher_index); - break; - } - } - - if (in_group_flags != NULL && in_group_flags[i] == 0 && group_min != -1) { - /* We are about to leave a group, but we found a match in it, so that's - * our answer. */ - ret = sk_SSL_CIPHER_value(allow, group_min); - break; - } - } - - return ret; -} - -int ssl3_get_req_cert_type(SSL *ssl, uint8_t *p) { - int ret = 0; - const uint8_t *sig; - size_t i, siglen; - int have_rsa_sign = 0; - int have_ecdsa_sign = 0; - - /* get configured sigalgs */ - siglen = tls12_get_psigalgs(ssl, &sig); - for (i = 0; i < siglen; i += 2, sig += 2) { - switch (sig[1]) { - case TLSEXT_signature_rsa: - have_rsa_sign = 1; - break; - - case TLSEXT_signature_ecdsa: - have_ecdsa_sign = 1; - break; - } - } - - if (have_rsa_sign) { - p[ret++] = SSL3_CT_RSA_SIGN; - } - - /* ECDSA certs can be used with RSA cipher suites as well so we don't need to - * check for SSL_kECDH or SSL_kECDHE. */ - if (ssl->version >= TLS1_VERSION && have_ecdsa_sign) { - p[ret++] = TLS_CT_ECDSA_SIGN; - } - - return ret; -} - -/* If we are using default SHA1+MD5 algorithms switch to new SHA256 PRF and - * handshake macs if required. */ -uint32_t ssl_get_algorithm_prf(const SSL *ssl) { - uint32_t algorithm_prf = ssl->s3->tmp.new_cipher->algorithm_prf; - if (algorithm_prf == SSL_HANDSHAKE_MAC_DEFAULT && - ssl3_protocol_version(ssl) >= TLS1_2_VERSION) { - return SSL_HANDSHAKE_MAC_SHA256; - } - return algorithm_prf; + return ssl->ctx->cipher_list; } diff --git a/Sources/BoringSSL/ssl/s3_pkt.c b/Sources/BoringSSL/ssl/s3_pkt.c index 81d163e86..2f919caed 100644 --- a/Sources/BoringSSL/ssl/s3_pkt.c +++ b/Sources/BoringSSL/ssl/s3_pkt.c @@ -110,7 +110,6 @@ #include #include -#include #include #include @@ -119,59 +118,66 @@ #include #include +#include "../crypto/internal.h" #include "internal.h" static int do_ssl3_write(SSL *ssl, int type, const uint8_t *buf, unsigned len); -/* kMaxWarningAlerts is the number of consecutive warning alerts that will be - * processed. */ -static const uint8_t kMaxWarningAlerts = 4; - /* ssl3_get_record reads a new input record. On success, it places it in * |ssl->s3->rrec| and returns one. Otherwise it returns <= 0 on error or if * more data is needed. */ static int ssl3_get_record(SSL *ssl) { - int ret; again: - /* Ensure the buffer is large enough to decrypt in-place. */ - ret = ssl_read_buffer_extend_to(ssl, ssl_record_prefix_len(ssl)); - if (ret <= 0) { - return ret; + switch (ssl->s3->recv_shutdown) { + case ssl_shutdown_none: + break; + case ssl_shutdown_fatal_alert: + OPENSSL_PUT_ERROR(SSL, SSL_R_PROTOCOL_IS_SHUTDOWN); + return -1; + case ssl_shutdown_close_notify: + return 0; } - assert(ssl_read_buffer_len(ssl) >= ssl_record_prefix_len(ssl)); - - uint8_t *out = ssl_read_buffer(ssl) + ssl_record_prefix_len(ssl); - size_t max_out = ssl_read_buffer_len(ssl) - ssl_record_prefix_len(ssl); - uint8_t type, alert; - size_t len, consumed; - switch (tls_open_record(ssl, &type, out, &len, &consumed, &alert, max_out, - ssl_read_buffer(ssl), ssl_read_buffer_len(ssl))) { - case ssl_open_record_success: - ssl_read_buffer_consume(ssl, consumed); - if (len > 0xffff) { + CBS body; + uint8_t type, alert = SSL_AD_DECODE_ERROR; + size_t consumed; + enum ssl_open_record_t open_ret = + tls_open_record(ssl, &type, &body, &consumed, &alert, + ssl_read_buffer(ssl), ssl_read_buffer_len(ssl)); + if (open_ret != ssl_open_record_partial) { + ssl_read_buffer_consume(ssl, consumed); + } + switch (open_ret) { + case ssl_open_record_partial: { + int read_ret = ssl_read_buffer_extend_to(ssl, consumed); + if (read_ret <= 0) { + return read_ret; + } + goto again; + } + + case ssl_open_record_success: + if (CBS_len(&body) > 0xffff) { OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW); return -1; } SSL3_RECORD *rr = &ssl->s3->rrec; rr->type = type; - rr->length = (uint16_t)len; - rr->data = out; + rr->length = (uint16_t)CBS_len(&body); + rr->data = (uint8_t *)CBS_data(&body); return 1; - case ssl_open_record_partial: - ret = ssl_read_buffer_extend_to(ssl, consumed); - if (ret <= 0) { - return ret; - } - goto again; - case ssl_open_record_discard: - ssl_read_buffer_consume(ssl, consumed); goto again; + case ssl_open_record_close_notify: + return 0; + + case ssl_open_record_fatal_alert: + return -1; + case ssl_open_record_error: ssl3_send_alert(ssl, SSL3_AL_FATAL, alert); return -1; @@ -182,33 +188,15 @@ static int ssl3_get_record(SSL *ssl) { return -1; } -int ssl3_write_app_data(SSL *ssl, const void *buf, int len) { - return ssl3_write_bytes(ssl, SSL3_RT_APPLICATION_DATA, buf, len); -} +int ssl3_write_app_data(SSL *ssl, const uint8_t *buf, int len) { + assert(!SSL_in_init(ssl) || SSL_in_false_start(ssl)); -/* Call this to write data in records of type |type|. It will return <= 0 if - * not all data has been sent or non-blocking IO. */ -int ssl3_write_bytes(SSL *ssl, int type, const void *buf_, int len) { - const uint8_t *buf = buf_; - unsigned int tot, n, nw; - int i; + unsigned tot, n, nw; - ssl->rwstate = SSL_NOTHING; assert(ssl->s3->wnum <= INT_MAX); tot = ssl->s3->wnum; ssl->s3->wnum = 0; - if (!ssl->in_handshake && SSL_in_init(ssl) && !SSL_in_false_start(ssl)) { - i = ssl->handshake_func(ssl); - if (i < 0) { - return i; - } - if (i == 0) { - OPENSSL_PUT_ERROR(SSL, SSL_R_SSL_HANDSHAKE_FAILURE); - return -1; - } - } - /* Ensure that if we end up with a smaller value of data to write out than * the the original len from a write which didn't complete for non-blocking * I/O and also somehow ended up avoiding the check for this in @@ -221,7 +209,7 @@ int ssl3_write_bytes(SSL *ssl, int type, const void *buf_, int len) { return -1; } - n = (len - tot); + n = len - tot; for (;;) { /* max contains the maximum number of bytes that we can put into a * record. */ @@ -232,27 +220,26 @@ int ssl3_write_bytes(SSL *ssl, int type, const void *buf_, int len) { nw = n; } - i = do_ssl3_write(ssl, type, &buf[tot], nw); - if (i <= 0) { + int ret = do_ssl3_write(ssl, SSL3_RT_APPLICATION_DATA, &buf[tot], nw); + if (ret <= 0) { ssl->s3->wnum = tot; - return i; + return ret; } - if (i == (int)n || (type == SSL3_RT_APPLICATION_DATA && - (ssl->mode & SSL_MODE_ENABLE_PARTIAL_WRITE))) { - return tot + i; + if (ret == (int)n || (ssl->mode & SSL_MODE_ENABLE_PARTIAL_WRITE)) { + return tot + ret; } - n -= i; - tot += i; + n -= ret; + tot += ret; } } static int ssl3_write_pending(SSL *ssl, int type, const uint8_t *buf, unsigned int len) { if (ssl->s3->wpend_tot > (int)len || - (ssl->s3->wpend_buf != buf && - !(ssl->mode & SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER)) || + (!(ssl->mode & SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER) && + ssl->s3->wpend_buf != buf) || ssl->s3->wpend_type != type) { OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_WRITE_RETRY); return -1; @@ -272,13 +259,12 @@ static int do_ssl3_write(SSL *ssl, int type, const uint8_t *buf, unsigned len) { return ssl3_write_pending(ssl, type, buf, len); } - /* If we have an alert to send, lets send it */ - if (ssl->s3->alert_dispatch) { - int ret = ssl->method->ssl_dispatch_alert(ssl); - if (ret <= 0) { - return ret; - } - /* if it went, fall through and send more stuff */ + /* The handshake flight buffer is mutually exclusive with application data. + * + * TODO(davidben): This will not be true when closure alerts use this. */ + if (ssl->s3->pending_flight != NULL) { + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + return -1; } if (len > SSL3_RT_MAX_PLAIN_LENGTH) { @@ -290,7 +276,7 @@ static int do_ssl3_write(SSL *ssl, int type, const uint8_t *buf, unsigned len) { return 0; } - size_t max_out = len + ssl_max_seal_overhead(ssl); + size_t max_out = len + SSL_max_seal_overhead(ssl); if (max_out < len) { OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW); return -1; @@ -314,333 +300,158 @@ static int do_ssl3_write(SSL *ssl, int type, const uint8_t *buf, unsigned len) { return ssl3_write_pending(ssl, type, buf, len); } -int ssl3_read_app_data(SSL *ssl, uint8_t *buf, int len, int peek) { - return ssl3_read_bytes(ssl, SSL3_RT_APPLICATION_DATA, buf, len, peek); -} +static int consume_record(SSL *ssl, uint8_t *out, int len, int peek) { + SSL3_RECORD *rr = &ssl->s3->rrec; -int ssl3_read_change_cipher_spec(SSL *ssl) { - uint8_t byte; - int ret = ssl3_read_bytes(ssl, SSL3_RT_CHANGE_CIPHER_SPEC, &byte, 1 /* len */, - 0 /* no peek */); - if (ret <= 0) { - return ret; + if (len <= 0) { + return len; } - assert(ret == 1); - if (ssl->s3->rrec.length != 0 || byte != SSL3_MT_CCS) { - OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_CHANGE_CIPHER_SPEC); - ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER); - return -1; + if (len > (int)rr->length) { + len = (int)rr->length; } - if (ssl->msg_callback != NULL) { - ssl->msg_callback(0, ssl->version, SSL3_RT_CHANGE_CIPHER_SPEC, &byte, 1, - ssl, ssl->msg_callback_arg); + OPENSSL_memcpy(out, rr->data, len); + if (!peek) { + rr->length -= len; + rr->data += len; + if (rr->length == 0) { + /* The record has been consumed, so we may now clear the buffer. */ + ssl_read_buffer_discard(ssl); + } } - - return 1; + return len; } -void ssl3_read_close_notify(SSL *ssl) { - ssl3_read_bytes(ssl, 0, NULL, 0, 0); -} +int ssl3_read_app_data(SSL *ssl, int *out_got_handshake, uint8_t *buf, int len, + int peek) { + assert(!SSL_in_init(ssl)); + assert(ssl->s3->initial_handshake_complete); + *out_got_handshake = 0; -static int ssl3_can_renegotiate(SSL *ssl) { - switch (ssl->renegotiate_mode) { - case ssl_renegotiate_never: - return 0; - case ssl_renegotiate_once: - return ssl->s3->total_renegotiations == 0; - case ssl_renegotiate_freely: - return 1; - case ssl_renegotiate_ignore: - return 1; - } + SSL3_RECORD *rr = &ssl->s3->rrec; - assert(0); - return 0; -} + for (;;) { + /* A previous iteration may have read a partial handshake message. Do not + * allow more app data in that case. */ + int has_hs_data = ssl->init_buf != NULL && ssl->init_buf->length > 0; -/* Return up to 'len' payload bytes received in 'type' records. - * 'type' is one of the following: - * - * - SSL3_RT_HANDSHAKE (when ssl3_get_message calls us) - * - SSL3_RT_CHANGE_CIPHER_SPEC (when ssl3_read_change_cipher_spec calls us) - * - SSL3_RT_APPLICATION_DATA (when ssl3_read_app_data calls us) - * - 0 (during a shutdown, no data has to be returned) - * - * If we don't have stored data to work from, read a SSL/TLS record first - * (possibly multiple records if we still don't have anything to return). - * - * This function must handle any surprises the peer may have for us, such as - * Alert records (e.g. close_notify) or renegotiation requests. */ -int ssl3_read_bytes(SSL *ssl, int type, uint8_t *buf, int len, int peek) { - int al, i, ret; - unsigned int n; - SSL3_RECORD *rr; - void (*cb)(const SSL *ssl, int type, int value) = NULL; - - if ((type && type != SSL3_RT_APPLICATION_DATA && type != SSL3_RT_HANDSHAKE && - type != SSL3_RT_CHANGE_CIPHER_SPEC) || - (peek && type != SSL3_RT_APPLICATION_DATA)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - return -1; - } + /* Get new packet if necessary. */ + if (rr->length == 0 && !has_hs_data) { + int ret = ssl3_get_record(ssl); + if (ret <= 0) { + return ret; + } + } - /* This may require multiple iterations. False Start will cause - * |ssl->handshake_func| to signal success one step early, but the handshake - * must be completely finished before other modes are accepted. - * - * TODO(davidben): Move this check up to a higher level. */ - while (!ssl->in_handshake && SSL_in_init(ssl)) { - assert(type == SSL3_RT_APPLICATION_DATA); - i = ssl->handshake_func(ssl); - if (i < 0) { - return i; + if (has_hs_data || rr->type == SSL3_RT_HANDSHAKE) { + /* Post-handshake data prior to TLS 1.3 is always renegotiation, which we + * never accept as a server. Otherwise |ssl3_get_message| will send + * |SSL_R_EXCESSIVE_MESSAGE_SIZE|. */ + if (ssl->server && ssl3_protocol_version(ssl) < TLS1_3_VERSION) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_NO_RENEGOTIATION); + OPENSSL_PUT_ERROR(SSL, SSL_R_NO_RENEGOTIATION); + return -1; + } + + /* Parse post-handshake handshake messages. */ + int ret = ssl3_get_message(ssl); + if (ret <= 0) { + return ret; + } + *out_got_handshake = 1; + return -1; } - if (i == 0) { - OPENSSL_PUT_ERROR(SSL, SSL_R_SSL_HANDSHAKE_FAILURE); + + if (rr->type != SSL3_RT_APPLICATION_DATA) { + OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_RECORD); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE); return -1; } - } -start: - ssl->rwstate = SSL_NOTHING; + if (rr->length != 0) { + return consume_record(ssl, buf, len, peek); + } + + /* Discard empty records and loop again. */ + } +} - /* ssl->s3->rrec.type - is the type of record - * ssl->s3->rrec.data - data - * ssl->s3->rrec.off - offset into 'data' for next read - * ssl->s3->rrec.length - number of bytes. */ - rr = &ssl->s3->rrec; +int ssl3_read_change_cipher_spec(SSL *ssl) { + SSL3_RECORD *rr = &ssl->s3->rrec; - /* get new packet if necessary */ if (rr->length == 0) { - ret = ssl3_get_record(ssl); + int ret = ssl3_get_record(ssl); if (ret <= 0) { return ret; } } - /* we now have a packet which can be read and processed */ - - /* If the other end has shut down, throw anything we read away (even in - * 'peek' mode) */ - if (ssl->shutdown & SSL_RECEIVED_SHUTDOWN) { - rr->length = 0; - ssl->rwstate = SSL_NOTHING; - return 0; + if (rr->type != SSL3_RT_CHANGE_CIPHER_SPEC) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE); + OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_RECORD); + return -1; } - if (type != 0 && type == rr->type) { - ssl->s3->warning_alert_count = 0; - - /* Make sure that we are not getting application data when we are doing a - * handshake for the first time. */ - if (SSL_in_init(ssl) && type == SSL3_RT_APPLICATION_DATA && - ssl->s3->aead_read_ctx == NULL) { - /* TODO(davidben): Is this check redundant with the handshake_func - * check? */ - al = SSL_AD_UNEXPECTED_MESSAGE; - OPENSSL_PUT_ERROR(SSL, SSL_R_APP_DATA_IN_HANDSHAKE); - goto f_err; - } - - /* Discard empty records. */ - if (rr->length == 0) { - goto start; - } - - if (len <= 0) { - return len; - } + if (rr->length != 1 || rr->data[0] != SSL3_MT_CCS) { + OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_CHANGE_CIPHER_SPEC); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER); + return -1; + } - if ((unsigned int)len > rr->length) { - n = rr->length; - } else { - n = (unsigned int)len; - } + ssl_do_msg_callback(ssl, 0 /* read */, SSL3_RT_CHANGE_CIPHER_SPEC, rr->data, + rr->length); - memcpy(buf, rr->data, n); - if (!peek) { - rr->length -= n; - rr->data += n; - if (rr->length == 0) { - /* The record has been consumed, so we may now clear the buffer. */ - ssl_read_buffer_discard(ssl); - } - } + rr->length = 0; + ssl_read_buffer_discard(ssl); + return 1; +} - return n; +void ssl3_read_close_notify(SSL *ssl) { + /* Read records until an error or close_notify. */ + while (ssl3_get_record(ssl) > 0) { + ; } +} - /* Process unexpected records. */ - - if (type == SSL3_RT_APPLICATION_DATA && rr->type == SSL3_RT_HANDSHAKE) { - /* If peer renegotiations are disabled, all out-of-order handshake records - * are fatal. Renegotiations as a server are never supported. */ - if (ssl->server || !ssl3_can_renegotiate(ssl)) { - al = SSL_AD_NO_RENEGOTIATION; - OPENSSL_PUT_ERROR(SSL, SSL_R_NO_RENEGOTIATION); - goto f_err; - } +int ssl3_read_handshake_bytes(SSL *ssl, uint8_t *buf, int len) { + SSL3_RECORD *rr = &ssl->s3->rrec; - /* This must be a HelloRequest, possibly fragmented over multiple records. - * Consume data from the handshake protocol until it is complete. */ - static const uint8_t kHelloRequest[] = {SSL3_MT_HELLO_REQUEST, 0, 0, 0}; - while (ssl->s3->hello_request_len < sizeof(kHelloRequest)) { - if (rr->length == 0) { - /* Get a new record. */ - goto start; - } - if (rr->data[0] != kHelloRequest[ssl->s3->hello_request_len]) { - al = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_HELLO_REQUEST); - goto f_err; + for (;;) { + /* Get new packet if necessary. */ + if (rr->length == 0) { + int ret = ssl3_get_record(ssl); + if (ret <= 0) { + return ret; } - rr->data++; - rr->length--; - ssl->s3->hello_request_len++; - } - ssl->s3->hello_request_len = 0; - - if (ssl->msg_callback) { - ssl->msg_callback(0, ssl->version, SSL3_RT_HANDSHAKE, kHelloRequest, - sizeof(kHelloRequest), ssl, ssl->msg_callback_arg); - } - - if (!SSL_is_init_finished(ssl) || !ssl->s3->initial_handshake_complete) { - /* This cannot happen. If a handshake is in progress, |type| must be - * |SSL3_RT_HANDSHAKE|. */ - assert(0); - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - goto err; - } - - if (ssl->renegotiate_mode == ssl_renegotiate_ignore) { - goto start; - } - - /* Renegotiation is only supported at quiescent points in the application - * protocol, namely in HTTPS, just before reading the HTTP response. Require - * the record-layer be idle and avoid complexities of sending a handshake - * record while an application_data record is being written. */ - if (ssl_write_buffer_is_pending(ssl)) { - al = SSL_AD_NO_RENEGOTIATION; - OPENSSL_PUT_ERROR(SSL, SSL_R_NO_RENEGOTIATION); - goto f_err; } - /* Begin a new handshake. */ - ssl->s3->total_renegotiations++; - ssl->state = SSL_ST_CONNECT; - i = ssl->handshake_func(ssl); - if (i < 0) { - return i; - } - if (i == 0) { - OPENSSL_PUT_ERROR(SSL, SSL_R_SSL_HANDSHAKE_FAILURE); + if (rr->type != SSL3_RT_HANDSHAKE) { + OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_RECORD); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE); return -1; } - /* The handshake completed synchronously. Continue reading records. */ - goto start; - } - - /* If an alert record, process one alert out of the record. Note that we allow - * a single record to contain multiple alerts. */ - if (rr->type == SSL3_RT_ALERT) { - /* Alerts may not be fragmented. */ - if (rr->length < 2) { - al = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ALERT); - goto f_err; - } - - if (ssl->msg_callback) { - ssl->msg_callback(0, ssl->version, SSL3_RT_ALERT, rr->data, 2, ssl, - ssl->msg_callback_arg); - } - const uint8_t alert_level = rr->data[0]; - const uint8_t alert_descr = rr->data[1]; - rr->length -= 2; - rr->data += 2; - - if (ssl->info_callback != NULL) { - cb = ssl->info_callback; - } else if (ssl->ctx->info_callback != NULL) { - cb = ssl->ctx->info_callback; - } - - if (cb != NULL) { - uint16_t alert = (alert_level << 8) | alert_descr; - cb(ssl, SSL_CB_READ_ALERT, alert); - } - - if (alert_level == SSL3_AL_WARNING) { - ssl->s3->warn_alert = alert_descr; - if (alert_descr == SSL_AD_CLOSE_NOTIFY) { - ssl->shutdown |= SSL_RECEIVED_SHUTDOWN; - return 0; - } - - /* This is a warning but we receive it if we requested renegotiation and - * the peer denied it. Terminate with a fatal alert because if - * application tried to renegotiatie it presumably had a good reason and - * expects it to succeed. - * - * In future we might have a renegotiation where we don't care if the - * peer refused it where we carry on. */ - else if (alert_descr == SSL_AD_NO_RENEGOTIATION) { - al = SSL_AD_HANDSHAKE_FAILURE; - OPENSSL_PUT_ERROR(SSL, SSL_R_NO_RENEGOTIATION); - goto f_err; - } - - ssl->s3->warning_alert_count++; - if (ssl->s3->warning_alert_count > kMaxWarningAlerts) { - al = SSL_AD_UNEXPECTED_MESSAGE; - OPENSSL_PUT_ERROR(SSL, SSL_R_TOO_MANY_WARNING_ALERTS); - goto f_err; - } - } else if (alert_level == SSL3_AL_FATAL) { - char tmp[16]; - - ssl->rwstate = SSL_NOTHING; - ssl->s3->fatal_alert = alert_descr; - OPENSSL_PUT_ERROR(SSL, SSL_AD_REASON_OFFSET + alert_descr); - BIO_snprintf(tmp, sizeof(tmp), "%d", alert_descr); - ERR_add_error_data(2, "SSL alert number ", tmp); - ssl->shutdown |= SSL_RECEIVED_SHUTDOWN; - SSL_CTX_remove_session(ssl->ctx, ssl->session); - return 0; - } else { - al = SSL_AD_ILLEGAL_PARAMETER; - OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_ALERT_TYPE); - goto f_err; + if (rr->length != 0) { + return consume_record(ssl, buf, len, 0 /* consume data */); } - goto start; - } - - if (ssl->shutdown & SSL_SENT_SHUTDOWN) { - /* close_notify has been sent, so discard all records other than alerts. */ - rr->length = 0; - goto start; + /* Discard empty records and loop again. */ } - - al = SSL_AD_UNEXPECTED_MESSAGE; - OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_RECORD); - -f_err: - ssl3_send_alert(ssl, SSL3_AL_FATAL, al); -err: - return -1; } int ssl3_send_alert(SSL *ssl, int level, int desc) { - /* If a fatal one, remove from cache */ - if (level == 2 && ssl->session != NULL) { - SSL_CTX_remove_session(ssl->ctx, ssl->session); + /* It is illegal to send an alert when we've already sent a closing one. */ + if (ssl->s3->send_shutdown != ssl_shutdown_none) { + OPENSSL_PUT_ERROR(SSL, SSL_R_PROTOCOL_IS_SHUTDOWN); + return -1; + } + + if (level == SSL3_AL_WARNING && desc == SSL_AD_CLOSE_NOTIFY) { + ssl->s3->send_shutdown = ssl_shutdown_close_notify; + } else { + assert(level == SSL3_AL_FATAL); + ssl->s3->send_shutdown = ssl_shutdown_fatal_alert; } ssl->s3->alert_dispatch = 1; @@ -649,45 +460,30 @@ int ssl3_send_alert(SSL *ssl, int level, int desc) { if (!ssl_write_buffer_is_pending(ssl)) { /* Nothing is being written out, so the alert may be dispatched * immediately. */ - return ssl->method->ssl_dispatch_alert(ssl); + return ssl->method->dispatch_alert(ssl); } - /* else data is still being written out, we will get written some time in the - * future */ + /* The alert will be dispatched later. */ return -1; } int ssl3_dispatch_alert(SSL *ssl) { - int i, j; - void (*cb)(const SSL *ssl, int type, int value) = NULL; - + int ret = do_ssl3_write(ssl, SSL3_RT_ALERT, &ssl->s3->send_alert[0], 2); + if (ret <= 0) { + return ret; + } ssl->s3->alert_dispatch = 0; - i = do_ssl3_write(ssl, SSL3_RT_ALERT, &ssl->s3->send_alert[0], 2); - if (i <= 0) { - ssl->s3->alert_dispatch = 1; - } else { - /* Alert sent to BIO. If it is important, flush it now. If the message - * does not get sent due to non-blocking IO, we will not worry too much. */ - if (ssl->s3->send_alert[0] == SSL3_AL_FATAL) { - BIO_flush(ssl->wbio); - } - if (ssl->msg_callback) { - ssl->msg_callback(1, ssl->version, SSL3_RT_ALERT, ssl->s3->send_alert, 2, - ssl, ssl->msg_callback_arg); - } + /* If the alert is fatal, flush the BIO now. */ + if (ssl->s3->send_alert[0] == SSL3_AL_FATAL) { + BIO_flush(ssl->wbio); + } - if (ssl->info_callback != NULL) { - cb = ssl->info_callback; - } else if (ssl->ctx->info_callback != NULL) { - cb = ssl->ctx->info_callback; - } + ssl_do_msg_callback(ssl, 1 /* write */, SSL3_RT_ALERT, ssl->s3->send_alert, + 2); - if (cb != NULL) { - j = (ssl->s3->send_alert[0] << 8) | ssl->s3->send_alert[1]; - cb(ssl, SSL_CB_WRITE_ALERT, j); - } - } + int alert = (ssl->s3->send_alert[0] << 8) | ssl->s3->send_alert[1]; + ssl_do_info_callback(ssl, SSL_CB_WRITE_ALERT, alert); - return i; + return 1; } diff --git a/Sources/BoringSSL/ssl/s3_srvr.c b/Sources/BoringSSL/ssl/s3_srvr.c deleted file mode 100644 index ae709dc36..000000000 --- a/Sources/BoringSSL/ssl/s3_srvr.c +++ /dev/null @@ -1,2272 +0,0 @@ -/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) - * All rights reserved. - * - * This package is an SSL implementation written - * by Eric Young (eay@cryptsoft.com). - * The implementation was written so as to conform with Netscapes SSL. - * - * This library is free for commercial and non-commercial use as long as - * the following conditions are aheared to. The following conditions - * apply to all code found in this distribution, be it the RC4, RSA, - * lhash, DES, etc., code; not just the SSL code. The SSL documentation - * included with this distribution is covered by the same copyright terms - * except that the holder is Tim Hudson (tjh@cryptsoft.com). - * - * Copyright remains Eric Young's, and as such any Copyright notices in - * the code are not to be removed. - * If this package is used in a product, Eric Young should be given attribution - * as the author of the parts of the library used. - * This can be in the form of a textual message at program startup or - * in documentation (online or textual) provided with the package. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * "This product includes cryptographic software written by - * Eric Young (eay@cryptsoft.com)" - * The word 'cryptographic' can be left out if the rouines from the library - * being used are not cryptographic related :-). - * 4. If you include any Windows specific code (or a derivative thereof) from - * the apps directory (application code) you must include an acknowledgement: - * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" - * - * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * The licence and distribution terms for any publically available version or - * derivative of this code cannot be changed. i.e. this code cannot simply be - * copied and put under another distribution licence - * [including the GNU Public Licence.] - */ -/* ==================================================================== - * Copyright (c) 1998-2007 The OpenSSL Project. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the OpenSSL Project - * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" - * - * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to - * endorse or promote products derived from this software without - * prior written permission. For written permission, please contact - * openssl-core@openssl.org. - * - * 5. Products derived from this software may not be called "OpenSSL" - * nor may "OpenSSL" appear in their names without prior written - * permission of the OpenSSL Project. - * - * 6. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the OpenSSL Project - * for use in the OpenSSL Toolkit (http://www.openssl.org/)" - * - * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This product includes cryptographic software written by Eric Young - * (eay@cryptsoft.com). This product includes software written by Tim - * Hudson (tjh@cryptsoft.com). - * - */ -/* ==================================================================== - * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. - * - * Portions of the attached software ("Contribution") are developed by - * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project. - * - * The Contribution is licensed pursuant to the OpenSSL open source - * license provided above. - * - * ECC cipher suite support in OpenSSL originally written by - * Vipul Gupta and Sumit Gupta of Sun Microsystems Laboratories. - * - */ -/* ==================================================================== - * Copyright 2005 Nokia. All rights reserved. - * - * The portions of the attached software ("Contribution") is developed by - * Nokia Corporation and is licensed pursuant to the OpenSSL open source - * license. - * - * The Contribution, originally written by Mika Kousa and Pasi Eronen of - * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites - * support (see RFC 4279) to OpenSSL. - * - * No patent licenses or other rights except those expressly stated in - * the OpenSSL open source license shall be deemed granted or received - * expressly, by implication, estoppel, or otherwise. - * - * No assurances are provided by Nokia that the Contribution does not - * infringe the patent or other intellectual property rights of any third - * party or that the license provides you with all the necessary rights - * to make use of the Contribution. - * - * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN - * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA - * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY - * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR - * OTHERWISE. */ - -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "internal.h" -#include "../crypto/internal.h" -#include "../crypto/dh/internal.h" - - -int ssl3_accept(SSL *ssl) { - BUF_MEM *buf = NULL; - uint32_t alg_a; - void (*cb)(const SSL *ssl, int type, int value) = NULL; - int ret = -1; - int new_state, state, skip = 0; - - assert(ssl->handshake_func == ssl3_accept); - assert(ssl->server); - assert(!SSL_IS_DTLS(ssl)); - - ERR_clear_error(); - ERR_clear_system_error(); - - if (ssl->info_callback != NULL) { - cb = ssl->info_callback; - } else if (ssl->ctx->info_callback != NULL) { - cb = ssl->ctx->info_callback; - } - - ssl->in_handshake++; - - if (ssl->cert == NULL) { - OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CERTIFICATE_SET); - return -1; - } - - for (;;) { - state = ssl->state; - - switch (ssl->state) { - case SSL_ST_ACCEPT: - if (cb != NULL) { - cb(ssl, SSL_CB_HANDSHAKE_START, 1); - } - - if (ssl->init_buf == NULL) { - buf = BUF_MEM_new(); - if (!buf || !BUF_MEM_grow(buf, SSL3_RT_MAX_PLAIN_LENGTH)) { - ret = -1; - goto end; - } - ssl->init_buf = buf; - buf = NULL; - } - ssl->init_num = 0; - - /* Enable a write buffer. This groups handshake messages within a flight - * into a single write. */ - if (!ssl_init_wbio_buffer(ssl, 1)) { - ret = -1; - goto end; - } - - if (!ssl3_init_handshake_buffer(ssl)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - ret = -1; - goto end; - } - - if (!ssl->s3->have_version) { - ssl->state = SSL3_ST_SR_INITIAL_BYTES; - } else { - ssl->state = SSL3_ST_SR_CLNT_HELLO_A; - } - break; - - case SSL3_ST_SR_INITIAL_BYTES: - ret = ssl3_get_initial_bytes(ssl); - if (ret <= 0) { - goto end; - } - /* ssl3_get_initial_bytes sets ssl->state to one of - * SSL3_ST_SR_V2_CLIENT_HELLO or SSL3_ST_SR_CLNT_HELLO_A on success. */ - break; - - case SSL3_ST_SR_V2_CLIENT_HELLO: - ret = ssl3_get_v2_client_hello(ssl); - if (ret <= 0) { - goto end; - } - ssl->state = SSL3_ST_SR_CLNT_HELLO_A; - break; - - case SSL3_ST_SR_CLNT_HELLO_A: - case SSL3_ST_SR_CLNT_HELLO_B: - case SSL3_ST_SR_CLNT_HELLO_C: - case SSL3_ST_SR_CLNT_HELLO_D: - ssl->shutdown = 0; - ret = ssl3_get_client_hello(ssl); - if (ret <= 0) { - goto end; - } - ssl->state = SSL3_ST_SW_SRVR_HELLO_A; - ssl->init_num = 0; - break; - - case SSL3_ST_SW_SRVR_HELLO_A: - case SSL3_ST_SW_SRVR_HELLO_B: - ret = ssl3_send_server_hello(ssl); - if (ret <= 0) { - goto end; - } - if (ssl->hit) { - if (ssl->tlsext_ticket_expected) { - ssl->state = SSL3_ST_SW_SESSION_TICKET_A; - } else { - ssl->state = SSL3_ST_SW_CHANGE_A; - } - } else { - ssl->state = SSL3_ST_SW_CERT_A; - } - ssl->init_num = 0; - break; - - case SSL3_ST_SW_CERT_A: - case SSL3_ST_SW_CERT_B: - if (ssl_cipher_has_server_public_key(ssl->s3->tmp.new_cipher)) { - ret = ssl3_send_server_certificate(ssl); - if (ret <= 0) { - goto end; - } - if (ssl->s3->tmp.certificate_status_expected) { - ssl->state = SSL3_ST_SW_CERT_STATUS_A; - } else { - ssl->state = SSL3_ST_SW_KEY_EXCH_A; - } - } else { - skip = 1; - ssl->state = SSL3_ST_SW_KEY_EXCH_A; - } - ssl->init_num = 0; - break; - - case SSL3_ST_SW_CERT_STATUS_A: - case SSL3_ST_SW_CERT_STATUS_B: - ret = ssl3_send_certificate_status(ssl); - if (ret <= 0) { - goto end; - } - ssl->state = SSL3_ST_SW_KEY_EXCH_A; - ssl->init_num = 0; - break; - - case SSL3_ST_SW_KEY_EXCH_A: - case SSL3_ST_SW_KEY_EXCH_B: - case SSL3_ST_SW_KEY_EXCH_C: - alg_a = ssl->s3->tmp.new_cipher->algorithm_auth; - - /* Send a ServerKeyExchange message if: - * - The key exchange is ephemeral or anonymous - * Diffie-Hellman. - * - There is a PSK identity hint. - * - * TODO(davidben): This logic is currently duplicated in d1_srvr.c. Fix - * this. In the meantime, keep them in sync. */ - if (ssl_cipher_requires_server_key_exchange(ssl->s3->tmp.new_cipher) || - ((alg_a & SSL_aPSK) && ssl->psk_identity_hint)) { - ret = ssl3_send_server_key_exchange(ssl); - if (ret <= 0) { - goto end; - } - } else { - skip = 1; - } - - ssl->state = SSL3_ST_SW_CERT_REQ_A; - ssl->init_num = 0; - break; - - case SSL3_ST_SW_CERT_REQ_A: - case SSL3_ST_SW_CERT_REQ_B: - if (ssl->s3->tmp.cert_request) { - ret = ssl3_send_certificate_request(ssl); - if (ret <= 0) { - goto end; - } - } else { - skip = 1; - } - ssl->state = SSL3_ST_SW_SRVR_DONE_A; - ssl->init_num = 0; - break; - - case SSL3_ST_SW_SRVR_DONE_A: - case SSL3_ST_SW_SRVR_DONE_B: - ret = ssl3_send_server_done(ssl); - if (ret <= 0) { - goto end; - } - ssl->s3->tmp.next_state = SSL3_ST_SR_CERT_A; - ssl->state = SSL3_ST_SW_FLUSH; - ssl->init_num = 0; - break; - - case SSL3_ST_SW_FLUSH: - /* This code originally checked to see if any data was pending using - * BIO_CTRL_INFO and then flushed. This caused problems as documented - * in PR#1939. The proposed fix doesn't completely resolve this issue - * as buggy implementations of BIO_CTRL_PENDING still exist. So instead - * we just flush unconditionally. */ - ssl->rwstate = SSL_WRITING; - if (BIO_flush(ssl->wbio) <= 0) { - ret = -1; - goto end; - } - ssl->rwstate = SSL_NOTHING; - - ssl->state = ssl->s3->tmp.next_state; - break; - - case SSL3_ST_SR_CERT_A: - case SSL3_ST_SR_CERT_B: - if (ssl->s3->tmp.cert_request) { - ret = ssl3_get_client_certificate(ssl); - if (ret <= 0) { - goto end; - } - } - ssl->init_num = 0; - ssl->state = SSL3_ST_SR_KEY_EXCH_A; - break; - - case SSL3_ST_SR_KEY_EXCH_A: - case SSL3_ST_SR_KEY_EXCH_B: - case SSL3_ST_SR_KEY_EXCH_C: - ret = ssl3_get_client_key_exchange(ssl); - if (ret <= 0) { - goto end; - } - ssl->state = SSL3_ST_SR_CERT_VRFY_A; - ssl->init_num = 0; - break; - - case SSL3_ST_SR_CERT_VRFY_A: - case SSL3_ST_SR_CERT_VRFY_B: - ret = ssl3_get_cert_verify(ssl); - if (ret <= 0) { - goto end; - } - - ssl->state = SSL3_ST_SR_CHANGE; - ssl->init_num = 0; - break; - - case SSL3_ST_SR_CHANGE: - ret = ssl->method->ssl_read_change_cipher_spec(ssl); - if (ret <= 0) { - goto end; - } - - if (!tls1_change_cipher_state(ssl, SSL3_CHANGE_CIPHER_SERVER_READ)) { - ret = -1; - goto end; - } - - if (ssl->s3->next_proto_neg_seen) { - ssl->state = SSL3_ST_SR_NEXT_PROTO_A; - } else if (ssl->s3->tlsext_channel_id_valid) { - ssl->state = SSL3_ST_SR_CHANNEL_ID_A; - } else { - ssl->state = SSL3_ST_SR_FINISHED_A; - } - break; - - case SSL3_ST_SR_NEXT_PROTO_A: - case SSL3_ST_SR_NEXT_PROTO_B: - ret = ssl3_get_next_proto(ssl); - if (ret <= 0) { - goto end; - } - ssl->init_num = 0; - if (ssl->s3->tlsext_channel_id_valid) { - ssl->state = SSL3_ST_SR_CHANNEL_ID_A; - } else { - ssl->state = SSL3_ST_SR_FINISHED_A; - } - break; - - case SSL3_ST_SR_CHANNEL_ID_A: - case SSL3_ST_SR_CHANNEL_ID_B: - ret = ssl3_get_channel_id(ssl); - if (ret <= 0) { - goto end; - } - ssl->init_num = 0; - ssl->state = SSL3_ST_SR_FINISHED_A; - break; - - case SSL3_ST_SR_FINISHED_A: - case SSL3_ST_SR_FINISHED_B: - ret = ssl3_get_finished(ssl, SSL3_ST_SR_FINISHED_A, - SSL3_ST_SR_FINISHED_B); - if (ret <= 0) { - goto end; - } - - if (ssl->hit) { - ssl->state = SSL_ST_OK; - } else if (ssl->tlsext_ticket_expected) { - ssl->state = SSL3_ST_SW_SESSION_TICKET_A; - } else { - ssl->state = SSL3_ST_SW_CHANGE_A; - } - /* If this is a full handshake with ChannelID then record the hashshake - * hashes in |ssl->session| in case we need them to verify a ChannelID - * signature on a resumption of this session in the future. */ - if (!ssl->hit && ssl->s3->tlsext_channel_id_valid) { - ret = tls1_record_handshake_hashes_for_channel_id(ssl); - if (ret <= 0) { - goto end; - } - } - ssl->init_num = 0; - break; - - case SSL3_ST_SW_SESSION_TICKET_A: - case SSL3_ST_SW_SESSION_TICKET_B: - ret = ssl3_send_new_session_ticket(ssl); - if (ret <= 0) { - goto end; - } - ssl->state = SSL3_ST_SW_CHANGE_A; - ssl->init_num = 0; - break; - - case SSL3_ST_SW_CHANGE_A: - case SSL3_ST_SW_CHANGE_B: - ret = ssl3_send_change_cipher_spec(ssl, SSL3_ST_SW_CHANGE_A, - SSL3_ST_SW_CHANGE_B); - if (ret <= 0) { - goto end; - } - ssl->state = SSL3_ST_SW_FINISHED_A; - ssl->init_num = 0; - - if (!tls1_change_cipher_state(ssl, SSL3_CHANGE_CIPHER_SERVER_WRITE)) { - ret = -1; - goto end; - } - break; - - case SSL3_ST_SW_FINISHED_A: - case SSL3_ST_SW_FINISHED_B: - ret = ssl3_send_finished(ssl, SSL3_ST_SW_FINISHED_A, - SSL3_ST_SW_FINISHED_B); - if (ret <= 0) { - goto end; - } - ssl->state = SSL3_ST_SW_FLUSH; - if (ssl->hit) { - ssl->s3->tmp.next_state = SSL3_ST_SR_CHANGE; - } else { - ssl->s3->tmp.next_state = SSL_ST_OK; - } - ssl->init_num = 0; - break; - - case SSL_ST_OK: - /* clean a few things up */ - ssl3_cleanup_key_block(ssl); - - BUF_MEM_free(ssl->init_buf); - ssl->init_buf = NULL; - - /* remove buffering on output */ - ssl_free_wbio_buffer(ssl); - - ssl->init_num = 0; - - /* If we aren't retaining peer certificates then we can discard it - * now. */ - if (ssl->ctx->retain_only_sha256_of_client_certs) { - X509_free(ssl->session->peer); - ssl->session->peer = NULL; - sk_X509_pop_free(ssl->session->cert_chain, X509_free); - ssl->session->cert_chain = NULL; - } - - ssl->s3->initial_handshake_complete = 1; - - ssl_update_cache(ssl, SSL_SESS_CACHE_SERVER); - - if (cb != NULL) { - cb(ssl, SSL_CB_HANDSHAKE_DONE, 1); - } - - ret = 1; - goto end; - - default: - OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_STATE); - ret = -1; - goto end; - } - - if (!ssl->s3->tmp.reuse_message && !skip && cb != NULL && - ssl->state != state) { - new_state = ssl->state; - ssl->state = state; - cb(ssl, SSL_CB_ACCEPT_LOOP, 1); - ssl->state = new_state; - } - skip = 0; - } - -end: - ssl->in_handshake--; - BUF_MEM_free(buf); - if (cb != NULL) { - cb(ssl, SSL_CB_ACCEPT_EXIT, ret); - } - return ret; -} - -int ssl3_get_initial_bytes(SSL *ssl) { - /* Read the first 5 bytes, the size of the TLS record header. This is - * sufficient to detect a V2ClientHello and ensures that we never read beyond - * the first record. */ - int ret = ssl_read_buffer_extend_to(ssl, SSL3_RT_HEADER_LENGTH); - if (ret <= 0) { - return ret; - } - assert(ssl_read_buffer_len(ssl) == SSL3_RT_HEADER_LENGTH); - const uint8_t *p = ssl_read_buffer(ssl); - - /* Some dedicated error codes for protocol mixups should the application wish - * to interpret them differently. (These do not overlap with ClientHello or - * V2ClientHello.) */ - if (strncmp("GET ", (const char *)p, 4) == 0 || - strncmp("POST ", (const char *)p, 5) == 0 || - strncmp("HEAD ", (const char *)p, 5) == 0 || - strncmp("PUT ", (const char *)p, 4) == 0) { - OPENSSL_PUT_ERROR(SSL, SSL_R_HTTP_REQUEST); - return -1; - } - if (strncmp("CONNE", (const char *)p, 5) == 0) { - OPENSSL_PUT_ERROR(SSL, SSL_R_HTTPS_PROXY_REQUEST); - return -1; - } - - /* Determine if this is a V2ClientHello. */ - if ((p[0] & 0x80) && p[2] == SSL2_MT_CLIENT_HELLO && - p[3] >= SSL3_VERSION_MAJOR) { - /* This is a V2ClientHello. */ - ssl->state = SSL3_ST_SR_V2_CLIENT_HELLO; - return 1; - } - - /* Fall through to the standard logic. */ - ssl->state = SSL3_ST_SR_CLNT_HELLO_A; - return 1; -} - -int ssl3_get_v2_client_hello(SSL *ssl) { - const uint8_t *p; - int ret; - CBS v2_client_hello, cipher_specs, session_id, challenge; - size_t msg_length, rand_len, len; - uint8_t msg_type; - uint16_t version, cipher_spec_length, session_id_length, challenge_length; - CBB client_hello, hello_body, cipher_suites; - uint8_t random[SSL3_RANDOM_SIZE]; - - /* Determine the length of the V2ClientHello. */ - assert(ssl_read_buffer_len(ssl) >= SSL3_RT_HEADER_LENGTH); - p = ssl_read_buffer(ssl); - msg_length = ((p[0] & 0x7f) << 8) | p[1]; - if (msg_length > (1024 * 4)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_RECORD_TOO_LARGE); - return -1; - } - if (msg_length < SSL3_RT_HEADER_LENGTH - 2) { - /* Reject lengths that are too short early. We have already read - * |SSL3_RT_HEADER_LENGTH| bytes, so we should not attempt to process an - * (invalid) V2ClientHello which would be shorter than that. */ - OPENSSL_PUT_ERROR(SSL, SSL_R_RECORD_LENGTH_MISMATCH); - return -1; - } - - /* Read the remainder of the V2ClientHello. */ - ret = ssl_read_buffer_extend_to(ssl, 2 + msg_length); - if (ret <= 0) { - return ret; - } - assert(ssl_read_buffer_len(ssl) == msg_length + 2); - CBS_init(&v2_client_hello, ssl_read_buffer(ssl) + 2, msg_length); - - /* The V2ClientHello without the length is incorporated into the handshake - * hash. */ - if (!ssl3_update_handshake_hash(ssl, CBS_data(&v2_client_hello), - CBS_len(&v2_client_hello))) { - return -1; - } - if (ssl->msg_callback) { - ssl->msg_callback(0, SSL2_VERSION, 0, CBS_data(&v2_client_hello), - CBS_len(&v2_client_hello), ssl, ssl->msg_callback_arg); - } - - if (!CBS_get_u8(&v2_client_hello, &msg_type) || - !CBS_get_u16(&v2_client_hello, &version) || - !CBS_get_u16(&v2_client_hello, &cipher_spec_length) || - !CBS_get_u16(&v2_client_hello, &session_id_length) || - !CBS_get_u16(&v2_client_hello, &challenge_length) || - !CBS_get_bytes(&v2_client_hello, &cipher_specs, cipher_spec_length) || - !CBS_get_bytes(&v2_client_hello, &session_id, session_id_length) || - !CBS_get_bytes(&v2_client_hello, &challenge, challenge_length) || - CBS_len(&v2_client_hello) != 0) { - OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); - return -1; - } - - /* msg_type has already been checked. */ - assert(msg_type == SSL2_MT_CLIENT_HELLO); - - /* The client_random is the V2ClientHello challenge. Truncate or - * left-pad with zeros as needed. */ - memset(random, 0, SSL3_RANDOM_SIZE); - rand_len = CBS_len(&challenge); - if (rand_len > SSL3_RANDOM_SIZE) { - rand_len = SSL3_RANDOM_SIZE; - } - memcpy(random + (SSL3_RANDOM_SIZE - rand_len), CBS_data(&challenge), - rand_len); - - /* Write out an equivalent SSLv3 ClientHello. */ - CBB_zero(&client_hello); - if (!CBB_init_fixed(&client_hello, (uint8_t *)ssl->init_buf->data, - ssl->init_buf->max) || - !CBB_add_u8(&client_hello, SSL3_MT_CLIENT_HELLO) || - !CBB_add_u24_length_prefixed(&client_hello, &hello_body) || - !CBB_add_u16(&hello_body, version) || - !CBB_add_bytes(&hello_body, random, SSL3_RANDOM_SIZE) || - /* No session id. */ - !CBB_add_u8(&hello_body, 0) || - !CBB_add_u16_length_prefixed(&hello_body, &cipher_suites)) { - CBB_cleanup(&client_hello); - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - return -1; - } - - /* Copy the cipher suites. */ - while (CBS_len(&cipher_specs) > 0) { - uint32_t cipher_spec; - if (!CBS_get_u24(&cipher_specs, &cipher_spec)) { - CBB_cleanup(&client_hello); - OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); - return -1; - } - - /* Skip SSLv2 ciphers. */ - if ((cipher_spec & 0xff0000) != 0) { - continue; - } - if (!CBB_add_u16(&cipher_suites, cipher_spec)) { - CBB_cleanup(&client_hello); - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - return -1; - } - } - - /* Add the null compression scheme and finish. */ - if (!CBB_add_u8(&hello_body, 1) || !CBB_add_u8(&hello_body, 0) || - !CBB_finish(&client_hello, NULL, &len)) { - CBB_cleanup(&client_hello); - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - return -1; - } - - /* Mark the message for "re"-use by the version-specific method. */ - ssl->s3->tmp.reuse_message = 1; - ssl->s3->tmp.message_type = SSL3_MT_CLIENT_HELLO; - /* The handshake message header is 4 bytes. */ - ssl->s3->tmp.message_size = len - 4; - - /* Consume and discard the V2ClientHello. */ - ssl_read_buffer_consume(ssl, 2 + msg_length); - ssl_read_buffer_discard(ssl); - - return 1; -} - -int ssl3_get_client_hello(SSL *ssl) { - int ok, al = SSL_AD_INTERNAL_ERROR, ret = -1; - long n; - const SSL_CIPHER *c; - STACK_OF(SSL_CIPHER) *ciphers = NULL; - struct ssl_early_callback_ctx early_ctx; - CBS client_hello; - uint16_t client_version; - CBS client_random, session_id, cipher_suites, compression_methods; - SSL_SESSION *session = NULL; - - /* We do this so that we will respond with our native type. If we are TLSv1 - * and we get SSLv3, we will respond with TLSv1, This down switching should - * be handled by a different method. If we are SSLv3, we will respond with - * SSLv3, even if prompted with TLSv1. */ - switch (ssl->state) { - case SSL3_ST_SR_CLNT_HELLO_A: - case SSL3_ST_SR_CLNT_HELLO_B: - n = ssl->method->ssl_get_message( - ssl, SSL3_ST_SR_CLNT_HELLO_A, SSL3_ST_SR_CLNT_HELLO_B, - SSL3_MT_CLIENT_HELLO, SSL3_RT_MAX_PLAIN_LENGTH, - ssl_hash_message, &ok); - - if (!ok) { - return n; - } - - ssl->state = SSL3_ST_SR_CLNT_HELLO_C; - /* fallthrough */ - case SSL3_ST_SR_CLNT_HELLO_C: - case SSL3_ST_SR_CLNT_HELLO_D: - /* We have previously parsed the ClientHello message, and can't call - * ssl_get_message again without hashing the message into the Finished - * digest again. */ - n = ssl->init_num; - - memset(&early_ctx, 0, sizeof(early_ctx)); - early_ctx.ssl = ssl; - early_ctx.client_hello = ssl->init_msg; - early_ctx.client_hello_len = n; - if (!ssl_early_callback_init(&early_ctx)) { - al = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_CLIENTHELLO_PARSE_FAILED); - goto f_err; - } - - if (ssl->state == SSL3_ST_SR_CLNT_HELLO_C && - ssl->ctx->select_certificate_cb != NULL) { - ssl->state = SSL3_ST_SR_CLNT_HELLO_D; - switch (ssl->ctx->select_certificate_cb(&early_ctx)) { - case 0: - ssl->rwstate = SSL_CERTIFICATE_SELECTION_PENDING; - goto err; - - case -1: - /* Connection rejected. */ - al = SSL_AD_ACCESS_DENIED; - OPENSSL_PUT_ERROR(SSL, SSL_R_CONNECTION_REJECTED); - goto f_err; - - default: - /* fallthrough */; - } - } - ssl->state = SSL3_ST_SR_CLNT_HELLO_D; - break; - - default: - OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_STATE); - return -1; - } - - CBS_init(&client_hello, ssl->init_msg, n); - if (!CBS_get_u16(&client_hello, &client_version) || - !CBS_get_bytes(&client_hello, &client_random, SSL3_RANDOM_SIZE) || - !CBS_get_u8_length_prefixed(&client_hello, &session_id) || - CBS_len(&session_id) > SSL_MAX_SSL_SESSION_ID_LENGTH) { - al = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); - goto f_err; - } - - /* use version from inside client hello, not from record header (may differ: - * see RFC 2246, Appendix E, second paragraph) */ - ssl->client_version = client_version; - - /* Load the client random. */ - memcpy(ssl->s3->client_random, CBS_data(&client_random), SSL3_RANDOM_SIZE); - - if (SSL_IS_DTLS(ssl)) { - CBS cookie; - - if (!CBS_get_u8_length_prefixed(&client_hello, &cookie) || - CBS_len(&cookie) > DTLS1_COOKIE_LENGTH) { - al = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); - goto f_err; - } - } - - /* Note: This codepath may run twice if |ssl_get_prev_session| completes - * asynchronously. - * - * TODO(davidben): Clean up the order of events around ClientHello - * processing. */ - if (!ssl->s3->have_version) { - /* Select version to use */ - uint16_t version = ssl3_get_mutual_version(ssl, client_version); - if (version == 0) { - OPENSSL_PUT_ERROR(SSL, SSL_R_UNSUPPORTED_PROTOCOL); - ssl->version = ssl->client_version; - al = SSL_AD_PROTOCOL_VERSION; - goto f_err; - } - ssl->version = version; - ssl->s3->enc_method = ssl3_get_enc_method(version); - assert(ssl->s3->enc_method != NULL); - /* At this point, the connection's version is known and |ssl->version| is - * fixed. Begin enforcing the record-layer version. */ - ssl->s3->have_version = 1; - } else if (SSL_IS_DTLS(ssl) ? (ssl->client_version > ssl->version) - : (ssl->client_version < ssl->version)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_VERSION_NUMBER); - al = SSL_AD_PROTOCOL_VERSION; - goto f_err; - } - - ssl->hit = 0; - int send_new_ticket = 0; - switch (ssl_get_prev_session(ssl, &session, &send_new_ticket, &early_ctx)) { - case ssl_session_success: - break; - case ssl_session_error: - goto err; - case ssl_session_retry: - ssl->rwstate = SSL_PENDING_SESSION; - goto err; - } - ssl->tlsext_ticket_expected = send_new_ticket; - - /* The EMS state is needed when making the resumption decision, but - * extensions are not normally parsed until later. This detects the EMS - * extension for the resumption decision and it's checked against the result - * of the normal parse later in this function. */ - const uint8_t *ems_data; - size_t ems_len; - int have_extended_master_secret = - ssl->version != SSL3_VERSION && - SSL_early_callback_ctx_extension_get(&early_ctx, - TLSEXT_TYPE_extended_master_secret, - &ems_data, &ems_len) && - ems_len == 0; - - if (session != NULL) { - if (session->extended_master_secret && - !have_extended_master_secret) { - /* A ClientHello without EMS that attempts to resume a session with EMS - * is fatal to the connection. */ - al = SSL_AD_HANDSHAKE_FAILURE; - OPENSSL_PUT_ERROR(SSL, SSL_R_RESUMED_EMS_SESSION_WITHOUT_EMS_EXTENSION); - goto f_err; - } - - ssl->hit = - /* Only resume if the session's version matches the negotiated version: - * most clients do not accept a mismatch. */ - ssl->version == session->ssl_version && - /* If the client offers the EMS extension, but the previous session - * didn't use it, then negotiate a new session. */ - have_extended_master_secret == session->extended_master_secret; - } - - if (ssl->hit) { - /* Use the new session. */ - SSL_SESSION_free(ssl->session); - ssl->session = session; - session = NULL; - - ssl->verify_result = ssl->session->verify_result; - } else { - if (!ssl_get_new_session(ssl, 1 /* server */)) { - goto err; - } - - /* Clear the session ID if we want the session to be single-use. */ - if (!(ssl->ctx->session_cache_mode & SSL_SESS_CACHE_SERVER)) { - ssl->session->session_id_length = 0; - } - } - - if (ssl->ctx->dos_protection_cb != NULL && - ssl->ctx->dos_protection_cb(&early_ctx) == 0) { - /* Connection rejected for DOS reasons. */ - al = SSL_AD_ACCESS_DENIED; - OPENSSL_PUT_ERROR(SSL, SSL_R_CONNECTION_REJECTED); - goto f_err; - } - - if (!CBS_get_u16_length_prefixed(&client_hello, &cipher_suites) || - CBS_len(&cipher_suites) == 0 || - CBS_len(&cipher_suites) % 2 != 0 || - !CBS_get_u8_length_prefixed(&client_hello, &compression_methods) || - CBS_len(&compression_methods) == 0) { - al = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); - goto f_err; - } - - ciphers = ssl_bytes_to_cipher_list(ssl, &cipher_suites); - if (ciphers == NULL) { - goto err; - } - - /* If it is a hit, check that the cipher is in the list. */ - if (ssl->hit) { - size_t j; - int found_cipher = 0; - uint32_t id = ssl->session->cipher->id; - - for (j = 0; j < sk_SSL_CIPHER_num(ciphers); j++) { - c = sk_SSL_CIPHER_value(ciphers, j); - if (c->id == id) { - found_cipher = 1; - break; - } - } - - if (!found_cipher) { - /* we need to have the cipher in the cipher list if we are asked to reuse - * it */ - al = SSL_AD_ILLEGAL_PARAMETER; - OPENSSL_PUT_ERROR(SSL, SSL_R_REQUIRED_CIPHER_MISSING); - goto f_err; - } - } - - /* Only null compression is supported. */ - if (memchr(CBS_data(&compression_methods), 0, - CBS_len(&compression_methods)) == NULL) { - al = SSL_AD_ILLEGAL_PARAMETER; - OPENSSL_PUT_ERROR(SSL, SSL_R_NO_COMPRESSION_SPECIFIED); - goto f_err; - } - - /* TLS extensions. */ - if (ssl->version >= SSL3_VERSION && - !ssl_parse_clienthello_tlsext(ssl, &client_hello)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_PARSE_TLSEXT); - goto err; - } - - /* There should be nothing left over in the record. */ - if (CBS_len(&client_hello) != 0) { - /* wrong packet length */ - al = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_PACKET_LENGTH); - goto f_err; - } - - if (have_extended_master_secret != ssl->s3->tmp.extended_master_secret) { - al = SSL_AD_INTERNAL_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_EMS_STATE_INCONSISTENT); - goto f_err; - } - - /* Given ciphers and SSL_get_ciphers, we must pick a cipher */ - if (!ssl->hit) { - if (ciphers == NULL) { - al = SSL_AD_ILLEGAL_PARAMETER; - OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CIPHERS_PASSED); - goto f_err; - } - - /* Let cert callback update server certificates if required */ - if (ssl->cert->cert_cb) { - int rv = ssl->cert->cert_cb(ssl, ssl->cert->cert_cb_arg); - if (rv == 0) { - al = SSL_AD_INTERNAL_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_CERT_CB_ERROR); - goto f_err; - } - if (rv < 0) { - ssl->rwstate = SSL_X509_LOOKUP; - goto err; - } - ssl->rwstate = SSL_NOTHING; - } - c = ssl3_choose_cipher(ssl, ciphers, ssl_get_cipher_preferences(ssl)); - - if (c == NULL) { - al = SSL_AD_HANDSHAKE_FAILURE; - OPENSSL_PUT_ERROR(SSL, SSL_R_NO_SHARED_CIPHER); - goto f_err; - } - ssl->session->cipher = c; - ssl->s3->tmp.new_cipher = c; - - /* Determine whether to request a client certificate. */ - ssl->s3->tmp.cert_request = !!(ssl->verify_mode & SSL_VERIFY_PEER); - /* Only request a certificate if Channel ID isn't negotiated. */ - if ((ssl->verify_mode & SSL_VERIFY_PEER_IF_NO_OBC) && - ssl->s3->tlsext_channel_id_valid) { - ssl->s3->tmp.cert_request = 0; - } - /* Plain PSK forbids Certificate and CertificateRequest. */ - if (ssl->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK) { - ssl->s3->tmp.cert_request = 0; - } - } else { - /* Session-id reuse */ - ssl->s3->tmp.new_cipher = ssl->session->cipher; - ssl->s3->tmp.cert_request = 0; - } - - /* Now that the cipher is known, initialize the handshake hash. */ - if (!ssl3_init_handshake_hash(ssl)) { - goto f_err; - } - - /* In TLS 1.2, client authentication requires hashing the handshake transcript - * under a different hash. Otherwise, release the handshake buffer. */ - if (!ssl->s3->tmp.cert_request || - ssl3_protocol_version(ssl) < TLS1_2_VERSION) { - ssl3_free_handshake_buffer(ssl); - } - - /* we now have the following setup; - * client_random - * cipher_list - our prefered list of ciphers - * ciphers - the clients prefered list of ciphers - * compression - basically ignored right now - * ssl version is set - sslv3 - * ssl->session - The ssl session has been setup. - * ssl->hit - session reuse flag - * ssl->tmp.new_cipher - the new cipher to use. */ - - ret = 1; - - if (0) { - f_err: - ssl3_send_alert(ssl, SSL3_AL_FATAL, al); - } - -err: - sk_SSL_CIPHER_free(ciphers); - SSL_SESSION_free(session); - return ret; -} - -int ssl3_send_server_hello(SSL *ssl) { - if (ssl->state == SSL3_ST_SW_SRVR_HELLO_B) { - return ssl_do_write(ssl); - } - - assert(ssl->state == SSL3_ST_SW_SRVR_HELLO_A); - - /* We only accept ChannelIDs on connections with ECDHE in order to avoid a - * known attack while we fix ChannelID itself. */ - if (ssl->s3->tlsext_channel_id_valid && - (ssl->s3->tmp.new_cipher->algorithm_mkey & SSL_kECDHE) == 0) { - ssl->s3->tlsext_channel_id_valid = 0; - } - - /* If this is a resumption and the original handshake didn't support - * ChannelID then we didn't record the original handshake hashes in the - * session and so cannot resume with ChannelIDs. */ - if (ssl->hit && ssl->session->original_handshake_hash_len == 0) { - ssl->s3->tlsext_channel_id_valid = 0; - } - - if (!ssl_fill_hello_random(ssl->s3->server_random, SSL3_RANDOM_SIZE, - 1 /* server */)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - return -1; - } - - CBB cbb, session_id; - size_t length; - CBB_zero(&cbb); - if (!CBB_init_fixed(&cbb, ssl_handshake_start(ssl), - ssl->init_buf->max - SSL_HM_HEADER_LENGTH(ssl)) || - !CBB_add_u16(&cbb, ssl->version) || - !CBB_add_bytes(&cbb, ssl->s3->server_random, SSL3_RANDOM_SIZE) || - !CBB_add_u8_length_prefixed(&cbb, &session_id) || - !CBB_add_bytes(&session_id, ssl->session->session_id, - ssl->session->session_id_length) || - !CBB_add_u16(&cbb, ssl_cipher_get_value(ssl->s3->tmp.new_cipher)) || - !CBB_add_u8(&cbb, 0 /* no compression */) || - !ssl_add_serverhello_tlsext(ssl, &cbb) || - !CBB_finish(&cbb, NULL, &length) || - !ssl_set_handshake_header(ssl, SSL3_MT_SERVER_HELLO, length)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - CBB_cleanup(&cbb); - return -1; - } - - ssl->state = SSL3_ST_SW_SRVR_HELLO_B; - return ssl_do_write(ssl); -} - -int ssl3_send_certificate_status(SSL *ssl) { - if (ssl->state == SSL3_ST_SW_CERT_STATUS_A) { - CBB out, ocsp_response; - size_t length; - - CBB_zero(&out); - if (!CBB_init_fixed(&out, ssl_handshake_start(ssl), - ssl->init_buf->max - SSL_HM_HEADER_LENGTH(ssl)) || - !CBB_add_u8(&out, TLSEXT_STATUSTYPE_ocsp) || - !CBB_add_u24_length_prefixed(&out, &ocsp_response) || - !CBB_add_bytes(&ocsp_response, ssl->ctx->ocsp_response, - ssl->ctx->ocsp_response_length) || - !CBB_finish(&out, NULL, &length) || - !ssl_set_handshake_header(ssl, SSL3_MT_CERTIFICATE_STATUS, length)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - CBB_cleanup(&out); - return -1; - } - - ssl->state = SSL3_ST_SW_CERT_STATUS_B; - } - - /* SSL3_ST_SW_CERT_STATUS_B */ - return ssl_do_write(ssl); -} - -int ssl3_send_server_done(SSL *ssl) { - if (ssl->state == SSL3_ST_SW_SRVR_DONE_A) { - if (!ssl_set_handshake_header(ssl, SSL3_MT_SERVER_DONE, 0)) { - return -1; - } - ssl->state = SSL3_ST_SW_SRVR_DONE_B; - } - - /* SSL3_ST_SW_SRVR_DONE_B */ - return ssl_do_write(ssl); -} - -int ssl3_send_server_key_exchange(SSL *ssl) { - if (ssl->state == SSL3_ST_SW_KEY_EXCH_C) { - return ssl_do_write(ssl); - } - - CBB cbb, child; - if (!CBB_init_fixed(&cbb, ssl_handshake_start(ssl), - ssl->init_buf->max - SSL_HM_HEADER_LENGTH(ssl))) { - goto err; - } - - if (ssl->state == SSL3_ST_SW_KEY_EXCH_A) { - /* This is the first iteration, so write parameters. */ - uint32_t alg_k = ssl->s3->tmp.new_cipher->algorithm_mkey; - uint32_t alg_a = ssl->s3->tmp.new_cipher->algorithm_auth; - - /* PSK ciphers begin with an identity hint. */ - if (alg_a & SSL_aPSK) { - size_t len = - (ssl->psk_identity_hint == NULL) ? 0 : strlen(ssl->psk_identity_hint); - if (!CBB_add_u16_length_prefixed(&cbb, &child) || - !CBB_add_bytes(&child, (const uint8_t *)ssl->psk_identity_hint, - len)) { - goto err; - } - } - - if (alg_k & SSL_kDHE) { - /* Determine the group to use. */ - DH *params = ssl->cert->dh_tmp; - if (params == NULL && ssl->cert->dh_tmp_cb != NULL) { - params = ssl->cert->dh_tmp_cb(ssl, 0, 1024); - } - if (params == NULL) { - OPENSSL_PUT_ERROR(SSL, SSL_R_MISSING_TMP_DH_KEY); - ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE); - goto err; - } - ssl->session->key_exchange_info = DH_num_bits(params); - - /* Set up DH, generate a key, and emit the public half. */ - DH *dh = DHparams_dup(params); - if (dh == NULL) { - goto err; - } - - SSL_ECDH_CTX_init_for_dhe(&ssl->s3->tmp.ecdh_ctx, dh); - if (!CBB_add_u16_length_prefixed(&cbb, &child) || - !BN_bn2cbb_padded(&child, BN_num_bytes(params->p), params->p) || - !CBB_add_u16_length_prefixed(&cbb, &child) || - !BN_bn2cbb_padded(&child, BN_num_bytes(params->g), params->g) || - !CBB_add_u16_length_prefixed(&cbb, &child) || - !SSL_ECDH_CTX_generate_keypair(&ssl->s3->tmp.ecdh_ctx, &child)) { - goto err; - } - } else if (alg_k & SSL_kECDHE) { - /* Determine the curve to use. */ - uint16_t curve_id; - if (!tls1_get_shared_curve(ssl, &curve_id)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_MISSING_TMP_ECDH_KEY); - ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE); - goto err; - } - ssl->session->key_exchange_info = curve_id; - - /* Set up ECDH, generate a key, and emit the public half. */ - if (!SSL_ECDH_CTX_init(&ssl->s3->tmp.ecdh_ctx, curve_id) || - !CBB_add_u8(&cbb, NAMED_CURVE_TYPE) || - !CBB_add_u16(&cbb, curve_id) || - !CBB_add_u8_length_prefixed(&cbb, &child) || - !SSL_ECDH_CTX_generate_keypair(&ssl->s3->tmp.ecdh_ctx, &child)) { - goto err; - } - } else { - assert(alg_k & SSL_kPSK); - } - - /* Otherwise, restore |cbb| from the previous iteration. - * TODO(davidben): When |ssl->init_buf| is gone, come up with a simpler - * pattern. Probably keep the |CBB| around in the handshake state. */ - } else if (!CBB_did_write(&cbb, ssl->init_num - SSL_HM_HEADER_LENGTH(ssl))) { - goto err; - } - - /* Add a signature. */ - if (ssl_cipher_has_server_public_key(ssl->s3->tmp.new_cipher)) { - if (!ssl_has_private_key(ssl)) { - ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); - goto err; - } - - const size_t max_sig_len = ssl_private_key_max_signature_len(ssl); - size_t sig_len; - enum ssl_private_key_result_t sign_result; - if (ssl->state == SSL3_ST_SW_KEY_EXCH_A) { - /* This is the first iteration, so set up the signature. Sample the - * parameter length before adding a signature algorithm. */ - if (!CBB_flush(&cbb)) { - goto err; - } - size_t params_len = CBB_len(&cbb); - - /* Determine signature algorithm. */ - const EVP_MD *md; - if (ssl3_protocol_version(ssl) >= TLS1_2_VERSION) { - md = tls1_choose_signing_digest(ssl); - if (!tls12_add_sigandhash(ssl, &cbb, md)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); - goto err; - } - } else if (ssl_private_key_type(ssl) == EVP_PKEY_RSA) { - md = EVP_md5_sha1(); - } else { - md = EVP_sha1(); - } - - /* Compute the digest and sign it. */ - uint8_t digest[EVP_MAX_MD_SIZE]; - unsigned digest_len = 0; - EVP_MD_CTX md_ctx; - EVP_MD_CTX_init(&md_ctx); - int digest_ret = - EVP_DigestInit_ex(&md_ctx, md, NULL) && - EVP_DigestUpdate(&md_ctx, ssl->s3->client_random, SSL3_RANDOM_SIZE) && - EVP_DigestUpdate(&md_ctx, ssl->s3->server_random, SSL3_RANDOM_SIZE) && - EVP_DigestUpdate(&md_ctx, CBB_data(&cbb), params_len) && - EVP_DigestFinal_ex(&md_ctx, digest, &digest_len); - EVP_MD_CTX_cleanup(&md_ctx); - uint8_t *ptr; - if (!digest_ret || - !CBB_add_u16_length_prefixed(&cbb, &child) || - !CBB_reserve(&child, &ptr, max_sig_len)) { - goto err; - } - sign_result = ssl_private_key_sign(ssl, ptr, &sig_len, max_sig_len, md, - digest, digest_len); - } else { - assert(ssl->state == SSL3_ST_SW_KEY_EXCH_B); - - /* Retry the signature. */ - uint8_t *ptr; - if (!CBB_add_u16_length_prefixed(&cbb, &child) || - !CBB_reserve(&child, &ptr, max_sig_len)) { - goto err; - } - sign_result = - ssl_private_key_sign_complete(ssl, ptr, &sig_len, max_sig_len); - } - - switch (sign_result) { - case ssl_private_key_success: - ssl->rwstate = SSL_NOTHING; - if (!CBB_did_write(&child, sig_len)) { - goto err; - } - break; - case ssl_private_key_failure: - ssl->rwstate = SSL_NOTHING; - goto err; - case ssl_private_key_retry: - /* Discard the unfinished signature and save the state of |cbb| for the - * next iteration. */ - CBB_discard_child(&cbb); - ssl->init_num = SSL_HM_HEADER_LENGTH(ssl) + CBB_len(&cbb); - ssl->rwstate = SSL_PRIVATE_KEY_OPERATION; - ssl->state = SSL3_ST_SW_KEY_EXCH_B; - goto err; - } - } - - size_t length; - if (!CBB_finish(&cbb, NULL, &length) || - !ssl_set_handshake_header(ssl, SSL3_MT_SERVER_KEY_EXCHANGE, length)) { - goto err; - } - ssl->state = SSL3_ST_SW_KEY_EXCH_C; - return ssl_do_write(ssl); - -err: - CBB_cleanup(&cbb); - return -1; -} - -int ssl3_send_certificate_request(SSL *ssl) { - uint8_t *p, *d; - size_t i; - int j, nl, off, n; - STACK_OF(X509_NAME) *sk = NULL; - X509_NAME *name; - BUF_MEM *buf; - - if (ssl->state == SSL3_ST_SW_CERT_REQ_A) { - buf = ssl->init_buf; - - d = p = ssl_handshake_start(ssl); - - /* get the list of acceptable cert types */ - p++; - n = ssl3_get_req_cert_type(ssl, p); - d[0] = n; - p += n; - n++; - - if (ssl3_protocol_version(ssl) >= TLS1_2_VERSION) { - const uint8_t *psigs; - nl = tls12_get_psigalgs(ssl, &psigs); - s2n(nl, p); - memcpy(p, psigs, nl); - p += nl; - n += nl + 2; - } - - off = n; - p += 2; - n += 2; - - sk = SSL_get_client_CA_list(ssl); - nl = 0; - if (sk != NULL) { - for (i = 0; i < sk_X509_NAME_num(sk); i++) { - name = sk_X509_NAME_value(sk, i); - j = i2d_X509_NAME(name, NULL); - if (!BUF_MEM_grow_clean(buf, SSL_HM_HEADER_LENGTH(ssl) + n + j + 2)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB); - goto err; - } - p = ssl_handshake_start(ssl) + n; - s2n(j, p); - i2d_X509_NAME(name, &p); - n += 2 + j; - nl += 2 + j; - } - } - - /* else no CA names */ - p = ssl_handshake_start(ssl) + off; - s2n(nl, p); - - if (!ssl_set_handshake_header(ssl, SSL3_MT_CERTIFICATE_REQUEST, n)) { - goto err; - } - ssl->state = SSL3_ST_SW_CERT_REQ_B; - } - - /* SSL3_ST_SW_CERT_REQ_B */ - return ssl_do_write(ssl); - -err: - return -1; -} - -int ssl3_get_client_key_exchange(SSL *ssl) { - int al; - CBS client_key_exchange; - uint32_t alg_k; - uint32_t alg_a; - uint8_t *premaster_secret = NULL; - size_t premaster_secret_len = 0; - uint8_t *decrypt_buf = NULL; - - unsigned psk_len = 0; - uint8_t psk[PSK_MAX_PSK_LEN]; - - if (ssl->state == SSL3_ST_SR_KEY_EXCH_A || - ssl->state == SSL3_ST_SR_KEY_EXCH_B) { - int ok; - const long n = ssl->method->ssl_get_message( - ssl, SSL3_ST_SR_KEY_EXCH_A, SSL3_ST_SR_KEY_EXCH_B, - SSL3_MT_CLIENT_KEY_EXCHANGE, 2048 /* ??? */, ssl_hash_message, &ok); - if (!ok) { - return n; - } - } - - CBS_init(&client_key_exchange, ssl->init_msg, ssl->init_num); - alg_k = ssl->s3->tmp.new_cipher->algorithm_mkey; - alg_a = ssl->s3->tmp.new_cipher->algorithm_auth; - - /* If using a PSK key exchange, prepare the pre-shared key. */ - if (alg_a & SSL_aPSK) { - CBS psk_identity; - - /* If using PSK, the ClientKeyExchange contains a psk_identity. If PSK, - * then this is the only field in the message. */ - if (!CBS_get_u16_length_prefixed(&client_key_exchange, &psk_identity) || - ((alg_k & SSL_kPSK) && CBS_len(&client_key_exchange) != 0)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); - al = SSL_AD_DECODE_ERROR; - goto f_err; - } - - if (ssl->psk_server_callback == NULL) { - OPENSSL_PUT_ERROR(SSL, SSL_R_PSK_NO_SERVER_CB); - al = SSL_AD_INTERNAL_ERROR; - goto f_err; - } - - if (CBS_len(&psk_identity) > PSK_MAX_IDENTITY_LEN || - CBS_contains_zero_byte(&psk_identity)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_DATA_LENGTH_TOO_LONG); - al = SSL_AD_ILLEGAL_PARAMETER; - goto f_err; - } - - if (!CBS_strdup(&psk_identity, &ssl->session->psk_identity)) { - al = SSL_AD_INTERNAL_ERROR; - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto f_err; - } - - /* Look up the key for the identity. */ - psk_len = ssl->psk_server_callback(ssl, ssl->session->psk_identity, psk, - sizeof(psk)); - if (psk_len > PSK_MAX_PSK_LEN) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - al = SSL_AD_INTERNAL_ERROR; - goto f_err; - } else if (psk_len == 0) { - /* PSK related to the given identity not found */ - OPENSSL_PUT_ERROR(SSL, SSL_R_PSK_IDENTITY_NOT_FOUND); - al = SSL_AD_UNKNOWN_PSK_IDENTITY; - goto f_err; - } - } - - /* Depending on the key exchange method, compute |premaster_secret| and - * |premaster_secret_len|. */ - if (alg_k & SSL_kRSA) { - /* Allocate a buffer large enough for an RSA decryption. */ - const size_t rsa_size = ssl_private_key_max_signature_len(ssl); - decrypt_buf = OPENSSL_malloc(rsa_size); - if (decrypt_buf == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; - } - - enum ssl_private_key_result_t decrypt_result; - size_t decrypt_len; - if (ssl->state == SSL3_ST_SR_KEY_EXCH_B) { - if (!ssl_has_private_key(ssl) || - ssl_private_key_type(ssl) != EVP_PKEY_RSA) { - al = SSL_AD_HANDSHAKE_FAILURE; - OPENSSL_PUT_ERROR(SSL, SSL_R_MISSING_RSA_CERTIFICATE); - goto f_err; - } - CBS encrypted_premaster_secret; - if (ssl->version > SSL3_VERSION) { - if (!CBS_get_u16_length_prefixed(&client_key_exchange, - &encrypted_premaster_secret) || - CBS_len(&client_key_exchange) != 0) { - al = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, - SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG); - goto f_err; - } - } else { - encrypted_premaster_secret = client_key_exchange; - } - - /* Decrypt with no padding. PKCS#1 padding will be removed as part of the - * timing-sensitive code below. */ - decrypt_result = ssl_private_key_decrypt( - ssl, decrypt_buf, &decrypt_len, rsa_size, - CBS_data(&encrypted_premaster_secret), - CBS_len(&encrypted_premaster_secret)); - } else { - assert(ssl->state == SSL3_ST_SR_KEY_EXCH_C); - /* Complete async decrypt. */ - decrypt_result = ssl_private_key_decrypt_complete( - ssl, decrypt_buf, &decrypt_len, rsa_size); - } - - switch (decrypt_result) { - case ssl_private_key_success: - ssl->rwstate = SSL_NOTHING; - break; - case ssl_private_key_failure: - ssl->rwstate = SSL_NOTHING; - goto err; - case ssl_private_key_retry: - ssl->rwstate = SSL_PRIVATE_KEY_OPERATION; - ssl->state = SSL3_ST_SR_KEY_EXCH_C; - goto err; - } - - assert(decrypt_len == rsa_size); - - /* Prepare a random premaster, to be used on invalid padding. See RFC 5246, - * section 7.4.7.1. */ - premaster_secret_len = SSL_MAX_MASTER_KEY_LENGTH; - premaster_secret = OPENSSL_malloc(premaster_secret_len); - if (premaster_secret == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; - } - if (!RAND_bytes(premaster_secret, premaster_secret_len)) { - goto err; - } - - /* The smallest padded premaster is 11 bytes of overhead. Small keys are - * publicly invalid. */ - if (decrypt_len < 11 + premaster_secret_len) { - al = SSL_AD_DECRYPT_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_DECRYPTION_FAILED); - goto f_err; - } - - /* Check the padding. See RFC 3447, section 7.2.2. */ - size_t padding_len = decrypt_len - premaster_secret_len; - uint8_t good = constant_time_eq_int_8(decrypt_buf[0], 0) & - constant_time_eq_int_8(decrypt_buf[1], 2); - size_t i; - for (i = 2; i < padding_len - 1; i++) { - good &= ~constant_time_is_zero_8(decrypt_buf[i]); - } - good &= constant_time_is_zero_8(decrypt_buf[padding_len - 1]); - - /* The premaster secret must begin with |client_version|. This too must be - * checked in constant time (http://eprint.iacr.org/2003/052/). */ - good &= constant_time_eq_8(decrypt_buf[padding_len], - (unsigned)(ssl->client_version >> 8)); - good &= constant_time_eq_8(decrypt_buf[padding_len + 1], - (unsigned)(ssl->client_version & 0xff)); - - /* Select, in constant time, either the decrypted premaster or the random - * premaster based on |good|. */ - for (i = 0; i < premaster_secret_len; i++) { - premaster_secret[i] = constant_time_select_8( - good, decrypt_buf[padding_len + i], premaster_secret[i]); - } - - OPENSSL_free(decrypt_buf); - decrypt_buf = NULL; - } else if (alg_k & (SSL_kECDHE|SSL_kDHE)) { - /* Parse the ClientKeyExchange. ECDHE uses a u8 length prefix while DHE uses - * u16. */ - CBS peer_key; - int peer_key_ok; - if (alg_k & SSL_kECDHE) { - peer_key_ok = CBS_get_u8_length_prefixed(&client_key_exchange, &peer_key); - } else { - peer_key_ok = - CBS_get_u16_length_prefixed(&client_key_exchange, &peer_key); - } - - if (!peer_key_ok || CBS_len(&client_key_exchange) != 0) { - al = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); - goto f_err; - } - - /* Compute the premaster. */ - uint8_t alert; - if (!SSL_ECDH_CTX_compute_secret(&ssl->s3->tmp.ecdh_ctx, &premaster_secret, - &premaster_secret_len, &alert, - CBS_data(&peer_key), CBS_len(&peer_key))) { - al = alert; - goto f_err; - } - - /* The key exchange state may now be discarded. */ - SSL_ECDH_CTX_cleanup(&ssl->s3->tmp.ecdh_ctx); - } else if (alg_k & SSL_kPSK) { - /* For plain PSK, other_secret is a block of 0s with the same length as the - * pre-shared key. */ - premaster_secret_len = psk_len; - premaster_secret = OPENSSL_malloc(premaster_secret_len); - if (premaster_secret == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; - } - memset(premaster_secret, 0, premaster_secret_len); - } else { - al = SSL_AD_HANDSHAKE_FAILURE; - OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_CIPHER_TYPE); - goto f_err; - } - - /* For a PSK cipher suite, the actual pre-master secret is combined with the - * pre-shared key. */ - if (alg_a & SSL_aPSK) { - CBB new_premaster, child; - uint8_t *new_data; - size_t new_len; - - CBB_zero(&new_premaster); - if (!CBB_init(&new_premaster, 2 + psk_len + 2 + premaster_secret_len) || - !CBB_add_u16_length_prefixed(&new_premaster, &child) || - !CBB_add_bytes(&child, premaster_secret, premaster_secret_len) || - !CBB_add_u16_length_prefixed(&new_premaster, &child) || - !CBB_add_bytes(&child, psk, psk_len) || - !CBB_finish(&new_premaster, &new_data, &new_len)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - CBB_cleanup(&new_premaster); - goto err; - } - - OPENSSL_cleanse(premaster_secret, premaster_secret_len); - OPENSSL_free(premaster_secret); - premaster_secret = new_data; - premaster_secret_len = new_len; - } - - /* Compute the master secret */ - ssl->session->master_key_length = tls1_generate_master_secret( - ssl, ssl->session->master_key, premaster_secret, premaster_secret_len); - if (ssl->session->master_key_length == 0) { - goto err; - } - ssl->session->extended_master_secret = ssl->s3->tmp.extended_master_secret; - - OPENSSL_cleanse(premaster_secret, premaster_secret_len); - OPENSSL_free(premaster_secret); - return 1; - -f_err: - ssl3_send_alert(ssl, SSL3_AL_FATAL, al); -err: - if (premaster_secret != NULL) { - OPENSSL_cleanse(premaster_secret, premaster_secret_len); - OPENSSL_free(premaster_secret); - } - OPENSSL_free(decrypt_buf); - - return -1; -} - -int ssl3_get_cert_verify(SSL *ssl) { - int al, ok, ret = 0; - long n; - CBS certificate_verify, signature; - X509 *peer = ssl->session->peer; - EVP_PKEY *pkey = NULL; - const EVP_MD *md = NULL; - uint8_t digest[EVP_MAX_MD_SIZE]; - size_t digest_length; - EVP_PKEY_CTX *pctx = NULL; - - /* Only RSA and ECDSA client certificates are supported, so a - * CertificateVerify is required if and only if there's a client certificate. - * */ - if (peer == NULL) { - ssl3_free_handshake_buffer(ssl); - return 1; - } - - n = ssl->method->ssl_get_message( - ssl, SSL3_ST_SR_CERT_VRFY_A, SSL3_ST_SR_CERT_VRFY_B, - SSL3_MT_CERTIFICATE_VERIFY, SSL3_RT_MAX_PLAIN_LENGTH, - ssl_dont_hash_message, &ok); - - if (!ok) { - return n; - } - - /* Filter out unsupported certificate types. */ - pkey = X509_get_pubkey(peer); - if (pkey == NULL) { - goto err; - } - if (!(X509_certificate_type(peer, pkey) & EVP_PKT_SIGN) || - (pkey->type != EVP_PKEY_RSA && pkey->type != EVP_PKEY_EC)) { - al = SSL_AD_UNSUPPORTED_CERTIFICATE; - OPENSSL_PUT_ERROR(SSL, SSL_R_PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE); - goto f_err; - } - - CBS_init(&certificate_verify, ssl->init_msg, n); - - /* Determine the digest type if needbe. */ - if (ssl3_protocol_version(ssl) >= TLS1_2_VERSION) { - uint8_t hash, signature_type; - if (!CBS_get_u8(&certificate_verify, &hash) || - !CBS_get_u8(&certificate_verify, &signature_type)) { - al = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); - goto f_err; - } - if (!tls12_check_peer_sigalg(ssl, &md, &al, hash, signature_type, pkey)) { - goto f_err; - } - } - - /* Compute the digest. */ - if (!ssl3_cert_verify_hash(ssl, digest, &digest_length, &md, pkey->type)) { - goto err; - } - - /* The handshake buffer is no longer necessary, and we may hash the current - * message.*/ - ssl3_free_handshake_buffer(ssl); - if (!ssl3_hash_current_message(ssl)) { - goto err; - } - - /* Parse and verify the signature. */ - if (!CBS_get_u16_length_prefixed(&certificate_verify, &signature) || - CBS_len(&certificate_verify) != 0) { - al = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); - goto f_err; - } - - pctx = EVP_PKEY_CTX_new(pkey, NULL); - if (pctx == NULL) { - goto err; - } - if (!EVP_PKEY_verify_init(pctx) || - !EVP_PKEY_CTX_set_signature_md(pctx, md) || - !EVP_PKEY_verify(pctx, CBS_data(&signature), CBS_len(&signature), digest, - digest_length)) { - al = SSL_AD_DECRYPT_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SIGNATURE); - goto f_err; - } - - ret = 1; - - if (0) { - f_err: - ssl3_send_alert(ssl, SSL3_AL_FATAL, al); - } - -err: - EVP_PKEY_CTX_free(pctx); - EVP_PKEY_free(pkey); - - return ret; -} - -int ssl3_get_client_certificate(SSL *ssl) { - int i, ok, al, ret = -1; - X509 *x = NULL; - unsigned long n; - STACK_OF(X509) *sk = NULL; - SHA256_CTX sha256; - CBS certificate_msg, certificate_list; - int is_first_certificate = 1; - - n = ssl->method->ssl_get_message(ssl, SSL3_ST_SR_CERT_A, SSL3_ST_SR_CERT_B, - -1, (long)ssl->max_cert_list, - ssl_hash_message, &ok); - - if (!ok) { - return n; - } - - if (ssl->s3->tmp.message_type == SSL3_MT_CLIENT_KEY_EXCHANGE) { - if ((ssl->verify_mode & SSL_VERIFY_PEER) && - (ssl->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE); - al = SSL_AD_HANDSHAKE_FAILURE; - goto f_err; - } - - /* If tls asked for a client cert, the client must return a 0 list */ - if (ssl->version > SSL3_VERSION && ssl->s3->tmp.cert_request) { - OPENSSL_PUT_ERROR(SSL, - SSL_R_TLS_PEER_DID_NOT_RESPOND_WITH_CERTIFICATE_LIST); - al = SSL_AD_UNEXPECTED_MESSAGE; - goto f_err; - } - ssl->s3->tmp.reuse_message = 1; - - return 1; - } - - if (ssl->s3->tmp.message_type != SSL3_MT_CERTIFICATE) { - al = SSL_AD_UNEXPECTED_MESSAGE; - OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_MESSAGE_TYPE); - goto f_err; - } - - CBS_init(&certificate_msg, ssl->init_msg, n); - - sk = sk_X509_new_null(); - if (sk == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; - } - - if (!CBS_get_u24_length_prefixed(&certificate_msg, &certificate_list) || - CBS_len(&certificate_msg) != 0) { - al = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); - goto f_err; - } - - while (CBS_len(&certificate_list) > 0) { - CBS certificate; - const uint8_t *data; - - if (!CBS_get_u24_length_prefixed(&certificate_list, &certificate)) { - al = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); - goto f_err; - } - - if (is_first_certificate && ssl->ctx->retain_only_sha256_of_client_certs) { - /* If this is the first certificate, and we don't want to keep peer - * certificates in memory, then we hash it right away. */ - SHA256_Init(&sha256); - SHA256_Update(&sha256, CBS_data(&certificate), CBS_len(&certificate)); - SHA256_Final(ssl->session->peer_sha256, &sha256); - ssl->session->peer_sha256_valid = 1; - } - is_first_certificate = 0; - - /* A u24 length cannot overflow a long. */ - data = CBS_data(&certificate); - x = d2i_X509(NULL, &data, (long)CBS_len(&certificate)); - if (x == NULL) { - al = SSL_AD_BAD_CERTIFICATE; - OPENSSL_PUT_ERROR(SSL, ERR_R_ASN1_LIB); - goto f_err; - } - if (data != CBS_data(&certificate) + CBS_len(&certificate)) { - al = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_CERT_LENGTH_MISMATCH); - goto f_err; - } - if (!sk_X509_push(sk, x)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; - } - x = NULL; - } - - if (sk_X509_num(sk) <= 0) { - /* No client certificate so the handshake buffer may be discarded. */ - ssl3_free_handshake_buffer(ssl); - - /* TLS does not mind 0 certs returned */ - if (ssl->version == SSL3_VERSION) { - al = SSL_AD_HANDSHAKE_FAILURE; - OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CERTIFICATES_RETURNED); - goto f_err; - } else if ((ssl->verify_mode & SSL_VERIFY_PEER) && - (ssl->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)) { - /* Fail for TLS only if we required a certificate */ - OPENSSL_PUT_ERROR(SSL, SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE); - al = SSL_AD_HANDSHAKE_FAILURE; - goto f_err; - } - } else { - i = ssl_verify_cert_chain(ssl, sk); - if (i <= 0) { - al = ssl_verify_alarm_type(ssl->verify_result); - OPENSSL_PUT_ERROR(SSL, SSL_R_CERTIFICATE_VERIFY_FAILED); - goto f_err; - } - } - - X509_free(ssl->session->peer); - ssl->session->peer = sk_X509_shift(sk); - ssl->session->verify_result = ssl->verify_result; - - sk_X509_pop_free(ssl->session->cert_chain, X509_free); - ssl->session->cert_chain = sk; - /* Inconsistency alert: cert_chain does *not* include the peer's own - * certificate, while we do include it in s3_clnt.c */ - - sk = NULL; - - ret = 1; - - if (0) { - f_err: - ssl3_send_alert(ssl, SSL3_AL_FATAL, al); - } - -err: - X509_free(x); - sk_X509_pop_free(sk, X509_free); - return ret; -} - -int ssl3_send_server_certificate(SSL *ssl) { - if (ssl->state == SSL3_ST_SW_CERT_A) { - if (!ssl3_output_cert_chain(ssl)) { - return 0; - } - ssl->state = SSL3_ST_SW_CERT_B; - } - - /* SSL3_ST_SW_CERT_B */ - return ssl_do_write(ssl); -} - -/* send a new session ticket (not necessarily for a new session) */ -int ssl3_send_new_session_ticket(SSL *ssl) { - int ret = -1; - uint8_t *session = NULL; - size_t session_len; - EVP_CIPHER_CTX ctx; - HMAC_CTX hctx; - - EVP_CIPHER_CTX_init(&ctx); - HMAC_CTX_init(&hctx); - - if (ssl->state == SSL3_ST_SW_SESSION_TICKET_A) { - uint8_t *p, *macstart; - int len; - unsigned int hlen; - SSL_CTX *tctx = ssl->initial_ctx; - uint8_t iv[EVP_MAX_IV_LENGTH]; - uint8_t key_name[16]; - /* The maximum overhead of encrypting the session is 16 (key name) + IV + - * one block of encryption overhead + HMAC. */ - const size_t max_ticket_overhead = - 16 + EVP_MAX_IV_LENGTH + EVP_MAX_BLOCK_LENGTH + EVP_MAX_MD_SIZE; - - /* Serialize the SSL_SESSION to be encoded into the ticket. */ - if (!SSL_SESSION_to_bytes_for_ticket(ssl->session, &session, - &session_len)) { - goto err; - } - - /* If the session is too long, emit a dummy value rather than abort the - * connection. */ - if (session_len > 0xFFFF - max_ticket_overhead) { - static const char kTicketPlaceholder[] = "TICKET TOO LARGE"; - const size_t placeholder_len = strlen(kTicketPlaceholder); - - OPENSSL_free(session); - session = NULL; - - p = ssl_handshake_start(ssl); - /* Emit ticket_lifetime_hint. */ - l2n(0, p); - /* Emit ticket. */ - s2n(placeholder_len, p); - memcpy(p, kTicketPlaceholder, placeholder_len); - p += placeholder_len; - - len = p - ssl_handshake_start(ssl); - if (!ssl_set_handshake_header(ssl, SSL3_MT_NEWSESSION_TICKET, len)) { - goto err; - } - ssl->state = SSL3_ST_SW_SESSION_TICKET_B; - return ssl_do_write(ssl); - } - - /* Grow buffer if need be: the length calculation is as follows: - * handshake_header_length + 4 (ticket lifetime hint) + 2 (ticket length) + - * max_ticket_overhead + * session_length */ - if (!BUF_MEM_grow(ssl->init_buf, SSL_HM_HEADER_LENGTH(ssl) + 6 + - max_ticket_overhead + session_len)) { - goto err; - } - p = ssl_handshake_start(ssl); - /* Initialize HMAC and cipher contexts. If callback present it does all the - * work otherwise use generated values from parent ctx. */ - if (tctx->tlsext_ticket_key_cb) { - if (tctx->tlsext_ticket_key_cb(ssl, key_name, iv, &ctx, &hctx, - 1 /* encrypt */) < 0) { - goto err; - } - } else { - if (!RAND_bytes(iv, 16) || - !EVP_EncryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, - tctx->tlsext_tick_aes_key, iv) || - !HMAC_Init_ex(&hctx, tctx->tlsext_tick_hmac_key, 16, tlsext_tick_md(), - NULL)) { - goto err; - } - memcpy(key_name, tctx->tlsext_tick_key_name, 16); - } - - /* Ticket lifetime hint (advisory only): We leave this unspecified for - * resumed session (for simplicity), and guess that tickets for new - * sessions will live as long as their sessions. */ - l2n(ssl->hit ? 0 : ssl->session->timeout, p); - - /* Skip ticket length for now */ - p += 2; - /* Output key name */ - macstart = p; - memcpy(p, key_name, 16); - p += 16; - /* output IV */ - memcpy(p, iv, EVP_CIPHER_CTX_iv_length(&ctx)); - p += EVP_CIPHER_CTX_iv_length(&ctx); - /* Encrypt session data */ - if (!EVP_EncryptUpdate(&ctx, p, &len, session, session_len)) { - goto err; - } - p += len; - if (!EVP_EncryptFinal_ex(&ctx, p, &len)) { - goto err; - } - p += len; - - if (!HMAC_Update(&hctx, macstart, p - macstart) || - !HMAC_Final(&hctx, p, &hlen)) { - goto err; - } - - p += hlen; - /* Now write out lengths: p points to end of data written */ - /* Total length */ - len = p - ssl_handshake_start(ssl); - /* Skip ticket lifetime hint */ - p = ssl_handshake_start(ssl) + 4; - s2n(len - 6, p); - if (!ssl_set_handshake_header(ssl, SSL3_MT_NEWSESSION_TICKET, len)) { - goto err; - } - ssl->state = SSL3_ST_SW_SESSION_TICKET_B; - } - - /* SSL3_ST_SW_SESSION_TICKET_B */ - ret = ssl_do_write(ssl); - -err: - OPENSSL_free(session); - EVP_CIPHER_CTX_cleanup(&ctx); - HMAC_CTX_cleanup(&hctx); - return ret; -} - -/* ssl3_get_next_proto reads a Next Protocol Negotiation handshake message. It - * sets the next_proto member in s if found */ -int ssl3_get_next_proto(SSL *ssl) { - int ok; - long n; - CBS next_protocol, selected_protocol, padding; - - /* Clients cannot send a NextProtocol message if we didn't see the extension - * in their ClientHello */ - if (!ssl->s3->next_proto_neg_seen) { - OPENSSL_PUT_ERROR(SSL, SSL_R_GOT_NEXT_PROTO_WITHOUT_EXTENSION); - return -1; - } - - n = ssl->method->ssl_get_message(ssl, SSL3_ST_SR_NEXT_PROTO_A, - SSL3_ST_SR_NEXT_PROTO_B, SSL3_MT_NEXT_PROTO, - 514, /* See the payload format below */ - ssl_hash_message, &ok); - - if (!ok) { - return n; - } - - CBS_init(&next_protocol, ssl->init_msg, n); - - /* The payload looks like: - * uint8 proto_len; - * uint8 proto[proto_len]; - * uint8 padding_len; - * uint8 padding[padding_len]; */ - if (!CBS_get_u8_length_prefixed(&next_protocol, &selected_protocol) || - !CBS_get_u8_length_prefixed(&next_protocol, &padding) || - CBS_len(&next_protocol) != 0 || - !CBS_stow(&selected_protocol, &ssl->s3->next_proto_negotiated, - &ssl->s3->next_proto_negotiated_len)) { - return 0; - } - - return 1; -} - -/* ssl3_get_channel_id reads and verifies a ClientID handshake message. */ -int ssl3_get_channel_id(SSL *ssl) { - int ret = -1, ok; - long n; - uint8_t channel_id_hash[EVP_MAX_MD_SIZE]; - size_t channel_id_hash_len; - const uint8_t *p; - uint16_t extension_type; - EC_GROUP *p256 = NULL; - EC_KEY *key = NULL; - EC_POINT *point = NULL; - ECDSA_SIG sig; - BIGNUM x, y; - CBS encrypted_extensions, extension; - - n = ssl->method->ssl_get_message( - ssl, SSL3_ST_SR_CHANNEL_ID_A, SSL3_ST_SR_CHANNEL_ID_B, - SSL3_MT_ENCRYPTED_EXTENSIONS, 2 + 2 + TLSEXT_CHANNEL_ID_SIZE, - ssl_dont_hash_message, &ok); - - if (!ok) { - return n; - } - - /* Before incorporating the EncryptedExtensions message to the handshake - * hash, compute the hash that should have been signed. */ - if (!tls1_channel_id_hash(ssl, channel_id_hash, &channel_id_hash_len)) { - return -1; - } - assert(channel_id_hash_len == SHA256_DIGEST_LENGTH); - - if (!ssl3_hash_current_message(ssl)) { - return -1; - } - - CBS_init(&encrypted_extensions, ssl->init_msg, n); - - /* EncryptedExtensions could include multiple extensions, but the only - * extension that could be negotiated is ChannelID, so there can only be one - * entry. - * - * The payload looks like: - * uint16 extension_type - * uint16 extension_len; - * uint8 x[32]; - * uint8 y[32]; - * uint8 r[32]; - * uint8 s[32]; */ - - if (!CBS_get_u16(&encrypted_extensions, &extension_type) || - !CBS_get_u16_length_prefixed(&encrypted_extensions, &extension) || - CBS_len(&encrypted_extensions) != 0 || - extension_type != TLSEXT_TYPE_channel_id || - CBS_len(&extension) != TLSEXT_CHANNEL_ID_SIZE) { - OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_MESSAGE); - return -1; - } - - p256 = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1); - if (!p256) { - OPENSSL_PUT_ERROR(SSL, SSL_R_NO_P256_SUPPORT); - return -1; - } - - BN_init(&x); - BN_init(&y); - sig.r = BN_new(); - sig.s = BN_new(); - if (sig.r == NULL || sig.s == NULL) { - goto err; - } - - p = CBS_data(&extension); - if (BN_bin2bn(p + 0, 32, &x) == NULL || - BN_bin2bn(p + 32, 32, &y) == NULL || - BN_bin2bn(p + 64, 32, sig.r) == NULL || - BN_bin2bn(p + 96, 32, sig.s) == NULL) { - goto err; - } - - point = EC_POINT_new(p256); - if (!point || - !EC_POINT_set_affine_coordinates_GFp(p256, point, &x, &y, NULL)) { - goto err; - } - - key = EC_KEY_new(); - if (!key || !EC_KEY_set_group(key, p256) || - !EC_KEY_set_public_key(key, point)) { - goto err; - } - - /* We stored the handshake hash in |tlsext_channel_id| the first time that we - * were called. */ - if (!ECDSA_do_verify(channel_id_hash, channel_id_hash_len, &sig, key)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_CHANNEL_ID_SIGNATURE_INVALID); - ssl->s3->tlsext_channel_id_valid = 0; - goto err; - } - - memcpy(ssl->s3->tlsext_channel_id, p, 64); - ret = 1; - -err: - BN_free(&x); - BN_free(&y); - BN_free(sig.r); - BN_free(sig.s); - EC_KEY_free(key); - EC_POINT_free(point); - EC_GROUP_free(p256); - return ret; -} diff --git a/Sources/BoringSSL/ssl/ssl_aead_ctx.c b/Sources/BoringSSL/ssl/ssl_aead_ctx.c index ea44a6cbf..e18ba69ac 100644 --- a/Sources/BoringSSL/ssl/ssl_aead_ctx.c +++ b/Sources/BoringSSL/ssl/ssl_aead_ctx.c @@ -22,20 +22,22 @@ #include #include +#include "../crypto/internal.h" #include "internal.h" -OPENSSL_COMPILE_ASSERT(EVP_AEAD_MAX_NONCE_LENGTH < 256, - variable_nonce_len_doesnt_fit_in_uint8_t); - SSL_AEAD_CTX *SSL_AEAD_CTX_new(enum evp_aead_direction_t direction, uint16_t version, const SSL_CIPHER *cipher, const uint8_t *enc_key, size_t enc_key_len, const uint8_t *mac_key, size_t mac_key_len, const uint8_t *fixed_iv, size_t fixed_iv_len) { const EVP_AEAD *aead; - size_t discard; - if (!ssl_cipher_get_evp_aead(&aead, &discard, &discard, cipher, version)) { + size_t expected_mac_key_len, expected_fixed_iv_len; + if (!ssl_cipher_get_evp_aead(&aead, &expected_mac_key_len, + &expected_fixed_iv_len, cipher, version) || + /* Ensure the caller returned correct key sizes. */ + expected_fixed_iv_len != fixed_iv_len || + expected_mac_key_len != mac_key_len) { OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); return 0; } @@ -48,9 +50,10 @@ SSL_AEAD_CTX *SSL_AEAD_CTX_new(enum evp_aead_direction_t direction, OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); return 0; } - memcpy(merged_key, mac_key, mac_key_len); - memcpy(merged_key + mac_key_len, enc_key, enc_key_len); - memcpy(merged_key + mac_key_len + enc_key_len, fixed_iv, fixed_iv_len); + OPENSSL_memcpy(merged_key, mac_key, mac_key_len); + OPENSSL_memcpy(merged_key + mac_key_len, enc_key, enc_key_len); + OPENSSL_memcpy(merged_key + mac_key_len + enc_key_len, fixed_iv, + fixed_iv_len); enc_key = merged_key; enc_key_len += mac_key_len; enc_key_len += fixed_iv_len; @@ -61,7 +64,7 @@ SSL_AEAD_CTX *SSL_AEAD_CTX_new(enum evp_aead_direction_t direction, OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); return NULL; } - memset(aead_ctx, 0, sizeof(SSL_AEAD_CTX)); + OPENSSL_memset(aead_ctx, 0, sizeof(SSL_AEAD_CTX)); aead_ctx->cipher = cipher; if (!EVP_AEAD_CTX_init_with_direction( @@ -72,10 +75,12 @@ SSL_AEAD_CTX *SSL_AEAD_CTX_new(enum evp_aead_direction_t direction, } assert(EVP_AEAD_nonce_length(aead) <= EVP_AEAD_MAX_NONCE_LENGTH); + OPENSSL_COMPILE_ASSERT(EVP_AEAD_MAX_NONCE_LENGTH < 256, + variable_nonce_len_doesnt_fit_in_uint8_t); aead_ctx->variable_nonce_len = (uint8_t)EVP_AEAD_nonce_length(aead); if (mac_key_len == 0) { assert(fixed_iv_len <= sizeof(aead_ctx->fixed_nonce)); - memcpy(aead_ctx->fixed_nonce, fixed_iv, fixed_iv_len); + OPENSSL_memcpy(aead_ctx->fixed_nonce, fixed_iv, fixed_iv_len); aead_ctx->fixed_nonce_len = fixed_iv_len; if (cipher->algorithm_enc & SSL_CHACHA20POLY1305) { @@ -92,7 +97,18 @@ SSL_AEAD_CTX *SSL_AEAD_CTX_new(enum evp_aead_direction_t direction, if (cipher->algorithm_enc & (SSL_AES128GCM | SSL_AES256GCM)) { aead_ctx->variable_nonce_included_in_record = 1; } + + /* The TLS 1.3 construction XORs the fixed nonce into the sequence number + * and omits the additional data. */ + if (version >= TLS1_3_VERSION) { + aead_ctx->xor_fixed_nonce = 1; + aead_ctx->variable_nonce_len = 8; + aead_ctx->variable_nonce_included_in_record = 0; + aead_ctx->omit_ad = 1; + assert(fixed_iv_len >= aead_ctx->variable_nonce_len); + } } else { + assert(version < TLS1_3_VERSION); aead_ctx->variable_nonce_included_in_record = 1; aead_ctx->random_variable_nonce = 1; aead_ctx->omit_length_in_ad = 1; @@ -110,19 +126,27 @@ void SSL_AEAD_CTX_free(SSL_AEAD_CTX *aead) { OPENSSL_free(aead); } -size_t SSL_AEAD_CTX_explicit_nonce_len(SSL_AEAD_CTX *aead) { +size_t SSL_AEAD_CTX_explicit_nonce_len(const SSL_AEAD_CTX *aead) { +#if defined(BORINGSSL_UNSAFE_FUZZER_MODE) + aead = NULL; +#endif + if (aead != NULL && aead->variable_nonce_included_in_record) { return aead->variable_nonce_len; } return 0; } -size_t SSL_AEAD_CTX_max_overhead(SSL_AEAD_CTX *aead) { +size_t SSL_AEAD_CTX_max_overhead(const SSL_AEAD_CTX *aead) { +#if defined(BORINGSSL_UNSAFE_FUZZER_MODE) + aead = NULL; +#endif + if (aead == NULL) { return 0; } return EVP_AEAD_max_overhead(aead->ctx.aead) + - SSL_AEAD_CTX_explicit_nonce_len(aead); + SSL_AEAD_CTX_explicit_nonce_len(aead); } /* ssl_aead_ctx_get_ad writes the additional data for |aead| into |out| and @@ -131,7 +155,11 @@ static size_t ssl_aead_ctx_get_ad(SSL_AEAD_CTX *aead, uint8_t out[13], uint8_t type, uint16_t wire_version, const uint8_t seqnum[8], size_t plaintext_len) { - memcpy(out, seqnum, 8); + if (aead->omit_ad) { + return 0; + } + + OPENSSL_memcpy(out, seqnum, 8); size_t len = 8; out[len++] = type; if (!aead->omit_version_in_ad) { @@ -145,18 +173,16 @@ static size_t ssl_aead_ctx_get_ad(SSL_AEAD_CTX *aead, uint8_t out[13], return len; } -int SSL_AEAD_CTX_open(SSL_AEAD_CTX *aead, uint8_t *out, size_t *out_len, - size_t max_out, uint8_t type, uint16_t wire_version, - const uint8_t seqnum[8], const uint8_t *in, - size_t in_len) { +int SSL_AEAD_CTX_open(SSL_AEAD_CTX *aead, CBS *out, uint8_t type, + uint16_t wire_version, const uint8_t seqnum[8], + uint8_t *in, size_t in_len) { +#if defined(BORINGSSL_UNSAFE_FUZZER_MODE) + aead = NULL; +#endif + if (aead == NULL) { /* Handle the initial NULL cipher. */ - if (in_len > max_out) { - OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFER_TOO_SMALL); - return 0; - } - memmove(out, in, in_len); - *out_len = in_len; + CBS_init(out, in, in_len); return 1; } @@ -183,9 +209,9 @@ int SSL_AEAD_CTX_open(SSL_AEAD_CTX *aead, uint8_t *out, size_t *out_len, /* Prepend the fixed nonce, or left-pad with zeros if XORing. */ if (aead->xor_fixed_nonce) { nonce_len = aead->fixed_nonce_len - aead->variable_nonce_len; - memset(nonce, 0, nonce_len); + OPENSSL_memset(nonce, 0, nonce_len); } else { - memcpy(nonce, aead->fixed_nonce, aead->fixed_nonce_len); + OPENSSL_memcpy(nonce, aead->fixed_nonce, aead->fixed_nonce_len); nonce_len += aead->fixed_nonce_len; } @@ -196,39 +222,48 @@ int SSL_AEAD_CTX_open(SSL_AEAD_CTX *aead, uint8_t *out, size_t *out_len, OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_PACKET_LENGTH); return 0; } - memcpy(nonce + nonce_len, in, aead->variable_nonce_len); + OPENSSL_memcpy(nonce + nonce_len, in, aead->variable_nonce_len); in += aead->variable_nonce_len; in_len -= aead->variable_nonce_len; } else { assert(aead->variable_nonce_len == 8); - memcpy(nonce + nonce_len, seqnum, aead->variable_nonce_len); + OPENSSL_memcpy(nonce + nonce_len, seqnum, aead->variable_nonce_len); } nonce_len += aead->variable_nonce_len; /* XOR the fixed nonce, if necessary. */ if (aead->xor_fixed_nonce) { assert(nonce_len == aead->fixed_nonce_len); - size_t i; - for (i = 0; i < aead->fixed_nonce_len; i++) { + for (size_t i = 0; i < aead->fixed_nonce_len; i++) { nonce[i] ^= aead->fixed_nonce[i]; } } - return EVP_AEAD_CTX_open(&aead->ctx, out, out_len, max_out, nonce, nonce_len, - in, in_len, ad, ad_len); + /* Decrypt in-place. */ + size_t len; + if (!EVP_AEAD_CTX_open(&aead->ctx, in, &len, in_len, nonce, nonce_len, + in, in_len, ad, ad_len)) { + return 0; + } + CBS_init(out, in, len); + return 1; } int SSL_AEAD_CTX_seal(SSL_AEAD_CTX *aead, uint8_t *out, size_t *out_len, size_t max_out, uint8_t type, uint16_t wire_version, const uint8_t seqnum[8], const uint8_t *in, size_t in_len) { +#if defined(BORINGSSL_UNSAFE_FUZZER_MODE) + aead = NULL; +#endif + if (aead == NULL) { /* Handle the initial NULL cipher. */ if (in_len > max_out) { OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFER_TOO_SMALL); return 0; } - memmove(out, in, in_len); + OPENSSL_memmove(out, in, in_len); *out_len = in_len; return 1; } @@ -244,9 +279,9 @@ int SSL_AEAD_CTX_seal(SSL_AEAD_CTX *aead, uint8_t *out, size_t *out_len, /* Prepend the fixed nonce, or left-pad with zeros if XORing. */ if (aead->xor_fixed_nonce) { nonce_len = aead->fixed_nonce_len - aead->variable_nonce_len; - memset(nonce, 0, nonce_len); + OPENSSL_memset(nonce, 0, nonce_len); } else { - memcpy(nonce, aead->fixed_nonce, aead->fixed_nonce_len); + OPENSSL_memcpy(nonce, aead->fixed_nonce, aead->fixed_nonce_len); nonce_len += aead->fixed_nonce_len; } @@ -260,7 +295,7 @@ int SSL_AEAD_CTX_seal(SSL_AEAD_CTX *aead, uint8_t *out, size_t *out_len, /* When sending we use the sequence number as the variable part of the * nonce. */ assert(aead->variable_nonce_len == 8); - memcpy(nonce + nonce_len, seqnum, aead->variable_nonce_len); + OPENSSL_memcpy(nonce + nonce_len, seqnum, aead->variable_nonce_len); } nonce_len += aead->variable_nonce_len; @@ -276,7 +311,8 @@ int SSL_AEAD_CTX_seal(SSL_AEAD_CTX *aead, uint8_t *out, size_t *out_len, OPENSSL_PUT_ERROR(SSL, SSL_R_OUTPUT_ALIASES_INPUT); return 0; } - memcpy(out, nonce + aead->fixed_nonce_len, aead->variable_nonce_len); + OPENSSL_memcpy(out, nonce + aead->fixed_nonce_len, + aead->variable_nonce_len); extra_len = aead->variable_nonce_len; out += aead->variable_nonce_len; max_out -= aead->variable_nonce_len; @@ -285,8 +321,7 @@ int SSL_AEAD_CTX_seal(SSL_AEAD_CTX *aead, uint8_t *out, size_t *out_len, /* XOR the fixed nonce, if necessary. */ if (aead->xor_fixed_nonce) { assert(nonce_len == aead->fixed_nonce_len); - size_t i; - for (i = 0; i < aead->fixed_nonce_len; i++) { + for (size_t i = 0; i < aead->fixed_nonce_len; i++) { nonce[i] ^= aead->fixed_nonce[i]; } } diff --git a/Sources/BoringSSL/ssl/ssl_asn1.c b/Sources/BoringSSL/ssl/ssl_asn1.c index 5ec33eb40..3533225af 100644 --- a/Sources/BoringSSL/ssl/ssl_asn1.c +++ b/Sources/BoringSSL/ssl/ssl_asn1.c @@ -85,24 +85,26 @@ #include #include +#include #include #include #include #include +#include "../crypto/internal.h" #include "internal.h" /* An SSL_SESSION is serialized as the following ASN.1 structure: * * SSLSession ::= SEQUENCE { - * version INTEGER (1), -- ignored + * version INTEGER (1), -- session structure version * sslVersion INTEGER, -- protocol version number * cipher OCTET STRING, -- two bytes long * sessionID OCTET STRING, * masterKey OCTET STRING, - * time [1] INTEGER OPTIONAL, -- seconds since UNIX epoch - * timeout [2] INTEGER OPTIONAL, -- in seconds + * time [1] INTEGER, -- seconds since UNIX epoch + * timeout [2] INTEGER, -- in seconds * peer [3] Certificate OPTIONAL, * sessionIDContext [4] OCTET STRING OPTIONAL, * verifyResult [5] INTEGER OPTIONAL, -- one of X509_V_* codes @@ -118,17 +120,28 @@ * ocspResponse [16] OCTET STRING OPTIONAL, * -- stapled OCSP response from the server * extendedMasterSecret [17] BOOLEAN OPTIONAL, - * keyExchangeInfo [18] INTEGER OPTIONAL, + * groupID [18] INTEGER OPTIONAL, + * -- For historical reasons, for legacy DHE or + * -- static RSA ciphers, this field contains + * -- another value to be discarded. * certChain [19] SEQUENCE OF Certificate OPTIONAL, + * ticketAgeAdd [21] OCTET STRING OPTIONAL, + * isServer [22] BOOLEAN DEFAULT TRUE, + * peerSignatureAlgorithm [23] INTEGER OPTIONAL, + * ticketMaxEarlyData [24] INTEGER OPTIONAL, + * authTimeout [25] INTEGER OPTIONAL, -- defaults to timeout + * earlyALPN [26] OCTET STRING OPTIONAL, * } * * Note: historically this serialization has included other optional - * fields. Their presense is currently treated as a parse error: + * fields. Their presence is currently treated as a parse error: * * keyArg [0] IMPLICIT OCTET STRING OPTIONAL, * pskIdentityHint [7] OCTET STRING OPTIONAL, * compressionMethod [11] OCTET STRING OPTIONAL, - * srpUsername [12] OCTET STRING OPTIONAL, */ + * srpUsername [12] OCTET STRING OPTIONAL, + * ticketFlags [20] INTEGER OPTIONAL, + */ static const unsigned kVersion = 1; @@ -160,26 +173,22 @@ static const int kOCSPResponseTag = CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 16; static const int kExtendedMasterSecretTag = CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 17; -static const int kKeyExchangeInfoTag = +static const int kGroupIDTag = CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 18; static const int kCertChainTag = CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 19; - -static int add_X509(CBB *cbb, X509 *x509) { - int len = i2d_X509(x509, NULL); - if (len < 0) { - return 0; - } - uint8_t *buf; - if (!CBB_add_space(cbb, &buf, len)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - return 0; - } - if (buf != NULL && i2d_X509(x509, &buf) < 0) { - return 0; - } - return 1; -} +static const int kTicketAgeAddTag = + CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 21; +static const int kIsServerTag = + CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 22; +static const int kPeerSignatureAlgorithmTag = + CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 23; +static const int kTicketMaxEarlyDataTag = + CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 24; +static const int kAuthTimeoutTag = + CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 25; +static const int kEarlyALPNTag = + CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 26; static int SSL_SESSION_to_bytes_full(const SSL_SESSION *in, uint8_t **out_data, size_t *out_len, int for_ticket) { @@ -206,32 +215,38 @@ static int SSL_SESSION_to_bytes_full(const SSL_SESSION *in, uint8_t **out_data, goto err; } - if (in->time != 0) { - if (!CBB_add_asn1(&session, &child, kTimeTag) || - !CBB_add_asn1_uint64(&child, in->time)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; - } + if (in->time < 0) { + OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); + goto err; } - if (in->timeout != 0) { - if (!CBB_add_asn1(&session, &child, kTimeoutTag) || - !CBB_add_asn1_uint64(&child, in->timeout)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; - } + if (!CBB_add_asn1(&session, &child, kTimeTag) || + !CBB_add_asn1_uint64(&child, in->time)) { + OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + goto err; + } + + if (in->timeout < 0) { + OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); + goto err; + } + + if (!CBB_add_asn1(&session, &child, kTimeoutTag) || + !CBB_add_asn1_uint64(&child, in->timeout)) { + OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + goto err; } /* The peer certificate is only serialized if the SHA-256 isn't * serialized instead. */ - if (in->peer && !in->peer_sha256_valid) { - if (!CBB_add_asn1(&session, &child, kPeerTag)) { + if (sk_CRYPTO_BUFFER_num(in->certs) > 0 && !in->peer_sha256_valid) { + const CRYPTO_BUFFER *buffer = sk_CRYPTO_BUFFER_value(in->certs, 0); + if (!CBB_add_asn1(&session, &child, kPeerTag) || + !CBB_add_bytes(&child, CRYPTO_BUFFER_data(buffer), + CRYPTO_BUFFER_len(buffer))) { OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); goto err; } - if (!add_X509(&child, in->peer)) { - goto err; - } } /* Although it is OPTIONAL and usually empty, OpenSSL has @@ -335,28 +350,81 @@ static int SSL_SESSION_to_bytes_full(const SSL_SESSION *in, uint8_t **out_data, } } - if (in->key_exchange_info > 0 && - (!CBB_add_asn1(&session, &child, kKeyExchangeInfoTag) || - !CBB_add_asn1_uint64(&child, in->key_exchange_info))) { + if (in->group_id > 0 && + (!CBB_add_asn1(&session, &child, kGroupIDTag) || + !CBB_add_asn1_uint64(&child, in->group_id))) { OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); goto err; } /* The certificate chain is only serialized if the leaf's SHA-256 isn't * serialized instead. */ - if (in->cert_chain != NULL && !in->peer_sha256_valid) { + if (in->certs != NULL && + !in->peer_sha256_valid && + sk_CRYPTO_BUFFER_num(in->certs) >= 2) { if (!CBB_add_asn1(&session, &child, kCertChainTag)) { OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); goto err; } - size_t i; - for (i = 0; i < sk_X509_num(in->cert_chain); i++) { - if (!add_X509(&child, sk_X509_value(in->cert_chain, i))) { + for (size_t i = 1; i < sk_CRYPTO_BUFFER_num(in->certs); i++) { + const CRYPTO_BUFFER *buffer = sk_CRYPTO_BUFFER_value(in->certs, i); + if (!CBB_add_bytes(&child, CRYPTO_BUFFER_data(buffer), + CRYPTO_BUFFER_len(buffer))) { + OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); goto err; } } } + if (in->ticket_age_add_valid) { + if (!CBB_add_asn1(&session, &child, kTicketAgeAddTag) || + !CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) || + !CBB_add_u32(&child2, in->ticket_age_add)) { + OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + goto err; + } + } + + if (!in->is_server) { + if (!CBB_add_asn1(&session, &child, kIsServerTag) || + !CBB_add_asn1(&child, &child2, CBS_ASN1_BOOLEAN) || + !CBB_add_u8(&child2, 0x00)) { + OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + goto err; + } + } + + if (in->peer_signature_algorithm != 0 && + (!CBB_add_asn1(&session, &child, kPeerSignatureAlgorithmTag) || + !CBB_add_asn1_uint64(&child, in->peer_signature_algorithm))) { + OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + goto err; + } + + if (in->ticket_max_early_data != 0 && + (!CBB_add_asn1(&session, &child, kTicketMaxEarlyDataTag) || + !CBB_add_asn1_uint64(&child, in->ticket_max_early_data))) { + OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + goto err; + } + + if (in->timeout != in->auth_timeout && + (!CBB_add_asn1(&session, &child, kAuthTimeoutTag) || + !CBB_add_asn1_uint64(&child, in->auth_timeout))) { + OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + goto err; + } + + if (in->early_alpn) { + if (!CBB_add_asn1(&session, &child, kEarlyALPNTag) || + !CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) || + !CBB_add_bytes(&child2, (const uint8_t *)in->early_alpn, + in->early_alpn_len)) { + OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + goto err; + } + } + if (!CBB_finish(&cbb, out_data, out_len)) { OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); goto err; @@ -370,6 +438,22 @@ static int SSL_SESSION_to_bytes_full(const SSL_SESSION *in, uint8_t **out_data, int SSL_SESSION_to_bytes(const SSL_SESSION *in, uint8_t **out_data, size_t *out_len) { + if (in->not_resumable) { + /* If the caller has an unresumable session, e.g. if |SSL_get_session| were + * called on a TLS 1.3 or False Started connection, serialize with a + * placeholder value so it is not accidentally deserialized into a resumable + * one. */ + static const char kNotResumableSession[] = "NOT RESUMABLE"; + + *out_len = strlen(kNotResumableSession); + *out_data = BUF_memdup(kNotResumableSession, *out_len); + if (*out_data == NULL) { + return 0; + } + + return 1; + } + return SSL_SESSION_to_bytes_full(in, out_data, out_len, 0); } @@ -393,7 +477,7 @@ int i2d_SSL_SESSION(SSL_SESSION *in, uint8_t **pp) { } if (pp) { - memcpy(*pp, out, len); + OPENSSL_memcpy(*pp, out, len); *pp += len; } OPENSSL_free(out); @@ -453,15 +537,15 @@ static int SSL_SESSION_parse_octet_string(CBS *cbs, uint8_t **out_ptr, /* SSL_SESSION_parse_bounded_octet_string parses an optional ASN.1 OCTET STRING * explicitly tagged with |tag| of size at most |max_out|. */ static int SSL_SESSION_parse_bounded_octet_string( - CBS *cbs, uint8_t *out, unsigned *out_len, unsigned max_out, unsigned tag) { + CBS *cbs, uint8_t *out, uint8_t *out_len, uint8_t max_out, unsigned tag) { CBS value; if (!CBS_get_optional_asn1_octet_string(cbs, &value, NULL, tag) || CBS_len(&value) > max_out) { OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); return 0; } - memcpy(out, CBS_data(&value), CBS_len(&value)); - *out_len = (unsigned)CBS_len(&value); + OPENSSL_memcpy(out, CBS_data(&value), CBS_len(&value)); + *out_len = (uint8_t)CBS_len(&value); return 1; } @@ -491,22 +575,22 @@ static int SSL_SESSION_parse_u32(CBS *cbs, uint32_t *out, unsigned tag, return 1; } -static X509 *parse_x509(CBS *cbs) { - if (CBS_len(cbs) > LONG_MAX) { +static int SSL_SESSION_parse_u16(CBS *cbs, uint16_t *out, unsigned tag, + uint16_t default_value) { + uint64_t value; + if (!CBS_get_optional_asn1_uint64(cbs, &value, tag, + (uint64_t)default_value) || + value > 0xffff) { OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); - return NULL; - } - const uint8_t *ptr = CBS_data(cbs); - X509 *ret = d2i_X509(NULL, &ptr, (long)CBS_len(cbs)); - if (ret == NULL) { - return NULL; + return 0; } - CBS_skip(cbs, ptr - CBS_data(cbs)); - return ret; + *out = (uint16_t)value; + return 1; } -static SSL_SESSION *SSL_SESSION_parse(CBS *cbs) { - SSL_SESSION *ret = SSL_SESSION_new(); +SSL_SESSION *SSL_SESSION_parse(CBS *cbs, const SSL_X509_METHOD *x509_method, + CRYPTO_BUFFER_POOL *pool) { + SSL_SESSION *ret = ssl_session_new(x509_method); if (ret == NULL) { goto err; } @@ -520,12 +604,6 @@ static SSL_SESSION *SSL_SESSION_parse(CBS *cbs) { OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); goto err; } - /* Only support SSLv3/TLS and DTLS. */ - if ((ssl_version >> 8) != SSL3_VERSION_MAJOR && - (ssl_version >> 8) != (DTLS1_VERSION >> 8)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_SSL_VERSION); - goto err; - } ret->ssl_version = ssl_version; CBS cipher; @@ -550,35 +628,34 @@ static SSL_SESSION *SSL_SESSION_parse(CBS *cbs) { OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); goto err; } - memcpy(ret->session_id, CBS_data(&session_id), CBS_len(&session_id)); + OPENSSL_memcpy(ret->session_id, CBS_data(&session_id), CBS_len(&session_id)); ret->session_id_length = CBS_len(&session_id); - memcpy(ret->master_key, CBS_data(&master_key), CBS_len(&master_key)); + OPENSSL_memcpy(ret->master_key, CBS_data(&master_key), CBS_len(&master_key)); ret->master_key_length = CBS_len(&master_key); - if (!SSL_SESSION_parse_long(&session, &ret->time, kTimeTag, time(NULL)) || - !SSL_SESSION_parse_long(&session, &ret->timeout, kTimeoutTag, 3)) { + CBS child; + uint64_t time, timeout; + if (!CBS_get_asn1(&session, &child, kTimeTag) || + !CBS_get_asn1_uint64(&child, &time) || + time > LONG_MAX || + !CBS_get_asn1(&session, &child, kTimeoutTag) || + !CBS_get_asn1_uint64(&child, &timeout) || + timeout > LONG_MAX) { OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); goto err; } + ret->time = (long)time; + ret->timeout = (long)timeout; + CBS peer; int has_peer; - if (!CBS_get_optional_asn1(&session, &peer, &has_peer, kPeerTag)) { + if (!CBS_get_optional_asn1(&session, &peer, &has_peer, kPeerTag) || + (has_peer && CBS_len(&peer) == 0)) { OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); goto err; } - X509_free(ret->peer); - ret->peer = NULL; - if (has_peer) { - ret->peer = parse_x509(&peer); - if (ret->peer == NULL) { - goto err; - } - if (CBS_len(&peer) != 0) { - OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); - goto err; - } - } + /* |peer| is processed with the certificate chain. */ if (!SSL_SESSION_parse_bounded_octet_string( &session, ret->sid_ctx, &ret->sid_ctx_length, sizeof(ret->sid_ctx), @@ -597,7 +674,7 @@ static SSL_SESSION *SSL_SESSION_parse(CBS *cbs) { } if (CBS_peek_asn1_tag(&session, kPeerSHA256Tag)) { - CBS child, peer_sha256; + CBS peer_sha256; if (!CBS_get_asn1(&session, &child, kPeerSHA256Tag) || !CBS_get_asn1(&child, &peer_sha256, CBS_ASN1_OCTETSTRING) || CBS_len(&peer_sha256) != sizeof(ret->peer_sha256) || @@ -605,7 +682,8 @@ static SSL_SESSION *SSL_SESSION_parse(CBS *cbs) { OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); goto err; } - memcpy(ret->peer_sha256, CBS_data(&peer_sha256), sizeof(ret->peer_sha256)); + OPENSSL_memcpy(ret->peer_sha256, CBS_data(&peer_sha256), + sizeof(ret->peer_sha256)); ret->peer_sha256_valid = 1; } else { ret->peer_sha256_valid = 0; @@ -634,41 +712,110 @@ static SSL_SESSION *SSL_SESSION_parse(CBS *cbs) { } ret->extended_master_secret = !!extended_master_secret; - if (!SSL_SESSION_parse_u32(&session, &ret->key_exchange_info, - kKeyExchangeInfoTag, 0)) { + uint32_t value; + if (!SSL_SESSION_parse_u32(&session, &value, kGroupIDTag, 0)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); + goto err; + } + + /* Historically, the group_id field was used for key-exchange-specific + * information. Discard all but the group ID. */ + if (ret->cipher->algorithm_mkey & (SSL_kRSA | SSL_kDHE)) { + value = 0; + } + + if (value > 0xffff) { OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); goto err; } + ret->group_id = (uint16_t)value; CBS cert_chain; + CBS_init(&cert_chain, NULL, 0); int has_cert_chain; if (!CBS_get_optional_asn1(&session, &cert_chain, &has_cert_chain, - kCertChainTag)) { + kCertChainTag) || + (has_cert_chain && CBS_len(&cert_chain) == 0)) { OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); goto err; } - sk_X509_pop_free(ret->cert_chain, X509_free); - ret->cert_chain = NULL; - if (has_cert_chain) { - ret->cert_chain = sk_X509_new_null(); - if (ret->cert_chain == NULL) { + if (has_cert_chain && !has_peer) { + OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); + goto err; + } + if (has_peer || has_cert_chain) { + ret->certs = sk_CRYPTO_BUFFER_new_null(); + if (ret->certs == NULL) { OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); goto err; } + + if (has_peer) { + /* TODO(agl): this should use the |SSL_CTX|'s pool. */ + CRYPTO_BUFFER *buffer = CRYPTO_BUFFER_new_from_CBS(&peer, pool); + if (buffer == NULL || + !sk_CRYPTO_BUFFER_push(ret->certs, buffer)) { + CRYPTO_BUFFER_free(buffer); + OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + goto err; + } + } + while (CBS_len(&cert_chain) > 0) { - X509 *x509 = parse_x509(&cert_chain); - if (x509 == NULL) { + CBS cert; + if (!CBS_get_any_asn1_element(&cert_chain, &cert, NULL, NULL) || + CBS_len(&cert) == 0) { + OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); goto err; } - if (!sk_X509_push(ret->cert_chain, x509)) { + + /* TODO(agl): this should use the |SSL_CTX|'s pool. */ + CRYPTO_BUFFER *buffer = CRYPTO_BUFFER_new_from_CBS(&cert, pool); + if (buffer == NULL || + !sk_CRYPTO_BUFFER_push(ret->certs, buffer)) { + CRYPTO_BUFFER_free(buffer); OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - X509_free(x509); goto err; } } } - if (CBS_len(&session) != 0) { + if (!x509_method->session_cache_objects(ret)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); + goto err; + } + + CBS age_add; + int age_add_present; + if (!CBS_get_optional_asn1_octet_string(&session, &age_add, &age_add_present, + kTicketAgeAddTag) || + (age_add_present && + !CBS_get_u32(&age_add, &ret->ticket_age_add)) || + CBS_len(&age_add) != 0) { + goto err; + } + ret->ticket_age_add_valid = age_add_present; + + int is_server; + if (!CBS_get_optional_asn1_bool(&session, &is_server, kIsServerTag, + 1 /* default to true */)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); + goto err; + } + /* TODO: in time we can include |is_server| for servers too, then we can + enforce that client and server sessions are never mixed up. */ + + ret->is_server = is_server; + + if (!SSL_SESSION_parse_u16(&session, &ret->peer_signature_algorithm, + kPeerSignatureAlgorithmTag, 0) || + !SSL_SESSION_parse_u32(&session, &ret->ticket_max_early_data, + kTicketMaxEarlyDataTag, 0) || + !SSL_SESSION_parse_long(&session, &ret->auth_timeout, kAuthTimeoutTag, + ret->timeout) || + !SSL_SESSION_parse_octet_string(&session, &ret->early_alpn, + &ret->early_alpn_len, kEarlyALPNTag) || + CBS_len(&session) != 0) { OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); goto err; } @@ -680,10 +827,11 @@ static SSL_SESSION *SSL_SESSION_parse(CBS *cbs) { return NULL; } -SSL_SESSION *SSL_SESSION_from_bytes(const uint8_t *in, size_t in_len) { +SSL_SESSION *SSL_SESSION_from_bytes(const uint8_t *in, size_t in_len, + const SSL_CTX *ctx) { CBS cbs; CBS_init(&cbs, in, in_len); - SSL_SESSION *ret = SSL_SESSION_parse(&cbs); + SSL_SESSION *ret = SSL_SESSION_parse(&cbs, ctx->x509_method, ctx->pool); if (ret == NULL) { return NULL; } @@ -694,25 +842,3 @@ SSL_SESSION *SSL_SESSION_from_bytes(const uint8_t *in, size_t in_len) { } return ret; } - -SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const uint8_t **pp, long length) { - if (length < 0) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - return NULL; - } - - CBS cbs; - CBS_init(&cbs, *pp, length); - - SSL_SESSION *ret = SSL_SESSION_parse(&cbs); - if (ret == NULL) { - return NULL; - } - - if (a) { - SSL_SESSION_free(*a); - *a = ret; - } - *pp = CBS_data(&cbs); - return ret; -} diff --git a/Sources/BoringSSL/ssl/ssl_buffer.c b/Sources/BoringSSL/ssl/ssl_buffer.c index 7fd74e484..c27db8ba8 100644 --- a/Sources/BoringSSL/ssl/ssl_buffer.c +++ b/Sources/BoringSSL/ssl/ssl_buffer.c @@ -24,6 +24,7 @@ #include #include +#include "../crypto/internal.h" #include "internal.h" @@ -67,7 +68,7 @@ static void consume_buffer(SSL3_BUFFER *buf, size_t len) { static void clear_buffer(SSL3_BUFFER *buf) { OPENSSL_free(buf->buf); - memset(buf, 0, sizeof(SSL3_BUFFER)); + OPENSSL_memset(buf, 0, sizeof(SSL3_BUFFER)); } OPENSSL_COMPILE_ASSERT(DTLS1_RT_HEADER_LENGTH + SSL3_RT_MAX_ENCRYPTED_LENGTH <= @@ -85,7 +86,7 @@ static int setup_read_buffer(SSL *ssl) { size_t header_len = ssl_record_prefix_len(ssl); size_t cap = SSL3_RT_MAX_ENCRYPTED_LENGTH; - if (SSL_IS_DTLS(ssl)) { + if (SSL_is_dtls(ssl)) { cap += DTLS1_RT_HEADER_LENGTH; } else { cap += SSL3_RT_HEADER_LENGTH; @@ -113,12 +114,11 @@ static int dtls_read_buffer_next_packet(SSL *ssl) { } /* Read a single packet from |ssl->rbio|. |buf->cap| must fit in an int. */ - ssl->rwstate = SSL_READING; int ret = BIO_read(ssl->rbio, buf->buf + buf->offset, (int)buf->cap); if (ret <= 0) { + ssl->rwstate = SSL_READING; return ret; } - ssl->rwstate = SSL_NOTHING; /* |BIO_read| was bound by |buf->cap|, so this cannot overflow. */ buf->len = (uint16_t)ret; return 1; @@ -136,13 +136,12 @@ static int tls_read_buffer_extend_to(SSL *ssl, size_t len) { while (buf->len < len) { /* The amount of data to read is bounded by |buf->cap|, which must fit in an * int. */ - ssl->rwstate = SSL_READING; int ret = BIO_read(ssl->rbio, buf->buf + buf->offset + buf->len, (int)(len - buf->len)); if (ret <= 0) { + ssl->rwstate = SSL_READING; return ret; } - ssl->rwstate = SSL_NOTHING; /* |BIO_read| was bound by |buf->cap - buf->len|, so this cannot * overflow. */ buf->len += (uint16_t)ret; @@ -164,10 +163,8 @@ int ssl_read_buffer_extend_to(SSL *ssl, size_t len) { return -1; } - ERR_clear_system_error(); - int ret; - if (SSL_IS_DTLS(ssl)) { + if (SSL_is_dtls(ssl)) { /* |len| is ignored for a datagram transport. */ ret = dtls_read_buffer_next_packet(ssl); } else { @@ -186,14 +183,13 @@ void ssl_read_buffer_consume(SSL *ssl, size_t len) { SSL3_BUFFER *buf = &ssl->s3->read_buffer; consume_buffer(buf, len); - if (!SSL_IS_DTLS(ssl)) { - /* The TLS stack never reads beyond the current record, so there will never - * be unconsumed data. If read-ahead is ever reimplemented, - * |ssl_read_buffer_discard| will require a |memcpy| to shift the excess - * back to the front of the buffer, to ensure there is enough space for the - * next record. */ - assert(buf->len == 0); - } + + /* The TLS stack never reads beyond the current record, so there will never be + * unconsumed data. If read-ahead is ever reimplemented, + * |ssl_read_buffer_discard| will require a |memcpy| to shift the excess back + * to the front of the buffer, to ensure there is enough space for the next + * record. */ + assert(SSL_is_dtls(ssl) || len == 0 || buf->len == 0); } void ssl_read_buffer_discard(SSL *ssl) { @@ -229,12 +225,12 @@ int ssl_write_buffer_init(SSL *ssl, uint8_t **out_ptr, size_t max_len) { return 0; } - size_t header_len = ssl_seal_prefix_len(ssl); + size_t header_len = ssl_seal_align_prefix_len(ssl); /* TODO(davidben): This matches the original behavior in keeping the malloc * size consistent. Does this matter? |cap| could just be |max_len|. */ size_t cap = SSL3_RT_MAX_PLAIN_LENGTH + SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD; - if (SSL_IS_DTLS(ssl)) { + if (SSL_is_dtls(ssl)) { cap += DTLS1_RT_HEADER_LENGTH; } else { cap += SSL3_RT_HEADER_LENGTH; @@ -268,12 +264,11 @@ static int tls_write_buffer_flush(SSL *ssl) { SSL3_BUFFER *buf = &ssl->s3->write_buffer; while (buf->len > 0) { - ssl->rwstate = SSL_WRITING; int ret = BIO_write(ssl->wbio, buf->buf + buf->offset, buf->len); if (ret <= 0) { + ssl->rwstate = SSL_WRITING; return ret; } - ssl->rwstate = SSL_NOTHING; consume_buffer(buf, (size_t)ret); } ssl_write_buffer_clear(ssl); @@ -286,16 +281,15 @@ static int dtls_write_buffer_flush(SSL *ssl) { return 1; } - ssl->rwstate = SSL_WRITING; int ret = BIO_write(ssl->wbio, buf->buf + buf->offset, buf->len); if (ret <= 0) { + ssl->rwstate = SSL_WRITING; /* If the write failed, drop the write buffer anyway. Datagram transports * can't write half a packet, so the caller is expected to retry from the * top. */ ssl_write_buffer_clear(ssl); return ret; } - ssl->rwstate = SSL_NOTHING; ssl_write_buffer_clear(ssl); return 1; } @@ -305,9 +299,8 @@ int ssl_write_buffer_flush(SSL *ssl) { OPENSSL_PUT_ERROR(SSL, SSL_R_BIO_NOT_SET); return -1; } - ERR_clear_system_error(); - if (SSL_IS_DTLS(ssl)) { + if (SSL_is_dtls(ssl)) { return dtls_write_buffer_flush(ssl); } else { return tls_write_buffer_flush(ssl); diff --git a/Sources/BoringSSL/ssl/ssl_cert.c b/Sources/BoringSSL/ssl/ssl_cert.c index 983e1a7bd..c60c6fa22 100644 --- a/Sources/BoringSSL/ssl/ssl_cert.c +++ b/Sources/BoringSSL/ssl/ssl_cert.c @@ -114,18 +114,21 @@ #include +#include +#include #include #include #include -#include +#include #include +#include #include #include +#include #include #include -#include "../crypto/dh/internal.h" #include "../crypto/internal.h" #include "internal.h" @@ -138,27 +141,41 @@ int SSL_get_ex_data_X509_STORE_CTX_idx(void) { return 0; } -CERT *ssl_cert_new(void) { +CERT *ssl_cert_new(const SSL_X509_METHOD *x509_method) { CERT *ret = OPENSSL_malloc(sizeof(CERT)); if (ret == NULL) { OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); return NULL; } - memset(ret, 0, sizeof(CERT)); + OPENSSL_memset(ret, 0, sizeof(CERT)); + ret->x509_method = x509_method; return ret; } +static CRYPTO_BUFFER *buffer_up_ref(CRYPTO_BUFFER *buffer) { + CRYPTO_BUFFER_up_ref(buffer); + return buffer; +} + CERT *ssl_cert_dup(CERT *cert) { CERT *ret = OPENSSL_malloc(sizeof(CERT)); if (ret == NULL) { OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); return NULL; } - memset(ret, 0, sizeof(CERT)); + OPENSSL_memset(ret, 0, sizeof(CERT)); - ret->mask_k = cert->mask_k; - ret->mask_a = cert->mask_a; + ret->chain = sk_CRYPTO_BUFFER_deep_copy(cert->chain, buffer_up_ref, + CRYPTO_BUFFER_free); + + if (cert->privatekey != NULL) { + EVP_PKEY_up_ref(cert->privatekey); + ret->privatekey = cert->privatekey; + } + + ret->key_method = cert->key_method; + ret->x509_method = cert->x509_method; if (cert->dh_tmp != NULL) { ret->dh_tmp = DHparams_dup(cert->dh_tmp); @@ -169,25 +186,36 @@ CERT *ssl_cert_dup(CERT *cert) { } ret->dh_tmp_cb = cert->dh_tmp_cb; - if (cert->x509 != NULL) { - ret->x509 = X509_up_ref(cert->x509); - } - - if (cert->privatekey != NULL) { - ret->privatekey = EVP_PKEY_up_ref(cert->privatekey); - } - - if (cert->chain) { - ret->chain = X509_chain_up_ref(cert->chain); - if (!ret->chain) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + if (cert->sigalgs != NULL) { + ret->sigalgs = + BUF_memdup(cert->sigalgs, cert->num_sigalgs * sizeof(cert->sigalgs[0])); + if (ret->sigalgs == NULL) { goto err; } } + ret->num_sigalgs = cert->num_sigalgs; ret->cert_cb = cert->cert_cb; ret->cert_cb_arg = cert->cert_cb_arg; + if (cert->verify_store != NULL) { + X509_STORE_up_ref(cert->verify_store); + ret->verify_store = cert->verify_store; + } + + if (cert->signed_cert_timestamp_list != NULL) { + CRYPTO_BUFFER_up_ref(cert->signed_cert_timestamp_list); + ret->signed_cert_timestamp_list = cert->signed_cert_timestamp_list; + } + + if (cert->ocsp_response != NULL) { + CRYPTO_BUFFER_up_ref(cert->ocsp_response); + ret->ocsp_response = cert->ocsp_response; + } + + ret->sid_ctx_length = cert->sid_ctx_length; + OPENSSL_memcpy(ret->sid_ctx, cert->sid_ctx, sizeof(ret->sid_ctx)); + return ret; err: @@ -201,12 +229,12 @@ void ssl_cert_clear_certs(CERT *cert) { return; } - X509_free(cert->x509); - cert->x509 = NULL; + cert->x509_method->cert_clear(cert); + + sk_CRYPTO_BUFFER_pop_free(cert->chain, CRYPTO_BUFFER_free); + cert->chain = NULL; EVP_PKEY_free(cert->privatekey); cert->privatekey = NULL; - sk_X509_pop_free(cert->chain, X509_free); - cert->chain = NULL; cert->key_method = NULL; } @@ -218,71 +246,122 @@ void ssl_cert_free(CERT *c) { DH_free(c->dh_tmp); ssl_cert_clear_certs(c); - OPENSSL_free(c->peer_sigalgs); - OPENSSL_free(c->digest_nids); + OPENSSL_free(c->sigalgs); + X509_STORE_free(c->verify_store); + CRYPTO_BUFFER_free(c->signed_cert_timestamp_list); + CRYPTO_BUFFER_free(c->ocsp_response); OPENSSL_free(c); } -int ssl_cert_set0_chain(CERT *cert, STACK_OF(X509) *chain) { - sk_X509_pop_free(cert->chain, X509_free); - cert->chain = chain; - return 1; +static void ssl_cert_set_cert_cb(CERT *c, int (*cb)(SSL *ssl, void *arg), + void *arg) { + c->cert_cb = cb; + c->cert_cb_arg = arg; } -int ssl_cert_set1_chain(CERT *cert, STACK_OF(X509) *chain) { - STACK_OF(X509) *dchain; - if (chain == NULL) { - return ssl_cert_set0_chain(cert, NULL); +int ssl_set_cert(CERT *cert, CRYPTO_BUFFER *buffer) { + CBS cert_cbs; + CRYPTO_BUFFER_init_CBS(buffer, &cert_cbs); + EVP_PKEY *pubkey = ssl_cert_parse_pubkey(&cert_cbs); + if (pubkey == NULL) { + return 0; } - dchain = X509_chain_up_ref(chain); - if (dchain == NULL) { + if (!ssl_is_key_type_supported(pubkey->type)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_CERTIFICATE_TYPE); + EVP_PKEY_free(pubkey); return 0; } - if (!ssl_cert_set0_chain(cert, dchain)) { - sk_X509_pop_free(dchain, X509_free); + /* An ECC certificate may be usable for ECDH or ECDSA. We only support ECDSA + * certificates, so sanity-check the key usage extension. */ + if (pubkey->type == EVP_PKEY_EC && + !ssl_cert_check_digital_signature_key_usage(&cert_cbs)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_CERTIFICATE_TYPE); + EVP_PKEY_free(pubkey); return 0; } - return 1; -} + if (cert->privatekey != NULL) { + /* Sanity-check that the private key and the certificate match, unless the + * key is opaque (in case of, say, a smartcard). */ + if (!EVP_PKEY_is_opaque(cert->privatekey) && + !ssl_compare_public_and_private_key(pubkey, cert->privatekey)) { + /* don't fail for a cert/key mismatch, just free current private key + * (when switching to a different cert & key, first this function should + * be used, then ssl_set_pkey */ + EVP_PKEY_free(cert->privatekey); + cert->privatekey = NULL; + /* clear error queue */ + ERR_clear_error(); + } + } -int ssl_cert_add0_chain_cert(CERT *cert, X509 *x509) { + EVP_PKEY_free(pubkey); + + cert->x509_method->cert_flush_cached_leaf(cert); + + if (cert->chain != NULL) { + CRYPTO_BUFFER_free(sk_CRYPTO_BUFFER_value(cert->chain, 0)); + sk_CRYPTO_BUFFER_set(cert->chain, 0, buffer); + CRYPTO_BUFFER_up_ref(buffer); + return 1; + } + + cert->chain = sk_CRYPTO_BUFFER_new_null(); if (cert->chain == NULL) { - cert->chain = sk_X509_new_null(); + return 0; } - if (cert->chain == NULL || !sk_X509_push(cert->chain, x509)) { + + if (!sk_CRYPTO_BUFFER_push(cert->chain, buffer)) { + sk_CRYPTO_BUFFER_free(cert->chain); + cert->chain = NULL; return 0; } + CRYPTO_BUFFER_up_ref(buffer); return 1; } -int ssl_cert_add1_chain_cert(CERT *cert, X509 *x509) { - if (!ssl_cert_add0_chain_cert(cert, x509)) { +int SSL_CTX_use_certificate_ASN1(SSL_CTX *ctx, size_t der_len, + const uint8_t *der) { + CRYPTO_BUFFER *buffer = CRYPTO_BUFFER_new(der, der_len, NULL); + if (buffer == NULL) { return 0; } - X509_up_ref(x509); - return 1; + const int ok = ssl_set_cert(ctx->cert, buffer); + CRYPTO_BUFFER_free(buffer); + return ok; } -void ssl_cert_set_cert_cb(CERT *c, int (*cb)(SSL *ssl, void *arg), void *arg) { - c->cert_cb = cb; - c->cert_cb_arg = arg; +int SSL_use_certificate_ASN1(SSL *ssl, const uint8_t *der, size_t der_len) { + CRYPTO_BUFFER *buffer = CRYPTO_BUFFER_new(der, der_len, NULL); + if (buffer == NULL) { + return 0; + } + + const int ok = ssl_set_cert(ssl->cert, buffer); + CRYPTO_BUFFER_free(buffer); + return ok; } -int ssl_verify_cert_chain(SSL *ssl, STACK_OF(X509) *cert_chain) { +int ssl_verify_cert_chain(SSL *ssl, long *out_verify_result, + STACK_OF(X509) *cert_chain) { if (cert_chain == NULL || sk_X509_num(cert_chain) == 0) { return 0; } + X509_STORE *verify_store = ssl->ctx->cert_store; + if (ssl->cert->verify_store != NULL) { + verify_store = ssl->cert->verify_store; + } + X509 *leaf = sk_X509_value(cert_chain, 0); int ret = 0; X509_STORE_CTX ctx; - if (!X509_STORE_CTX_init(&ctx, ssl->ctx->cert_store, leaf, cert_chain)) { + if (!X509_STORE_CTX_init(&ctx, verify_store, leaf, cert_chain)) { OPENSSL_PUT_ERROR(SSL, ERR_R_X509_LIB); return 0; } @@ -303,13 +382,24 @@ int ssl_verify_cert_chain(SSL *ssl, STACK_OF(X509) *cert_chain) { X509_STORE_CTX_set_verify_cb(&ctx, ssl->verify_callback); } + int verify_ret; if (ssl->ctx->app_verify_callback != NULL) { - ret = ssl->ctx->app_verify_callback(&ctx, ssl->ctx->app_verify_arg); + verify_ret = ssl->ctx->app_verify_callback(&ctx, ssl->ctx->app_verify_arg); } else { - ret = X509_verify_cert(&ctx); + verify_ret = X509_verify_cert(&ctx); + } + + *out_verify_result = ctx.error; + + /* If |SSL_VERIFY_NONE|, the error is non-fatal, but we keep the result. */ + if (verify_ret <= 0 && ssl->verify_mode != SSL_VERIFY_NONE) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, ssl_verify_alarm_type(ctx.error)); + OPENSSL_PUT_ERROR(SSL, SSL_R_CERTIFICATE_VERIFY_FAILED); + goto err; } - ssl->verify_result = ctx.error; + ERR_clear_error(); + ret = 1; err: X509_STORE_CTX_cleanup(&ctx); @@ -328,8 +418,7 @@ STACK_OF(X509_NAME) *SSL_dup_CA_list(STACK_OF(X509_NAME) *list) { return NULL; } - size_t i; - for (i = 0; i < sk_X509_NAME_num(list); i++) { + for (size_t i = 0; i < sk_X509_NAME_num(list); i++) { X509_NAME *name = X509_NAME_dup(sk_X509_NAME_value(list, i)); if (name == NULL || !sk_X509_NAME_push(ret, name)) { X509_NAME_free(name); @@ -360,7 +449,11 @@ STACK_OF(X509_NAME) *SSL_get_client_CA_list(const SSL *ssl) { * |SSL_set_connect_state|. If |handshake_func| is NULL, |ssl| is in an * indeterminate mode and |ssl->server| is unset. */ if (ssl->handshake_func != NULL && !ssl->server) { - return ssl->s3->tmp.ca_names; + if (ssl->s3->hs != NULL) { + return ssl->s3->hs->ca_names; + } + + return NULL; } if (ssl->client_CA != NULL) { @@ -403,137 +496,517 @@ int SSL_CTX_add_client_CA(SSL_CTX *ctx, X509 *x509) { return add_client_CA(&ctx->client_CA, x509); } -/* Add a certificate to a BUF_MEM structure */ -static int ssl_add_cert_to_buf(BUF_MEM *buf, unsigned long *l, X509 *x) { - int n; - uint8_t *p; +int ssl_has_certificate(const SSL *ssl) { + return ssl->cert->chain != NULL && + sk_CRYPTO_BUFFER_value(ssl->cert->chain, 0) != NULL && + ssl_has_private_key(ssl); +} + +STACK_OF(CRYPTO_BUFFER) *ssl_parse_cert_chain(uint8_t *out_alert, + EVP_PKEY **out_pubkey, + uint8_t *out_leaf_sha256, + CBS *cbs, + CRYPTO_BUFFER_POOL *pool) { + *out_pubkey = NULL; + + STACK_OF(CRYPTO_BUFFER) *ret = sk_CRYPTO_BUFFER_new_null(); + if (ret == NULL) { + *out_alert = SSL_AD_INTERNAL_ERROR; + OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + return NULL; + } + + CBS certificate_list; + if (!CBS_get_u24_length_prefixed(cbs, &certificate_list)) { + *out_alert = SSL_AD_DECODE_ERROR; + OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + goto err; + } + + while (CBS_len(&certificate_list) > 0) { + CBS certificate; + if (!CBS_get_u24_length_prefixed(&certificate_list, &certificate) || + CBS_len(&certificate) == 0) { + *out_alert = SSL_AD_DECODE_ERROR; + OPENSSL_PUT_ERROR(SSL, SSL_R_CERT_LENGTH_MISMATCH); + goto err; + } - n = i2d_X509(x, NULL); - if (!BUF_MEM_grow_clean(buf, (int)(n + (*l) + 3))) { - OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB); + if (sk_CRYPTO_BUFFER_num(ret) == 0) { + *out_pubkey = ssl_cert_parse_pubkey(&certificate); + if (*out_pubkey == NULL) { + *out_alert = SSL_AD_DECODE_ERROR; + goto err; + } + + /* Retain the hash of the leaf certificate if requested. */ + if (out_leaf_sha256 != NULL) { + SHA256(CBS_data(&certificate), CBS_len(&certificate), out_leaf_sha256); + } + } + + CRYPTO_BUFFER *buf = + CRYPTO_BUFFER_new_from_CBS(&certificate, pool); + if (buf == NULL) { + *out_alert = SSL_AD_DECODE_ERROR; + goto err; + } + + if (!sk_CRYPTO_BUFFER_push(ret, buf)) { + *out_alert = SSL_AD_INTERNAL_ERROR; + CRYPTO_BUFFER_free(buf); + OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + goto err; + } + } + + return ret; + +err: + EVP_PKEY_free(*out_pubkey); + *out_pubkey = NULL; + sk_CRYPTO_BUFFER_pop_free(ret, CRYPTO_BUFFER_free); + return NULL; +} + +int ssl_add_cert_chain(SSL *ssl, CBB *cbb) { + if (!ssl_has_certificate(ssl)) { + return CBB_add_u24(cbb, 0); + } + + CBB certs; + if (!CBB_add_u24_length_prefixed(cbb, &certs)) { + goto err; + } + + STACK_OF(CRYPTO_BUFFER) *chain = ssl->cert->chain; + for (size_t i = 0; i < sk_CRYPTO_BUFFER_num(chain); i++) { + CRYPTO_BUFFER *buffer = sk_CRYPTO_BUFFER_value(chain, i); + CBB child; + if (!CBB_add_u24_length_prefixed(&certs, &child) || + !CBB_add_bytes(&child, CRYPTO_BUFFER_data(buffer), + CRYPTO_BUFFER_len(buffer)) || + !CBB_flush(&certs)) { + goto err; + } + } + + return CBB_flush(cbb); + +err: + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + return 0; +} + +/* ssl_cert_skip_to_spki parses a DER-encoded, X.509 certificate from |in| and + * positions |*out_tbs_cert| to cover the TBSCertificate, starting at the + * subjectPublicKeyInfo. */ +static int ssl_cert_skip_to_spki(const CBS *in, CBS *out_tbs_cert) { + /* From RFC 5280, section 4.1 + * Certificate ::= SEQUENCE { + * tbsCertificate TBSCertificate, + * signatureAlgorithm AlgorithmIdentifier, + * signatureValue BIT STRING } + + * TBSCertificate ::= SEQUENCE { + * version [0] EXPLICIT Version DEFAULT v1, + * serialNumber CertificateSerialNumber, + * signature AlgorithmIdentifier, + * issuer Name, + * validity Validity, + * subject Name, + * subjectPublicKeyInfo SubjectPublicKeyInfo, + * ... } */ + CBS buf = *in; + + CBS toplevel; + if (!CBS_get_asn1(&buf, &toplevel, CBS_ASN1_SEQUENCE) || + CBS_len(&buf) != 0 || + !CBS_get_asn1(&toplevel, out_tbs_cert, CBS_ASN1_SEQUENCE) || + /* version */ + !CBS_get_optional_asn1( + out_tbs_cert, NULL, NULL, + CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 0) || + /* serialNumber */ + !CBS_get_asn1(out_tbs_cert, NULL, CBS_ASN1_INTEGER) || + /* signature algorithm */ + !CBS_get_asn1(out_tbs_cert, NULL, CBS_ASN1_SEQUENCE) || + /* issuer */ + !CBS_get_asn1(out_tbs_cert, NULL, CBS_ASN1_SEQUENCE) || + /* validity */ + !CBS_get_asn1(out_tbs_cert, NULL, CBS_ASN1_SEQUENCE) || + /* subject */ + !CBS_get_asn1(out_tbs_cert, NULL, CBS_ASN1_SEQUENCE)) { return 0; } - p = (uint8_t *)&(buf->data[*l]); - l2n3(n, p); - i2d_X509(x, &p); - *l += n + 3; return 1; } -/* Add certificate chain to internal SSL BUF_MEM structure. */ -int ssl_add_cert_chain(SSL *ssl, unsigned long *l) { - CERT *cert = ssl->cert; - BUF_MEM *buf = ssl->init_buf; - int no_chain = 0; - size_t i; +EVP_PKEY *ssl_cert_parse_pubkey(const CBS *in) { + CBS buf = *in, tbs_cert; + if (!ssl_cert_skip_to_spki(&buf, &tbs_cert)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_CANNOT_PARSE_LEAF_CERT); + return NULL; + } - X509 *x = cert->x509; - STACK_OF(X509) *chain = cert->chain; + return EVP_parse_public_key(&tbs_cert); +} + +int ssl_compare_public_and_private_key(const EVP_PKEY *pubkey, + const EVP_PKEY *privkey) { + int ret = 0; + + switch (EVP_PKEY_cmp(pubkey, privkey)) { + case 1: + ret = 1; + break; + case 0: + OPENSSL_PUT_ERROR(X509, X509_R_KEY_VALUES_MISMATCH); + break; + case -1: + OPENSSL_PUT_ERROR(X509, X509_R_KEY_TYPE_MISMATCH); + break; + case -2: + OPENSSL_PUT_ERROR(X509, X509_R_UNKNOWN_KEY_TYPE); + default: + assert(0); + break; + } + + return ret; +} + +int ssl_cert_check_private_key(const CERT *cert, const EVP_PKEY *privkey) { + if (privkey == NULL) { + OPENSSL_PUT_ERROR(SSL, SSL_R_NO_PRIVATE_KEY_ASSIGNED); + return 0; + } + + if (cert->chain == NULL || + sk_CRYPTO_BUFFER_value(cert->chain, 0) == NULL) { + OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CERTIFICATE_ASSIGNED); + return 0; + } - if (x == NULL) { - OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CERTIFICATE_SET); + CBS cert_cbs; + CRYPTO_BUFFER_init_CBS(sk_CRYPTO_BUFFER_value(cert->chain, 0), &cert_cbs); + EVP_PKEY *pubkey = ssl_cert_parse_pubkey(&cert_cbs); + if (!pubkey) { + OPENSSL_PUT_ERROR(X509, X509_R_UNKNOWN_KEY_TYPE); return 0; } - if ((ssl->mode & SSL_MODE_NO_AUTO_CHAIN) || chain != NULL) { - no_chain = 1; + const int ok = ssl_compare_public_and_private_key(pubkey, privkey); + EVP_PKEY_free(pubkey); + return ok; +} + +int ssl_cert_check_digital_signature_key_usage(const CBS *in) { + CBS buf = *in; + + CBS tbs_cert, outer_extensions; + int has_extensions; + if (!ssl_cert_skip_to_spki(&buf, &tbs_cert) || + /* subjectPublicKeyInfo */ + !CBS_get_asn1(&tbs_cert, NULL, CBS_ASN1_SEQUENCE) || + /* issuerUniqueID */ + !CBS_get_optional_asn1( + &tbs_cert, NULL, NULL, + CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 1) || + /* subjectUniqueID */ + !CBS_get_optional_asn1( + &tbs_cert, NULL, NULL, + CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 2) || + !CBS_get_optional_asn1( + &tbs_cert, &outer_extensions, &has_extensions, + CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 3)) { + goto parse_err; + } + + if (!has_extensions) { + return 1; } - if (no_chain) { - if (!ssl_add_cert_to_buf(buf, l, x)) { + CBS extensions; + if (!CBS_get_asn1(&outer_extensions, &extensions, CBS_ASN1_SEQUENCE)) { + goto parse_err; + } + + while (CBS_len(&extensions) > 0) { + CBS extension, oid, contents; + if (!CBS_get_asn1(&extensions, &extension, CBS_ASN1_SEQUENCE) || + !CBS_get_asn1(&extension, &oid, CBS_ASN1_OBJECT) || + (CBS_peek_asn1_tag(&extension, CBS_ASN1_BOOLEAN) && + !CBS_get_asn1(&extension, NULL, CBS_ASN1_BOOLEAN)) || + !CBS_get_asn1(&extension, &contents, CBS_ASN1_OCTETSTRING) || + CBS_len(&extension) != 0) { + goto parse_err; + } + + static const uint8_t kKeyUsageOID[3] = {0x55, 0x1d, 0x0f}; + if (CBS_len(&oid) != sizeof(kKeyUsageOID) || + OPENSSL_memcmp(CBS_data(&oid), kKeyUsageOID, sizeof(kKeyUsageOID)) != + 0) { + continue; + } + + CBS bit_string; + if (!CBS_get_asn1(&contents, &bit_string, CBS_ASN1_BITSTRING) || + CBS_len(&contents) != 0) { + goto parse_err; + } + + /* This is the KeyUsage extension. See + * https://tools.ietf.org/html/rfc5280#section-4.2.1.3 */ + if (!CBS_is_valid_asn1_bitstring(&bit_string)) { + goto parse_err; + } + + if (!CBS_asn1_bitstring_has_bit(&bit_string, 0)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_ECC_CERT_NOT_FOR_SIGNING); return 0; } - for (i = 0; i < sk_X509_num(chain); i++) { - x = sk_X509_value(chain, i); - if (!ssl_add_cert_to_buf(buf, l, x)) { - return 0; - } + return 1; + } + + /* No KeyUsage extension found. */ + return 1; + +parse_err: + OPENSSL_PUT_ERROR(SSL, SSL_R_CANNOT_PARSE_LEAF_CERT); + return 0; +} + +static int ca_dn_cmp(const X509_NAME **a, const X509_NAME **b) { + return X509_NAME_cmp(*a, *b); +} + +STACK_OF(X509_NAME) * + ssl_parse_client_CA_list(SSL *ssl, uint8_t *out_alert, CBS *cbs) { + STACK_OF(X509_NAME) *ret = sk_X509_NAME_new(ca_dn_cmp); + X509_NAME *name = NULL; + if (ret == NULL) { + *out_alert = SSL_AD_INTERNAL_ERROR; + OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + return NULL; + } + + CBS child; + if (!CBS_get_u16_length_prefixed(cbs, &child)) { + *out_alert = SSL_AD_DECODE_ERROR; + OPENSSL_PUT_ERROR(SSL, SSL_R_LENGTH_MISMATCH); + goto err; + } + + while (CBS_len(&child) > 0) { + CBS distinguished_name; + if (!CBS_get_u16_length_prefixed(&child, &distinguished_name)) { + *out_alert = SSL_AD_DECODE_ERROR; + OPENSSL_PUT_ERROR(SSL, SSL_R_CA_DN_TOO_LONG); + goto err; + } + + const uint8_t *ptr = CBS_data(&distinguished_name); + /* A u16 length cannot overflow a long. */ + name = d2i_X509_NAME(NULL, &ptr, (long)CBS_len(&distinguished_name)); + if (name == NULL || + ptr != CBS_data(&distinguished_name) + CBS_len(&distinguished_name)) { + *out_alert = SSL_AD_DECODE_ERROR; + OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + goto err; } - } else { - X509_STORE_CTX xs_ctx; - if (!X509_STORE_CTX_init(&xs_ctx, ssl->ctx->cert_store, x, NULL)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_X509_LIB); + if (!sk_X509_NAME_push(ret, name)) { + *out_alert = SSL_AD_INTERNAL_ERROR; + OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + goto err; + } + name = NULL; + } + + return ret; + +err: + X509_NAME_free(name); + sk_X509_NAME_pop_free(ret, X509_NAME_free); + return NULL; +} + +int ssl_add_client_CA_list(SSL *ssl, CBB *cbb) { + CBB child, name_cbb; + if (!CBB_add_u16_length_prefixed(cbb, &child)) { + return 0; + } + + STACK_OF(X509_NAME) *sk = SSL_get_client_CA_list(ssl); + if (sk == NULL) { + return CBB_flush(cbb); + } + + for (size_t i = 0; i < sk_X509_NAME_num(sk); i++) { + X509_NAME *name = sk_X509_NAME_value(sk, i); + int len = i2d_X509_NAME(name, NULL); + if (len < 0) { return 0; } - X509_verify_cert(&xs_ctx); - /* Don't leave errors in the queue */ - ERR_clear_error(); - for (i = 0; i < sk_X509_num(xs_ctx.chain); i++) { - x = sk_X509_value(xs_ctx.chain, i); - - if (!ssl_add_cert_to_buf(buf, l, x)) { - X509_STORE_CTX_cleanup(&xs_ctx); - return 0; - } + uint8_t *ptr; + if (!CBB_add_u16_length_prefixed(&child, &name_cbb) || + !CBB_add_space(&name_cbb, &ptr, (size_t)len) || + (len > 0 && i2d_X509_NAME(name, &ptr) < 0)) { + return 0; } - X509_STORE_CTX_cleanup(&xs_ctx); } - return 1; + return CBB_flush(cbb); } -int SSL_CTX_set0_chain(SSL_CTX *ctx, STACK_OF(X509) *chain) { - return ssl_cert_set0_chain(ctx->cert, chain); +static int set_cert_store(X509_STORE **store_ptr, X509_STORE *new_store, int take_ref) { + X509_STORE_free(*store_ptr); + *store_ptr = new_store; + + if (new_store != NULL && take_ref) { + X509_STORE_up_ref(new_store); + } + + return 1; } -int SSL_CTX_set1_chain(SSL_CTX *ctx, STACK_OF(X509) *chain) { - return ssl_cert_set1_chain(ctx->cert, chain); +int SSL_CTX_set0_verify_cert_store(SSL_CTX *ctx, X509_STORE *store) { + return set_cert_store(&ctx->cert->verify_store, store, 0); } -int SSL_set0_chain(SSL *ssl, STACK_OF(X509) *chain) { - return ssl_cert_set0_chain(ssl->cert, chain); +int SSL_CTX_set1_verify_cert_store(SSL_CTX *ctx, X509_STORE *store) { + return set_cert_store(&ctx->cert->verify_store, store, 1); } -int SSL_set1_chain(SSL *ssl, STACK_OF(X509) *chain) { - return ssl_cert_set1_chain(ssl->cert, chain); +int SSL_set0_verify_cert_store(SSL *ssl, X509_STORE *store) { + return set_cert_store(&ssl->cert->verify_store, store, 0); } -int SSL_CTX_add0_chain_cert(SSL_CTX *ctx, X509 *x509) { - return ssl_cert_add0_chain_cert(ctx->cert, x509); +int SSL_set1_verify_cert_store(SSL *ssl, X509_STORE *store) { + return set_cert_store(&ssl->cert->verify_store, store, 1); } -int SSL_CTX_add1_chain_cert(SSL_CTX *ctx, X509 *x509) { - return ssl_cert_add1_chain_cert(ctx->cert, x509); +void SSL_CTX_set_cert_cb(SSL_CTX *ctx, int (*cb)(SSL *ssl, void *arg), + void *arg) { + ssl_cert_set_cert_cb(ctx->cert, cb, arg); } -int SSL_CTX_add_extra_chain_cert(SSL_CTX *ctx, X509 *x509) { - return SSL_CTX_add0_chain_cert(ctx, x509); +void SSL_set_cert_cb(SSL *ssl, int (*cb)(SSL *ssl, void *arg), void *arg) { + ssl_cert_set_cert_cb(ssl->cert, cb, arg); } -int SSL_add0_chain_cert(SSL *ssl, X509 *x509) { - return ssl_cert_add0_chain_cert(ssl->cert, x509); +int ssl_check_leaf_certificate(SSL_HANDSHAKE *hs, EVP_PKEY *pkey, + const CRYPTO_BUFFER *leaf) { + SSL *const ssl = hs->ssl; + assert(ssl3_protocol_version(ssl) < TLS1_3_VERSION); + + /* Check the certificate's type matches the cipher. */ + int expected_type = ssl_cipher_get_key_type(hs->new_cipher); + assert(expected_type != EVP_PKEY_NONE); + if (pkey->type != expected_type) { + OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CERTIFICATE_TYPE); + return 0; + } + + if (hs->new_cipher->algorithm_auth & SSL_aECDSA) { + CBS leaf_cbs; + CBS_init(&leaf_cbs, CRYPTO_BUFFER_data(leaf), CRYPTO_BUFFER_len(leaf)); + /* ECDSA and ECDH certificates use the same public key format. Instead, + * they are distinguished by the key usage extension in the certificate. */ + if (!ssl_cert_check_digital_signature_key_usage(&leaf_cbs)) { + return 0; + } + + EC_KEY *ec_key = EVP_PKEY_get0_EC_KEY(pkey); + if (ec_key == NULL) { + OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECC_CERT); + return 0; + } + + /* Check the key's group and point format are acceptable. */ + uint16_t group_id; + if (!ssl_nid_to_group_id( + &group_id, EC_GROUP_get_curve_name(EC_KEY_get0_group(ec_key))) || + !tls1_check_group_id(ssl, group_id) || + EC_KEY_get_conv_form(ec_key) != POINT_CONVERSION_UNCOMPRESSED) { + OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECC_CERT); + return 0; + } + } + + return 1; } -int SSL_add1_chain_cert(SSL *ssl, X509 *x509) { - return ssl_cert_add1_chain_cert(ssl->cert, x509); +static int do_client_cert_cb(SSL *ssl, void *arg) { + if (ssl_has_certificate(ssl) || ssl->ctx->client_cert_cb == NULL) { + return 1; + } + + X509 *x509 = NULL; + EVP_PKEY *pkey = NULL; + int ret = ssl->ctx->client_cert_cb(ssl, &x509, &pkey); + if (ret < 0) { + return -1; + } + + if (ret != 0) { + if (!SSL_use_certificate(ssl, x509) || + !SSL_use_PrivateKey(ssl, pkey)) { + return 0; + } + } + + X509_free(x509); + EVP_PKEY_free(pkey); + return 1; } -int SSL_CTX_clear_chain_certs(SSL_CTX *ctx) { - return SSL_CTX_set0_chain(ctx, NULL); +void SSL_CTX_set_client_cert_cb(SSL_CTX *ctx, int (*cb)(SSL *ssl, + X509 **out_x509, + EVP_PKEY **out_pkey)) { + /* Emulate the old client certificate callback with the new one. */ + SSL_CTX_set_cert_cb(ctx, do_client_cert_cb, NULL); + ctx->client_cert_cb = cb; } -int SSL_CTX_clear_extra_chain_certs(SSL_CTX *ctx) { - return SSL_CTX_clear_chain_certs(ctx); +static int set_signed_cert_timestamp_list(CERT *cert, const uint8_t *list, + size_t list_len) { + CBS sct_list; + CBS_init(&sct_list, list, list_len); + if (!ssl_is_sct_list_valid(&sct_list)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SCT_LIST); + return 0; + } + + CRYPTO_BUFFER_free(cert->signed_cert_timestamp_list); + cert->signed_cert_timestamp_list = + CRYPTO_BUFFER_new(CBS_data(&sct_list), CBS_len(&sct_list), NULL); + return cert->signed_cert_timestamp_list != NULL; } -int SSL_clear_chain_certs(SSL *ssl) { - return SSL_set0_chain(ssl, NULL); +int SSL_CTX_set_signed_cert_timestamp_list(SSL_CTX *ctx, const uint8_t *list, + size_t list_len) { + return set_signed_cert_timestamp_list(ctx->cert, list, list_len); } -int SSL_CTX_get0_chain_certs(const SSL_CTX *ctx, STACK_OF(X509) **out_chain) { - *out_chain = ctx->cert->chain; - return 1; +int SSL_set_signed_cert_timestamp_list(SSL *ssl, const uint8_t *list, + size_t list_len) { + return set_signed_cert_timestamp_list(ssl->cert, list, list_len); } -int SSL_CTX_get_extra_chain_certs(const SSL_CTX *ctx, - STACK_OF(X509) **out_chain) { - return SSL_CTX_get0_chain_certs(ctx, out_chain); +int SSL_CTX_set_ocsp_response(SSL_CTX *ctx, const uint8_t *response, + size_t response_len) { + CRYPTO_BUFFER_free(ctx->cert->ocsp_response); + ctx->cert->ocsp_response = CRYPTO_BUFFER_new(response, response_len, NULL); + return ctx->cert->ocsp_response != NULL; } -int SSL_get0_chain_certs(const SSL *ssl, STACK_OF(X509) **out_chain) { - *out_chain = ssl->cert->chain; - return 1; +int SSL_set_ocsp_response(SSL *ssl, const uint8_t *response, + size_t response_len) { + CRYPTO_BUFFER_free(ssl->cert->ocsp_response); + ssl->cert->ocsp_response = CRYPTO_BUFFER_new(response, response_len, NULL); + return ssl->cert->ocsp_response != NULL; } diff --git a/Sources/BoringSSL/ssl/ssl_cipher.c b/Sources/BoringSSL/ssl/ssl_cipher.c index 4ff9f5c22..4a7459f46 100644 --- a/Sources/BoringSSL/ssl/ssl_cipher.c +++ b/Sources/BoringSSL/ssl/ssl_cipher.c @@ -141,7 +141,6 @@ #include #include -#include #include #include @@ -152,6 +151,7 @@ #include #include "internal.h" +#include "../crypto/internal.h" /* kCiphers is an array of all supported ciphers, sorted by id. */ @@ -168,28 +168,6 @@ static const SSL_CIPHER kCiphers[] = { SSL_HANDSHAKE_MAC_DEFAULT, }, - /* Cipher 04 */ - { - SSL3_TXT_RSA_RC4_128_MD5, - SSL3_CK_RSA_RC4_128_MD5, - SSL_kRSA, - SSL_aRSA, - SSL_RC4, - SSL_MD5, - SSL_HANDSHAKE_MAC_DEFAULT, - }, - - /* Cipher 05 */ - { - SSL3_TXT_RSA_RC4_128_SHA, - SSL3_CK_RSA_RC4_128_SHA, - SSL_kRSA, - SSL_aRSA, - SSL_RC4, - SSL_SHA1, - SSL_HANDSHAKE_MAC_DEFAULT, - }, - /* Cipher 0A */ { SSL3_TXT_RSA_DES_192_CBC3_SHA, @@ -297,17 +275,6 @@ static const SSL_CIPHER kCiphers[] = { /* PSK cipher suites. */ - /* Cipher 8A */ - { - TLS1_TXT_PSK_WITH_RC4_128_SHA, - TLS1_CK_PSK_WITH_RC4_128_SHA, - SSL_kPSK, - SSL_aPSK, - SSL_RC4, - SSL_SHA1, - SSL_HANDSHAKE_MAC_DEFAULT, - }, - /* Cipher 8C */ { TLS1_TXT_PSK_WITH_AES_128_CBC_SHA, @@ -376,15 +343,39 @@ static const SSL_CIPHER kCiphers[] = { SSL_HANDSHAKE_MAC_SHA384, }, - /* Cipher C007 */ + /* TLS 1.3 suites. */ + + /* Cipher 1301 */ { - TLS1_TXT_ECDHE_ECDSA_WITH_RC4_128_SHA, - TLS1_CK_ECDHE_ECDSA_WITH_RC4_128_SHA, - SSL_kECDHE, - SSL_aECDSA, - SSL_RC4, - SSL_SHA1, - SSL_HANDSHAKE_MAC_DEFAULT, + TLS1_TXT_AES_128_GCM_SHA256, + TLS1_CK_AES_128_GCM_SHA256, + SSL_kGENERIC, + SSL_aGENERIC, + SSL_AES128GCM, + SSL_AEAD, + SSL_HANDSHAKE_MAC_SHA256, + }, + + /* Cipher 1302 */ + { + TLS1_TXT_AES_256_GCM_SHA384, + TLS1_CK_AES_256_GCM_SHA384, + SSL_kGENERIC, + SSL_aGENERIC, + SSL_AES256GCM, + SSL_AEAD, + SSL_HANDSHAKE_MAC_SHA384, + }, + + /* Cipher 1303 */ + { + TLS1_TXT_CHACHA20_POLY1305_SHA256, + TLS1_CK_CHACHA20_POLY1305_SHA256, + SSL_kGENERIC, + SSL_aGENERIC, + SSL_CHACHA20POLY1305, + SSL_AEAD, + SSL_HANDSHAKE_MAC_SHA256, }, /* Cipher C009 */ @@ -409,17 +400,6 @@ static const SSL_CIPHER kCiphers[] = { SSL_HANDSHAKE_MAC_DEFAULT, }, - /* Cipher C011 */ - { - TLS1_TXT_ECDHE_RSA_WITH_RC4_128_SHA, - TLS1_CK_ECDHE_RSA_WITH_RC4_128_SHA, - SSL_kECDHE, - SSL_aRSA, - SSL_RC4, - SSL_SHA1, - SSL_HANDSHAKE_MAC_DEFAULT, - }, - /* Cipher C013 */ { TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA, @@ -562,28 +542,6 @@ static const SSL_CIPHER kCiphers[] = { /* ChaCha20-Poly1305 cipher suites. */ -#if !defined(BORINGSSL_ANDROID_SYSTEM) - { - TLS1_TXT_ECDHE_RSA_WITH_CHACHA20_POLY1305_OLD, - TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305_OLD, - SSL_kECDHE, - SSL_aRSA, - SSL_CHACHA20POLY1305_OLD, - SSL_AEAD, - SSL_HANDSHAKE_MAC_SHA256, - }, - - { - TLS1_TXT_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_OLD, - TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305_OLD, - SSL_kECDHE, - SSL_aECDSA, - SSL_CHACHA20POLY1305_OLD, - SSL_AEAD, - SSL_HANDSHAKE_MAC_SHA256, - }, -#endif - /* Cipher CCA8 */ { TLS1_TXT_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, @@ -616,9 +574,10 @@ static const SSL_CIPHER kCiphers[] = { SSL_AEAD, SSL_HANDSHAKE_MAC_SHA256, }, + }; -static const size_t kCiphersLen = sizeof(kCiphers) / sizeof(kCiphers[0]); +static const size_t kCiphersLen = OPENSSL_ARRAY_SIZE(kCiphers); #define CIPHER_ADD 1 #define CIPHER_KILL 2 @@ -652,7 +611,7 @@ typedef struct cipher_alias_st { } CIPHER_ALIAS; static const CIPHER_ALIAS kCipherAliases[] = { - /* "ALL" doesn't include eNULL (must be specifically enabled) */ + /* "ALL" doesn't include eNULL. It must be explicitly enabled. */ {"ALL", ~0u, ~0u, ~SSL_eNULL, ~0u, 0}, /* The "COMPLEMENTOFDEFAULT" rule is omitted. It matches nothing. */ @@ -689,16 +648,13 @@ static const CIPHER_ALIAS kCipherAliases[] = { /* symmetric encryption aliases */ {"3DES", ~0u, ~0u, SSL_3DES, ~0u, 0}, - {"RC4", ~0u, ~0u, SSL_RC4, ~0u, 0}, {"AES128", ~0u, ~0u, SSL_AES128 | SSL_AES128GCM, ~0u, 0}, {"AES256", ~0u, ~0u, SSL_AES256 | SSL_AES256GCM, ~0u, 0}, {"AES", ~0u, ~0u, SSL_AES, ~0u, 0}, {"AESGCM", ~0u, ~0u, SSL_AES128GCM | SSL_AES256GCM, ~0u, 0}, - {"CHACHA20", ~0u, ~0u, SSL_CHACHA20POLY1305 | SSL_CHACHA20POLY1305_OLD, ~0u, - 0}, + {"CHACHA20", ~0u, ~0u, SSL_CHACHA20POLY1305, ~0u, 0}, /* MAC aliases */ - {"MD5", ~0u, ~0u, ~0u, SSL_MD5, 0}, {"SHA1", ~0u, ~0u, ~SSL_eNULL, SSL_SHA1, 0}, {"SHA", ~0u, ~0u, ~SSL_eNULL, SSL_SHA1, 0}, {"SHA256", ~0u, ~0u, ~0u, SSL_SHA256, 0}, @@ -711,13 +667,11 @@ static const CIPHER_ALIAS kCipherAliases[] = { {"TLSv1.2", ~0u, ~0u, ~SSL_eNULL, ~0u, TLS1_2_VERSION}, /* Legacy strength classes. */ - {"MEDIUM", ~0u, ~0u, SSL_RC4, ~0u, 0}, - {"HIGH", ~0u, ~0u, ~(SSL_eNULL|SSL_RC4), ~0u, 0}, - {"FIPS", ~0u, ~0u, ~(SSL_eNULL|SSL_RC4), ~0u, 0}, + {"HIGH", ~0u, ~0u, ~SSL_eNULL, ~0u, 0}, + {"FIPS", ~0u, ~0u, ~SSL_eNULL, ~0u, 0}, }; -static const size_t kCipherAliasesLen = - sizeof(kCipherAliases) / sizeof(kCipherAliases[0]); +static const size_t kCipherAliasesLen = OPENSSL_ARRAY_SIZE(kCipherAliases); static int ssl_cipher_id_cmp(const void *in_a, const void *in_b) { const SSL_CIPHER *a = in_a; @@ -732,10 +686,6 @@ static int ssl_cipher_id_cmp(const void *in_a, const void *in_b) { } } -static int ssl_cipher_ptr_id_cmp(const SSL_CIPHER **a, const SSL_CIPHER **b) { - return ssl_cipher_id_cmp(*a, *b); -} - const SSL_CIPHER *SSL_get_cipher_by_value(uint16_t value) { SSL_CIPHER c; @@ -752,140 +702,96 @@ int ssl_cipher_get_evp_aead(const EVP_AEAD **out_aead, *out_mac_secret_len = 0; *out_fixed_iv_len = 0; - switch (cipher->algorithm_enc) { - case SSL_AES128GCM: + if (cipher->algorithm_mac == SSL_AEAD) { + if (cipher->algorithm_enc == SSL_AES128GCM) { *out_aead = EVP_aead_aes_128_gcm(); *out_fixed_iv_len = 4; - return 1; - - case SSL_AES256GCM: + } else if (cipher->algorithm_enc == SSL_AES256GCM) { *out_aead = EVP_aead_aes_256_gcm(); *out_fixed_iv_len = 4; - return 1; - -#if !defined(BORINGSSL_ANDROID_SYSTEM) - case SSL_CHACHA20POLY1305_OLD: - *out_aead = EVP_aead_chacha20_poly1305_old(); - *out_fixed_iv_len = 0; - return 1; -#endif - - case SSL_CHACHA20POLY1305: + } else if (cipher->algorithm_enc == SSL_CHACHA20POLY1305) { *out_aead = EVP_aead_chacha20_poly1305(); *out_fixed_iv_len = 12; - return 1; - - case SSL_RC4: - switch (cipher->algorithm_mac) { - case SSL_MD5: - if (version == SSL3_VERSION) { - *out_aead = EVP_aead_rc4_md5_ssl3(); - } else { - *out_aead = EVP_aead_rc4_md5_tls(); - } - *out_mac_secret_len = MD5_DIGEST_LENGTH; - return 1; - case SSL_SHA1: - if (version == SSL3_VERSION) { - *out_aead = EVP_aead_rc4_sha1_ssl3(); - } else { - *out_aead = EVP_aead_rc4_sha1_tls(); - } - *out_mac_secret_len = SHA_DIGEST_LENGTH; - return 1; - default: - return 0; - } + } else { + return 0; + } - case SSL_AES128: - switch (cipher->algorithm_mac) { - case SSL_SHA1: - if (version == SSL3_VERSION) { - *out_aead = EVP_aead_aes_128_cbc_sha1_ssl3(); - *out_fixed_iv_len = 16; - } else if (version == TLS1_VERSION) { - *out_aead = EVP_aead_aes_128_cbc_sha1_tls_implicit_iv(); - *out_fixed_iv_len = 16; - } else { - *out_aead = EVP_aead_aes_128_cbc_sha1_tls(); - } - *out_mac_secret_len = SHA_DIGEST_LENGTH; - return 1; - case SSL_SHA256: - *out_aead = EVP_aead_aes_128_cbc_sha256_tls(); - *out_mac_secret_len = SHA256_DIGEST_LENGTH; - return 1; - default: - return 0; + /* In TLS 1.3, the iv_len is equal to the AEAD nonce length whereas the code + * above computes the TLS 1.2 construction. */ + if (version >= TLS1_3_VERSION) { + *out_fixed_iv_len = EVP_AEAD_nonce_length(*out_aead); + } + } else if (cipher->algorithm_mac == SSL_SHA1) { + if (cipher->algorithm_enc == SSL_eNULL) { + if (version == SSL3_VERSION) { + *out_aead = EVP_aead_null_sha1_ssl3(); + } else { + *out_aead = EVP_aead_null_sha1_tls(); } - - case SSL_AES256: - switch (cipher->algorithm_mac) { - case SSL_SHA1: - if (version == SSL3_VERSION) { - *out_aead = EVP_aead_aes_256_cbc_sha1_ssl3(); - *out_fixed_iv_len = 16; - } else if (version == TLS1_VERSION) { - *out_aead = EVP_aead_aes_256_cbc_sha1_tls_implicit_iv(); - *out_fixed_iv_len = 16; - } else { - *out_aead = EVP_aead_aes_256_cbc_sha1_tls(); - } - *out_mac_secret_len = SHA_DIGEST_LENGTH; - return 1; - case SSL_SHA256: - *out_aead = EVP_aead_aes_256_cbc_sha256_tls(); - *out_mac_secret_len = SHA256_DIGEST_LENGTH; - return 1; - case SSL_SHA384: - *out_aead = EVP_aead_aes_256_cbc_sha384_tls(); - *out_mac_secret_len = SHA384_DIGEST_LENGTH; - return 1; - default: - return 0; + } else if (cipher->algorithm_enc == SSL_3DES) { + if (version == SSL3_VERSION) { + *out_aead = EVP_aead_des_ede3_cbc_sha1_ssl3(); + *out_fixed_iv_len = 8; + } else if (version == TLS1_VERSION) { + *out_aead = EVP_aead_des_ede3_cbc_sha1_tls_implicit_iv(); + *out_fixed_iv_len = 8; + } else { + *out_aead = EVP_aead_des_ede3_cbc_sha1_tls(); } - - case SSL_3DES: - switch (cipher->algorithm_mac) { - case SSL_SHA1: - if (version == SSL3_VERSION) { - *out_aead = EVP_aead_des_ede3_cbc_sha1_ssl3(); - *out_fixed_iv_len = 8; - } else if (version == TLS1_VERSION) { - *out_aead = EVP_aead_des_ede3_cbc_sha1_tls_implicit_iv(); - *out_fixed_iv_len = 8; - } else { - *out_aead = EVP_aead_des_ede3_cbc_sha1_tls(); - } - *out_mac_secret_len = SHA_DIGEST_LENGTH; - return 1; - default: - return 0; + } else if (cipher->algorithm_enc == SSL_AES128) { + if (version == SSL3_VERSION) { + *out_aead = EVP_aead_aes_128_cbc_sha1_ssl3(); + *out_fixed_iv_len = 16; + } else if (version == TLS1_VERSION) { + *out_aead = EVP_aead_aes_128_cbc_sha1_tls_implicit_iv(); + *out_fixed_iv_len = 16; + } else { + *out_aead = EVP_aead_aes_128_cbc_sha1_tls(); } - - case SSL_eNULL: - switch (cipher->algorithm_mac) { - case SSL_SHA1: - if (version == SSL3_VERSION) { - *out_aead = EVP_aead_null_sha1_ssl3(); - } else { - *out_aead = EVP_aead_null_sha1_tls(); - } - *out_mac_secret_len = SHA_DIGEST_LENGTH; - return 1; - default: - return 0; + } else if (cipher->algorithm_enc == SSL_AES256) { + if (version == SSL3_VERSION) { + *out_aead = EVP_aead_aes_256_cbc_sha1_ssl3(); + *out_fixed_iv_len = 16; + } else if (version == TLS1_VERSION) { + *out_aead = EVP_aead_aes_256_cbc_sha1_tls_implicit_iv(); + *out_fixed_iv_len = 16; + } else { + *out_aead = EVP_aead_aes_256_cbc_sha1_tls(); } + } else { + return 0; + } - default: + *out_mac_secret_len = SHA_DIGEST_LENGTH; + } else if (cipher->algorithm_mac == SSL_SHA256) { + if (cipher->algorithm_enc == SSL_AES128) { + *out_aead = EVP_aead_aes_128_cbc_sha256_tls(); + } else if (cipher->algorithm_enc == SSL_AES256) { + *out_aead = EVP_aead_aes_256_cbc_sha256_tls(); + } else { return 0; + } + + *out_mac_secret_len = SHA256_DIGEST_LENGTH; + } else if (cipher->algorithm_mac == SSL_SHA384) { + if (cipher->algorithm_enc != SSL_AES256) { + return 0; + } + + *out_aead = EVP_aead_aes_256_cbc_sha384_tls(); + *out_mac_secret_len = SHA384_DIGEST_LENGTH; + } else { + return 0; } + + return 1; } -const EVP_MD *ssl_get_handshake_digest(uint32_t algorithm_prf) { +const EVP_MD *ssl_get_handshake_digest(uint32_t algorithm_prf, + uint16_t version) { switch (algorithm_prf) { case SSL_HANDSHAKE_MAC_DEFAULT: - return EVP_sha1(); + return version >= TLS1_2_VERSION ? EVP_sha256() : EVP_md5_sha1(); case SSL_HANDSHAKE_MAC_SHA256: return EVP_sha256(); case SSL_HANDSHAKE_MAC_SHA384: @@ -952,10 +858,11 @@ static void ssl_cipher_collect_ciphers(const SSL_PROTOCOL_METHOD *ssl_method, /* The set of ciphers is static, but some subset may be unsupported by * |ssl_method|, so the list may be smaller. */ size_t co_list_num = 0; - size_t i; - for (i = 0; i < kCiphersLen; i++) { + for (size_t i = 0; i < kCiphersLen; i++) { const SSL_CIPHER *cipher = &kCiphers[i]; - if (ssl_method->supports_cipher(cipher)) { + if (ssl_method->supports_cipher(cipher) && + /* TLS 1.3 ciphers do not participate in this mechanism. */ + cipher->algorithm_mkey != SSL_kGENERIC) { co_list[co_list_num].cipher = cipher; co_list[co_list_num].next = NULL; co_list[co_list_num].prev = NULL; @@ -972,7 +879,7 @@ static void ssl_cipher_collect_ciphers(const SSL_PROTOCOL_METHOD *ssl_method, if (co_list_num > 1) { co_list[0].next = &co_list[1]; - for (i = 1; i < co_list_num - 1; i++) { + for (size_t i = 1; i < co_list_num - 1; i++) { co_list[i].prev = &co_list[i - 1]; co_list[i].next = &co_list[i + 1]; } @@ -1051,13 +958,14 @@ static void ssl_cipher_apply_rule( if (strength_bits != SSL_CIPHER_get_bits(cp, NULL)) { continue; } - } else if (!(alg_mkey & cp->algorithm_mkey) || - !(alg_auth & cp->algorithm_auth) || - !(alg_enc & cp->algorithm_enc) || - !(alg_mac & cp->algorithm_mac) || - (min_version != 0 && - SSL_CIPHER_get_min_version(cp) != min_version)) { - continue; + } else { + if (!(alg_mkey & cp->algorithm_mkey) || + !(alg_auth & cp->algorithm_auth) || + !(alg_enc & cp->algorithm_enc) || + !(alg_mac & cp->algorithm_mac) || + (min_version != 0 && SSL_CIPHER_get_min_version(cp) != min_version)) { + continue; + } } /* add the cipher if it has not been added yet. */ @@ -1137,7 +1045,7 @@ static int ssl_cipher_strength_sort(CIPHER_ORDER **head_p, OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); return 0; } - memset(number_uses, 0, (max_strength_bits + 1) * sizeof(int)); + OPENSSL_memset(number_uses, 0, (max_strength_bits + 1) * sizeof(int)); /* Now find the strength_bits values actually used. */ curr = *head_p; @@ -1162,16 +1070,15 @@ static int ssl_cipher_strength_sort(CIPHER_ORDER **head_p, static int ssl_cipher_process_rulestr(const SSL_PROTOCOL_METHOD *ssl_method, const char *rule_str, CIPHER_ORDER **head_p, - CIPHER_ORDER **tail_p) { + CIPHER_ORDER **tail_p, int strict) { uint32_t alg_mkey, alg_auth, alg_enc, alg_mac; uint16_t min_version; const char *l, *buf; - int multi, skip_rule, rule, retval, ok, in_group = 0, has_group = 0; + int multi, skip_rule, rule, ok, in_group = 0, has_group = 0; size_t j, buf_len; uint32_t cipher_id; char ch; - retval = 1; l = rule_str; for (;;) { ch = *l; @@ -1197,8 +1104,7 @@ static int ssl_cipher_process_rulestr(const SSL_PROTOCOL_METHOD *ssl_method, } else if (!(ch >= 'a' && ch <= 'z') && !(ch >= 'A' && ch <= 'Z') && !(ch >= '0' && ch <= '9')) { OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_OPERATOR_IN_GROUP); - retval = in_group = 0; - break; + return 0; } else { rule = CIPHER_ADD; } @@ -1217,8 +1123,7 @@ static int ssl_cipher_process_rulestr(const SSL_PROTOCOL_METHOD *ssl_method, } else if (ch == '[') { if (in_group) { OPENSSL_PUT_ERROR(SSL, SSL_R_NESTED_GROUP); - retval = in_group = 0; - break; + return 0; } in_group = 1; has_group = 1; @@ -1232,8 +1137,7 @@ static int ssl_cipher_process_rulestr(const SSL_PROTOCOL_METHOD *ssl_method, * Otherwise the in_group bits will get mixed up. */ if (has_group && rule != CIPHER_ADD) { OPENSSL_PUT_ERROR(SSL, SSL_R_MIXED_SPECIAL_OPERATOR_WITH_GROUPS); - retval = in_group = 0; - break; + return 0; } if (ITEM_SEP(ch)) { @@ -1264,9 +1168,7 @@ static int ssl_cipher_process_rulestr(const SSL_PROTOCOL_METHOD *ssl_method, /* We hit something we cannot deal with, it is no command or separator * nor alphanumeric, so we call this an error. */ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_COMMAND); - retval = in_group = 0; - l++; - break; + return 0; } if (rule == CIPHER_SPECIAL) { @@ -1304,6 +1206,10 @@ static int ssl_cipher_process_rulestr(const SSL_PROTOCOL_METHOD *ssl_method, } if (j == kCipherAliasesLen) { skip_rule = 1; + if (strict) { + OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_COMMAND); + return 0; + } } } @@ -1315,29 +1221,6 @@ static int ssl_cipher_process_rulestr(const SSL_PROTOCOL_METHOD *ssl_method, multi = 1; } - /* If one of the CHACHA20_POLY1305 variants is selected, include the other - * as well. They have the same name to avoid requiring changes in - * configuration. Apply this transformation late so that the cipher name - * still behaves as an exact name and not an alias in multipart rules. - * - * This is temporary and will be removed when the pre-standard construction - * is removed. */ - if (cipher_id == TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305_OLD || - cipher_id == TLS1_CK_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256) { - cipher_id = 0; - alg_mkey = SSL_kECDHE; - alg_auth = SSL_aRSA; - alg_enc = SSL_CHACHA20POLY1305|SSL_CHACHA20POLY1305_OLD; - alg_mac = SSL_AEAD; - } else if (cipher_id == TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305_OLD || - cipher_id == TLS1_CK_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256) { - cipher_id = 0; - alg_mkey = SSL_kECDHE; - alg_auth = SSL_aECDSA; - alg_enc = SSL_CHACHA20POLY1305|SSL_CHACHA20POLY1305_OLD; - alg_mac = SSL_AEAD; - } - /* Ok, we have the rule, now apply it. */ if (rule == CIPHER_SPECIAL) { /* special command */ @@ -1349,7 +1232,7 @@ static int ssl_cipher_process_rulestr(const SSL_PROTOCOL_METHOD *ssl_method, } if (ok == 0) { - retval = 0; + return 0; } /* We do not support any "multi" options together with "@", so throw away @@ -1365,20 +1248,17 @@ static int ssl_cipher_process_rulestr(const SSL_PROTOCOL_METHOD *ssl_method, if (in_group) { OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_COMMAND); - retval = 0; + return 0; } - return retval; + return 1; } STACK_OF(SSL_CIPHER) * ssl_create_cipher_list(const SSL_PROTOCOL_METHOD *ssl_method, struct ssl_cipher_preference_list_st **out_cipher_list, - STACK_OF(SSL_CIPHER) **out_cipher_list_by_id, - const char *rule_str) { - int ok; - STACK_OF(SSL_CIPHER) *cipherstack = NULL, *tmp_cipher_list = NULL; - const char *rule_p; + const char *rule_str, int strict) { + STACK_OF(SSL_CIPHER) *cipherstack = NULL; CIPHER_ORDER *co_list = NULL, *head = NULL, *tail = NULL, *curr; uint8_t *in_group_flags = NULL; unsigned int num_in_group_flags = 0; @@ -1403,48 +1283,40 @@ ssl_create_cipher_list(const SSL_PROTOCOL_METHOD *ssl_method, /* Now arrange all ciphers by preference: * TODO(davidben): Compute this order once and copy it. */ - /* Everything else being equal, prefer ECDHE_ECDSA then ECDHE_RSA over other + /* Everything else being equal, prefer ECDHE_ECDSA and ECDHE_RSA over other * key exchange mechanisms */ ssl_cipher_apply_rule(0, SSL_kECDHE, SSL_aECDSA, ~0u, ~0u, 0, CIPHER_ADD, -1, 0, &head, &tail); ssl_cipher_apply_rule(0, SSL_kECDHE, ~0u, ~0u, ~0u, 0, CIPHER_ADD, -1, 0, &head, &tail); - ssl_cipher_apply_rule(0, SSL_kECDHE, ~0u, ~0u, ~0u, 0, CIPHER_DEL, -1, 0, - &head, &tail); + ssl_cipher_apply_rule(0, ~0u, ~0u, ~0u, ~0u, 0, CIPHER_DEL, -1, 0, &head, + &tail); /* Order the bulk ciphers. First the preferred AEAD ciphers. We prefer * CHACHA20 unless there is hardware support for fast and constant-time * AES_GCM. Of the two CHACHA20 variants, the new one is preferred over the * old one. */ if (EVP_has_aes_hardware()) { - ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_AES256GCM, ~0u, 0, CIPHER_ADD, -1, 0, - &head, &tail); ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_AES128GCM, ~0u, 0, CIPHER_ADD, -1, 0, &head, &tail); + ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_AES256GCM, ~0u, 0, CIPHER_ADD, -1, 0, + &head, &tail); ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_CHACHA20POLY1305, ~0u, 0, CIPHER_ADD, -1, 0, &head, &tail); - ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_CHACHA20POLY1305_OLD, ~0u, 0, - CIPHER_ADD, -1, 0, &head, &tail); } else { ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_CHACHA20POLY1305, ~0u, 0, CIPHER_ADD, -1, 0, &head, &tail); - ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_CHACHA20POLY1305_OLD, ~0u, 0, - CIPHER_ADD, -1, 0, &head, &tail); - ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_AES256GCM, ~0u, 0, CIPHER_ADD, -1, 0, - &head, &tail); ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_AES128GCM, ~0u, 0, CIPHER_ADD, -1, 0, &head, &tail); + ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_AES256GCM, ~0u, 0, CIPHER_ADD, -1, 0, + &head, &tail); } - /* Then the legacy non-AEAD ciphers: AES_256_CBC, AES-128_CBC, RC4_128_SHA, - * RC4_128_MD5, 3DES_EDE_CBC_SHA. */ - ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_AES256, ~0u, 0, CIPHER_ADD, -1, 0, - &head, &tail); + /* Then the legacy non-AEAD ciphers: AES_128_CBC, AES_256_CBC, + * 3DES_EDE_CBC_SHA. */ ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_AES128, ~0u, 0, CIPHER_ADD, -1, 0, &head, &tail); - ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_RC4, ~SSL_MD5, 0, CIPHER_ADD, -1, 0, - &head, &tail); - ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_RC4, SSL_MD5, 0, CIPHER_ADD, -1, 0, + ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_AES256, ~0u, 0, CIPHER_ADD, -1, 0, &head, &tail); ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_3DES, ~0u, 0, CIPHER_ADD, -1, 0, &head, &tail); @@ -1454,7 +1326,7 @@ ssl_create_cipher_list(const SSL_PROTOCOL_METHOD *ssl_method, &tail); /* Move ciphers without forward secrecy to the end. */ - ssl_cipher_apply_rule(0, ~(SSL_kDHE | SSL_kECDHE), ~0u, ~0u, ~0u, 0, + ssl_cipher_apply_rule(0, (SSL_kRSA | SSL_kPSK), ~0u, ~0u, ~0u, 0, CIPHER_ORD, -1, 0, &head, &tail); /* Now disable everything (maintaining the ordering!) */ @@ -1463,22 +1335,20 @@ ssl_create_cipher_list(const SSL_PROTOCOL_METHOD *ssl_method, /* If the rule_string begins with DEFAULT, apply the default rule before * using the (possibly available) additional rules. */ - ok = 1; - rule_p = rule_str; + const char *rule_p = rule_str; if (strncmp(rule_str, "DEFAULT", 7) == 0) { - ok = ssl_cipher_process_rulestr(ssl_method, SSL_DEFAULT_CIPHER_LIST, &head, - &tail); + if (!ssl_cipher_process_rulestr(ssl_method, SSL_DEFAULT_CIPHER_LIST, &head, + &tail, strict)) { + goto err; + } rule_p += 7; if (*rule_p == ':') { rule_p++; } } - if (ok && strlen(rule_p) > 0) { - ok = ssl_cipher_process_rulestr(ssl_method, rule_p, &head, &tail); - } - - if (!ok) { + if (*rule_p != '\0' && + !ssl_cipher_process_rulestr(ssl_method, rule_p, &head, &tail, strict)) { goto err; } @@ -1507,10 +1377,6 @@ ssl_create_cipher_list(const SSL_PROTOCOL_METHOD *ssl_method, OPENSSL_free(co_list); /* Not needed any longer */ co_list = NULL; - tmp_cipher_list = sk_SSL_CIPHER_dup(cipherstack); - if (tmp_cipher_list == NULL) { - goto err; - } pref_list = OPENSSL_malloc(sizeof(struct ssl_cipher_preference_list_st)); if (!pref_list) { goto err; @@ -1520,7 +1386,7 @@ ssl_create_cipher_list(const SSL_PROTOCOL_METHOD *ssl_method, if (!pref_list->in_group_flags) { goto err; } - memcpy(pref_list->in_group_flags, in_group_flags, num_in_group_flags); + OPENSSL_memcpy(pref_list->in_group_flags, in_group_flags, num_in_group_flags); OPENSSL_free(in_group_flags); in_group_flags = NULL; if (*out_cipher_list != NULL) { @@ -1529,26 +1395,12 @@ ssl_create_cipher_list(const SSL_PROTOCOL_METHOD *ssl_method, *out_cipher_list = pref_list; pref_list = NULL; - if (out_cipher_list_by_id != NULL) { - sk_SSL_CIPHER_free(*out_cipher_list_by_id); - *out_cipher_list_by_id = tmp_cipher_list; - tmp_cipher_list = NULL; - (void) sk_SSL_CIPHER_set_cmp_func(*out_cipher_list_by_id, - ssl_cipher_ptr_id_cmp); - - sk_SSL_CIPHER_sort(*out_cipher_list_by_id); - } else { - sk_SSL_CIPHER_free(tmp_cipher_list); - tmp_cipher_list = NULL; - } - return cipherstack; err: OPENSSL_free(co_list); OPENSSL_free(in_group_flags); sk_SSL_CIPHER_free(cipherstack); - sk_SSL_CIPHER_free(tmp_cipher_list); if (pref_list) { OPENSSL_free(pref_list->in_group_flags); } @@ -1569,14 +1421,18 @@ int SSL_CIPHER_is_AES(const SSL_CIPHER *cipher) { return (cipher->algorithm_enc & SSL_AES) != 0; } -int SSL_CIPHER_has_MD5_HMAC(const SSL_CIPHER *cipher) { - return (cipher->algorithm_mac & SSL_MD5) != 0; -} - int SSL_CIPHER_has_SHA1_HMAC(const SSL_CIPHER *cipher) { return (cipher->algorithm_mac & SSL_SHA1) != 0; } +int SSL_CIPHER_has_SHA256_HMAC(const SSL_CIPHER *cipher) { + return (cipher->algorithm_mac & SSL_SHA256) != 0; +} + +int SSL_CIPHER_is_AEAD(const SSL_CIPHER *cipher) { + return (cipher->algorithm_mac & SSL_AEAD) != 0; +} + int SSL_CIPHER_is_AESGCM(const SSL_CIPHER *cipher) { return (cipher->algorithm_enc & (SSL_AES128GCM | SSL_AES256GCM)) != 0; } @@ -1594,21 +1450,15 @@ int SSL_CIPHER_is_AES256CBC(const SSL_CIPHER *cipher) { } int SSL_CIPHER_is_CHACHA20POLY1305(const SSL_CIPHER *cipher) { - return (cipher->algorithm_enc & - (SSL_CHACHA20POLY1305 | SSL_CHACHA20POLY1305_OLD)) != 0; + return (cipher->algorithm_enc & SSL_CHACHA20POLY1305) != 0; } int SSL_CIPHER_is_NULL(const SSL_CIPHER *cipher) { return (cipher->algorithm_enc & SSL_eNULL) != 0; } -int SSL_CIPHER_is_RC4(const SSL_CIPHER *cipher) { - return (cipher->algorithm_enc & SSL_RC4) != 0; -} - int SSL_CIPHER_is_block_cipher(const SSL_CIPHER *cipher) { - /* Neither stream cipher nor AEAD. */ - return (cipher->algorithm_enc & (SSL_RC4 | SSL_eNULL)) == 0 && + return (cipher->algorithm_enc & SSL_eNULL) == 0 && cipher->algorithm_mac != SSL_AEAD; } @@ -1616,11 +1466,24 @@ int SSL_CIPHER_is_ECDSA(const SSL_CIPHER *cipher) { return (cipher->algorithm_auth & SSL_aECDSA) != 0; } +int SSL_CIPHER_is_DHE(const SSL_CIPHER *cipher) { + return (cipher->algorithm_mkey & SSL_kDHE) != 0; +} + int SSL_CIPHER_is_ECDHE(const SSL_CIPHER *cipher) { return (cipher->algorithm_mkey & SSL_kECDHE) != 0; } +int SSL_CIPHER_is_static_RSA(const SSL_CIPHER *cipher) { + return (cipher->algorithm_mkey & SSL_kRSA) != 0; +} + uint16_t SSL_CIPHER_get_min_version(const SSL_CIPHER *cipher) { + if (cipher->algorithm_mkey == SSL_kGENERIC || + cipher->algorithm_auth == SSL_aGENERIC) { + return TLS1_3_VERSION; + } + if (cipher->algorithm_prf != SSL_HANDSHAKE_MAC_DEFAULT) { /* Cipher suites before TLS 1.2 use the default PRF, while all those added * afterwards specify a particular hash. */ @@ -1629,6 +1492,14 @@ uint16_t SSL_CIPHER_get_min_version(const SSL_CIPHER *cipher) { return SSL3_VERSION; } +uint16_t SSL_CIPHER_get_max_version(const SSL_CIPHER *cipher) { + if (cipher->algorithm_mkey == SSL_kGENERIC || + cipher->algorithm_auth == SSL_aGENERIC) { + return TLS1_3_VERSION; + } + return TLS1_2_VERSION; +} + /* return the actual cipher being used */ const char *SSL_CIPHER_get_name(const SSL_CIPHER *cipher) { if (cipher != NULL) { @@ -1673,6 +1544,10 @@ const char *SSL_CIPHER_get_kx_name(const SSL_CIPHER *cipher) { assert(cipher->algorithm_auth == SSL_aPSK); return "PSK"; + case SSL_kGENERIC: + assert(cipher->algorithm_auth == SSL_aGENERIC); + return "GENERIC"; + default: assert(0); return "UNKNOWN"; @@ -1683,8 +1558,6 @@ static const char *ssl_cipher_get_enc_name(const SSL_CIPHER *cipher) { switch (cipher->algorithm_enc) { case SSL_3DES: return "3DES_EDE_CBC"; - case SSL_RC4: - return "RC4"; case SSL_AES128: return "AES_128_CBC"; case SSL_AES256: @@ -1694,7 +1567,6 @@ static const char *ssl_cipher_get_enc_name(const SSL_CIPHER *cipher) { case SSL_AES256GCM: return "AES_256_GCM"; case SSL_CHACHA20POLY1305: - case SSL_CHACHA20POLY1305_OLD: return "CHACHA20_POLY1305"; break; default: @@ -1706,15 +1578,10 @@ static const char *ssl_cipher_get_enc_name(const SSL_CIPHER *cipher) { static const char *ssl_cipher_get_prf_name(const SSL_CIPHER *cipher) { switch (cipher->algorithm_prf) { case SSL_HANDSHAKE_MAC_DEFAULT: - /* Before TLS 1.2, the PRF component is the hash used in the HMAC, which is - * only ever MD5 or SHA-1. */ - switch (cipher->algorithm_mac) { - case SSL_MD5: - return "MD5"; - case SSL_SHA1: - return "SHA"; - } - break; + /* Before TLS 1.2, the PRF component is the hash used in the HMAC, which + * is SHA-1 for all supported ciphers. */ + assert(cipher->algorithm_mac == SSL_SHA1); + return "SHA"; case SSL_HANDSHAKE_MAC_SHA256: return "SHA256"; case SSL_HANDSHAKE_MAC_SHA384: @@ -1733,16 +1600,23 @@ char *SSL_CIPHER_get_rfc_name(const SSL_CIPHER *cipher) { const char *enc_name = ssl_cipher_get_enc_name(cipher); const char *prf_name = ssl_cipher_get_prf_name(cipher); - /* The final name is TLS_{kx_name}_WITH_{enc_name}_{prf_name}. */ - size_t len = 4 + strlen(kx_name) + 6 + strlen(enc_name) + 1 + - strlen(prf_name) + 1; + /* The final name is TLS_{kx_name}_WITH_{enc_name}_{prf_name} or + * TLS_{enc_name}_{prf_name} depending on whether the cipher is AEAD-only. */ + size_t len = 4 + strlen(enc_name) + 1 + strlen(prf_name) + 1; + + if (cipher->algorithm_mkey != SSL_kGENERIC) { + len += strlen(kx_name) + 6; + } + char *ret = OPENSSL_malloc(len); if (ret == NULL) { return NULL; } + if (BUF_strlcpy(ret, "TLS_", len) >= len || - BUF_strlcat(ret, kx_name, len) >= len || - BUF_strlcat(ret, "_WITH_", len) >= len || + (cipher->algorithm_mkey != SSL_kGENERIC && + (BUF_strlcat(ret, kx_name, len) >= len || + BUF_strlcat(ret, "_WITH_", len) >= len)) || BUF_strlcat(ret, enc_name, len) >= len || BUF_strlcat(ret, "_", len) >= len || BUF_strlcat(ret, prf_name, len) >= len) { @@ -1750,6 +1624,7 @@ char *SSL_CIPHER_get_rfc_name(const SSL_CIPHER *cipher) { OPENSSL_free(ret); return NULL; } + assert(strlen(ret) + 1 == len); return ret; } @@ -1763,16 +1638,12 @@ int SSL_CIPHER_get_bits(const SSL_CIPHER *cipher, int *out_alg_bits) { switch (cipher->algorithm_enc) { case SSL_AES128: case SSL_AES128GCM: - case SSL_RC4: alg_bits = 128; strength_bits = 128; break; case SSL_AES256: case SSL_AES256GCM: -#if !defined(BORINGSSL_ANDROID_SYSTEM) - case SSL_CHACHA20POLY1305_OLD: -#endif case SSL_CHACHA20POLY1305: alg_bits = 256; strength_bits = 256; @@ -1827,6 +1698,10 @@ const char *SSL_CIPHER_description(const SSL_CIPHER *cipher, char *buf, kx = "PSK"; break; + case SSL_kGENERIC: + kx = "GENERIC"; + break; + default: kx = "unknown"; } @@ -1844,6 +1719,10 @@ const char *SSL_CIPHER_description(const SSL_CIPHER *cipher, char *buf, au = "PSK"; break; + case SSL_aGENERIC: + au = "GENERIC"; + break; + default: au = "unknown"; break; @@ -1854,10 +1733,6 @@ const char *SSL_CIPHER_description(const SSL_CIPHER *cipher, char *buf, enc = "3DES(168)"; break; - case SSL_RC4: - enc = "RC4(128)"; - break; - case SSL_AES128: enc = "AES(128)"; break; @@ -1874,10 +1749,6 @@ const char *SSL_CIPHER_description(const SSL_CIPHER *cipher, char *buf, enc = "AESGCM(256)"; break; - case SSL_CHACHA20POLY1305_OLD: - enc = "ChaCha20-Poly1305-Old"; - break; - case SSL_CHACHA20POLY1305: enc = "ChaCha20-Poly1305"; break; @@ -1892,10 +1763,6 @@ const char *SSL_CIPHER_description(const SSL_CIPHER *cipher, char *buf, } switch (alg_mac) { - case SSL_MD5: - mac = "MD5"; - break; - case SSL_SHA1: mac = "SHA1"; break; @@ -1942,6 +1809,8 @@ int SSL_COMP_add_compression_method(int id, COMP_METHOD *cm) { return 1; } const char *SSL_COMP_get_name(const COMP_METHOD *comp) { return NULL; } +void SSL_COMP_free_compression_methods(void) {} + int ssl_cipher_get_key_type(const SSL_CIPHER *cipher) { uint32_t alg_a = cipher->algorithm_auth; @@ -1954,20 +1823,14 @@ int ssl_cipher_get_key_type(const SSL_CIPHER *cipher) { return EVP_PKEY_NONE; } -int ssl_cipher_has_server_public_key(const SSL_CIPHER *cipher) { - /* PSK-authenticated ciphers do not use a certificate. (RSA_PSK is not - * supported.) */ - if (cipher->algorithm_auth & SSL_aPSK) { - return 0; - } - - /* All other ciphers include it. */ - return 1; +int ssl_cipher_uses_certificate_auth(const SSL_CIPHER *cipher) { + return (cipher->algorithm_auth & SSL_aCERT) != 0; } int ssl_cipher_requires_server_key_exchange(const SSL_CIPHER *cipher) { /* Ephemeral Diffie-Hellman key exchanges require a ServerKeyExchange. */ - if (cipher->algorithm_mkey & SSL_kDHE || cipher->algorithm_mkey & SSL_kECDHE) { + if (cipher->algorithm_mkey & SSL_kDHE || + cipher->algorithm_mkey & SSL_kECDHE) { return 1; } @@ -1989,19 +1852,9 @@ size_t ssl_cipher_get_record_split_len(const SSL_CIPHER *cipher) { return 0; } - size_t mac_len; - switch (cipher->algorithm_mac) { - case SSL_MD5: - mac_len = MD5_DIGEST_LENGTH; - break; - case SSL_SHA1: - mac_len = SHA_DIGEST_LENGTH; - break; - default: - return 0; - } - - size_t ret = 1 + mac_len; + /* All supported TLS 1.0 ciphers use SHA-1. */ + assert(cipher->algorithm_mac == SSL_SHA1); + size_t ret = 1 + SHA_DIGEST_LENGTH; ret += block_size - (ret % block_size); return ret; } diff --git a/Sources/BoringSSL/ssl/ssl_ecdh.c b/Sources/BoringSSL/ssl/ssl_ecdh.c index 700d94715..f49d5661a 100644 --- a/Sources/BoringSSL/ssl/ssl_ecdh.c +++ b/Sources/BoringSSL/ssl/ssl_ecdh.c @@ -23,9 +23,10 @@ #include #include #include -#include +#include #include "internal.h" +#include "../crypto/internal.h" /* |EC_POINT| implementation. */ @@ -35,7 +36,7 @@ static void ssl_ec_point_cleanup(SSL_ECDH_CTX *ctx) { BN_clear_free(private_key); } -static int ssl_ec_point_generate_keypair(SSL_ECDH_CTX *ctx, CBB *out) { +static int ssl_ec_point_offer(SSL_ECDH_CTX *ctx, CBB *out) { assert(ctx->data == NULL); BIGNUM *private_key = BN_new(); if (private_key == NULL) { @@ -58,12 +59,9 @@ static int ssl_ec_point_generate_keypair(SSL_ECDH_CTX *ctx, CBB *out) { } /* Generate a private key. */ - const BIGNUM *order = EC_GROUP_get0_order(group); - do { - if (!BN_rand_range(private_key, order)) { - goto err; - } - } while (BN_is_zero(private_key)); + if (!BN_rand_range_ex(private_key, 1, EC_GROUP_get0_order(group))) { + goto err; + } /* Compute the corresponding public key and serialize it. */ public_key = EC_POINT_new(group); @@ -84,9 +82,9 @@ static int ssl_ec_point_generate_keypair(SSL_ECDH_CTX *ctx, CBB *out) { return ret; } -int ssl_ec_point_compute_secret(SSL_ECDH_CTX *ctx, uint8_t **out_secret, - size_t *out_secret_len, uint8_t *out_alert, - const uint8_t *peer_key, size_t peer_key_len) { +static int ssl_ec_point_finish(SSL_ECDH_CTX *ctx, uint8_t **out_secret, + size_t *out_secret_len, uint8_t *out_alert, + const uint8_t *peer_key, size_t peer_key_len) { BIGNUM *private_key = (BIGNUM *)ctx->data; assert(private_key != NULL); *out_alert = SSL_AD_INTERNAL_ERROR; @@ -147,6 +145,18 @@ int ssl_ec_point_compute_secret(SSL_ECDH_CTX *ctx, uint8_t **out_secret, return ret; } +static int ssl_ec_point_accept(SSL_ECDH_CTX *ctx, CBB *out_public_key, + uint8_t **out_secret, size_t *out_secret_len, + uint8_t *out_alert, const uint8_t *peer_key, + size_t peer_key_len) { + *out_alert = SSL_AD_INTERNAL_ERROR; + if (!ssl_ec_point_offer(ctx, out_public_key) || + !ssl_ec_point_finish(ctx, out_secret, out_secret_len, out_alert, peer_key, + peer_key_len)) { + return 0; + } + return 1; +} /* X25119 implementation. */ @@ -158,7 +168,7 @@ static void ssl_x25519_cleanup(SSL_ECDH_CTX *ctx) { OPENSSL_free(ctx->data); } -static int ssl_x25519_generate_keypair(SSL_ECDH_CTX *ctx, CBB *out) { +static int ssl_x25519_offer(SSL_ECDH_CTX *ctx, CBB *out) { assert(ctx->data == NULL); ctx->data = OPENSSL_malloc(32); @@ -171,10 +181,9 @@ static int ssl_x25519_generate_keypair(SSL_ECDH_CTX *ctx, CBB *out) { return CBB_add_bytes(out, public_key, sizeof(public_key)); } -static int ssl_x25519_compute_secret(SSL_ECDH_CTX *ctx, uint8_t **out_secret, - size_t *out_secret_len, uint8_t *out_alert, - const uint8_t *peer_key, - size_t peer_key_len) { +static int ssl_x25519_finish(SSL_ECDH_CTX *ctx, uint8_t **out_secret, + size_t *out_secret_len, uint8_t *out_alert, + const uint8_t *peer_key, size_t peer_key_len) { assert(ctx->data != NULL); *out_alert = SSL_AD_INTERNAL_ERROR; @@ -196,6 +205,19 @@ static int ssl_x25519_compute_secret(SSL_ECDH_CTX *ctx, uint8_t **out_secret, return 1; } +static int ssl_x25519_accept(SSL_ECDH_CTX *ctx, CBB *out_public_key, + uint8_t **out_secret, size_t *out_secret_len, + uint8_t *out_alert, const uint8_t *peer_key, + size_t peer_key_len) { + *out_alert = SSL_AD_INTERNAL_ERROR; + if (!ssl_x25519_offer(ctx, out_public_key) || + !ssl_x25519_finish(ctx, out_secret, out_secret_len, out_alert, peer_key, + peer_key_len)) { + return 0; + } + return 1; +} + /* Legacy DHE-based implementation. */ @@ -203,7 +225,7 @@ static void ssl_dhe_cleanup(SSL_ECDH_CTX *ctx) { DH_free((DH *)ctx->data); } -static int ssl_dhe_generate_keypair(SSL_ECDH_CTX *ctx, CBB *out) { +static int ssl_dhe_offer(SSL_ECDH_CTX *ctx, CBB *out) { DH *dh = (DH *)ctx->data; /* The group must have been initialized already, but not the key. */ assert(dh != NULL); @@ -215,10 +237,9 @@ static int ssl_dhe_generate_keypair(SSL_ECDH_CTX *ctx, CBB *out) { BN_bn2cbb_padded(out, BN_num_bytes(dh->p), dh->pub_key); } -static int ssl_dhe_compute_secret(SSL_ECDH_CTX *ctx, uint8_t **out_secret, - size_t *out_secret_len, uint8_t *out_alert, - const uint8_t *peer_key, - size_t peer_key_len) { +static int ssl_dhe_finish(SSL_ECDH_CTX *ctx, uint8_t **out_secret, + size_t *out_secret_len, uint8_t *out_alert, + const uint8_t *peer_key, size_t peer_key_len) { DH *dh = (DH *)ctx->data; assert(dh != NULL); assert(dh->priv_key != NULL); @@ -254,53 +275,79 @@ static int ssl_dhe_compute_secret(SSL_ECDH_CTX *ctx, uint8_t **out_secret, return 0; } +static int ssl_dhe_accept(SSL_ECDH_CTX *ctx, CBB *out_public_key, + uint8_t **out_secret, size_t *out_secret_len, + uint8_t *out_alert, const uint8_t *peer_key, + size_t peer_key_len) { + *out_alert = SSL_AD_INTERNAL_ERROR; + if (!ssl_dhe_offer(ctx, out_public_key) || + !ssl_dhe_finish(ctx, out_secret, out_secret_len, out_alert, peer_key, + peer_key_len)) { + return 0; + } + return 1; +} + static const SSL_ECDH_METHOD kDHEMethod = { NID_undef, 0, "", ssl_dhe_cleanup, - ssl_dhe_generate_keypair, - ssl_dhe_compute_secret, + ssl_dhe_offer, + ssl_dhe_accept, + ssl_dhe_finish, + CBS_get_u16_length_prefixed, + CBB_add_u16_length_prefixed, }; - static const SSL_ECDH_METHOD kMethods[] = { { NID_X9_62_prime256v1, SSL_CURVE_SECP256R1, "P-256", ssl_ec_point_cleanup, - ssl_ec_point_generate_keypair, - ssl_ec_point_compute_secret, + ssl_ec_point_offer, + ssl_ec_point_accept, + ssl_ec_point_finish, + CBS_get_u8_length_prefixed, + CBB_add_u8_length_prefixed, }, { NID_secp384r1, SSL_CURVE_SECP384R1, "P-384", ssl_ec_point_cleanup, - ssl_ec_point_generate_keypair, - ssl_ec_point_compute_secret, + ssl_ec_point_offer, + ssl_ec_point_accept, + ssl_ec_point_finish, + CBS_get_u8_length_prefixed, + CBB_add_u8_length_prefixed, }, { NID_secp521r1, SSL_CURVE_SECP521R1, "P-521", ssl_ec_point_cleanup, - ssl_ec_point_generate_keypair, - ssl_ec_point_compute_secret, + ssl_ec_point_offer, + ssl_ec_point_accept, + ssl_ec_point_finish, + CBS_get_u8_length_prefixed, + CBB_add_u8_length_prefixed, }, { - NID_x25519, + NID_X25519, SSL_CURVE_X25519, "X25519", ssl_x25519_cleanup, - ssl_x25519_generate_keypair, - ssl_x25519_compute_secret, + ssl_x25519_offer, + ssl_x25519_accept, + ssl_x25519_finish, + CBS_get_u8_length_prefixed, + CBB_add_u8_length_prefixed, }, }; -static const SSL_ECDH_METHOD *method_from_curve_id(uint16_t curve_id) { - size_t i; - for (i = 0; i < sizeof(kMethods) / sizeof(kMethods[0]); i++) { - if (kMethods[i].curve_id == curve_id) { +static const SSL_ECDH_METHOD *method_from_group_id(uint16_t group_id) { + for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(kMethods); i++) { + if (kMethods[i].group_id == group_id) { return &kMethods[i]; } } @@ -308,8 +355,7 @@ static const SSL_ECDH_METHOD *method_from_curve_id(uint16_t curve_id) { } static const SSL_ECDH_METHOD *method_from_nid(int nid) { - size_t i; - for (i = 0; i < sizeof(kMethods) / sizeof(kMethods[0]); i++) { + for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(kMethods); i++) { if (kMethods[i].nid == nid) { return &kMethods[i]; } @@ -317,27 +363,46 @@ static const SSL_ECDH_METHOD *method_from_nid(int nid) { return NULL; } -const char* SSL_get_curve_name(uint16_t curve_id) { - const SSL_ECDH_METHOD *method = method_from_curve_id(curve_id); +static const SSL_ECDH_METHOD *method_from_name(const char *name, size_t len) { + for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(kMethods); i++) { + if (len == strlen(kMethods[i].name) && + !strncmp(kMethods[i].name, name, len)) { + return &kMethods[i]; + } + } + return NULL; +} + +const char* SSL_get_curve_name(uint16_t group_id) { + const SSL_ECDH_METHOD *method = method_from_group_id(group_id); if (method == NULL) { return NULL; } return method->name; } -int ssl_nid_to_curve_id(uint16_t *out_curve_id, int nid) { +int ssl_nid_to_group_id(uint16_t *out_group_id, int nid) { const SSL_ECDH_METHOD *method = method_from_nid(nid); if (method == NULL) { return 0; } - *out_curve_id = method->curve_id; + *out_group_id = method->group_id; + return 1; +} + +int ssl_name_to_group_id(uint16_t *out_group_id, const char *name, size_t len) { + const SSL_ECDH_METHOD *method = method_from_name(name, len); + if (method == NULL) { + return 0; + } + *out_group_id = method->group_id; return 1; } -int SSL_ECDH_CTX_init(SSL_ECDH_CTX *ctx, uint16_t curve_id) { +int SSL_ECDH_CTX_init(SSL_ECDH_CTX *ctx, uint16_t group_id) { SSL_ECDH_CTX_cleanup(ctx); - const SSL_ECDH_METHOD *method = method_from_curve_id(curve_id); + const SSL_ECDH_METHOD *method = method_from_group_id(group_id); if (method == NULL) { OPENSSL_PUT_ERROR(SSL, SSL_R_UNSUPPORTED_ELLIPTIC_CURVE); return 0; @@ -362,13 +427,39 @@ void SSL_ECDH_CTX_cleanup(SSL_ECDH_CTX *ctx) { ctx->data = NULL; } -int SSL_ECDH_CTX_generate_keypair(SSL_ECDH_CTX *ctx, CBB *out_public_key) { - return ctx->method->generate_keypair(ctx, out_public_key); +uint16_t SSL_ECDH_CTX_get_id(const SSL_ECDH_CTX *ctx) { + return ctx->method->group_id; +} + +int SSL_ECDH_CTX_get_key(SSL_ECDH_CTX *ctx, CBS *cbs, CBS *out) { + if (ctx->method == NULL) { + return 0; + } + return ctx->method->get_key(cbs, out); +} + +int SSL_ECDH_CTX_add_key(SSL_ECDH_CTX *ctx, CBB *cbb, CBB *out_contents) { + if (ctx->method == NULL) { + return 0; + } + return ctx->method->add_key(cbb, out_contents); +} + +int SSL_ECDH_CTX_offer(SSL_ECDH_CTX *ctx, CBB *out_public_key) { + return ctx->method->offer(ctx, out_public_key); +} + +int SSL_ECDH_CTX_accept(SSL_ECDH_CTX *ctx, CBB *out_public_key, + uint8_t **out_secret, size_t *out_secret_len, + uint8_t *out_alert, const uint8_t *peer_key, + size_t peer_key_len) { + return ctx->method->accept(ctx, out_public_key, out_secret, out_secret_len, + out_alert, peer_key, peer_key_len); } -int SSL_ECDH_CTX_compute_secret(SSL_ECDH_CTX *ctx, uint8_t **out_secret, - size_t *out_secret_len, uint8_t *out_alert, - const uint8_t *peer_key, size_t peer_key_len) { - return ctx->method->compute_secret(ctx, out_secret, out_secret_len, out_alert, - peer_key, peer_key_len); +int SSL_ECDH_CTX_finish(SSL_ECDH_CTX *ctx, uint8_t **out_secret, + size_t *out_secret_len, uint8_t *out_alert, + const uint8_t *peer_key, size_t peer_key_len) { + return ctx->method->finish(ctx, out_secret, out_secret_len, out_alert, + peer_key, peer_key_len); } diff --git a/Sources/BoringSSL/ssl/ssl_file.c b/Sources/BoringSSL/ssl/ssl_file.c index 42cf800c7..59351a32f 100644 --- a/Sources/BoringSSL/ssl/ssl_file.c +++ b/Sources/BoringSSL/ssl/ssl_file.c @@ -121,7 +121,6 @@ #include #include -#include "../crypto/directory.h" #include "internal.h" @@ -165,16 +164,17 @@ STACK_OF(X509_NAME) *SSL_load_client_CA_file(const char *file) { goto err; } - /* check for duplicates */ - xn = X509_NAME_dup(xn); - if (xn == NULL) { - goto err; - } + /* Check for duplicates. */ if (sk_X509_NAME_find(sk, NULL, xn)) { + continue; + } + + xn = X509_NAME_dup(xn); + if (xn == NULL || + !sk_X509_NAME_push(sk /* non-owning */, xn) || + !sk_X509_NAME_push(ret /* owning */, xn)) { X509_NAME_free(xn); - } else { - sk_X509_NAME_push(sk, xn); - sk_X509_NAME_push(ret, xn); + goto err; } } @@ -198,7 +198,7 @@ int SSL_add_file_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack, BIO *in; X509 *x = NULL; X509_NAME *xn = NULL; - int ret = 1; + int ret = 0; int (*oldcmp)(const X509_NAME **a, const X509_NAME **b); oldcmp = sk_X509_NAME_set_cmp_func(stack, xname_cmp); @@ -221,24 +221,24 @@ int SSL_add_file_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack, if (xn == NULL) { goto err; } - xn = X509_NAME_dup(xn); - if (xn == NULL) { - goto err; - } + + /* Check for duplicates. */ if (sk_X509_NAME_find(stack, NULL, xn)) { + continue; + } + + xn = X509_NAME_dup(xn); + if (xn == NULL || + !sk_X509_NAME_push(stack, xn)) { X509_NAME_free(xn); - } else { - sk_X509_NAME_push(stack, xn); + goto err; } } ERR_clear_error(); + ret = 1; - if (0) { - err: - ret = 0; - } - +err: BIO_free(in); X509_free(x); @@ -247,53 +247,6 @@ int SSL_add_file_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack, return ret; } -/* Add a directory of certs to a stack. - * - * \param stack the stack to append to. - * \param dir the directory to append from. All files in this directory will be - * examined as potential certs. Any that are acceptable to - * SSL_add_dir_cert_subjects_to_stack() that are not already in the stack will - * be included. - * \return 1 for success, 0 for failure. Note that in the case of failure some - * certs may have been added to \c stack. */ -int SSL_add_dir_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack, - const char *dir) { - OPENSSL_DIR_CTX *d = NULL; - const char *filename; - int ret = 0; - - /* Note that a side effect is that the CAs will be sorted by name */ - while ((filename = OPENSSL_DIR_read(&d, dir))) { - char buf[1024]; - int r; - - if (strlen(dir) + strlen(filename) + 2 > sizeof(buf)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_PATH_TOO_LONG); - goto err; - } - - r = BIO_snprintf(buf, sizeof buf, "%s/%s", dir, filename); - if (r <= 0 || r >= (int)sizeof(buf) || - !SSL_add_file_cert_subjects_to_stack(stack, buf)) { - goto err; - } - } - - if (errno) { - OPENSSL_PUT_ERROR(SSL, ERR_R_SYS_LIB); - ERR_add_error_data(3, "OPENSSL_DIR_read(&ctx, '", dir, "')"); - goto err; - } - - ret = 1; - -err: - if (d) { - OPENSSL_DIR_end(&d); - } - return ret; -} - int SSL_use_certificate_file(SSL *ssl, const char *file, int type) { int reason_code; BIO *in; @@ -620,14 +573,3 @@ void SSL_CTX_set_default_passwd_cb(SSL_CTX *ctx, pem_password_cb *cb) { void SSL_CTX_set_default_passwd_cb_userdata(SSL_CTX *ctx, void *data) { ctx->default_passwd_callback_userdata = data; } - -SSL_SESSION *d2i_SSL_SESSION_bio(BIO *bio, SSL_SESSION **out) { - return ASN1_d2i_bio_of(SSL_SESSION, SSL_SESSION_new, d2i_SSL_SESSION, bio, - out); -} - -int i2d_SSL_SESSION_bio(BIO *bio, const SSL_SESSION *session) { - return ASN1_i2d_bio_of(SSL_SESSION, i2d_SSL_SESSION, bio, session); -} - -IMPLEMENT_PEM_rw(SSL_SESSION, SSL_SESSION, PEM_STRING_SSL_SESSION, SSL_SESSION) diff --git a/Sources/BoringSSL/ssl/ssl_lib.c b/Sources/BoringSSL/ssl/ssl_lib.c index b72601172..e37f9f944 100644 --- a/Sources/BoringSSL/ssl/ssl_lib.c +++ b/Sources/BoringSSL/ssl/ssl_lib.c @@ -141,7 +141,7 @@ #include #include -#include +#include #include #include @@ -150,18 +150,28 @@ #include #include #include -#include #include -#include #include "internal.h" #include "../crypto/internal.h" +#if defined(OPENSSL_WINDOWS) +#include +#else +#include +#include +#endif + /* |SSL_R_UNKNOWN_PROTOCOL| is no longer emitted, but continue to define it * to avoid downstream churn. */ OPENSSL_DECLARE_ERROR_REASON(SSL, UNKNOWN_PROTOCOL) +/* The following errors are no longer emitted, but are used in nginx without + * #ifdefs. */ +OPENSSL_DECLARE_ERROR_REASON(SSL, BLOCK_CIPHER_PAD_IS_WRONG) +OPENSSL_DECLARE_ERROR_REASON(SSL, NO_CIPHERS_SPECIFIED) + /* Some error codes are special. Ensure the make_errors.go script never * regresses this. */ OPENSSL_COMPILE_ASSERT(SSL_R_TLSV1_ALERT_NO_RENEGOTIATION == @@ -186,8 +196,8 @@ static uint32_t ssl_session_hash(const SSL_SESSION *sess) { uint8_t tmp_storage[sizeof(uint32_t)]; if (sess->session_id_length < sizeof(tmp_storage)) { - memset(tmp_storage, 0, sizeof(tmp_storage)); - memcpy(tmp_storage, sess->session_id, sess->session_id_length); + OPENSSL_memset(tmp_storage, 0, sizeof(tmp_storage)); + OPENSSL_memcpy(tmp_storage, sess->session_id, sess->session_id_length); session_id = tmp_storage; } @@ -214,7 +224,7 @@ static int ssl_session_cmp(const SSL_SESSION *a, const SSL_SESSION *b) { return 1; } - return memcmp(a->session_id, b->session_id, a->session_id_length); + return OPENSSL_memcmp(a->session_id, b->session_id, a->session_id_length); } SSL_CTX *SSL_CTX_new(const SSL_METHOD *method) { @@ -235,23 +245,24 @@ SSL_CTX *SSL_CTX_new(const SSL_METHOD *method) { goto err; } - memset(ret, 0, sizeof(SSL_CTX)); + OPENSSL_memset(ret, 0, sizeof(SSL_CTX)); ret->method = method->method; + ret->x509_method = method->x509_method; CRYPTO_MUTEX_init(&ret->lock); ret->session_cache_mode = SSL_SESS_CACHE_SERVER; ret->session_cache_size = SSL_SESSION_CACHE_MAX_SIZE_DEFAULT; - /* We take the system default */ ret->session_timeout = SSL_DEFAULT_SESSION_TIMEOUT; + ret->session_psk_dhe_timeout = SSL_DEFAULT_SESSION_PSK_DHE_TIMEOUT; ret->references = 1; ret->max_cert_list = SSL_MAX_CERT_LIST_DEFAULT; ret->verify_mode = SSL_VERIFY_NONE; - ret->cert = ssl_cert_new(); + ret->cert = ssl_cert_new(method->x509_method); if (ret->cert == NULL) { goto err; } @@ -266,7 +277,7 @@ SSL_CTX *SSL_CTX_new(const SSL_METHOD *method) { } ssl_create_cipher_list(ret->method, &ret->cipher_list, - &ret->cipher_list_by_id, SSL_DEFAULT_CIPHER_LIST); + SSL_DEFAULT_CIPHER_LIST, 1 /* strict */); if (ret->cipher_list == NULL || sk_SSL_CIPHER_num(ret->cipher_list->ciphers) <= 0) { OPENSSL_PUT_ERROR(SSL, SSL_R_LIBRARY_HAS_NO_CIPHERS); @@ -294,11 +305,16 @@ SSL_CTX *SSL_CTX_new(const SSL_METHOD *method) { ret->options |= SSL_OP_NO_TICKET; } + /* Disable the auto-chaining feature by default. Once this has stuck without + * problems, the feature will be removed entirely. */ + ret->mode = SSL_MODE_NO_AUTO_CHAIN; + /* Lock the SSL_CTX to the specified version, for compatibility with legacy * uses of SSL_METHOD. */ - if (method->version != 0) { - SSL_CTX_set_max_version(ret, method->version); - SSL_CTX_set_min_version(ret, method->version); + if (!SSL_CTX_set_max_proto_version(ret, method->version) || + !SSL_CTX_set_min_proto_version(ret, method->version)) { + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + goto err2; } return ret; @@ -310,6 +326,11 @@ SSL_CTX *SSL_CTX_new(const SSL_METHOD *method) { return NULL; } +int SSL_CTX_up_ref(SSL_CTX *ctx) { + CRYPTO_refcount_inc(&ctx->references); + return 1; +} + void SSL_CTX_free(SSL_CTX *ctx) { if (ctx == NULL || !CRYPTO_refcount_dec_and_test_zero(&ctx->references)) { @@ -332,9 +353,6 @@ void SSL_CTX_free(SSL_CTX *ctx) { lh_SSL_SESSION_free(ctx->sessions); X509_STORE_free(ctx->cert_store); ssl_cipher_preference_list_free(ctx->cipher_list); - sk_SSL_CIPHER_free(ctx->cipher_list_by_id); - ssl_cipher_preference_list_free(ctx->cipher_list_tls10); - ssl_cipher_preference_list_free(ctx->cipher_list_tls11); ssl_cert_free(ctx->cert); sk_SSL_CUSTOM_EXTENSION_pop_free(ctx->client_custom_extensions, SSL_CUSTOM_EXTENSION_free); @@ -343,10 +361,8 @@ void SSL_CTX_free(SSL_CTX *ctx) { sk_X509_NAME_pop_free(ctx->client_CA, X509_NAME_free); sk_SRTP_PROTECTION_PROFILE_free(ctx->srtp_profiles); OPENSSL_free(ctx->psk_identity_hint); - OPENSSL_free(ctx->tlsext_ellipticcurvelist); + OPENSSL_free(ctx->supported_group_list); OPENSSL_free(ctx->alpn_client_proto_list); - OPENSSL_free(ctx->ocsp_response); - OPENSSL_free(ctx->signed_cert_timestamp_list); EVP_PKEY_free(ctx->tlsext_channel_id_private); OPENSSL_free(ctx); @@ -366,11 +382,15 @@ SSL *SSL_new(SSL_CTX *ctx) { if (ssl == NULL) { goto err; } - memset(ssl, 0, sizeof(SSL)); + OPENSSL_memset(ssl, 0, sizeof(SSL)); ssl->min_version = ctx->min_version; ssl->max_version = ctx->max_version; + /* RFC 6347 states that implementations SHOULD use an initial timer value of + * 1 second. */ + ssl->initial_timeout_duration_ms = 1000; + ssl->options = ctx->options; ssl->mode = ctx->mode; ssl->max_cert_list = ctx->max_cert_list; @@ -383,10 +403,9 @@ SSL *SSL_new(SSL_CTX *ctx) { ssl->msg_callback = ctx->msg_callback; ssl->msg_callback_arg = ctx->msg_callback_arg; ssl->verify_mode = ctx->verify_mode; - ssl->sid_ctx_length = ctx->sid_ctx_length; - assert(ssl->sid_ctx_length <= sizeof ssl->sid_ctx); - memcpy(&ssl->sid_ctx, &ctx->sid_ctx, sizeof(ssl->sid_ctx)); ssl->verify_callback = ctx->default_verify_callback; + ssl->retain_only_sha256_of_client_certs = + ctx->retain_only_sha256_of_client_certs; ssl->param = X509_VERIFY_PARAM_new(); if (!ssl->param) { @@ -396,31 +415,29 @@ SSL *SSL_new(SSL_CTX *ctx) { ssl->quiet_shutdown = ctx->quiet_shutdown; ssl->max_send_fragment = ctx->max_send_fragment; - CRYPTO_refcount_inc(&ctx->references); + SSL_CTX_up_ref(ctx); ssl->ctx = ctx; - CRYPTO_refcount_inc(&ctx->references); + SSL_CTX_up_ref(ctx); ssl->initial_ctx = ctx; - if (ctx->tlsext_ellipticcurvelist) { - ssl->tlsext_ellipticcurvelist = - BUF_memdup(ctx->tlsext_ellipticcurvelist, - ctx->tlsext_ellipticcurvelist_length * 2); - if (!ssl->tlsext_ellipticcurvelist) { + if (ctx->supported_group_list) { + ssl->supported_group_list = BUF_memdup(ctx->supported_group_list, + ctx->supported_group_list_len * 2); + if (!ssl->supported_group_list) { goto err; } - ssl->tlsext_ellipticcurvelist_length = ctx->tlsext_ellipticcurvelist_length; + ssl->supported_group_list_len = ctx->supported_group_list_len; } - if (ssl->ctx->alpn_client_proto_list) { - ssl->alpn_client_proto_list = BUF_memdup( - ssl->ctx->alpn_client_proto_list, ssl->ctx->alpn_client_proto_list_len); + if (ctx->alpn_client_proto_list) { + ssl->alpn_client_proto_list = BUF_memdup(ctx->alpn_client_proto_list, + ctx->alpn_client_proto_list_len); if (ssl->alpn_client_proto_list == NULL) { goto err; } - ssl->alpn_client_proto_list_len = ssl->ctx->alpn_client_proto_list_len; + ssl->alpn_client_proto_list_len = ctx->alpn_client_proto_list_len; } - ssl->verify_result = X509_V_OK; ssl->method = ctx->method; if (!ssl->method->ssl_new(ssl)) { @@ -443,13 +460,12 @@ SSL *SSL_new(SSL_CTX *ctx) { ssl->tlsext_channel_id_enabled = ctx->tlsext_channel_id_enabled; if (ctx->tlsext_channel_id_private) { - ssl->tlsext_channel_id_private = - EVP_PKEY_up_ref(ctx->tlsext_channel_id_private); + EVP_PKEY_up_ref(ctx->tlsext_channel_id_private); + ssl->tlsext_channel_id_private = ctx->tlsext_channel_id_private; } - ssl->signed_cert_timestamps_enabled = - ssl->ctx->signed_cert_timestamps_enabled; - ssl->ocsp_stapling_enabled = ssl->ctx->ocsp_stapling_enabled; + ssl->signed_cert_timestamps_enabled = ctx->signed_cert_timestamps_enabled; + ssl->ocsp_stapling_enabled = ctx->ocsp_stapling_enabled; return ssl; @@ -469,35 +485,21 @@ void SSL_free(SSL *ssl) { CRYPTO_free_ex_data(&g_ex_data_class_ssl, ssl, &ssl->ex_data); - if (ssl->bbio != NULL) { - /* If the buffering BIO is in place, pop it off */ - if (ssl->bbio == ssl->wbio) { - ssl->wbio = BIO_pop(ssl->wbio); - } - BIO_free(ssl->bbio); - ssl->bbio = NULL; - } - - int free_wbio = ssl->wbio != ssl->rbio; BIO_free_all(ssl->rbio); - if (free_wbio) { - BIO_free_all(ssl->wbio); - } + BIO_free_all(ssl->wbio); BUF_MEM_free(ssl->init_buf); /* add extra stuff */ ssl_cipher_preference_list_free(ssl->cipher_list); - sk_SSL_CIPHER_free(ssl->cipher_list_by_id); - ssl_clear_bad_session(ssl); SSL_SESSION_free(ssl->session); ssl_cert_free(ssl->cert); OPENSSL_free(ssl->tlsext_hostname); SSL_CTX_free(ssl->initial_ctx); - OPENSSL_free(ssl->tlsext_ellipticcurvelist); + OPENSSL_free(ssl->supported_group_list); OPENSSL_free(ssl->alpn_client_proto_list); EVP_PKEY_free(ssl->tlsext_channel_id_private); OPENSSL_free(ssl->psk_identity_hint); @@ -514,42 +516,73 @@ void SSL_free(SSL *ssl) { void SSL_set_connect_state(SSL *ssl) { ssl->server = 0; - ssl->shutdown = 0; - ssl->state = SSL_ST_CONNECT; - ssl->handshake_func = ssl->method->ssl_connect; + ssl->handshake_func = ssl3_connect; } void SSL_set_accept_state(SSL *ssl) { ssl->server = 1; - ssl->shutdown = 0; - ssl->state = SSL_ST_ACCEPT; - ssl->handshake_func = ssl->method->ssl_accept; + ssl->handshake_func = ssl3_accept; +} + +void SSL_set0_rbio(SSL *ssl, BIO *rbio) { + BIO_free_all(ssl->rbio); + ssl->rbio = rbio; +} + +void SSL_set0_wbio(SSL *ssl, BIO *wbio) { + BIO_free_all(ssl->wbio); + ssl->wbio = wbio; } void SSL_set_bio(SSL *ssl, BIO *rbio, BIO *wbio) { - /* If the output buffering BIO is still in place, remove it. */ - if (ssl->bbio != NULL) { - if (ssl->wbio == ssl->bbio) { - ssl->wbio = ssl->wbio->next_bio; - ssl->bbio->next_bio = NULL; - } + /* For historical reasons, this function has many different cases in ownership + * handling. */ + + /* If nothing has changed, do nothing */ + if (rbio == SSL_get_rbio(ssl) && wbio == SSL_get_wbio(ssl)) { + return; } - if (ssl->rbio != rbio) { - BIO_free_all(ssl->rbio); + /* If the two arguments are equal, one fewer reference is granted than + * taken. */ + if (rbio != NULL && rbio == wbio) { + BIO_up_ref(rbio); } - if (ssl->wbio != wbio && ssl->rbio != ssl->wbio) { - BIO_free_all(ssl->wbio); + + /* If only the wbio is changed, adopt only one reference. */ + if (rbio == SSL_get_rbio(ssl)) { + SSL_set0_wbio(ssl, wbio); + return; } - ssl->rbio = rbio; - ssl->wbio = wbio; + + /* There is an asymmetry here for historical reasons. If only the rbio is + * changed AND the rbio and wbio were originally different, then we only adopt + * one reference. */ + if (wbio == SSL_get_wbio(ssl) && SSL_get_rbio(ssl) != SSL_get_wbio(ssl)) { + SSL_set0_rbio(ssl, rbio); + return; + } + + /* Otherwise, adopt both references. */ + SSL_set0_rbio(ssl, rbio); + SSL_set0_wbio(ssl, wbio); } BIO *SSL_get_rbio(const SSL *ssl) { return ssl->rbio; } BIO *SSL_get_wbio(const SSL *ssl) { return ssl->wbio; } +void ssl_reset_error_state(SSL *ssl) { + /* Functions which use |SSL_get_error| must reset I/O and error state on + * entry. */ + ssl->rwstate = SSL_NOTHING; + ERR_clear_error(); + ERR_clear_system_error(); +} + int SSL_do_handshake(SSL *ssl) { + ssl_reset_error_state(ssl); + if (ssl->handshake_func == NULL) { OPENSSL_PUT_ERROR(SSL, SSL_R_CONNECTION_TYPE_NOT_SET); return -1; @@ -559,149 +592,272 @@ int SSL_do_handshake(SSL *ssl) { return 1; } - return ssl->handshake_func(ssl); + if (ssl->s3->hs == NULL) { + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + return -1; + } + + /* Run the handshake. */ + assert(ssl->s3->hs != NULL); + int ret = ssl->handshake_func(ssl->s3->hs); + if (ret <= 0) { + return ret; + } + + /* Destroy the handshake object if the handshake has completely finished. */ + if (!SSL_in_init(ssl)) { + ssl_handshake_free(ssl->s3->hs); + ssl->s3->hs = NULL; + } + + return 1; } int SSL_connect(SSL *ssl) { - if (ssl->handshake_func == 0) { + if (ssl->handshake_func == NULL) { /* Not properly initialized yet */ SSL_set_connect_state(ssl); } - if (ssl->handshake_func != ssl->method->ssl_connect) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - return -1; - } - - return ssl->handshake_func(ssl); + return SSL_do_handshake(ssl); } int SSL_accept(SSL *ssl) { - if (ssl->handshake_func == 0) { + if (ssl->handshake_func == NULL) { /* Not properly initialized yet */ SSL_set_accept_state(ssl); } - if (ssl->handshake_func != ssl->method->ssl_accept) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - return -1; + return SSL_do_handshake(ssl); +} + +static int ssl_do_renegotiate(SSL *ssl) { + /* We do not accept renegotiations as a server or SSL 3.0. SSL 3.0 will be + * removed entirely in the future and requires retaining more data for + * renegotiation_info. */ + if (ssl->server || ssl->version == SSL3_VERSION) { + goto no_renegotiation; } - return ssl->handshake_func(ssl); -} + if (ssl->s3->tmp.message_type != SSL3_MT_HELLO_REQUEST || + ssl->init_num != 0) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); + OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_HELLO_REQUEST); + return 0; + } -int SSL_read(SSL *ssl, void *buf, int num) { - if (ssl->handshake_func == 0) { - OPENSSL_PUT_ERROR(SSL, SSL_R_UNINITIALIZED); - return -1; + switch (ssl->renegotiate_mode) { + case ssl_renegotiate_ignore: + /* Ignore the HelloRequest. */ + return 1; + + case ssl_renegotiate_once: + if (ssl->s3->total_renegotiations != 0) { + goto no_renegotiation; + } + break; + + case ssl_renegotiate_never: + goto no_renegotiation; + + case ssl_renegotiate_freely: + break; + } + + /* Renegotiation is only supported at quiescent points in the application + * protocol, namely in HTTPS, just before reading the HTTP response. Require + * the record-layer be idle and avoid complexities of sending a handshake + * record while an application_data record is being written. */ + if (ssl_write_buffer_is_pending(ssl)) { + goto no_renegotiation; } - if (ssl->shutdown & SSL_RECEIVED_SHUTDOWN) { - ssl->rwstate = SSL_NOTHING; + /* Begin a new handshake. */ + if (ssl->s3->hs != NULL) { + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + return 0; + } + ssl->s3->hs = ssl_handshake_new(ssl); + if (ssl->s3->hs == NULL) { return 0; } - ERR_clear_system_error(); - return ssl->method->ssl_read_app_data(ssl, buf, num, 0); + ssl->s3->total_renegotiations++; + return 1; + +no_renegotiation: + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_NO_RENEGOTIATION); + OPENSSL_PUT_ERROR(SSL, SSL_R_NO_RENEGOTIATION); + return 0; } -int SSL_peek(SSL *ssl, void *buf, int num) { - if (ssl->handshake_func == 0) { +static int ssl_do_post_handshake(SSL *ssl) { + if (ssl3_protocol_version(ssl) < TLS1_3_VERSION) { + return ssl_do_renegotiate(ssl); + } + + return tls13_post_handshake(ssl); +} + +static int ssl_read_impl(SSL *ssl, void *buf, int num, int peek) { + ssl_reset_error_state(ssl); + + if (ssl->handshake_func == NULL) { OPENSSL_PUT_ERROR(SSL, SSL_R_UNINITIALIZED); return -1; } - if (ssl->shutdown & SSL_RECEIVED_SHUTDOWN) { - return 0; + for (;;) { + /* Complete the current handshake, if any. False Start will cause + * |SSL_do_handshake| to return mid-handshake, so this may require multiple + * iterations. */ + while (SSL_in_init(ssl)) { + int ret = SSL_do_handshake(ssl); + if (ret < 0) { + return ret; + } + if (ret == 0) { + OPENSSL_PUT_ERROR(SSL, SSL_R_SSL_HANDSHAKE_FAILURE); + return -1; + } + } + + int got_handshake; + int ret = ssl->method->read_app_data(ssl, &got_handshake, buf, num, peek); + if (ret > 0 || !got_handshake) { + ssl->s3->key_update_count = 0; + return ret; + } + + /* Handle the post-handshake message and try again. */ + if (!ssl_do_post_handshake(ssl)) { + return -1; + } + ssl->method->release_current_message(ssl, 1 /* free buffer */); } +} - ERR_clear_system_error(); - return ssl->method->ssl_read_app_data(ssl, buf, num, 1); +int SSL_read(SSL *ssl, void *buf, int num) { + return ssl_read_impl(ssl, buf, num, 0 /* consume bytes */); +} + +int SSL_peek(SSL *ssl, void *buf, int num) { + return ssl_read_impl(ssl, buf, num, 1 /* peek */); } int SSL_write(SSL *ssl, const void *buf, int num) { - if (ssl->handshake_func == 0) { + ssl_reset_error_state(ssl); + + if (ssl->handshake_func == NULL) { OPENSSL_PUT_ERROR(SSL, SSL_R_UNINITIALIZED); return -1; } - if (ssl->shutdown & SSL_SENT_SHUTDOWN) { - ssl->rwstate = SSL_NOTHING; + if (ssl->s3->send_shutdown != ssl_shutdown_none) { OPENSSL_PUT_ERROR(SSL, SSL_R_PROTOCOL_IS_SHUTDOWN); return -1; } - ERR_clear_system_error(); - return ssl->method->ssl_write_app_data(ssl, buf, num); + /* If necessary, complete the handshake implicitly. */ + if (SSL_in_init(ssl) && !SSL_in_false_start(ssl)) { + int ret = SSL_do_handshake(ssl); + if (ret < 0) { + return ret; + } + if (ret == 0) { + OPENSSL_PUT_ERROR(SSL, SSL_R_SSL_HANDSHAKE_FAILURE); + return -1; + } + } + + return ssl->method->write_app_data(ssl, buf, num); } int SSL_shutdown(SSL *ssl) { - /* Note that this function behaves differently from what one might expect. - * Return values are 0 for no success (yet), 1 for success; but calling it - * once is usually not enough, even if blocking I/O is used (see - * ssl3_shutdown). */ + ssl_reset_error_state(ssl); - if (ssl->handshake_func == 0) { + if (ssl->handshake_func == NULL) { OPENSSL_PUT_ERROR(SSL, SSL_R_UNINITIALIZED); return -1; } + /* If we are in the middle of a handshake, silently succeed. Consumers often + * call this function before |SSL_free|, whether the handshake succeeded or + * not. We assume the caller has already handled failed handshakes. */ if (SSL_in_init(ssl)) { return 1; } - /* Do nothing if configured not to send a close_notify. */ if (ssl->quiet_shutdown) { - ssl->shutdown = SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN; + /* Do nothing if configured not to send a close_notify. */ + ssl->s3->send_shutdown = ssl_shutdown_close_notify; + ssl->s3->recv_shutdown = ssl_shutdown_close_notify; return 1; } - if (!(ssl->shutdown & SSL_SENT_SHUTDOWN)) { - ssl->shutdown |= SSL_SENT_SHUTDOWN; - ssl3_send_alert(ssl, SSL3_AL_WARNING, SSL_AD_CLOSE_NOTIFY); + /* This function completes in two stages. It sends a close_notify and then it + * waits for a close_notify to come in. Perform exactly one action and return + * whether or not it succeeds. */ - /* our shutdown alert has been sent now, and if it still needs to be - * written, ssl->s3->alert_dispatch will be true */ - if (ssl->s3->alert_dispatch) { - return -1; /* return WANT_WRITE */ + if (ssl->s3->send_shutdown != ssl_shutdown_close_notify) { + /* Send a close_notify. */ + if (ssl3_send_alert(ssl, SSL3_AL_WARNING, SSL_AD_CLOSE_NOTIFY) <= 0) { + return -1; } } else if (ssl->s3->alert_dispatch) { - /* resend it if not sent */ - int ret = ssl->method->ssl_dispatch_alert(ssl); - if (ret == -1) { - /* we only get to return -1 here the 2nd/Nth invocation, we must have - * already signalled return 0 upon a previous invoation, return - * WANT_WRITE */ - return ret; + /* Finish sending the close_notify. */ + if (ssl->method->dispatch_alert(ssl) <= 0) { + return -1; } - } else if (!(ssl->shutdown & SSL_RECEIVED_SHUTDOWN)) { - /* If we are waiting for a close from our peer, we are closed */ - ssl->method->ssl_read_close_notify(ssl); - if (!(ssl->shutdown & SSL_RECEIVED_SHUTDOWN)) { - return -1; /* return WANT_READ */ + } else if (ssl->s3->recv_shutdown != ssl_shutdown_close_notify) { + /* Wait for the peer's close_notify. */ + ssl->method->read_close_notify(ssl); + if (ssl->s3->recv_shutdown != ssl_shutdown_close_notify) { + return -1; } } - if (ssl->shutdown == (SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN) && - !ssl->s3->alert_dispatch) { - return 1; - } else { - return 0; + /* Return 0 for unidirectional shutdown and 1 for bidirectional shutdown. */ + return ssl->s3->recv_shutdown == ssl_shutdown_close_notify; +} + +int SSL_send_fatal_alert(SSL *ssl, uint8_t alert) { + if (ssl->s3->alert_dispatch) { + if (ssl->s3->send_alert[0] != SSL3_AL_FATAL || + ssl->s3->send_alert[1] != alert) { + /* We are already attempting to write a different alert. */ + OPENSSL_PUT_ERROR(SSL, SSL_R_PROTOCOL_IS_SHUTDOWN); + return -1; + } + return ssl->method->dispatch_alert(ssl); } + + return ssl3_send_alert(ssl, SSL3_AL_FATAL, alert); } -int SSL_get_error(const SSL *ssl, int ret_code) { - int reason; - uint32_t err; - BIO *bio; +void SSL_CTX_set_early_data_enabled(SSL_CTX *ctx, int enabled) { + ctx->enable_early_data = !!enabled; +} + +static int bio_retry_reason_to_error(int reason) { + switch (reason) { + case BIO_RR_CONNECT: + return SSL_ERROR_WANT_CONNECT; + case BIO_RR_ACCEPT: + return SSL_ERROR_WANT_ACCEPT; + default: + return SSL_ERROR_SYSCALL; + } +} +int SSL_get_error(const SSL *ssl, int ret_code) { if (ret_code > 0) { return SSL_ERROR_NONE; } /* Make things return SSL_ERROR_SYSCALL when doing SSL_do_handshake etc, * where we do encode the error */ - err = ERR_peek_error(); + uint32_t err = ERR_peek_error(); if (err != 0) { if (ERR_GET_LIB(err) == ERR_LIB_SYS) { return SSL_ERROR_SYSCALL; @@ -710,9 +866,7 @@ int SSL_get_error(const SSL *ssl, int ret_code) { } if (ret_code == 0) { - if ((ssl->shutdown & SSL_RECEIVED_SHUTDOWN) && - (ssl->s3->warn_alert == SSL_AD_CLOSE_NOTIFY)) { - /* The socket was cleanly shut down with a close_notify. */ + if (ssl->s3->recv_shutdown == ssl_shutdown_close_notify) { return SSL_ERROR_ZERO_RETURN; } /* An EOF was observed which violates the protocol, and the underlying @@ -721,98 +875,110 @@ int SSL_get_error(const SSL *ssl, int ret_code) { return SSL_ERROR_SYSCALL; } - if (SSL_want_session(ssl)) { - return SSL_ERROR_PENDING_SESSION; - } - - if (SSL_want_certificate(ssl)) { - return SSL_ERROR_PENDING_CERTIFICATE; - } - - if (SSL_want_read(ssl)) { - bio = SSL_get_rbio(ssl); - if (BIO_should_read(bio)) { - return SSL_ERROR_WANT_READ; - } + switch (ssl->rwstate) { + case SSL_PENDING_SESSION: + return SSL_ERROR_PENDING_SESSION; - if (BIO_should_write(bio)) { - /* This one doesn't make too much sense ... We never try to write to the - * rbio, and an application program where rbio and wbio are separate - * couldn't even know what it should wait for. However if we ever set - * ssl->rwstate incorrectly (so that we have SSL_want_read(ssl) instead of - * SSL_want_write(ssl)) and rbio and wbio *are* the same, this test works - * around that bug; so it might be safer to keep it. */ - return SSL_ERROR_WANT_WRITE; - } + case SSL_CERTIFICATE_SELECTION_PENDING: + return SSL_ERROR_PENDING_CERTIFICATE; - if (BIO_should_io_special(bio)) { - reason = BIO_get_retry_reason(bio); - if (reason == BIO_RR_CONNECT) { - return SSL_ERROR_WANT_CONNECT; + case SSL_READING: { + BIO *bio = SSL_get_rbio(ssl); + if (BIO_should_read(bio)) { + return SSL_ERROR_WANT_READ; } - if (reason == BIO_RR_ACCEPT) { - return SSL_ERROR_WANT_ACCEPT; + if (BIO_should_write(bio)) { + /* TODO(davidben): OpenSSL historically checked for writes on the read + * BIO. Can this be removed? */ + return SSL_ERROR_WANT_WRITE; } - return SSL_ERROR_SYSCALL; /* unknown */ - } - } + if (BIO_should_io_special(bio)) { + return bio_retry_reason_to_error(BIO_get_retry_reason(bio)); + } - if (SSL_want_write(ssl)) { - bio = SSL_get_wbio(ssl); - if (BIO_should_write(bio)) { - return SSL_ERROR_WANT_WRITE; + break; } - if (BIO_should_read(bio)) { - /* See above (SSL_want_read(ssl) with BIO_should_write(bio)) */ - return SSL_ERROR_WANT_READ; - } + case SSL_WRITING: { + BIO *bio = SSL_get_wbio(ssl); + if (BIO_should_write(bio)) { + return SSL_ERROR_WANT_WRITE; + } - if (BIO_should_io_special(bio)) { - reason = BIO_get_retry_reason(bio); - if (reason == BIO_RR_CONNECT) { - return SSL_ERROR_WANT_CONNECT; + if (BIO_should_read(bio)) { + /* TODO(davidben): OpenSSL historically checked for reads on the write + * BIO. Can this be removed? */ + return SSL_ERROR_WANT_READ; } - if (reason == BIO_RR_ACCEPT) { - return SSL_ERROR_WANT_ACCEPT; + if (BIO_should_io_special(bio)) { + return bio_retry_reason_to_error(BIO_get_retry_reason(bio)); } - return SSL_ERROR_SYSCALL; + break; } + + case SSL_X509_LOOKUP: + return SSL_ERROR_WANT_X509_LOOKUP; + + case SSL_CHANNEL_ID_LOOKUP: + return SSL_ERROR_WANT_CHANNEL_ID_LOOKUP; + + case SSL_PRIVATE_KEY_OPERATION: + return SSL_ERROR_WANT_PRIVATE_KEY_OPERATION; + } + + return SSL_ERROR_SYSCALL; +} + +static int set_min_version(const SSL_PROTOCOL_METHOD *method, uint16_t *out, + uint16_t version) { + if (version == 0) { + *out = method->min_version; + return 1; } - if (SSL_want_x509_lookup(ssl)) { - return SSL_ERROR_WANT_X509_LOOKUP; + if (version == TLS1_3_VERSION) { + version = TLS1_3_DRAFT_VERSION; } - if (SSL_want_channel_id_lookup(ssl)) { - return SSL_ERROR_WANT_CHANNEL_ID_LOOKUP; + return method->version_from_wire(out, version); +} + +static int set_max_version(const SSL_PROTOCOL_METHOD *method, uint16_t *out, + uint16_t version) { + if (version == 0) { + *out = method->max_version; + /* TODO(svaldez): Enable TLS 1.3 by default once fully implemented. */ + if (*out > TLS1_2_VERSION) { + *out = TLS1_2_VERSION; + } + return 1; } - if (SSL_want_private_key_operation(ssl)) { - return SSL_ERROR_WANT_PRIVATE_KEY_OPERATION; + if (version == TLS1_3_VERSION) { + version = TLS1_3_DRAFT_VERSION; } - return SSL_ERROR_SYSCALL; + return method->version_from_wire(out, version); } -void SSL_CTX_set_min_version(SSL_CTX *ctx, uint16_t version) { - ctx->min_version = version; +int SSL_CTX_set_min_proto_version(SSL_CTX *ctx, uint16_t version) { + return set_min_version(ctx->method, &ctx->min_version, version); } -void SSL_CTX_set_max_version(SSL_CTX *ctx, uint16_t version) { - ctx->max_version = version; +int SSL_CTX_set_max_proto_version(SSL_CTX *ctx, uint16_t version) { + return set_max_version(ctx->method, &ctx->max_version, version); } -void SSL_set_min_version(SSL *ssl, uint16_t version) { - ssl->min_version = version; +int SSL_set_min_proto_version(SSL *ssl, uint16_t version) { + return set_min_version(ssl->method, &ssl->min_version, version); } -void SSL_set_max_version(SSL *ssl, uint16_t version) { - ssl->max_version = version; +int SSL_set_max_proto_version(SSL *ssl, uint16_t version) { + return set_max_version(ssl->method, &ssl->max_version, version); } uint32_t SSL_CTX_set_options(SSL_CTX *ctx, uint32_t options) { @@ -863,28 +1029,25 @@ uint32_t SSL_clear_mode(SSL *ssl, uint32_t mode) { uint32_t SSL_get_mode(const SSL *ssl) { return ssl->mode; } -X509 *SSL_get_peer_certificate(const SSL *ssl) { - if (ssl == NULL || ssl->session == NULL || ssl->session->peer == NULL) { - return NULL; - } - return X509_up_ref(ssl->session->peer); -} - -STACK_OF(X509) *SSL_get_peer_cert_chain(const SSL *ssl) { - if (ssl == NULL || ssl->session == NULL) { - return NULL; - } - return ssl->session->cert_chain; +void SSL_CTX_set0_buffer_pool(SSL_CTX *ctx, CRYPTO_BUFFER_POOL *pool) { + ctx->pool = pool; } int SSL_get_tls_unique(const SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out) { + /* tls-unique is not defined for SSL 3.0 or TLS 1.3. */ + if (!ssl->s3->initial_handshake_complete || + ssl3_protocol_version(ssl) < TLS1_VERSION || + ssl3_protocol_version(ssl) >= TLS1_3_VERSION) { + goto err; + } + /* The tls-unique value is the first Finished message in the handshake, which * is the client's in a full handshake and the server's for a resumption. See * https://tools.ietf.org/html/rfc5929#section-3.1. */ const uint8_t *finished = ssl->s3->previous_client_finished; size_t finished_len = ssl->s3->previous_client_finished_len; - if (ssl->hit) { + if (ssl->session != NULL) { /* tls-unique is broken for resumed sessions unless EMS is used. */ if (!ssl->session->extended_master_secret) { goto err; @@ -893,71 +1056,46 @@ int SSL_get_tls_unique(const SSL *ssl, uint8_t *out, size_t *out_len, finished_len = ssl->s3->previous_server_finished_len; } - if (!ssl->s3->initial_handshake_complete || - ssl->version < TLS1_VERSION) { - goto err; - } - *out_len = finished_len; if (finished_len > max_out) { *out_len = max_out; } - memcpy(out, finished, *out_len); + OPENSSL_memcpy(out, finished, *out_len); return 1; err: *out_len = 0; - memset(out, 0, max_out); + OPENSSL_memset(out, 0, max_out); return 0; } -int SSL_CTX_set_session_id_context(SSL_CTX *ctx, const uint8_t *sid_ctx, - unsigned sid_ctx_len) { - if (sid_ctx_len > sizeof(ctx->sid_ctx)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG); - return 0; - } - ctx->sid_ctx_length = sid_ctx_len; - memcpy(ctx->sid_ctx, sid_ctx, sid_ctx_len); - - return 1; -} - -int SSL_set_session_id_context(SSL *ssl, const uint8_t *sid_ctx, - unsigned sid_ctx_len) { - if (sid_ctx_len > SSL_MAX_SID_CTX_LENGTH) { +static int set_session_id_context(CERT *cert, const uint8_t *sid_ctx, + size_t sid_ctx_len) { + if (sid_ctx_len > sizeof(cert->sid_ctx)) { OPENSSL_PUT_ERROR(SSL, SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG); return 0; } - ssl->sid_ctx_length = sid_ctx_len; - memcpy(ssl->sid_ctx, sid_ctx, sid_ctx_len); + OPENSSL_COMPILE_ASSERT(sizeof(cert->sid_ctx) < 256, sid_ctx_too_large); + cert->sid_ctx_length = (uint8_t)sid_ctx_len; + OPENSSL_memcpy(cert->sid_ctx, sid_ctx, sid_ctx_len); return 1; } -int SSL_CTX_set_purpose(SSL_CTX *ctx, int purpose) { - return X509_VERIFY_PARAM_set_purpose(ctx->param, purpose); -} - -int SSL_set_purpose(SSL *ssl, int purpose) { - return X509_VERIFY_PARAM_set_purpose(ssl->param, purpose); -} - -int SSL_CTX_set_trust(SSL_CTX *ctx, int trust) { - return X509_VERIFY_PARAM_set_trust(ctx->param, trust); -} - -int SSL_set_trust(SSL *ssl, int trust) { - return X509_VERIFY_PARAM_set_trust(ssl->param, trust); +int SSL_CTX_set_session_id_context(SSL_CTX *ctx, const uint8_t *sid_ctx, + size_t sid_ctx_len) { + return set_session_id_context(ctx->cert, sid_ctx, sid_ctx_len); } -int SSL_CTX_set1_param(SSL_CTX *ctx, const X509_VERIFY_PARAM *param) { - return X509_VERIFY_PARAM_set1(ctx->param, param); +int SSL_set_session_id_context(SSL *ssl, const uint8_t *sid_ctx, + size_t sid_ctx_len) { + return set_session_id_context(ssl->cert, sid_ctx, sid_ctx_len); } -int SSL_set1_param(SSL *ssl, const X509_VERIFY_PARAM *param) { - return X509_VERIFY_PARAM_set1(ssl->param, param); +const uint8_t *SSL_get0_session_id_context(const SSL *ssl, size_t *out_len) { + *out_len = ssl->cert->sid_ctx_length; + return ssl->cert->sid_ctx; } void ssl_cipher_preference_list_free( @@ -970,10 +1108,6 @@ void ssl_cipher_preference_list_free( OPENSSL_free(cipher_list); } -X509_VERIFY_PARAM *SSL_CTX_get0_param(SSL_CTX *ctx) { return ctx->param; } - -X509_VERIFY_PARAM *SSL_get0_param(SSL *ssl) { return ssl->param; } - void SSL_certs_clear(SSL *ssl) { ssl_cert_clear_certs(ssl->cert); } int SSL_get_fd(const SSL *ssl) { return SSL_get_rfd(ssl); } @@ -997,7 +1131,7 @@ int SSL_get_wfd(const SSL *ssl) { } int SSL_set_fd(SSL *ssl, int fd) { - BIO *bio = BIO_new(BIO_s_fd()); + BIO *bio = BIO_new(BIO_s_socket()); if (bio == NULL) { OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB); return 0; @@ -1008,102 +1142,108 @@ int SSL_set_fd(SSL *ssl, int fd) { } int SSL_set_wfd(SSL *ssl, int fd) { - if (ssl->rbio == NULL || - BIO_method_type(ssl->rbio) != BIO_TYPE_FD || - BIO_get_fd(ssl->rbio, NULL) != fd) { - BIO *bio = BIO_new(BIO_s_fd()); + BIO *rbio = SSL_get_rbio(ssl); + if (rbio == NULL || BIO_method_type(rbio) != BIO_TYPE_SOCKET || + BIO_get_fd(rbio, NULL) != fd) { + BIO *bio = BIO_new(BIO_s_socket()); if (bio == NULL) { OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB); return 0; } BIO_set_fd(bio, fd, BIO_NOCLOSE); - SSL_set_bio(ssl, SSL_get_rbio(ssl), bio); + SSL_set0_wbio(ssl, bio); } else { - SSL_set_bio(ssl, SSL_get_rbio(ssl), SSL_get_rbio(ssl)); + /* Copy the rbio over to the wbio. */ + BIO_up_ref(rbio); + SSL_set0_wbio(ssl, rbio); } return 1; } int SSL_set_rfd(SSL *ssl, int fd) { - if (ssl->wbio == NULL || BIO_method_type(ssl->wbio) != BIO_TYPE_FD || - BIO_get_fd(ssl->wbio, NULL) != fd) { - BIO *bio = BIO_new(BIO_s_fd()); + BIO *wbio = SSL_get_wbio(ssl); + if (wbio == NULL || BIO_method_type(wbio) != BIO_TYPE_SOCKET || + BIO_get_fd(wbio, NULL) != fd) { + BIO *bio = BIO_new(BIO_s_socket()); if (bio == NULL) { OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB); return 0; } BIO_set_fd(bio, fd, BIO_NOCLOSE); - SSL_set_bio(ssl, bio, SSL_get_wbio(ssl)); + SSL_set0_rbio(ssl, bio); } else { - SSL_set_bio(ssl, SSL_get_wbio(ssl), SSL_get_wbio(ssl)); + /* Copy the wbio over to the rbio. */ + BIO_up_ref(wbio); + SSL_set0_rbio(ssl, wbio); } return 1; } +static size_t copy_finished(void *out, size_t out_len, const uint8_t *in, + size_t in_len) { + if (out_len > in_len) { + out_len = in_len; + } + OPENSSL_memcpy(out, in, out_len); + return in_len; +} + size_t SSL_get_finished(const SSL *ssl, void *buf, size_t count) { - size_t ret = 0; + if (!ssl->s3->initial_handshake_complete || + ssl3_protocol_version(ssl) < TLS1_VERSION || + ssl3_protocol_version(ssl) >= TLS1_3_VERSION) { + return 0; + } - if (ssl->s3 != NULL) { - ret = ssl->s3->tmp.finish_md_len; - if (count > ret) { - count = ret; - } - memcpy(buf, ssl->s3->tmp.finish_md, count); + if (ssl->server) { + return copy_finished(buf, count, ssl->s3->previous_server_finished, + ssl->s3->previous_server_finished_len); } - return ret; + return copy_finished(buf, count, ssl->s3->previous_client_finished, + ssl->s3->previous_client_finished_len); } size_t SSL_get_peer_finished(const SSL *ssl, void *buf, size_t count) { - size_t ret = 0; + if (!ssl->s3->initial_handshake_complete || + ssl3_protocol_version(ssl) < TLS1_VERSION || + ssl3_protocol_version(ssl) >= TLS1_3_VERSION) { + return 0; + } - if (ssl->s3 != NULL) { - ret = ssl->s3->tmp.peer_finish_md_len; - if (count > ret) { - count = ret; - } - memcpy(buf, ssl->s3->tmp.peer_finish_md, count); + if (ssl->server) { + return copy_finished(buf, count, ssl->s3->previous_client_finished, + ssl->s3->previous_client_finished_len); } - return ret; + return copy_finished(buf, count, ssl->s3->previous_server_finished, + ssl->s3->previous_server_finished_len); } int SSL_get_verify_mode(const SSL *ssl) { return ssl->verify_mode; } -int SSL_get_verify_depth(const SSL *ssl) { - return X509_VERIFY_PARAM_get_depth(ssl->param); -} - int SSL_get_extms_support(const SSL *ssl) { - return ssl->s3->tmp.extended_master_secret == 1; -} - -int (*SSL_get_verify_callback(const SSL *ssl))(int, X509_STORE_CTX *) { - return ssl->verify_callback; -} - -int SSL_CTX_get_verify_mode(const SSL_CTX *ctx) { return ctx->verify_mode; } - -int SSL_CTX_get_verify_depth(const SSL_CTX *ctx) { - return X509_VERIFY_PARAM_get_depth(ctx->param); -} - -int (*SSL_CTX_get_verify_callback(const SSL_CTX *ctx))( - int ok, X509_STORE_CTX *store_ctx) { - return ctx->default_verify_callback; -} + /* TLS 1.3 does not require extended master secret and always reports as + * supporting it. */ + if (!ssl->s3->have_version) { + return 0; + } + if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) { + return 1; + } -void SSL_set_verify(SSL *ssl, int mode, - int (*callback)(int ok, X509_STORE_CTX *store_ctx)) { - ssl->verify_mode = mode; - if (callback != NULL) { - ssl->verify_callback = callback; + /* If the initial handshake completed, query the established session. */ + if (ssl->s3->established_session != NULL) { + return ssl->s3->established_session->extended_master_secret; } -} -void SSL_set_verify_depth(SSL *ssl, int depth) { - X509_VERIFY_PARAM_set_depth(ssl->param, depth); + /* Otherwise, query the in-progress handshake. */ + if (ssl->s3->hs != NULL) { + return ssl->s3->hs->extended_master_secret; + } + assert(0); + return 0; } int SSL_CTX_get_read_ahead(const SSL_CTX *ctx) { return 0; } @@ -1123,32 +1263,12 @@ int SSL_pending(const SSL *ssl) { /* Fix this so it checks all the valid key/cert options */ int SSL_CTX_check_private_key(const SSL_CTX *ctx) { - if (ctx->cert->x509 == NULL) { - OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CERTIFICATE_ASSIGNED); - return 0; - } - - if (ctx->cert->privatekey == NULL) { - OPENSSL_PUT_ERROR(SSL, SSL_R_NO_PRIVATE_KEY_ASSIGNED); - return 0; - } - - return X509_check_private_key(ctx->cert->x509, ctx->cert->privatekey); + return ssl_cert_check_private_key(ctx->cert, ctx->cert->privatekey); } /* Fix this function so that it takes an optional type parameter */ int SSL_check_private_key(const SSL *ssl) { - if (ssl->cert->x509 == NULL) { - OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CERTIFICATE_ASSIGNED); - return 0; - } - - if (ssl->cert->privatekey == NULL) { - OPENSSL_PUT_ERROR(SSL, SSL_R_NO_PRIVATE_KEY_ASSIGNED); - return 0; - } - - return X509_check_private_key(ssl->cert->x509, ssl->cert->privatekey); + return ssl_cert_check_private_key(ssl->cert, ssl->cert->privatekey); } long SSL_get_default_timeout(const SSL *ssl) { @@ -1165,6 +1285,10 @@ int SSL_renegotiate_pending(SSL *ssl) { return SSL_in_init(ssl) && ssl->s3->initial_handshake_complete; } +int SSL_total_renegotiations(const SSL *ssl) { + return ssl->s3->total_renegotiations; +} + size_t SSL_CTX_get_max_cert_list(const SSL_CTX *ctx) { return ctx->max_cert_list; } @@ -1212,7 +1336,7 @@ int SSL_set_max_send_fragment(SSL *ssl, size_t max_send_fragment) { } int SSL_set_mtu(SSL *ssl, unsigned mtu) { - if (!SSL_IS_DTLS(ssl) || mtu < dtls1_min_mtu()) { + if (!SSL_is_dtls(ssl) || mtu < dtls1_min_mtu()) { return 0; } ssl->d1->mtu = mtu; @@ -1220,7 +1344,11 @@ int SSL_set_mtu(SSL *ssl, unsigned mtu) { } int SSL_get_secure_renegotiation_support(const SSL *ssl) { - return ssl->s3->send_connection_binding; + if (!ssl->s3->have_version) { + return 0; + } + return ssl3_protocol_version(ssl) >= TLS1_3_VERSION || + ssl->s3->send_connection_binding; } LHASH_OF(SSL_SESSION) *SSL_CTX_sessions(SSL_CTX *ctx) { return ctx->sessions; } @@ -1249,48 +1377,110 @@ int SSL_CTX_get_session_cache_mode(const SSL_CTX *ctx) { return ctx->session_cache_mode; } -STACK_OF(SSL_CIPHER) *SSL_get_ciphers(const SSL *ssl) { - if (ssl == NULL) { - return NULL; - } - if (ssl->cipher_list != NULL) { - return ssl->cipher_list->ciphers; +int SSL_CTX_get_tlsext_ticket_keys(SSL_CTX *ctx, void *out, size_t len) { + if (out == NULL) { + return 48; } - - if (ssl->version >= TLS1_1_VERSION && ssl->ctx != NULL && - ssl->ctx->cipher_list_tls11 != NULL) { - return ssl->ctx->cipher_list_tls11->ciphers; + if (len != 48) { + OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_TICKET_KEYS_LENGTH); + return 0; } + uint8_t *out_bytes = out; + OPENSSL_memcpy(out_bytes, ctx->tlsext_tick_key_name, 16); + OPENSSL_memcpy(out_bytes + 16, ctx->tlsext_tick_hmac_key, 16); + OPENSSL_memcpy(out_bytes + 32, ctx->tlsext_tick_aes_key, 16); + return 1; +} - if (ssl->version >= TLS1_VERSION && ssl->ctx != NULL && - ssl->ctx->cipher_list_tls10 != NULL) { - return ssl->ctx->cipher_list_tls10->ciphers; +int SSL_CTX_set_tlsext_ticket_keys(SSL_CTX *ctx, const void *in, size_t len) { + if (in == NULL) { + return 48; } - - if (ssl->ctx != NULL && ssl->ctx->cipher_list != NULL) { - return ssl->ctx->cipher_list->ciphers; + if (len != 48) { + OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_TICKET_KEYS_LENGTH); + return 0; } + const uint8_t *in_bytes = in; + OPENSSL_memcpy(ctx->tlsext_tick_key_name, in_bytes, 16); + OPENSSL_memcpy(ctx->tlsext_tick_hmac_key, in_bytes + 16, 16); + OPENSSL_memcpy(ctx->tlsext_tick_aes_key, in_bytes + 32, 16); + return 1; +} - return NULL; +int SSL_CTX_set_tlsext_ticket_key_cb( + SSL_CTX *ctx, int (*callback)(SSL *ssl, uint8_t *key_name, uint8_t *iv, + EVP_CIPHER_CTX *ctx, HMAC_CTX *hmac_ctx, + int encrypt)) { + ctx->tlsext_ticket_key_cb = callback; + return 1; } -/* return a STACK of the ciphers available for the SSL and in order of - * algorithm id */ -STACK_OF(SSL_CIPHER) *ssl_get_ciphers_by_id(SSL *ssl) { - if (ssl == NULL) { - return NULL; - } +int SSL_CTX_set1_curves(SSL_CTX *ctx, const int *curves, size_t curves_len) { + return tls1_set_curves(&ctx->supported_group_list, + &ctx->supported_group_list_len, curves, + curves_len); +} - if (ssl->cipher_list_by_id != NULL) { - return ssl->cipher_list_by_id; - } +int SSL_set1_curves(SSL *ssl, const int *curves, size_t curves_len) { + return tls1_set_curves(&ssl->supported_group_list, + &ssl->supported_group_list_len, curves, + curves_len); +} + +int SSL_CTX_set1_curves_list(SSL_CTX *ctx, const char *curves) { + return tls1_set_curves_list(&ctx->supported_group_list, + &ctx->supported_group_list_len, curves); +} - if (ssl->ctx != NULL && ssl->ctx->cipher_list_by_id != NULL) { - return ssl->ctx->cipher_list_by_id; +int SSL_set1_curves_list(SSL *ssl, const char *curves) { + return tls1_set_curves_list(&ssl->supported_group_list, + &ssl->supported_group_list_len, curves); +} + +uint16_t SSL_get_curve_id(const SSL *ssl) { + /* TODO(davidben): This checks the wrong session if there is a renegotiation in + * progress. */ + SSL_SESSION *session = SSL_get_session(ssl); + if (session == NULL) { + return 0; } - return NULL; + return session->group_id; +} + +int SSL_CTX_set_tmp_dh(SSL_CTX *ctx, const DH *dh) { + DH_free(ctx->cert->dh_tmp); + ctx->cert->dh_tmp = DHparams_dup(dh); + if (ctx->cert->dh_tmp == NULL) { + OPENSSL_PUT_ERROR(SSL, ERR_R_DH_LIB); + return 0; + } + return 1; +} + +int SSL_set_tmp_dh(SSL *ssl, const DH *dh) { + DH_free(ssl->cert->dh_tmp); + ssl->cert->dh_tmp = DHparams_dup(dh); + if (ssl->cert->dh_tmp == NULL) { + OPENSSL_PUT_ERROR(SSL, ERR_R_DH_LIB); + return 0; + } + return 1; +} + +STACK_OF(SSL_CIPHER) *SSL_get_ciphers(const SSL *ssl) { + if (ssl == NULL) { + return NULL; + } + + const struct ssl_cipher_preference_list_st *prefs = + ssl_get_cipher_preferences(ssl); + if (prefs == NULL) { + return NULL; + } + + return prefs->ciphers; } const char *SSL_get_cipher_list(const SSL *ssl, int n) { @@ -1315,8 +1505,9 @@ const char *SSL_get_cipher_list(const SSL *ssl, int n) { } int SSL_CTX_set_cipher_list(SSL_CTX *ctx, const char *str) { - STACK_OF(SSL_CIPHER) *cipher_list = ssl_create_cipher_list( - ctx->method, &ctx->cipher_list, &ctx->cipher_list_by_id, str); + STACK_OF(SSL_CIPHER) *cipher_list = + ssl_create_cipher_list(ctx->method, &ctx->cipher_list, str, + 0 /* not strict */); if (cipher_list == NULL) { return 0; } @@ -1330,9 +1521,10 @@ int SSL_CTX_set_cipher_list(SSL_CTX *ctx, const char *str) { return 1; } -int SSL_CTX_set_cipher_list_tls10(SSL_CTX *ctx, const char *str) { - STACK_OF(SSL_CIPHER) *cipher_list = ssl_create_cipher_list( - ctx->method, &ctx->cipher_list_tls10, NULL, str); +int SSL_CTX_set_strict_cipher_list(SSL_CTX *ctx, const char *str) { + STACK_OF(SSL_CIPHER) *cipher_list = + ssl_create_cipher_list(ctx->method, &ctx->cipher_list, str, + 1 /* strict */); if (cipher_list == NULL) { return 0; } @@ -1346,9 +1538,10 @@ int SSL_CTX_set_cipher_list_tls10(SSL_CTX *ctx, const char *str) { return 1; } -int SSL_CTX_set_cipher_list_tls11(SSL_CTX *ctx, const char *str) { - STACK_OF(SSL_CIPHER) *cipher_list = ssl_create_cipher_list( - ctx->method, &ctx->cipher_list_tls11, NULL, str); +int SSL_set_cipher_list(SSL *ssl, const char *str) { + STACK_OF(SSL_CIPHER) *cipher_list = + ssl_create_cipher_list(ssl->ctx->method, &ssl->cipher_list, str, + 0 /* not strict */); if (cipher_list == NULL) { return 0; } @@ -1362,9 +1555,10 @@ int SSL_CTX_set_cipher_list_tls11(SSL_CTX *ctx, const char *str) { return 1; } -int SSL_set_cipher_list(SSL *ssl, const char *str) { - STACK_OF(SSL_CIPHER) *cipher_list = ssl_create_cipher_list( - ssl->ctx->method, &ssl->cipher_list, &ssl->cipher_list_by_id, str); +int SSL_set_strict_cipher_list(SSL *ssl, const char *str) { + STACK_OF(SSL_CIPHER) *cipher_list = + ssl_create_cipher_list(ssl->ctx->method, &ssl->cipher_list, str, + 1 /* strict */); if (cipher_list == NULL) { return 0; } @@ -1378,72 +1572,6 @@ int SSL_set_cipher_list(SSL *ssl, const char *str) { return 1; } -STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *ssl, const CBS *cbs) { - CBS cipher_suites = *cbs; - const SSL_CIPHER *c; - STACK_OF(SSL_CIPHER) *sk; - - if (ssl->s3) { - ssl->s3->send_connection_binding = 0; - } - - if (CBS_len(&cipher_suites) % 2 != 0) { - OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST); - return NULL; - } - - sk = sk_SSL_CIPHER_new_null(); - if (sk == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; - } - - while (CBS_len(&cipher_suites) > 0) { - uint16_t cipher_suite; - - if (!CBS_get_u16(&cipher_suites, &cipher_suite)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - goto err; - } - - /* Check for SCSV. */ - if (ssl->s3 && cipher_suite == (SSL3_CK_SCSV & 0xffff)) { - /* SCSV is fatal if renegotiating. */ - if (ssl->s3->initial_handshake_complete) { - OPENSSL_PUT_ERROR(SSL, SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING); - ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE); - goto err; - } - ssl->s3->send_connection_binding = 1; - continue; - } - - /* Check for FALLBACK_SCSV. */ - if (ssl->s3 && cipher_suite == (SSL3_CK_FALLBACK_SCSV & 0xffff)) { - uint16_t max_version = ssl3_get_max_server_version(ssl); - if (SSL_IS_DTLS(ssl) ? (uint16_t)ssl->version > max_version - : (uint16_t)ssl->version < max_version) { - OPENSSL_PUT_ERROR(SSL, SSL_R_INAPPROPRIATE_FALLBACK); - ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL3_AD_INAPPROPRIATE_FALLBACK); - goto err; - } - continue; - } - - c = SSL_get_cipher_by_value(cipher_suite); - if (c != NULL && !sk_SSL_CIPHER_push(sk, c)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; - } - } - - return sk; - -err: - sk_SSL_CIPHER_free(sk); - return NULL; -} - const char *SSL_get_servername(const SSL *ssl, const int type) { if (type != TLSEXT_NAMETYPE_host_name) { return NULL; @@ -1455,41 +1583,49 @@ const char *SSL_get_servername(const SSL *ssl, const int type) { return ssl->tlsext_hostname; } - if (ssl->session == NULL) { + /* During the handshake, report the handshake value. */ + if (ssl->s3->hs != NULL) { + return ssl->s3->hs->hostname; + } + + /* SSL_get_servername may also be called after the handshake to look up the + * SNI value. + * + * TODO(davidben): This is almost unused. Can we remove it? */ + SSL_SESSION *session = SSL_get_session(ssl); + if (session == NULL) { return NULL; } - return ssl->session->tlsext_hostname; + return session->tlsext_hostname; } int SSL_get_servername_type(const SSL *ssl) { - if (ssl->session != NULL && ssl->session->tlsext_hostname != NULL) { - return TLSEXT_NAMETYPE_host_name; + SSL_SESSION *session = SSL_get_session(ssl); + if (session == NULL || session->tlsext_hostname == NULL) { + return -1; } - - return -1; + return TLSEXT_NAMETYPE_host_name; } void SSL_CTX_enable_signed_cert_timestamps(SSL_CTX *ctx) { ctx->signed_cert_timestamps_enabled = 1; } -int SSL_enable_signed_cert_timestamps(SSL *ssl) { +void SSL_enable_signed_cert_timestamps(SSL *ssl) { ssl->signed_cert_timestamps_enabled = 1; - return 1; } void SSL_CTX_enable_ocsp_stapling(SSL_CTX *ctx) { ctx->ocsp_stapling_enabled = 1; } -int SSL_enable_ocsp_stapling(SSL *ssl) { +void SSL_enable_ocsp_stapling(SSL *ssl) { ssl->ocsp_stapling_enabled = 1; - return 1; } void SSL_get0_signed_cert_timestamp_list(const SSL *ssl, const uint8_t **out, size_t *out_len) { - SSL_SESSION *session = ssl->session; + SSL_SESSION *session = SSL_get_session(ssl); *out_len = 0; *out = NULL; @@ -1503,7 +1639,7 @@ void SSL_get0_signed_cert_timestamp_list(const SSL *ssl, const uint8_t **out, void SSL_get0_ocsp_response(const SSL *ssl, const uint8_t **out, size_t *out_len) { - SSL_SESSION *session = ssl->session; + SSL_SESSION *session = SSL_get_session(ssl); *out_len = 0; *out = NULL; @@ -1514,31 +1650,35 @@ void SSL_get0_ocsp_response(const SSL *ssl, const uint8_t **out, *out_len = session->ocsp_response_length; } -int SSL_CTX_set_signed_cert_timestamp_list(SSL_CTX *ctx, const uint8_t *list, - size_t list_len) { - OPENSSL_free(ctx->signed_cert_timestamp_list); - ctx->signed_cert_timestamp_list_length = 0; +int SSL_set_tlsext_host_name(SSL *ssl, const char *name) { + OPENSSL_free(ssl->tlsext_hostname); + ssl->tlsext_hostname = NULL; - ctx->signed_cert_timestamp_list = BUF_memdup(list, list_len); - if (ctx->signed_cert_timestamp_list == NULL) { - return 0; + if (name == NULL) { + return 1; } - ctx->signed_cert_timestamp_list_length = list_len; + size_t len = strlen(name); + if (len == 0 || len > TLSEXT_MAXLEN_host_name) { + OPENSSL_PUT_ERROR(SSL, SSL_R_SSL3_EXT_INVALID_SERVERNAME); + return 0; + } + ssl->tlsext_hostname = BUF_strdup(name); + if (ssl->tlsext_hostname == NULL) { + OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + return 0; + } return 1; } -int SSL_CTX_set_ocsp_response(SSL_CTX *ctx, const uint8_t *response, - size_t response_len) { - OPENSSL_free(ctx->ocsp_response); - ctx->ocsp_response_length = 0; - - ctx->ocsp_response = BUF_memdup(response, response_len); - if (ctx->ocsp_response == NULL) { - return 0; - } - ctx->ocsp_response_length = response_len; +int SSL_CTX_set_tlsext_servername_callback( + SSL_CTX *ctx, int (*callback)(SSL *ssl, int *out_alert, void *arg)) { + ctx->tlsext_servername_callback = callback; + return 1; +} +int SSL_CTX_set_tlsext_servername_arg(SSL_CTX *ctx, void *arg) { + ctx->tlsext_servername_arg = arg; return 1; } @@ -1553,7 +1693,7 @@ int SSL_select_next_proto(uint8_t **out, uint8_t *out_len, for (i = 0; i < server_len;) { for (j = 0; j < client_len;) { if (server[i] == client[j] && - memcmp(&server[i + 1], &client[j + 1], server[i]) == 0) { + OPENSSL_memcmp(&server[i + 1], &client[j + 1], server[i]) == 0) { /* We found a match */ result = &server[i]; status = OPENSSL_NPN_NEGOTIATED; @@ -1647,100 +1787,83 @@ void SSL_get0_alpn_selected(const SSL *ssl, const uint8_t **out_data, } } -void SSL_CTX_set_cert_verify_callback(SSL_CTX *ctx, - int (*cb)(X509_STORE_CTX *store_ctx, - void *arg), - void *arg) { - ctx->app_verify_callback = cb; - ctx->app_verify_arg = arg; -} -void SSL_CTX_set_verify(SSL_CTX *ctx, int mode, - int (*cb)(int, X509_STORE_CTX *)) { - ctx->verify_mode = mode; - ctx->default_verify_callback = cb; +void SSL_CTX_set_tls_channel_id_enabled(SSL_CTX *ctx, int enabled) { + ctx->tlsext_channel_id_enabled = !!enabled; } -void SSL_CTX_set_verify_depth(SSL_CTX *ctx, int depth) { - X509_VERIFY_PARAM_set_depth(ctx->param, depth); +int SSL_CTX_enable_tls_channel_id(SSL_CTX *ctx) { + SSL_CTX_set_tls_channel_id_enabled(ctx, 1); + return 1; } -void SSL_CTX_set_cert_cb(SSL_CTX *ctx, int (*cb)(SSL *ssl, void *arg), - void *arg) { - ssl_cert_set_cert_cb(ctx->cert, cb, arg); +void SSL_set_tls_channel_id_enabled(SSL *ssl, int enabled) { + ssl->tlsext_channel_id_enabled = !!enabled; } -void SSL_set_cert_cb(SSL *ssl, int (*cb)(SSL *ssl, void *arg), void *arg) { - ssl_cert_set_cert_cb(ssl->cert, cb, arg); +int SSL_enable_tls_channel_id(SSL *ssl) { + SSL_set_tls_channel_id_enabled(ssl, 1); + return 1; } -void ssl_get_compatible_server_ciphers(SSL *ssl, uint32_t *out_mask_k, - uint32_t *out_mask_a) { - CERT *c = ssl->cert; - int have_rsa_cert = 0, dh_tmp; - uint32_t mask_k, mask_a; - int have_ecc_cert = 0, ecdsa_ok; - X509 *x; - - dh_tmp = (c->dh_tmp != NULL || c->dh_tmp_cb != NULL); +static int is_p256_key(EVP_PKEY *private_key) { + const EC_KEY *ec_key = EVP_PKEY_get0_EC_KEY(private_key); + return ec_key != NULL && + EC_GROUP_get_curve_name(EC_KEY_get0_group(ec_key)) == + NID_X9_62_prime256v1; +} - if (ssl->cert->x509 != NULL && ssl_has_private_key(ssl)) { - if (ssl_private_key_type(ssl) == EVP_PKEY_RSA) { - have_rsa_cert = 1; - } else if (ssl_private_key_type(ssl) == EVP_PKEY_EC) { - have_ecc_cert = 1; - } +int SSL_CTX_set1_tls_channel_id(SSL_CTX *ctx, EVP_PKEY *private_key) { + if (!is_p256_key(private_key)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_CHANNEL_ID_NOT_P256); + return 0; } - mask_k = 0; - mask_a = 0; + EVP_PKEY_free(ctx->tlsext_channel_id_private); + EVP_PKEY_up_ref(private_key); + ctx->tlsext_channel_id_private = private_key; + ctx->tlsext_channel_id_enabled = 1; - if (dh_tmp) { - mask_k |= SSL_kDHE; - } - if (have_rsa_cert) { - mask_k |= SSL_kRSA; - mask_a |= SSL_aRSA; - } + return 1; +} - /* An ECC certificate may be usable for ECDSA cipher suites depending on the - * key usage extension and on the client's curve preferences. */ - if (have_ecc_cert) { - x = c->x509; - /* This call populates extension flags (ex_flags). */ - X509_check_purpose(x, -1, 0); - ecdsa_ok = (x->ex_flags & EXFLAG_KUSAGE) - ? (x->ex_kusage & X509v3_KU_DIGITAL_SIGNATURE) - : 1; - if (!tls1_check_ec_cert(ssl, x)) { - ecdsa_ok = 0; - } - if (ecdsa_ok) { - mask_a |= SSL_aECDSA; - } +int SSL_set1_tls_channel_id(SSL *ssl, EVP_PKEY *private_key) { + if (!is_p256_key(private_key)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_CHANNEL_ID_NOT_P256); + return 0; } - /* If we are considering an ECC cipher suite that uses an ephemeral EC - * key, check for a shared curve. */ - uint16_t unused; - if (tls1_get_shared_curve(ssl, &unused)) { - mask_k |= SSL_kECDHE; - } + EVP_PKEY_free(ssl->tlsext_channel_id_private); + EVP_PKEY_up_ref(private_key); + ssl->tlsext_channel_id_private = private_key; + ssl->tlsext_channel_id_enabled = 1; - /* PSK requires a server callback. */ - if (ssl->psk_server_callback != NULL) { - mask_k |= SSL_kPSK; - mask_a |= SSL_aPSK; + return 1; +} + +size_t SSL_get_tls_channel_id(SSL *ssl, uint8_t *out, size_t max_out) { + if (!ssl->s3->tlsext_channel_id_valid) { + return 0; } + OPENSSL_memcpy(out, ssl->s3->tlsext_channel_id, + (max_out < 64) ? max_out : 64); + return 64; +} - *out_mask_k = mask_k; - *out_mask_a = mask_a; +size_t SSL_get0_certificate_types(SSL *ssl, const uint8_t **out_types) { + if (ssl->server || ssl->s3->hs == NULL) { + *out_types = NULL; + return 0; + } + *out_types = ssl->s3->hs->certificate_types; + return ssl->s3->hs->num_certificate_types; } -void ssl_update_cache(SSL *ssl, int mode) { +void ssl_update_cache(SSL_HANDSHAKE *hs, int mode) { + SSL *const ssl = hs->ssl; SSL_CTX *ctx = ssl->initial_ctx; /* Never cache sessions with empty session IDs. */ - if (ssl->session->session_id_length == 0 || + if (ssl->s3->established_session->session_id_length == 0 || (ctx->session_cache_mode & mode) != mode) { return; } @@ -1752,14 +1875,17 @@ void ssl_update_cache(SSL *ssl, int mode) { /* A client may see new sessions on abbreviated handshakes if the server * decides to renew the ticket. Once the handshake is completed, it should be * inserted into the cache. */ - if (!ssl->hit || (!ssl->server && ssl->tlsext_ticket_expected)) { + if (ssl->s3->established_session != ssl->session || + (!ssl->server && hs->ticket_expected)) { if (use_internal_cache) { - SSL_CTX_add_session(ctx, ssl->session); + SSL_CTX_add_session(ctx, ssl->s3->established_session); } - if (ctx->new_session_cb != NULL && - !ctx->new_session_cb(ssl, SSL_SESSION_up_ref(ssl->session))) { - /* |new_session_cb|'s return value signals whether it took ownership. */ - SSL_SESSION_free(ssl->session); + if (ctx->new_session_cb != NULL) { + SSL_SESSION_up_ref(ssl->s3->established_session); + if (!ctx->new_session_cb(ssl, ssl->s3->established_session)) { + /* |new_session_cb|'s return value signals whether it took ownership. */ + SSL_SESSION_free(ssl->s3->established_session); + } } } @@ -1773,16 +1899,22 @@ void ssl_update_cache(SSL *ssl, int mode) { flush_cache = 1; ctx->handshakes_since_cache_flush = 0; } - CRYPTO_MUTEX_unlock(&ctx->lock); + CRYPTO_MUTEX_unlock_write(&ctx->lock); if (flush_cache) { - SSL_CTX_flush_sessions(ctx, (unsigned long)time(NULL)); + struct timeval now; + ssl_get_current_time(ssl, &now); + SSL_CTX_flush_sessions(ctx, (long)now.tv_sec); } } } static const char *ssl_get_version(int version) { switch (version) { + /* Report TLS 1.3 draft version as TLS 1.3 in the public API. */ + case TLS1_3_DRAFT_VERSION: + return "TLSv1.3"; + case TLS1_2_VERSION: return "TLSv1.2"; @@ -1814,14 +1946,6 @@ const char *SSL_SESSION_get_version(const SSL_SESSION *session) { return ssl_get_version(session->ssl_version); } -X509 *SSL_get_certificate(const SSL *ssl) { - if (ssl->cert != NULL) { - return ssl->cert->x509; - } - - return NULL; -} - EVP_PKEY *SSL_get_privatekey(const SSL *ssl) { if (ssl->cert != NULL) { return ssl->cert->privatekey; @@ -1830,14 +1954,6 @@ EVP_PKEY *SSL_get_privatekey(const SSL *ssl) { return NULL; } -X509 *SSL_CTX_get0_certificate(const SSL_CTX *ctx) { - if (ctx->cert != NULL) { - return ctx->cert->x509; - } - - return NULL; -} - EVP_PKEY *SSL_CTX_get0_privatekey(const SSL_CTX *ctx) { if (ctx->cert != NULL) { return ctx->cert->privatekey; @@ -1853,58 +1969,15 @@ const SSL_CIPHER *SSL_get_current_cipher(const SSL *ssl) { return ssl->s3->aead_write_ctx->cipher; } -const COMP_METHOD *SSL_get_current_compression(SSL *ssl) { return NULL; } - -const COMP_METHOD *SSL_get_current_expansion(SSL *ssl) { return NULL; } - -int ssl_init_wbio_buffer(SSL *ssl, int push) { - BIO *bbio; - - if (ssl->bbio == NULL) { - bbio = BIO_new(BIO_f_buffer()); - if (bbio == NULL) { - return 0; - } - ssl->bbio = bbio; - } else { - bbio = ssl->bbio; - if (ssl->bbio == ssl->wbio) { - ssl->wbio = BIO_pop(ssl->wbio); - } - } - - BIO_reset(bbio); - if (!BIO_set_read_buffer_size(bbio, 1)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB); - return 0; - } - - if (push) { - if (ssl->wbio != bbio) { - ssl->wbio = BIO_push(bbio, ssl->wbio); - } - } else { - if (ssl->wbio == bbio) { - ssl->wbio = BIO_pop(bbio); - } - } - - return 1; +int SSL_session_reused(const SSL *ssl) { + return ssl->s3->session_reused; } -void ssl_free_wbio_buffer(SSL *ssl) { - if (ssl->bbio == NULL) { - return; - } +const COMP_METHOD *SSL_get_current_compression(SSL *ssl) { return NULL; } - if (ssl->bbio == ssl->wbio) { - /* remove buffering */ - ssl->wbio = BIO_pop(ssl->wbio); - } +const COMP_METHOD *SSL_get_current_expansion(SSL *ssl) { return NULL; } - BIO_free(ssl->bbio); - ssl->bbio = NULL; -} +int *SSL_get_server_tmp_key(SSL *ssl, EVP_PKEY **out_key) { return 0; } void SSL_CTX_set_quiet_shutdown(SSL_CTX *ctx, int mode) { ctx->quiet_shutdown = (mode != 0); @@ -1923,14 +1996,41 @@ int SSL_get_quiet_shutdown(const SSL *ssl) { return ssl->quiet_shutdown; } void SSL_set_shutdown(SSL *ssl, int mode) { /* It is an error to clear any bits that have already been set. (We can't try * to get a second close_notify or send two.) */ - assert((ssl->shutdown & mode) == ssl->shutdown); + assert((SSL_get_shutdown(ssl) & mode) == SSL_get_shutdown(ssl)); + + if (mode & SSL_RECEIVED_SHUTDOWN && + ssl->s3->recv_shutdown == ssl_shutdown_none) { + ssl->s3->recv_shutdown = ssl_shutdown_close_notify; + } - ssl->shutdown |= mode; + if (mode & SSL_SENT_SHUTDOWN && + ssl->s3->send_shutdown == ssl_shutdown_none) { + ssl->s3->send_shutdown = ssl_shutdown_close_notify; + } } -int SSL_get_shutdown(const SSL *ssl) { return ssl->shutdown; } +int SSL_get_shutdown(const SSL *ssl) { + int ret = 0; + if (ssl->s3->recv_shutdown != ssl_shutdown_none) { + /* Historically, OpenSSL set |SSL_RECEIVED_SHUTDOWN| on both close_notify + * and fatal alert. */ + ret |= SSL_RECEIVED_SHUTDOWN; + } + if (ssl->s3->send_shutdown == ssl_shutdown_close_notify) { + /* Historically, OpenSSL set |SSL_SENT_SHUTDOWN| on only close_notify. */ + ret |= SSL_SENT_SHUTDOWN; + } + return ret; +} -int SSL_version(const SSL *ssl) { return ssl->version; } +int SSL_version(const SSL *ssl) { + /* Report TLS 1.3 draft version as TLS 1.3 in the public API. */ + if (ssl->version == TLS1_3_DRAFT_VERSION) { + return TLS1_3_VERSION; + } + + return ssl->version; +} SSL_CTX *SSL_get_SSL_CTX(const SSL *ssl) { return ssl->ctx; } @@ -1939,6 +2039,12 @@ SSL_CTX *SSL_set_SSL_CTX(SSL *ssl, SSL_CTX *ctx) { return ssl->ctx; } + /* One cannot change the X.509 callbacks during a connection. */ + if (ssl->ctx->x509_method != ctx->x509_method) { + assert(0); + return NULL; + } + if (ctx == NULL) { ctx = ssl->initial_ctx; } @@ -1946,26 +2052,13 @@ SSL_CTX *SSL_set_SSL_CTX(SSL *ssl, SSL_CTX *ctx) { ssl_cert_free(ssl->cert); ssl->cert = ssl_cert_dup(ctx->cert); - CRYPTO_refcount_inc(&ctx->references); - SSL_CTX_free(ssl->ctx); /* decrement reference count */ + SSL_CTX_up_ref(ctx); + SSL_CTX_free(ssl->ctx); ssl->ctx = ctx; - ssl->sid_ctx_length = ctx->sid_ctx_length; - assert(ssl->sid_ctx_length <= sizeof(ssl->sid_ctx)); - memcpy(ssl->sid_ctx, ctx->sid_ctx, sizeof(ssl->sid_ctx)); - return ssl->ctx; } -int SSL_CTX_set_default_verify_paths(SSL_CTX *ctx) { - return X509_STORE_set_default_paths(ctx->cert_store); -} - -int SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *ca_file, - const char *ca_dir) { - return X509_STORE_load_locations(ctx->cert_store, ca_file, ca_dir); -} - void SSL_set_info_callback(SSL *ssl, void (*cb)(const SSL *ssl, int type, int value)) { ssl->info_callback = cb; @@ -1976,16 +2069,20 @@ void (*SSL_get_info_callback(const SSL *ssl))(const SSL *ssl, int type, return ssl->info_callback; } -int SSL_state(const SSL *ssl) { return ssl->state; } +int SSL_state(const SSL *ssl) { + return SSL_in_init(ssl) ? SSL_ST_INIT : SSL_ST_OK; +} void SSL_set_state(SSL *ssl, int state) { } -void SSL_set_verify_result(SSL *ssl, long result) { - ssl->verify_result = result; +char *SSL_get_shared_ciphers(const SSL *ssl, char *buf, int len) { + if (len <= 0) { + return NULL; + } + buf[0] = '\0'; + return buf; } -long SSL_get_verify_result(const SSL *ssl) { return ssl->verify_result; } - int SSL_get_ex_new_index(long argl, void *argp, CRYPTO_EX_unused *unused, CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func) { int index; @@ -2023,15 +2120,6 @@ void *SSL_CTX_get_ex_data(const SSL_CTX *ctx, int idx) { return CRYPTO_get_ex_data(&ctx->ex_data, idx); } -X509_STORE *SSL_CTX_get_cert_store(const SSL_CTX *ctx) { - return ctx->cert_store; -} - -void SSL_CTX_set_cert_store(SSL_CTX *ctx, X509_STORE *store) { - X509_STORE_free(ctx->cert_store); - ctx->cert_store = store; -} - int SSL_want(const SSL *ssl) { return ssl->rwstate; } void SSL_CTX_set_tmp_rsa_callback(SSL_CTX *ctx, @@ -2088,7 +2176,11 @@ int SSL_use_psk_identity_hint(SSL *ssl, const char *identity_hint) { OPENSSL_free(ssl->psk_identity_hint); ssl->psk_identity_hint = NULL; - if (identity_hint != NULL) { + /* Treat the empty hint as not supplying one. Plain PSK makes it possible to + * send either no hint (omit ServerKeyExchange) or an empty hint, while + * ECDHE_PSK can only spell empty hint. Having different capabilities is odd, + * so we interpret empty and missing as identical. */ + if (identity_hint != NULL && identity_hint[0] != '\0') { ssl->psk_identity_hint = BUF_strdup(identity_hint); if (ssl->psk_identity_hint == NULL) { return 0; @@ -2106,11 +2198,14 @@ const char *SSL_get_psk_identity_hint(const SSL *ssl) { } const char *SSL_get_psk_identity(const SSL *ssl) { - if (ssl == NULL || ssl->session == NULL) { + if (ssl == NULL) { return NULL; } - - return ssl->session->psk_identity; + SSL_SESSION *session = SSL_get_session(ssl); + if (session == NULL) { + return NULL; + } + return session->psk_identity; } void SSL_set_psk_client_callback( @@ -2166,16 +2261,26 @@ void SSL_CTX_set_keylog_callback(SSL_CTX *ctx, ctx->keylog_callback = cb; } +void (*SSL_CTX_get_keylog_callback(const SSL_CTX *ctx))(const SSL *ssl, + const char *line) { + return ctx->keylog_callback; +} + +void SSL_CTX_set_current_time_cb(SSL_CTX *ctx, + void (*cb)(const SSL *ssl, + struct timeval *out_clock)) { + ctx->current_time_cb = cb; +} + static int cbb_add_hex(CBB *cbb, const uint8_t *in, size_t in_len) { static const char hextable[] = "0123456789abcdef"; uint8_t *out; - size_t i; if (!CBB_add_space(cbb, &out, in_len * 2)) { return 0; } - for (i = 0; i < in_len; i++) { + for (size_t i = 0; i < in_len; i++) { *(out++) = (uint8_t)hextable[in[i] >> 4]; *(out++) = (uint8_t)hextable[in[i] & 0xf]; } @@ -2183,61 +2288,22 @@ static int cbb_add_hex(CBB *cbb, const uint8_t *in, size_t in_len) { return 1; } -int ssl_log_rsa_client_key_exchange(const SSL *ssl, - const uint8_t *encrypted_premaster, - size_t encrypted_premaster_len, - const uint8_t *premaster, - size_t premaster_len) { +int ssl_log_secret(const SSL *ssl, const char *label, const uint8_t *secret, + size_t secret_len) { if (ssl->ctx->keylog_callback == NULL) { return 1; } - if (encrypted_premaster_len < 8) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - return 0; - } - CBB cbb; uint8_t *out; size_t out_len; - if (!CBB_init(&cbb, 4 + 16 + 1 + premaster_len * 2 + 1) || - !CBB_add_bytes(&cbb, (const uint8_t *)"RSA ", 4) || - /* Only the first 8 bytes of the encrypted premaster secret are - * logged. */ - !cbb_add_hex(&cbb, encrypted_premaster, 8) || + if (!CBB_init(&cbb, strlen(label) + 1 + SSL3_RANDOM_SIZE * 2 + 1 + + secret_len * 2 + 1) || + !CBB_add_bytes(&cbb, (const uint8_t *)label, strlen(label)) || !CBB_add_bytes(&cbb, (const uint8_t *)" ", 1) || - !cbb_add_hex(&cbb, premaster, premaster_len) || - !CBB_add_u8(&cbb, 0 /* NUL */) || - !CBB_finish(&cbb, &out, &out_len)) { - CBB_cleanup(&cbb); - return 0; - } - - ssl->ctx->keylog_callback(ssl, (const char *)out); - OPENSSL_free(out); - return 1; -} - -int ssl_log_master_secret(const SSL *ssl, const uint8_t *client_random, - size_t client_random_len, const uint8_t *master, - size_t master_len) { - if (ssl->ctx->keylog_callback == NULL) { - return 1; - } - - if (client_random_len != 32) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - return 0; - } - - CBB cbb; - uint8_t *out; - size_t out_len; - if (!CBB_init(&cbb, 14 + 64 + 1 + master_len * 2 + 1) || - !CBB_add_bytes(&cbb, (const uint8_t *)"CLIENT_RANDOM ", 14) || - !cbb_add_hex(&cbb, client_random, 32) || + !cbb_add_hex(&cbb, ssl->s3->client_random, SSL3_RANDOM_SIZE) || !CBB_add_bytes(&cbb, (const uint8_t *)" ", 1) || - !cbb_add_hex(&cbb, master, master_len) || + !cbb_add_hex(&cbb, secret, secret_len) || !CBB_add_u8(&cbb, 0 /* NUL */) || !CBB_finish(&cbb, &out, &out_len)) { CBB_cleanup(&cbb); @@ -2250,15 +2316,19 @@ int ssl_log_master_secret(const SSL *ssl, const uint8_t *client_random, } int SSL_is_init_finished(const SSL *ssl) { - return ssl->state == SSL_ST_OK; + return !SSL_in_init(ssl); } int SSL_in_init(const SSL *ssl) { - return (ssl->state & SSL_ST_INIT) != 0; + SSL_HANDSHAKE *hs = ssl->s3->hs; + return hs != NULL && hs->state != SSL_ST_OK; } int SSL_in_false_start(const SSL *ssl) { - return ssl->s3->tmp.in_false_start; + if (ssl->s3->hs == NULL) { + return 0; + } + return ssl->s3->hs->in_false_start; } int SSL_cutthrough_complete(const SSL *ssl) { @@ -2276,115 +2346,50 @@ int ssl3_can_false_start(const SSL *ssl) { const SSL_CIPHER *const cipher = SSL_get_current_cipher(ssl); /* False Start only for TLS 1.2 with an ECDHE+AEAD cipher and ALPN or NPN. */ - return !SSL_IS_DTLS(ssl) && - SSL_version(ssl) >= TLS1_2_VERSION && - (ssl->s3->alpn_selected || ssl->s3->next_proto_neg_seen) && + return !SSL_is_dtls(ssl) && + SSL_version(ssl) == TLS1_2_VERSION && + (ssl->s3->alpn_selected != NULL || + ssl->s3->next_proto_negotiated != NULL) && cipher != NULL && cipher->algorithm_mkey == SSL_kECDHE && cipher->algorithm_mac == SSL_AEAD; } -const SSL3_ENC_METHOD *ssl3_get_enc_method(uint16_t version) { - switch (version) { - case SSL3_VERSION: - return &SSLv3_enc_data; - - case TLS1_VERSION: - case TLS1_1_VERSION: - case TLS1_2_VERSION: - case DTLS1_VERSION: - case DTLS1_2_VERSION: - return &TLSv1_enc_data; +const struct { + uint16_t version; + uint32_t flag; +} kVersions[] = { + {SSL3_VERSION, SSL_OP_NO_SSLv3}, + {TLS1_VERSION, SSL_OP_NO_TLSv1}, + {TLS1_1_VERSION, SSL_OP_NO_TLSv1_1}, + {TLS1_2_VERSION, SSL_OP_NO_TLSv1_2}, + {TLS1_3_VERSION, SSL_OP_NO_TLSv1_3}, +}; - default: - return NULL; - } -} +static const size_t kVersionsLen = OPENSSL_ARRAY_SIZE(kVersions); -uint16_t ssl3_get_max_server_version(const SSL *ssl) { - uint16_t max_version; - - if (SSL_IS_DTLS(ssl)) { - max_version = (ssl->max_version != 0) ? ssl->max_version : DTLS1_2_VERSION; - if (!(ssl->options & SSL_OP_NO_DTLSv1_2) && - DTLS1_2_VERSION >= max_version) { - return DTLS1_2_VERSION; - } - if (!(ssl->options & SSL_OP_NO_DTLSv1) && DTLS1_VERSION >= max_version) { - return DTLS1_VERSION; +int ssl_get_version_range(const SSL *ssl, uint16_t *out_min_version, + uint16_t *out_max_version) { + /* For historical reasons, |SSL_OP_NO_DTLSv1| aliases |SSL_OP_NO_TLSv1|, but + * DTLS 1.0 should be mapped to TLS 1.1. */ + uint32_t options = ssl->options; + if (SSL_is_dtls(ssl)) { + options &= ~SSL_OP_NO_TLSv1_1; + if (options & SSL_OP_NO_DTLSv1) { + options |= SSL_OP_NO_TLSv1_1; } - return 0; - } - - max_version = (ssl->max_version != 0) ? ssl->max_version : TLS1_2_VERSION; - if (!(ssl->options & SSL_OP_NO_TLSv1_2) && TLS1_2_VERSION <= max_version) { - return TLS1_2_VERSION; - } - if (!(ssl->options & SSL_OP_NO_TLSv1_1) && TLS1_1_VERSION <= max_version) { - return TLS1_1_VERSION; - } - if (!(ssl->options & SSL_OP_NO_TLSv1) && TLS1_VERSION <= max_version) { - return TLS1_VERSION; } - if (!(ssl->options & SSL_OP_NO_SSLv3) && SSL3_VERSION <= max_version) { - return SSL3_VERSION; - } - return 0; -} - -uint16_t ssl3_get_mutual_version(SSL *ssl, uint16_t client_version) { - uint16_t version = 0; - - if (SSL_IS_DTLS(ssl)) { - /* Clamp client_version to max_version. */ - if (ssl->max_version != 0 && client_version < ssl->max_version) { - client_version = ssl->max_version; - } - if (client_version <= DTLS1_2_VERSION && - !(ssl->options & SSL_OP_NO_DTLSv1_2)) { - version = DTLS1_2_VERSION; - } else if (client_version <= DTLS1_VERSION && - !(ssl->options & SSL_OP_NO_DTLSv1)) { - version = DTLS1_VERSION; - } + uint16_t min_version = ssl->min_version; + uint16_t max_version = ssl->max_version; - /* Check against min_version. */ - if (version != 0 && ssl->min_version != 0 && version > ssl->min_version) { - return 0; - } - return version; - } else { - /* Clamp client_version to max_version. */ - if (ssl->max_version != 0 && client_version > ssl->max_version) { - client_version = ssl->max_version; - } - - if (client_version >= TLS1_2_VERSION && - !(ssl->options & SSL_OP_NO_TLSv1_2)) { - version = TLS1_2_VERSION; - } else if (client_version >= TLS1_1_VERSION && - !(ssl->options & SSL_OP_NO_TLSv1_1)) { - version = TLS1_1_VERSION; - } else if (client_version >= TLS1_VERSION && - !(ssl->options & SSL_OP_NO_TLSv1)) { - version = TLS1_VERSION; - } else if (client_version >= SSL3_VERSION && - !(ssl->options & SSL_OP_NO_SSLv3)) { - version = SSL3_VERSION; - } - - /* Check against min_version. */ - if (version != 0 && ssl->min_version != 0 && version < ssl->min_version) { - return 0; - } - return version; + /* Bound the range to only those implemented in this protocol. */ + if (min_version < ssl->method->min_version) { + min_version = ssl->method->min_version; + } + if (max_version > ssl->method->max_version) { + max_version = ssl->method->max_version; } -} - -uint16_t ssl3_get_max_client_version(SSL *ssl) { - uint32_t options = ssl->options; - uint16_t version = 0; /* OpenSSL's API for controlling versions entails blacklisting individual * protocols. This has two problems. First, on the client, the protocol can @@ -2395,124 +2400,68 @@ uint16_t ssl3_get_max_client_version(SSL *ssl) { * To account for both of these, OpenSSL interprets the client-side bitmask * as a min/max range by picking the lowest contiguous non-empty range of * enabled protocols. Note that this means it is impossible to set a maximum - * version of TLS 1.2 in a future-proof way. - * - * By this scheme, the maximum version is the lowest version V such that V is - * enabled and V+1 is disabled or unimplemented. */ - if (SSL_IS_DTLS(ssl)) { - if (!(options & SSL_OP_NO_DTLSv1_2)) { - version = DTLS1_2_VERSION; - } - if (!(options & SSL_OP_NO_DTLSv1) && (options & SSL_OP_NO_DTLSv1_2)) { - version = DTLS1_VERSION; - } - if (ssl->max_version != 0 && version < ssl->max_version) { - version = ssl->max_version; - } - } else { - if (!(options & SSL_OP_NO_TLSv1_2)) { - version = TLS1_2_VERSION; - } - if (!(options & SSL_OP_NO_TLSv1_1) && (options & SSL_OP_NO_TLSv1_2)) { - version = TLS1_1_VERSION; - } - if (!(options & SSL_OP_NO_TLSv1) && (options & SSL_OP_NO_TLSv1_1)) { - version = TLS1_VERSION; - } - if (!(options & SSL_OP_NO_SSLv3) && (options & SSL_OP_NO_TLSv1)) { - version = SSL3_VERSION; - } - if (ssl->max_version != 0 && version > ssl->max_version) { - version = ssl->max_version; - } - } - - return version; -} - -int ssl3_is_version_enabled(SSL *ssl, uint16_t version) { - if (SSL_IS_DTLS(ssl)) { - if (ssl->max_version != 0 && version < ssl->max_version) { - return 0; + * version of the higest supported TLS version in a future-proof way. */ + int any_enabled = 0; + for (size_t i = 0; i < kVersionsLen; i++) { + /* Only look at the versions already enabled. */ + if (min_version > kVersions[i].version) { + continue; } - if (ssl->min_version != 0 && version > ssl->min_version) { - return 0; + if (max_version < kVersions[i].version) { + break; } - switch (version) { - case DTLS1_VERSION: - return !(ssl->options & SSL_OP_NO_DTLSv1); - - case DTLS1_2_VERSION: - return !(ssl->options & SSL_OP_NO_DTLSv1_2); - - default: - return 0; - } - } else { - if (ssl->max_version != 0 && version > ssl->max_version) { - return 0; - } - if (ssl->min_version != 0 && version < ssl->min_version) { - return 0; + if (!(options & kVersions[i].flag)) { + /* The minimum version is the first enabled version. */ + if (!any_enabled) { + any_enabled = 1; + min_version = kVersions[i].version; + } + continue; } - switch (version) { - case SSL3_VERSION: - return !(ssl->options & SSL_OP_NO_SSLv3); - - case TLS1_VERSION: - return !(ssl->options & SSL_OP_NO_TLSv1); - - case TLS1_1_VERSION: - return !(ssl->options & SSL_OP_NO_TLSv1_1); - - case TLS1_2_VERSION: - return !(ssl->options & SSL_OP_NO_TLSv1_2); - - default: - return 0; + /* If there is a disabled version after the first enabled one, all versions + * after it are implicitly disabled. */ + if (any_enabled) { + max_version = kVersions[i-1].version; + break; } } -} -uint16_t ssl3_version_from_wire(const SSL *ssl, uint16_t wire_version) { - if (!SSL_IS_DTLS(ssl)) { - return wire_version; + if (!any_enabled) { + OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_SSL_VERSION); + return 0; } - uint16_t tls_version = ~wire_version; - uint16_t version = tls_version + 0x0201; - /* If either component overflowed, clamp it so comparisons still work. */ - if ((version >> 8) < (tls_version >> 8)) { - version = 0xff00 | (version & 0xff); - } - if ((version & 0xff) < (tls_version & 0xff)) { - version = (version & 0xff00) | 0xff; - } - /* DTLS 1.0 maps to TLS 1.1, not TLS 1.0. */ - if (version == TLS1_VERSION) { - version = TLS1_1_VERSION; - } - return version; + *out_min_version = min_version; + *out_max_version = max_version; + return 1; } uint16_t ssl3_protocol_version(const SSL *ssl) { assert(ssl->s3->have_version); - return ssl3_version_from_wire(ssl, ssl->version); + uint16_t version; + if (!ssl->method->version_from_wire(&version, ssl->version)) { + /* TODO(davidben): Use the internal version representation for ssl->version + * and map to the public API representation at API boundaries. */ + assert(0); + return 0; + } + + return version; } -int SSL_cache_hit(SSL *ssl) { return SSL_session_reused(ssl); } +int SSL_is_server(const SSL *ssl) { return ssl->server; } -int SSL_is_server(SSL *ssl) { return ssl->server; } +int SSL_is_dtls(const SSL *ssl) { return ssl->method->is_dtls; } -void SSL_CTX_set_select_certificate_cb( - SSL_CTX *ctx, int (*cb)(const struct ssl_early_callback_ctx *)) { +void SSL_CTX_set_select_certificate_cb(SSL_CTX *ctx, + int (*cb)(const SSL_CLIENT_HELLO *)) { ctx->select_certificate_cb = cb; } -void SSL_CTX_set_dos_protection_cb( - SSL_CTX *ctx, int (*cb)(const struct ssl_early_callback_ctx *)) { +void SSL_CTX_set_dos_protection_cb(SSL_CTX *ctx, + int (*cb)(const SSL_CLIENT_HELLO *)) { ctx->dos_protection_cb = cb; } @@ -2520,21 +2469,6 @@ void SSL_set_renegotiate_mode(SSL *ssl, enum ssl_renegotiate_mode_t mode) { ssl->renegotiate_mode = mode; } -void SSL_set_reject_peer_renegotiations(SSL *ssl, int reject) { - SSL_set_renegotiate_mode( - ssl, reject ? ssl_renegotiate_never : ssl_renegotiate_freely); -} - -int SSL_get_rc4_state(const SSL *ssl, const RC4_KEY **read_key, - const RC4_KEY **write_key) { - if (ssl->s3->aead_read_ctx == NULL || ssl->s3->aead_write_ctx == NULL) { - return 0; - } - - return EVP_AEAD_CTX_get_rc4_state(&ssl->s3->aead_read_ctx->ctx, read_key) && - EVP_AEAD_CTX_get_rc4_state(&ssl->s3->aead_write_ctx->ctx, write_key); -} - int SSL_get_ivs(const SSL *ssl, const uint8_t **out_read_iv, const uint8_t **out_write_iv, size_t *out_iv_len) { if (ssl->s3->aead_read_ctx == NULL || ssl->s3->aead_write_ctx == NULL) { @@ -2562,7 +2496,7 @@ static uint64_t be_to_u64(const uint8_t in[8]) { uint64_t SSL_get_read_sequence(const SSL *ssl) { /* TODO(davidben): Internally represent sequence numbers as uint64_t. */ - if (SSL_IS_DTLS(ssl)) { + if (SSL_is_dtls(ssl)) { /* max_seq_num already includes the epoch. */ assert(ssl->d1->r_epoch == (ssl->d1->bitmap.max_seq_num >> 48)); return ssl->d1->bitmap.max_seq_num; @@ -2572,15 +2506,22 @@ uint64_t SSL_get_read_sequence(const SSL *ssl) { uint64_t SSL_get_write_sequence(const SSL *ssl) { uint64_t ret = be_to_u64(ssl->s3->write_sequence); - if (SSL_IS_DTLS(ssl)) { + if (SSL_is_dtls(ssl)) { assert((ret >> 48) == 0); ret |= ((uint64_t)ssl->d1->w_epoch) << 48; } return ret; } -uint8_t SSL_get_server_key_exchange_hash(const SSL *ssl) { - return ssl->s3->tmp.server_key_exchange_hash; +uint16_t SSL_get_peer_signature_algorithm(const SSL *ssl) { + /* TODO(davidben): This checks the wrong session if there is a renegotiation + * in progress. */ + SSL_SESSION *session = SSL_get_session(ssl); + if (session == NULL) { + return 0; + } + + return session->peer_signature_algorithm; } size_t SSL_get_client_random(const SSL *ssl, uint8_t *out, size_t max_out) { @@ -2590,7 +2531,7 @@ size_t SSL_get_client_random(const SSL *ssl, uint8_t *out, size_t max_out) { if (max_out > sizeof(ssl->s3->client_random)) { max_out = sizeof(ssl->s3->client_random); } - memcpy(out, ssl->s3->client_random, max_out); + OPENSSL_memcpy(out, ssl->s3->client_random, max_out); return max_out; } @@ -2601,46 +2542,42 @@ size_t SSL_get_server_random(const SSL *ssl, uint8_t *out, size_t max_out) { if (max_out > sizeof(ssl->s3->server_random)) { max_out = sizeof(ssl->s3->server_random); } - memcpy(out, ssl->s3->server_random, max_out); + OPENSSL_memcpy(out, ssl->s3->server_random, max_out); return max_out; } const SSL_CIPHER *SSL_get_pending_cipher(const SSL *ssl) { - if (!SSL_in_init(ssl)) { + SSL_HANDSHAKE *hs = ssl->s3->hs; + if (hs == NULL) { return NULL; } - return ssl->s3->tmp.new_cipher; + return hs->new_cipher; +} + +void SSL_set_retain_only_sha256_of_client_certs(SSL *ssl, int enabled) { + ssl->retain_only_sha256_of_client_certs = !!enabled; } void SSL_CTX_set_retain_only_sha256_of_client_certs(SSL_CTX *ctx, int enabled) { ctx->retain_only_sha256_of_client_certs = !!enabled; } -int SSL_clear(SSL *ssl) { - if (ssl->method == NULL) { - OPENSSL_PUT_ERROR(SSL, SSL_R_NO_METHOD_SPECIFIED); - return 0; - } - - if (ssl_clear_bad_session(ssl)) { - SSL_SESSION_free(ssl->session); - ssl->session = NULL; - } +void SSL_CTX_set_grease_enabled(SSL_CTX *ctx, int enabled) { + ctx->grease_enabled = !!enabled; +} - ssl->hit = 0; - ssl->shutdown = 0; +void SSL_CTX_set_short_header_enabled(SSL_CTX *ctx, int enabled) { + ctx->short_header_enabled = !!enabled; +} - /* SSL_clear may be called before or after the |ssl| is initialized in either - * accept or connect state. In the latter case, SSL_clear should preserve the - * half and reset |ssl->state| accordingly. */ - if (ssl->handshake_func != NULL) { - if (ssl->server) { - SSL_set_accept_state(ssl); - } else { - SSL_set_connect_state(ssl); - } - } else { - assert(ssl->state == 0); +int SSL_clear(SSL *ssl) { + /* In OpenSSL, reusing a client |SSL| with |SSL_clear| causes the previously + * established session to be offered the next time around. wpa_supplicant + * depends on this behavior, so emulate it. */ + SSL_SESSION *session = NULL; + if (!ssl->server && ssl->s3->established_session != NULL) { + session = ssl->s3->established_session; + SSL_SESSION_up_ref(session); } /* TODO(davidben): Some state on |ssl| is reset both in |SSL_new| and @@ -2653,6 +2590,8 @@ int SSL_clear(SSL *ssl) { BUF_MEM_free(ssl->init_buf); ssl->init_buf = NULL; + ssl->init_msg = NULL; + ssl->init_num = 0; /* The ssl->d1->mtu is simultaneously configuration (preserved across * clear) and connection-specific state (gets reset). @@ -2665,18 +2604,60 @@ int SSL_clear(SSL *ssl) { ssl->method->ssl_free(ssl); if (!ssl->method->ssl_new(ssl)) { + SSL_SESSION_free(session); return 0; } - if (SSL_IS_DTLS(ssl) && (SSL_get_options(ssl) & SSL_OP_NO_QUERY_MTU)) { + if (SSL_is_dtls(ssl) && (SSL_get_options(ssl) & SSL_OP_NO_QUERY_MTU)) { ssl->d1->mtu = mtu; } - ssl->client_version = ssl->version; + if (session != NULL) { + SSL_set_session(ssl, session); + SSL_SESSION_free(session); + } return 1; } +void ssl_do_info_callback(const SSL *ssl, int type, int value) { + void (*cb)(const SSL *ssl, int type, int value) = NULL; + if (ssl->info_callback != NULL) { + cb = ssl->info_callback; + } else if (ssl->ctx->info_callback != NULL) { + cb = ssl->ctx->info_callback; + } + + if (cb != NULL) { + cb(ssl, type, value); + } +} + +void ssl_do_msg_callback(SSL *ssl, int is_write, int content_type, + const void *buf, size_t len) { + if (ssl->msg_callback == NULL) { + return; + } + + /* |version| is zero when calling for |SSL3_RT_HEADER| and |SSL2_VERSION| for + * a V2ClientHello. */ + int version; + switch (content_type) { + case 0: + /* V2ClientHello */ + version = SSL2_VERSION; + break; + case SSL3_RT_HEADER: + version = 0; + break; + default: + version = SSL_version(ssl); + } + + ssl->msg_callback(is_write, version, content_type, buf, len, ssl, + ssl->msg_callback_arg); +} + int SSL_CTX_sess_connect(const SSL_CTX *ctx) { return 0; } int SSL_CTX_sess_connect_good(const SSL_CTX *ctx) { return 0; } int SSL_CTX_sess_connect_renegotiate(const SSL_CTX *ctx) { return 0; } @@ -2688,5 +2669,68 @@ int SSL_CTX_sess_cb_hits(const SSL_CTX *ctx) { return 0; } int SSL_CTX_sess_misses(const SSL_CTX *ctx) { return 0; } int SSL_CTX_sess_timeouts(const SSL_CTX *ctx) { return 0; } int SSL_CTX_sess_cache_full(const SSL_CTX *ctx) { return 0; } + +int SSL_num_renegotiations(const SSL *ssl) { + return SSL_total_renegotiations(ssl); +} + +int SSL_CTX_need_tmp_RSA(const SSL_CTX *ctx) { return 0; } +int SSL_need_tmp_RSA(const SSL *ssl) { return 0; } +int SSL_CTX_set_tmp_rsa(SSL_CTX *ctx, const RSA *rsa) { return 1; } +int SSL_set_tmp_rsa(SSL *ssl, const RSA *rsa) { return 1; } void ERR_load_SSL_strings(void) {} void SSL_load_error_strings(void) {} +int SSL_cache_hit(SSL *ssl) { return SSL_session_reused(ssl); } + +int SSL_CTX_set_tmp_ecdh(SSL_CTX *ctx, const EC_KEY *ec_key) { + if (ec_key == NULL || EC_KEY_get0_group(ec_key) == NULL) { + OPENSSL_PUT_ERROR(SSL, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + int nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec_key)); + return SSL_CTX_set1_curves(ctx, &nid, 1); +} + +int SSL_set_tmp_ecdh(SSL *ssl, const EC_KEY *ec_key) { + if (ec_key == NULL || EC_KEY_get0_group(ec_key) == NULL) { + OPENSSL_PUT_ERROR(SSL, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + int nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec_key)); + return SSL_set1_curves(ssl, &nid, 1); +} + +void ssl_get_current_time(const SSL *ssl, struct timeval *out_clock) { + if (ssl->ctx->current_time_cb != NULL) { + ssl->ctx->current_time_cb(ssl, out_clock); + return; + } + +#if defined(BORINGSSL_UNSAFE_DETERMINISTIC_MODE) + out_clock->tv_sec = 1234; + out_clock->tv_usec = 1234; +#elif defined(OPENSSL_WINDOWS) + struct _timeb time; + _ftime(&time); + out_clock->tv_sec = time.time; + out_clock->tv_usec = time.millitm * 1000; +#else + gettimeofday(out_clock, NULL); +#endif +} + +int SSL_CTX_set_min_version(SSL_CTX *ctx, uint16_t version) { + return SSL_CTX_set_min_proto_version(ctx, version); +} + +int SSL_CTX_set_max_version(SSL_CTX *ctx, uint16_t version) { + return SSL_CTX_set_max_proto_version(ctx, version); +} + +int SSL_set_min_version(SSL *ssl, uint16_t version) { + return SSL_set_min_proto_version(ssl, version); +} + +int SSL_set_max_version(SSL *ssl, uint16_t version) { + return SSL_set_max_proto_version(ssl, version); +} diff --git a/Sources/BoringSSL/ssl/ssl_privkey.c b/Sources/BoringSSL/ssl/ssl_privkey.c new file mode 100644 index 000000000..79622473d --- /dev/null +++ b/Sources/BoringSSL/ssl/ssl_privkey.c @@ -0,0 +1,683 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "internal.h" + + +int ssl_is_key_type_supported(int key_type) { + return key_type == EVP_PKEY_RSA || key_type == EVP_PKEY_EC; +} + +static int ssl_set_pkey(CERT *cert, EVP_PKEY *pkey) { + if (!ssl_is_key_type_supported(pkey->type)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_CERTIFICATE_TYPE); + return 0; + } + + if (cert->chain != NULL && + sk_CRYPTO_BUFFER_value(cert->chain, 0) != NULL && + /* Sanity-check that the private key and the certificate match, unless + * the key is opaque (in case of, say, a smartcard). */ + !EVP_PKEY_is_opaque(pkey) && + !ssl_cert_check_private_key(cert, pkey)) { + return 0; + } + + EVP_PKEY_free(cert->privatekey); + EVP_PKEY_up_ref(pkey); + cert->privatekey = pkey; + + return 1; +} + +int SSL_use_RSAPrivateKey(SSL *ssl, RSA *rsa) { + EVP_PKEY *pkey; + int ret; + + if (rsa == NULL) { + OPENSSL_PUT_ERROR(SSL, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + + pkey = EVP_PKEY_new(); + if (pkey == NULL) { + OPENSSL_PUT_ERROR(SSL, ERR_R_EVP_LIB); + return 0; + } + + RSA_up_ref(rsa); + EVP_PKEY_assign_RSA(pkey, rsa); + + ret = ssl_set_pkey(ssl->cert, pkey); + EVP_PKEY_free(pkey); + + return ret; +} + +int SSL_use_PrivateKey(SSL *ssl, EVP_PKEY *pkey) { + if (pkey == NULL) { + OPENSSL_PUT_ERROR(SSL, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + + return ssl_set_pkey(ssl->cert, pkey); +} + +int SSL_use_PrivateKey_ASN1(int type, SSL *ssl, const uint8_t *der, + size_t der_len) { + if (der_len > LONG_MAX) { + OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW); + return 0; + } + + const uint8_t *p = der; + EVP_PKEY *pkey = d2i_PrivateKey(type, NULL, &p, (long)der_len); + if (pkey == NULL || p != der + der_len) { + OPENSSL_PUT_ERROR(SSL, ERR_R_ASN1_LIB); + EVP_PKEY_free(pkey); + return 0; + } + + int ret = SSL_use_PrivateKey(ssl, pkey); + EVP_PKEY_free(pkey); + return ret; +} + +int SSL_CTX_use_RSAPrivateKey(SSL_CTX *ctx, RSA *rsa) { + int ret; + EVP_PKEY *pkey; + + if (rsa == NULL) { + OPENSSL_PUT_ERROR(SSL, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + + pkey = EVP_PKEY_new(); + if (pkey == NULL) { + OPENSSL_PUT_ERROR(SSL, ERR_R_EVP_LIB); + return 0; + } + + RSA_up_ref(rsa); + EVP_PKEY_assign_RSA(pkey, rsa); + + ret = ssl_set_pkey(ctx->cert, pkey); + EVP_PKEY_free(pkey); + return ret; +} + +int SSL_CTX_use_RSAPrivateKey_ASN1(SSL_CTX *ctx, const uint8_t *der, + size_t der_len) { + RSA *rsa = RSA_private_key_from_bytes(der, der_len); + if (rsa == NULL) { + OPENSSL_PUT_ERROR(SSL, ERR_R_ASN1_LIB); + return 0; + } + + int ret = SSL_CTX_use_RSAPrivateKey(ctx, rsa); + RSA_free(rsa); + return ret; +} + +int SSL_CTX_use_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey) { + if (pkey == NULL) { + OPENSSL_PUT_ERROR(SSL, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + + return ssl_set_pkey(ctx->cert, pkey); +} + +int SSL_CTX_use_PrivateKey_ASN1(int type, SSL_CTX *ctx, const uint8_t *der, + size_t der_len) { + if (der_len > LONG_MAX) { + OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW); + return 0; + } + + const uint8_t *p = der; + EVP_PKEY *pkey = d2i_PrivateKey(type, NULL, &p, (long)der_len); + if (pkey == NULL || p != der + der_len) { + OPENSSL_PUT_ERROR(SSL, ERR_R_ASN1_LIB); + EVP_PKEY_free(pkey); + return 0; + } + + int ret = SSL_CTX_use_PrivateKey(ctx, pkey); + EVP_PKEY_free(pkey); + return ret; +} + +void SSL_set_private_key_method(SSL *ssl, + const SSL_PRIVATE_KEY_METHOD *key_method) { + ssl->cert->key_method = key_method; +} + +void SSL_CTX_set_private_key_method(SSL_CTX *ctx, + const SSL_PRIVATE_KEY_METHOD *key_method) { + ctx->cert->key_method = key_method; +} + +static int set_signing_algorithm_prefs(CERT *cert, const uint16_t *prefs, + size_t num_prefs) { + OPENSSL_free(cert->sigalgs); + + cert->num_sigalgs = 0; + cert->sigalgs = BUF_memdup(prefs, num_prefs * sizeof(prefs[0])); + if (cert->sigalgs == NULL) { + OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + return 0; + } + cert->num_sigalgs = num_prefs; + + return 1; +} + +int SSL_CTX_set_signing_algorithm_prefs(SSL_CTX *ctx, const uint16_t *prefs, + size_t num_prefs) { + return set_signing_algorithm_prefs(ctx->cert, prefs, num_prefs); +} + + +int SSL_set_signing_algorithm_prefs(SSL *ssl, const uint16_t *prefs, + size_t num_prefs) { + return set_signing_algorithm_prefs(ssl->cert, prefs, num_prefs); +} + +int SSL_set_private_key_digest_prefs(SSL *ssl, const int *digest_nids, + size_t num_digests) { + OPENSSL_free(ssl->cert->sigalgs); + + OPENSSL_COMPILE_ASSERT(sizeof(int) >= 2 * sizeof(uint16_t), + digest_list_conversion_cannot_overflow); + + ssl->cert->num_sigalgs = 0; + ssl->cert->sigalgs = OPENSSL_malloc(sizeof(uint16_t) * 2 * num_digests); + if (ssl->cert->sigalgs == NULL) { + OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + return 0; + } + + /* Convert the digest list to a signature algorithms list. + * + * TODO(davidben): Replace this API with one that can express RSA-PSS, etc. */ + for (size_t i = 0; i < num_digests; i++) { + switch (digest_nids[i]) { + case NID_sha1: + ssl->cert->sigalgs[ssl->cert->num_sigalgs] = SSL_SIGN_RSA_PKCS1_SHA1; + ssl->cert->sigalgs[ssl->cert->num_sigalgs + 1] = SSL_SIGN_ECDSA_SHA1; + ssl->cert->num_sigalgs += 2; + break; + case NID_sha256: + ssl->cert->sigalgs[ssl->cert->num_sigalgs] = SSL_SIGN_RSA_PKCS1_SHA256; + ssl->cert->sigalgs[ssl->cert->num_sigalgs + 1] = + SSL_SIGN_ECDSA_SECP256R1_SHA256; + ssl->cert->num_sigalgs += 2; + break; + case NID_sha384: + ssl->cert->sigalgs[ssl->cert->num_sigalgs] = SSL_SIGN_RSA_PKCS1_SHA384; + ssl->cert->sigalgs[ssl->cert->num_sigalgs + 1] = + SSL_SIGN_ECDSA_SECP384R1_SHA384; + ssl->cert->num_sigalgs += 2; + break; + case NID_sha512: + ssl->cert->sigalgs[ssl->cert->num_sigalgs] = SSL_SIGN_RSA_PKCS1_SHA512; + ssl->cert->sigalgs[ssl->cert->num_sigalgs + 1] = + SSL_SIGN_ECDSA_SECP521R1_SHA512; + ssl->cert->num_sigalgs += 2; + break; + } + } + + return 1; +} + +int ssl_has_private_key(const SSL *ssl) { + return ssl->cert->privatekey != NULL || ssl->cert->key_method != NULL; +} + +int ssl_is_ecdsa_key_type(int type) { + switch (type) { + /* TODO(davidben): Remove support for |EVP_PKEY_EC| key types. */ + case EVP_PKEY_EC: + case NID_X9_62_prime256v1: + case NID_secp384r1: + case NID_secp521r1: + return 1; + default: + return 0; + } +} + +int ssl_private_key_type(SSL *ssl) { + if (ssl->cert->key_method != NULL) { + return ssl->cert->key_method->type(ssl); + } + switch (EVP_PKEY_id(ssl->cert->privatekey)) { + case EVP_PKEY_RSA: + return NID_rsaEncryption; + case EVP_PKEY_EC: + return EC_GROUP_get_curve_name( + EC_KEY_get0_group(EVP_PKEY_get0_EC_KEY(ssl->cert->privatekey))); + default: + return NID_undef; + } +} + +size_t ssl_private_key_max_signature_len(SSL *ssl) { + if (ssl->cert->key_method != NULL) { + return ssl->cert->key_method->max_signature_len(ssl); + } + return EVP_PKEY_size(ssl->cert->privatekey); +} + +/* TODO(davidben): Forbid RSA-PKCS1 in TLS 1.3. For now we allow it because NSS + * has yet to start doing RSA-PSS, so enforcing it would complicate interop + * testing. */ +static int is_rsa_pkcs1(const EVP_MD **out_md, uint16_t sigalg) { + switch (sigalg) { + case SSL_SIGN_RSA_PKCS1_MD5_SHA1: + *out_md = EVP_md5_sha1(); + return 1; + case SSL_SIGN_RSA_PKCS1_SHA1: + *out_md = EVP_sha1(); + return 1; + case SSL_SIGN_RSA_PKCS1_SHA256: + *out_md = EVP_sha256(); + return 1; + case SSL_SIGN_RSA_PKCS1_SHA384: + *out_md = EVP_sha384(); + return 1; + case SSL_SIGN_RSA_PKCS1_SHA512: + *out_md = EVP_sha512(); + return 1; + default: + return 0; + } +} + +static int ssl_sign_rsa_pkcs1(SSL *ssl, uint8_t *out, size_t *out_len, + size_t max_out, const EVP_MD *md, + const uint8_t *in, size_t in_len) { + EVP_MD_CTX ctx; + EVP_MD_CTX_init(&ctx); + *out_len = max_out; + int ret = EVP_DigestSignInit(&ctx, NULL, md, NULL, ssl->cert->privatekey) && + EVP_DigestSignUpdate(&ctx, in, in_len) && + EVP_DigestSignFinal(&ctx, out, out_len); + EVP_MD_CTX_cleanup(&ctx); + return ret; +} + +static int ssl_verify_rsa_pkcs1(SSL *ssl, const uint8_t *signature, + size_t signature_len, const EVP_MD *md, + EVP_PKEY *pkey, const uint8_t *in, + size_t in_len) { + if (pkey->type != EVP_PKEY_RSA) { + OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_SIGNATURE_TYPE); + return 0; + } + + EVP_MD_CTX md_ctx; + EVP_MD_CTX_init(&md_ctx); + int ret = EVP_DigestVerifyInit(&md_ctx, NULL, md, NULL, pkey) && + EVP_DigestVerifyUpdate(&md_ctx, in, in_len) && + EVP_DigestVerifyFinal(&md_ctx, signature, signature_len); + EVP_MD_CTX_cleanup(&md_ctx); + return ret; +} + +static int is_ecdsa(int *out_curve, const EVP_MD **out_md, uint16_t sigalg) { + switch (sigalg) { + case SSL_SIGN_ECDSA_SHA1: + *out_curve = NID_undef; + *out_md = EVP_sha1(); + return 1; + case SSL_SIGN_ECDSA_SECP256R1_SHA256: + *out_curve = NID_X9_62_prime256v1; + *out_md = EVP_sha256(); + return 1; + case SSL_SIGN_ECDSA_SECP384R1_SHA384: + *out_curve = NID_secp384r1; + *out_md = EVP_sha384(); + return 1; + case SSL_SIGN_ECDSA_SECP521R1_SHA512: + *out_curve = NID_secp521r1; + *out_md = EVP_sha512(); + return 1; + default: + return 0; + } +} + +static int ssl_sign_ecdsa(SSL *ssl, uint8_t *out, size_t *out_len, + size_t max_out, int curve, const EVP_MD *md, + const uint8_t *in, size_t in_len) { + EC_KEY *ec_key = EVP_PKEY_get0_EC_KEY(ssl->cert->privatekey); + if (ec_key == NULL) { + OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_SIGNATURE_TYPE); + return 0; + } + + /* In TLS 1.3, the curve is also specified by the signature algorithm. */ + if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION && + (curve == NID_undef || + EC_GROUP_get_curve_name(EC_KEY_get0_group(ec_key)) != curve)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_SIGNATURE_TYPE); + return 0; + } + + EVP_MD_CTX ctx; + EVP_MD_CTX_init(&ctx); + *out_len = max_out; + int ret = EVP_DigestSignInit(&ctx, NULL, md, NULL, ssl->cert->privatekey) && + EVP_DigestSignUpdate(&ctx, in, in_len) && + EVP_DigestSignFinal(&ctx, out, out_len); + EVP_MD_CTX_cleanup(&ctx); + return ret; +} + +static int ssl_verify_ecdsa(SSL *ssl, const uint8_t *signature, + size_t signature_len, int curve, const EVP_MD *md, + EVP_PKEY *pkey, const uint8_t *in, size_t in_len) { + EC_KEY *ec_key = EVP_PKEY_get0_EC_KEY(pkey); + if (ec_key == NULL) { + OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_SIGNATURE_TYPE); + return 0; + } + + /* In TLS 1.3, the curve is also specified by the signature algorithm. */ + if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION && + (curve == NID_undef || + EC_GROUP_get_curve_name(EC_KEY_get0_group(ec_key)) != curve)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_SIGNATURE_TYPE); + return 0; + } + + EVP_MD_CTX md_ctx; + EVP_MD_CTX_init(&md_ctx); + int ret = EVP_DigestVerifyInit(&md_ctx, NULL, md, NULL, pkey) && + EVP_DigestVerifyUpdate(&md_ctx, in, in_len) && + EVP_DigestVerifyFinal(&md_ctx, signature, signature_len); + EVP_MD_CTX_cleanup(&md_ctx); + return ret; +} + +static int is_rsa_pss(const EVP_MD **out_md, uint16_t sigalg) { + switch (sigalg) { + case SSL_SIGN_RSA_PSS_SHA256: + *out_md = EVP_sha256(); + return 1; + case SSL_SIGN_RSA_PSS_SHA384: + *out_md = EVP_sha384(); + return 1; + case SSL_SIGN_RSA_PSS_SHA512: + *out_md = EVP_sha512(); + return 1; + default: + return 0; + } +} + +static int ssl_sign_rsa_pss(SSL *ssl, uint8_t *out, size_t *out_len, + size_t max_out, const EVP_MD *md, + const uint8_t *in, size_t in_len) { + EVP_MD_CTX ctx; + EVP_MD_CTX_init(&ctx); + *out_len = max_out; + EVP_PKEY_CTX *pctx; + int ret = + EVP_DigestSignInit(&ctx, &pctx, md, NULL, ssl->cert->privatekey) && + EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING) && + EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, -1 /* salt len = hash len */) && + EVP_DigestSignUpdate(&ctx, in, in_len) && + EVP_DigestSignFinal(&ctx, out, out_len); + EVP_MD_CTX_cleanup(&ctx); + return ret; +} + +static int ssl_verify_rsa_pss(SSL *ssl, const uint8_t *signature, + size_t signature_len, const EVP_MD *md, + EVP_PKEY *pkey, const uint8_t *in, + size_t in_len) { + if (pkey->type != EVP_PKEY_RSA) { + OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_SIGNATURE_TYPE); + return 0; + } + + EVP_MD_CTX md_ctx; + EVP_MD_CTX_init(&md_ctx); + EVP_PKEY_CTX *pctx; + int ret = + EVP_DigestVerifyInit(&md_ctx, &pctx, md, NULL, pkey) && + EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING) && + EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, -1 /* salt len = hash len */) && + EVP_DigestVerifyUpdate(&md_ctx, in, in_len) && + EVP_DigestVerifyFinal(&md_ctx, signature, signature_len); + EVP_MD_CTX_cleanup(&md_ctx); + return ret; +} + +enum ssl_private_key_result_t ssl_private_key_sign( + SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out, + uint16_t signature_algorithm, const uint8_t *in, size_t in_len) { + if (ssl->cert->key_method != NULL) { + if (ssl->cert->key_method->sign != NULL) { + return ssl->cert->key_method->sign(ssl, out, out_len, max_out, + signature_algorithm, in, in_len); + } + + /* TODO(davidben): Remove support for |sign_digest|-only + * |SSL_PRIVATE_KEY_METHOD|s. */ + const EVP_MD *md; + int curve; + if (!is_rsa_pkcs1(&md, signature_algorithm) && + !is_ecdsa(&curve, &md, signature_algorithm)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_UNSUPPORTED_PROTOCOL_FOR_CUSTOM_KEY); + return ssl_private_key_failure; + } + + uint8_t hash[EVP_MAX_MD_SIZE]; + unsigned hash_len; + if (!EVP_Digest(in, in_len, hash, &hash_len, md, NULL)) { + return ssl_private_key_failure; + } + + return ssl->cert->key_method->sign_digest(ssl, out, out_len, max_out, md, + hash, hash_len); + } + + const EVP_MD *md; + if (is_rsa_pkcs1(&md, signature_algorithm) && + ssl3_protocol_version(ssl) < TLS1_3_VERSION) { + return ssl_sign_rsa_pkcs1(ssl, out, out_len, max_out, md, in, in_len) + ? ssl_private_key_success + : ssl_private_key_failure; + } + + int curve; + if (is_ecdsa(&curve, &md, signature_algorithm)) { + return ssl_sign_ecdsa(ssl, out, out_len, max_out, curve, md, in, in_len) + ? ssl_private_key_success + : ssl_private_key_failure; + } + + if (is_rsa_pss(&md, signature_algorithm)) { + return ssl_sign_rsa_pss(ssl, out, out_len, max_out, md, in, in_len) + ? ssl_private_key_success + : ssl_private_key_failure; + } + + OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_SIGNATURE_TYPE); + return ssl_private_key_failure; +} + +int ssl_public_key_verify(SSL *ssl, const uint8_t *signature, + size_t signature_len, uint16_t signature_algorithm, + EVP_PKEY *pkey, const uint8_t *in, size_t in_len) { + const EVP_MD *md; + if (is_rsa_pkcs1(&md, signature_algorithm) && + ssl3_protocol_version(ssl) < TLS1_3_VERSION) { + return ssl_verify_rsa_pkcs1(ssl, signature, signature_len, md, pkey, in, + in_len); + } + + int curve; + if (is_ecdsa(&curve, &md, signature_algorithm)) { + return ssl_verify_ecdsa(ssl, signature, signature_len, curve, md, pkey, in, + in_len); + } + + if (is_rsa_pss(&md, signature_algorithm)) { + return ssl_verify_rsa_pss(ssl, signature, signature_len, md, pkey, in, + in_len); + } + + OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_SIGNATURE_TYPE); + return 0; +} + +enum ssl_private_key_result_t ssl_private_key_decrypt( + SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out, + const uint8_t *in, size_t in_len) { + if (ssl->cert->key_method != NULL) { + return ssl->cert->key_method->decrypt(ssl, out, out_len, max_out, in, + in_len); + } + + RSA *rsa = EVP_PKEY_get0_RSA(ssl->cert->privatekey); + if (rsa == NULL) { + /* Decrypt operations are only supported for RSA keys. */ + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + return ssl_private_key_failure; + } + + /* Decrypt with no padding. PKCS#1 padding will be removed as part + * of the timing-sensitive code by the caller. */ + if (!RSA_decrypt(rsa, out_len, out, max_out, in, in_len, RSA_NO_PADDING)) { + return ssl_private_key_failure; + } + return ssl_private_key_success; +} + +enum ssl_private_key_result_t ssl_private_key_complete(SSL *ssl, uint8_t *out, + size_t *out_len, + size_t max_out) { + /* Only custom keys may be asynchronous. */ + return ssl->cert->key_method->complete(ssl, out, out_len, max_out); +} + +int ssl_private_key_supports_signature_algorithm(SSL *ssl, + uint16_t signature_algorithm) { + const EVP_MD *md; + if (is_rsa_pkcs1(&md, signature_algorithm) && + ssl3_protocol_version(ssl) < TLS1_3_VERSION) { + return ssl_private_key_type(ssl) == NID_rsaEncryption; + } + + int curve; + if (is_ecdsa(&curve, &md, signature_algorithm)) { + int type = ssl_private_key_type(ssl); + if (!ssl_is_ecdsa_key_type(type)) { + return 0; + } + + /* Prior to TLS 1.3, ECDSA curves did not match the signature algorithm. */ + if (ssl3_protocol_version(ssl) < TLS1_3_VERSION) { + return 1; + } + + return curve != NID_undef && type == curve; + } + + if (is_rsa_pss(&md, signature_algorithm)) { + if (ssl_private_key_type(ssl) != NID_rsaEncryption) { + return 0; + } + + /* Ensure the RSA key is large enough for the hash. RSASSA-PSS requires that + * emLen be at least hLen + sLen + 2. Both hLen and sLen are the size of the + * hash in TLS. Reasonable RSA key sizes are large enough for the largest + * defined RSASSA-PSS algorithm, but 1024-bit RSA is slightly too large for + * SHA-512. 1024-bit RSA is sometimes used for test credentials, so check + * the size to fall back to another algorithm. */ + if (ssl_private_key_max_signature_len(ssl) < 2 * EVP_MD_size(md) + 2) { + return 0; + } + + /* RSA-PSS is only supported by message-based private keys. */ + if (ssl->cert->key_method != NULL && ssl->cert->key_method->sign == NULL) { + return 0; + } + + return 1; + } + + return 0; +} diff --git a/Sources/BoringSSL/ssl/ssl_rsa.c b/Sources/BoringSSL/ssl/ssl_rsa.c deleted file mode 100644 index 990979b1f..000000000 --- a/Sources/BoringSSL/ssl/ssl_rsa.c +++ /dev/null @@ -1,423 +0,0 @@ -/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) - * All rights reserved. - * - * This package is an SSL implementation written - * by Eric Young (eay@cryptsoft.com). - * The implementation was written so as to conform with Netscapes SSL. - * - * This library is free for commercial and non-commercial use as long as - * the following conditions are aheared to. The following conditions - * apply to all code found in this distribution, be it the RC4, RSA, - * lhash, DES, etc., code; not just the SSL code. The SSL documentation - * included with this distribution is covered by the same copyright terms - * except that the holder is Tim Hudson (tjh@cryptsoft.com). - * - * Copyright remains Eric Young's, and as such any Copyright notices in - * the code are not to be removed. - * If this package is used in a product, Eric Young should be given attribution - * as the author of the parts of the library used. - * This can be in the form of a textual message at program startup or - * in documentation (online or textual) provided with the package. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * "This product includes cryptographic software written by - * Eric Young (eay@cryptsoft.com)" - * The word 'cryptographic' can be left out if the rouines from the library - * being used are not cryptographic related :-). - * 4. If you include any Windows specific code (or a derivative thereof) from - * the apps directory (application code) you must include an acknowledgement: - * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" - * - * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * The licence and distribution terms for any publically available version or - * derivative of this code cannot be changed. i.e. this code cannot simply be - * copied and put under another distribution licence - * [including the GNU Public Licence.] */ - -#include - -#include - -#include -#include -#include -#include - -#include "internal.h" - - -static int ssl_set_cert(CERT *c, X509 *x509); -static int ssl_set_pkey(CERT *c, EVP_PKEY *pkey); - -static int is_key_type_supported(int key_type) { - return key_type == EVP_PKEY_RSA || key_type == EVP_PKEY_EC; -} - -int SSL_use_certificate(SSL *ssl, X509 *x) { - if (x == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_PASSED_NULL_PARAMETER); - return 0; - } - return ssl_set_cert(ssl->cert, x); -} - -int SSL_use_certificate_ASN1(SSL *ssl, const uint8_t *der, size_t der_len) { - if (der_len > LONG_MAX) { - OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW); - return 0; - } - - const uint8_t *p = der; - X509 *x509 = d2i_X509(NULL, &p, (long)der_len); - if (x509 == NULL || p != der + der_len) { - OPENSSL_PUT_ERROR(SSL, ERR_R_ASN1_LIB); - X509_free(x509); - return 0; - } - - int ret = SSL_use_certificate(ssl, x509); - X509_free(x509); - return ret; -} - -int SSL_use_RSAPrivateKey(SSL *ssl, RSA *rsa) { - EVP_PKEY *pkey; - int ret; - - if (rsa == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_PASSED_NULL_PARAMETER); - return 0; - } - - pkey = EVP_PKEY_new(); - if (pkey == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_EVP_LIB); - return 0; - } - - RSA_up_ref(rsa); - EVP_PKEY_assign_RSA(pkey, rsa); - - ret = ssl_set_pkey(ssl->cert, pkey); - EVP_PKEY_free(pkey); - - return ret; -} - -static int ssl_set_pkey(CERT *c, EVP_PKEY *pkey) { - if (!is_key_type_supported(pkey->type)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_CERTIFICATE_TYPE); - return 0; - } - - if (c->x509 != NULL) { - /* Sanity-check that the private key and the certificate match, unless the - * key is opaque (in case of, say, a smartcard). */ - if (!EVP_PKEY_is_opaque(pkey) && - !X509_check_private_key(c->x509, pkey)) { - X509_free(c->x509); - c->x509 = NULL; - return 0; - } - } - - EVP_PKEY_free(c->privatekey); - c->privatekey = EVP_PKEY_up_ref(pkey); - - return 1; -} - -int SSL_use_RSAPrivateKey_ASN1(SSL *ssl, const uint8_t *der, size_t der_len) { - RSA *rsa = RSA_private_key_from_bytes(der, der_len); - if (rsa == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_ASN1_LIB); - return 0; - } - - int ret = SSL_use_RSAPrivateKey(ssl, rsa); - RSA_free(rsa); - return ret; -} - -int SSL_use_PrivateKey(SSL *ssl, EVP_PKEY *pkey) { - int ret; - - if (pkey == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_PASSED_NULL_PARAMETER); - return 0; - } - - ret = ssl_set_pkey(ssl->cert, pkey); - return ret; -} - -int SSL_use_PrivateKey_ASN1(int type, SSL *ssl, const uint8_t *der, - size_t der_len) { - if (der_len > LONG_MAX) { - OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW); - return 0; - } - - const uint8_t *p = der; - EVP_PKEY *pkey = d2i_PrivateKey(type, NULL, &p, (long)der_len); - if (pkey == NULL || p != der + der_len) { - OPENSSL_PUT_ERROR(SSL, ERR_R_ASN1_LIB); - EVP_PKEY_free(pkey); - return 0; - } - - int ret = SSL_use_PrivateKey(ssl, pkey); - EVP_PKEY_free(pkey); - return ret; -} - -int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x) { - if (x == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_PASSED_NULL_PARAMETER); - return 0; - } - - return ssl_set_cert(ctx->cert, x); -} - -static int ssl_set_cert(CERT *c, X509 *x) { - EVP_PKEY *pkey = X509_get_pubkey(x); - if (pkey == NULL) { - OPENSSL_PUT_ERROR(SSL, SSL_R_X509_LIB); - return 0; - } - - if (!is_key_type_supported(pkey->type)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_CERTIFICATE_TYPE); - EVP_PKEY_free(pkey); - return 0; - } - - if (c->privatekey != NULL) { - /* Sanity-check that the private key and the certificate match, unless the - * key is opaque (in case of, say, a smartcard). */ - if (!EVP_PKEY_is_opaque(c->privatekey) && - !X509_check_private_key(x, c->privatekey)) { - /* don't fail for a cert/key mismatch, just free current private key - * (when switching to a different cert & key, first this function should - * be used, then ssl_set_pkey */ - EVP_PKEY_free(c->privatekey); - c->privatekey = NULL; - /* clear error queue */ - ERR_clear_error(); - } - } - - EVP_PKEY_free(pkey); - - X509_free(c->x509); - c->x509 = X509_up_ref(x); - - return 1; -} - -int SSL_CTX_use_certificate_ASN1(SSL_CTX *ctx, size_t der_len, - const uint8_t *der) { - if (der_len > LONG_MAX) { - OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW); - return 0; - } - - const uint8_t *p = der; - X509 *x509 = d2i_X509(NULL, &p, (long)der_len); - if (x509 == NULL || p != der + der_len) { - OPENSSL_PUT_ERROR(SSL, ERR_R_ASN1_LIB); - X509_free(x509); - return 0; - } - - int ret = SSL_CTX_use_certificate(ctx, x509); - X509_free(x509); - return ret; -} - -int SSL_CTX_use_RSAPrivateKey(SSL_CTX *ctx, RSA *rsa) { - int ret; - EVP_PKEY *pkey; - - if (rsa == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_PASSED_NULL_PARAMETER); - return 0; - } - - pkey = EVP_PKEY_new(); - if (pkey == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_EVP_LIB); - return 0; - } - - RSA_up_ref(rsa); - EVP_PKEY_assign_RSA(pkey, rsa); - - ret = ssl_set_pkey(ctx->cert, pkey); - EVP_PKEY_free(pkey); - return ret; -} - -int SSL_CTX_use_RSAPrivateKey_ASN1(SSL_CTX *ctx, const uint8_t *der, - size_t der_len) { - RSA *rsa = RSA_private_key_from_bytes(der, der_len); - if (rsa == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_ASN1_LIB); - return 0; - } - - int ret = SSL_CTX_use_RSAPrivateKey(ctx, rsa); - RSA_free(rsa); - return ret; -} - -int SSL_CTX_use_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey) { - if (pkey == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_PASSED_NULL_PARAMETER); - return 0; - } - - return ssl_set_pkey(ctx->cert, pkey); -} - -int SSL_CTX_use_PrivateKey_ASN1(int type, SSL_CTX *ctx, const uint8_t *der, - size_t der_len) { - if (der_len > LONG_MAX) { - OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW); - return 0; - } - - const uint8_t *p = der; - EVP_PKEY *pkey = d2i_PrivateKey(type, NULL, &p, (long)der_len); - if (pkey == NULL || p != der + der_len) { - OPENSSL_PUT_ERROR(SSL, ERR_R_ASN1_LIB); - EVP_PKEY_free(pkey); - return 0; - } - - int ret = SSL_CTX_use_PrivateKey(ctx, pkey); - EVP_PKEY_free(pkey); - return ret; -} - -void SSL_set_private_key_method(SSL *ssl, - const SSL_PRIVATE_KEY_METHOD *key_method) { - ssl->cert->key_method = key_method; -} - -int SSL_set_private_key_digest_prefs(SSL *ssl, const int *digest_nids, - size_t num_digests) { - OPENSSL_free(ssl->cert->digest_nids); - - ssl->cert->num_digest_nids = 0; - ssl->cert->digest_nids = BUF_memdup(digest_nids, num_digests*sizeof(int)); - if (ssl->cert->digest_nids == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - return 0; - } - - ssl->cert->num_digest_nids = num_digests; - return 1; -} - -int ssl_has_private_key(SSL *ssl) { - return ssl->cert->privatekey != NULL || ssl->cert->key_method != NULL; -} - -int ssl_private_key_type(SSL *ssl) { - if (ssl->cert->key_method != NULL) { - return ssl->cert->key_method->type(ssl); - } - return EVP_PKEY_id(ssl->cert->privatekey); -} - -size_t ssl_private_key_max_signature_len(SSL *ssl) { - if (ssl->cert->key_method != NULL) { - return ssl->cert->key_method->max_signature_len(ssl); - } - return EVP_PKEY_size(ssl->cert->privatekey); -} - -enum ssl_private_key_result_t ssl_private_key_sign( - SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out, const EVP_MD *md, - const uint8_t *in, size_t in_len) { - if (ssl->cert->key_method != NULL) { - return ssl->cert->key_method->sign(ssl, out, out_len, max_out, md, in, - in_len); - } - - enum ssl_private_key_result_t ret = ssl_private_key_failure; - EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(ssl->cert->privatekey, NULL); - if (ctx == NULL) { - goto end; - } - - size_t len = max_out; - if (!EVP_PKEY_sign_init(ctx) || - !EVP_PKEY_CTX_set_signature_md(ctx, md) || - !EVP_PKEY_sign(ctx, out, &len, in, in_len)) { - goto end; - } - *out_len = len; - ret = ssl_private_key_success; - -end: - EVP_PKEY_CTX_free(ctx); - return ret; -} - -enum ssl_private_key_result_t ssl_private_key_sign_complete( - SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out) { - /* Only custom keys may be asynchronous. */ - return ssl->cert->key_method->sign_complete(ssl, out, out_len, max_out); -} - -enum ssl_private_key_result_t ssl_private_key_decrypt( - SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out, - const uint8_t *in, size_t in_len) { - if (ssl->cert->key_method != NULL) { - return ssl->cert->key_method->decrypt(ssl, out, out_len, max_out, in, - in_len); - } - - RSA *rsa = EVP_PKEY_get0_RSA(ssl->cert->privatekey); - if (rsa == NULL) { - /* Decrypt operations are only supported for RSA keys. */ - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - return ssl_private_key_failure; - } - - /* Decrypt with no padding. PKCS#1 padding will be removed as part - * of the timing-sensitive code by the caller. */ - if (!RSA_decrypt(rsa, out_len, out, max_out, in, in_len, RSA_NO_PADDING)) { - return ssl_private_key_failure; - } - return ssl_private_key_success; -} - -enum ssl_private_key_result_t ssl_private_key_decrypt_complete( - SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out) { - /* Only custom keys may be asynchronous. */ - return ssl->cert->key_method->decrypt_complete(ssl, out, out_len, max_out); -} diff --git a/Sources/BoringSSL/ssl/ssl_session.c b/Sources/BoringSSL/ssl/ssl_session.c index 804a04f60..bbe88c360 100644 --- a/Sources/BoringSSL/ssl/ssl_session.c +++ b/Sources/BoringSSL/ssl/ssl_session.c @@ -136,7 +136,7 @@ #include #include -#include +#include #include #include @@ -160,27 +160,209 @@ static void SSL_SESSION_list_remove(SSL_CTX *ctx, SSL_SESSION *session); static void SSL_SESSION_list_add(SSL_CTX *ctx, SSL_SESSION *session); static int remove_session_lock(SSL_CTX *ctx, SSL_SESSION *session, int lock); -SSL_SESSION *SSL_SESSION_new(void) { +SSL_SESSION *ssl_session_new(const SSL_X509_METHOD *x509_method) { SSL_SESSION *session = OPENSSL_malloc(sizeof(SSL_SESSION)); if (session == NULL) { OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); return 0; } - memset(session, 0, sizeof(SSL_SESSION)); + OPENSSL_memset(session, 0, sizeof(SSL_SESSION)); - session->verify_result = 1; /* avoid 0 (= X509_V_OK) just in case */ + session->x509_method = x509_method; + session->verify_result = X509_V_ERR_INVALID_CALL; session->references = 1; session->timeout = SSL_DEFAULT_SESSION_TIMEOUT; - session->time = (unsigned long)time(NULL); + session->auth_timeout = SSL_DEFAULT_SESSION_TIMEOUT; + session->time = (long)time(NULL); CRYPTO_new_ex_data(&session->ex_data); return session; } -SSL_SESSION *SSL_SESSION_up_ref(SSL_SESSION *session) { - if (session != NULL) { - CRYPTO_refcount_inc(&session->references); +SSL_SESSION *SSL_SESSION_new(const SSL_CTX *ctx) { + return ssl_session_new(ctx->x509_method); +} + +SSL_SESSION *SSL_SESSION_dup(SSL_SESSION *session, int dup_flags) { + SSL_SESSION *new_session = ssl_session_new(session->x509_method); + if (new_session == NULL) { + goto err; } - return session; + + new_session->is_server = session->is_server; + new_session->ssl_version = session->ssl_version; + new_session->sid_ctx_length = session->sid_ctx_length; + OPENSSL_memcpy(new_session->sid_ctx, session->sid_ctx, session->sid_ctx_length); + + /* Copy the key material. */ + new_session->master_key_length = session->master_key_length; + OPENSSL_memcpy(new_session->master_key, session->master_key, + session->master_key_length); + new_session->cipher = session->cipher; + + /* Copy authentication state. */ + if (session->psk_identity != NULL) { + new_session->psk_identity = BUF_strdup(session->psk_identity); + if (new_session->psk_identity == NULL) { + goto err; + } + } + if (session->certs != NULL) { + new_session->certs = sk_CRYPTO_BUFFER_new_null(); + if (new_session->certs == NULL) { + goto err; + } + for (size_t i = 0; i < sk_CRYPTO_BUFFER_num(session->certs); i++) { + CRYPTO_BUFFER *buffer = sk_CRYPTO_BUFFER_value(session->certs, i); + if (!sk_CRYPTO_BUFFER_push(new_session->certs, buffer)) { + goto err; + } + CRYPTO_BUFFER_up_ref(buffer); + } + } + + if (!session->x509_method->session_dup(new_session, session)) { + goto err; + } + + new_session->verify_result = session->verify_result; + + new_session->ocsp_response_length = session->ocsp_response_length; + if (session->ocsp_response != NULL) { + new_session->ocsp_response = BUF_memdup(session->ocsp_response, + session->ocsp_response_length); + if (new_session->ocsp_response == NULL) { + goto err; + } + } + + new_session->tlsext_signed_cert_timestamp_list_length = + session->tlsext_signed_cert_timestamp_list_length; + if (session->tlsext_signed_cert_timestamp_list != NULL) { + new_session->tlsext_signed_cert_timestamp_list = + BUF_memdup(session->tlsext_signed_cert_timestamp_list, + session->tlsext_signed_cert_timestamp_list_length); + if (new_session->tlsext_signed_cert_timestamp_list == NULL) { + goto err; + } + } + + OPENSSL_memcpy(new_session->peer_sha256, session->peer_sha256, + SHA256_DIGEST_LENGTH); + new_session->peer_sha256_valid = session->peer_sha256_valid; + + if (session->tlsext_hostname != NULL) { + new_session->tlsext_hostname = BUF_strdup(session->tlsext_hostname); + if (new_session->tlsext_hostname == NULL) { + goto err; + } + } + + new_session->peer_signature_algorithm = session->peer_signature_algorithm; + + new_session->timeout = session->timeout; + new_session->auth_timeout = session->auth_timeout; + new_session->time = session->time; + + /* Copy non-authentication connection properties. */ + if (dup_flags & SSL_SESSION_INCLUDE_NONAUTH) { + new_session->session_id_length = session->session_id_length; + OPENSSL_memcpy(new_session->session_id, session->session_id, + session->session_id_length); + + new_session->group_id = session->group_id; + + OPENSSL_memcpy(new_session->original_handshake_hash, + session->original_handshake_hash, + session->original_handshake_hash_len); + new_session->original_handshake_hash_len = + session->original_handshake_hash_len; + new_session->tlsext_tick_lifetime_hint = session->tlsext_tick_lifetime_hint; + new_session->ticket_age_add = session->ticket_age_add; + new_session->ticket_max_early_data = session->ticket_max_early_data; + new_session->extended_master_secret = session->extended_master_secret; + + if (session->early_alpn != NULL) { + new_session->early_alpn = + BUF_memdup(session->early_alpn, session->early_alpn_len); + if (new_session->early_alpn == NULL) { + goto err; + } + } + new_session->early_alpn_len = session->early_alpn_len; + } + + /* Copy the ticket. */ + if (dup_flags & SSL_SESSION_INCLUDE_TICKET) { + if (session->tlsext_tick != NULL) { + new_session->tlsext_tick = + BUF_memdup(session->tlsext_tick, session->tlsext_ticklen); + if (new_session->tlsext_tick == NULL) { + goto err; + } + } + new_session->tlsext_ticklen = session->tlsext_ticklen; + } + + /* The new_session does not get a copy of the ex_data. */ + + new_session->not_resumable = 1; + return new_session; + +err: + SSL_SESSION_free(new_session); + OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + return 0; +} + +void ssl_session_rebase_time(SSL *ssl, SSL_SESSION *session) { + struct timeval now; + ssl_get_current_time(ssl, &now); + + /* To avoid overflows and underflows, if we've gone back in time or any value + * is negative, update the time, but mark the session expired. */ + if (session->time > now.tv_sec || + session->time < 0 || + now.tv_sec < 0) { + session->time = now.tv_sec; + session->timeout = 0; + session->auth_timeout = 0; + return; + } + + /* Adjust the session time and timeouts. If the session has already expired, + * clamp the timeouts at zero. */ + long delta = now.tv_sec - session->time; + session->time = now.tv_sec; + if (session->timeout < delta) { + session->timeout = 0; + } else { + session->timeout -= delta; + } + if (session->auth_timeout < delta) { + session->auth_timeout = 0; + } else { + session->auth_timeout -= delta; + } +} + +void ssl_session_renew_timeout(SSL *ssl, SSL_SESSION *session, long timeout) { + /* Rebase the timestamp relative to the current time so |timeout| is measured + * correctly. */ + ssl_session_rebase_time(ssl, session); + + if (session->timeout > timeout) { + return; + } + + session->timeout = timeout; + if (session->timeout > session->auth_timeout) { + session->timeout = session->auth_timeout; + } +} + +int SSL_SESSION_up_ref(SSL_SESSION *session) { + CRYPTO_refcount_inc(&session->references); + return 1; } void SSL_SESSION_free(SSL_SESSION *session) { @@ -193,13 +375,14 @@ void SSL_SESSION_free(SSL_SESSION *session) { OPENSSL_cleanse(session->master_key, sizeof(session->master_key)); OPENSSL_cleanse(session->session_id, sizeof(session->session_id)); - X509_free(session->peer); - sk_X509_pop_free(session->cert_chain, X509_free); + sk_CRYPTO_BUFFER_pop_free(session->certs, CRYPTO_BUFFER_free); + session->x509_method->session_clear(session); OPENSSL_free(session->tlsext_hostname); OPENSSL_free(session->tlsext_tick); OPENSSL_free(session->tlsext_signed_cert_timestamp_list); OPENSSL_free(session->ocsp_response); OPENSSL_free(session->psk_identity); + OPENSSL_free(session->early_alpn); OPENSSL_cleanse(session, sizeof(*session)); OPENSSL_free(session); } @@ -224,12 +407,21 @@ long SSL_SESSION_get_time(const SSL_SESSION *session) { return session->time; } -uint32_t SSL_SESSION_get_key_exchange_info(const SSL_SESSION *session) { - return session->key_exchange_info; +X509 *SSL_SESSION_get0_peer(const SSL_SESSION *session) { + return session->x509_peer; } -X509 *SSL_SESSION_get0_peer(const SSL_SESSION *session) { - return session->peer; +size_t SSL_SESSION_get_master_key(const SSL_SESSION *session, uint8_t *out, + size_t max_out) { + /* TODO(davidben): Fix master_key_length's type and remove these casts. */ + if (max_out == 0) { + return (size_t)session->master_key_length; + } + if (max_out > (size_t)session->master_key_length) { + max_out = (size_t)session->master_key_length; + } + OPENSSL_memcpy(out, session->master_key, max_out); + return max_out; } long SSL_SESSION_set_time(SSL_SESSION *session, long time) { @@ -247,18 +439,20 @@ long SSL_SESSION_set_timeout(SSL_SESSION *session, long timeout) { } session->timeout = timeout; + session->auth_timeout = timeout; return 1; } int SSL_SESSION_set1_id_context(SSL_SESSION *session, const uint8_t *sid_ctx, - unsigned sid_ctx_len) { - if (sid_ctx_len > SSL_MAX_SID_CTX_LENGTH) { + size_t sid_ctx_len) { + if (sid_ctx_len > sizeof(session->sid_ctx)) { OPENSSL_PUT_ERROR(SSL, SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG); return 0; } - session->sid_ctx_length = sid_ctx_len; - memcpy(session->sid_ctx, sid_ctx, sid_ctx_len); + assert(sizeof(session->sid_ctx) < 256); + session->sid_ctx_length = (uint8_t)sid_ctx_len; + OPENSSL_memcpy(session->sid_ctx, sid_ctx, sid_ctx_len); return 1; } @@ -267,15 +461,25 @@ SSL_SESSION *SSL_magic_pending_session_ptr(void) { return (SSL_SESSION *)&g_pending_session_magic; } -SSL_SESSION *SSL_get_session(const SSL *ssl) -{ - /* aka SSL_get0_session; gets 0 objects, just returns a copy of the pointer */ +SSL_SESSION *SSL_get_session(const SSL *ssl) { + /* Once the handshake completes we return the established session. Otherwise + * we return the intermediate session, either |session| (for resumption) or + * |new_session| if doing a full handshake. */ + if (!SSL_in_init(ssl)) { + return ssl->s3->established_session; + } + if (ssl->s3->hs->new_session != NULL) { + return ssl->s3->hs->new_session; + } return ssl->session; } SSL_SESSION *SSL_get1_session(SSL *ssl) { - /* variant of SSL_get_session: caller really gets something */ - return SSL_SESSION_up_ref(ssl->session); + SSL_SESSION *ret = SSL_get_session(ssl); + if (ret != NULL) { + SSL_SESSION_up_ref(ret); + } + return ret; } int SSL_SESSION_get_ex_new_index(long argl, void *argp, @@ -298,26 +502,51 @@ void *SSL_SESSION_get_ex_data(const SSL_SESSION *session, int idx) { return CRYPTO_get_ex_data(&session->ex_data, idx); } -int ssl_get_new_session(SSL *ssl, int is_server) { +const EVP_MD *SSL_SESSION_get_digest(const SSL_SESSION *session, + const SSL *ssl) { + uint16_t version; + if (!ssl->method->version_from_wire(&version, session->ssl_version)) { + return NULL; + } + + return ssl_get_handshake_digest(session->cipher->algorithm_prf, version); +} + +int ssl_get_new_session(SSL_HANDSHAKE *hs, int is_server) { + SSL *const ssl = hs->ssl; if (ssl->mode & SSL_MODE_NO_SESSION_CREATION) { OPENSSL_PUT_ERROR(SSL, SSL_R_SESSION_MAY_NOT_BE_CREATED); return 0; } - SSL_SESSION *session = SSL_SESSION_new(); + SSL_SESSION *session = ssl_session_new(ssl->ctx->x509_method); if (session == NULL) { return 0; } - /* If the context has a default timeout, use it over the default. */ - if (ssl->initial_ctx->session_timeout != 0) { + session->is_server = is_server; + session->ssl_version = ssl->version; + + /* Fill in the time from the |SSL_CTX|'s clock. */ + struct timeval now; + ssl_get_current_time(ssl, &now); + session->time = now.tv_sec; + + uint16_t version = ssl3_protocol_version(ssl); + if (version >= TLS1_3_VERSION) { + /* TLS 1.3 uses tickets as authenticators, so we are willing to use them for + * longer. */ + session->timeout = ssl->initial_ctx->session_psk_dhe_timeout; + session->auth_timeout = SSL_DEFAULT_SESSION_AUTH_TIMEOUT; + } else { + /* TLS 1.2 resumption does not incorporate new key material, so we use a + * much shorter timeout. */ session->timeout = ssl->initial_ctx->session_timeout; + session->auth_timeout = ssl->initial_ctx->session_timeout; } - session->ssl_version = ssl->version; - if (is_server) { - if (ssl->tlsext_ticket_expected) { + if (hs->ticket_expected || version >= TLS1_3_VERSION) { /* Don't set session IDs for sessions resumed with tickets. This will keep * them out of the session cache. */ session->session_id_length = 0; @@ -327,29 +556,25 @@ int ssl_get_new_session(SSL *ssl, int is_server) { goto err; } } - - if (ssl->tlsext_hostname != NULL) { - session->tlsext_hostname = BUF_strdup(ssl->tlsext_hostname); - if (session->tlsext_hostname == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; - } - } } else { session->session_id_length = 0; } - if (ssl->sid_ctx_length > sizeof(session->sid_ctx)) { + if (ssl->cert->sid_ctx_length > sizeof(session->sid_ctx)) { OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); goto err; } - memcpy(session->sid_ctx, ssl->sid_ctx, ssl->sid_ctx_length); - session->sid_ctx_length = ssl->sid_ctx_length; + OPENSSL_memcpy(session->sid_ctx, ssl->cert->sid_ctx, + ssl->cert->sid_ctx_length); + session->sid_ctx_length = ssl->cert->sid_ctx_length; - session->verify_result = X509_V_OK; + /* The session is marked not resumable until it is completely filled in. */ + session->not_resumable = 1; + session->verify_result = X509_V_ERR_INVALID_CALL; - SSL_SESSION_free(ssl->session); - ssl->session = session; + SSL_SESSION_free(hs->new_session); + hs->new_session = session; + ssl_set_session(ssl, NULL); return 1; err: @@ -357,6 +582,147 @@ int ssl_get_new_session(SSL *ssl, int is_server) { return 0; } +int ssl_encrypt_ticket(SSL *ssl, CBB *out, const SSL_SESSION *session) { + int ret = 0; + + /* Serialize the SSL_SESSION to be encoded into the ticket. */ + uint8_t *session_buf = NULL; + size_t session_len; + if (!SSL_SESSION_to_bytes_for_ticket(session, &session_buf, &session_len)) { + return -1; + } + + EVP_CIPHER_CTX ctx; + EVP_CIPHER_CTX_init(&ctx); + HMAC_CTX hctx; + HMAC_CTX_init(&hctx); + + /* If the session is too long, emit a dummy value rather than abort the + * connection. */ + static const size_t kMaxTicketOverhead = + 16 + EVP_MAX_IV_LENGTH + EVP_MAX_BLOCK_LENGTH + EVP_MAX_MD_SIZE; + if (session_len > 0xffff - kMaxTicketOverhead) { + static const char kTicketPlaceholder[] = "TICKET TOO LARGE"; + if (CBB_add_bytes(out, (const uint8_t *)kTicketPlaceholder, + strlen(kTicketPlaceholder))) { + ret = 1; + } + goto err; + } + + /* Initialize HMAC and cipher contexts. If callback present it does all the + * work otherwise use generated values from parent ctx. */ + SSL_CTX *tctx = ssl->initial_ctx; + uint8_t iv[EVP_MAX_IV_LENGTH]; + uint8_t key_name[16]; + if (tctx->tlsext_ticket_key_cb != NULL) { + if (tctx->tlsext_ticket_key_cb(ssl, key_name, iv, &ctx, &hctx, + 1 /* encrypt */) < 0) { + goto err; + } + } else { + if (!RAND_bytes(iv, 16) || + !EVP_EncryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, + tctx->tlsext_tick_aes_key, iv) || + !HMAC_Init_ex(&hctx, tctx->tlsext_tick_hmac_key, 16, tlsext_tick_md(), + NULL)) { + goto err; + } + OPENSSL_memcpy(key_name, tctx->tlsext_tick_key_name, 16); + } + + uint8_t *ptr; + if (!CBB_add_bytes(out, key_name, 16) || + !CBB_add_bytes(out, iv, EVP_CIPHER_CTX_iv_length(&ctx)) || + !CBB_reserve(out, &ptr, session_len + EVP_MAX_BLOCK_LENGTH)) { + goto err; + } + + size_t total = 0; +#if defined(BORINGSSL_UNSAFE_FUZZER_MODE) + OPENSSL_memcpy(ptr, session_buf, session_len); + total = session_len; +#else + int len; + if (!EVP_EncryptUpdate(&ctx, ptr + total, &len, session_buf, session_len)) { + goto err; + } + total += len; + if (!EVP_EncryptFinal_ex(&ctx, ptr + total, &len)) { + goto err; + } + total += len; +#endif + if (!CBB_did_write(out, total)) { + goto err; + } + + unsigned hlen; + if (!HMAC_Update(&hctx, CBB_data(out), CBB_len(out)) || + !CBB_reserve(out, &ptr, EVP_MAX_MD_SIZE) || + !HMAC_Final(&hctx, ptr, &hlen) || + !CBB_did_write(out, hlen)) { + goto err; + } + + ret = 1; + +err: + OPENSSL_free(session_buf); + EVP_CIPHER_CTX_cleanup(&ctx); + HMAC_CTX_cleanup(&hctx); + return ret; +} + +int ssl_session_is_context_valid(const SSL *ssl, const SSL_SESSION *session) { + if (session == NULL) { + return 0; + } + + return session->sid_ctx_length == ssl->cert->sid_ctx_length && + OPENSSL_memcmp(session->sid_ctx, ssl->cert->sid_ctx, + ssl->cert->sid_ctx_length) == 0; +} + +int ssl_session_is_time_valid(const SSL *ssl, const SSL_SESSION *session) { + if (session == NULL) { + return 0; + } + + struct timeval now; + ssl_get_current_time(ssl, &now); + + /* Reject tickets from the future to avoid underflow. */ + if ((long)now.tv_sec < session->time) { + return 0; + } + + return session->timeout > (long)now.tv_sec - session->time; +} + +int ssl_session_is_resumable(const SSL_HANDSHAKE *hs, + const SSL_SESSION *session) { + const SSL *const ssl = hs->ssl; + return ssl_session_is_context_valid(ssl, session) && + /* The session must have been created by the same type of end point as + * we're now using it with. */ + ssl->server == session->is_server && + /* The session must not be expired. */ + ssl_session_is_time_valid(ssl, session) && + /* Only resume if the session's version matches the negotiated + * version. */ + ssl->version == session->ssl_version && + /* Only resume if the session's cipher matches the negotiated one. */ + hs->new_cipher == session->cipher && + /* If the session contains a client certificate (either the full + * certificate or just the hash) then require that the form of the + * certificate matches the current configuration. */ + ((sk_CRYPTO_BUFFER_num(session->certs) == 0 && + !session->peer_sha256_valid) || + session->peer_sha256_valid == + ssl->retain_only_sha256_of_client_certs); +} + /* ssl_lookup_session looks up |session_id| in the session cache and sets * |*out_session| to an |SSL_SESSION| object if found. The caller takes * ownership of the result. */ @@ -369,14 +735,14 @@ static enum ssl_session_result_t ssl_lookup_session( return ssl_session_success; } - SSL_SESSION *session; + SSL_SESSION *session = NULL; /* Try the internal cache, if it exists. */ if (!(ssl->initial_ctx->session_cache_mode & SSL_SESS_CACHE_NO_INTERNAL_LOOKUP)) { SSL_SESSION data; data.ssl_version = ssl->version; data.session_id_length = session_id_len; - memcpy(data.session_id, session_id, session_id_len); + OPENSSL_memcpy(data.session_id, session_id, session_id_len); CRYPTO_MUTEX_lock_read(&ssl->initial_ctx->lock); session = lh_SSL_SESSION_retrieve(ssl->initial_ctx->sessions, &data); @@ -384,40 +750,45 @@ static enum ssl_session_result_t ssl_lookup_session( SSL_SESSION_up_ref(session); } /* TODO(davidben): This should probably move it to the front of the list. */ - CRYPTO_MUTEX_unlock(&ssl->initial_ctx->lock); + CRYPTO_MUTEX_unlock_read(&ssl->initial_ctx->lock); + } - if (session != NULL) { - *out_session = session; + /* Fall back to the external cache, if it exists. */ + if (session == NULL && + ssl->initial_ctx->get_session_cb != NULL) { + int copy = 1; + session = ssl->initial_ctx->get_session_cb(ssl, (uint8_t *)session_id, + session_id_len, ©); + + if (session == NULL) { return ssl_session_success; } - } - /* Fall back to the external cache, if it exists. */ - if (ssl->initial_ctx->get_session_cb == NULL) { - return ssl_session_success; - } - int copy = 1; - session = ssl->initial_ctx->get_session_cb(ssl, (uint8_t *)session_id, - session_id_len, ©); - if (session == NULL) { - return ssl_session_success; - } - if (session == SSL_magic_pending_session_ptr()) { - return ssl_session_retry; - } + if (session == SSL_magic_pending_session_ptr()) { + return ssl_session_retry; + } - /* Increment reference count now if the session callback asks us to do so - * (note that if the session structures returned by the callback are shared - * between threads, it must handle the reference count itself [i.e. copy == - * 0], or things won't be thread-safe). */ - if (copy) { - SSL_SESSION_up_ref(session); + /* Increment reference count now if the session callback asks us to do so + * (note that if the session structures returned by the callback are shared + * between threads, it must handle the reference count itself [i.e. copy == + * 0], or things won't be thread-safe). */ + if (copy) { + SSL_SESSION_up_ref(session); + } + + /* Add the externally cached session to the internal cache if necessary. */ + if (!(ssl->initial_ctx->session_cache_mode & + SSL_SESS_CACHE_NO_INTERNAL_STORE)) { + SSL_CTX_add_session(ssl->initial_ctx, session); + } } - /* Add the externally cached session to the internal cache if necessary. */ - if (!(ssl->initial_ctx->session_cache_mode & - SSL_SESS_CACHE_NO_INTERNAL_STORE)) { - SSL_CTX_add_session(ssl->initial_ctx, session); + if (session != NULL && + !ssl_session_is_time_valid(ssl, session)) { + /* The session was from the cache, so remove it. */ + SSL_CTX_remove_session(ssl->initial_ctx, session); + SSL_SESSION_free(session); + session = NULL; } *out_session = session; @@ -425,8 +796,8 @@ static enum ssl_session_result_t ssl_lookup_session( } enum ssl_session_result_t ssl_get_prev_session( - SSL *ssl, SSL_SESSION **out_session, int *out_send_ticket, - const struct ssl_early_callback_ctx *ctx) { + SSL *ssl, SSL_SESSION **out_session, int *out_tickets_supported, + int *out_renew_ticket, const SSL_CLIENT_HELLO *client_hello) { /* This is used only by servers. */ assert(ssl->server); SSL_SESSION *session = NULL; @@ -438,62 +809,26 @@ enum ssl_session_result_t ssl_get_prev_session( const int tickets_supported = !(SSL_get_options(ssl) & SSL_OP_NO_TICKET) && ssl->version > SSL3_VERSION && - SSL_early_callback_ctx_extension_get(ctx, TLSEXT_TYPE_session_ticket, - &ticket, &ticket_len); - int from_cache = 0; + SSL_early_callback_ctx_extension_get( + client_hello, TLSEXT_TYPE_session_ticket, &ticket, &ticket_len); if (tickets_supported && ticket_len > 0) { if (!tls_process_ticket(ssl, &session, &renew_ticket, ticket, ticket_len, - ctx->session_id, ctx->session_id_len)) { + client_hello->session_id, + client_hello->session_id_len)) { return ssl_session_error; } } else { /* The client didn't send a ticket, so the session ID is a real ID. */ enum ssl_session_result_t lookup_ret = ssl_lookup_session( - ssl, &session, ctx->session_id, ctx->session_id_len); + ssl, &session, client_hello->session_id, client_hello->session_id_len); if (lookup_ret != ssl_session_success) { return lookup_ret; } - from_cache = 1; - } - - if (session == NULL || - session->sid_ctx_length != ssl->sid_ctx_length || - memcmp(session->sid_ctx, ssl->sid_ctx, ssl->sid_ctx_length) != 0) { - /* The client did not offer a suitable ticket or session ID. If supported, - * the new session should use a ticket. */ - goto no_session; - } - - if ((ssl->verify_mode & SSL_VERIFY_PEER) && ssl->sid_ctx_length == 0) { - /* We can't be sure if this session is being used out of context, which is - * especially important for SSL_VERIFY_PEER. The application should have - * used SSL[_CTX]_set_session_id_context. - * - * For this error case, we generate an error instead of treating the event - * like a cache miss (otherwise it would be easy for applications to - * effectively disable the session cache by accident without anyone - * noticing). */ - OPENSSL_PUT_ERROR(SSL, SSL_R_SESSION_ID_CONTEXT_UNINITIALIZED); - SSL_SESSION_free(session); - return ssl_session_error; - } - - if (session->timeout < (long)(time(NULL) - session->time)) { - if (from_cache) { - /* The session was from the cache, so remove it. */ - SSL_CTX_remove_session(ssl->initial_ctx, session); - } - goto no_session; } *out_session = session; - *out_send_ticket = renew_ticket; - return ssl_session_success; - -no_session: - *out_session = NULL; - *out_send_ticket = tickets_supported; - SSL_SESSION_free(session); + *out_tickets_supported = tickets_supported; + *out_renew_ticket = renew_ticket; return ssl_session_success; } @@ -505,7 +840,7 @@ int SSL_CTX_add_session(SSL_CTX *ctx, SSL_SESSION *session) { SSL_SESSION *old_session; CRYPTO_MUTEX_lock_write(&ctx->lock); if (!lh_SSL_SESSION_insert(ctx->sessions, &old_session, session)) { - CRYPTO_MUTEX_unlock(&ctx->lock); + CRYPTO_MUTEX_unlock_write(&ctx->lock); SSL_SESSION_free(session); return 0; } @@ -513,7 +848,7 @@ int SSL_CTX_add_session(SSL_CTX *ctx, SSL_SESSION *session) { if (old_session != NULL) { if (old_session == session) { /* |session| was already in the cache. */ - CRYPTO_MUTEX_unlock(&ctx->lock); + CRYPTO_MUTEX_unlock_write(&ctx->lock); SSL_SESSION_free(old_session); return 0; } @@ -535,7 +870,7 @@ int SSL_CTX_add_session(SSL_CTX *ctx, SSL_SESSION *session) { } } - CRYPTO_MUTEX_unlock(&ctx->lock); + CRYPTO_MUTEX_unlock_write(&ctx->lock); return 1; } @@ -559,7 +894,7 @@ static int remove_session_lock(SSL_CTX *ctx, SSL_SESSION *session, int lock) { } if (lock) { - CRYPTO_MUTEX_unlock(&ctx->lock); + CRYPTO_MUTEX_unlock_write(&ctx->lock); } if (ret) { @@ -575,18 +910,27 @@ static int remove_session_lock(SSL_CTX *ctx, SSL_SESSION *session, int lock) { } int SSL_set_session(SSL *ssl, SSL_SESSION *session) { + /* SSL_set_session may only be called before the handshake has started. */ + if (ssl->s3->initial_handshake_complete || + ssl->s3->hs == NULL || + ssl->s3->hs->state != SSL_ST_INIT) { + abort(); + } + + ssl_set_session(ssl, session); + return 1; +} + +void ssl_set_session(SSL *ssl, SSL_SESSION *session) { if (ssl->session == session) { - return 1; + return; } SSL_SESSION_free(ssl->session); ssl->session = session; if (session != NULL) { SSL_SESSION_up_ref(session); - ssl->verify_result = session->verify_result; } - - return 1; } long SSL_CTX_set_timeout(SSL_CTX *ctx, long timeout) { @@ -594,6 +938,11 @@ long SSL_CTX_set_timeout(SSL_CTX *ctx, long timeout) { return 0; } + /* Historically, zero was treated as |SSL_DEFAULT_SESSION_TIMEOUT|. */ + if (timeout == 0) { + timeout = SSL_DEFAULT_SESSION_TIMEOUT; + } + long old_timeout = ctx->session_timeout; ctx->session_timeout = timeout; return old_timeout; @@ -607,6 +956,10 @@ long SSL_CTX_get_timeout(const SSL_CTX *ctx) { return ctx->session_timeout; } +void SSL_CTX_set_session_psk_dhe_timeout(SSL_CTX *ctx, long timeout) { + ctx->session_psk_dhe_timeout = timeout; +} + typedef struct timeout_param_st { SSL_CTX *ctx; long time; @@ -642,17 +995,7 @@ void SSL_CTX_flush_sessions(SSL_CTX *ctx, long time) { tp.time = time; CRYPTO_MUTEX_lock_write(&ctx->lock); lh_SSL_SESSION_doall_arg(tp.cache, timeout_doall_arg, &tp); - CRYPTO_MUTEX_unlock(&ctx->lock); -} - -int ssl_clear_bad_session(SSL *ssl) { - if (ssl->session != NULL && !(ssl->shutdown & SSL_SENT_SHUTDOWN) && - !SSL_in_init(ssl)) { - SSL_CTX_remove_session(ssl->ctx, ssl->session); - return 1; - } - - return 0; + CRYPTO_MUTEX_unlock_write(&ctx->lock); } /* locked by SSL_CTX in the calling function */ @@ -743,17 +1086,6 @@ void (*SSL_CTX_get_info_callback(SSL_CTX *ctx))(const SSL *ssl, int type, return ctx->info_callback; } -void SSL_CTX_set_client_cert_cb(SSL_CTX *ctx, int (*cb)(SSL *ssl, - X509 **out_x509, - EVP_PKEY **out_pkey)) { - ctx->client_cert_cb = cb; -} - -int (*SSL_CTX_get_client_cert_cb(SSL_CTX *ctx))(SSL *ssl, X509 **out_x509, - EVP_PKEY **out_pkey) { - return ctx->client_cert_cb; -} - void SSL_CTX_set_channel_id_cb(SSL_CTX *ctx, void (*cb)(SSL *ssl, EVP_PKEY **pkey)) { ctx->channel_id_cb = cb; diff --git a/Sources/BoringSSL/ssl/ssl_stat.c b/Sources/BoringSSL/ssl/ssl_stat.c index 8fa197d56..571b4a9a2 100644 --- a/Sources/BoringSSL/ssl/ssl_stat.c +++ b/Sources/BoringSSL/ssl/ssl_stat.c @@ -83,11 +83,22 @@ #include +#include + #include "internal.h" +static int ssl_state(const SSL *ssl) { + if (ssl->s3->hs == NULL) { + assert(ssl->s3->initial_handshake_complete); + return SSL_ST_OK; + } + + return ssl->s3->hs->state; +} + const char *SSL_state_string_long(const SSL *ssl) { - switch (ssl->state) { + switch (ssl_state(ssl)) { case SSL_ST_ACCEPT: return "before accept initialization"; @@ -104,85 +115,44 @@ const char *SSL_state_string_long(const SSL *ssl) { case SSL3_ST_CW_CLNT_HELLO_A: return "SSLv3 write client hello A"; - case SSL3_ST_CW_CLNT_HELLO_B: - return "SSLv3 write client hello B"; - case SSL3_ST_CR_SRVR_HELLO_A: return "SSLv3 read server hello A"; - case SSL3_ST_CR_SRVR_HELLO_B: - return "SSLv3 read server hello B"; - case SSL3_ST_CR_CERT_A: return "SSLv3 read server certificate A"; - case SSL3_ST_CR_CERT_B: - return "SSLv3 read server certificate B"; - case SSL3_ST_CR_KEY_EXCH_A: return "SSLv3 read server key exchange A"; - case SSL3_ST_CR_KEY_EXCH_B: - return "SSLv3 read server key exchange B"; - case SSL3_ST_CR_CERT_REQ_A: return "SSLv3 read server certificate request A"; - case SSL3_ST_CR_CERT_REQ_B: - return "SSLv3 read server certificate request B"; - case SSL3_ST_CR_SESSION_TICKET_A: return "SSLv3 read server session ticket A"; - case SSL3_ST_CR_SESSION_TICKET_B: - return "SSLv3 read server session ticket B"; - case SSL3_ST_CR_SRVR_DONE_A: return "SSLv3 read server done A"; - case SSL3_ST_CR_SRVR_DONE_B: - return "SSLv3 read server done B"; - case SSL3_ST_CW_CERT_A: return "SSLv3 write client certificate A"; - case SSL3_ST_CW_CERT_B: - return "SSLv3 write client certificate B"; - - case SSL3_ST_CW_CERT_C: - return "SSLv3 write client certificate C"; - - case SSL3_ST_CW_CERT_D: - return "SSLv3 write client certificate D"; - case SSL3_ST_CW_KEY_EXCH_A: return "SSLv3 write client key exchange A"; - case SSL3_ST_CW_KEY_EXCH_B: - return "SSLv3 write client key exchange B"; - case SSL3_ST_CW_CERT_VRFY_A: return "SSLv3 write certificate verify A"; case SSL3_ST_CW_CERT_VRFY_B: return "SSLv3 write certificate verify B"; - case SSL3_ST_CW_CHANGE_A: - case SSL3_ST_SW_CHANGE_A: - return "SSLv3 write change cipher spec A"; - - case SSL3_ST_CW_CHANGE_B: - case SSL3_ST_SW_CHANGE_B: - return "SSLv3 write change cipher spec B"; + case SSL3_ST_CW_CHANGE: + case SSL3_ST_SW_CHANGE: + return "SSLv3 write change cipher spec"; case SSL3_ST_CW_FINISHED_A: case SSL3_ST_SW_FINISHED_A: return "SSLv3 write finished A"; - case SSL3_ST_CW_FINISHED_B: - case SSL3_ST_SW_FINISHED_B: - return "SSLv3 write finished B"; - case SSL3_ST_CR_CHANGE: case SSL3_ST_SR_CHANGE: return "SSLv3 read change cipher spec"; @@ -191,10 +161,6 @@ const char *SSL_state_string_long(const SSL *ssl) { case SSL3_ST_SR_FINISHED_A: return "SSLv3 read finished A"; - case SSL3_ST_CR_FINISHED_B: - case SSL3_ST_SR_FINISHED_B: - return "SSLv3 read finished B"; - case SSL3_ST_CW_FLUSH: case SSL3_ST_SW_FLUSH: return "SSLv3 flush data"; @@ -208,60 +174,27 @@ const char *SSL_state_string_long(const SSL *ssl) { case SSL3_ST_SR_CLNT_HELLO_C: return "SSLv3 read client hello C"; - case SSL3_ST_SR_CLNT_HELLO_D: - return "SSLv3 read client hello D"; - - case SSL3_ST_SW_HELLO_REQ_A: - return "SSLv3 write hello request A"; - - case SSL3_ST_SW_HELLO_REQ_B: - return "SSLv3 write hello request B"; - - case SSL3_ST_SW_HELLO_REQ_C: - return "SSLv3 write hello request C"; - case SSL3_ST_SW_SRVR_HELLO_A: return "SSLv3 write server hello A"; - case SSL3_ST_SW_SRVR_HELLO_B: - return "SSLv3 write server hello B"; - case SSL3_ST_SW_CERT_A: return "SSLv3 write certificate A"; - case SSL3_ST_SW_CERT_B: - return "SSLv3 write certificate B"; - case SSL3_ST_SW_KEY_EXCH_A: return "SSLv3 write key exchange A"; - case SSL3_ST_SW_KEY_EXCH_B: - return "SSLv3 write key exchange B"; - case SSL3_ST_SW_CERT_REQ_A: return "SSLv3 write certificate request A"; - case SSL3_ST_SW_CERT_REQ_B: - return "SSLv3 write certificate request B"; - case SSL3_ST_SW_SESSION_TICKET_A: return "SSLv3 write session ticket A"; - case SSL3_ST_SW_SESSION_TICKET_B: - return "SSLv3 write session ticket B"; - case SSL3_ST_SW_SRVR_DONE_A: return "SSLv3 write server done A"; - case SSL3_ST_SW_SRVR_DONE_B: - return "SSLv3 write server done B"; - case SSL3_ST_SR_CERT_A: return "SSLv3 read client certificate A"; - case SSL3_ST_SR_CERT_B: - return "SSLv3 read client certificate B"; - case SSL3_ST_SR_KEY_EXCH_A: return "SSLv3 read client key exchange A"; @@ -271,23 +204,17 @@ const char *SSL_state_string_long(const SSL *ssl) { case SSL3_ST_SR_CERT_VRFY_A: return "SSLv3 read certificate verify A"; - case SSL3_ST_SR_CERT_VRFY_B: - return "SSLv3 read certificate verify B"; - /* DTLS */ case DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A: return "DTLS1 read hello verify request A"; - case DTLS1_ST_CR_HELLO_VERIFY_REQUEST_B: - return "DTLS1 read hello verify request B"; - default: return "unknown state"; } } const char *SSL_state_string(const SSL *ssl) { - switch (ssl->state) { + switch (ssl_state(ssl)) { case SSL_ST_ACCEPT: return "AINIT "; @@ -305,79 +232,41 @@ const char *SSL_state_string(const SSL *ssl) { case SSL3_ST_CW_CLNT_HELLO_A: return "3WCH_A"; - case SSL3_ST_CW_CLNT_HELLO_B: - return "3WCH_B"; - case SSL3_ST_CR_SRVR_HELLO_A: return "3RSH_A"; - case SSL3_ST_CR_SRVR_HELLO_B: - return "3RSH_B"; - case SSL3_ST_CR_CERT_A: return "3RSC_A"; - case SSL3_ST_CR_CERT_B: - return "3RSC_B"; - case SSL3_ST_CR_KEY_EXCH_A: return "3RSKEA"; - case SSL3_ST_CR_KEY_EXCH_B: - return "3RSKEB"; - case SSL3_ST_CR_CERT_REQ_A: return "3RCR_A"; - case SSL3_ST_CR_CERT_REQ_B: - return "3RCR_B"; - case SSL3_ST_CR_SRVR_DONE_A: return "3RSD_A"; - case SSL3_ST_CR_SRVR_DONE_B: - return "3RSD_B"; - case SSL3_ST_CW_CERT_A: return "3WCC_A"; - case SSL3_ST_CW_CERT_B: - return "3WCC_B"; - - case SSL3_ST_CW_CERT_C: - return "3WCC_C"; - - case SSL3_ST_CW_CERT_D: - return "3WCC_D"; - case SSL3_ST_CW_KEY_EXCH_A: return "3WCKEA"; - case SSL3_ST_CW_KEY_EXCH_B: - return "3WCKEB"; - case SSL3_ST_CW_CERT_VRFY_A: return "3WCV_A"; case SSL3_ST_CW_CERT_VRFY_B: return "3WCV_B"; - case SSL3_ST_SW_CHANGE_A: - case SSL3_ST_CW_CHANGE_A: - return "3WCCSA"; - - case SSL3_ST_SW_CHANGE_B: - case SSL3_ST_CW_CHANGE_B: - return "3WCCSB"; + case SSL3_ST_SW_CHANGE: + case SSL3_ST_CW_CHANGE: + return "3WCCS_"; case SSL3_ST_SW_FINISHED_A: case SSL3_ST_CW_FINISHED_A: return "3WFINA"; - case SSL3_ST_SW_FINISHED_B: - case SSL3_ST_CW_FINISHED_B: - return "3WFINB"; - case SSL3_ST_CR_CHANGE: case SSL3_ST_SR_CHANGE: return "3RCCS_"; @@ -386,19 +275,6 @@ const char *SSL_state_string(const SSL *ssl) { case SSL3_ST_CR_FINISHED_A: return "3RFINA"; - case SSL3_ST_SR_FINISHED_B: - case SSL3_ST_CR_FINISHED_B: - return "3RFINB"; - - case SSL3_ST_SW_HELLO_REQ_A: - return "3WHR_A"; - - case SSL3_ST_SW_HELLO_REQ_B: - return "3WHR_B"; - - case SSL3_ST_SW_HELLO_REQ_C: - return "3WHR_C"; - case SSL3_ST_SR_CLNT_HELLO_A: return "3RCH_A"; @@ -408,21 +284,12 @@ const char *SSL_state_string(const SSL *ssl) { case SSL3_ST_SR_CLNT_HELLO_C: return "3RCH_C"; - case SSL3_ST_SR_CLNT_HELLO_D: - return "3RCH_D"; - case SSL3_ST_SW_SRVR_HELLO_A: return "3WSH_A"; - case SSL3_ST_SW_SRVR_HELLO_B: - return "3WSH_B"; - case SSL3_ST_SW_CERT_A: return "3WSC_A"; - case SSL3_ST_SW_CERT_B: - return "3WSC_B"; - case SSL3_ST_SW_KEY_EXCH_A: return "3WSKEA"; @@ -432,40 +299,22 @@ const char *SSL_state_string(const SSL *ssl) { case SSL3_ST_SW_CERT_REQ_A: return "3WCR_A"; - case SSL3_ST_SW_CERT_REQ_B: - return "3WCR_B"; - case SSL3_ST_SW_SRVR_DONE_A: return "3WSD_A"; - case SSL3_ST_SW_SRVR_DONE_B: - return "3WSD_B"; - case SSL3_ST_SR_CERT_A: return "3RCC_A"; - case SSL3_ST_SR_CERT_B: - return "3RCC_B"; - case SSL3_ST_SR_KEY_EXCH_A: return "3RCKEA"; - case SSL3_ST_SR_KEY_EXCH_B: - return "3RCKEB"; - case SSL3_ST_SR_CERT_VRFY_A: return "3RCV_A"; - case SSL3_ST_SR_CERT_VRFY_B: - return "3RCV_B"; - /* DTLS */ case DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A: return "DRCHVA"; - case DTLS1_ST_CR_HELLO_VERIFY_REQUEST_B: - return "DRCHVB"; - default: return "UNKWN "; } @@ -558,6 +407,9 @@ const char *SSL_alert_desc_string_long(int value) { case TLS1_AD_INTERNAL_ERROR: return "internal error"; + case SSL3_AD_INAPPROPRIATE_FALLBACK: + return "inappropriate fallback"; + case TLS1_AD_USER_CANCELLED: return "user canceled"; @@ -582,8 +434,8 @@ const char *SSL_alert_desc_string_long(int value) { case TLS1_AD_UNKNOWN_PSK_IDENTITY: return "unknown PSK identity"; - case SSL3_AD_INAPPROPRIATE_FALLBACK: - return "inappropriate fallback"; + case TLS1_AD_CERTIFICATE_REQUIRED: + return "certificate required"; default: return "unknown"; diff --git a/Sources/BoringSSL/ssl/s3_enc.c b/Sources/BoringSSL/ssl/ssl_transcript.c similarity index 62% rename from Sources/BoringSSL/ssl/s3_enc.c rename to Sources/BoringSSL/ssl/ssl_transcript.c index a25877cab..9cc37778c 100644 --- a/Sources/BoringSSL/ssl/s3_enc.c +++ b/Sources/BoringSSL/ssl/ssl_transcript.c @@ -136,98 +136,24 @@ #include #include -#include #include +#include +#include #include -#include #include #include -#include +#include +#include +#include "../crypto/internal.h" #include "internal.h" -static int ssl3_handshake_mac(SSL *ssl, int md_nid, const char *sender, - size_t sender_len, uint8_t *p); - -static int ssl3_prf(const SSL *ssl, uint8_t *out, size_t out_len, - const uint8_t *secret, size_t secret_len, const char *label, - size_t label_len, const uint8_t *seed1, size_t seed1_len, - const uint8_t *seed2, size_t seed2_len) { - EVP_MD_CTX md5; - EVP_MD_CTX sha1; - uint8_t buf[16], smd[SHA_DIGEST_LENGTH]; - uint8_t c = 'A'; - size_t i, j, k; - - k = 0; - EVP_MD_CTX_init(&md5); - EVP_MD_CTX_init(&sha1); - for (i = 0; i < out_len; i += MD5_DIGEST_LENGTH) { - k++; - if (k > sizeof(buf)) { - /* bug: 'buf' is too small for this ciphersuite */ - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - return 0; - } - - for (j = 0; j < k; j++) { - buf[j] = c; - } - c++; - if (!EVP_DigestInit_ex(&sha1, EVP_sha1(), NULL)) { - OPENSSL_PUT_ERROR(SSL, ERR_LIB_EVP); - return 0; - } - EVP_DigestUpdate(&sha1, buf, k); - EVP_DigestUpdate(&sha1, secret, secret_len); - /* |label| is ignored for SSLv3. */ - if (seed1_len) { - EVP_DigestUpdate(&sha1, seed1, seed1_len); - } - if (seed2_len) { - EVP_DigestUpdate(&sha1, seed2, seed2_len); - } - EVP_DigestFinal_ex(&sha1, smd, NULL); - - if (!EVP_DigestInit_ex(&md5, EVP_md5(), NULL)) { - OPENSSL_PUT_ERROR(SSL, ERR_LIB_EVP); - return 0; - } - EVP_DigestUpdate(&md5, secret, secret_len); - EVP_DigestUpdate(&md5, smd, SHA_DIGEST_LENGTH); - if (i + MD5_DIGEST_LENGTH > out_len) { - EVP_DigestFinal_ex(&md5, smd, NULL); - memcpy(out, smd, out_len - i); - } else { - EVP_DigestFinal_ex(&md5, out, NULL); - } - - out += MD5_DIGEST_LENGTH; - } - - OPENSSL_cleanse(smd, SHA_DIGEST_LENGTH); - EVP_MD_CTX_cleanup(&md5); - EVP_MD_CTX_cleanup(&sha1); - - return 1; -} - -void ssl3_cleanup_key_block(SSL *ssl) { - if (ssl->s3->tmp.key_block != NULL) { - OPENSSL_cleanse(ssl->s3->tmp.key_block, ssl->s3->tmp.key_block_length); - OPENSSL_free(ssl->s3->tmp.key_block); - ssl->s3->tmp.key_block = NULL; - } - ssl->s3->tmp.key_block_length = 0; -} - -int ssl3_init_handshake_buffer(SSL *ssl) { - ssl3_free_handshake_buffer(ssl); - ssl3_free_handshake_hash(ssl); - ssl->s3->handshake_buffer = BUF_MEM_new(); - return ssl->s3->handshake_buffer != NULL; +int SSL_TRANSCRIPT_init(SSL_TRANSCRIPT *transcript) { + SSL_TRANSCRIPT_cleanup(transcript); + transcript->buffer = BUF_MEM_new(); + return transcript->buffer != NULL; } /* init_digest_with_data calls |EVP_DigestInit_ex| on |ctx| with |md| and then @@ -241,102 +167,113 @@ static int init_digest_with_data(EVP_MD_CTX *ctx, const EVP_MD *md, return 1; } -int ssl3_init_handshake_hash(SSL *ssl) { - ssl3_free_handshake_hash(ssl); +int SSL_TRANSCRIPT_init_hash(SSL_TRANSCRIPT *transcript, uint16_t version, + int algorithm_prf) { + const EVP_MD *md = ssl_get_handshake_digest(algorithm_prf, version); - uint32_t algorithm_prf = ssl_get_algorithm_prf(ssl); - if (!init_digest_with_data(&ssl->s3->handshake_hash, - ssl_get_handshake_digest(algorithm_prf), - ssl->s3->handshake_buffer)) { - return 0; + /* To support SSL 3.0's Finished and CertificateVerify constructions, + * EVP_md5_sha1() is split into MD5 and SHA-1 halves. When SSL 3.0 is removed, + * we can simplify this. */ + if (md == EVP_md5_sha1()) { + if (!init_digest_with_data(&transcript->md5, EVP_md5(), + transcript->buffer)) { + return 0; + } + md = EVP_sha1(); } - if (algorithm_prf == SSL_HANDSHAKE_MAC_DEFAULT && - !init_digest_with_data(&ssl->s3->handshake_md5, EVP_md5(), - ssl->s3->handshake_buffer)) { + if (!init_digest_with_data(&transcript->hash, md, transcript->buffer)) { return 0; } return 1; } -void ssl3_free_handshake_hash(SSL *ssl) { - EVP_MD_CTX_cleanup(&ssl->s3->handshake_hash); - EVP_MD_CTX_cleanup(&ssl->s3->handshake_md5); +void SSL_TRANSCRIPT_cleanup(SSL_TRANSCRIPT *transcript) { + SSL_TRANSCRIPT_free_buffer(transcript); + EVP_MD_CTX_cleanup(&transcript->hash); + EVP_MD_CTX_cleanup(&transcript->md5); } -void ssl3_free_handshake_buffer(SSL *ssl) { - BUF_MEM_free(ssl->s3->handshake_buffer); - ssl->s3->handshake_buffer = NULL; +void SSL_TRANSCRIPT_free_buffer(SSL_TRANSCRIPT *transcript) { + BUF_MEM_free(transcript->buffer); + transcript->buffer = NULL; } -int ssl3_update_handshake_hash(SSL *ssl, const uint8_t *in, size_t in_len) { +size_t SSL_TRANSCRIPT_digest_len(const SSL_TRANSCRIPT *transcript) { + return EVP_MD_size(SSL_TRANSCRIPT_md(transcript)); +} + +const EVP_MD *SSL_TRANSCRIPT_md(const SSL_TRANSCRIPT *transcript) { + if (EVP_MD_CTX_md(&transcript->md5) != NULL) { + return EVP_md5_sha1(); + } + return EVP_MD_CTX_md(&transcript->hash); +} + +int SSL_TRANSCRIPT_update(SSL_TRANSCRIPT *transcript, const uint8_t *in, + size_t in_len) { /* Depending on the state of the handshake, either the handshake buffer may be * active, the rolling hash, or both. */ - - if (ssl->s3->handshake_buffer != NULL) { - size_t new_len = ssl->s3->handshake_buffer->length + in_len; + if (transcript->buffer != NULL) { + size_t new_len = transcript->buffer->length + in_len; if (new_len < in_len) { OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW); return 0; } - if (!BUF_MEM_grow(ssl->s3->handshake_buffer, new_len)) { + if (!BUF_MEM_grow(transcript->buffer, new_len)) { return 0; } - memcpy(ssl->s3->handshake_buffer->data + new_len - in_len, in, in_len); + OPENSSL_memcpy(transcript->buffer->data + new_len - in_len, in, in_len); } - if (EVP_MD_CTX_md(&ssl->s3->handshake_hash) != NULL) { - EVP_DigestUpdate(&ssl->s3->handshake_hash, in, in_len); + if (EVP_MD_CTX_md(&transcript->hash) != NULL) { + EVP_DigestUpdate(&transcript->hash, in, in_len); } - if (EVP_MD_CTX_md(&ssl->s3->handshake_md5) != NULL) { - EVP_DigestUpdate(&ssl->s3->handshake_md5, in, in_len); + if (EVP_MD_CTX_md(&transcript->md5) != NULL) { + EVP_DigestUpdate(&transcript->md5, in, in_len); } - return 1; -} -static int ssl3_cert_verify_mac(SSL *ssl, int md_nid, uint8_t *p) { - return ssl3_handshake_mac(ssl, md_nid, NULL, 0, p); + return 1; } -static int ssl3_final_finish_mac(SSL *ssl, int from_server, uint8_t *out) { - const char *sender = from_server ? SSL3_MD_SERVER_FINISHED_CONST - : SSL3_MD_CLIENT_FINISHED_CONST; - const size_t sender_len = 4; - int ret, sha1len; - ret = ssl3_handshake_mac(ssl, NID_md5, sender, sender_len, out); - if (ret == 0) { - return 0; +int SSL_TRANSCRIPT_get_hash(const SSL_TRANSCRIPT *transcript, uint8_t *out, + size_t *out_len) { + int ret = 0; + EVP_MD_CTX ctx; + EVP_MD_CTX_init(&ctx); + unsigned md5_len = 0; + if (EVP_MD_CTX_md(&transcript->md5) != NULL) { + if (!EVP_MD_CTX_copy_ex(&ctx, &transcript->md5) || + !EVP_DigestFinal_ex(&ctx, out, &md5_len)) { + goto err; + } } - out += ret; - - sha1len = ssl3_handshake_mac(ssl, NID_sha1, sender, sender_len, out); - if (sha1len == 0) { - return 0; + unsigned len; + if (!EVP_MD_CTX_copy_ex(&ctx, &transcript->hash) || + !EVP_DigestFinal_ex(&ctx, out + md5_len, &len)) { + goto err; } - ret += sha1len; + *out_len = md5_len + len; + ret = 1; + +err: + EVP_MD_CTX_cleanup(&ctx); return ret; } -static int ssl3_handshake_mac(SSL *ssl, int md_nid, const char *sender, - size_t sender_len, uint8_t *p) { - unsigned int ret; +static int ssl3_handshake_mac(SSL_TRANSCRIPT *transcript, + const SSL_SESSION *session, + const EVP_MD_CTX *ctx_template, + const char *sender, size_t sender_len, + uint8_t *p, size_t *out_len) { + unsigned int len; size_t npad, n; unsigned int i; uint8_t md_buf[EVP_MAX_MD_SIZE]; EVP_MD_CTX ctx; - const EVP_MD_CTX *ctx_template; - - if (md_nid == NID_md5) { - ctx_template = &ssl->s3->handshake_md5; - } else if (md_nid == EVP_MD_CTX_type(&ssl->s3->handshake_hash)) { - ctx_template = &ssl->s3->handshake_hash; - } else { - OPENSSL_PUT_ERROR(SSL, SSL_R_NO_REQUIRED_DIGEST); - return 0; - } EVP_MD_CTX_init(&ctx); if (!EVP_MD_CTX_copy_ex(&ctx, ctx_template)) { @@ -365,8 +302,7 @@ static int ssl3_handshake_mac(SSL *ssl, int md_nid, const char *sender, if (sender != NULL) { EVP_DigestUpdate(&ctx, sender, sender_len); } - EVP_DigestUpdate(&ctx, ssl->session->master_key, - ssl->session->master_key_length); + EVP_DigestUpdate(&ctx, session->master_key, session->master_key_length); EVP_DigestUpdate(&ctx, kPad1, npad); EVP_DigestFinal_ex(&ctx, md_buf, &i); @@ -375,21 +311,95 @@ static int ssl3_handshake_mac(SSL *ssl, int md_nid, const char *sender, OPENSSL_PUT_ERROR(SSL, ERR_LIB_EVP); return 0; } - EVP_DigestUpdate(&ctx, ssl->session->master_key, - ssl->session->master_key_length); + EVP_DigestUpdate(&ctx, session->master_key, session->master_key_length); EVP_DigestUpdate(&ctx, kPad2, npad); EVP_DigestUpdate(&ctx, md_buf, i); - EVP_DigestFinal_ex(&ctx, p, &ret); + EVP_DigestFinal_ex(&ctx, p, &len); EVP_MD_CTX_cleanup(&ctx); - return ret; + *out_len = len; + return 1; +} + +int SSL_TRANSCRIPT_ssl3_cert_verify_hash(SSL_TRANSCRIPT *transcript, + uint8_t *out, size_t *out_len, + const SSL_SESSION *session, + int signature_algorithm) { + if (SSL_TRANSCRIPT_md(transcript) != EVP_md5_sha1()) { + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + return 0; + } + + if (signature_algorithm == SSL_SIGN_RSA_PKCS1_MD5_SHA1) { + size_t md5_len, len; + if (!ssl3_handshake_mac(transcript, session, &transcript->md5, NULL, 0, out, + &md5_len) || + !ssl3_handshake_mac(transcript, session, &transcript->hash, NULL, 0, + out + md5_len, &len)) { + return 0; + } + *out_len = md5_len + len; + return 1; + } + + if (signature_algorithm == SSL_SIGN_ECDSA_SHA1) { + return ssl3_handshake_mac(transcript, session, &transcript->hash, NULL, 0, + out, out_len); + } + + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + return 0; } +int SSL_TRANSCRIPT_finish_mac(SSL_TRANSCRIPT *transcript, uint8_t *out, + size_t *out_len, const SSL_SESSION *session, + int from_server, uint16_t version) { + if (version == SSL3_VERSION) { + if (SSL_TRANSCRIPT_md(transcript) != EVP_md5_sha1()) { + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + return 0; + } + + const char *sender = from_server ? SSL3_MD_SERVER_FINISHED_CONST + : SSL3_MD_CLIENT_FINISHED_CONST; + const size_t sender_len = 4; + size_t md5_len, len; + if (!ssl3_handshake_mac(transcript, session, &transcript->md5, sender, + sender_len, out, &md5_len) || + !ssl3_handshake_mac(transcript, session, &transcript->hash, sender, + sender_len, out + md5_len, &len)) { + return 0; + } + *out_len = md5_len + len; + return 1; + } -const SSL3_ENC_METHOD SSLv3_enc_data = { - ssl3_prf, - ssl3_final_finish_mac, - ssl3_cert_verify_mac, -}; + /* At this point, the handshake should have released the handshake buffer on + * its own. */ + assert(transcript->buffer == NULL); + + const char *label = TLS_MD_CLIENT_FINISH_CONST; + size_t label_len = TLS_MD_SERVER_FINISH_CONST_SIZE; + if (from_server) { + label = TLS_MD_SERVER_FINISH_CONST; + label_len = TLS_MD_SERVER_FINISH_CONST_SIZE; + } + + uint8_t digests[EVP_MAX_MD_SIZE]; + size_t digests_len; + if (!SSL_TRANSCRIPT_get_hash(transcript, digests, &digests_len)) { + return 0; + } + + static const size_t kFinishedLen = 12; + if (!tls1_prf(SSL_TRANSCRIPT_md(transcript), out, kFinishedLen, + session->master_key, session->master_key_length, label, + label_len, digests, digests_len, NULL, 0)) { + return 0; + } + + *out_len = kFinishedLen; + return 1; +} diff --git a/Sources/BoringSSL/ssl/ssl_x509.c b/Sources/BoringSSL/ssl/ssl_x509.c new file mode 100644 index 000000000..2955c2137 --- /dev/null +++ b/Sources/BoringSSL/ssl/ssl_x509.c @@ -0,0 +1,815 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright (c) 1998-2007 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * ECC cipher suite support in OpenSSL originally developed by + * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project. + */ +/* ==================================================================== + * Copyright 2005 Nokia. All rights reserved. + * + * The portions of the attached software ("Contribution") is developed by + * Nokia Corporation and is licensed pursuant to the OpenSSL open source + * license. + * + * The Contribution, originally written by Mika Kousa and Pasi Eronen of + * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites + * support (see RFC 4279) to OpenSSL. + * + * No patent licenses or other rights except those expressly stated in + * the OpenSSL open source license shall be deemed granted or received + * expressly, by implication, estoppel, or otherwise. + * + * No assurances are provided by Nokia that the Contribution does not + * infringe the patent or other intellectual property rights of any third + * party or that the license provides you with all the necessary rights + * to make use of the Contribution. + * + * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN + * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA + * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY + * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR + * OTHERWISE. */ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "internal.h" + + +X509 *SSL_get_peer_certificate(const SSL *ssl) { + if (ssl == NULL) { + return NULL; + } + SSL_SESSION *session = SSL_get_session(ssl); + if (session == NULL || session->x509_peer == NULL) { + return NULL; + } + X509_up_ref(session->x509_peer); + return session->x509_peer; +} + +STACK_OF(X509) *SSL_get_peer_cert_chain(const SSL *ssl) { + if (ssl == NULL) { + return NULL; + } + SSL_SESSION *session = SSL_get_session(ssl); + if (session == NULL || + session->x509_chain == NULL) { + return NULL; + } + + if (!ssl->server) { + return session->x509_chain; + } + + /* OpenSSL historically didn't include the leaf certificate in the returned + * certificate chain, but only for servers. */ + if (session->x509_chain_without_leaf == NULL) { + session->x509_chain_without_leaf = sk_X509_new_null(); + if (session->x509_chain_without_leaf == NULL) { + return NULL; + } + + for (size_t i = 1; i < sk_X509_num(session->x509_chain); i++) { + X509 *cert = sk_X509_value(session->x509_chain, i); + if (!sk_X509_push(session->x509_chain_without_leaf, cert)) { + sk_X509_pop_free(session->x509_chain_without_leaf, X509_free); + session->x509_chain_without_leaf = NULL; + return NULL; + } + X509_up_ref(cert); + } + } + + return session->x509_chain_without_leaf; +} + +STACK_OF(X509) *SSL_get_peer_full_cert_chain(const SSL *ssl) { + SSL_SESSION *session = SSL_get_session(ssl); + if (session == NULL) { + return NULL; + } + + return session->x509_chain; +} + +int SSL_CTX_set_purpose(SSL_CTX *ctx, int purpose) { + return X509_VERIFY_PARAM_set_purpose(ctx->param, purpose); +} + +int SSL_set_purpose(SSL *ssl, int purpose) { + return X509_VERIFY_PARAM_set_purpose(ssl->param, purpose); +} + +int SSL_CTX_set_trust(SSL_CTX *ctx, int trust) { + return X509_VERIFY_PARAM_set_trust(ctx->param, trust); +} + +int SSL_set_trust(SSL *ssl, int trust) { + return X509_VERIFY_PARAM_set_trust(ssl->param, trust); +} + +int SSL_CTX_set1_param(SSL_CTX *ctx, const X509_VERIFY_PARAM *param) { + return X509_VERIFY_PARAM_set1(ctx->param, param); +} + +int SSL_set1_param(SSL *ssl, const X509_VERIFY_PARAM *param) { + return X509_VERIFY_PARAM_set1(ssl->param, param); +} + +X509_VERIFY_PARAM *SSL_CTX_get0_param(SSL_CTX *ctx) { return ctx->param; } + +X509_VERIFY_PARAM *SSL_get0_param(SSL *ssl) { return ssl->param; } + +int SSL_get_verify_depth(const SSL *ssl) { + return X509_VERIFY_PARAM_get_depth(ssl->param); +} + +int (*SSL_get_verify_callback(const SSL *ssl))(int, X509_STORE_CTX *) { + return ssl->verify_callback; +} + +int SSL_CTX_get_verify_mode(const SSL_CTX *ctx) { return ctx->verify_mode; } + +int SSL_CTX_get_verify_depth(const SSL_CTX *ctx) { + return X509_VERIFY_PARAM_get_depth(ctx->param); +} + +int (*SSL_CTX_get_verify_callback(const SSL_CTX *ctx))( + int ok, X509_STORE_CTX *store_ctx) { + return ctx->default_verify_callback; +} + +void SSL_set_verify(SSL *ssl, int mode, + int (*callback)(int ok, X509_STORE_CTX *store_ctx)) { + ssl->verify_mode = mode; + if (callback != NULL) { + ssl->verify_callback = callback; + } +} + +void SSL_set_verify_depth(SSL *ssl, int depth) { + X509_VERIFY_PARAM_set_depth(ssl->param, depth); +} + +void SSL_CTX_set_cert_verify_callback(SSL_CTX *ctx, + int (*cb)(X509_STORE_CTX *store_ctx, + void *arg), + void *arg) { + ctx->app_verify_callback = cb; + ctx->app_verify_arg = arg; +} + +void SSL_CTX_set_verify(SSL_CTX *ctx, int mode, + int (*cb)(int, X509_STORE_CTX *)) { + ctx->verify_mode = mode; + ctx->default_verify_callback = cb; +} + +void SSL_CTX_set_verify_depth(SSL_CTX *ctx, int depth) { + X509_VERIFY_PARAM_set_depth(ctx->param, depth); +} + +int SSL_CTX_set_default_verify_paths(SSL_CTX *ctx) { + return X509_STORE_set_default_paths(ctx->cert_store); +} + +int SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *ca_file, + const char *ca_dir) { + return X509_STORE_load_locations(ctx->cert_store, ca_file, ca_dir); +} + +void SSL_set_verify_result(SSL *ssl, long result) { + if (result != X509_V_OK) { + abort(); + } +} + +long SSL_get_verify_result(const SSL *ssl) { + SSL_SESSION *session = SSL_get_session(ssl); + if (session == NULL) { + return X509_V_ERR_INVALID_CALL; + } + return session->verify_result; +} + +X509_STORE *SSL_CTX_get_cert_store(const SSL_CTX *ctx) { + return ctx->cert_store; +} + +void SSL_CTX_set_cert_store(SSL_CTX *ctx, X509_STORE *store) { + X509_STORE_free(ctx->cert_store); + ctx->cert_store = store; +} + +static void ssl_crypto_x509_flush_cached_leaf(CERT *cert) { + X509_free(cert->x509_leaf); + cert->x509_leaf = NULL; +} + +static void ssl_crypto_x509_flush_cached_chain(CERT *cert) { + sk_X509_pop_free(cert->x509_chain, X509_free); + cert->x509_chain = NULL; +} + +static void ssl_crypto_x509_clear(CERT *cert) { + ssl_crypto_x509_flush_cached_leaf(cert); + ssl_crypto_x509_flush_cached_chain(cert); + + X509_free(cert->x509_stash); + cert->x509_stash = NULL; +} + +static int ssl_crypto_x509_session_cache_objects(SSL_SESSION *sess) { + STACK_OF(X509) *chain = NULL; + const size_t num_certs = sk_CRYPTO_BUFFER_num(sess->certs); + + if (num_certs > 0) { + chain = sk_X509_new_null(); + if (chain == NULL) { + OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + goto err; + } + } + + X509 *leaf = NULL; + for (size_t i = 0; i < num_certs; i++) { + X509 *x509 = X509_parse_from_buffer(sk_CRYPTO_BUFFER_value(sess->certs, i)); + if (x509 == NULL) { + OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + goto err; + } + if (!sk_X509_push(chain, x509)) { + OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + X509_free(x509); + goto err; + } + if (i == 0) { + leaf = x509; + } + } + + sk_X509_pop_free(sess->x509_chain, X509_free); + sess->x509_chain = chain; + sk_X509_pop_free(sess->x509_chain_without_leaf, X509_free); + sess->x509_chain_without_leaf = NULL; + + X509_free(sess->x509_peer); + if (leaf != NULL) { + X509_up_ref(leaf); + } + sess->x509_peer = leaf; + + return 1; + +err: + sk_X509_pop_free(chain, X509_free); + return 0; +} + +static int ssl_crypto_x509_session_dup(SSL_SESSION *new_session, + const SSL_SESSION *session) { + if (session->x509_peer != NULL) { + X509_up_ref(session->x509_peer); + new_session->x509_peer = session->x509_peer; + } + if (session->x509_chain != NULL) { + new_session->x509_chain = X509_chain_up_ref(session->x509_chain); + if (new_session->x509_chain == NULL) { + return 0; + } + } + + return 1; +} + +static void ssl_crypto_x509_session_clear(SSL_SESSION *session) { + X509_free(session->x509_peer); + session->x509_peer = NULL; + sk_X509_pop_free(session->x509_chain, X509_free); + session->x509_chain = NULL; + sk_X509_pop_free(session->x509_chain_without_leaf, X509_free); + session->x509_chain_without_leaf = NULL; +} + +const SSL_X509_METHOD ssl_crypto_x509_method = { + ssl_crypto_x509_clear, + ssl_crypto_x509_flush_cached_chain, + ssl_crypto_x509_flush_cached_leaf, + ssl_crypto_x509_session_cache_objects, + ssl_crypto_x509_session_dup, + ssl_crypto_x509_session_clear, +}; + +/* x509_to_buffer returns a |CRYPTO_BUFFER| that contains the serialised + * contents of |x509|. */ +static CRYPTO_BUFFER *x509_to_buffer(X509 *x509) { + uint8_t *buf = NULL; + int cert_len = i2d_X509(x509, &buf); + if (cert_len <= 0) { + return 0; + } + + CRYPTO_BUFFER *buffer = CRYPTO_BUFFER_new(buf, cert_len, NULL); + OPENSSL_free(buf); + + return buffer; +} + +static int ssl_use_certificate(CERT *cert, X509 *x) { + if (x == NULL) { + OPENSSL_PUT_ERROR(SSL, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + + CRYPTO_BUFFER *buffer = x509_to_buffer(x); + if (buffer == NULL) { + return 0; + } + + const int ok = ssl_set_cert(cert, buffer); + CRYPTO_BUFFER_free(buffer); + return ok; +} + +int SSL_use_certificate(SSL *ssl, X509 *x) { + return ssl_use_certificate(ssl->cert, x); +} + +int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x) { + return ssl_use_certificate(ctx->cert, x); +} + +/* ssl_cert_cache_leaf_cert sets |cert->x509_leaf|, if currently NULL, from the + * first element of |cert->chain|. */ +static int ssl_cert_cache_leaf_cert(CERT *cert) { + assert(cert->x509_method); + + if (cert->x509_leaf != NULL || + cert->chain == NULL) { + return 1; + } + + CRYPTO_BUFFER *leaf = sk_CRYPTO_BUFFER_value(cert->chain, 0); + if (!leaf) { + return 1; + } + + cert->x509_leaf = X509_parse_from_buffer(leaf); + return cert->x509_leaf != NULL; +} + +static X509 *ssl_cert_get0_leaf(CERT *cert) { + if (cert->x509_leaf == NULL && + !ssl_cert_cache_leaf_cert(cert)) { + return NULL; + } + + return cert->x509_leaf; +} + +X509 *SSL_get_certificate(const SSL *ssl) { + return ssl_cert_get0_leaf(ssl->cert); +} + +X509 *SSL_CTX_get0_certificate(const SSL_CTX *ctx) { + return ssl_cert_get0_leaf(ctx->cert); +} + +/* new_leafless_chain returns a fresh stack of buffers set to {NULL}. */ +static STACK_OF(CRYPTO_BUFFER) *new_leafless_chain(void) { + STACK_OF(CRYPTO_BUFFER) *chain = sk_CRYPTO_BUFFER_new_null(); + if (chain == NULL) { + return NULL; + } + + if (!sk_CRYPTO_BUFFER_push(chain, NULL)) { + sk_CRYPTO_BUFFER_free(chain); + return NULL; + } + + return chain; +} + +/* ssl_cert_set_chain sets elements 1.. of |cert->chain| to the serialised + * forms of elements of |chain|. It returns one on success or zero on error, in + * which case no change to |cert->chain| is made. It preverses the existing + * leaf from |cert->chain|, if any. */ +static int ssl_cert_set_chain(CERT *cert, STACK_OF(X509) *chain) { + STACK_OF(CRYPTO_BUFFER) *new_chain = NULL; + + if (cert->chain != NULL) { + new_chain = sk_CRYPTO_BUFFER_new_null(); + if (new_chain == NULL) { + return 0; + } + + CRYPTO_BUFFER *leaf = sk_CRYPTO_BUFFER_value(cert->chain, 0); + if (!sk_CRYPTO_BUFFER_push(new_chain, leaf)) { + goto err; + } + /* |leaf| might be NULL if it's a “leafless” chain. */ + if (leaf != NULL) { + CRYPTO_BUFFER_up_ref(leaf); + } + } + + for (size_t i = 0; i < sk_X509_num(chain); i++) { + if (new_chain == NULL) { + new_chain = new_leafless_chain(); + if (new_chain == NULL) { + goto err; + } + } + + CRYPTO_BUFFER *buffer = x509_to_buffer(sk_X509_value(chain, i)); + if (buffer == NULL || + !sk_CRYPTO_BUFFER_push(new_chain, buffer)) { + CRYPTO_BUFFER_free(buffer); + goto err; + } + } + + sk_CRYPTO_BUFFER_pop_free(cert->chain, CRYPTO_BUFFER_free); + cert->chain = new_chain; + + return 1; + +err: + sk_CRYPTO_BUFFER_pop_free(new_chain, CRYPTO_BUFFER_free); + return 0; +} + +static int ssl_cert_set0_chain(CERT *cert, STACK_OF(X509) *chain) { + if (!ssl_cert_set_chain(cert, chain)) { + return 0; + } + + sk_X509_pop_free(chain, X509_free); + ssl_crypto_x509_flush_cached_chain(cert); + return 1; +} + +static int ssl_cert_set1_chain(CERT *cert, STACK_OF(X509) *chain) { + if (!ssl_cert_set_chain(cert, chain)) { + return 0; + } + + ssl_crypto_x509_flush_cached_chain(cert); + return 1; +} + +static int ssl_cert_append_cert(CERT *cert, X509 *x509) { + assert(cert->x509_method); + + CRYPTO_BUFFER *buffer = x509_to_buffer(x509); + if (buffer == NULL) { + return 0; + } + + if (cert->chain != NULL) { + if (!sk_CRYPTO_BUFFER_push(cert->chain, buffer)) { + CRYPTO_BUFFER_free(buffer); + return 0; + } + + return 1; + } + + cert->chain = new_leafless_chain(); + if (cert->chain == NULL || + !sk_CRYPTO_BUFFER_push(cert->chain, buffer)) { + CRYPTO_BUFFER_free(buffer); + sk_CRYPTO_BUFFER_free(cert->chain); + cert->chain = NULL; + return 0; + } + + return 1; +} + +static int ssl_cert_add0_chain_cert(CERT *cert, X509 *x509) { + if (!ssl_cert_append_cert(cert, x509)) { + return 0; + } + + X509_free(cert->x509_stash); + cert->x509_stash = x509; + ssl_crypto_x509_flush_cached_chain(cert); + return 1; +} + +static int ssl_cert_add1_chain_cert(CERT *cert, X509 *x509) { + if (!ssl_cert_append_cert(cert, x509)) { + return 0; + } + + ssl_crypto_x509_flush_cached_chain(cert); + return 1; +} + +int SSL_CTX_set0_chain(SSL_CTX *ctx, STACK_OF(X509) *chain) { + return ssl_cert_set0_chain(ctx->cert, chain); +} + +int SSL_CTX_set1_chain(SSL_CTX *ctx, STACK_OF(X509) *chain) { + return ssl_cert_set1_chain(ctx->cert, chain); +} + +int SSL_set0_chain(SSL *ssl, STACK_OF(X509) *chain) { + return ssl_cert_set0_chain(ssl->cert, chain); +} + +int SSL_set1_chain(SSL *ssl, STACK_OF(X509) *chain) { + return ssl_cert_set1_chain(ssl->cert, chain); +} + +int SSL_CTX_add0_chain_cert(SSL_CTX *ctx, X509 *x509) { + return ssl_cert_add0_chain_cert(ctx->cert, x509); +} + +int SSL_CTX_add1_chain_cert(SSL_CTX *ctx, X509 *x509) { + return ssl_cert_add1_chain_cert(ctx->cert, x509); +} + +int SSL_CTX_add_extra_chain_cert(SSL_CTX *ctx, X509 *x509) { + return SSL_CTX_add0_chain_cert(ctx, x509); +} + +int SSL_add0_chain_cert(SSL *ssl, X509 *x509) { + return ssl_cert_add0_chain_cert(ssl->cert, x509); +} + +int SSL_add1_chain_cert(SSL *ssl, X509 *x509) { + return ssl_cert_add1_chain_cert(ssl->cert, x509); +} + +int SSL_CTX_clear_chain_certs(SSL_CTX *ctx) { + return SSL_CTX_set0_chain(ctx, NULL); +} + +int SSL_CTX_clear_extra_chain_certs(SSL_CTX *ctx) { + return SSL_CTX_clear_chain_certs(ctx); +} + +int SSL_clear_chain_certs(SSL *ssl) { + return SSL_set0_chain(ssl, NULL); +} + +int ssl_auto_chain_if_needed(SSL *ssl) { + /* Only build a chain if there are no intermediates configured and the feature + * isn't disabled. */ + if ((ssl->mode & SSL_MODE_NO_AUTO_CHAIN) || + !ssl_has_certificate(ssl) || + ssl->cert->chain == NULL || + sk_CRYPTO_BUFFER_num(ssl->cert->chain) > 1) { + return 1; + } + + X509 *leaf = + X509_parse_from_buffer(sk_CRYPTO_BUFFER_value(ssl->cert->chain, 0)); + if (!leaf) { + OPENSSL_PUT_ERROR(SSL, ERR_R_X509_LIB); + return 0; + } + + X509_STORE_CTX ctx; + if (!X509_STORE_CTX_init(&ctx, ssl->ctx->cert_store, leaf, NULL)) { + X509_free(leaf); + OPENSSL_PUT_ERROR(SSL, ERR_R_X509_LIB); + return 0; + } + + /* Attempt to build a chain, ignoring the result. */ + X509_verify_cert(&ctx); + X509_free(leaf); + ERR_clear_error(); + + /* Remove the leaf from the generated chain. */ + X509_free(sk_X509_shift(ctx.chain)); + + const int ok = ssl_cert_set_chain(ssl->cert, ctx.chain); + X509_STORE_CTX_cleanup(&ctx); + if (!ok) { + return 0; + } + + ssl_crypto_x509_flush_cached_chain(ssl->cert); + + return 1; +} + +/* ssl_cert_cache_chain_certs fills in |cert->x509_chain| from elements 1.. of + * |cert->chain|. */ +static int ssl_cert_cache_chain_certs(CERT *cert) { + assert(cert->x509_method); + + if (cert->x509_chain != NULL || + cert->chain == NULL || + sk_CRYPTO_BUFFER_num(cert->chain) < 2) { + return 1; + } + + STACK_OF(X509) *chain = sk_X509_new_null(); + if (chain == NULL) { + return 0; + } + + for (size_t i = 1; i < sk_CRYPTO_BUFFER_num(cert->chain); i++) { + CRYPTO_BUFFER *buffer = sk_CRYPTO_BUFFER_value(cert->chain, i); + X509 *x509 = X509_parse_from_buffer(buffer); + if (x509 == NULL || + !sk_X509_push(chain, x509)) { + X509_free(x509); + goto err; + } + } + + cert->x509_chain = chain; + return 1; + +err: + sk_X509_pop_free(chain, X509_free); + return 0; +} + +int SSL_CTX_get0_chain_certs(const SSL_CTX *ctx, STACK_OF(X509) **out_chain) { + if (!ssl_cert_cache_chain_certs(ctx->cert)) { + *out_chain = NULL; + return 0; + } + + *out_chain = ctx->cert->x509_chain; + return 1; +} + +int SSL_CTX_get_extra_chain_certs(const SSL_CTX *ctx, + STACK_OF(X509) **out_chain) { + return SSL_CTX_get0_chain_certs(ctx, out_chain); +} + +int SSL_get0_chain_certs(const SSL *ssl, STACK_OF(X509) **out_chain) { + if (!ssl_cert_cache_chain_certs(ssl->cert)) { + *out_chain = NULL; + return 0; + } + + *out_chain = ssl->cert->x509_chain; + return 1; +} + +static SSL_SESSION *ssl_session_new_with_crypto_x509(void) { + return ssl_session_new(&ssl_crypto_x509_method); +} + +SSL_SESSION *d2i_SSL_SESSION_bio(BIO *bio, SSL_SESSION **out) { + return ASN1_d2i_bio_of(SSL_SESSION, ssl_session_new_with_crypto_x509, + d2i_SSL_SESSION, bio, out); +} + +int i2d_SSL_SESSION_bio(BIO *bio, const SSL_SESSION *session) { + return ASN1_i2d_bio_of(SSL_SESSION, i2d_SSL_SESSION, bio, session); +} + +IMPLEMENT_PEM_rw(SSL_SESSION, SSL_SESSION, PEM_STRING_SSL_SESSION, SSL_SESSION) + +SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const uint8_t **pp, long length) { + if (length < 0) { + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + return NULL; + } + + CBS cbs; + CBS_init(&cbs, *pp, length); + + SSL_SESSION *ret = SSL_SESSION_parse(&cbs, &ssl_crypto_x509_method, + NULL /* no buffer pool */); + if (ret == NULL) { + return NULL; + } + + if (a) { + SSL_SESSION_free(*a); + *a = ret; + } + *pp = CBS_data(&cbs); + return ret; +} diff --git a/Sources/BoringSSL/ssl/t1_enc.c b/Sources/BoringSSL/ssl/t1_enc.c index 216514dc4..9f11e0566 100644 --- a/Sources/BoringSSL/ssl/t1_enc.c +++ b/Sources/BoringSSL/ssl/t1_enc.c @@ -136,7 +136,6 @@ #include #include -#include #include #include @@ -144,9 +143,10 @@ #include #include #include -#include +#include #include +#include "../crypto/internal.h" #include "internal.h" @@ -224,18 +224,17 @@ static int tls1_P_hash(uint8_t *out, size_t out_len, const EVP_MD *md, return ret; } -static int tls1_prf(const SSL *ssl, uint8_t *out, size_t out_len, - const uint8_t *secret, size_t secret_len, const char *label, - size_t label_len, const uint8_t *seed1, size_t seed1_len, - const uint8_t *seed2, size_t seed2_len) { +int tls1_prf(const EVP_MD *digest, uint8_t *out, size_t out_len, + const uint8_t *secret, size_t secret_len, const char *label, + size_t label_len, const uint8_t *seed1, size_t seed1_len, + const uint8_t *seed2, size_t seed2_len) { if (out_len == 0) { return 1; } - memset(out, 0, out_len); + OPENSSL_memset(out, 0, out_len); - uint32_t algorithm_prf = ssl_get_algorithm_prf(ssl); - if (algorithm_prf == SSL_HANDSHAKE_MAC_DEFAULT) { + if (digest == EVP_md5_sha1()) { /* If using the MD5/SHA1 PRF, |secret| is partitioned between SHA-1 and * MD5, MD5 first. */ size_t secret_half = secret_len - (secret_len / 2); @@ -248,104 +247,98 @@ static int tls1_prf(const SSL *ssl, uint8_t *out, size_t out_len, /* Note that, if |secret_len| is odd, the two halves share a byte. */ secret = secret + (secret_len - secret_half); secret_len = secret_half; + + digest = EVP_sha1(); } - if (!tls1_P_hash(out, out_len, ssl_get_handshake_digest(algorithm_prf), - secret, secret_len, (const uint8_t *)label, label_len, - seed1, seed1_len, seed2, seed2_len)) { + if (!tls1_P_hash(out, out_len, digest, secret, secret_len, + (const uint8_t *)label, label_len, seed1, seed1_len, seed2, + seed2_len)) { return 0; } return 1; } -int tls1_change_cipher_state(SSL *ssl, int which) { - /* Ensure the key block is set up. */ - if (!tls1_setup_key_block(ssl)) { - return 0; - } - - /* is_read is true if we have just read a ChangeCipherSpec message - i.e. we - * need to update the read cipherspec. Otherwise we have just written one. */ - const char is_read = (which & SSL3_CC_READ) != 0; - /* use_client_keys is true if we wish to use the keys for the "client write" - * direction. This is the case if we're a client sending a ChangeCipherSpec, - * or a server reading a client's ChangeCipherSpec. */ - const char use_client_keys = which == SSL3_CHANGE_CIPHER_CLIENT_WRITE || - which == SSL3_CHANGE_CIPHER_SERVER_READ; +static int ssl3_prf(uint8_t *out, size_t out_len, const uint8_t *secret, + size_t secret_len, const char *label, size_t label_len, + const uint8_t *seed1, size_t seed1_len, + const uint8_t *seed2, size_t seed2_len) { + EVP_MD_CTX md5; + EVP_MD_CTX sha1; + uint8_t buf[16], smd[SHA_DIGEST_LENGTH]; + uint8_t c = 'A'; + size_t i, j, k; + + k = 0; + EVP_MD_CTX_init(&md5); + EVP_MD_CTX_init(&sha1); + for (i = 0; i < out_len; i += MD5_DIGEST_LENGTH) { + k++; + if (k > sizeof(buf)) { + /* bug: 'buf' is too small for this ciphersuite */ + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + return 0; + } - size_t mac_secret_len = ssl->s3->tmp.new_mac_secret_len; - size_t key_len = ssl->s3->tmp.new_key_len; - size_t iv_len = ssl->s3->tmp.new_fixed_iv_len; - assert((mac_secret_len + key_len + iv_len) * 2 == - ssl->s3->tmp.key_block_length); + for (j = 0; j < k; j++) { + buf[j] = c; + } + c++; + if (!EVP_DigestInit_ex(&sha1, EVP_sha1(), NULL)) { + OPENSSL_PUT_ERROR(SSL, ERR_LIB_EVP); + return 0; + } + EVP_DigestUpdate(&sha1, buf, k); + EVP_DigestUpdate(&sha1, secret, secret_len); + /* |label| is ignored for SSLv3. */ + if (seed1_len) { + EVP_DigestUpdate(&sha1, seed1, seed1_len); + } + if (seed2_len) { + EVP_DigestUpdate(&sha1, seed2, seed2_len); + } + EVP_DigestFinal_ex(&sha1, smd, NULL); - const uint8_t *key_data = ssl->s3->tmp.key_block; - const uint8_t *client_write_mac_secret = key_data; - key_data += mac_secret_len; - const uint8_t *server_write_mac_secret = key_data; - key_data += mac_secret_len; - const uint8_t *client_write_key = key_data; - key_data += key_len; - const uint8_t *server_write_key = key_data; - key_data += key_len; - const uint8_t *client_write_iv = key_data; - key_data += iv_len; - const uint8_t *server_write_iv = key_data; - key_data += iv_len; + if (!EVP_DigestInit_ex(&md5, EVP_md5(), NULL)) { + OPENSSL_PUT_ERROR(SSL, ERR_LIB_EVP); + return 0; + } + EVP_DigestUpdate(&md5, secret, secret_len); + EVP_DigestUpdate(&md5, smd, SHA_DIGEST_LENGTH); + if (i + MD5_DIGEST_LENGTH > out_len) { + EVP_DigestFinal_ex(&md5, smd, NULL); + OPENSSL_memcpy(out, smd, out_len - i); + } else { + EVP_DigestFinal_ex(&md5, out, NULL); + } - const uint8_t *mac_secret, *key, *iv; - if (use_client_keys) { - mac_secret = client_write_mac_secret; - key = client_write_key; - iv = client_write_iv; - } else { - mac_secret = server_write_mac_secret; - key = server_write_key; - iv = server_write_iv; + out += MD5_DIGEST_LENGTH; } - SSL_AEAD_CTX *aead_ctx = - SSL_AEAD_CTX_new(is_read ? evp_aead_open : evp_aead_seal, - ssl3_protocol_version(ssl), ssl->s3->tmp.new_cipher, key, - key_len, mac_secret, mac_secret_len, iv, iv_len); - if (aead_ctx == NULL) { - return 0; - } + OPENSSL_cleanse(smd, SHA_DIGEST_LENGTH); + EVP_MD_CTX_cleanup(&md5); + EVP_MD_CTX_cleanup(&sha1); - if (is_read) { - ssl_set_read_state(ssl, aead_ctx); - } else { - ssl_set_write_state(ssl, aead_ctx); - } return 1; } -size_t SSL_get_key_block_len(const SSL *ssl) { - return 2 * ((size_t)ssl->s3->tmp.new_mac_secret_len + - (size_t)ssl->s3->tmp.new_key_len + - (size_t)ssl->s3->tmp.new_fixed_iv_len); -} - -int SSL_generate_key_block(const SSL *ssl, uint8_t *out, size_t out_len) { - return ssl->s3->enc_method->prf( - ssl, out, out_len, ssl->session->master_key, - ssl->session->master_key_length, TLS_MD_KEY_EXPANSION_CONST, - TLS_MD_KEY_EXPANSION_CONST_SIZE, ssl->s3->server_random, SSL3_RANDOM_SIZE, - ssl->s3->client_random, SSL3_RANDOM_SIZE); -} - -int tls1_setup_key_block(SSL *ssl) { - if (ssl->s3->tmp.key_block_length != 0) { +static int tls1_setup_key_block(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + if (hs->key_block_len != 0) { return 1; } + SSL_SESSION *session = ssl->session; + if (hs->new_session != NULL) { + session = hs->new_session; + } + const EVP_AEAD *aead = NULL; size_t mac_secret_len, fixed_iv_len; - if (ssl->session->cipher == NULL || + if (session->cipher == NULL || !ssl_cipher_get_evp_aead(&aead, &mac_secret_len, &fixed_iv_len, - ssl->session->cipher, - ssl3_protocol_version(ssl))) { + session->cipher, ssl3_protocol_version(ssl))) { OPENSSL_PUT_ERROR(SSL, SSL_R_CIPHER_OR_HASH_UNAVAILABLE); return 0; } @@ -371,8 +364,6 @@ int tls1_setup_key_block(SSL *ssl) { size_t key_block_len = SSL_get_key_block_len(ssl); - ssl3_cleanup_key_block(ssl); - uint8_t *keyblock = OPENSSL_malloc(key_block_len); if (keyblock == NULL) { OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); @@ -385,133 +376,130 @@ int tls1_setup_key_block(SSL *ssl) { } assert(key_block_len < 256); - ssl->s3->tmp.key_block_length = (uint8_t)key_block_len; - ssl->s3->tmp.key_block = keyblock; + hs->key_block_len = (uint8_t)key_block_len; + hs->key_block = keyblock; return 1; } -static int tls1_cert_verify_mac(SSL *ssl, int md_nid, uint8_t *out) { - const EVP_MD_CTX *ctx_template; - if (md_nid == NID_md5) { - ctx_template = &ssl->s3->handshake_md5; - } else if (md_nid == EVP_MD_CTX_type(&ssl->s3->handshake_hash)) { - ctx_template = &ssl->s3->handshake_hash; - } else { - OPENSSL_PUT_ERROR(SSL, SSL_R_NO_REQUIRED_DIGEST); - return 0; - } - - EVP_MD_CTX ctx; - EVP_MD_CTX_init(&ctx); - if (!EVP_MD_CTX_copy_ex(&ctx, ctx_template)) { - EVP_MD_CTX_cleanup(&ctx); +int tls1_change_cipher_state(SSL_HANDSHAKE *hs, int which) { + SSL *const ssl = hs->ssl; + /* Ensure the key block is set up. */ + if (!tls1_setup_key_block(hs)) { return 0; } - unsigned ret; - EVP_DigestFinal_ex(&ctx, out, &ret); - EVP_MD_CTX_cleanup(&ctx); - return ret; -} -static int append_digest(const EVP_MD_CTX *ctx, uint8_t *out, size_t *out_len, - size_t max_out) { - int ret = 0; - EVP_MD_CTX ctx_copy; - EVP_MD_CTX_init(&ctx_copy); + /* is_read is true if we have just read a ChangeCipherSpec message - i.e. we + * need to update the read cipherspec. Otherwise we have just written one. */ + const char is_read = (which & SSL3_CC_READ) != 0; + /* use_client_keys is true if we wish to use the keys for the "client write" + * direction. This is the case if we're a client sending a ChangeCipherSpec, + * or a server reading a client's ChangeCipherSpec. */ + const char use_client_keys = which == SSL3_CHANGE_CIPHER_CLIENT_WRITE || + which == SSL3_CHANGE_CIPHER_SERVER_READ; - if (EVP_MD_CTX_size(ctx) > max_out) { - OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFER_TOO_SMALL); - goto err; - } - unsigned len; - if (!EVP_MD_CTX_copy_ex(&ctx_copy, ctx) || - !EVP_DigestFinal_ex(&ctx_copy, out, &len)) { - goto err; - } - assert(len == EVP_MD_CTX_size(ctx)); + size_t mac_secret_len = ssl->s3->tmp.new_mac_secret_len; + size_t key_len = ssl->s3->tmp.new_key_len; + size_t iv_len = ssl->s3->tmp.new_fixed_iv_len; + assert((mac_secret_len + key_len + iv_len) * 2 == hs->key_block_len); - *out_len = len; - ret = 1; + const uint8_t *key_data = hs->key_block; + const uint8_t *client_write_mac_secret = key_data; + key_data += mac_secret_len; + const uint8_t *server_write_mac_secret = key_data; + key_data += mac_secret_len; + const uint8_t *client_write_key = key_data; + key_data += key_len; + const uint8_t *server_write_key = key_data; + key_data += key_len; + const uint8_t *client_write_iv = key_data; + key_data += iv_len; + const uint8_t *server_write_iv = key_data; + key_data += iv_len; -err: - EVP_MD_CTX_cleanup(&ctx_copy); - return ret; -} + const uint8_t *mac_secret, *key, *iv; + if (use_client_keys) { + mac_secret = client_write_mac_secret; + key = client_write_key; + iv = client_write_iv; + } else { + mac_secret = server_write_mac_secret; + key = server_write_key; + iv = server_write_iv; + } -/* tls1_handshake_digest calculates the current handshake hash and writes it to - * |out|, which has space for |out_len| bytes. It returns the number of bytes - * written or -1 in the event of an error. This function works on a copy of the - * underlying digests so can be called multiple times and prior to the final - * update etc. */ -int tls1_handshake_digest(SSL *ssl, uint8_t *out, size_t out_len) { - size_t md5_len = 0; - if (EVP_MD_CTX_md(&ssl->s3->handshake_md5) != NULL && - !append_digest(&ssl->s3->handshake_md5, out, &md5_len, out_len)) { - return -1; + SSL_AEAD_CTX *aead_ctx = SSL_AEAD_CTX_new( + is_read ? evp_aead_open : evp_aead_seal, ssl3_protocol_version(ssl), + hs->new_cipher, key, key_len, mac_secret, mac_secret_len, iv, iv_len); + if (aead_ctx == NULL) { + return 0; } - size_t len; - if (!append_digest(&ssl->s3->handshake_hash, out + md5_len, &len, - out_len - md5_len)) { - return -1; + if (is_read) { + return ssl->method->set_read_state(ssl, aead_ctx); } - return (int)(md5_len + len); + return ssl->method->set_write_state(ssl, aead_ctx); } -static int tls1_final_finish_mac(SSL *ssl, int from_server, uint8_t *out) { - /* At this point, the handshake should have released the handshake buffer on - * its own. */ - assert(ssl->s3->handshake_buffer == NULL); - - const char *label = TLS_MD_CLIENT_FINISH_CONST; - size_t label_len = TLS_MD_SERVER_FINISH_CONST_SIZE; - if (from_server) { - label = TLS_MD_SERVER_FINISH_CONST; - label_len = TLS_MD_SERVER_FINISH_CONST_SIZE; - } +size_t SSL_get_key_block_len(const SSL *ssl) { + return 2 * ((size_t)ssl->s3->tmp.new_mac_secret_len + + (size_t)ssl->s3->tmp.new_key_len + + (size_t)ssl->s3->tmp.new_fixed_iv_len); +} - uint8_t buf[EVP_MAX_MD_SIZE]; - int digests_len = tls1_handshake_digest(ssl, buf, sizeof(buf)); - if (digests_len < 0) { - return 0; +int SSL_generate_key_block(const SSL *ssl, uint8_t *out, size_t out_len) { + if (ssl3_protocol_version(ssl) == SSL3_VERSION) { + return ssl3_prf(out, out_len, SSL_get_session(ssl)->master_key, + SSL_get_session(ssl)->master_key_length, + TLS_MD_KEY_EXPANSION_CONST, TLS_MD_KEY_EXPANSION_CONST_SIZE, + ssl->s3->server_random, SSL3_RANDOM_SIZE, + ssl->s3->client_random, SSL3_RANDOM_SIZE); } - static const size_t kFinishedLen = 12; - if (!ssl->s3->enc_method->prf(ssl, out, kFinishedLen, - ssl->session->master_key, - ssl->session->master_key_length, label, - label_len, buf, digests_len, NULL, 0)) { + const EVP_MD *digest = ssl_get_handshake_digest( + SSL_get_session(ssl)->cipher->algorithm_prf, ssl3_protocol_version(ssl)); + if (digest == NULL) { + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); return 0; } - - return (int)kFinishedLen; + return tls1_prf(digest, out, out_len, SSL_get_session(ssl)->master_key, + SSL_get_session(ssl)->master_key_length, + TLS_MD_KEY_EXPANSION_CONST, TLS_MD_KEY_EXPANSION_CONST_SIZE, + ssl->s3->server_random, SSL3_RANDOM_SIZE, + ssl->s3->client_random, SSL3_RANDOM_SIZE); } -int tls1_generate_master_secret(SSL *ssl, uint8_t *out, +int tls1_generate_master_secret(SSL_HANDSHAKE *hs, uint8_t *out, const uint8_t *premaster, size_t premaster_len) { - if (ssl->s3->tmp.extended_master_secret) { + const SSL *ssl = hs->ssl; + if (hs->extended_master_secret) { uint8_t digests[EVP_MAX_MD_SIZE]; - int digests_len = tls1_handshake_digest(ssl, digests, sizeof(digests)); - if (digests_len == -1) { - return 0; - } - - if (!ssl->s3->enc_method->prf(ssl, out, SSL3_MASTER_SECRET_SIZE, premaster, - premaster_len, - TLS_MD_EXTENDED_MASTER_SECRET_CONST, - TLS_MD_EXTENDED_MASTER_SECRET_CONST_SIZE, - digests, digests_len, NULL, 0)) { + size_t digests_len; + if (!SSL_TRANSCRIPT_get_hash(&hs->transcript, digests, &digests_len) || + !tls1_prf(SSL_TRANSCRIPT_md(&hs->transcript), out, + SSL3_MASTER_SECRET_SIZE, premaster, premaster_len, + TLS_MD_EXTENDED_MASTER_SECRET_CONST, + TLS_MD_EXTENDED_MASTER_SECRET_CONST_SIZE, digests, + digests_len, NULL, 0)) { return 0; } } else { - if (!ssl->s3->enc_method->prf(ssl, out, SSL3_MASTER_SECRET_SIZE, premaster, - premaster_len, TLS_MD_MASTER_SECRET_CONST, - TLS_MD_MASTER_SECRET_CONST_SIZE, - ssl->s3->client_random, SSL3_RANDOM_SIZE, - ssl->s3->server_random, SSL3_RANDOM_SIZE)) { - return 0; + if (ssl3_protocol_version(ssl) == SSL3_VERSION) { + if (!ssl3_prf(out, SSL3_MASTER_SECRET_SIZE, premaster, premaster_len, + TLS_MD_MASTER_SECRET_CONST, TLS_MD_MASTER_SECRET_CONST_SIZE, + ssl->s3->client_random, SSL3_RANDOM_SIZE, + ssl->s3->server_random, SSL3_RANDOM_SIZE)) { + return 0; + } + } else { + if (!tls1_prf(SSL_TRANSCRIPT_md(&hs->transcript), out, + SSL3_MASTER_SECRET_SIZE, premaster, premaster_len, + TLS_MD_MASTER_SECRET_CONST, TLS_MD_MASTER_SECRET_CONST_SIZE, + ssl->s3->client_random, SSL3_RANDOM_SIZE, + ssl->s3->server_random, SSL3_RANDOM_SIZE)) { + return 0; + } } } @@ -526,6 +514,16 @@ int SSL_export_keying_material(SSL *ssl, uint8_t *out, size_t out_len, return 0; } + /* Exporters may not be used in the middle of a renegotiation. */ + if (SSL_in_init(ssl) && !SSL_in_false_start(ssl)) { + return 0; + } + + if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) { + return tls13_export_keying_material(ssl, out, out_len, label, label_len, + context, context_len, use_context); + } + size_t seed_len = 2 * SSL3_RANDOM_SIZE; if (use_context) { if (context_len >= 1u << 16) { @@ -540,24 +538,24 @@ int SSL_export_keying_material(SSL *ssl, uint8_t *out, size_t out_len, return 0; } - memcpy(seed, ssl->s3->client_random, SSL3_RANDOM_SIZE); - memcpy(seed + SSL3_RANDOM_SIZE, ssl->s3->server_random, SSL3_RANDOM_SIZE); + OPENSSL_memcpy(seed, ssl->s3->client_random, SSL3_RANDOM_SIZE); + OPENSSL_memcpy(seed + SSL3_RANDOM_SIZE, ssl->s3->server_random, + SSL3_RANDOM_SIZE); if (use_context) { seed[2 * SSL3_RANDOM_SIZE] = (uint8_t)(context_len >> 8); seed[2 * SSL3_RANDOM_SIZE + 1] = (uint8_t)context_len; - memcpy(seed + 2 * SSL3_RANDOM_SIZE + 2, context, context_len); + OPENSSL_memcpy(seed + 2 * SSL3_RANDOM_SIZE + 2, context, context_len); } - int ret = - ssl->s3->enc_method->prf(ssl, out, out_len, ssl->session->master_key, - ssl->session->master_key_length, label, - label_len, seed, seed_len, NULL, 0); + const EVP_MD *digest = ssl_get_handshake_digest( + SSL_get_session(ssl)->cipher->algorithm_prf, ssl3_protocol_version(ssl)); + if (digest == NULL) { + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + return 0; + } + int ret = tls1_prf(digest, out, out_len, SSL_get_session(ssl)->master_key, + SSL_get_session(ssl)->master_key_length, label, label_len, + seed, seed_len, NULL, 0); OPENSSL_free(seed); return ret; } - -const SSL3_ENC_METHOD TLSv1_enc_data = { - tls1_prf, - tls1_final_finish_mac, - tls1_cert_verify_mac, -}; diff --git a/Sources/BoringSSL/ssl/t1_lib.c b/Sources/BoringSSL/ssl/t1_lib.c index 434286bfd..d6ef1ffd8 100644 --- a/Sources/BoringSSL/ssl/t1_lib.c +++ b/Sources/BoringSSL/ssl/t1_lib.c @@ -110,7 +110,6 @@ #include #include -#include #include #include @@ -120,15 +119,15 @@ #include #include #include -#include +#include #include #include #include "internal.h" +#include "../crypto/internal.h" -static int ssl_check_clienthello_tlsext(SSL *ssl); -static int ssl_check_serverhello_tlsext(SSL *ssl); +static int ssl_check_clienthello_tlsext(SSL_HANDSHAKE *hs); static int compare_uint16_t(const void *p1, const void *p2) { uint16_t u1 = *((const uint16_t *)p1); @@ -203,88 +202,86 @@ static int tls1_check_duplicate_extensions(const CBS *cbs) { return ret; } -char ssl_early_callback_init(struct ssl_early_callback_ctx *ctx) { - CBS client_hello, session_id, cipher_suites, compression_methods, extensions; +int ssl_client_hello_init(SSL *ssl, SSL_CLIENT_HELLO *out, const uint8_t *in, + size_t in_len) { + OPENSSL_memset(out, 0, sizeof(*out)); + out->ssl = ssl; + out->client_hello = in; + out->client_hello_len = in_len; - CBS_init(&client_hello, ctx->client_hello, ctx->client_hello_len); - - if (/* Skip client version. */ - !CBS_skip(&client_hello, 2) || - /* Skip client nonce. */ - !CBS_skip(&client_hello, 32) || - /* Extract session_id. */ - !CBS_get_u8_length_prefixed(&client_hello, &session_id)) { + CBS client_hello, random, session_id; + CBS_init(&client_hello, out->client_hello, out->client_hello_len); + if (!CBS_get_u16(&client_hello, &out->version) || + !CBS_get_bytes(&client_hello, &random, SSL3_RANDOM_SIZE) || + !CBS_get_u8_length_prefixed(&client_hello, &session_id) || + CBS_len(&session_id) > SSL_MAX_SSL_SESSION_ID_LENGTH) { return 0; } - ctx->session_id = CBS_data(&session_id); - ctx->session_id_len = CBS_len(&session_id); + out->random = CBS_data(&random); + out->random_len = CBS_len(&random); + out->session_id = CBS_data(&session_id); + out->session_id_len = CBS_len(&session_id); /* Skip past DTLS cookie */ - if (SSL_IS_DTLS(ctx->ssl)) { + if (SSL_is_dtls(out->ssl)) { CBS cookie; - - if (!CBS_get_u8_length_prefixed(&client_hello, &cookie)) { + if (!CBS_get_u8_length_prefixed(&client_hello, &cookie) || + CBS_len(&cookie) > DTLS1_COOKIE_LENGTH) { return 0; } } - /* Extract cipher_suites. */ + CBS cipher_suites, compression_methods; if (!CBS_get_u16_length_prefixed(&client_hello, &cipher_suites) || - CBS_len(&cipher_suites) < 2 || (CBS_len(&cipher_suites) & 1) != 0) { - return 0; - } - ctx->cipher_suites = CBS_data(&cipher_suites); - ctx->cipher_suites_len = CBS_len(&cipher_suites); - - /* Extract compression_methods. */ - if (!CBS_get_u8_length_prefixed(&client_hello, &compression_methods) || + CBS_len(&cipher_suites) < 2 || (CBS_len(&cipher_suites) & 1) != 0 || + !CBS_get_u8_length_prefixed(&client_hello, &compression_methods) || CBS_len(&compression_methods) < 1) { return 0; } - ctx->compression_methods = CBS_data(&compression_methods); - ctx->compression_methods_len = CBS_len(&compression_methods); + + out->cipher_suites = CBS_data(&cipher_suites); + out->cipher_suites_len = CBS_len(&cipher_suites); + out->compression_methods = CBS_data(&compression_methods); + out->compression_methods_len = CBS_len(&compression_methods); /* If the ClientHello ends here then it's valid, but doesn't have any * extensions. (E.g. SSLv3.) */ if (CBS_len(&client_hello) == 0) { - ctx->extensions = NULL; - ctx->extensions_len = 0; + out->extensions = NULL; + out->extensions_len = 0; return 1; } /* Extract extensions and check it is valid. */ + CBS extensions; if (!CBS_get_u16_length_prefixed(&client_hello, &extensions) || !tls1_check_duplicate_extensions(&extensions) || CBS_len(&client_hello) != 0) { return 0; } - ctx->extensions = CBS_data(&extensions); - ctx->extensions_len = CBS_len(&extensions); + + out->extensions = CBS_data(&extensions); + out->extensions_len = CBS_len(&extensions); return 1; } -int SSL_early_callback_ctx_extension_get( - const struct ssl_early_callback_ctx *ctx, uint16_t extension_type, - const uint8_t **out_data, size_t *out_len) { +int ssl_client_hello_get_extension(const SSL_CLIENT_HELLO *client_hello, + CBS *out, uint16_t extension_type) { CBS extensions; - - CBS_init(&extensions, ctx->extensions, ctx->extensions_len); - + CBS_init(&extensions, client_hello->extensions, client_hello->extensions_len); while (CBS_len(&extensions) != 0) { + /* Decode the next extension. */ uint16_t type; CBS extension; - - /* Decode the next extension. */ if (!CBS_get_u16(&extensions, &type) || !CBS_get_u16_length_prefixed(&extensions, &extension)) { return 0; } if (type == extension_type) { - *out_data = CBS_data(&extension); - *out_len = CBS_len(&extension); + *out = extension; return 1; } } @@ -292,77 +289,69 @@ int SSL_early_callback_ctx_extension_get( return 0; } -static const uint16_t eccurves_default[] = { +int SSL_early_callback_ctx_extension_get(const SSL_CLIENT_HELLO *client_hello, + uint16_t extension_type, + const uint8_t **out_data, + size_t *out_len) { + CBS cbs; + if (!ssl_client_hello_get_extension(client_hello, &cbs, extension_type)) { + return 0; + } + + *out_data = CBS_data(&cbs); + *out_len = CBS_len(&cbs); + return 1; +} + +static const uint16_t kDefaultGroups[] = { SSL_CURVE_X25519, SSL_CURVE_SECP256R1, SSL_CURVE_SECP384R1, -#if defined(BORINGSSL_ANDROID_SYSTEM) - SSL_CURVE_SECP521R1, -#endif }; -/* tls1_get_curvelist sets |*out_curve_ids| and |*out_curve_ids_len| to the - * list of allowed curve IDs. If |get_peer_curves| is non-zero, return the - * peer's curve list. Otherwise, return the preferred list. */ -static void tls1_get_curvelist(SSL *ssl, int get_peer_curves, - const uint16_t **out_curve_ids, - size_t *out_curve_ids_len) { - if (get_peer_curves) { - /* Only clients send a curve list, so this function is only called - * on the server. */ - assert(ssl->server); - *out_curve_ids = ssl->s3->tmp.peer_ellipticcurvelist; - *out_curve_ids_len = ssl->s3->tmp.peer_ellipticcurvelist_length; - return; - } - - *out_curve_ids = ssl->tlsext_ellipticcurvelist; - *out_curve_ids_len = ssl->tlsext_ellipticcurvelist_length; - if (!*out_curve_ids) { - *out_curve_ids = eccurves_default; - *out_curve_ids_len = sizeof(eccurves_default) / sizeof(eccurves_default[0]); +void tls1_get_grouplist(SSL *ssl, const uint16_t **out_group_ids, + size_t *out_group_ids_len) { + *out_group_ids = ssl->supported_group_list; + *out_group_ids_len = ssl->supported_group_list_len; + if (!*out_group_ids) { + *out_group_ids = kDefaultGroups; + *out_group_ids_len = OPENSSL_ARRAY_SIZE(kDefaultGroups); } } -int tls1_get_shared_curve(SSL *ssl, uint16_t *out_curve_id) { - const uint16_t *curves, *peer_curves, *pref, *supp; - size_t curves_len, peer_curves_len, pref_len, supp_len, i, j; - - /* Can't do anything on client side */ - if (ssl->server == 0) { - return 0; - } +int tls1_get_shared_group(SSL_HANDSHAKE *hs, uint16_t *out_group_id) { + SSL *const ssl = hs->ssl; + assert(ssl->server); - tls1_get_curvelist(ssl, 0 /* local curves */, &curves, &curves_len); - tls1_get_curvelist(ssl, 1 /* peer curves */, &peer_curves, &peer_curves_len); + const uint16_t *groups, *pref, *supp; + size_t groups_len, pref_len, supp_len; + tls1_get_grouplist(ssl, &groups, &groups_len); - if (peer_curves_len == 0) { - /* Clients are not required to send a supported_curves extension. In this - * case, the server is free to pick any curve it likes. See RFC 4492, - * section 4, paragraph 3. - * - * However, in the interests of compatibility, we will skip ECDH if the - * client didn't send an extension because we can't be sure that they'll - * support our favoured curve. */ - return 0; - } + /* Clients are not required to send a supported_groups extension. In this + * case, the server is free to pick any group it likes. See RFC 4492, + * section 4, paragraph 3. + * + * However, in the interests of compatibility, we will skip ECDH if the + * client didn't send an extension because we can't be sure that they'll + * support our favoured group. Thus we do not special-case an emtpy + * |peer_supported_group_list|. */ if (ssl->options & SSL_OP_CIPHER_SERVER_PREFERENCE) { - pref = curves; - pref_len = curves_len; - supp = peer_curves; - supp_len = peer_curves_len; + pref = groups; + pref_len = groups_len; + supp = hs->peer_supported_group_list; + supp_len = hs->peer_supported_group_list_len; } else { - pref = peer_curves; - pref_len = peer_curves_len; - supp = curves; - supp_len = curves_len; + pref = hs->peer_supported_group_list; + pref_len = hs->peer_supported_group_list_len; + supp = groups; + supp_len = groups_len; } - for (i = 0; i < pref_len; i++) { - for (j = 0; j < supp_len; j++) { + for (size_t i = 0; i < pref_len; i++) { + for (size_t j = 0; j < supp_len; j++) { if (pref[i] == supp[j]) { - *out_curve_id = pref[i]; + *out_group_id = pref[i]; return 1; } } @@ -371,236 +360,171 @@ int tls1_get_shared_curve(SSL *ssl, uint16_t *out_curve_id) { return 0; } -int tls1_set_curves(uint16_t **out_curve_ids, size_t *out_curve_ids_len, +int tls1_set_curves(uint16_t **out_group_ids, size_t *out_group_ids_len, const int *curves, size_t ncurves) { - uint16_t *curve_ids; - size_t i; + uint16_t *group_ids; - curve_ids = OPENSSL_malloc(ncurves * sizeof(uint16_t)); - if (curve_ids == NULL) { + group_ids = OPENSSL_malloc(ncurves * sizeof(uint16_t)); + if (group_ids == NULL) { return 0; } - for (i = 0; i < ncurves; i++) { - if (!ssl_nid_to_curve_id(&curve_ids[i], curves[i])) { - OPENSSL_free(curve_ids); + for (size_t i = 0; i < ncurves; i++) { + if (!ssl_nid_to_group_id(&group_ids[i], curves[i])) { + OPENSSL_free(group_ids); return 0; } } - OPENSSL_free(*out_curve_ids); - *out_curve_ids = curve_ids; - *out_curve_ids_len = ncurves; + OPENSSL_free(*out_group_ids); + *out_group_ids = group_ids; + *out_group_ids_len = ncurves; return 1; } -/* tls1_curve_params_from_ec_key sets |*out_curve_id| and |*out_comp_id| to the - * TLS curve ID and point format, respectively, for |ec|. It returns one on - * success and zero on failure. */ -static int tls1_curve_params_from_ec_key(uint16_t *out_curve_id, - uint8_t *out_comp_id, EC_KEY *ec) { - int nid; - uint16_t id; - const EC_GROUP *grp; - - if (ec == NULL) { - return 0; - } - - grp = EC_KEY_get0_group(ec); - if (grp == NULL) { - return 0; - } +int tls1_set_curves_list(uint16_t **out_group_ids, size_t *out_group_ids_len, + const char *curves) { + uint16_t *group_ids = NULL; + size_t ncurves = 0; - /* Determine curve ID */ - nid = EC_GROUP_get_curve_name(grp); - if (!ssl_nid_to_curve_id(&id, nid)) { - return 0; - } + const char *col; + const char *ptr = curves; - /* Set the named curve ID. Arbitrary explicit curves are not supported. */ - *out_curve_id = id; + do { + col = strchr(ptr, ':'); - if (out_comp_id) { - if (EC_KEY_get0_public_key(ec) == NULL) { - return 0; - } - if (EC_KEY_get_conv_form(ec) == POINT_CONVERSION_COMPRESSED) { - *out_comp_id = TLSEXT_ECPOINTFORMAT_ansiX962_compressed_prime; - } else { - *out_comp_id = TLSEXT_ECPOINTFORMAT_uncompressed; + uint16_t group_id; + if (!ssl_name_to_group_id(&group_id, ptr, + col ? (size_t)(col - ptr) : strlen(ptr))) { + goto err; } - } - - return 1; -} - -/* tls1_check_curve_id returns one if |curve_id| is consistent with both our - * and the peer's curve preferences. Note: if called as the client, only our - * preferences are checked; the peer (the server) does not send preferences. */ -int tls1_check_curve_id(SSL *ssl, uint16_t curve_id) { - const uint16_t *curves; - size_t curves_len, i, get_peer_curves; - /* Check against our list, then the peer's list. */ - for (get_peer_curves = 0; get_peer_curves <= 1; get_peer_curves++) { - if (get_peer_curves && !ssl->server) { - /* Servers do not present a preference list so, if we are a client, only - * check our list. */ - continue; + uint16_t *new_group_ids = OPENSSL_realloc(group_ids, + (ncurves + 1) * sizeof(uint16_t)); + if (new_group_ids == NULL) { + goto err; } + group_ids = new_group_ids; - tls1_get_curvelist(ssl, get_peer_curves, &curves, &curves_len); - if (get_peer_curves && curves_len == 0) { - /* Clients are not required to send a supported_curves extension. In this - * case, the server is free to pick any curve it likes. See RFC 4492, - * section 4, paragraph 3. */ - continue; - } - for (i = 0; i < curves_len; i++) { - if (curves[i] == curve_id) { - break; - } - } + group_ids[ncurves] = group_id; + ncurves++; - if (i == curves_len) { - return 0; + if (col) { + ptr = col + 1; } - } + } while (col); + + OPENSSL_free(*out_group_ids); + *out_group_ids = group_ids; + *out_group_ids_len = ncurves; return 1; -} -int tls1_check_ec_cert(SSL *ssl, X509 *x) { - int ret = 0; - EVP_PKEY *pkey = X509_get_pubkey(x); - uint16_t curve_id; - uint8_t comp_id; +err: + OPENSSL_free(group_ids); + return 0; +} - if (!pkey) { - goto done; - } - EC_KEY *ec_key = EVP_PKEY_get0_EC_KEY(pkey); - if (ec_key == NULL || - !tls1_curve_params_from_ec_key(&curve_id, &comp_id, ec_key) || - !tls1_check_curve_id(ssl, curve_id) || - comp_id != TLSEXT_ECPOINTFORMAT_uncompressed) { - goto done; +int tls1_check_group_id(SSL *ssl, uint16_t group_id) { + const uint16_t *groups; + size_t groups_len; + tls1_get_grouplist(ssl, &groups, &groups_len); + for (size_t i = 0; i < groups_len; i++) { + if (groups[i] == group_id) { + return 1; + } } - ret = 1; - -done: - EVP_PKEY_free(pkey); - return ret; + return 0; } -/* List of supported signature algorithms and hashes. Should make this - * customisable at some point, for now include everything we support. */ +/* kVerifySignatureAlgorithms is the default list of accepted signature + * algorithms for verifying. + * + * For now, RSA-PSS signature algorithms are not enabled on Android's system + * BoringSSL. Once the change in Chrome has stuck and the values are finalized, + * restore them. */ +static const uint16_t kVerifySignatureAlgorithms[] = { + /* Prefer SHA-256 algorithms. */ + SSL_SIGN_ECDSA_SECP256R1_SHA256, +#if !defined(BORINGSSL_ANDROID_SYSTEM) + SSL_SIGN_RSA_PSS_SHA256, +#endif + SSL_SIGN_RSA_PKCS1_SHA256, -#define tlsext_sigalg_rsa(md) md, TLSEXT_signature_rsa, + /* Larger hashes are acceptable. */ + SSL_SIGN_ECDSA_SECP384R1_SHA384, +#if !defined(BORINGSSL_ANDROID_SYSTEM) + SSL_SIGN_RSA_PSS_SHA384, +#endif + SSL_SIGN_RSA_PKCS1_SHA384, -#define tlsext_sigalg_ecdsa(md) md, TLSEXT_signature_ecdsa, + /* TODO(davidben): Remove this. */ +#if defined(BORINGSSL_ANDROID_SYSTEM) + SSL_SIGN_ECDSA_SECP521R1_SHA512, +#endif +#if !defined(BORINGSSL_ANDROID_SYSTEM) + SSL_SIGN_RSA_PSS_SHA512, +#endif + SSL_SIGN_RSA_PKCS1_SHA512, -#define tlsext_sigalg(md) tlsext_sigalg_rsa(md) tlsext_sigalg_ecdsa(md) + /* For now, SHA-1 is still accepted but least preferable. */ + SSL_SIGN_RSA_PKCS1_SHA1, -static const uint8_t tls12_sigalgs[] = { - tlsext_sigalg(TLSEXT_hash_sha512) - tlsext_sigalg(TLSEXT_hash_sha384) - tlsext_sigalg(TLSEXT_hash_sha256) - tlsext_sigalg(TLSEXT_hash_sha1) }; -size_t tls12_get_psigalgs(SSL *ssl, const uint8_t **psigs) { - *psigs = tls12_sigalgs; - return sizeof(tls12_sigalgs); -} - -int tls12_check_peer_sigalg(SSL *ssl, const EVP_MD **out_md, int *out_alert, - uint8_t hash, uint8_t signature, EVP_PKEY *pkey) { - const uint8_t *sent_sigs; - size_t sent_sigslen, i; - int sigalg = tls12_get_sigid(pkey->type); - - /* Should never happen */ - if (sigalg == -1) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - *out_alert = SSL_AD_INTERNAL_ERROR; - return 0; - } - - /* Check key type is consistent with signature */ - if (sigalg != signature) { - OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_SIGNATURE_TYPE); - *out_alert = SSL_AD_ILLEGAL_PARAMETER; - return 0; - } +/* kSignSignatureAlgorithms is the default list of supported signature + * algorithms for signing. + * + * For now, RSA-PSS signature algorithms are not enabled on Android's system + * BoringSSL. Once the change in Chrome has stuck and the values are finalized, + * restore them. */ +static const uint16_t kSignSignatureAlgorithms[] = { + /* Prefer SHA-256 algorithms. */ + SSL_SIGN_ECDSA_SECP256R1_SHA256, +#if !defined(BORINGSSL_ANDROID_SYSTEM) + SSL_SIGN_RSA_PSS_SHA256, +#endif + SSL_SIGN_RSA_PKCS1_SHA256, - /* Check signature matches a type we sent */ - sent_sigslen = tls12_get_psigalgs(ssl, &sent_sigs); - for (i = 0; i < sent_sigslen; i += 2, sent_sigs += 2) { - if (hash == sent_sigs[0] && signature == sent_sigs[1]) { - break; - } - } + /* If needed, sign larger hashes. + * + * TODO(davidben): Determine which of these may be pruned. */ + SSL_SIGN_ECDSA_SECP384R1_SHA384, +#if !defined(BORINGSSL_ANDROID_SYSTEM) + SSL_SIGN_RSA_PSS_SHA384, +#endif + SSL_SIGN_RSA_PKCS1_SHA384, - if (i == sent_sigslen) { - OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_SIGNATURE_TYPE); - *out_alert = SSL_AD_ILLEGAL_PARAMETER; - return 0; - } + SSL_SIGN_ECDSA_SECP521R1_SHA512, +#if !defined(BORINGSSL_ANDROID_SYSTEM) + SSL_SIGN_RSA_PSS_SHA512, +#endif + SSL_SIGN_RSA_PKCS1_SHA512, - *out_md = tls12_get_hash(hash); - if (*out_md == NULL) { - OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_DIGEST); - *out_alert = SSL_AD_ILLEGAL_PARAMETER; - return 0; - } + /* If the peer supports nothing else, sign with SHA-1. */ + SSL_SIGN_ECDSA_SHA1, + SSL_SIGN_RSA_PKCS1_SHA1, +}; - return 1; +size_t tls12_get_verify_sigalgs(const SSL *ssl, const uint16_t **out) { + *out = kVerifySignatureAlgorithms; + return OPENSSL_ARRAY_SIZE(kVerifySignatureAlgorithms); } -/* Get a mask of disabled algorithms: an algorithm is disabled if it isn't - * supported or doesn't appear in supported signature algorithms. Unlike - * ssl_cipher_get_disabled this applies to a specific session and not global - * settings. */ -void ssl_set_client_disabled(SSL *ssl) { - CERT *c = ssl->cert; - const uint8_t *sigalgs; - size_t i, sigalgslen; - int have_rsa = 0, have_ecdsa = 0; - c->mask_a = 0; - c->mask_k = 0; - - /* Now go through all signature algorithms seeing if we support any for RSA, - * DSA, ECDSA. Do this for all versions not just TLS 1.2. */ - sigalgslen = tls12_get_psigalgs(ssl, &sigalgs); - for (i = 0; i < sigalgslen; i += 2, sigalgs += 2) { - switch (sigalgs[1]) { - case TLSEXT_signature_rsa: - have_rsa = 1; - break; - - case TLSEXT_signature_ecdsa: - have_ecdsa = 1; - break; +int tls12_check_peer_sigalg(SSL *ssl, int *out_alert, uint16_t sigalg) { + const uint16_t *verify_sigalgs; + size_t num_verify_sigalgs = tls12_get_verify_sigalgs(ssl, &verify_sigalgs); + for (size_t i = 0; i < num_verify_sigalgs; i++) { + if (sigalg == verify_sigalgs[i]) { + return 1; } } - /* Disable auth if we don't include any appropriate signature algorithms. */ - if (!have_rsa) { - c->mask_a |= SSL_aRSA; - } - if (!have_ecdsa) { - c->mask_a |= SSL_aECDSA; - } - - /* with PSK there must be client callback set */ - if (!ssl->psk_client_callback) { - c->mask_a |= SSL_aPSK; - c->mask_k |= SSL_kPSK; - } + OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_SIGNATURE_TYPE); + *out_alert = SSL_AD_ILLEGAL_PARAMETER; + return 0; } /* tls_extension represents a TLS extension that is handled internally. The @@ -620,25 +544,45 @@ void ssl_set_client_disabled(SSL *ssl) { * |*out_alert| isn't set, then a |decode_error| alert will be sent. */ struct tls_extension { uint16_t value; - void (*init)(SSL *ssl); + void (*init)(SSL_HANDSHAKE *hs); - int (*add_clienthello)(SSL *ssl, CBB *out); - int (*parse_serverhello)(SSL *ssl, uint8_t *out_alert, CBS *contents); + int (*add_clienthello)(SSL_HANDSHAKE *hs, CBB *out); + int (*parse_serverhello)(SSL_HANDSHAKE *hs, uint8_t *out_alert, + CBS *contents); - int (*parse_clienthello)(SSL *ssl, uint8_t *out_alert, CBS *contents); - int (*add_serverhello)(SSL *ssl, CBB *out); + int (*parse_clienthello)(SSL_HANDSHAKE *hs, uint8_t *out_alert, + CBS *contents); + int (*add_serverhello)(SSL_HANDSHAKE *hs, CBB *out); }; +static int forbid_parse_serverhello(SSL_HANDSHAKE *hs, uint8_t *out_alert, + CBS *contents) { + if (contents != NULL) { + /* Servers MUST NOT send this extension. */ + *out_alert = SSL_AD_UNSUPPORTED_EXTENSION; + OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION); + return 0; + } + + return 1; +} + +static int ignore_parse_clienthello(SSL_HANDSHAKE *hs, uint8_t *out_alert, + CBS *contents) { + /* This extension from the client is handled elsewhere. */ + return 1; +} + +static int dont_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) { + return 1; +} /* Server name indication (SNI). * * https://tools.ietf.org/html/rfc6066#section-3. */ -static void ext_sni_init(SSL *ssl) { - ssl->s3->tmp.should_ack_sni = 0; -} - -static int ext_sni_add_clienthello(SSL *ssl, CBB *out) { +static int ext_sni_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) { + SSL *const ssl = hs->ssl; if (ssl->tlsext_hostname == NULL) { return 1; } @@ -658,8 +602,9 @@ static int ext_sni_add_clienthello(SSL *ssl, CBB *out) { return 1; } -static int ext_sni_parse_serverhello(SSL *ssl, uint8_t *out_alert, +static int ext_sni_parse_serverhello(SSL_HANDSHAKE *hs, uint8_t *out_alert, CBS *contents) { + SSL *const ssl = hs->ssl; if (contents == NULL) { return 1; } @@ -670,10 +615,10 @@ static int ext_sni_parse_serverhello(SSL *ssl, uint8_t *out_alert, assert(ssl->tlsext_hostname != NULL); - if (!ssl->hit) { - assert(ssl->session->tlsext_hostname == NULL); - ssl->session->tlsext_hostname = BUF_strdup(ssl->tlsext_hostname); - if (!ssl->session->tlsext_hostname) { + if (ssl->session == NULL) { + OPENSSL_free(hs->new_session->tlsext_hostname); + hs->new_session->tlsext_hostname = BUF_strdup(ssl->tlsext_hostname); + if (!hs->new_session->tlsext_hostname) { *out_alert = SSL_AD_INTERNAL_ERROR; return 0; } @@ -682,97 +627,50 @@ static int ext_sni_parse_serverhello(SSL *ssl, uint8_t *out_alert, return 1; } -static int ext_sni_parse_clienthello(SSL *ssl, uint8_t *out_alert, +static int ext_sni_parse_clienthello(SSL_HANDSHAKE *hs, uint8_t *out_alert, CBS *contents) { if (contents == NULL) { return 1; } - /* The servername extension is treated as follows: - * - * - Only the hostname type is supported with a maximum length of 255. - * - The servername is rejected if too long or if it contains zeros, in - * which case an fatal alert is generated. - * - The servername field is maintained together with the session cache. - * - When a session is resumed, the servername callback is invoked in order - * to allow the application to position itself to the right context. - * - The servername is acknowledged if it is new for a session or when - * it is identical to a previously used for the same session. - * Applications can control the behaviour. They can at any time - * set a 'desirable' servername for a new SSL object. This can be the - * case for example with HTTPS when a Host: header field is received and - * a renegotiation is requested. In this case, a possible servername - * presented in the new client hello is only acknowledged if it matches - * the value of the Host: field. - * - Applications must use SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION - * if they provide for changing an explicit servername context for the - * session, - * i.e. when the session has been established with a servername extension. - */ - - CBS server_name_list; - char have_seen_host_name = 0; - + CBS server_name_list, host_name; + uint8_t name_type; if (!CBS_get_u16_length_prefixed(contents, &server_name_list) || - CBS_len(&server_name_list) == 0 || + !CBS_get_u8(&server_name_list, &name_type) || + /* Although the server_name extension was intended to be extensible to + * new name types and multiple names, OpenSSL 1.0.x had a bug which meant + * different name types will cause an error. Further, RFC 4366 originally + * defined syntax inextensibly. RFC 6066 corrected this mistake, but + * adding new name types is no longer feasible. + * + * Act as if the extensibility does not exist to simplify parsing. */ + !CBS_get_u16_length_prefixed(&server_name_list, &host_name) || + CBS_len(&server_name_list) != 0 || CBS_len(contents) != 0) { return 0; } - /* Decode each ServerName in the extension. */ - while (CBS_len(&server_name_list) > 0) { - uint8_t name_type; - CBS host_name; - - if (!CBS_get_u8(&server_name_list, &name_type) || - !CBS_get_u16_length_prefixed(&server_name_list, &host_name)) { - return 0; - } - - /* Only host_name is supported. */ - if (name_type != TLSEXT_NAMETYPE_host_name) { - continue; - } - - if (have_seen_host_name) { - /* The ServerNameList MUST NOT contain more than one name of the same - * name_type. */ - return 0; - } - - have_seen_host_name = 1; - - if (CBS_len(&host_name) == 0 || - CBS_len(&host_name) > TLSEXT_MAXLEN_host_name || - CBS_contains_zero_byte(&host_name)) { - *out_alert = SSL_AD_UNRECOGNIZED_NAME; - return 0; - } - - if (!ssl->hit) { - assert(ssl->session->tlsext_hostname == NULL); - if (ssl->session->tlsext_hostname) { - /* This should be impossible. */ - return 0; - } - - /* Copy the hostname as a string. */ - if (!CBS_strdup(&host_name, &ssl->session->tlsext_hostname)) { - *out_alert = SSL_AD_INTERNAL_ERROR; - return 0; - } + if (name_type != TLSEXT_NAMETYPE_host_name || + CBS_len(&host_name) == 0 || + CBS_len(&host_name) > TLSEXT_MAXLEN_host_name || + CBS_contains_zero_byte(&host_name)) { + *out_alert = SSL_AD_UNRECOGNIZED_NAME; + return 0; + } - ssl->s3->tmp.should_ack_sni = 1; - } + /* Copy the hostname as a string. */ + if (!CBS_strdup(&host_name, &hs->hostname)) { + *out_alert = SSL_AD_INTERNAL_ERROR; + return 0; } + hs->should_ack_sni = 1; return 1; } -static int ext_sni_add_serverhello(SSL *ssl, CBB *out) { - if (ssl->hit || - !ssl->s3->tmp.should_ack_sni || - ssl->session->tlsext_hostname == NULL) { +static int ext_sni_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) { + if (hs->ssl->s3->session_reused || + !hs->should_ack_sni) { return 1; } @@ -789,7 +687,21 @@ static int ext_sni_add_serverhello(SSL *ssl, CBB *out) { * * https://tools.ietf.org/html/rfc5746 */ -static int ext_ri_add_clienthello(SSL *ssl, CBB *out) { +static int ext_ri_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) { + SSL *const ssl = hs->ssl; + uint16_t min_version, max_version; + if (!ssl_get_version_range(ssl, &min_version, &max_version)) { + return 0; + } + + /* Renegotiation indication is not necessary in TLS 1.3. */ + if (min_version >= TLS1_3_VERSION) { + return 1; + } + + assert(ssl->s3->initial_handshake_complete == + (ssl->s3->previous_client_finished_len != 0)); + CBB contents, prev_finished; if (!CBB_add_u16(out, TLSEXT_TYPE_renegotiate) || !CBB_add_u16_length_prefixed(out, &contents) || @@ -803,8 +715,13 @@ static int ext_ri_add_clienthello(SSL *ssl, CBB *out) { return 1; } -static int ext_ri_parse_serverhello(SSL *ssl, uint8_t *out_alert, +static int ext_ri_parse_serverhello(SSL_HANDSHAKE *hs, uint8_t *out_alert, CBS *contents) { + SSL *const ssl = hs->ssl; + if (contents != NULL && ssl3_protocol_version(ssl) >= TLS1_3_VERSION) { + return 0; + } + /* Servers may not switch between omitting the extension and supporting it. * See RFC 5746, sections 3.5 and 4.2. */ if (ssl->s3->initial_handshake_complete && @@ -831,6 +748,10 @@ static int ext_ri_parse_serverhello(SSL *ssl, uint8_t *out_alert, /* Check for logic errors */ assert(!expected_len || ssl->s3->previous_client_finished_len); assert(!expected_len || ssl->s3->previous_server_finished_len); + assert(ssl->s3->initial_handshake_complete == + (ssl->s3->previous_client_finished_len != 0)); + assert(ssl->s3->initial_handshake_complete == + (ssl->s3->previous_server_finished_len != 0)); /* Parse out the extension contents. */ CBS renegotiated_connection; @@ -868,41 +789,31 @@ static int ext_ri_parse_serverhello(SSL *ssl, uint8_t *out_alert, return 1; } -static int ext_ri_parse_clienthello(SSL *ssl, uint8_t *out_alert, +static int ext_ri_parse_clienthello(SSL_HANDSHAKE *hs, uint8_t *out_alert, CBS *contents) { + SSL *const ssl = hs->ssl; /* Renegotiation isn't supported as a server so this function should never be * called after the initial handshake. */ assert(!ssl->s3->initial_handshake_complete); - CBS fake_contents; - static const uint8_t kFakeExtension[] = {0}; + if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) { + return 1; + } if (contents == NULL) { - if (ssl->s3->send_connection_binding) { - /* The renegotiation SCSV was received so pretend that we received a - * renegotiation extension. */ - CBS_init(&fake_contents, kFakeExtension, sizeof(kFakeExtension)); - contents = &fake_contents; - /* We require that the renegotiation extension is at index zero of - * kExtensions. */ - ssl->s3->tmp.extensions.received |= (1u << 0); - } else { - return 1; - } + return 1; } CBS renegotiated_connection; - if (!CBS_get_u8_length_prefixed(contents, &renegotiated_connection) || CBS_len(contents) != 0) { OPENSSL_PUT_ERROR(SSL, SSL_R_RENEGOTIATION_ENCODING_ERR); return 0; } - /* Check that the extension matches */ - if (!CBS_mem_equal(&renegotiated_connection, - ssl->s3->previous_client_finished, - ssl->s3->previous_client_finished_len)) { + /* Check that the extension matches. We do not support renegotiation as a + * server, so this must be empty. */ + if (CBS_len(&renegotiated_connection) != 0) { OPENSSL_PUT_ERROR(SSL, SSL_R_RENEGOTIATION_MISMATCH); *out_alert = SSL_AD_HANDSHAKE_FAILURE; return 0; @@ -913,16 +824,19 @@ static int ext_ri_parse_clienthello(SSL *ssl, uint8_t *out_alert, return 1; } -static int ext_ri_add_serverhello(SSL *ssl, CBB *out) { - CBB contents, prev_finished; +static int ext_ri_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) { + SSL *const ssl = hs->ssl; + /* Renegotiation isn't supported as a server so this function should never be + * called after the initial handshake. */ + assert(!ssl->s3->initial_handshake_complete); + + if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) { + return 1; + } + if (!CBB_add_u16(out, TLSEXT_TYPE_renegotiate) || - !CBB_add_u16_length_prefixed(out, &contents) || - !CBB_add_u8_length_prefixed(&contents, &prev_finished) || - !CBB_add_bytes(&prev_finished, ssl->s3->previous_client_finished, - ssl->s3->previous_client_finished_len) || - !CBB_add_bytes(&prev_finished, ssl->s3->previous_server_finished, - ssl->s3->previous_server_finished_len) || - !CBB_flush(out)) { + !CBB_add_u16(out, 1 /* length */) || + !CBB_add_u8(out, 0 /* empty renegotiation info */)) { return 0; } @@ -934,12 +848,14 @@ static int ext_ri_add_serverhello(SSL *ssl, CBB *out) { * * https://tools.ietf.org/html/rfc7627 */ -static void ext_ems_init(SSL *ssl) { - ssl->s3->tmp.extended_master_secret = 0; -} +static int ext_ems_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) { + uint16_t min_version, max_version; + if (!ssl_get_version_range(hs->ssl, &min_version, &max_version)) { + return 0; + } -static int ext_ems_add_clienthello(SSL *ssl, CBB *out) { - if (ssl->version == SSL3_VERSION) { + /* Extended master secret is not necessary in TLS 1.3. */ + if (min_version >= TLS1_3_VERSION || max_version <= SSL3_VERSION) { return 1; } @@ -951,23 +867,41 @@ static int ext_ems_add_clienthello(SSL *ssl, CBB *out) { return 1; } -static int ext_ems_parse_serverhello(SSL *ssl, uint8_t *out_alert, +static int ext_ems_parse_serverhello(SSL_HANDSHAKE *hs, uint8_t *out_alert, CBS *contents) { - if (contents == NULL) { - return 1; + SSL *const ssl = hs->ssl; + + if (contents != NULL) { + if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION || + ssl->version == SSL3_VERSION || + CBS_len(contents) != 0) { + return 0; + } + + hs->extended_master_secret = 1; } - if (ssl->version == SSL3_VERSION || CBS_len(contents) != 0) { + /* Whether EMS is negotiated may not change on renegotiation. */ + if (ssl->s3->established_session != NULL && + hs->extended_master_secret != + ssl->s3->established_session->extended_master_secret) { + OPENSSL_PUT_ERROR(SSL, SSL_R_RENEGOTIATION_EMS_MISMATCH); + *out_alert = SSL_AD_ILLEGAL_PARAMETER; return 0; } - ssl->s3->tmp.extended_master_secret = 1; return 1; } -static int ext_ems_parse_clienthello(SSL *ssl, uint8_t *out_alert, +static int ext_ems_parse_clienthello(SSL_HANDSHAKE *hs, uint8_t *out_alert, CBS *contents) { - if (ssl->version == SSL3_VERSION || contents == NULL) { + uint16_t version = ssl3_protocol_version(hs->ssl); + if (version >= TLS1_3_VERSION || + version == SSL3_VERSION) { + return 1; + } + + if (contents == NULL) { return 1; } @@ -975,12 +909,12 @@ static int ext_ems_parse_clienthello(SSL *ssl, uint8_t *out_alert, return 0; } - ssl->s3->tmp.extended_master_secret = 1; + hs->extended_master_secret = 1; return 1; } -static int ext_ems_add_serverhello(SSL *ssl, CBB *out) { - if (!ssl->s3->tmp.extended_master_secret) { +static int ext_ems_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) { + if (!hs->extended_master_secret) { return 1; } @@ -997,8 +931,16 @@ static int ext_ems_add_serverhello(SSL *ssl, CBB *out) { * * https://tools.ietf.org/html/rfc5077 */ -static int ext_ticket_add_clienthello(SSL *ssl, CBB *out) { - if (SSL_get_options(ssl) & SSL_OP_NO_TICKET) { +static int ext_ticket_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) { + SSL *const ssl = hs->ssl; + uint16_t min_version, max_version; + if (!ssl_get_version_range(ssl, &min_version, &max_version)) { + return 0; + } + + /* TLS 1.3 uses a different ticket extension. */ + if (min_version >= TLS1_3_VERSION || + SSL_get_options(ssl) & SSL_OP_NO_TICKET) { return 1; } @@ -1009,9 +951,14 @@ static int ext_ticket_add_clienthello(SSL *ssl, CBB *out) { * advertise the extension to avoid potentially breaking servers which carry * over the state from the previous handshake, such as OpenSSL servers * without upstream's 3c3f0259238594d77264a78944d409f2127642c4. */ + uint16_t session_version; if (!ssl->s3->initial_handshake_complete && ssl->session != NULL && - ssl->session->tlsext_tick != NULL) { + ssl->session->tlsext_tick != NULL && + /* Don't send TLS 1.3 session tickets in the ticket extension. */ + ssl->method->version_from_wire(&session_version, + ssl->session->ssl_version) && + session_version < TLS1_3_VERSION) { ticket_data = ssl->session->tlsext_tick; ticket_len = ssl->session->tlsext_ticklen; } @@ -1027,14 +974,17 @@ static int ext_ticket_add_clienthello(SSL *ssl, CBB *out) { return 1; } -static int ext_ticket_parse_serverhello(SSL *ssl, uint8_t *out_alert, +static int ext_ticket_parse_serverhello(SSL_HANDSHAKE *hs, uint8_t *out_alert, CBS *contents) { - ssl->tlsext_ticket_expected = 0; - + SSL *const ssl = hs->ssl; if (contents == NULL) { return 1; } + if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) { + return 0; + } + /* If |SSL_OP_NO_TICKET| is set then no extension will have been sent and * this function should never be called, even if the server tries to send the * extension. */ @@ -1044,25 +994,17 @@ static int ext_ticket_parse_serverhello(SSL *ssl, uint8_t *out_alert, return 0; } - ssl->tlsext_ticket_expected = 1; - return 1; -} - -static int ext_ticket_parse_clienthello(SSL *ssl, uint8_t *out_alert, - CBS *contents) { - /* This function isn't used because the ticket extension from the client is - * handled in ssl_session.c. */ + hs->ticket_expected = 1; return 1; } -static int ext_ticket_add_serverhello(SSL *ssl, CBB *out) { - if (!ssl->tlsext_ticket_expected) { +static int ext_ticket_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) { + if (!hs->ticket_expected) { return 1; } - /* If |SSL_OP_NO_TICKET| is set, |tlsext_ticket_expected| should never be - * true. */ - assert((SSL_get_options(ssl) & SSL_OP_NO_TICKET) == 0); + /* If |SSL_OP_NO_TICKET| is set, |ticket_expected| should never be true. */ + assert((SSL_get_options(hs->ssl) & SSL_OP_NO_TICKET) == 0); if (!CBB_add_u16(out, TLSEXT_TYPE_session_ticket) || !CBB_add_u16(out, 0 /* length */)) { @@ -1077,43 +1019,45 @@ static int ext_ticket_add_serverhello(SSL *ssl, CBB *out) { * * https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */ -static int ext_sigalgs_add_clienthello(SSL *ssl, CBB *out) { - if (ssl3_version_from_wire(ssl, ssl->client_version) < TLS1_2_VERSION) { +static int ext_sigalgs_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) { + SSL *const ssl = hs->ssl; + uint16_t min_version, max_version; + if (!ssl_get_version_range(ssl, &min_version, &max_version)) { + return 0; + } + + if (max_version < TLS1_2_VERSION) { return 1; } - const uint8_t *sigalgs_data; - const size_t sigalgs_len = tls12_get_psigalgs(ssl, &sigalgs_data); + const uint16_t *sigalgs; + const size_t num_sigalgs = tls12_get_verify_sigalgs(ssl, &sigalgs); - CBB contents, sigalgs; + CBB contents, sigalgs_cbb; if (!CBB_add_u16(out, TLSEXT_TYPE_signature_algorithms) || !CBB_add_u16_length_prefixed(out, &contents) || - !CBB_add_u16_length_prefixed(&contents, &sigalgs) || - !CBB_add_bytes(&sigalgs, sigalgs_data, sigalgs_len) || - !CBB_flush(out)) { + !CBB_add_u16_length_prefixed(&contents, &sigalgs_cbb)) { return 0; } - return 1; -} + for (size_t i = 0; i < num_sigalgs; i++) { + if (!CBB_add_u16(&sigalgs_cbb, sigalgs[i])) { + return 0; + } + } -static int ext_sigalgs_parse_serverhello(SSL *ssl, uint8_t *out_alert, - CBS *contents) { - if (contents != NULL) { - /* Servers MUST NOT send this extension. */ - *out_alert = SSL_AD_UNSUPPORTED_EXTENSION; - OPENSSL_PUT_ERROR(SSL, SSL_R_SIGNATURE_ALGORITHMS_EXTENSION_SENT_BY_SERVER); + if (!CBB_flush(out)) { return 0; } return 1; } -static int ext_sigalgs_parse_clienthello(SSL *ssl, uint8_t *out_alert, +static int ext_sigalgs_parse_clienthello(SSL_HANDSHAKE *hs, uint8_t *out_alert, CBS *contents) { - OPENSSL_free(ssl->cert->peer_sigalgs); - ssl->cert->peer_sigalgs = NULL; - ssl->cert->peer_sigalgslen = 0; + OPENSSL_free(hs->peer_sigalgs); + hs->peer_sigalgs = NULL; + hs->num_peer_sigalgs = 0; if (contents == NULL) { return 1; @@ -1123,29 +1067,20 @@ static int ext_sigalgs_parse_clienthello(SSL *ssl, uint8_t *out_alert, if (!CBS_get_u16_length_prefixed(contents, &supported_signature_algorithms) || CBS_len(contents) != 0 || CBS_len(&supported_signature_algorithms) == 0 || - !tls1_parse_peer_sigalgs(ssl, &supported_signature_algorithms)) { + !tls1_parse_peer_sigalgs(hs, &supported_signature_algorithms)) { return 0; } return 1; } -static int ext_sigalgs_add_serverhello(SSL *ssl, CBB *out) { - /* Servers MUST NOT send this extension. */ - return 1; -} - /* OCSP Stapling. * * https://tools.ietf.org/html/rfc6066#section-8 */ -static void ext_ocsp_init(SSL *ssl) { - ssl->s3->tmp.certificate_status_expected = 0; - ssl->tlsext_status_type = -1; -} - -static int ext_ocsp_add_clienthello(SSL *ssl, CBB *out) { +static int ext_ocsp_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) { + SSL *const ssl = hs->ssl; if (!ssl->ocsp_stapling_enabled) { return 1; } @@ -1160,25 +1095,36 @@ static int ext_ocsp_add_clienthello(SSL *ssl, CBB *out) { return 0; } - ssl->tlsext_status_type = TLSEXT_STATUSTYPE_ocsp; return 1; } -static int ext_ocsp_parse_serverhello(SSL *ssl, uint8_t *out_alert, +static int ext_ocsp_parse_serverhello(SSL_HANDSHAKE *hs, uint8_t *out_alert, CBS *contents) { + SSL *const ssl = hs->ssl; if (contents == NULL) { return 1; } - if (CBS_len(contents) != 0) { + /* TLS 1.3 OCSP responses are included in the Certificate extensions. */ + if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) { return 0; } - ssl->s3->tmp.certificate_status_expected = 1; + /* OCSP stapling is forbidden on non-certificate ciphers. */ + if (CBS_len(contents) != 0 || + !ssl_cipher_uses_certificate_auth(hs->new_cipher)) { + return 0; + } + + /* Note this does not check for resumption in TLS 1.2. Sending + * status_request here does not make sense, but OpenSSL does so and the + * specification does not say anything. Tolerate it but ignore it. */ + + hs->certificate_status_expected = 1; return 1; } -static int ext_ocsp_parse_clienthello(SSL *ssl, uint8_t *out_alert, +static int ext_ocsp_parse_clienthello(SSL_HANDSHAKE *hs, uint8_t *out_alert, CBS *contents) { if (contents == NULL) { return 1; @@ -1191,20 +1137,22 @@ static int ext_ocsp_parse_clienthello(SSL *ssl, uint8_t *out_alert, /* We cannot decide whether OCSP stapling will occur yet because the correct * SSL_CTX might not have been selected. */ - ssl->s3->tmp.ocsp_stapling_requested = status_type == TLSEXT_STATUSTYPE_ocsp; + hs->ocsp_stapling_requested = status_type == TLSEXT_STATUSTYPE_ocsp; return 1; } -static int ext_ocsp_add_serverhello(SSL *ssl, CBB *out) { - /* The extension shouldn't be sent when resuming sessions. */ - if (ssl->hit || - !ssl->s3->tmp.ocsp_stapling_requested || - ssl->ctx->ocsp_response_length == 0) { +static int ext_ocsp_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) { + SSL *const ssl = hs->ssl; + if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION || + !hs->ocsp_stapling_requested || + ssl->cert->ocsp_response == NULL || + ssl->s3->session_reused || + !ssl_cipher_uses_certificate_auth(hs->new_cipher)) { return 1; } - ssl->s3->tmp.certificate_status_expected = 1; + hs->certificate_status_expected = 1; return CBB_add_u16(out, TLSEXT_TYPE_status_request) && CBB_add_u16(out, 0 /* length */); @@ -1215,15 +1163,11 @@ static int ext_ocsp_add_serverhello(SSL *ssl, CBB *out) { * * https://htmlpreview.github.io/?https://github.com/agl/technotes/blob/master/nextprotoneg.html */ -static void ext_npn_init(SSL *ssl) { - ssl->s3->next_proto_neg_seen = 0; -} - -static int ext_npn_add_clienthello(SSL *ssl, CBB *out) { +static int ext_npn_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) { + SSL *const ssl = hs->ssl; if (ssl->s3->initial_handshake_complete || ssl->ctx->next_proto_select_cb == NULL || - (ssl->options & SSL_OP_DISABLE_NPN) || - SSL_IS_DTLS(ssl)) { + SSL_is_dtls(ssl)) { return 1; } @@ -1235,19 +1179,23 @@ static int ext_npn_add_clienthello(SSL *ssl, CBB *out) { return 1; } -static int ext_npn_parse_serverhello(SSL *ssl, uint8_t *out_alert, +static int ext_npn_parse_serverhello(SSL_HANDSHAKE *hs, uint8_t *out_alert, CBS *contents) { + SSL *const ssl = hs->ssl; if (contents == NULL) { return 1; } + if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) { + return 0; + } + /* If any of these are false then we should never have sent the NPN * extension in the ClientHello and thus this function should never have been * called. */ assert(!ssl->s3->initial_handshake_complete); - assert(!SSL_IS_DTLS(ssl)); + assert(!SSL_is_dtls(ssl)); assert(ssl->ctx->next_proto_select_cb != NULL); - assert(!(ssl->options & SSL_OP_DISABLE_NPN)); if (ssl->s3->alpn_selected != NULL) { /* NPN and ALPN may not be negotiated in the same connection. */ @@ -1284,36 +1232,38 @@ static int ext_npn_parse_serverhello(SSL *ssl, uint8_t *out_alert, } ssl->s3->next_proto_negotiated_len = selected_len; - ssl->s3->next_proto_neg_seen = 1; + hs->next_proto_neg_seen = 1; return 1; } -static int ext_npn_parse_clienthello(SSL *ssl, uint8_t *out_alert, +static int ext_npn_parse_clienthello(SSL_HANDSHAKE *hs, uint8_t *out_alert, CBS *contents) { + SSL *const ssl = hs->ssl; + if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) { + return 1; + } + if (contents != NULL && CBS_len(contents) != 0) { return 0; } if (contents == NULL || ssl->s3->initial_handshake_complete || - /* If the ALPN extension is seen before NPN, ignore it. (If ALPN is seen - * afterwards, parsing the ALPN extension will clear - * |next_proto_neg_seen|. */ - ssl->s3->alpn_selected != NULL || ssl->ctx->next_protos_advertised_cb == NULL || - SSL_IS_DTLS(ssl)) { + SSL_is_dtls(ssl)) { return 1; } - ssl->s3->next_proto_neg_seen = 1; + hs->next_proto_neg_seen = 1; return 1; } -static int ext_npn_add_serverhello(SSL *ssl, CBB *out) { +static int ext_npn_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) { + SSL *const ssl = hs->ssl; /* |next_proto_neg_seen| might have been cleared when an ALPN extension was * parsed. */ - if (!ssl->s3->next_proto_neg_seen) { + if (!hs->next_proto_neg_seen) { return 1; } @@ -1323,7 +1273,7 @@ static int ext_npn_add_serverhello(SSL *ssl, CBB *out) { if (ssl->ctx->next_protos_advertised_cb( ssl, &npa, &npa_len, ssl->ctx->next_protos_advertised_cb_arg) != SSL_TLSEXT_ERR_OK) { - ssl->s3->next_proto_neg_seen = 0; + hs->next_proto_neg_seen = 0; return 1; } @@ -1343,7 +1293,8 @@ static int ext_npn_add_serverhello(SSL *ssl, CBB *out) { * * https://tools.ietf.org/html/rfc6962#section-3.3.1 */ -static int ext_sct_add_clienthello(SSL *ssl, CBB *out) { +static int ext_sct_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) { + SSL *const ssl = hs->ssl; if (!ssl->signed_cert_timestamps_enabled) { return 1; } @@ -1356,25 +1307,36 @@ static int ext_sct_add_clienthello(SSL *ssl, CBB *out) { return 1; } -static int ext_sct_parse_serverhello(SSL *ssl, uint8_t *out_alert, +static int ext_sct_parse_serverhello(SSL_HANDSHAKE *hs, uint8_t *out_alert, CBS *contents) { + SSL *const ssl = hs->ssl; if (contents == NULL) { return 1; } + /* TLS 1.3 SCTs are included in the Certificate extensions. */ + if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) { + *out_alert = SSL_AD_DECODE_ERROR; + return 0; + } + /* If this is false then we should never have sent the SCT extension in the * ClientHello and thus this function should never have been called. */ assert(ssl->signed_cert_timestamps_enabled); - if (CBS_len(contents) == 0) { + if (!ssl_is_sct_list_valid(contents)) { *out_alert = SSL_AD_DECODE_ERROR; return 0; } - /* Session resumption uses the original session information. */ - if (!ssl->hit && - !CBS_stow(contents, &ssl->session->tlsext_signed_cert_timestamp_list, - &ssl->session->tlsext_signed_cert_timestamp_list_length)) { + /* Session resumption uses the original session information. The extension + * should not be sent on resumption, but RFC 6962 did not make it a + * requirement, so tolerate this. + * + * TODO(davidben): Enforce this anyway. */ + if (!ssl->s3->session_reused && + !CBS_stow(contents, &hs->new_session->tlsext_signed_cert_timestamp_list, + &hs->new_session->tlsext_signed_cert_timestamp_list_length)) { *out_alert = SSL_AD_INTERNAL_ERROR; return 0; } @@ -1382,23 +1344,36 @@ static int ext_sct_parse_serverhello(SSL *ssl, uint8_t *out_alert, return 1; } -static int ext_sct_parse_clienthello(SSL *ssl, uint8_t *out_alert, +static int ext_sct_parse_clienthello(SSL_HANDSHAKE *hs, uint8_t *out_alert, CBS *contents) { - return contents == NULL || CBS_len(contents) == 0; -} - -static int ext_sct_add_serverhello(SSL *ssl, CBB *out) { + if (contents == NULL) { + return 1; + } + + if (CBS_len(contents) != 0) { + return 0; + } + + hs->scts_requested = 1; + return 1; +} + +static int ext_sct_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) { + SSL *const ssl = hs->ssl; /* The extension shouldn't be sent when resuming sessions. */ - if (ssl->hit || - ssl->ctx->signed_cert_timestamp_list_length == 0) { + if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION || + ssl->s3->session_reused || + ssl->cert->signed_cert_timestamp_list == NULL) { return 1; } CBB contents; return CBB_add_u16(out, TLSEXT_TYPE_certificate_timestamp) && CBB_add_u16_length_prefixed(out, &contents) && - CBB_add_bytes(&contents, ssl->ctx->signed_cert_timestamp_list, - ssl->ctx->signed_cert_timestamp_list_length) && + CBB_add_bytes( + &contents, + CRYPTO_BUFFER_data(ssl->cert->signed_cert_timestamp_list), + CRYPTO_BUFFER_len(ssl->cert->signed_cert_timestamp_list)) && CBB_flush(out); } @@ -1407,12 +1382,8 @@ static int ext_sct_add_serverhello(SSL *ssl, CBB *out) { * * https://tools.ietf.org/html/rfc7301 */ -static void ext_alpn_init(SSL *ssl) { - OPENSSL_free(ssl->s3->alpn_selected); - ssl->s3->alpn_selected = NULL; -} - -static int ext_alpn_add_clienthello(SSL *ssl, CBB *out) { +static int ext_alpn_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) { + SSL *const ssl = hs->ssl; if (ssl->alpn_client_proto_list == NULL || ssl->s3->initial_handshake_complete) { return 1; @@ -1431,8 +1402,9 @@ static int ext_alpn_add_clienthello(SSL *ssl, CBB *out) { return 1; } -static int ext_alpn_parse_serverhello(SSL *ssl, uint8_t *out_alert, +static int ext_alpn_parse_serverhello(SSL_HANDSHAKE *hs, uint8_t *out_alert, CBS *contents) { + SSL *const ssl = hs->ssl; if (contents == NULL) { return 1; } @@ -1440,7 +1412,7 @@ static int ext_alpn_parse_serverhello(SSL *ssl, uint8_t *out_alert, assert(!ssl->s3->initial_handshake_complete); assert(ssl->alpn_client_proto_list != NULL); - if (ssl->s3->next_proto_neg_seen) { + if (hs->next_proto_neg_seen) { /* NPN and ALPN may not be negotiated in the same connection. */ *out_alert = SSL_AD_ILLEGAL_PARAMETER; OPENSSL_PUT_ERROR(SSL, SSL_R_NEGOTIATED_BOTH_NPN_AND_ALPN); @@ -1459,6 +1431,33 @@ static int ext_alpn_parse_serverhello(SSL *ssl, uint8_t *out_alert, return 0; } + /* Check that the protcol name is one of the ones we advertised. */ + int protocol_ok = 0; + CBS client_protocol_name_list, client_protocol_name; + CBS_init(&client_protocol_name_list, ssl->alpn_client_proto_list, + ssl->alpn_client_proto_list_len); + while (CBS_len(&client_protocol_name_list) > 0) { + if (!CBS_get_u8_length_prefixed(&client_protocol_name_list, + &client_protocol_name)) { + *out_alert = SSL_AD_INTERNAL_ERROR; + return 0; + } + + if (CBS_len(&client_protocol_name) == CBS_len(&protocol_name) && + OPENSSL_memcmp(CBS_data(&client_protocol_name), + CBS_data(&protocol_name), + CBS_len(&protocol_name)) == 0) { + protocol_ok = 1; + break; + } + } + + if (!protocol_ok) { + OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_ALPN_PROTOCOL); + *out_alert = SSL_AD_ILLEGAL_PARAMETER; + return 0; + } + if (!CBS_stow(&protocol_name, &ssl->s3->alpn_selected, &ssl->s3->alpn_selected_len)) { *out_alert = SSL_AD_INTERNAL_ERROR; @@ -1468,24 +1467,27 @@ static int ext_alpn_parse_serverhello(SSL *ssl, uint8_t *out_alert, return 1; } -static int ext_alpn_parse_clienthello(SSL *ssl, uint8_t *out_alert, - CBS *contents) { - if (contents == NULL) { - return 1; - } - +int ssl_negotiate_alpn(SSL_HANDSHAKE *hs, uint8_t *out_alert, + const SSL_CLIENT_HELLO *client_hello) { + SSL *const ssl = hs->ssl; + CBS contents; if (ssl->ctx->alpn_select_cb == NULL || - ssl->s3->initial_handshake_complete) { + !ssl_client_hello_get_extension( + client_hello, &contents, + TLSEXT_TYPE_application_layer_protocol_negotiation)) { + /* Ignore ALPN if not configured or no extension was supplied. */ return 1; } /* ALPN takes precedence over NPN. */ - ssl->s3->next_proto_neg_seen = 0; + hs->next_proto_neg_seen = 0; CBS protocol_name_list; - if (!CBS_get_u16_length_prefixed(contents, &protocol_name_list) || - CBS_len(contents) != 0 || + if (!CBS_get_u16_length_prefixed(&contents, &protocol_name_list) || + CBS_len(&contents) != 0 || CBS_len(&protocol_name_list) < 2) { + OPENSSL_PUT_ERROR(SSL, SSL_R_PARSE_TLSEXT); + *out_alert = SSL_AD_DECODE_ERROR; return 0; } @@ -1497,6 +1499,8 @@ static int ext_alpn_parse_clienthello(SSL *ssl, uint8_t *out_alert, if (!CBS_get_u8_length_prefixed(&protocol_name_list_copy, &protocol_name) || /* Empty protocol names are forbidden. */ CBS_len(&protocol_name) == 0) { + OPENSSL_PUT_ERROR(SSL, SSL_R_PARSE_TLSEXT); + *out_alert = SSL_AD_DECODE_ERROR; return 0; } } @@ -1519,7 +1523,8 @@ static int ext_alpn_parse_clienthello(SSL *ssl, uint8_t *out_alert, return 1; } -static int ext_alpn_add_serverhello(SSL *ssl, CBB *out) { +static int ext_alpn_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) { + SSL *const ssl = hs->ssl; if (ssl->s3->alpn_selected == NULL) { return 1; } @@ -1543,13 +1548,14 @@ static int ext_alpn_add_serverhello(SSL *ssl, CBB *out) { * * https://tools.ietf.org/html/draft-balfanz-tls-channelid-01 */ -static void ext_channel_id_init(SSL *ssl) { - ssl->s3->tlsext_channel_id_valid = 0; +static void ext_channel_id_init(SSL_HANDSHAKE *hs) { + hs->ssl->s3->tlsext_channel_id_valid = 0; } -static int ext_channel_id_add_clienthello(SSL *ssl, CBB *out) { +static int ext_channel_id_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) { + SSL *const ssl = hs->ssl; if (!ssl->tlsext_channel_id_enabled || - SSL_IS_DTLS(ssl)) { + SSL_is_dtls(ssl)) { return 1; } @@ -1561,13 +1567,14 @@ static int ext_channel_id_add_clienthello(SSL *ssl, CBB *out) { return 1; } -static int ext_channel_id_parse_serverhello(SSL *ssl, uint8_t *out_alert, - CBS *contents) { +static int ext_channel_id_parse_serverhello(SSL_HANDSHAKE *hs, + uint8_t *out_alert, CBS *contents) { + SSL *const ssl = hs->ssl; if (contents == NULL) { return 1; } - assert(!SSL_IS_DTLS(ssl)); + assert(!SSL_is_dtls(ssl)); assert(ssl->tlsext_channel_id_enabled); if (CBS_len(contents) != 0) { @@ -1578,11 +1585,12 @@ static int ext_channel_id_parse_serverhello(SSL *ssl, uint8_t *out_alert, return 1; } -static int ext_channel_id_parse_clienthello(SSL *ssl, uint8_t *out_alert, - CBS *contents) { +static int ext_channel_id_parse_clienthello(SSL_HANDSHAKE *hs, + uint8_t *out_alert, CBS *contents) { + SSL *const ssl = hs->ssl; if (contents == NULL || !ssl->tlsext_channel_id_enabled || - SSL_IS_DTLS(ssl)) { + SSL_is_dtls(ssl)) { return 1; } @@ -1594,7 +1602,8 @@ static int ext_channel_id_parse_clienthello(SSL *ssl, uint8_t *out_alert, return 1; } -static int ext_channel_id_add_serverhello(SSL *ssl, CBB *out) { +static int ext_channel_id_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) { + SSL *const ssl = hs->ssl; if (!ssl->s3->tlsext_channel_id_valid) { return 1; } @@ -1613,11 +1622,12 @@ static int ext_channel_id_add_serverhello(SSL *ssl, CBB *out) { * https://tools.ietf.org/html/rfc5764 */ -static void ext_srtp_init(SSL *ssl) { - ssl->srtp_profile = NULL; +static void ext_srtp_init(SSL_HANDSHAKE *hs) { + hs->ssl->srtp_profile = NULL; } -static int ext_srtp_add_clienthello(SSL *ssl, CBB *out) { +static int ext_srtp_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) { + SSL *const ssl = hs->ssl; STACK_OF(SRTP_PROTECTION_PROFILE) *profiles = SSL_get_srtp_profiles(ssl); if (profiles == NULL) { return 1; @@ -1634,8 +1644,7 @@ static int ext_srtp_add_clienthello(SSL *ssl, CBB *out) { return 0; } - size_t i; - for (i = 0; i < num_profiles; i++) { + for (size_t i = 0; i < num_profiles; i++) { if (!CBB_add_u16(&profile_ids, sk_SRTP_PROTECTION_PROFILE_value(profiles, i)->id)) { return 0; @@ -1650,8 +1659,9 @@ static int ext_srtp_add_clienthello(SSL *ssl, CBB *out) { return 1; } -static int ext_srtp_parse_serverhello(SSL *ssl, uint8_t *out_alert, +static int ext_srtp_parse_serverhello(SSL_HANDSHAKE *hs, uint8_t *out_alert, CBS *contents) { + SSL *const ssl = hs->ssl; if (contents == NULL) { return 1; } @@ -1682,8 +1692,7 @@ static int ext_srtp_parse_serverhello(SSL *ssl, uint8_t *out_alert, /* Check to see if the server gave us something we support (and presumably * offered). */ - size_t i; - for (i = 0; i < sk_SRTP_PROTECTION_PROFILE_num(profiles); i++) { + for (size_t i = 0; i < sk_SRTP_PROTECTION_PROFILE_num(profiles); i++) { const SRTP_PROTECTION_PROFILE *profile = sk_SRTP_PROTECTION_PROFILE_value(profiles, i); @@ -1698,8 +1707,9 @@ static int ext_srtp_parse_serverhello(SSL *ssl, uint8_t *out_alert, return 0; } -static int ext_srtp_parse_clienthello(SSL *ssl, uint8_t *out_alert, +static int ext_srtp_parse_clienthello(SSL_HANDSHAKE *hs, uint8_t *out_alert, CBS *contents) { + SSL *const ssl = hs->ssl; if (contents == NULL) { return 1; } @@ -1718,8 +1728,7 @@ static int ext_srtp_parse_clienthello(SSL *ssl, uint8_t *out_alert, SSL_get_srtp_profiles(ssl); /* Pick the server's most preferred profile. */ - size_t i; - for (i = 0; i < sk_SRTP_PROTECTION_PROFILE_num(server_profiles); i++) { + for (size_t i = 0; i < sk_SRTP_PROTECTION_PROFILE_num(server_profiles); i++) { const SRTP_PROTECTION_PROFILE *server_profile = sk_SRTP_PROTECTION_PROFILE_value(server_profiles, i); @@ -1742,7 +1751,8 @@ static int ext_srtp_parse_clienthello(SSL *ssl, uint8_t *out_alert, return 1; } -static int ext_srtp_add_serverhello(SSL *ssl, CBB *out) { +static int ext_srtp_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) { + SSL *const ssl = hs->ssl; if (ssl->srtp_profile == NULL) { return 1; } @@ -1765,28 +1775,7 @@ static int ext_srtp_add_serverhello(SSL *ssl, CBB *out) { * * https://tools.ietf.org/html/rfc4492#section-5.1.2 */ -static int ssl_any_ec_cipher_suites_enabled(const SSL *ssl) { - if (ssl->version < TLS1_VERSION && !SSL_IS_DTLS(ssl)) { - return 0; - } - - const STACK_OF(SSL_CIPHER) *cipher_stack = SSL_get_ciphers(ssl); - - size_t i; - for (i = 0; i < sk_SSL_CIPHER_num(cipher_stack); i++) { - const SSL_CIPHER *cipher = sk_SSL_CIPHER_value(cipher_stack, i); - - const uint32_t alg_k = cipher->algorithm_mkey; - const uint32_t alg_a = cipher->algorithm_auth; - if ((alg_k & SSL_kECDHE) || (alg_a & SSL_aECDSA)) { - return 1; - } - } - - return 0; -} - -static int ext_ec_point_add_extension(SSL *ssl, CBB *out) { +static int ext_ec_point_add_extension(SSL_HANDSHAKE *hs, CBB *out) { CBB contents, formats; if (!CBB_add_u16(out, TLSEXT_TYPE_ec_point_formats) || !CBB_add_u16_length_prefixed(out, &contents) || @@ -1799,20 +1788,30 @@ static int ext_ec_point_add_extension(SSL *ssl, CBB *out) { return 1; } -static int ext_ec_point_add_clienthello(SSL *ssl, CBB *out) { - if (!ssl_any_ec_cipher_suites_enabled(ssl)) { +static int ext_ec_point_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) { + uint16_t min_version, max_version; + if (!ssl_get_version_range(hs->ssl, &min_version, &max_version)) { + return 0; + } + + /* The point format extension is unneccessary in TLS 1.3. */ + if (min_version >= TLS1_3_VERSION) { return 1; } - return ext_ec_point_add_extension(ssl, out); + return ext_ec_point_add_extension(hs, out); } -static int ext_ec_point_parse_serverhello(SSL *ssl, uint8_t *out_alert, +static int ext_ec_point_parse_serverhello(SSL_HANDSHAKE *hs, uint8_t *out_alert, CBS *contents) { if (contents == NULL) { return 1; } + if (ssl3_protocol_version(hs->ssl) >= TLS1_3_VERSION) { + return 0; + } + CBS ec_point_format_list; if (!CBS_get_u8_length_prefixed(contents, &ec_point_format_list) || CBS_len(contents) != 0) { @@ -1821,8 +1820,9 @@ static int ext_ec_point_parse_serverhello(SSL *ssl, uint8_t *out_alert, /* Per RFC 4492, section 5.1.2, implementations MUST support the uncompressed * point format. */ - if (memchr(CBS_data(&ec_point_format_list), TLSEXT_ECPOINTFORMAT_uncompressed, - CBS_len(&ec_point_format_list)) == NULL) { + if (OPENSSL_memchr(CBS_data(&ec_point_format_list), + TLSEXT_ECPOINTFORMAT_uncompressed, + CBS_len(&ec_point_format_list)) == NULL) { *out_alert = SSL_AD_ILLEGAL_PARAMETER; return 0; } @@ -1830,303 +1830,978 @@ static int ext_ec_point_parse_serverhello(SSL *ssl, uint8_t *out_alert, return 1; } -static int ext_ec_point_parse_clienthello(SSL *ssl, uint8_t *out_alert, +static int ext_ec_point_parse_clienthello(SSL_HANDSHAKE *hs, uint8_t *out_alert, CBS *contents) { - return ext_ec_point_parse_serverhello(ssl, out_alert, contents); + if (ssl3_protocol_version(hs->ssl) >= TLS1_3_VERSION) { + return 1; + } + + return ext_ec_point_parse_serverhello(hs, out_alert, contents); } -static int ext_ec_point_add_serverhello(SSL *ssl, CBB *out) { - const uint32_t alg_k = ssl->s3->tmp.new_cipher->algorithm_mkey; - const uint32_t alg_a = ssl->s3->tmp.new_cipher->algorithm_auth; +static int ext_ec_point_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) { + SSL *const ssl = hs->ssl; + if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) { + return 1; + } + + const uint32_t alg_k = hs->new_cipher->algorithm_mkey; + const uint32_t alg_a = hs->new_cipher->algorithm_auth; const int using_ecc = (alg_k & SSL_kECDHE) || (alg_a & SSL_aECDSA); if (!using_ecc) { return 1; } - return ext_ec_point_add_extension(ssl, out); + return ext_ec_point_add_extension(hs, out); } -/* EC supported curves. +/* Pre Shared Key * - * https://tools.ietf.org/html/rfc4492#section-5.1.2 */ + * https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.6 */ -static void ext_ec_curves_init(SSL *ssl) { - OPENSSL_free(ssl->s3->tmp.peer_ellipticcurvelist); - ssl->s3->tmp.peer_ellipticcurvelist = NULL; - ssl->s3->tmp.peer_ellipticcurvelist_length = 0; -} - -static int ext_ec_curves_add_clienthello(SSL *ssl, CBB *out) { - if (!ssl_any_ec_cipher_suites_enabled(ssl)) { - return 1; +static size_t ext_pre_shared_key_clienthello_length(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + uint16_t min_version, max_version; + if (!ssl_get_version_range(ssl, &min_version, &max_version)) { + return 0; } - CBB contents, curves_bytes; - if (!CBB_add_u16(out, TLSEXT_TYPE_elliptic_curves) || - !CBB_add_u16_length_prefixed(out, &contents) || - !CBB_add_u16_length_prefixed(&contents, &curves_bytes)) { + uint16_t session_version; + if (max_version < TLS1_3_VERSION || ssl->session == NULL || + !ssl->method->version_from_wire(&session_version, + ssl->session->ssl_version) || + session_version < TLS1_3_VERSION) { return 0; } - const uint16_t *curves; - size_t curves_len; - tls1_get_curvelist(ssl, 0, &curves, &curves_len); - - size_t i; - for (i = 0; i < curves_len; i++) { - if (!CBB_add_u16(&curves_bytes, curves[i])) { - return 0; - } + const EVP_MD *digest = SSL_SESSION_get_digest(ssl->session, ssl); + if (digest == NULL) { + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + return 0; } - return CBB_flush(out); + size_t binder_len = EVP_MD_size(digest); + return 15 + ssl->session->tlsext_ticklen + binder_len; } -static int ext_ec_curves_parse_serverhello(SSL *ssl, uint8_t *out_alert, - CBS *contents) { - /* This extension is not expected to be echoed by servers and is ignored. */ - return 1; -} +static int ext_pre_shared_key_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) { + SSL *const ssl = hs->ssl; + uint16_t min_version, max_version; + if (!ssl_get_version_range(ssl, &min_version, &max_version)) { + return 0; + } -static int ext_ec_curves_parse_clienthello(SSL *ssl, uint8_t *out_alert, - CBS *contents) { - if (contents == NULL) { + uint16_t session_version; + if (max_version < TLS1_3_VERSION || ssl->session == NULL || + !ssl->method->version_from_wire(&session_version, + ssl->session->ssl_version) || + session_version < TLS1_3_VERSION) { return 1; } - CBS elliptic_curve_list; - if (!CBS_get_u16_length_prefixed(contents, &elliptic_curve_list) || - CBS_len(&elliptic_curve_list) == 0 || - (CBS_len(&elliptic_curve_list) & 1) != 0 || - CBS_len(contents) != 0) { - return 0; - } + struct timeval now; + ssl_get_current_time(ssl, &now); + uint32_t ticket_age = 1000 * (now.tv_sec - ssl->session->time); + uint32_t obfuscated_ticket_age = ticket_age + ssl->session->ticket_age_add; - ssl->s3->tmp.peer_ellipticcurvelist = OPENSSL_malloc(CBS_len(&elliptic_curve_list)); - if (ssl->s3->tmp.peer_ellipticcurvelist == NULL) { - *out_alert = SSL_AD_INTERNAL_ERROR; + /* Fill in a placeholder zero binder of the appropriate length. It will be + * computed and filled in later after length prefixes are computed. */ + uint8_t zero_binder[EVP_MAX_MD_SIZE] = {0}; + + const EVP_MD *digest = SSL_SESSION_get_digest(ssl->session, ssl); + if (digest == NULL) { + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); return 0; } - const size_t num_curves = CBS_len(&elliptic_curve_list) / 2; - size_t i; - for (i = 0; i < num_curves; i++) { - if (!CBS_get_u16(&elliptic_curve_list, - &ssl->s3->tmp.peer_ellipticcurvelist[i])) { - goto err; - } + size_t binder_len = EVP_MD_size(digest); + + CBB contents, identity, ticket, binders, binder; + if (!CBB_add_u16(out, TLSEXT_TYPE_pre_shared_key) || + !CBB_add_u16_length_prefixed(out, &contents) || + !CBB_add_u16_length_prefixed(&contents, &identity) || + !CBB_add_u16_length_prefixed(&identity, &ticket) || + !CBB_add_bytes(&ticket, ssl->session->tlsext_tick, + ssl->session->tlsext_ticklen) || + !CBB_add_u32(&identity, obfuscated_ticket_age) || + !CBB_add_u16_length_prefixed(&contents, &binders) || + !CBB_add_u8_length_prefixed(&binders, &binder) || + !CBB_add_bytes(&binder, zero_binder, binder_len)) { + return 0; } - assert(CBS_len(&elliptic_curve_list) == 0); - ssl->s3->tmp.peer_ellipticcurvelist_length = num_curves; + hs->needs_psk_binder = 1; + return CBB_flush(out); +} - return 1; +int ssl_ext_pre_shared_key_parse_serverhello(SSL_HANDSHAKE *hs, + uint8_t *out_alert, + CBS *contents) { + uint16_t psk_id; + if (!CBS_get_u16(contents, &psk_id) || + CBS_len(contents) != 0) { + OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + *out_alert = SSL_AD_DECODE_ERROR; + return 0; + } -err: - OPENSSL_free(ssl->s3->tmp.peer_ellipticcurvelist); - ssl->s3->tmp.peer_ellipticcurvelist = NULL; - *out_alert = SSL_AD_INTERNAL_ERROR; - return 0; -} + /* We only advertise one PSK identity, so the only legal index is zero. */ + if (psk_id != 0) { + OPENSSL_PUT_ERROR(SSL, SSL_R_PSK_IDENTITY_NOT_FOUND); + *out_alert = SSL_AD_UNKNOWN_PSK_IDENTITY; + return 0; + } -static int ext_ec_curves_add_serverhello(SSL *ssl, CBB *out) { - /* Servers don't echo this extension. */ return 1; } +int ssl_ext_pre_shared_key_parse_clienthello(SSL_HANDSHAKE *hs, + SSL_SESSION **out_session, + CBS *out_binders, + uint8_t *out_alert, + CBS *contents) { + SSL *const ssl = hs->ssl; + /* We only process the first PSK identity since we don't support pure PSK. */ + uint32_t obfuscated_ticket_age; + CBS identities, ticket, binders; + if (!CBS_get_u16_length_prefixed(contents, &identities) || + !CBS_get_u16_length_prefixed(&identities, &ticket) || + !CBS_get_u32(&identities, &obfuscated_ticket_age) || + !CBS_get_u16_length_prefixed(contents, &binders) || + CBS_len(&binders) == 0 || + CBS_len(contents) != 0) { + OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + *out_alert = SSL_AD_DECODE_ERROR; + return 0; + } -/* kExtensions contains all the supported extensions. */ -static const struct tls_extension kExtensions[] = { - { - /* The renegotiation extension must always be at index zero because the - * |received| and |sent| bitsets need to be tweaked when the "extension" is - * sent as an SCSV. */ - TLSEXT_TYPE_renegotiate, - NULL, - ext_ri_add_clienthello, - ext_ri_parse_serverhello, - ext_ri_parse_clienthello, - ext_ri_add_serverhello, - }, - { - TLSEXT_TYPE_server_name, - ext_sni_init, - ext_sni_add_clienthello, - ext_sni_parse_serverhello, - ext_sni_parse_clienthello, - ext_sni_add_serverhello, - }, - { - TLSEXT_TYPE_extended_master_secret, - ext_ems_init, - ext_ems_add_clienthello, - ext_ems_parse_serverhello, - ext_ems_parse_clienthello, - ext_ems_add_serverhello, - }, - { - TLSEXT_TYPE_session_ticket, - NULL, - ext_ticket_add_clienthello, - ext_ticket_parse_serverhello, - ext_ticket_parse_clienthello, - ext_ticket_add_serverhello, - }, - { - TLSEXT_TYPE_signature_algorithms, - NULL, - ext_sigalgs_add_clienthello, - ext_sigalgs_parse_serverhello, - ext_sigalgs_parse_clienthello, - ext_sigalgs_add_serverhello, - }, - { - TLSEXT_TYPE_status_request, - ext_ocsp_init, - ext_ocsp_add_clienthello, - ext_ocsp_parse_serverhello, - ext_ocsp_parse_clienthello, - ext_ocsp_add_serverhello, - }, - { - TLSEXT_TYPE_next_proto_neg, - ext_npn_init, - ext_npn_add_clienthello, - ext_npn_parse_serverhello, - ext_npn_parse_clienthello, - ext_npn_add_serverhello, - }, - { - TLSEXT_TYPE_certificate_timestamp, - NULL, - ext_sct_add_clienthello, - ext_sct_parse_serverhello, - ext_sct_parse_clienthello, - ext_sct_add_serverhello, - }, - { - TLSEXT_TYPE_application_layer_protocol_negotiation, - ext_alpn_init, - ext_alpn_add_clienthello, - ext_alpn_parse_serverhello, - ext_alpn_parse_clienthello, - ext_alpn_add_serverhello, - }, - { - TLSEXT_TYPE_channel_id, - ext_channel_id_init, - ext_channel_id_add_clienthello, - ext_channel_id_parse_serverhello, - ext_channel_id_parse_clienthello, - ext_channel_id_add_serverhello, - }, - { - TLSEXT_TYPE_srtp, - ext_srtp_init, - ext_srtp_add_clienthello, - ext_srtp_parse_serverhello, - ext_srtp_parse_clienthello, - ext_srtp_add_serverhello, - }, - { - TLSEXT_TYPE_ec_point_formats, - NULL, - ext_ec_point_add_clienthello, - ext_ec_point_parse_serverhello, - ext_ec_point_parse_clienthello, - ext_ec_point_add_serverhello, - }, - { - TLSEXT_TYPE_elliptic_curves, - ext_ec_curves_init, - ext_ec_curves_add_clienthello, - ext_ec_curves_parse_serverhello, - ext_ec_curves_parse_clienthello, - ext_ec_curves_add_serverhello, - }, -}; + *out_binders = binders; -#define kNumExtensions (sizeof(kExtensions) / sizeof(struct tls_extension)) + /* Check the syntax of the remaining identities, but do not process them. */ + size_t num_identities = 1; + while (CBS_len(&identities) != 0) { + CBS unused_ticket; + uint32_t unused_obfuscated_ticket_age; + if (!CBS_get_u16_length_prefixed(&identities, &unused_ticket) || + !CBS_get_u32(&identities, &unused_obfuscated_ticket_age)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + *out_alert = SSL_AD_DECODE_ERROR; + return 0; + } -OPENSSL_COMPILE_ASSERT(kNumExtensions <= - sizeof(((SSL *)NULL)->s3->tmp.extensions.sent) * 8, - too_many_extensions_for_sent_bitset); -OPENSSL_COMPILE_ASSERT(kNumExtensions <= - sizeof(((SSL *)NULL)->s3->tmp.extensions.received) * - 8, - too_many_extensions_for_received_bitset); + num_identities++; + } -static const struct tls_extension *tls_extension_find(uint32_t *out_index, - uint16_t value) { - unsigned i; - for (i = 0; i < kNumExtensions; i++) { - if (kExtensions[i].value == value) { - *out_index = i; - return &kExtensions[i]; + /* Check the syntax of the binders. The value will be checked later if + * resuming. */ + size_t num_binders = 0; + while (CBS_len(&binders) != 0) { + CBS binder; + if (!CBS_get_u8_length_prefixed(&binders, &binder)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + *out_alert = SSL_AD_DECODE_ERROR; + return 0; } + + num_binders++; } - return NULL; -} + if (num_identities != num_binders) { + OPENSSL_PUT_ERROR(SSL, SSL_R_PSK_IDENTITY_BINDER_COUNT_MISMATCH); + *out_alert = SSL_AD_ILLEGAL_PARAMETER; + return 0; + } -int SSL_extension_supported(unsigned extension_value) { - uint32_t index; - return extension_value == TLSEXT_TYPE_padding || - tls_extension_find(&index, extension_value) != NULL; + /* TODO(svaldez): Check that the ticket_age is valid when attempting to use + * the PSK for 0-RTT. http://crbug.com/boringssl/113 */ + + /* TLS 1.3 session tickets are renewed separately as part of the + * NewSessionTicket. */ + int unused_renew; + if (!tls_process_ticket(ssl, out_session, &unused_renew, CBS_data(&ticket), + CBS_len(&ticket), NULL, 0)) { + *out_alert = SSL_AD_INTERNAL_ERROR; + return 0; + } + + return 1; } -int ssl_add_clienthello_tlsext(SSL *ssl, CBB *out, size_t header_len) { - /* don't add extensions for SSLv3 unless doing secure renegotiation */ - if (ssl->client_version == SSL3_VERSION && - !ssl->s3->send_connection_binding) { +int ssl_ext_pre_shared_key_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) { + if (!hs->ssl->s3->session_reused) { return 1; } - CBB extensions; - if (!CBB_add_u16_length_prefixed(out, &extensions)) { - goto err; + CBB contents; + if (!CBB_add_u16(out, TLSEXT_TYPE_pre_shared_key) || + !CBB_add_u16_length_prefixed(out, &contents) || + /* We only consider the first identity for resumption */ + !CBB_add_u16(&contents, 0) || + !CBB_flush(out)) { + return 0; } - ssl->s3->tmp.extensions.sent = 0; - ssl->s3->tmp.custom_extensions.sent = 0; + return 1; +} - size_t i; - for (i = 0; i < kNumExtensions; i++) { - if (kExtensions[i].init != NULL) { - kExtensions[i].init(ssl); - } - } - for (i = 0; i < kNumExtensions; i++) { - const size_t len_before = CBB_len(&extensions); - if (!kExtensions[i].add_clienthello(ssl, &extensions)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_ADDING_EXTENSION); - ERR_add_error_dataf("extension: %u", (unsigned)kExtensions[i].value); - goto err; - } +/* Pre-Shared Key Exchange Modes + * + * https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.7 */ - if (CBB_len(&extensions) != len_before) { - ssl->s3->tmp.extensions.sent |= (1u << i); - } +static int ext_psk_key_exchange_modes_add_clienthello(SSL_HANDSHAKE *hs, + CBB *out) { + SSL *const ssl = hs->ssl; + uint16_t min_version, max_version; + if (!ssl_get_version_range(ssl, &min_version, &max_version)) { + return 0; } - if (!custom_ext_add_clienthello(ssl, &extensions)) { - goto err; + if (max_version < TLS1_3_VERSION) { + return 1; } - if (!SSL_IS_DTLS(ssl)) { - header_len += 2 + CBB_len(&extensions); - if (header_len > 0xff && header_len < 0x200) { + CBB contents, ke_modes; + if (!CBB_add_u16(out, TLSEXT_TYPE_psk_key_exchange_modes) || + !CBB_add_u16_length_prefixed(out, &contents) || + !CBB_add_u8_length_prefixed(&contents, &ke_modes) || + !CBB_add_u8(&ke_modes, SSL_PSK_DHE_KE)) { + return 0; + } + + return CBB_flush(out); +} + +static int ext_psk_key_exchange_modes_parse_clienthello(SSL_HANDSHAKE *hs, + uint8_t *out_alert, + CBS *contents) { + if (contents == NULL) { + return 1; + } + + CBS ke_modes; + if (!CBS_get_u8_length_prefixed(contents, &ke_modes) || + CBS_len(&ke_modes) == 0 || + CBS_len(contents) != 0) { + *out_alert = SSL_AD_DECODE_ERROR; + return 0; + } + + /* We only support tickets with PSK_DHE_KE. */ + hs->accept_psk_mode = OPENSSL_memchr(CBS_data(&ke_modes), SSL_PSK_DHE_KE, + CBS_len(&ke_modes)) != NULL; + + return 1; +} + + +/* Early Data Indication + * + * https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.8 */ + +static int ext_early_data_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) { + /* TODO(svaldez): Support 0RTT. */ + return 1; +} + +static int ext_early_data_parse_clienthello(SSL_HANDSHAKE *hs, + uint8_t *out_alert, CBS *contents) { + SSL *const ssl = hs->ssl; + if (contents == NULL) { + return 1; + } + + if (CBS_len(contents) != 0) { + *out_alert = SSL_AD_DECODE_ERROR; + return 0; + } + + /* Since we don't currently accept 0-RTT, we have to skip past any early data + * the client might have sent. */ + if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) { + ssl->s3->skip_early_data = 1; + } + return 1; +} + + +/* Key Share + * + * https://tools.ietf.org/html/draft-ietf-tls-tls13-16#section-4.2.5 */ + +static int ext_key_share_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) { + SSL *const ssl = hs->ssl; + uint16_t min_version, max_version; + if (!ssl_get_version_range(ssl, &min_version, &max_version)) { + return 0; + } + + if (max_version < TLS1_3_VERSION) { + return 1; + } + + CBB contents, kse_bytes; + if (!CBB_add_u16(out, TLSEXT_TYPE_key_share) || + !CBB_add_u16_length_prefixed(out, &contents) || + !CBB_add_u16_length_prefixed(&contents, &kse_bytes)) { + return 0; + } + + uint16_t group_id = hs->retry_group; + if (hs->received_hello_retry_request) { + /* We received a HelloRetryRequest without a new curve, so there is no new + * share to append. Leave |ecdh_ctx| as-is. */ + if (group_id == 0 && + !CBB_add_bytes(&kse_bytes, hs->key_share_bytes, + hs->key_share_bytes_len)) { + return 0; + } + OPENSSL_free(hs->key_share_bytes); + hs->key_share_bytes = NULL; + hs->key_share_bytes_len = 0; + if (group_id == 0) { + return CBB_flush(out); + } + } else { + /* Add a fake group. See draft-davidben-tls-grease-01. */ + if (ssl->ctx->grease_enabled && + (!CBB_add_u16(&kse_bytes, + ssl_get_grease_value(ssl, ssl_grease_group)) || + !CBB_add_u16(&kse_bytes, 1 /* length */) || + !CBB_add_u8(&kse_bytes, 0 /* one byte key share */))) { + return 0; + } + + /* Predict the most preferred group. */ + const uint16_t *groups; + size_t groups_len; + tls1_get_grouplist(ssl, &groups, &groups_len); + if (groups_len == 0) { + OPENSSL_PUT_ERROR(SSL, SSL_R_NO_GROUPS_SPECIFIED); + return 0; + } + + group_id = groups[0]; + } + + CBB key_exchange; + if (!CBB_add_u16(&kse_bytes, group_id) || + !CBB_add_u16_length_prefixed(&kse_bytes, &key_exchange) || + !SSL_ECDH_CTX_init(&hs->ecdh_ctx, group_id) || + !SSL_ECDH_CTX_offer(&hs->ecdh_ctx, &key_exchange) || + !CBB_flush(&kse_bytes)) { + return 0; + } + + if (!hs->received_hello_retry_request) { + /* Save the contents of the extension to repeat it in the second + * ClientHello. */ + hs->key_share_bytes_len = CBB_len(&kse_bytes); + hs->key_share_bytes = BUF_memdup(CBB_data(&kse_bytes), CBB_len(&kse_bytes)); + if (hs->key_share_bytes == NULL) { + return 0; + } + } + + return CBB_flush(out); +} + +int ssl_ext_key_share_parse_serverhello(SSL_HANDSHAKE *hs, uint8_t **out_secret, + size_t *out_secret_len, + uint8_t *out_alert, CBS *contents) { + CBS peer_key; + uint16_t group_id; + if (!CBS_get_u16(contents, &group_id) || + !CBS_get_u16_length_prefixed(contents, &peer_key) || + CBS_len(contents) != 0) { + *out_alert = SSL_AD_DECODE_ERROR; + return 0; + } + + if (SSL_ECDH_CTX_get_id(&hs->ecdh_ctx) != group_id) { + *out_alert = SSL_AD_ILLEGAL_PARAMETER; + OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CURVE); + return 0; + } + + if (!SSL_ECDH_CTX_finish(&hs->ecdh_ctx, out_secret, out_secret_len, out_alert, + CBS_data(&peer_key), CBS_len(&peer_key))) { + *out_alert = SSL_AD_INTERNAL_ERROR; + return 0; + } + + hs->new_session->group_id = group_id; + SSL_ECDH_CTX_cleanup(&hs->ecdh_ctx); + return 1; +} + +int ssl_ext_key_share_parse_clienthello(SSL_HANDSHAKE *hs, int *out_found, + uint8_t **out_secret, + size_t *out_secret_len, + uint8_t *out_alert, CBS *contents) { + uint16_t group_id; + CBS key_shares; + if (!tls1_get_shared_group(hs, &group_id)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_NO_SHARED_GROUP); + *out_alert = SSL_AD_HANDSHAKE_FAILURE; + return 0; + } + + if (!CBS_get_u16_length_prefixed(contents, &key_shares) || + CBS_len(contents) != 0) { + OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + return 0; + } + + /* Find the corresponding key share. */ + int found = 0; + CBS peer_key; + while (CBS_len(&key_shares) > 0) { + uint16_t id; + CBS peer_key_tmp; + if (!CBS_get_u16(&key_shares, &id) || + !CBS_get_u16_length_prefixed(&key_shares, &peer_key_tmp)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + return 0; + } + + if (id == group_id) { + if (found) { + OPENSSL_PUT_ERROR(SSL, SSL_R_DUPLICATE_KEY_SHARE); + *out_alert = SSL_AD_ILLEGAL_PARAMETER; + return 0; + } + + found = 1; + peer_key = peer_key_tmp; + /* Continue parsing the structure to keep peers honest. */ + } + } + + if (!found) { + *out_found = 0; + *out_secret = NULL; + *out_secret_len = 0; + return 1; + } + + /* Compute the DH secret. */ + uint8_t *secret = NULL; + size_t secret_len; + SSL_ECDH_CTX group; + OPENSSL_memset(&group, 0, sizeof(SSL_ECDH_CTX)); + CBB public_key; + if (!CBB_init(&public_key, 32) || + !SSL_ECDH_CTX_init(&group, group_id) || + !SSL_ECDH_CTX_accept(&group, &public_key, &secret, &secret_len, out_alert, + CBS_data(&peer_key), CBS_len(&peer_key)) || + !CBB_finish(&public_key, &hs->public_key, &hs->public_key_len)) { + OPENSSL_free(secret); + SSL_ECDH_CTX_cleanup(&group); + CBB_cleanup(&public_key); + *out_alert = SSL_AD_ILLEGAL_PARAMETER; + return 0; + } + + SSL_ECDH_CTX_cleanup(&group); + + *out_secret = secret; + *out_secret_len = secret_len; + *out_found = 1; + return 1; +} + +int ssl_ext_key_share_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) { + uint16_t group_id; + CBB kse_bytes, public_key; + if (!tls1_get_shared_group(hs, &group_id) || + !CBB_add_u16(out, TLSEXT_TYPE_key_share) || + !CBB_add_u16_length_prefixed(out, &kse_bytes) || + !CBB_add_u16(&kse_bytes, group_id) || + !CBB_add_u16_length_prefixed(&kse_bytes, &public_key) || + !CBB_add_bytes(&public_key, hs->public_key, hs->public_key_len) || + !CBB_flush(out)) { + return 0; + } + + OPENSSL_free(hs->public_key); + hs->public_key = NULL; + hs->public_key_len = 0; + + hs->new_session->group_id = group_id; + return 1; +} + + +/* Supported Versions + * + * https://tools.ietf.org/html/draft-ietf-tls-tls13-16#section-4.2.1 */ + +static int ext_supported_versions_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) { + SSL *const ssl = hs->ssl; + uint16_t min_version, max_version; + if (!ssl_get_version_range(ssl, &min_version, &max_version)) { + return 0; + } + + if (max_version <= TLS1_2_VERSION) { + return 1; + } + + CBB contents, versions; + if (!CBB_add_u16(out, TLSEXT_TYPE_supported_versions) || + !CBB_add_u16_length_prefixed(out, &contents) || + !CBB_add_u8_length_prefixed(&contents, &versions)) { + return 0; + } + + /* Add a fake version. See draft-davidben-tls-grease-01. */ + if (ssl->ctx->grease_enabled && + !CBB_add_u16(&versions, ssl_get_grease_value(ssl, ssl_grease_version))) { + return 0; + } + + for (uint16_t version = max_version; version >= min_version; version--) { + if (!CBB_add_u16(&versions, ssl->method->version_to_wire(version))) { + return 0; + } + } + + if (!CBB_flush(out)) { + return 0; + } + + return 1; +} + + +/* Cookie + * + * https://tools.ietf.org/html/draft-ietf-tls-tls13-16#section-4.2.2 */ + +static int ext_cookie_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) { + if (hs->cookie == NULL) { + return 1; + } + + CBB contents, cookie; + if (!CBB_add_u16(out, TLSEXT_TYPE_cookie) || + !CBB_add_u16_length_prefixed(out, &contents) || + !CBB_add_u16_length_prefixed(&contents, &cookie) || + !CBB_add_bytes(&cookie, hs->cookie, hs->cookie_len) || + !CBB_flush(out)) { + return 0; + } + + /* The cookie is no longer needed in memory. */ + OPENSSL_free(hs->cookie); + hs->cookie = NULL; + hs->cookie_len = 0; + return 1; +} + + +/* Short record headers + * + * This is a non-standard extension which negotiates + * https://github.com/tlswg/tls13-spec/pull/762 for experimenting. */ + +static int ext_short_header_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) { + SSL *const ssl = hs->ssl; + uint16_t min_version, max_version; + if (!ssl_get_version_range(ssl, &min_version, &max_version)) { + return 0; + } + + if (max_version < TLS1_3_VERSION || + !ssl->ctx->short_header_enabled) { + return 1; + } + + return CBB_add_u16(out, TLSEXT_TYPE_short_header) && + CBB_add_u16(out, 0 /* empty extension */); +} + +static int ext_short_header_parse_clienthello(SSL_HANDSHAKE *hs, + uint8_t *out_alert, + CBS *contents) { + SSL *const ssl = hs->ssl; + if (contents == NULL || + !ssl->ctx->short_header_enabled || + ssl3_protocol_version(ssl) < TLS1_3_VERSION) { + return 1; + } + + if (CBS_len(contents) != 0) { + return 0; + } + + ssl->s3->short_header = 1; + return 1; +} + + +/* Negotiated Groups + * + * https://tools.ietf.org/html/rfc4492#section-5.1.2 + * https://tools.ietf.org/html/draft-ietf-tls-tls13-16#section-4.2.4 */ + +static int ext_supported_groups_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) { + SSL *const ssl = hs->ssl; + CBB contents, groups_bytes; + if (!CBB_add_u16(out, TLSEXT_TYPE_supported_groups) || + !CBB_add_u16_length_prefixed(out, &contents) || + !CBB_add_u16_length_prefixed(&contents, &groups_bytes)) { + return 0; + } + + /* Add a fake group. See draft-davidben-tls-grease-01. */ + if (ssl->ctx->grease_enabled && + !CBB_add_u16(&groups_bytes, + ssl_get_grease_value(ssl, ssl_grease_group))) { + return 0; + } + + const uint16_t *groups; + size_t groups_len; + tls1_get_grouplist(ssl, &groups, &groups_len); + + for (size_t i = 0; i < groups_len; i++) { + if (!CBB_add_u16(&groups_bytes, groups[i])) { + return 0; + } + } + + return CBB_flush(out); +} + +static int ext_supported_groups_parse_serverhello(SSL_HANDSHAKE *hs, + uint8_t *out_alert, + CBS *contents) { + /* This extension is not expected to be echoed by servers in TLS 1.2, but some + * BigIP servers send it nonetheless, so do not enforce this. */ + return 1; +} + +static int ext_supported_groups_parse_clienthello(SSL_HANDSHAKE *hs, + uint8_t *out_alert, + CBS *contents) { + if (contents == NULL) { + return 1; + } + + CBS supported_group_list; + if (!CBS_get_u16_length_prefixed(contents, &supported_group_list) || + CBS_len(&supported_group_list) == 0 || + (CBS_len(&supported_group_list) & 1) != 0 || + CBS_len(contents) != 0) { + return 0; + } + + hs->peer_supported_group_list = + OPENSSL_malloc(CBS_len(&supported_group_list)); + if (hs->peer_supported_group_list == NULL) { + *out_alert = SSL_AD_INTERNAL_ERROR; + return 0; + } + + const size_t num_groups = CBS_len(&supported_group_list) / 2; + for (size_t i = 0; i < num_groups; i++) { + if (!CBS_get_u16(&supported_group_list, + &hs->peer_supported_group_list[i])) { + goto err; + } + } + + assert(CBS_len(&supported_group_list) == 0); + hs->peer_supported_group_list_len = num_groups; + + return 1; + +err: + OPENSSL_free(hs->peer_supported_group_list); + hs->peer_supported_group_list = NULL; + *out_alert = SSL_AD_INTERNAL_ERROR; + return 0; +} + +static int ext_supported_groups_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) { + /* Servers don't echo this extension. */ + return 1; +} + + +/* kExtensions contains all the supported extensions. */ +static const struct tls_extension kExtensions[] = { + { + TLSEXT_TYPE_renegotiate, + NULL, + ext_ri_add_clienthello, + ext_ri_parse_serverhello, + ext_ri_parse_clienthello, + ext_ri_add_serverhello, + }, + { + TLSEXT_TYPE_server_name, + NULL, + ext_sni_add_clienthello, + ext_sni_parse_serverhello, + ext_sni_parse_clienthello, + ext_sni_add_serverhello, + }, + { + TLSEXT_TYPE_extended_master_secret, + NULL, + ext_ems_add_clienthello, + ext_ems_parse_serverhello, + ext_ems_parse_clienthello, + ext_ems_add_serverhello, + }, + { + TLSEXT_TYPE_session_ticket, + NULL, + ext_ticket_add_clienthello, + ext_ticket_parse_serverhello, + /* Ticket extension client parsing is handled in ssl_session.c */ + ignore_parse_clienthello, + ext_ticket_add_serverhello, + }, + { + TLSEXT_TYPE_signature_algorithms, + NULL, + ext_sigalgs_add_clienthello, + forbid_parse_serverhello, + ext_sigalgs_parse_clienthello, + dont_add_serverhello, + }, + { + TLSEXT_TYPE_status_request, + NULL, + ext_ocsp_add_clienthello, + ext_ocsp_parse_serverhello, + ext_ocsp_parse_clienthello, + ext_ocsp_add_serverhello, + }, + { + TLSEXT_TYPE_next_proto_neg, + NULL, + ext_npn_add_clienthello, + ext_npn_parse_serverhello, + ext_npn_parse_clienthello, + ext_npn_add_serverhello, + }, + { + TLSEXT_TYPE_certificate_timestamp, + NULL, + ext_sct_add_clienthello, + ext_sct_parse_serverhello, + ext_sct_parse_clienthello, + ext_sct_add_serverhello, + }, + { + TLSEXT_TYPE_application_layer_protocol_negotiation, + NULL, + ext_alpn_add_clienthello, + ext_alpn_parse_serverhello, + /* ALPN is negotiated late in |ssl_negotiate_alpn|. */ + ignore_parse_clienthello, + ext_alpn_add_serverhello, + }, + { + TLSEXT_TYPE_channel_id, + ext_channel_id_init, + ext_channel_id_add_clienthello, + ext_channel_id_parse_serverhello, + ext_channel_id_parse_clienthello, + ext_channel_id_add_serverhello, + }, + { + TLSEXT_TYPE_srtp, + ext_srtp_init, + ext_srtp_add_clienthello, + ext_srtp_parse_serverhello, + ext_srtp_parse_clienthello, + ext_srtp_add_serverhello, + }, + { + TLSEXT_TYPE_ec_point_formats, + NULL, + ext_ec_point_add_clienthello, + ext_ec_point_parse_serverhello, + ext_ec_point_parse_clienthello, + ext_ec_point_add_serverhello, + }, + { + TLSEXT_TYPE_key_share, + NULL, + ext_key_share_add_clienthello, + forbid_parse_serverhello, + ignore_parse_clienthello, + dont_add_serverhello, + }, + { + TLSEXT_TYPE_psk_key_exchange_modes, + NULL, + ext_psk_key_exchange_modes_add_clienthello, + forbid_parse_serverhello, + ext_psk_key_exchange_modes_parse_clienthello, + dont_add_serverhello, + }, + { + TLSEXT_TYPE_early_data, + NULL, + ext_early_data_add_clienthello, + forbid_parse_serverhello, + ext_early_data_parse_clienthello, + dont_add_serverhello, + }, + { + TLSEXT_TYPE_supported_versions, + NULL, + ext_supported_versions_add_clienthello, + forbid_parse_serverhello, + ignore_parse_clienthello, + dont_add_serverhello, + }, + { + TLSEXT_TYPE_cookie, + NULL, + ext_cookie_add_clienthello, + forbid_parse_serverhello, + ignore_parse_clienthello, + dont_add_serverhello, + }, + { + TLSEXT_TYPE_short_header, + NULL, + ext_short_header_add_clienthello, + forbid_parse_serverhello, + ext_short_header_parse_clienthello, + dont_add_serverhello, + }, + /* The final extension must be non-empty. WebSphere Application Server 7.0 is + * intolerant to the last extension being zero-length. See + * https://crbug.com/363583. */ + { + TLSEXT_TYPE_supported_groups, + NULL, + ext_supported_groups_add_clienthello, + ext_supported_groups_parse_serverhello, + ext_supported_groups_parse_clienthello, + ext_supported_groups_add_serverhello, + }, +}; + +#define kNumExtensions (sizeof(kExtensions) / sizeof(struct tls_extension)) + +OPENSSL_COMPILE_ASSERT(kNumExtensions <= + sizeof(((SSL_HANDSHAKE *)NULL)->extensions.sent) * 8, + too_many_extensions_for_sent_bitset); +OPENSSL_COMPILE_ASSERT( + kNumExtensions <= sizeof(((SSL_HANDSHAKE *)NULL)->extensions.received) * 8, + too_many_extensions_for_received_bitset); + +static const struct tls_extension *tls_extension_find(uint32_t *out_index, + uint16_t value) { + unsigned i; + for (i = 0; i < kNumExtensions; i++) { + if (kExtensions[i].value == value) { + *out_index = i; + return &kExtensions[i]; + } + } + + return NULL; +} + +int SSL_extension_supported(unsigned extension_value) { + uint32_t index; + return extension_value == TLSEXT_TYPE_padding || + tls_extension_find(&index, extension_value) != NULL; +} + +int ssl_add_clienthello_tlsext(SSL_HANDSHAKE *hs, CBB *out, size_t header_len) { + SSL *const ssl = hs->ssl; + /* Don't add extensions for SSLv3 unless doing secure renegotiation. */ + if (hs->client_version == SSL3_VERSION && + !ssl->s3->send_connection_binding) { + return 1; + } + + CBB extensions; + if (!CBB_add_u16_length_prefixed(out, &extensions)) { + goto err; + } + + hs->extensions.sent = 0; + hs->custom_extensions.sent = 0; + + for (size_t i = 0; i < kNumExtensions; i++) { + if (kExtensions[i].init != NULL) { + kExtensions[i].init(hs); + } + } + + uint16_t grease_ext1 = 0; + if (ssl->ctx->grease_enabled) { + /* Add a fake empty extension. See draft-davidben-tls-grease-01. */ + grease_ext1 = ssl_get_grease_value(ssl, ssl_grease_extension1); + if (!CBB_add_u16(&extensions, grease_ext1) || + !CBB_add_u16(&extensions, 0 /* zero length */)) { + goto err; + } + } + + for (size_t i = 0; i < kNumExtensions; i++) { + const size_t len_before = CBB_len(&extensions); + if (!kExtensions[i].add_clienthello(hs, &extensions)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_ADDING_EXTENSION); + ERR_add_error_dataf("extension %u", (unsigned)kExtensions[i].value); + goto err; + } + + if (CBB_len(&extensions) != len_before) { + hs->extensions.sent |= (1u << i); + } + } + + if (!custom_ext_add_clienthello(hs, &extensions)) { + goto err; + } + + if (ssl->ctx->grease_enabled) { + /* Add a fake non-empty extension. See draft-davidben-tls-grease-01. */ + uint16_t grease_ext2 = ssl_get_grease_value(ssl, ssl_grease_extension2); + + /* The two fake extensions must not have the same value. GREASE values are + * of the form 0x1a1a, 0x2a2a, 0x3a3a, etc., so XOR to generate a different + * one. */ + if (grease_ext1 == grease_ext2) { + grease_ext2 ^= 0x1010; + } + + if (!CBB_add_u16(&extensions, grease_ext2) || + !CBB_add_u16(&extensions, 1 /* one byte length */) || + !CBB_add_u8(&extensions, 0 /* single zero byte as contents */)) { + goto err; + } + } + + if (!SSL_is_dtls(ssl)) { + size_t psk_extension_len = ext_pre_shared_key_clienthello_length(hs); + header_len += 2 + CBB_len(&extensions) + psk_extension_len; + if (header_len > 0xff && header_len < 0x200) { /* Add padding to workaround bugs in F5 terminators. See RFC 7685. * * NB: because this code works out the length of all existing extensions * it MUST always appear last. */ size_t padding_len = 0x200 - header_len; - /* Extensions take at least four bytes to encode. Always include least + /* Extensions take at least four bytes to encode. Always include at least * one byte of data if including the extension. WebSphere Application - * Server 7.0 is intolerant to the last extension being zero-length. */ + * Server 7.0 is intolerant to the last extension being zero-length. See + * https://crbug.com/363583. */ if (padding_len >= 4 + 1) { padding_len -= 4; } else { @@ -2140,10 +2815,15 @@ int ssl_add_clienthello_tlsext(SSL *ssl, CBB *out, size_t header_len) { goto err; } - memset(padding_bytes, 0, padding_len); + OPENSSL_memset(padding_bytes, 0, padding_len); } } + /* The PSK extension must be last, including after the padding. */ + if (!ext_pre_shared_key_add_clienthello(hs, &extensions)) { + goto err; + } + /* Discard empty extensions blocks. */ if (CBB_len(&extensions) == 0) { CBB_discard_child(out); @@ -2156,32 +2836,33 @@ int ssl_add_clienthello_tlsext(SSL *ssl, CBB *out, size_t header_len) { return 0; } -int ssl_add_serverhello_tlsext(SSL *ssl, CBB *out) { +int ssl_add_serverhello_tlsext(SSL_HANDSHAKE *hs, CBB *out) { + SSL *const ssl = hs->ssl; CBB extensions; if (!CBB_add_u16_length_prefixed(out, &extensions)) { goto err; } - unsigned i; - for (i = 0; i < kNumExtensions; i++) { - if (!(ssl->s3->tmp.extensions.received & (1u << i))) { + for (unsigned i = 0; i < kNumExtensions; i++) { + if (!(hs->extensions.received & (1u << i))) { /* Don't send extensions that were not received. */ continue; } - if (!kExtensions[i].add_serverhello(ssl, &extensions)) { + if (!kExtensions[i].add_serverhello(hs, &extensions)) { OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_ADDING_EXTENSION); - ERR_add_error_dataf("extension: %u", (unsigned)kExtensions[i].value); + ERR_add_error_dataf("extension %u", (unsigned)kExtensions[i].value); goto err; } } - if (!custom_ext_add_serverhello(ssl, &extensions)) { + if (!custom_ext_add_serverhello(hs, &extensions)) { goto err; } - /* Discard empty extensions blocks. */ - if (CBB_len(&extensions) == 0) { + /* Discard empty extensions blocks before TLS 1.3. */ + if (ssl3_protocol_version(ssl) < TLS1_3_VERSION && + CBB_len(&extensions) == 0) { CBB_discard_child(out); } @@ -2192,96 +2873,102 @@ int ssl_add_serverhello_tlsext(SSL *ssl, CBB *out) { return 0; } -static int ssl_scan_clienthello_tlsext(SSL *ssl, CBS *cbs, int *out_alert) { - size_t i; - for (i = 0; i < kNumExtensions; i++) { +static int ssl_scan_clienthello_tlsext(SSL_HANDSHAKE *hs, + const SSL_CLIENT_HELLO *client_hello, + int *out_alert) { + SSL *const ssl = hs->ssl; + for (size_t i = 0; i < kNumExtensions; i++) { if (kExtensions[i].init != NULL) { - kExtensions[i].init(ssl); + kExtensions[i].init(hs); } } - ssl->s3->tmp.extensions.received = 0; - ssl->s3->tmp.custom_extensions.received = 0; - /* The renegotiation extension must always be at index zero because the - * |received| and |sent| bitsets need to be tweaked when the "extension" is - * sent as an SCSV. */ - assert(kExtensions[0].value == TLSEXT_TYPE_renegotiate); + hs->extensions.received = 0; + hs->custom_extensions.received = 0; + + CBS extensions; + CBS_init(&extensions, client_hello->extensions, client_hello->extensions_len); + while (CBS_len(&extensions) != 0) { + uint16_t type; + CBS extension; - /* There may be no extensions. */ - if (CBS_len(cbs) != 0) { - /* Decode the extensions block and check it is valid. */ - CBS extensions; - if (!CBS_get_u16_length_prefixed(cbs, &extensions) || - !tls1_check_duplicate_extensions(&extensions)) { + /* Decode the next extension. */ + if (!CBS_get_u16(&extensions, &type) || + !CBS_get_u16_length_prefixed(&extensions, &extension)) { *out_alert = SSL_AD_DECODE_ERROR; return 0; } - while (CBS_len(&extensions) != 0) { - uint16_t type; - CBS extension; - - /* Decode the next extension. */ - if (!CBS_get_u16(&extensions, &type) || - !CBS_get_u16_length_prefixed(&extensions, &extension)) { - *out_alert = SSL_AD_DECODE_ERROR; - return 0; - } - - /* RFC 5746 made the existence of extensions in SSL 3.0 somewhat - * ambiguous. Ignore all but the renegotiation_info extension. */ - if (ssl->version == SSL3_VERSION && type != TLSEXT_TYPE_renegotiate) { - continue; - } - - unsigned ext_index; - const struct tls_extension *const ext = - tls_extension_find(&ext_index, type); + /* RFC 5746 made the existence of extensions in SSL 3.0 somewhat + * ambiguous. Ignore all but the renegotiation_info extension. */ + if (ssl->version == SSL3_VERSION && type != TLSEXT_TYPE_renegotiate) { + continue; + } - if (ext == NULL) { - if (!custom_ext_parse_clienthello(ssl, out_alert, type, &extension)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_PARSING_EXTENSION); - return 0; - } - continue; - } + unsigned ext_index; + const struct tls_extension *const ext = + tls_extension_find(&ext_index, type); - ssl->s3->tmp.extensions.received |= (1u << ext_index); - uint8_t alert = SSL_AD_DECODE_ERROR; - if (!ext->parse_clienthello(ssl, &alert, &extension)) { - *out_alert = alert; + if (ext == NULL) { + if (!custom_ext_parse_clienthello(hs, out_alert, type, &extension)) { OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_PARSING_EXTENSION); - ERR_add_error_dataf("extension: %u", (unsigned)type); return 0; } + continue; + } + + hs->extensions.received |= (1u << ext_index); + uint8_t alert = SSL_AD_DECODE_ERROR; + if (!ext->parse_clienthello(hs, &alert, &extension)) { + *out_alert = alert; + OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_PARSING_EXTENSION); + ERR_add_error_dataf("extension %u", (unsigned)type); + return 0; } } - for (i = 0; i < kNumExtensions; i++) { - if (!(ssl->s3->tmp.extensions.received & (1u << i))) { - /* Extension wasn't observed so call the callback with a NULL - * parameter. */ - uint8_t alert = SSL_AD_DECODE_ERROR; - if (!kExtensions[i].parse_clienthello(ssl, &alert, NULL)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_MISSING_EXTENSION); - ERR_add_error_dataf("extension: %u", (unsigned)kExtensions[i].value); - *out_alert = alert; - return 0; - } + for (size_t i = 0; i < kNumExtensions; i++) { + if (hs->extensions.received & (1u << i)) { + continue; + } + + CBS *contents = NULL, fake_contents; + static const uint8_t kFakeRenegotiateExtension[] = {0}; + if (kExtensions[i].value == TLSEXT_TYPE_renegotiate && + ssl_client_cipher_list_contains_cipher(client_hello, + SSL3_CK_SCSV & 0xffff)) { + /* The renegotiation SCSV was received so pretend that we received a + * renegotiation extension. */ + CBS_init(&fake_contents, kFakeRenegotiateExtension, + sizeof(kFakeRenegotiateExtension)); + contents = &fake_contents; + hs->extensions.received |= (1u << i); + } + + /* Extension wasn't observed so call the callback with a NULL + * parameter. */ + uint8_t alert = SSL_AD_DECODE_ERROR; + if (!kExtensions[i].parse_clienthello(hs, &alert, contents)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_MISSING_EXTENSION); + ERR_add_error_dataf("extension %u", (unsigned)kExtensions[i].value); + *out_alert = alert; + return 0; } } return 1; } -int ssl_parse_clienthello_tlsext(SSL *ssl, CBS *cbs) { - int alert = -1; - if (ssl_scan_clienthello_tlsext(ssl, cbs, &alert) <= 0) { +int ssl_parse_clienthello_tlsext(SSL_HANDSHAKE *hs, + const SSL_CLIENT_HELLO *client_hello) { + SSL *const ssl = hs->ssl; + int alert = SSL_AD_DECODE_ERROR; + if (ssl_scan_clienthello_tlsext(hs, client_hello, &alert) <= 0) { ssl3_send_alert(ssl, SSL3_AL_FATAL, alert); return 0; } - if (ssl_check_clienthello_tlsext(ssl) <= 0) { + if (ssl_check_clienthello_tlsext(hs) <= 0) { OPENSSL_PUT_ERROR(SSL, SSL_R_CLIENTHELLO_TLSEXT); return 0; } @@ -2289,72 +2976,77 @@ int ssl_parse_clienthello_tlsext(SSL *ssl, CBS *cbs) { return 1; } -OPENSSL_COMPILE_ASSERT(kNumExtensions <= sizeof(uint32_t) * 8, too_many_bits); +static int ssl_scan_serverhello_tlsext(SSL_HANDSHAKE *hs, CBS *cbs, + int *out_alert) { + SSL *const ssl = hs->ssl; + /* Before TLS 1.3, ServerHello extensions blocks may be omitted if empty. */ + if (CBS_len(cbs) == 0 && ssl3_protocol_version(ssl) < TLS1_3_VERSION) { + return 1; + } + + /* Decode the extensions block and check it is valid. */ + CBS extensions; + if (!CBS_get_u16_length_prefixed(cbs, &extensions) || + !tls1_check_duplicate_extensions(&extensions)) { + *out_alert = SSL_AD_DECODE_ERROR; + return 0; + } -static int ssl_scan_serverhello_tlsext(SSL *ssl, CBS *cbs, int *out_alert) { uint32_t received = 0; + while (CBS_len(&extensions) != 0) { + uint16_t type; + CBS extension; - if (CBS_len(cbs) != 0) { - /* Decode the extensions block and check it is valid. */ - CBS extensions; - if (!CBS_get_u16_length_prefixed(cbs, &extensions) || - !tls1_check_duplicate_extensions(&extensions)) { + /* Decode the next extension. */ + if (!CBS_get_u16(&extensions, &type) || + !CBS_get_u16_length_prefixed(&extensions, &extension)) { *out_alert = SSL_AD_DECODE_ERROR; return 0; } + unsigned ext_index; + const struct tls_extension *const ext = + tls_extension_find(&ext_index, type); - while (CBS_len(&extensions) != 0) { - uint16_t type; - CBS extension; - - /* Decode the next extension. */ - if (!CBS_get_u16(&extensions, &type) || - !CBS_get_u16_length_prefixed(&extensions, &extension)) { - *out_alert = SSL_AD_DECODE_ERROR; + if (ext == NULL) { + if (!custom_ext_parse_serverhello(hs, out_alert, type, &extension)) { return 0; } + continue; + } - unsigned ext_index; - const struct tls_extension *const ext = - tls_extension_find(&ext_index, type); - - if (ext == NULL) { - if (!custom_ext_parse_serverhello(ssl, out_alert, type, &extension)) { - return 0; - } - continue; - } + OPENSSL_COMPILE_ASSERT(kNumExtensions <= sizeof(hs->extensions.sent) * 8, + too_many_bits); - if (!(ssl->s3->tmp.extensions.sent & (1u << ext_index))) { - /* If the extension was never sent then it is illegal. */ - OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION); - ERR_add_error_dataf("extension :%u", (unsigned)type); - *out_alert = SSL_AD_DECODE_ERROR; - return 0; - } + if (!(hs->extensions.sent & (1u << ext_index)) && + type != TLSEXT_TYPE_renegotiate) { + /* If the extension was never sent then it is illegal, except for the + * renegotiation extension which, in SSL 3.0, is signaled via SCSV. */ + OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION); + ERR_add_error_dataf("extension :%u", (unsigned)type); + *out_alert = SSL_AD_UNSUPPORTED_EXTENSION; + return 0; + } - received |= (1u << ext_index); + received |= (1u << ext_index); - uint8_t alert = SSL_AD_DECODE_ERROR; - if (!ext->parse_serverhello(ssl, &alert, &extension)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_PARSING_EXTENSION); - ERR_add_error_dataf("extension: %u", (unsigned)type); - *out_alert = alert; - return 0; - } + uint8_t alert = SSL_AD_DECODE_ERROR; + if (!ext->parse_serverhello(hs, &alert, &extension)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_PARSING_EXTENSION); + ERR_add_error_dataf("extension %u", (unsigned)type); + *out_alert = alert; + return 0; } } - size_t i; - for (i = 0; i < kNumExtensions; i++) { + for (size_t i = 0; i < kNumExtensions; i++) { if (!(received & (1u << i))) { /* Extension wasn't observed so call the callback with a NULL * parameter. */ uint8_t alert = SSL_AD_DECODE_ERROR; - if (!kExtensions[i].parse_serverhello(ssl, &alert, NULL)) { + if (!kExtensions[i].parse_serverhello(hs, &alert, NULL)) { OPENSSL_PUT_ERROR(SSL, SSL_R_MISSING_EXTENSION); - ERR_add_error_dataf("extension: %u", (unsigned)kExtensions[i].value); + ERR_add_error_dataf("extension %u", (unsigned)kExtensions[i].value); *out_alert = alert; return 0; } @@ -2364,18 +3056,15 @@ static int ssl_scan_serverhello_tlsext(SSL *ssl, CBS *cbs, int *out_alert) { return 1; } -static int ssl_check_clienthello_tlsext(SSL *ssl) { +static int ssl_check_clienthello_tlsext(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; int ret = SSL_TLSEXT_ERR_NOACK; int al = SSL_AD_UNRECOGNIZED_NAME; - /* The handling of the ECPointFormats extension is done elsewhere, namely in - * ssl3_choose_cipher in s3_lib.c. */ - - if (ssl->ctx != NULL && ssl->ctx->tlsext_servername_callback != 0) { + if (ssl->ctx->tlsext_servername_callback != 0) { ret = ssl->ctx->tlsext_servername_callback(ssl, &al, - ssl->ctx->tlsext_servername_arg); - } else if (ssl->initial_ctx != NULL && - ssl->initial_ctx->tlsext_servername_callback != 0) { + ssl->ctx->tlsext_servername_arg); + } else if (ssl->initial_ctx->tlsext_servername_callback != 0) { ret = ssl->initial_ctx->tlsext_servername_callback( ssl, &al, ssl->initial_ctx->tlsext_servername_arg); } @@ -2385,39 +3074,8 @@ static int ssl_check_clienthello_tlsext(SSL *ssl) { ssl3_send_alert(ssl, SSL3_AL_FATAL, al); return -1; - case SSL_TLSEXT_ERR_ALERT_WARNING: - ssl3_send_alert(ssl, SSL3_AL_WARNING, al); - return 1; - case SSL_TLSEXT_ERR_NOACK: - ssl->s3->tmp.should_ack_sni = 0; - return 1; - - default: - return 1; - } -} - -static int ssl_check_serverhello_tlsext(SSL *ssl) { - int ret = SSL_TLSEXT_ERR_OK; - int al = SSL_AD_UNRECOGNIZED_NAME; - - if (ssl->ctx != NULL && ssl->ctx->tlsext_servername_callback != 0) { - ret = ssl->ctx->tlsext_servername_callback(ssl, &al, - ssl->ctx->tlsext_servername_arg); - } else if (ssl->initial_ctx != NULL && - ssl->initial_ctx->tlsext_servername_callback != 0) { - ret = ssl->initial_ctx->tlsext_servername_callback( - ssl, &al, ssl->initial_ctx->tlsext_servername_arg); - } - - switch (ret) { - case SSL_TLSEXT_ERR_ALERT_FATAL: - ssl3_send_alert(ssl, SSL3_AL_FATAL, al); - return -1; - - case SSL_TLSEXT_ERR_ALERT_WARNING: - ssl3_send_alert(ssl, SSL3_AL_WARNING, al); + hs->should_ack_sni = 0; return 1; default: @@ -2425,18 +3083,14 @@ static int ssl_check_serverhello_tlsext(SSL *ssl) { } } -int ssl_parse_serverhello_tlsext(SSL *ssl, CBS *cbs) { - int alert = -1; - if (ssl_scan_serverhello_tlsext(ssl, cbs, &alert) <= 0) { +int ssl_parse_serverhello_tlsext(SSL_HANDSHAKE *hs, CBS *cbs) { + SSL *const ssl = hs->ssl; + int alert = SSL_AD_DECODE_ERROR; + if (ssl_scan_serverhello_tlsext(hs, cbs, &alert) <= 0) { ssl3_send_alert(ssl, SSL3_AL_FATAL, alert); return 0; } - if (ssl_check_serverhello_tlsext(ssl) <= 0) { - OPENSSL_PUT_ERROR(SSL, SSL_R_SERVERHELLO_TLSEXT); - return 0; - } - return 1; } @@ -2456,6 +3110,10 @@ int tls_process_ticket(SSL *ssl, SSL_SESSION **out_session, *out_renew_ticket = 0; *out_session = NULL; + if (SSL_get_options(ssl) & SSL_OP_NO_TICKET) { + goto done; + } + if (session_id_len > SSL_MAX_SSL_SESSION_ID_LENGTH) { goto done; } @@ -2485,8 +3143,8 @@ int tls_process_ticket(SSL *ssl, SSL_SESSION **out_session, } } else { /* Check the key name matches. */ - if (memcmp(ticket, ssl_ctx->tlsext_tick_key_name, - SSL_TICKET_KEY_NAME_LEN) != 0) { + if (OPENSSL_memcmp(ticket, ssl_ctx->tlsext_tick_key_name, + SSL_TICKET_KEY_NAME_LEN) != 0) { goto done; } if (!HMAC_Init_ex(&hmac_ctx, ssl_ctx->tlsext_tick_hmac_key, @@ -2509,7 +3167,12 @@ int tls_process_ticket(SSL *ssl, SSL_SESSION **out_session, } HMAC_Update(&hmac_ctx, ticket, ticket_len - mac_len); HMAC_Final(&hmac_ctx, mac, NULL); - if (CRYPTO_memcmp(mac, ticket + (ticket_len - mac_len), mac_len) != 0) { + int mac_ok = + CRYPTO_memcmp(mac, ticket + (ticket_len - mac_len), mac_len) == 0; +#if defined(BORINGSSL_UNSAFE_FUZZER_MODE) + mac_ok = 1; +#endif + if (!mac_ok) { goto done; } @@ -2522,6 +3185,11 @@ int tls_process_ticket(SSL *ssl, SSL_SESSION **out_session, ret = 0; goto done; } + size_t plaintext_len; +#if defined(BORINGSSL_UNSAFE_FUZZER_MODE) + OPENSSL_memcpy(plaintext, ciphertext, ciphertext_len); + plaintext_len = ciphertext_len; +#else if (ciphertext_len >= INT_MAX) { goto done; } @@ -2532,9 +3200,12 @@ int tls_process_ticket(SSL *ssl, SSL_SESSION **out_session, ERR_clear_error(); /* Don't leave an error on the queue. */ goto done; } + plaintext_len = (size_t)(len1 + len2); +#endif /* Decode the session. */ - SSL_SESSION *session = SSL_SESSION_from_bytes(plaintext, len1 + len2); + SSL_SESSION *session = + SSL_SESSION_from_bytes(plaintext, plaintext_len, ssl->ctx); if (session == NULL) { ERR_clear_error(); /* Don't leave an error on the queue. */ goto done; @@ -2542,7 +3213,7 @@ int tls_process_ticket(SSL *ssl, SSL_SESSION **out_session, /* Copy the client's session ID into the new session, to denote the ticket has * been accepted. */ - memcpy(session->session_id, session_id, session_id_len); + OPENSSL_memcpy(session->session_id, session_id, session_id_len); session->session_id_length = session_id_len; *out_session = session; @@ -2554,99 +3225,17 @@ int tls_process_ticket(SSL *ssl, SSL_SESSION **out_session, return ret; } -/* Tables to translate from NIDs to TLS v1.2 ids */ -typedef struct { - int nid; - int id; -} tls12_lookup; - -static const tls12_lookup tls12_md[] = { - {NID_sha1, TLSEXT_hash_sha1}, - {NID_sha256, TLSEXT_hash_sha256}, - {NID_sha384, TLSEXT_hash_sha384}, - {NID_sha512, TLSEXT_hash_sha512}, -}; - -static const tls12_lookup tls12_sig[] = {{EVP_PKEY_RSA, TLSEXT_signature_rsa}, - {EVP_PKEY_EC, TLSEXT_signature_ecdsa}}; - -static int tls12_find_id(int nid, const tls12_lookup *table, size_t tlen) { - size_t i; - for (i = 0; i < tlen; i++) { - if (table[i].nid == nid) { - return table[i].id; - } - } - - return -1; -} - -int tls12_get_sigid(int pkey_type) { - return tls12_find_id(pkey_type, tls12_sig, - sizeof(tls12_sig) / sizeof(tls12_lookup)); -} - -int tls12_add_sigandhash(SSL *ssl, CBB *out, const EVP_MD *md) { - int md_id = tls12_find_id(EVP_MD_type(md), tls12_md, - sizeof(tls12_md) / sizeof(tls12_lookup)); - int sig_id = tls12_get_sigid(ssl_private_key_type(ssl)); - - return md_id != -1 && - sig_id != -1 && - CBB_add_u8(out, (uint8_t)md_id) && - CBB_add_u8(out, (uint8_t)sig_id); -} - -const EVP_MD *tls12_get_hash(uint8_t hash_alg) { - switch (hash_alg) { - case TLSEXT_hash_sha1: - return EVP_sha1(); - - case TLSEXT_hash_sha256: - return EVP_sha256(); - - case TLSEXT_hash_sha384: - return EVP_sha384(); - - case TLSEXT_hash_sha512: - return EVP_sha512(); - - default: - return NULL; - } -} - -/* tls12_get_pkey_type returns the EVP_PKEY type corresponding to TLS signature - * algorithm |sig_alg|. It returns -1 if the type is unknown. */ -static int tls12_get_pkey_type(uint8_t sig_alg) { - switch (sig_alg) { - case TLSEXT_signature_rsa: - return EVP_PKEY_RSA; - - case TLSEXT_signature_ecdsa: - return EVP_PKEY_EC; - - default: - return -1; - } -} - -OPENSSL_COMPILE_ASSERT(sizeof(TLS_SIGALGS) == 2, - sizeof_tls_sigalgs_is_not_two); - -int tls1_parse_peer_sigalgs(SSL *ssl, const CBS *in_sigalgs) { +int tls1_parse_peer_sigalgs(SSL_HANDSHAKE *hs, const CBS *in_sigalgs) { /* Extension ignored for inappropriate versions */ - if (ssl3_protocol_version(ssl) < TLS1_2_VERSION) { + if (ssl3_protocol_version(hs->ssl) < TLS1_2_VERSION) { return 1; } - CERT *const cert = ssl->cert; - OPENSSL_free(cert->peer_sigalgs); - cert->peer_sigalgs = NULL; - cert->peer_sigalgslen = 0; + OPENSSL_free(hs->peer_sigalgs); + hs->peer_sigalgs = NULL; + hs->num_peer_sigalgs = 0; size_t num_sigalgs = CBS_len(in_sigalgs); - if (num_sigalgs % 2 != 0) { return 0; } @@ -2658,22 +3247,18 @@ int tls1_parse_peer_sigalgs(SSL *ssl, const CBS *in_sigalgs) { return 1; } - /* This multiplication doesn't overflow because sizeof(TLS_SIGALGS) is two - * (statically asserted above) and we just divided |num_sigalgs| by two. */ - cert->peer_sigalgs = OPENSSL_malloc(num_sigalgs * sizeof(TLS_SIGALGS)); - if (cert->peer_sigalgs == NULL) { + /* This multiplication doesn't overflow because sizeof(uint16_t) is two + * and we just divided |num_sigalgs| by two. */ + hs->peer_sigalgs = OPENSSL_malloc(num_sigalgs * sizeof(uint16_t)); + if (hs->peer_sigalgs == NULL) { return 0; } - cert->peer_sigalgslen = num_sigalgs; + hs->num_peer_sigalgs = num_sigalgs; CBS sigalgs; CBS_init(&sigalgs, CBS_data(in_sigalgs), CBS_len(in_sigalgs)); - - size_t i; - for (i = 0; i < num_sigalgs; i++) { - TLS_SIGALGS *const sigalg = &cert->peer_sigalgs[i]; - if (!CBS_get_u8(&sigalgs, &sigalg->rhash) || - !CBS_get_u8(&sigalgs, &sigalg->rsign)) { + for (size_t i = 0; i < num_sigalgs; i++) { + if (!CBS_get_u16(&sigalgs, &hs->peer_sigalgs[i])) { return 0; } } @@ -2681,101 +3266,314 @@ int tls1_parse_peer_sigalgs(SSL *ssl, const CBS *in_sigalgs) { return 1; } -const EVP_MD *tls1_choose_signing_digest(SSL *ssl) { +int tls1_choose_signature_algorithm(SSL_HANDSHAKE *hs, uint16_t *out) { + SSL *const ssl = hs->ssl; CERT *cert = ssl->cert; - int type = ssl_private_key_type(ssl); - size_t i, j; - - static const int kDefaultDigestList[] = {NID_sha256, NID_sha384, NID_sha512, - NID_sha1}; - - const int *digest_nids = kDefaultDigestList; - size_t num_digest_nids = - sizeof(kDefaultDigestList) / sizeof(kDefaultDigestList[0]); - if (cert->digest_nids != NULL) { - digest_nids = cert->digest_nids; - num_digest_nids = cert->num_digest_nids; - } - - for (i = 0; i < num_digest_nids; i++) { - const int digest_nid = digest_nids[i]; - for (j = 0; j < cert->peer_sigalgslen; j++) { - const EVP_MD *md = tls12_get_hash(cert->peer_sigalgs[j].rhash); - if (md == NULL || - digest_nid != EVP_MD_type(md) || - tls12_get_pkey_type(cert->peer_sigalgs[j].rsign) != type) { - continue; - } - return md; + /* Before TLS 1.2, the signature algorithm isn't negotiated as part of the + * handshake. It is fixed at MD5-SHA1 for RSA and SHA1 for ECDSA. */ + if (ssl3_protocol_version(ssl) < TLS1_2_VERSION) { + int type = ssl_private_key_type(ssl); + if (type == NID_rsaEncryption) { + *out = SSL_SIGN_RSA_PKCS1_MD5_SHA1; + return 1; + } + if (ssl_is_ecdsa_key_type(type)) { + *out = SSL_SIGN_ECDSA_SHA1; + return 1; + } + OPENSSL_PUT_ERROR(SSL, SSL_R_NO_COMMON_SIGNATURE_ALGORITHMS); + return 0; + } + + const uint16_t *sigalgs = cert->sigalgs; + size_t num_sigalgs = cert->num_sigalgs; + if (sigalgs == NULL) { + sigalgs = kSignSignatureAlgorithms; + num_sigalgs = OPENSSL_ARRAY_SIZE(kSignSignatureAlgorithms); + } + + const uint16_t *peer_sigalgs = hs->peer_sigalgs; + size_t num_peer_sigalgs = hs->num_peer_sigalgs; + if (num_peer_sigalgs == 0 && ssl3_protocol_version(ssl) < TLS1_3_VERSION) { + /* If the client didn't specify any signature_algorithms extension then + * we can assume that it supports SHA1. See + * http://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */ + static const uint16_t kDefaultPeerAlgorithms[] = {SSL_SIGN_RSA_PKCS1_SHA1, + SSL_SIGN_ECDSA_SHA1}; + peer_sigalgs = kDefaultPeerAlgorithms; + num_peer_sigalgs = OPENSSL_ARRAY_SIZE(kDefaultPeerAlgorithms); + } + + for (size_t i = 0; i < num_sigalgs; i++) { + uint16_t sigalg = sigalgs[i]; + /* SSL_SIGN_RSA_PKCS1_MD5_SHA1 is an internal value and should never be + * negotiated. */ + if (sigalg == SSL_SIGN_RSA_PKCS1_MD5_SHA1 || + !ssl_private_key_supports_signature_algorithm(ssl, sigalgs[i])) { + continue; + } + + for (size_t j = 0; j < num_peer_sigalgs; j++) { + if (sigalg == peer_sigalgs[j]) { + *out = sigalg; + return 1; + } } } - /* If no suitable digest may be found, default to SHA-1. */ - return EVP_sha1(); + OPENSSL_PUT_ERROR(SSL, SSL_R_NO_COMMON_SIGNATURE_ALGORITHMS); + return 0; } -int tls1_channel_id_hash(SSL *ssl, uint8_t *out, size_t *out_len) { +int tls1_verify_channel_id(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; int ret = 0; - EVP_MD_CTX ctx; + uint16_t extension_type; + CBS extension, channel_id; + + /* A Channel ID handshake message is structured to contain multiple + * extensions, but the only one that can be present is Channel ID. */ + CBS_init(&channel_id, ssl->init_msg, ssl->init_num); + if (!CBS_get_u16(&channel_id, &extension_type) || + !CBS_get_u16_length_prefixed(&channel_id, &extension) || + CBS_len(&channel_id) != 0 || + extension_type != TLSEXT_TYPE_channel_id || + CBS_len(&extension) != TLSEXT_CHANNEL_ID_SIZE) { + OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); + return 0; + } + + EC_GROUP *p256 = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1); + if (!p256) { + OPENSSL_PUT_ERROR(SSL, SSL_R_NO_P256_SUPPORT); + return 0; + } - EVP_MD_CTX_init(&ctx); - if (!EVP_DigestInit_ex(&ctx, EVP_sha256(), NULL)) { + EC_KEY *key = NULL; + EC_POINT *point = NULL; + BIGNUM x, y; + ECDSA_SIG sig; + BN_init(&x); + BN_init(&y); + sig.r = BN_new(); + sig.s = BN_new(); + if (sig.r == NULL || sig.s == NULL) { goto err; } - static const char kClientIDMagic[] = "TLS Channel ID signature"; - EVP_DigestUpdate(&ctx, kClientIDMagic, sizeof(kClientIDMagic)); + const uint8_t *p = CBS_data(&extension); + if (BN_bin2bn(p + 0, 32, &x) == NULL || + BN_bin2bn(p + 32, 32, &y) == NULL || + BN_bin2bn(p + 64, 32, sig.r) == NULL || + BN_bin2bn(p + 96, 32, sig.s) == NULL) { + goto err; + } - if (ssl->hit) { - static const char kResumptionMagic[] = "Resumption"; - EVP_DigestUpdate(&ctx, kResumptionMagic, sizeof(kResumptionMagic)); - if (ssl->session->original_handshake_hash_len == 0) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - goto err; - } - EVP_DigestUpdate(&ctx, ssl->session->original_handshake_hash, - ssl->session->original_handshake_hash_len); + point = EC_POINT_new(p256); + if (point == NULL || + !EC_POINT_set_affine_coordinates_GFp(p256, point, &x, &y, NULL)) { + goto err; + } + + key = EC_KEY_new(); + if (key == NULL || + !EC_KEY_set_group(key, p256) || + !EC_KEY_set_public_key(key, point)) { + goto err; + } + + uint8_t digest[EVP_MAX_MD_SIZE]; + size_t digest_len; + if (!tls1_channel_id_hash(hs, digest, &digest_len)) { + goto err; } - uint8_t handshake_hash[EVP_MAX_MD_SIZE]; - int handshake_hash_len = tls1_handshake_digest(ssl, handshake_hash, - sizeof(handshake_hash)); - if (handshake_hash_len < 0) { + int sig_ok = ECDSA_do_verify(digest, digest_len, &sig, key); +#if defined(BORINGSSL_UNSAFE_FUZZER_MODE) + sig_ok = 1; +#endif + if (!sig_ok) { + OPENSSL_PUT_ERROR(SSL, SSL_R_CHANNEL_ID_SIGNATURE_INVALID); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECRYPT_ERROR); + ssl->s3->tlsext_channel_id_valid = 0; + goto err; + } + + OPENSSL_memcpy(ssl->s3->tlsext_channel_id, p, 64); + ret = 1; + +err: + BN_free(&x); + BN_free(&y); + BN_free(sig.r); + BN_free(sig.s); + EC_KEY_free(key); + EC_POINT_free(point); + EC_GROUP_free(p256); + return ret; +} + +int tls1_write_channel_id(SSL_HANDSHAKE *hs, CBB *cbb) { + SSL *const ssl = hs->ssl; + uint8_t digest[EVP_MAX_MD_SIZE]; + size_t digest_len; + if (!tls1_channel_id_hash(hs, digest, &digest_len)) { + return 0; + } + + EC_KEY *ec_key = EVP_PKEY_get0_EC_KEY(ssl->tlsext_channel_id_private); + if (ec_key == NULL) { + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + return 0; + } + + int ret = 0; + BIGNUM *x = BN_new(); + BIGNUM *y = BN_new(); + ECDSA_SIG *sig = NULL; + if (x == NULL || y == NULL || + !EC_POINT_get_affine_coordinates_GFp(EC_KEY_get0_group(ec_key), + EC_KEY_get0_public_key(ec_key), + x, y, NULL)) { + goto err; + } + + sig = ECDSA_do_sign(digest, digest_len, ec_key); + if (sig == NULL) { + goto err; + } + + CBB child; + if (!CBB_add_u16(cbb, TLSEXT_TYPE_channel_id) || + !CBB_add_u16_length_prefixed(cbb, &child) || + !BN_bn2cbb_padded(&child, 32, x) || + !BN_bn2cbb_padded(&child, 32, y) || + !BN_bn2cbb_padded(&child, 32, sig->r) || + !BN_bn2cbb_padded(&child, 32, sig->s) || + !CBB_flush(cbb)) { goto err; } - EVP_DigestUpdate(&ctx, handshake_hash, (size_t)handshake_hash_len); - unsigned len_u; - EVP_DigestFinal_ex(&ctx, out, &len_u); - *out_len = len_u; ret = 1; err: - EVP_MD_CTX_cleanup(&ctx); + BN_free(x); + BN_free(y); + ECDSA_SIG_free(sig); return ret; } +int tls1_channel_id_hash(SSL_HANDSHAKE *hs, uint8_t *out, size_t *out_len) { + SSL *const ssl = hs->ssl; + if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) { + uint8_t *msg; + size_t msg_len; + if (!tls13_get_cert_verify_signature_input(hs, &msg, &msg_len, + ssl_cert_verify_channel_id)) { + return 0; + } + SHA256(msg, msg_len, out); + *out_len = SHA256_DIGEST_LENGTH; + OPENSSL_free(msg); + return 1; + } + + SHA256_CTX ctx; + + SHA256_Init(&ctx); + static const char kClientIDMagic[] = "TLS Channel ID signature"; + SHA256_Update(&ctx, kClientIDMagic, sizeof(kClientIDMagic)); + + if (ssl->session != NULL) { + static const char kResumptionMagic[] = "Resumption"; + SHA256_Update(&ctx, kResumptionMagic, sizeof(kResumptionMagic)); + if (ssl->session->original_handshake_hash_len == 0) { + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + return 0; + } + SHA256_Update(&ctx, ssl->session->original_handshake_hash, + ssl->session->original_handshake_hash_len); + } + + uint8_t hs_hash[EVP_MAX_MD_SIZE]; + size_t hs_hash_len; + if (!SSL_TRANSCRIPT_get_hash(&hs->transcript, hs_hash, &hs_hash_len)) { + return 0; + } + SHA256_Update(&ctx, hs_hash, (size_t)hs_hash_len); + SHA256_Final(out, &ctx); + *out_len = SHA256_DIGEST_LENGTH; + return 1; +} + /* tls1_record_handshake_hashes_for_channel_id records the current handshake - * hashes in |ssl->session| so that Channel ID resumptions can sign that + * hashes in |hs->new_session| so that Channel ID resumptions can sign that * data. */ -int tls1_record_handshake_hashes_for_channel_id(SSL *ssl) { - int digest_len; +int tls1_record_handshake_hashes_for_channel_id(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; /* This function should never be called for a resumed session because the * handshake hashes that we wish to record are for the original, full * handshake. */ - if (ssl->hit) { + if (ssl->session != NULL) { return -1; } - digest_len = - tls1_handshake_digest(ssl, ssl->session->original_handshake_hash, - sizeof(ssl->session->original_handshake_hash)); - if (digest_len < 0) { + OPENSSL_COMPILE_ASSERT( + sizeof(hs->new_session->original_handshake_hash) == EVP_MAX_MD_SIZE, + original_handshake_hash_is_too_small); + + size_t digest_len; + if (!SSL_TRANSCRIPT_get_hash(&hs->transcript, + hs->new_session->original_handshake_hash, + &digest_len)) { return -1; } - ssl->session->original_handshake_hash_len = digest_len; + OPENSSL_COMPILE_ASSERT(EVP_MAX_MD_SIZE <= 0xff, max_md_size_is_too_large); + hs->new_session->original_handshake_hash_len = (uint8_t)digest_len; + + return 1; +} + +int ssl_do_channel_id_callback(SSL *ssl) { + if (ssl->tlsext_channel_id_private != NULL || + ssl->ctx->channel_id_cb == NULL) { + return 1; + } + + EVP_PKEY *key = NULL; + ssl->ctx->channel_id_cb(ssl, &key); + if (key == NULL) { + /* The caller should try again later. */ + return 1; + } + + int ret = SSL_set1_tls_channel_id(ssl, key); + EVP_PKEY_free(key); + return ret; +} + +int ssl_is_sct_list_valid(const CBS *contents) { + /* Shallow parse the SCT list for sanity. By the RFC + * (https://tools.ietf.org/html/rfc6962#section-3.3) neither the list nor any + * of the SCTs may be empty. */ + CBS copy = *contents; + CBS sct_list; + if (!CBS_get_u16_length_prefixed(©, &sct_list) || + CBS_len(©) != 0 || + CBS_len(&sct_list) == 0) { + return 0; + } + + while (CBS_len(&sct_list) > 0) { + CBS sct; + if (!CBS_get_u16_length_prefixed(&sct_list, &sct) || + CBS_len(&sct) == 0) { + return 0; + } + } return 1; } diff --git a/Sources/BoringSSL/ssl/tls13_both.c b/Sources/BoringSSL/ssl/tls13_both.c new file mode 100644 index 000000000..91cae9ad3 --- /dev/null +++ b/Sources/BoringSSL/ssl/tls13_both.c @@ -0,0 +1,634 @@ +/* Copyright (c) 2016, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "../crypto/internal.h" +#include "internal.h" + + +/* kMaxKeyUpdates is the number of consecutive KeyUpdates that will be + * processed. Without this limit an attacker could force unbounded processing + * without being able to return application data. */ +static const uint8_t kMaxKeyUpdates = 32; + +int tls13_handshake(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + for (;;) { + /* Resolve the operation the handshake was waiting on. */ + switch (hs->wait) { + case ssl_hs_error: + OPENSSL_PUT_ERROR(SSL, SSL_R_SSL_HANDSHAKE_FAILURE); + return -1; + + case ssl_hs_flush: + case ssl_hs_flush_and_read_message: { + int ret = ssl->method->flush_flight(ssl); + if (ret <= 0) { + return ret; + } + if (hs->wait != ssl_hs_flush_and_read_message) { + break; + } + ssl->method->expect_flight(ssl); + hs->wait = ssl_hs_read_message; + /* Fall-through. */ + } + + case ssl_hs_read_message: { + int ret = ssl->method->ssl_get_message(ssl); + if (ret <= 0) { + return ret; + } + break; + } + + case ssl_hs_x509_lookup: + ssl->rwstate = SSL_X509_LOOKUP; + hs->wait = ssl_hs_ok; + return -1; + + case ssl_hs_channel_id_lookup: + ssl->rwstate = SSL_CHANNEL_ID_LOOKUP; + hs->wait = ssl_hs_ok; + return -1; + + case ssl_hs_private_key_operation: + ssl->rwstate = SSL_PRIVATE_KEY_OPERATION; + hs->wait = ssl_hs_ok; + return -1; + + case ssl_hs_ok: + break; + } + + /* Run the state machine again. */ + hs->wait = hs->do_tls13_handshake(hs); + if (hs->wait == ssl_hs_error) { + /* Don't loop around to avoid a stray |SSL_R_SSL_HANDSHAKE_FAILURE| the + * first time around. */ + return -1; + } + if (hs->wait == ssl_hs_ok) { + /* The handshake has completed. */ + return 1; + } + + /* Otherwise, loop to the beginning and resolve what was blocking the + * handshake. */ + } +} + +int tls13_get_cert_verify_signature_input( + SSL_HANDSHAKE *hs, uint8_t **out, size_t *out_len, + enum ssl_cert_verify_context_t cert_verify_context) { + CBB cbb; + if (!CBB_init(&cbb, 64 + 33 + 1 + 2 * EVP_MAX_MD_SIZE)) { + goto err; + } + + for (size_t i = 0; i < 64; i++) { + if (!CBB_add_u8(&cbb, 0x20)) { + goto err; + } + } + + const uint8_t *context; + size_t context_len; + if (cert_verify_context == ssl_cert_verify_server) { + /* Include the NUL byte. */ + static const char kContext[] = "TLS 1.3, server CertificateVerify"; + context = (const uint8_t *)kContext; + context_len = sizeof(kContext); + } else if (cert_verify_context == ssl_cert_verify_client) { + static const char kContext[] = "TLS 1.3, client CertificateVerify"; + context = (const uint8_t *)kContext; + context_len = sizeof(kContext); + } else if (cert_verify_context == ssl_cert_verify_channel_id) { + static const char kContext[] = "TLS 1.3, Channel ID"; + context = (const uint8_t *)kContext; + context_len = sizeof(kContext); + } else { + goto err; + } + + if (!CBB_add_bytes(&cbb, context, context_len)) { + goto err; + } + + uint8_t context_hash[EVP_MAX_MD_SIZE]; + size_t context_hash_len; + if (!SSL_TRANSCRIPT_get_hash(&hs->transcript, context_hash, + &context_hash_len) || + !CBB_add_bytes(&cbb, context_hash, context_hash_len) || + !CBB_finish(&cbb, out, out_len)) { + goto err; + } + + return 1; + +err: + OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + CBB_cleanup(&cbb); + return 0; +} + +int tls13_process_certificate(SSL_HANDSHAKE *hs, int allow_anonymous) { + SSL *const ssl = hs->ssl; + CBS cbs, context, certificate_list; + CBS_init(&cbs, ssl->init_msg, ssl->init_num); + if (!CBS_get_u8_length_prefixed(&cbs, &context) || + CBS_len(&context) != 0) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); + OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + return 0; + } + + const int retain_sha256 = + ssl->server && ssl->retain_only_sha256_of_client_certs; + int ret = 0; + + EVP_PKEY *pkey = NULL; + STACK_OF(CRYPTO_BUFFER) *certs = sk_CRYPTO_BUFFER_new_null(); + if (certs == NULL) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); + OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + goto err; + } + + if (!CBS_get_u24_length_prefixed(&cbs, &certificate_list)) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); + OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + goto err; + } + + while (CBS_len(&certificate_list) > 0) { + CBS certificate, extensions; + if (!CBS_get_u24_length_prefixed(&certificate_list, &certificate) || + !CBS_get_u16_length_prefixed(&certificate_list, &extensions) || + CBS_len(&certificate) == 0) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); + OPENSSL_PUT_ERROR(SSL, SSL_R_CERT_LENGTH_MISMATCH); + goto err; + } + + if (sk_CRYPTO_BUFFER_num(certs) == 0) { + pkey = ssl_cert_parse_pubkey(&certificate); + if (pkey == NULL) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); + OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + goto err; + } + /* TLS 1.3 always uses certificate keys for signing thus the correct + * keyUsage is enforced. */ + if (!ssl_cert_check_digital_signature_key_usage(&certificate)) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER); + goto err; + } + + if (retain_sha256) { + /* Retain the hash of the leaf certificate if requested. */ + SHA256(CBS_data(&certificate), CBS_len(&certificate), + hs->new_session->peer_sha256); + } + } + + CRYPTO_BUFFER *buf = + CRYPTO_BUFFER_new_from_CBS(&certificate, ssl->ctx->pool); + if (buf == NULL || + !sk_CRYPTO_BUFFER_push(certs, buf)) { + CRYPTO_BUFFER_free(buf); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); + OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + goto err; + } + + /* Parse out the extensions. */ + int have_status_request = 0, have_sct = 0; + CBS status_request, sct; + const SSL_EXTENSION_TYPE ext_types[] = { + {TLSEXT_TYPE_status_request, &have_status_request, &status_request}, + {TLSEXT_TYPE_certificate_timestamp, &have_sct, &sct}, + }; + + uint8_t alert = SSL_AD_DECODE_ERROR; + if (!ssl_parse_extensions(&extensions, &alert, ext_types, + OPENSSL_ARRAY_SIZE(ext_types), + 0 /* reject unknown */)) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, alert); + goto err; + } + + /* All Certificate extensions are parsed, but only the leaf extensions are + * stored. */ + if (have_status_request) { + if (ssl->server || !ssl->ocsp_stapling_enabled) { + OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNSUPPORTED_EXTENSION); + goto err; + } + + uint8_t status_type; + CBS ocsp_response; + if (!CBS_get_u8(&status_request, &status_type) || + status_type != TLSEXT_STATUSTYPE_ocsp || + !CBS_get_u24_length_prefixed(&status_request, &ocsp_response) || + CBS_len(&ocsp_response) == 0 || + CBS_len(&status_request) != 0) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); + goto err; + } + + if (sk_CRYPTO_BUFFER_num(certs) == 1 && + !CBS_stow(&ocsp_response, &hs->new_session->ocsp_response, + &hs->new_session->ocsp_response_length)) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); + goto err; + } + } + + if (have_sct) { + if (ssl->server || !ssl->signed_cert_timestamps_enabled) { + OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNSUPPORTED_EXTENSION); + goto err; + } + + if (!ssl_is_sct_list_valid(&sct)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_PARSING_EXTENSION); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); + goto err; + } + + if (sk_CRYPTO_BUFFER_num(certs) == 1 && + !CBS_stow( + &sct, &hs->new_session->tlsext_signed_cert_timestamp_list, + &hs->new_session->tlsext_signed_cert_timestamp_list_length)) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); + goto err; + } + } + } + + if (CBS_len(&cbs) != 0) { + OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); + goto err; + } + + EVP_PKEY_free(hs->peer_pubkey); + hs->peer_pubkey = pkey; + pkey = NULL; + + sk_CRYPTO_BUFFER_pop_free(hs->new_session->certs, CRYPTO_BUFFER_free); + hs->new_session->certs = certs; + certs = NULL; + + if (!ssl->ctx->x509_method->session_cache_objects(hs->new_session)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); + goto err; + } + + if (sk_CRYPTO_BUFFER_num(hs->new_session->certs) == 0) { + if (!allow_anonymous) { + OPENSSL_PUT_ERROR(SSL, SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_CERTIFICATE_REQUIRED); + goto err; + } + + /* OpenSSL returns X509_V_OK when no certificates are requested. This is + * classed by them as a bug, but it's assumed by at least NGINX. */ + hs->new_session->verify_result = X509_V_OK; + + /* No certificate, so nothing more to do. */ + ret = 1; + goto err; + } + + hs->new_session->peer_sha256_valid = retain_sha256; + + if (!ssl_verify_cert_chain(ssl, &hs->new_session->verify_result, + hs->new_session->x509_chain)) { + goto err; + } + + ret = 1; + +err: + sk_CRYPTO_BUFFER_pop_free(certs, CRYPTO_BUFFER_free); + EVP_PKEY_free(pkey); + return ret; +} + +int tls13_process_certificate_verify(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + int ret = 0; + uint8_t *msg = NULL; + size_t msg_len; + + if (hs->peer_pubkey == NULL) { + goto err; + } + + CBS cbs, signature; + uint16_t signature_algorithm; + CBS_init(&cbs, ssl->init_msg, ssl->init_num); + if (!CBS_get_u16(&cbs, &signature_algorithm) || + !CBS_get_u16_length_prefixed(&cbs, &signature) || + CBS_len(&cbs) != 0) { + OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); + goto err; + } + + int al; + if (!tls12_check_peer_sigalg(ssl, &al, signature_algorithm)) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, al); + goto err; + } + hs->new_session->peer_signature_algorithm = signature_algorithm; + + if (!tls13_get_cert_verify_signature_input( + hs, &msg, &msg_len, + ssl->server ? ssl_cert_verify_client : ssl_cert_verify_server)) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); + goto err; + } + + int sig_ok = + ssl_public_key_verify(ssl, CBS_data(&signature), CBS_len(&signature), + signature_algorithm, hs->peer_pubkey, msg, msg_len); +#if defined(BORINGSSL_UNSAFE_FUZZER_MODE) + sig_ok = 1; + ERR_clear_error(); +#endif + if (!sig_ok) { + OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SIGNATURE); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECRYPT_ERROR); + goto err; + } + + ret = 1; + +err: + OPENSSL_free(msg); + return ret; +} + +int tls13_process_finished(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + uint8_t verify_data[EVP_MAX_MD_SIZE]; + size_t verify_data_len; + if (!tls13_finished_mac(hs, verify_data, &verify_data_len, !ssl->server)) { + return 0; + } + + int finished_ok = + ssl->init_num == verify_data_len && + CRYPTO_memcmp(verify_data, ssl->init_msg, verify_data_len) == 0; +#if defined(BORINGSSL_UNSAFE_FUZZER_MODE) + finished_ok = 1; +#endif + if (!finished_ok) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECRYPT_ERROR); + OPENSSL_PUT_ERROR(SSL, SSL_R_DIGEST_CHECK_FAILED); + return 0; + } + + return 1; +} + +int tls13_add_certificate(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + CBB cbb, body, certificate_list; + if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_CERTIFICATE) || + /* The request context is always empty in the handshake. */ + !CBB_add_u8(&body, 0) || + !CBB_add_u24_length_prefixed(&body, &certificate_list)) { + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + goto err; + } + + if (!ssl_has_certificate(ssl)) { + if (!ssl_add_message_cbb(ssl, &cbb)) { + goto err; + } + + return 1; + } + + CERT *cert = ssl->cert; + CRYPTO_BUFFER *leaf_buf = sk_CRYPTO_BUFFER_value(cert->chain, 0); + CBB leaf, extensions; + if (!CBB_add_u24_length_prefixed(&certificate_list, &leaf) || + !CBB_add_bytes(&leaf, CRYPTO_BUFFER_data(leaf_buf), + CRYPTO_BUFFER_len(leaf_buf)) || + !CBB_add_u16_length_prefixed(&certificate_list, &extensions)) { + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + goto err; + } + + if (hs->scts_requested && ssl->cert->signed_cert_timestamp_list != NULL) { + CBB contents; + if (!CBB_add_u16(&extensions, TLSEXT_TYPE_certificate_timestamp) || + !CBB_add_u16_length_prefixed(&extensions, &contents) || + !CBB_add_bytes( + &contents, + CRYPTO_BUFFER_data(ssl->cert->signed_cert_timestamp_list), + CRYPTO_BUFFER_len(ssl->cert->signed_cert_timestamp_list)) || + !CBB_flush(&extensions)) { + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + goto err; + } + } + + if (hs->ocsp_stapling_requested && + ssl->cert->ocsp_response != NULL) { + CBB contents, ocsp_response; + if (!CBB_add_u16(&extensions, TLSEXT_TYPE_status_request) || + !CBB_add_u16_length_prefixed(&extensions, &contents) || + !CBB_add_u8(&contents, TLSEXT_STATUSTYPE_ocsp) || + !CBB_add_u24_length_prefixed(&contents, &ocsp_response) || + !CBB_add_bytes(&ocsp_response, + CRYPTO_BUFFER_data(ssl->cert->ocsp_response), + CRYPTO_BUFFER_len(ssl->cert->ocsp_response)) || + !CBB_flush(&extensions)) { + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + goto err; + } + } + + for (size_t i = 1; i < sk_CRYPTO_BUFFER_num(cert->chain); i++) { + CRYPTO_BUFFER *cert_buf = sk_CRYPTO_BUFFER_value(cert->chain, i); + CBB child; + if (!CBB_add_u24_length_prefixed(&certificate_list, &child) || + !CBB_add_bytes(&child, CRYPTO_BUFFER_data(cert_buf), + CRYPTO_BUFFER_len(cert_buf)) || + !CBB_add_u16(&certificate_list, 0 /* no extensions */)) { + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + goto err; + } + } + + if (!ssl_add_message_cbb(ssl, &cbb)) { + goto err; + } + + return 1; + +err: + CBB_cleanup(&cbb); + return 0; +} + +enum ssl_private_key_result_t tls13_add_certificate_verify(SSL_HANDSHAKE *hs, + int is_first_run) { + SSL *const ssl = hs->ssl; + enum ssl_private_key_result_t ret = ssl_private_key_failure; + uint8_t *msg = NULL; + size_t msg_len; + CBB cbb, body; + CBB_zero(&cbb); + + uint16_t signature_algorithm; + if (!tls1_choose_signature_algorithm(hs, &signature_algorithm)) { + goto err; + } + if (!ssl->method->init_message(ssl, &cbb, &body, + SSL3_MT_CERTIFICATE_VERIFY) || + !CBB_add_u16(&body, signature_algorithm)) { + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + goto err; + } + + /* Sign the digest. */ + CBB child; + const size_t max_sig_len = ssl_private_key_max_signature_len(ssl); + uint8_t *sig; + size_t sig_len; + if (!CBB_add_u16_length_prefixed(&body, &child) || + !CBB_reserve(&child, &sig, max_sig_len)) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); + goto err; + } + + enum ssl_private_key_result_t sign_result; + if (is_first_run) { + if (!tls13_get_cert_verify_signature_input( + hs, &msg, &msg_len, + ssl->server ? ssl_cert_verify_server : ssl_cert_verify_client)) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); + goto err; + } + sign_result = ssl_private_key_sign(ssl, sig, &sig_len, max_sig_len, + signature_algorithm, msg, msg_len); + } else { + sign_result = ssl_private_key_complete(ssl, sig, &sig_len, max_sig_len); + } + + if (sign_result != ssl_private_key_success) { + ret = sign_result; + goto err; + } + + if (!CBB_did_write(&child, sig_len) || + !ssl_add_message_cbb(ssl, &cbb)) { + goto err; + } + + ret = ssl_private_key_success; + +err: + CBB_cleanup(&cbb); + OPENSSL_free(msg); + return ret; +} + +int tls13_add_finished(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + size_t verify_data_len; + uint8_t verify_data[EVP_MAX_MD_SIZE]; + + if (!tls13_finished_mac(hs, verify_data, &verify_data_len, ssl->server)) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); + OPENSSL_PUT_ERROR(SSL, SSL_R_DIGEST_CHECK_FAILED); + return 0; + } + + CBB cbb, body; + if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_FINISHED) || + !CBB_add_bytes(&body, verify_data, verify_data_len) || + !ssl_add_message_cbb(ssl, &cbb)) { + CBB_cleanup(&cbb); + return 0; + } + + return 1; +} + +static int tls13_receive_key_update(SSL *ssl) { + CBS cbs; + uint8_t key_update_request; + CBS_init(&cbs, ssl->init_msg, ssl->init_num); + if (!CBS_get_u8(&cbs, &key_update_request) || + CBS_len(&cbs) != 0 || + (key_update_request != SSL_KEY_UPDATE_NOT_REQUESTED && + key_update_request != SSL_KEY_UPDATE_REQUESTED)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); + return 0; + } + + /* TODO(svaldez): Send KeyUpdate if |key_update_request| is + * |SSL_KEY_UPDATE_REQUESTED|. */ + return tls13_rotate_traffic_key(ssl, evp_aead_open); +} + +int tls13_post_handshake(SSL *ssl) { + if (ssl->s3->tmp.message_type == SSL3_MT_KEY_UPDATE) { + ssl->s3->key_update_count++; + if (ssl->s3->key_update_count > kMaxKeyUpdates) { + OPENSSL_PUT_ERROR(SSL, SSL_R_TOO_MANY_KEY_UPDATES); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE); + return 0; + } + + return tls13_receive_key_update(ssl); + } + + ssl->s3->key_update_count = 0; + + if (ssl->s3->tmp.message_type == SSL3_MT_NEW_SESSION_TICKET && + !ssl->server) { + return tls13_process_new_session_ticket(ssl); + } + + // TODO(svaldez): Handle post-handshake authentication. + + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE); + OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_MESSAGE); + return 0; +} diff --git a/Sources/BoringSSL/ssl/tls13_client.c b/Sources/BoringSSL/ssl/tls13_client.c new file mode 100644 index 000000000..8e994e581 --- /dev/null +++ b/Sources/BoringSSL/ssl/tls13_client.c @@ -0,0 +1,712 @@ +/* Copyright (c) 2016, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "../crypto/internal.h" +#include "internal.h" + + +enum client_hs_state_t { + state_process_hello_retry_request = 0, + state_send_second_client_hello, + state_process_server_hello, + state_process_encrypted_extensions, + state_process_certificate_request, + state_process_server_certificate, + state_process_server_certificate_verify, + state_process_server_finished, + state_send_client_certificate, + state_send_client_certificate_verify, + state_complete_client_certificate_verify, + state_complete_second_flight, + state_done, +}; + +static const uint8_t kZeroes[EVP_MAX_MD_SIZE] = {0}; + +static enum ssl_hs_wait_t do_process_hello_retry_request(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + if (ssl->s3->tmp.message_type != SSL3_MT_HELLO_RETRY_REQUEST) { + hs->tls13_state = state_process_server_hello; + return ssl_hs_ok; + } + + CBS cbs, extensions; + uint16_t server_wire_version; + CBS_init(&cbs, ssl->init_msg, ssl->init_num); + if (!CBS_get_u16(&cbs, &server_wire_version) || + !CBS_get_u16_length_prefixed(&cbs, &extensions) || + /* HelloRetryRequest may not be empty. */ + CBS_len(&extensions) == 0 || + CBS_len(&cbs) != 0) { + OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); + return ssl_hs_error; + } + + int have_cookie, have_key_share; + CBS cookie, key_share; + const SSL_EXTENSION_TYPE ext_types[] = { + {TLSEXT_TYPE_key_share, &have_key_share, &key_share}, + {TLSEXT_TYPE_cookie, &have_cookie, &cookie}, + }; + + uint8_t alert = SSL_AD_DECODE_ERROR; + if (!ssl_parse_extensions(&extensions, &alert, ext_types, + OPENSSL_ARRAY_SIZE(ext_types), + 0 /* reject unknown */)) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, alert); + return ssl_hs_error; + } + + if (have_cookie) { + CBS cookie_value; + if (!CBS_get_u16_length_prefixed(&cookie, &cookie_value) || + CBS_len(&cookie_value) == 0 || + CBS_len(&cookie) != 0) { + OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); + return ssl_hs_error; + } + + if (!CBS_stow(&cookie_value, &hs->cookie, &hs->cookie_len)) { + return ssl_hs_error; + } + } + + if (have_key_share) { + uint16_t group_id; + if (!CBS_get_u16(&key_share, &group_id) || CBS_len(&key_share) != 0) { + OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); + return ssl_hs_error; + } + + /* The group must be supported. */ + const uint16_t *groups; + size_t groups_len; + tls1_get_grouplist(ssl, &groups, &groups_len); + int found = 0; + for (size_t i = 0; i < groups_len; i++) { + if (groups[i] == group_id) { + found = 1; + break; + } + } + + if (!found) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER); + OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CURVE); + return ssl_hs_error; + } + + /* Check that the HelloRetryRequest does not request the key share that + * was provided in the initial ClientHello. */ + if (SSL_ECDH_CTX_get_id(&hs->ecdh_ctx) == group_id) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER); + OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CURVE); + return ssl_hs_error; + } + + SSL_ECDH_CTX_cleanup(&hs->ecdh_ctx); + hs->retry_group = group_id; + } + + if (!ssl_hash_current_message(hs)) { + return ssl_hs_error; + } + + hs->received_hello_retry_request = 1; + hs->tls13_state = state_send_second_client_hello; + return ssl_hs_ok; +} + +static enum ssl_hs_wait_t do_send_second_client_hello(SSL_HANDSHAKE *hs) { + if (!ssl_write_client_hello(hs)) { + return ssl_hs_error; + } + + hs->tls13_state = state_process_server_hello; + return ssl_hs_flush_and_read_message; +} + +static enum ssl_hs_wait_t do_process_server_hello(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + if (!ssl_check_message_type(ssl, SSL3_MT_SERVER_HELLO)) { + return ssl_hs_error; + } + + CBS cbs, server_random, extensions; + uint16_t server_wire_version; + uint16_t cipher_suite; + CBS_init(&cbs, ssl->init_msg, ssl->init_num); + if (!CBS_get_u16(&cbs, &server_wire_version) || + !CBS_get_bytes(&cbs, &server_random, SSL3_RANDOM_SIZE) || + !CBS_get_u16(&cbs, &cipher_suite) || + !CBS_get_u16_length_prefixed(&cbs, &extensions) || + CBS_len(&cbs) != 0) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); + OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + return ssl_hs_error; + } + + if (server_wire_version != ssl->version) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); + OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_VERSION_NUMBER); + return ssl_hs_error; + } + + assert(ssl->s3->have_version); + OPENSSL_memcpy(ssl->s3->server_random, CBS_data(&server_random), + SSL3_RANDOM_SIZE); + + const SSL_CIPHER *cipher = SSL_get_cipher_by_value(cipher_suite); + if (cipher == NULL) { + OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_CIPHER_RETURNED); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER); + return ssl_hs_error; + } + + /* Check if the cipher is a TLS 1.3 cipher. */ + if (SSL_CIPHER_get_min_version(cipher) > ssl3_protocol_version(ssl) || + SSL_CIPHER_get_max_version(cipher) < ssl3_protocol_version(ssl)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CIPHER_RETURNED); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER); + return ssl_hs_error; + } + + /* Parse out the extensions. */ + int have_key_share = 0, have_pre_shared_key = 0, have_short_header = 0; + CBS key_share, pre_shared_key, short_header; + const SSL_EXTENSION_TYPE ext_types[] = { + {TLSEXT_TYPE_key_share, &have_key_share, &key_share}, + {TLSEXT_TYPE_pre_shared_key, &have_pre_shared_key, &pre_shared_key}, + {TLSEXT_TYPE_short_header, &have_short_header, &short_header}, + }; + + uint8_t alert = SSL_AD_DECODE_ERROR; + if (!ssl_parse_extensions(&extensions, &alert, ext_types, + OPENSSL_ARRAY_SIZE(ext_types), + 0 /* reject unknown */)) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, alert); + return ssl_hs_error; + } + + alert = SSL_AD_DECODE_ERROR; + if (have_pre_shared_key) { + if (ssl->session == NULL) { + OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNSUPPORTED_EXTENSION); + return ssl_hs_error; + } + + if (!ssl_ext_pre_shared_key_parse_serverhello(hs, &alert, + &pre_shared_key)) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, alert); + return ssl_hs_error; + } + + if (ssl->session->ssl_version != ssl->version) { + OPENSSL_PUT_ERROR(SSL, SSL_R_OLD_SESSION_VERSION_NOT_RETURNED); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER); + return ssl_hs_error; + } + + if (ssl->session->cipher->algorithm_prf != cipher->algorithm_prf) { + OPENSSL_PUT_ERROR(SSL, SSL_R_OLD_SESSION_PRF_HASH_MISMATCH); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER); + return ssl_hs_error; + } + + if (!ssl_session_is_context_valid(ssl, ssl->session)) { + /* This is actually a client application bug. */ + OPENSSL_PUT_ERROR(SSL, + SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER); + return ssl_hs_error; + } + + ssl->s3->session_reused = 1; + /* Only authentication information carries over in TLS 1.3. */ + hs->new_session = SSL_SESSION_dup(ssl->session, SSL_SESSION_DUP_AUTH_ONLY); + if (hs->new_session == NULL) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); + return ssl_hs_error; + } + ssl_set_session(ssl, NULL); + + /* Resumption incorporates fresh key material, so refresh the timeout. */ + ssl_session_renew_timeout(ssl, hs->new_session, + ssl->initial_ctx->session_psk_dhe_timeout); + } else if (!ssl_get_new_session(hs, 0)) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); + return ssl_hs_error; + } + + hs->new_session->cipher = cipher; + hs->new_cipher = cipher; + + /* Store the initial negotiated ALPN in the session. */ + if (ssl->s3->alpn_selected != NULL) { + hs->new_session->early_alpn = + BUF_memdup(ssl->s3->alpn_selected, ssl->s3->alpn_selected_len); + if (hs->new_session->early_alpn == NULL) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); + return ssl_hs_error; + } + hs->new_session->early_alpn_len = ssl->s3->alpn_selected_len; + } + + /* The PRF hash is now known. Set up the key schedule. */ + if (!tls13_init_key_schedule(hs)) { + return ssl_hs_error; + } + + /* Incorporate the PSK into the running secret. */ + if (ssl->s3->session_reused) { + if (!tls13_advance_key_schedule(hs, hs->new_session->master_key, + hs->new_session->master_key_length)) { + return ssl_hs_error; + } + } else if (!tls13_advance_key_schedule(hs, kZeroes, hs->hash_len)) { + return ssl_hs_error; + } + + if (!have_key_share) { + /* We do not support psk_ke and thus always require a key share. */ + OPENSSL_PUT_ERROR(SSL, SSL_R_MISSING_KEY_SHARE); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_MISSING_EXTENSION); + return ssl_hs_error; + } + + /* Resolve ECDHE and incorporate it into the secret. */ + uint8_t *dhe_secret; + size_t dhe_secret_len; + alert = SSL_AD_DECODE_ERROR; + if (!ssl_ext_key_share_parse_serverhello(hs, &dhe_secret, &dhe_secret_len, + &alert, &key_share)) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, alert); + return ssl_hs_error; + } + + if (!tls13_advance_key_schedule(hs, dhe_secret, dhe_secret_len)) { + OPENSSL_free(dhe_secret); + return ssl_hs_error; + } + OPENSSL_free(dhe_secret); + + /* Negotiate short record headers. */ + if (have_short_header) { + if (CBS_len(&short_header) != 0) { + OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); + return ssl_hs_error; + } + + if (!ssl->ctx->short_header_enabled) { + OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNSUPPORTED_EXTENSION); + return ssl_hs_error; + } + + ssl->s3->short_header = 1; + } + + if (!ssl_hash_current_message(hs) || + !tls13_derive_handshake_secrets(hs) || + !tls13_set_traffic_key(ssl, evp_aead_open, hs->server_handshake_secret, + hs->hash_len) || + !tls13_set_traffic_key(ssl, evp_aead_seal, hs->client_handshake_secret, + hs->hash_len)) { + return ssl_hs_error; + } + + hs->tls13_state = state_process_encrypted_extensions; + return ssl_hs_read_message; +} + +static enum ssl_hs_wait_t do_process_encrypted_extensions(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + if (!ssl_check_message_type(ssl, SSL3_MT_ENCRYPTED_EXTENSIONS)) { + return ssl_hs_error; + } + + CBS cbs; + CBS_init(&cbs, ssl->init_msg, ssl->init_num); + if (!ssl_parse_serverhello_tlsext(hs, &cbs)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_PARSE_TLSEXT); + return ssl_hs_error; + } + if (CBS_len(&cbs) != 0) { + OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); + return ssl_hs_error; + } + + if (!ssl_hash_current_message(hs)) { + return ssl_hs_error; + } + + hs->tls13_state = state_process_certificate_request; + return ssl_hs_read_message; +} + +static enum ssl_hs_wait_t do_process_certificate_request(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + /* CertificateRequest may only be sent in non-resumption handshakes. */ + if (ssl->s3->session_reused) { + hs->tls13_state = state_process_server_finished; + return ssl_hs_ok; + } + + /* CertificateRequest is optional. */ + if (ssl->s3->tmp.message_type != SSL3_MT_CERTIFICATE_REQUEST) { + hs->tls13_state = state_process_server_certificate; + return ssl_hs_ok; + } + + CBS cbs, context, supported_signature_algorithms; + CBS_init(&cbs, ssl->init_msg, ssl->init_num); + if (!CBS_get_u8_length_prefixed(&cbs, &context) || + /* The request context is always empty during the handshake. */ + CBS_len(&context) != 0 || + !CBS_get_u16_length_prefixed(&cbs, &supported_signature_algorithms) || + CBS_len(&supported_signature_algorithms) == 0 || + !tls1_parse_peer_sigalgs(hs, &supported_signature_algorithms)) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); + OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + return ssl_hs_error; + } + + uint8_t alert = SSL_AD_DECODE_ERROR; + STACK_OF(X509_NAME) *ca_sk = ssl_parse_client_CA_list(ssl, &alert, &cbs); + if (ca_sk == NULL) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, alert); + return ssl_hs_error; + } + + /* Ignore extensions. */ + CBS extensions; + if (!CBS_get_u16_length_prefixed(&cbs, &extensions) || + CBS_len(&cbs) != 0) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); + sk_X509_NAME_pop_free(ca_sk, X509_NAME_free); + OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + return ssl_hs_error; + } + + hs->cert_request = 1; + sk_X509_NAME_pop_free(hs->ca_names, X509_NAME_free); + hs->ca_names = ca_sk; + + if (!ssl_hash_current_message(hs)) { + return ssl_hs_error; + } + + hs->tls13_state = state_process_server_certificate; + return ssl_hs_read_message; +} + +static enum ssl_hs_wait_t do_process_server_certificate(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + if (!ssl_check_message_type(ssl, SSL3_MT_CERTIFICATE) || + !tls13_process_certificate(hs, 0 /* certificate required */) || + !ssl_hash_current_message(hs)) { + return ssl_hs_error; + } + + hs->tls13_state = state_process_server_certificate_verify; + return ssl_hs_read_message; +} + +static enum ssl_hs_wait_t do_process_server_certificate_verify( + SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + if (!ssl_check_message_type(ssl, SSL3_MT_CERTIFICATE_VERIFY) || + !tls13_process_certificate_verify(hs) || + !ssl_hash_current_message(hs)) { + return ssl_hs_error; + } + + hs->tls13_state = state_process_server_finished; + return ssl_hs_read_message; +} + +static enum ssl_hs_wait_t do_process_server_finished(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + if (!ssl_check_message_type(ssl, SSL3_MT_FINISHED) || + !tls13_process_finished(hs) || + !ssl_hash_current_message(hs) || + /* Update the secret to the master secret and derive traffic keys. */ + !tls13_advance_key_schedule(hs, kZeroes, hs->hash_len) || + !tls13_derive_application_secrets(hs)) { + return ssl_hs_error; + } + + ssl->method->received_flight(ssl); + hs->tls13_state = state_send_client_certificate; + return ssl_hs_ok; +} + +static enum ssl_hs_wait_t do_send_client_certificate(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + /* The peer didn't request a certificate. */ + if (!hs->cert_request) { + hs->tls13_state = state_complete_second_flight; + return ssl_hs_ok; + } + + /* Call cert_cb to update the certificate. */ + if (ssl->cert->cert_cb != NULL) { + int rv = ssl->cert->cert_cb(ssl, ssl->cert->cert_cb_arg); + if (rv == 0) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); + OPENSSL_PUT_ERROR(SSL, SSL_R_CERT_CB_ERROR); + return ssl_hs_error; + } + if (rv < 0) { + hs->tls13_state = state_send_client_certificate; + return ssl_hs_x509_lookup; + } + } + + if (!ssl_auto_chain_if_needed(ssl) || + !tls13_add_certificate(hs)) { + return ssl_hs_error; + } + + hs->tls13_state = state_send_client_certificate_verify; + return ssl_hs_ok; +} + +static enum ssl_hs_wait_t do_send_client_certificate_verify(SSL_HANDSHAKE *hs, + int is_first_run) { + SSL *const ssl = hs->ssl; + /* Don't send CertificateVerify if there is no certificate. */ + if (!ssl_has_certificate(ssl)) { + hs->tls13_state = state_complete_second_flight; + return ssl_hs_ok; + } + + switch (tls13_add_certificate_verify(hs, is_first_run)) { + case ssl_private_key_success: + hs->tls13_state = state_complete_second_flight; + return ssl_hs_ok; + + case ssl_private_key_retry: + hs->tls13_state = state_complete_client_certificate_verify; + return ssl_hs_private_key_operation; + + case ssl_private_key_failure: + return ssl_hs_error; + } + + assert(0); + return ssl_hs_error; +} + +static enum ssl_hs_wait_t do_complete_second_flight(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + + /* Send a Channel ID assertion if necessary. */ + if (ssl->s3->tlsext_channel_id_valid) { + if (!ssl_do_channel_id_callback(ssl)) { + hs->tls13_state = state_complete_second_flight; + return ssl_hs_error; + } + + if (ssl->tlsext_channel_id_private == NULL) { + return ssl_hs_channel_id_lookup; + } + + CBB cbb, body; + if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_CHANNEL_ID) || + !tls1_write_channel_id(hs, &body) || + !ssl_add_message_cbb(ssl, &cbb)) { + CBB_cleanup(&cbb); + return ssl_hs_error; + } + } + + /* Send a Finished message. */ + if (!tls13_add_finished(hs)) { + return ssl_hs_error; + } + + /* Derive the final keys and enable them. */ + if (!tls13_set_traffic_key(ssl, evp_aead_open, hs->server_traffic_secret_0, + hs->hash_len) || + !tls13_set_traffic_key(ssl, evp_aead_seal, hs->client_traffic_secret_0, + hs->hash_len) || + !tls13_derive_resumption_secret(hs)) { + return ssl_hs_error; + } + + hs->tls13_state = state_done; + return ssl_hs_flush; +} + +enum ssl_hs_wait_t tls13_client_handshake(SSL_HANDSHAKE *hs) { + while (hs->tls13_state != state_done) { + enum ssl_hs_wait_t ret = ssl_hs_error; + enum client_hs_state_t state = hs->tls13_state; + switch (state) { + case state_process_hello_retry_request: + ret = do_process_hello_retry_request(hs); + break; + case state_send_second_client_hello: + ret = do_send_second_client_hello(hs); + break; + case state_process_server_hello: + ret = do_process_server_hello(hs); + break; + case state_process_encrypted_extensions: + ret = do_process_encrypted_extensions(hs); + break; + case state_process_certificate_request: + ret = do_process_certificate_request(hs); + break; + case state_process_server_certificate: + ret = do_process_server_certificate(hs); + break; + case state_process_server_certificate_verify: + ret = do_process_server_certificate_verify(hs); + break; + case state_process_server_finished: + ret = do_process_server_finished(hs); + break; + case state_send_client_certificate: + ret = do_send_client_certificate(hs); + break; + case state_send_client_certificate_verify: + ret = do_send_client_certificate_verify(hs, 1 /* first run */); + break; + case state_complete_client_certificate_verify: + ret = do_send_client_certificate_verify(hs, 0 /* complete */); + break; + case state_complete_second_flight: + ret = do_complete_second_flight(hs); + break; + case state_done: + ret = ssl_hs_ok; + break; + } + + if (ret != ssl_hs_ok) { + return ret; + } + } + + return ssl_hs_ok; +} + +int tls13_process_new_session_ticket(SSL *ssl) { + int ret = 0; + SSL_SESSION *session = SSL_SESSION_dup(ssl->s3->established_session, + SSL_SESSION_INCLUDE_NONAUTH); + if (session == NULL) { + return 0; + } + + ssl_session_rebase_time(ssl, session); + + uint32_t server_timeout; + CBS cbs, ticket, extensions; + CBS_init(&cbs, ssl->init_msg, ssl->init_num); + if (!CBS_get_u32(&cbs, &server_timeout) || + !CBS_get_u32(&cbs, &session->ticket_age_add) || + !CBS_get_u16_length_prefixed(&cbs, &ticket) || + !CBS_stow(&ticket, &session->tlsext_tick, &session->tlsext_ticklen) || + !CBS_get_u16_length_prefixed(&cbs, &extensions) || + CBS_len(&cbs) != 0) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); + OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + goto err; + } + + /* Cap the renewable lifetime by the server advertised value. This avoids + * wasting bandwidth on 0-RTT when we know the server will reject it. + * + * TODO(davidben): This dance where we're not sure if long or uint32_t is + * bigger is silly. session->timeout should not be a long to begin with. + * https://crbug.com/boringssl/155. */ +#if LONG_MAX < 0xffffffff + if (server_timeout > LONG_MAX) { + server_timeout = LONG_MAX; + } +#endif + if (session->timeout > (long)server_timeout) { + session->timeout = (long)server_timeout; + } + + /* Parse out the extensions. */ + int have_early_data_info = 0; + CBS early_data_info; + const SSL_EXTENSION_TYPE ext_types[] = { + {TLSEXT_TYPE_ticket_early_data_info, &have_early_data_info, + &early_data_info}, + }; + + uint8_t alert = SSL_AD_DECODE_ERROR; + if (!ssl_parse_extensions(&extensions, &alert, ext_types, + OPENSSL_ARRAY_SIZE(ext_types), + 1 /* ignore unknown */)) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, alert); + goto err; + } + + if (have_early_data_info && ssl->ctx->enable_early_data) { + if (!CBS_get_u32(&early_data_info, &session->ticket_max_early_data) || + CBS_len(&early_data_info) != 0) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); + OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + goto err; + } + } + + session->ticket_age_add_valid = 1; + session->not_resumable = 0; + + if (ssl->ctx->new_session_cb != NULL && + ssl->ctx->new_session_cb(ssl, session)) { + /* |new_session_cb|'s return value signals that it took ownership. */ + session = NULL; + } + + ret = 1; + +err: + SSL_SESSION_free(session); + return ret; +} + +void ssl_clear_tls13_state(SSL_HANDSHAKE *hs) { + SSL_ECDH_CTX_cleanup(&hs->ecdh_ctx); + + OPENSSL_free(hs->key_share_bytes); + hs->key_share_bytes = NULL; + hs->key_share_bytes_len = 0; +} diff --git a/Sources/BoringSSL/ssl/tls13_enc.c b/Sources/BoringSSL/ssl/tls13_enc.c new file mode 100644 index 000000000..412705da8 --- /dev/null +++ b/Sources/BoringSSL/ssl/tls13_enc.c @@ -0,0 +1,430 @@ +/* Copyright (c) 2016, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "../crypto/internal.h" +#include "internal.h" + + +int tls13_init_key_schedule(SSL_HANDSHAKE *hs) { + if (!SSL_TRANSCRIPT_init_hash(&hs->transcript, ssl3_protocol_version(hs->ssl), + hs->new_cipher->algorithm_prf)) { + return 0; + } + + + hs->hash_len = SSL_TRANSCRIPT_digest_len(&hs->transcript); + + /* Initialize the secret to the zero key. */ + OPENSSL_memset(hs->secret, 0, hs->hash_len); + + SSL_TRANSCRIPT_free_buffer(&hs->transcript); + return 1; +} + +int tls13_advance_key_schedule(SSL_HANDSHAKE *hs, const uint8_t *in, + size_t len) { + return HKDF_extract(hs->secret, &hs->hash_len, + SSL_TRANSCRIPT_md(&hs->transcript), in, len, hs->secret, + hs->hash_len); +} + +static int hkdf_expand_label(uint8_t *out, const EVP_MD *digest, + const uint8_t *secret, size_t secret_len, + const uint8_t *label, size_t label_len, + const uint8_t *hash, size_t hash_len, size_t len) { + static const char kTLS13LabelVersion[] = "TLS 1.3, "; + + CBB cbb, child; + uint8_t *hkdf_label; + size_t hkdf_label_len; + if (!CBB_init(&cbb, 2 + 1 + strlen(kTLS13LabelVersion) + label_len + 1 + + hash_len) || + !CBB_add_u16(&cbb, len) || + !CBB_add_u8_length_prefixed(&cbb, &child) || + !CBB_add_bytes(&child, (const uint8_t *)kTLS13LabelVersion, + strlen(kTLS13LabelVersion)) || + !CBB_add_bytes(&child, label, label_len) || + !CBB_add_u8_length_prefixed(&cbb, &child) || + !CBB_add_bytes(&child, hash, hash_len) || + !CBB_finish(&cbb, &hkdf_label, &hkdf_label_len)) { + CBB_cleanup(&cbb); + return 0; + } + + int ret = HKDF_expand(out, len, digest, secret, secret_len, hkdf_label, + hkdf_label_len); + OPENSSL_free(hkdf_label); + return ret; +} + +/* derive_secret derives a secret of length |len| and writes the result in |out| + * with the given label and the current base secret and most recently-saved + * handshake context. It returns one on success and zero on error. */ +static int derive_secret(SSL_HANDSHAKE *hs, uint8_t *out, size_t len, + const uint8_t *label, size_t label_len) { + uint8_t context_hash[EVP_MAX_MD_SIZE]; + size_t context_hash_len; + if (!SSL_TRANSCRIPT_get_hash(&hs->transcript, context_hash, + &context_hash_len)) { + return 0; + } + + return hkdf_expand_label(out, SSL_TRANSCRIPT_md(&hs->transcript), hs->secret, + hs->hash_len, label, label_len, context_hash, + context_hash_len, len); +} + +int tls13_set_traffic_key(SSL *ssl, enum evp_aead_direction_t direction, + const uint8_t *traffic_secret, + size_t traffic_secret_len) { + if (traffic_secret_len > 0xff) { + OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW); + return 0; + } + + /* Look up cipher suite properties. */ + const EVP_AEAD *aead; + size_t discard; + if (!ssl_cipher_get_evp_aead(&aead, &discard, &discard, + SSL_get_session(ssl)->cipher, + ssl3_protocol_version(ssl))) { + return 0; + } + + const EVP_MD *digest = ssl_get_handshake_digest( + SSL_get_session(ssl)->cipher->algorithm_prf, ssl3_protocol_version(ssl)); + + /* Derive the key. */ + size_t key_len = EVP_AEAD_key_length(aead); + uint8_t key[EVP_AEAD_MAX_KEY_LENGTH]; + if (!hkdf_expand_label(key, digest, traffic_secret, traffic_secret_len, + (const uint8_t *)"key", 3, NULL, 0, key_len)) { + return 0; + } + + /* Derive the IV. */ + size_t iv_len = EVP_AEAD_nonce_length(aead); + uint8_t iv[EVP_AEAD_MAX_NONCE_LENGTH]; + if (!hkdf_expand_label(iv, digest, traffic_secret, traffic_secret_len, + (const uint8_t *)"iv", 2, NULL, 0, iv_len)) { + return 0; + } + + SSL_AEAD_CTX *traffic_aead = SSL_AEAD_CTX_new( + direction, ssl3_protocol_version(ssl), SSL_get_session(ssl)->cipher, key, + key_len, NULL, 0, iv, iv_len); + if (traffic_aead == NULL) { + return 0; + } + + if (direction == evp_aead_open) { + if (!ssl->method->set_read_state(ssl, traffic_aead)) { + return 0; + } + } else { + if (!ssl->method->set_write_state(ssl, traffic_aead)) { + return 0; + } + } + + /* Save the traffic secret. */ + if (direction == evp_aead_open) { + OPENSSL_memmove(ssl->s3->read_traffic_secret, traffic_secret, + traffic_secret_len); + ssl->s3->read_traffic_secret_len = traffic_secret_len; + } else { + OPENSSL_memmove(ssl->s3->write_traffic_secret, traffic_secret, + traffic_secret_len); + ssl->s3->write_traffic_secret_len = traffic_secret_len; + } + + return 1; +} + +static const char kTLS13LabelClientHandshakeTraffic[] = + "client handshake traffic secret"; +static const char kTLS13LabelServerHandshakeTraffic[] = + "server handshake traffic secret"; +static const char kTLS13LabelClientApplicationTraffic[] = + "client application traffic secret"; +static const char kTLS13LabelServerApplicationTraffic[] = + "server application traffic secret"; + +int tls13_derive_handshake_secrets(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + return derive_secret(hs, hs->client_handshake_secret, hs->hash_len, + (const uint8_t *)kTLS13LabelClientHandshakeTraffic, + strlen(kTLS13LabelClientHandshakeTraffic)) && + ssl_log_secret(ssl, "CLIENT_HANDSHAKE_TRAFFIC_SECRET", + hs->client_handshake_secret, hs->hash_len) && + derive_secret(hs, hs->server_handshake_secret, hs->hash_len, + (const uint8_t *)kTLS13LabelServerHandshakeTraffic, + strlen(kTLS13LabelServerHandshakeTraffic)) && + ssl_log_secret(ssl, "SERVER_HANDSHAKE_TRAFFIC_SECRET", + hs->server_handshake_secret, hs->hash_len); +} + +static const char kTLS13LabelExporter[] = "exporter master secret"; + +int tls13_derive_application_secrets(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + ssl->s3->exporter_secret_len = hs->hash_len; + return derive_secret(hs, hs->client_traffic_secret_0, hs->hash_len, + (const uint8_t *)kTLS13LabelClientApplicationTraffic, + strlen(kTLS13LabelClientApplicationTraffic)) && + ssl_log_secret(ssl, "CLIENT_TRAFFIC_SECRET_0", + hs->client_traffic_secret_0, hs->hash_len) && + derive_secret(hs, hs->server_traffic_secret_0, hs->hash_len, + (const uint8_t *)kTLS13LabelServerApplicationTraffic, + strlen(kTLS13LabelServerApplicationTraffic)) && + ssl_log_secret(ssl, "SERVER_TRAFFIC_SECRET_0", + hs->server_traffic_secret_0, hs->hash_len) && + derive_secret(hs, ssl->s3->exporter_secret, hs->hash_len, + (const uint8_t *)kTLS13LabelExporter, + strlen(kTLS13LabelExporter)); +} + +static const char kTLS13LabelApplicationTraffic[] = + "application traffic secret"; + +int tls13_rotate_traffic_key(SSL *ssl, enum evp_aead_direction_t direction) { + const EVP_MD *digest = ssl_get_handshake_digest( + SSL_get_session(ssl)->cipher->algorithm_prf, ssl3_protocol_version(ssl)); + + uint8_t *secret; + size_t secret_len; + if (direction == evp_aead_open) { + secret = ssl->s3->read_traffic_secret; + secret_len = ssl->s3->read_traffic_secret_len; + } else { + secret = ssl->s3->write_traffic_secret; + secret_len = ssl->s3->write_traffic_secret_len; + } + + if (!hkdf_expand_label(secret, digest, secret, secret_len, + (const uint8_t *)kTLS13LabelApplicationTraffic, + strlen(kTLS13LabelApplicationTraffic), NULL, 0, + secret_len)) { + return 0; + } + + return tls13_set_traffic_key(ssl, direction, secret, secret_len); +} + +static const char kTLS13LabelResumption[] = "resumption master secret"; + +int tls13_derive_resumption_secret(SSL_HANDSHAKE *hs) { + if (hs->hash_len > SSL_MAX_MASTER_KEY_LENGTH) { + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + return 0; + } + + hs->new_session->master_key_length = hs->hash_len; + return derive_secret( + hs, hs->new_session->master_key, hs->new_session->master_key_length, + (const uint8_t *)kTLS13LabelResumption, strlen(kTLS13LabelResumption)); +} + +static const char kTLS13LabelFinished[] = "finished"; + +/* tls13_verify_data sets |out| to be the HMAC of |context| using a derived + * Finished key for both Finished messages and the PSK binder. */ +static int tls13_verify_data(const EVP_MD *digest, uint8_t *out, + size_t *out_len, const uint8_t *secret, + size_t hash_len, uint8_t *context, + size_t context_len) { + uint8_t key[EVP_MAX_MD_SIZE]; + unsigned len; + if (!hkdf_expand_label(key, digest, secret, hash_len, + (const uint8_t *)kTLS13LabelFinished, + strlen(kTLS13LabelFinished), NULL, 0, hash_len) || + HMAC(digest, key, hash_len, context, context_len, out, &len) == NULL) { + return 0; + } + *out_len = len; + return 1; +} + +int tls13_finished_mac(SSL_HANDSHAKE *hs, uint8_t *out, size_t *out_len, + int is_server) { + SSL *const ssl = hs->ssl; + + const uint8_t *traffic_secret; + if (is_server == ssl->server) { + traffic_secret = ssl->s3->write_traffic_secret; + } else { + traffic_secret = ssl->s3->read_traffic_secret; + } + + uint8_t context_hash[EVP_MAX_MD_SIZE]; + size_t context_hash_len; + if (!SSL_TRANSCRIPT_get_hash(&hs->transcript, context_hash, + &context_hash_len) || + !tls13_verify_data(SSL_TRANSCRIPT_md(&hs->transcript), out, out_len, + traffic_secret, hs->hash_len, context_hash, + context_hash_len)) { + return 0; + } + return 1; +} + +int tls13_export_keying_material(SSL *ssl, uint8_t *out, size_t out_len, + const char *label, size_t label_len, + const uint8_t *context, size_t context_len, + int use_context) { + const EVP_MD *digest = ssl_get_handshake_digest( + SSL_get_session(ssl)->cipher->algorithm_prf, ssl3_protocol_version(ssl)); + + const uint8_t *hash = NULL; + size_t hash_len = 0; + if (use_context) { + hash = context; + hash_len = context_len; + } + return hkdf_expand_label(out, digest, ssl->s3->exporter_secret, + ssl->s3->exporter_secret_len, (const uint8_t *)label, + label_len, hash, hash_len, out_len); +} + +static const char kTLS13LabelPSKBinder[] = "resumption psk binder key"; + +static int tls13_psk_binder(uint8_t *out, const EVP_MD *digest, uint8_t *psk, + size_t psk_len, uint8_t *context, + size_t context_len, size_t hash_len) { + uint8_t binder_context[EVP_MAX_MD_SIZE]; + unsigned binder_context_len; + if (!EVP_Digest(NULL, 0, binder_context, &binder_context_len, digest, NULL)) { + return 0; + } + + uint8_t early_secret[EVP_MAX_MD_SIZE] = {0}; + size_t early_secret_len; + if (!HKDF_extract(early_secret, &early_secret_len, digest, psk, hash_len, + NULL, 0)) { + return 0; + } + + uint8_t binder_key[EVP_MAX_MD_SIZE] = {0}; + size_t len; + if (!hkdf_expand_label(binder_key, digest, early_secret, hash_len, + (const uint8_t *)kTLS13LabelPSKBinder, + strlen(kTLS13LabelPSKBinder), binder_context, + binder_context_len, hash_len) || + !tls13_verify_data(digest, out, &len, binder_key, hash_len, context, + context_len)) { + return 0; + } + + return 1; +} + +int tls13_write_psk_binder(SSL_HANDSHAKE *hs, uint8_t *msg, size_t len) { + SSL *const ssl = hs->ssl; + const EVP_MD *digest = SSL_SESSION_get_digest(ssl->session, ssl); + if (digest == NULL) { + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + return 0; + } + size_t hash_len = EVP_MD_size(digest); + + if (len < hash_len + 3) { + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + return 0; + } + + EVP_MD_CTX ctx; + EVP_MD_CTX_init(&ctx); + uint8_t context[EVP_MAX_MD_SIZE]; + unsigned context_len; + if (!EVP_DigestInit_ex(&ctx, digest, NULL) || + !EVP_DigestUpdate(&ctx, hs->transcript.buffer->data, + hs->transcript.buffer->length) || + !EVP_DigestUpdate(&ctx, msg, len - hash_len - 3) || + !EVP_DigestFinal_ex(&ctx, context, &context_len)) { + EVP_MD_CTX_cleanup(&ctx); + return 0; + } + + EVP_MD_CTX_cleanup(&ctx); + + uint8_t verify_data[EVP_MAX_MD_SIZE] = {0}; + if (!tls13_psk_binder(verify_data, digest, ssl->session->master_key, + ssl->session->master_key_length, context, context_len, + hash_len)) { + return 0; + } + + OPENSSL_memcpy(msg + len - hash_len, verify_data, hash_len); + return 1; +} + +int tls13_verify_psk_binder(SSL_HANDSHAKE *hs, SSL_SESSION *session, + CBS *binders) { + size_t hash_len = SSL_TRANSCRIPT_digest_len(&hs->transcript); + + /* Get the full ClientHello, including message header. It must be large enough + * to exclude the binders. */ + CBS message; + hs->ssl->method->get_current_message(hs->ssl, &message); + if (CBS_len(&message) < CBS_len(binders) + 2) { + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + return 0; + } + + /* Hash a ClientHello prefix up to the binders. For now, this assumes we only + * ever verify PSK binders on initial ClientHellos. */ + uint8_t context[EVP_MAX_MD_SIZE]; + unsigned context_len; + if (!EVP_Digest(CBS_data(&message), CBS_len(&message) - CBS_len(binders) - 2, + context, &context_len, SSL_TRANSCRIPT_md(&hs->transcript), + NULL)) { + return 0; + } + + uint8_t verify_data[EVP_MAX_MD_SIZE] = {0}; + CBS binder; + if (!tls13_psk_binder(verify_data, SSL_TRANSCRIPT_md(&hs->transcript), + session->master_key, session->master_key_length, + context, context_len, hash_len) || + /* We only consider the first PSK, so compare against the first binder. */ + !CBS_get_u8_length_prefixed(binders, &binder)) { + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + return 0; + } + + int binder_ok = + CBS_len(&binder) == hash_len && + CRYPTO_memcmp(CBS_data(&binder), verify_data, hash_len) == 0; +#if defined(BORINGSSL_UNSAFE_FUZZER_MODE) + binder_ok = 1; +#endif + if (!binder_ok) { + OPENSSL_PUT_ERROR(SSL, SSL_R_DIGEST_CHECK_FAILED); + return 0; + } + + return 1; +} diff --git a/Sources/BoringSSL/ssl/tls13_server.c b/Sources/BoringSSL/ssl/tls13_server.c new file mode 100644 index 000000000..402c23431 --- /dev/null +++ b/Sources/BoringSSL/ssl/tls13_server.c @@ -0,0 +1,680 @@ +/* Copyright (c) 2016, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "../crypto/internal.h" +#include "internal.h" + + +/* kMaxEarlyDataAccepted is the advertised number of plaintext bytes of early + * data that will be accepted. This value should be slightly below + * kMaxEarlyDataSkipped in tls_record.c, which is measured in ciphertext. */ +static const size_t kMaxEarlyDataAccepted = 14336; + +enum server_hs_state_t { + state_select_parameters = 0, + state_send_hello_retry_request, + state_process_second_client_hello, + state_send_server_hello, + state_send_server_certificate_verify, + state_complete_server_certificate_verify, + state_send_server_finished, + state_process_client_certificate, + state_process_client_certificate_verify, + state_process_channel_id, + state_process_client_finished, + state_send_new_session_ticket, + state_done, +}; + +static const uint8_t kZeroes[EVP_MAX_MD_SIZE] = {0}; + +static int resolve_ecdhe_secret(SSL_HANDSHAKE *hs, int *out_need_retry, + SSL_CLIENT_HELLO *client_hello) { + SSL *const ssl = hs->ssl; + *out_need_retry = 0; + + /* We only support connections that include an ECDHE key exchange. */ + CBS key_share; + if (!ssl_client_hello_get_extension(client_hello, &key_share, + TLSEXT_TYPE_key_share)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_MISSING_KEY_SHARE); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_MISSING_EXTENSION); + return 0; + } + + int found_key_share; + uint8_t *dhe_secret; + size_t dhe_secret_len; + uint8_t alert = SSL_AD_DECODE_ERROR; + if (!ssl_ext_key_share_parse_clienthello(hs, &found_key_share, &dhe_secret, + &dhe_secret_len, &alert, + &key_share)) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, alert); + return 0; + } + + if (!found_key_share) { + *out_need_retry = 1; + return 0; + } + + int ok = tls13_advance_key_schedule(hs, dhe_secret, dhe_secret_len); + OPENSSL_free(dhe_secret); + return ok; +} + +static const SSL_CIPHER *choose_tls13_cipher( + const SSL *ssl, const SSL_CLIENT_HELLO *client_hello) { + if (client_hello->cipher_suites_len % 2 != 0) { + return NULL; + } + + CBS cipher_suites; + CBS_init(&cipher_suites, client_hello->cipher_suites, + client_hello->cipher_suites_len); + + const int aes_is_fine = EVP_has_aes_hardware(); + const uint16_t version = ssl3_protocol_version(ssl); + + const SSL_CIPHER *best = NULL; + while (CBS_len(&cipher_suites) > 0) { + uint16_t cipher_suite; + if (!CBS_get_u16(&cipher_suites, &cipher_suite)) { + return NULL; + } + + /* Limit to TLS 1.3 ciphers we know about. */ + const SSL_CIPHER *candidate = SSL_get_cipher_by_value(cipher_suite); + if (candidate == NULL || + SSL_CIPHER_get_min_version(candidate) > version || + SSL_CIPHER_get_max_version(candidate) < version) { + continue; + } + + /* TLS 1.3 removes legacy ciphers, so honor the client order, but prefer + * ChaCha20 if we do not have AES hardware. */ + if (aes_is_fine) { + return candidate; + } + + if (candidate->algorithm_enc == SSL_CHACHA20POLY1305) { + return candidate; + } + + if (best == NULL) { + best = candidate; + } + } + + return best; +} + +static enum ssl_hs_wait_t do_select_parameters(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + /* The short record header extension is incompatible with early data. */ + if (ssl->s3->skip_early_data && ssl->s3->short_header) { + OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION); + return ssl_hs_error; + } + + SSL_CLIENT_HELLO client_hello; + if (!ssl_client_hello_init(ssl, &client_hello, ssl->init_msg, + ssl->init_num)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_CLIENTHELLO_PARSE_FAILED); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); + return ssl_hs_error; + } + + /* Negotiate the cipher suite. */ + hs->new_cipher = choose_tls13_cipher(ssl, &client_hello); + if (hs->new_cipher == NULL) { + OPENSSL_PUT_ERROR(SSL, SSL_R_NO_SHARED_CIPHER); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE); + return ssl_hs_error; + } + + /* The PRF hash is now known. Set up the key schedule and hash the + * ClientHello. */ + if (!tls13_init_key_schedule(hs) || + !ssl_hash_current_message(hs)) { + return ssl_hs_error; + } + + + /* Decode the ticket if we agree on a PSK key exchange mode. */ + uint8_t alert = SSL_AD_DECODE_ERROR; + SSL_SESSION *session = NULL; + CBS pre_shared_key, binders; + if (hs->accept_psk_mode && + ssl_client_hello_get_extension(&client_hello, &pre_shared_key, + TLSEXT_TYPE_pre_shared_key)) { + /* Verify that the pre_shared_key extension is the last extension in + * ClientHello. */ + if (CBS_data(&pre_shared_key) + CBS_len(&pre_shared_key) != + client_hello.extensions + client_hello.extensions_len) { + OPENSSL_PUT_ERROR(SSL, SSL_R_PRE_SHARED_KEY_MUST_BE_LAST); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER); + return ssl_hs_error; + } + + if (!ssl_ext_pre_shared_key_parse_clienthello(hs, &session, &binders, + &alert, &pre_shared_key)) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, alert); + return ssl_hs_error; + } + } + + if (session != NULL && + !ssl_session_is_resumable(hs, session)) { + SSL_SESSION_free(session); + session = NULL; + } + + /* Set up the new session, either using the original one as a template or + * creating a fresh one. */ + if (session == NULL) { + if (!ssl_get_new_session(hs, 1 /* server */)) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); + return ssl_hs_error; + } + + hs->new_session->cipher = hs->new_cipher; + + /* On new sessions, stash the SNI value in the session. */ + if (hs->hostname != NULL) { + OPENSSL_free(hs->new_session->tlsext_hostname); + hs->new_session->tlsext_hostname = BUF_strdup(hs->hostname); + if (hs->new_session->tlsext_hostname == NULL) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); + return ssl_hs_error; + } + } + } else { + /* Check the PSK binder. */ + if (!tls13_verify_psk_binder(hs, session, &binders)) { + SSL_SESSION_free(session); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECRYPT_ERROR); + return ssl_hs_error; + } + + /* Only authentication information carries over in TLS 1.3. */ + hs->new_session = SSL_SESSION_dup(session, SSL_SESSION_DUP_AUTH_ONLY); + if (hs->new_session == NULL) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); + return ssl_hs_error; + } + ssl->s3->session_reused = 1; + SSL_SESSION_free(session); + + /* Resumption incorporates fresh key material, so refresh the timeout. */ + ssl_session_renew_timeout(ssl, hs->new_session, + ssl->initial_ctx->session_psk_dhe_timeout); + } + + if (ssl->ctx->dos_protection_cb != NULL && + ssl->ctx->dos_protection_cb(&client_hello) == 0) { + /* Connection rejected for DOS reasons. */ + OPENSSL_PUT_ERROR(SSL, SSL_R_CONNECTION_REJECTED); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); + return ssl_hs_error; + } + + /* HTTP/2 negotiation depends on the cipher suite, so ALPN negotiation was + * deferred. Complete it now. */ + alert = SSL_AD_DECODE_ERROR; + if (!ssl_negotiate_alpn(hs, &alert, &client_hello)) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, alert); + return ssl_hs_error; + } + + /* Store the initial negotiated ALPN in the session. */ + if (ssl->s3->alpn_selected != NULL) { + hs->new_session->early_alpn = + BUF_memdup(ssl->s3->alpn_selected, ssl->s3->alpn_selected_len); + if (hs->new_session->early_alpn == NULL) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); + return ssl_hs_error; + } + hs->new_session->early_alpn_len = ssl->s3->alpn_selected_len; + } + + /* Incorporate the PSK into the running secret. */ + if (ssl->s3->session_reused) { + if (!tls13_advance_key_schedule(hs, hs->new_session->master_key, + hs->new_session->master_key_length)) { + return ssl_hs_error; + } + } else if (!tls13_advance_key_schedule(hs, kZeroes, hs->hash_len)) { + return ssl_hs_error; + } + + ssl->method->received_flight(ssl); + + /* Resolve ECDHE and incorporate it into the secret. */ + int need_retry; + if (!resolve_ecdhe_secret(hs, &need_retry, &client_hello)) { + if (need_retry) { + hs->tls13_state = state_send_hello_retry_request; + return ssl_hs_ok; + } + return ssl_hs_error; + } + + hs->tls13_state = state_send_server_hello; + return ssl_hs_ok; +} + +static enum ssl_hs_wait_t do_send_hello_retry_request(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + CBB cbb, body, extensions; + uint16_t group_id; + if (!ssl->method->init_message(ssl, &cbb, &body, + SSL3_MT_HELLO_RETRY_REQUEST) || + !CBB_add_u16(&body, ssl->version) || + !tls1_get_shared_group(hs, &group_id) || + !CBB_add_u16_length_prefixed(&body, &extensions) || + !CBB_add_u16(&extensions, TLSEXT_TYPE_key_share) || + !CBB_add_u16(&extensions, 2 /* length */) || + !CBB_add_u16(&extensions, group_id) || + !ssl_add_message_cbb(ssl, &cbb)) { + CBB_cleanup(&cbb); + return ssl_hs_error; + } + + hs->tls13_state = state_process_second_client_hello; + return ssl_hs_flush_and_read_message; +} + +static enum ssl_hs_wait_t do_process_second_client_hello(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + if (!ssl_check_message_type(ssl, SSL3_MT_CLIENT_HELLO)) { + return ssl_hs_error; + } + + SSL_CLIENT_HELLO client_hello; + if (!ssl_client_hello_init(ssl, &client_hello, ssl->init_msg, + ssl->init_num)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_CLIENTHELLO_PARSE_FAILED); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); + return ssl_hs_error; + } + + int need_retry; + if (!resolve_ecdhe_secret(hs, &need_retry, &client_hello)) { + if (need_retry) { + /* Only send one HelloRetryRequest. */ + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER); + OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CURVE); + } + return ssl_hs_error; + } + + if (!ssl_hash_current_message(hs)) { + return ssl_hs_error; + } + + ssl->method->received_flight(ssl); + hs->tls13_state = state_send_server_hello; + return ssl_hs_ok; +} + +static enum ssl_hs_wait_t do_send_server_hello(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + + /* Send a ServerHello. */ + CBB cbb, body, extensions; + if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_SERVER_HELLO) || + !CBB_add_u16(&body, ssl->version) || + !RAND_bytes(ssl->s3->server_random, sizeof(ssl->s3->server_random)) || + !CBB_add_bytes(&body, ssl->s3->server_random, SSL3_RANDOM_SIZE) || + !CBB_add_u16(&body, ssl_cipher_get_value(hs->new_cipher)) || + !CBB_add_u16_length_prefixed(&body, &extensions) || + !ssl_ext_pre_shared_key_add_serverhello(hs, &extensions) || + !ssl_ext_key_share_add_serverhello(hs, &extensions)) { + goto err; + } + + if (ssl->s3->short_header) { + if (!CBB_add_u16(&extensions, TLSEXT_TYPE_short_header) || + !CBB_add_u16(&extensions, 0 /* empty extension */)) { + goto err; + } + } + + if (!ssl_add_message_cbb(ssl, &cbb)) { + goto err; + } + + /* Derive and enable the handshake traffic secrets. */ + if (!tls13_derive_handshake_secrets(hs) || + !tls13_set_traffic_key(ssl, evp_aead_open, hs->client_handshake_secret, + hs->hash_len) || + !tls13_set_traffic_key(ssl, evp_aead_seal, hs->server_handshake_secret, + hs->hash_len)) { + goto err; + } + + /* Send EncryptedExtensions. */ + if (!ssl->method->init_message(ssl, &cbb, &body, + SSL3_MT_ENCRYPTED_EXTENSIONS) || + !ssl_add_serverhello_tlsext(hs, &body) || + !ssl_add_message_cbb(ssl, &cbb)) { + goto err; + } + + /* Determine whether to request a client certificate. */ + hs->cert_request = !!(ssl->verify_mode & SSL_VERIFY_PEER); + /* CertificateRequest may only be sent in non-resumption handshakes. */ + if (ssl->s3->session_reused) { + hs->cert_request = 0; + } + + /* Send a CertificateRequest, if necessary. */ + if (hs->cert_request) { + CBB sigalgs_cbb; + if (!ssl->method->init_message(ssl, &cbb, &body, + SSL3_MT_CERTIFICATE_REQUEST) || + !CBB_add_u8(&body, 0 /* no certificate_request_context. */)) { + goto err; + } + + const uint16_t *sigalgs; + size_t num_sigalgs = tls12_get_verify_sigalgs(ssl, &sigalgs); + if (!CBB_add_u16_length_prefixed(&body, &sigalgs_cbb)) { + goto err; + } + + for (size_t i = 0; i < num_sigalgs; i++) { + if (!CBB_add_u16(&sigalgs_cbb, sigalgs[i])) { + goto err; + } + } + + if (!ssl_add_client_CA_list(ssl, &body) || + !CBB_add_u16(&body, 0 /* empty certificate_extensions. */) || + !ssl_add_message_cbb(ssl, &cbb)) { + goto err; + } + } + + /* Send the server Certificate message, if necessary. */ + if (!ssl->s3->session_reused) { + if (!ssl_has_certificate(ssl)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CERTIFICATE_SET); + goto err; + } + + if (!tls13_add_certificate(hs)) { + goto err; + } + + hs->tls13_state = state_send_server_certificate_verify; + return ssl_hs_ok; + } + + hs->tls13_state = state_send_server_finished; + return ssl_hs_ok; + +err: + CBB_cleanup(&cbb); + return ssl_hs_error; +} + +static enum ssl_hs_wait_t do_send_server_certificate_verify(SSL_HANDSHAKE *hs, + int is_first_run) { + switch (tls13_add_certificate_verify(hs, is_first_run)) { + case ssl_private_key_success: + hs->tls13_state = state_send_server_finished; + return ssl_hs_ok; + + case ssl_private_key_retry: + hs->tls13_state = state_complete_server_certificate_verify; + return ssl_hs_private_key_operation; + + case ssl_private_key_failure: + return ssl_hs_error; + } + + assert(0); + return ssl_hs_error; +} + +static enum ssl_hs_wait_t do_send_server_finished(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + if (!tls13_add_finished(hs) || + /* Update the secret to the master secret and derive traffic keys. */ + !tls13_advance_key_schedule(hs, kZeroes, hs->hash_len) || + !tls13_derive_application_secrets(hs) || + !tls13_set_traffic_key(ssl, evp_aead_seal, hs->server_traffic_secret_0, + hs->hash_len)) { + return ssl_hs_error; + } + + hs->tls13_state = state_process_client_certificate; + return ssl_hs_flush_and_read_message; +} + +static enum ssl_hs_wait_t do_process_client_certificate(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + if (!hs->cert_request) { + /* OpenSSL returns X509_V_OK when no certificates are requested. This is + * classed by them as a bug, but it's assumed by at least NGINX. */ + hs->new_session->verify_result = X509_V_OK; + + /* Skip this state. */ + hs->tls13_state = state_process_channel_id; + return ssl_hs_ok; + } + + const int allow_anonymous = + (ssl->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) == 0; + + if (!ssl_check_message_type(ssl, SSL3_MT_CERTIFICATE) || + !tls13_process_certificate(hs, allow_anonymous) || + !ssl_hash_current_message(hs)) { + return ssl_hs_error; + } + + hs->tls13_state = state_process_client_certificate_verify; + return ssl_hs_read_message; +} + +static enum ssl_hs_wait_t do_process_client_certificate_verify( + SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + if (sk_CRYPTO_BUFFER_num(hs->new_session->certs) == 0) { + /* Skip this state. */ + hs->tls13_state = state_process_channel_id; + return ssl_hs_ok; + } + + if (!ssl_check_message_type(ssl, SSL3_MT_CERTIFICATE_VERIFY) || + !tls13_process_certificate_verify(hs) || + !ssl_hash_current_message(hs)) { + return ssl_hs_error; + } + + hs->tls13_state = state_process_channel_id; + return ssl_hs_read_message; +} + +static enum ssl_hs_wait_t do_process_channel_id(SSL_HANDSHAKE *hs) { + if (!hs->ssl->s3->tlsext_channel_id_valid) { + hs->tls13_state = state_process_client_finished; + return ssl_hs_ok; + } + + if (!ssl_check_message_type(hs->ssl, SSL3_MT_CHANNEL_ID) || + !tls1_verify_channel_id(hs) || + !ssl_hash_current_message(hs)) { + return ssl_hs_error; + } + + hs->tls13_state = state_process_client_finished; + return ssl_hs_read_message; +} + +static enum ssl_hs_wait_t do_process_client_finished(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + if (!ssl_check_message_type(ssl, SSL3_MT_FINISHED) || + !tls13_process_finished(hs) || + !ssl_hash_current_message(hs) || + /* evp_aead_seal keys have already been switched. */ + !tls13_set_traffic_key(ssl, evp_aead_open, hs->client_traffic_secret_0, + hs->hash_len) || + !tls13_derive_resumption_secret(hs)) { + return ssl_hs_error; + } + + ssl->method->received_flight(ssl); + + /* Rebase the session timestamp so that it is measured from ticket + * issuance. */ + ssl_session_rebase_time(ssl, hs->new_session); + hs->tls13_state = state_send_new_session_ticket; + return ssl_hs_ok; +} + +static enum ssl_hs_wait_t do_send_new_session_ticket(SSL_HANDSHAKE *hs) { + /* TLS 1.3 recommends single-use tickets, so issue multiple tickets in case the + * client makes several connections before getting a renewal. */ + static const int kNumTickets = 2; + + SSL *const ssl = hs->ssl; + /* If the client doesn't accept resumption with PSK_DHE_KE, don't send a + * session ticket. */ + if (!hs->accept_psk_mode) { + hs->tls13_state = state_done; + return ssl_hs_ok; + } + + SSL_SESSION *session = hs->new_session; + CBB cbb; + CBB_zero(&cbb); + + for (int i = 0; i < kNumTickets; i++) { + if (!RAND_bytes((uint8_t *)&session->ticket_age_add, 4)) { + goto err; + } + + CBB body, ticket, extensions; + if (!ssl->method->init_message(ssl, &cbb, &body, + SSL3_MT_NEW_SESSION_TICKET) || + !CBB_add_u32(&body, session->timeout) || + !CBB_add_u32(&body, session->ticket_age_add) || + !CBB_add_u16_length_prefixed(&body, &ticket) || + !ssl_encrypt_ticket(ssl, &ticket, session) || + !CBB_add_u16_length_prefixed(&body, &extensions)) { + goto err; + } + + if (ssl->ctx->enable_early_data) { + session->ticket_max_early_data = kMaxEarlyDataAccepted; + + CBB early_data_info; + if (!CBB_add_u16(&extensions, TLSEXT_TYPE_ticket_early_data_info) || + !CBB_add_u16_length_prefixed(&extensions, &early_data_info) || + !CBB_add_u32(&early_data_info, session->ticket_max_early_data) || + !CBB_flush(&extensions)) { + goto err; + } + } + + /* Add a fake extension. See draft-davidben-tls-grease-01. */ + if (!CBB_add_u16(&extensions, + ssl_get_grease_value(ssl, ssl_grease_ticket_extension)) || + !CBB_add_u16(&extensions, 0 /* empty */)) { + goto err; + } + + if (!ssl_add_message_cbb(ssl, &cbb)) { + goto err; + } + } + + hs->session_tickets_sent++; + hs->tls13_state = state_done; + return ssl_hs_flush; + +err: + CBB_cleanup(&cbb); + return ssl_hs_error; +} + +enum ssl_hs_wait_t tls13_server_handshake(SSL_HANDSHAKE *hs) { + while (hs->tls13_state != state_done) { + enum ssl_hs_wait_t ret = ssl_hs_error; + enum server_hs_state_t state = hs->tls13_state; + switch (state) { + case state_select_parameters: + ret = do_select_parameters(hs); + break; + case state_send_hello_retry_request: + ret = do_send_hello_retry_request(hs); + break; + case state_process_second_client_hello: + ret = do_process_second_client_hello(hs); + break; + case state_send_server_hello: + ret = do_send_server_hello(hs); + break; + case state_send_server_certificate_verify: + ret = do_send_server_certificate_verify(hs, 1 /* first run */); + break; + case state_complete_server_certificate_verify: + ret = do_send_server_certificate_verify(hs, 0 /* complete */); + break; + case state_send_server_finished: + ret = do_send_server_finished(hs); + break; + case state_process_client_certificate: + ret = do_process_client_certificate(hs); + break; + case state_process_client_certificate_verify: + ret = do_process_client_certificate_verify(hs); + break; + case state_process_channel_id: + ret = do_process_channel_id(hs); + break; + case state_process_client_finished: + ret = do_process_client_finished(hs); + break; + case state_send_new_session_ticket: + ret = do_send_new_session_ticket(hs); + break; + case state_done: + ret = ssl_hs_ok; + break; + } + + if (ret != ssl_hs_ok) { + return ret; + } + } + + return ssl_hs_ok; +} diff --git a/Sources/BoringSSL/ssl/s3_meth.c b/Sources/BoringSSL/ssl/tls_method.c similarity index 55% rename from Sources/BoringSSL/ssl/s3_meth.c rename to Sources/BoringSSL/ssl/tls_method.c index b60b5f2c1..eaad2cafb 100644 --- a/Sources/BoringSSL/ssl/s3_meth.c +++ b/Sources/BoringSSL/ssl/tls_method.c @@ -56,33 +56,114 @@ #include +#include +#include + +#include + +#include "../crypto/internal.h" #include "internal.h" -static const SSL_PROTOCOL_METHOD TLS_protocol_method = { +static int ssl3_version_from_wire(uint16_t *out_version, + uint16_t wire_version) { + switch (wire_version) { + case SSL3_VERSION: + case TLS1_VERSION: + case TLS1_1_VERSION: + case TLS1_2_VERSION: + *out_version = wire_version; + return 1; + case TLS1_3_DRAFT_VERSION: + *out_version = TLS1_3_VERSION; + return 1; + } + + return 0; +} + +static uint16_t ssl3_version_to_wire(uint16_t version) { + switch (version) { + case SSL3_VERSION: + case TLS1_VERSION: + case TLS1_1_VERSION: + case TLS1_2_VERSION: + return version; + case TLS1_3_VERSION: + return TLS1_3_DRAFT_VERSION; + } + + /* It is an error to use this function with an invalid version. */ + assert(0); + return 0; +} + +static int ssl3_supports_cipher(const SSL_CIPHER *cipher) { return 1; } + +static void ssl3_expect_flight(SSL *ssl) {} + +static void ssl3_received_flight(SSL *ssl) {} + +static int ssl3_set_read_state(SSL *ssl, SSL_AEAD_CTX *aead_ctx) { + if (ssl->s3->rrec.length != 0) { + /* There may not be unprocessed record data at a cipher change. */ + OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFERED_MESSAGES_ON_CIPHER_CHANGE); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE); + SSL_AEAD_CTX_free(aead_ctx); + return 0; + } + + OPENSSL_memset(ssl->s3->read_sequence, 0, sizeof(ssl->s3->read_sequence)); + + SSL_AEAD_CTX_free(ssl->s3->aead_read_ctx); + ssl->s3->aead_read_ctx = aead_ctx; + return 1; +} + +static int ssl3_set_write_state(SSL *ssl, SSL_AEAD_CTX *aead_ctx) { + OPENSSL_memset(ssl->s3->write_sequence, 0, sizeof(ssl->s3->write_sequence)); + + SSL_AEAD_CTX_free(ssl->s3->aead_write_ctx); + ssl->s3->aead_write_ctx = aead_ctx; + return 1; +} + +static const SSL_PROTOCOL_METHOD kTLSProtocolMethod = { 0 /* is_dtls */, + SSL3_VERSION, + TLS1_3_VERSION, + ssl3_version_from_wire, + ssl3_version_to_wire, ssl3_new, ssl3_free, - ssl3_accept, - ssl3_connect, ssl3_get_message, + ssl3_get_current_message, + ssl3_release_current_message, ssl3_read_app_data, ssl3_read_change_cipher_spec, ssl3_read_close_notify, ssl3_write_app_data, ssl3_dispatch_alert, ssl3_supports_cipher, - SSL3_HM_HEADER_LENGTH, - ssl3_set_handshake_header, - ssl3_handshake_write, + ssl3_init_message, + ssl3_finish_message, + ssl3_add_message, + ssl3_add_change_cipher_spec, + ssl3_add_alert, + ssl3_flush_flight, + ssl3_expect_flight, + ssl3_received_flight, + ssl3_set_read_state, + ssl3_set_write_state, }; const SSL_METHOD *TLS_method(void) { - static const SSL_METHOD method = { + static const SSL_METHOD kMethod = { 0, - &TLS_protocol_method, + &kTLSProtocolMethod, + &ssl_crypto_x509_method, }; - return &method; + return &kMethod; } const SSL_METHOD *SSLv23_method(void) { @@ -92,35 +173,39 @@ const SSL_METHOD *SSLv23_method(void) { /* Legacy version-locked methods. */ const SSL_METHOD *TLSv1_2_method(void) { - static const SSL_METHOD method = { + static const SSL_METHOD kMethod = { TLS1_2_VERSION, - &TLS_protocol_method, + &kTLSProtocolMethod, + &ssl_crypto_x509_method, }; - return &method; + return &kMethod; } const SSL_METHOD *TLSv1_1_method(void) { - static const SSL_METHOD method = { + static const SSL_METHOD kMethod = { TLS1_1_VERSION, - &TLS_protocol_method, + &kTLSProtocolMethod, + &ssl_crypto_x509_method, }; - return &method; + return &kMethod; } const SSL_METHOD *TLSv1_method(void) { - static const SSL_METHOD method = { + static const SSL_METHOD kMethod = { TLS1_VERSION, - &TLS_protocol_method, + &kTLSProtocolMethod, + &ssl_crypto_x509_method, }; - return &method; + return &kMethod; } const SSL_METHOD *SSLv3_method(void) { - static const SSL_METHOD method = { + static const SSL_METHOD kMethod = { SSL3_VERSION, - &TLS_protocol_method, + &kTLSProtocolMethod, + &ssl_crypto_x509_method, }; - return &method; + return &kMethod; } /* Legacy side-specific methods. */ @@ -164,3 +249,32 @@ const SSL_METHOD *SSLv23_server_method(void) { const SSL_METHOD *SSLv23_client_method(void) { return SSLv23_method(); } + +const SSL_METHOD *TLS_server_method(void) { + return TLS_method(); +} + +const SSL_METHOD *TLS_client_method(void) { + return TLS_method(); +} + +static void ssl_noop_x509_clear(CERT *cert) {} +static void ssl_noop_x509_flush_cached_leaf(CERT *cert) {} +static void ssl_noop_x509_flush_cached_chain(CERT *cert) {} +static int ssl_noop_x509_session_cache_objects(SSL_SESSION *sess) { + return 1; +} +static int ssl_noop_x509_session_dup(SSL_SESSION *new_session, + const SSL_SESSION *session) { + return 1; +} +static void ssl_noop_x509_session_clear(SSL_SESSION *session) {} + +const SSL_X509_METHOD ssl_noop_x509_method = { + ssl_noop_x509_clear, + ssl_noop_x509_flush_cached_chain, + ssl_noop_x509_flush_cached_leaf, + ssl_noop_x509_session_cache_objects, + ssl_noop_x509_session_dup, + ssl_noop_x509_session_clear, +}; diff --git a/Sources/BoringSSL/ssl/tls_record.c b/Sources/BoringSSL/ssl/tls_record.c index d53e1d78c..6ff79c4b4 100644 --- a/Sources/BoringSSL/ssl/tls_record.c +++ b/Sources/BoringSSL/ssl/tls_record.c @@ -113,8 +113,10 @@ #include #include +#include #include "internal.h" +#include "../crypto/internal.h" /* kMaxEmptyRecords is the number of consecutive, empty records that will be @@ -123,6 +125,17 @@ * forever. */ static const uint8_t kMaxEmptyRecords = 32; +/* kMaxEarlyDataSkipped is the maximum number of rejected early data bytes that + * will be skipped. Without this limit an attacker could send records at a + * faster rate than we can process and cause trial decryption to loop forever. + * This value should be slightly above kMaxEarlyDataAccepted in tls13_server.c, + * which is measured in plaintext. */ +static const size_t kMaxEarlyDataSkipped = 16384; + +/* kMaxWarningAlerts is the number of consecutive warning alerts that will be + * processed. */ +static const uint8_t kMaxWarningAlerts = 4; + /* ssl_needs_record_splitting returns one if |ssl|'s current outgoing cipher * state needs record-splitting and zero otherwise. */ static int ssl_needs_record_splitting(const SSL *ssl) { @@ -132,9 +145,21 @@ static int ssl_needs_record_splitting(const SSL *ssl) { SSL_CIPHER_is_block_cipher(ssl->s3->aead_write_ctx->cipher); } +static int ssl_uses_short_header(const SSL *ssl, + enum evp_aead_direction_t dir) { + if (!ssl->s3->short_header) { + return 0; + } + + if (dir == evp_aead_open) { + return ssl->s3->aead_read_ctx != NULL; + } + + return ssl->s3->aead_write_ctx != NULL; +} + int ssl_record_sequence_update(uint8_t *seq, size_t seq_len) { - size_t i; - for (i = seq_len - 1; i < seq_len; i--) { + for (size_t i = seq_len - 1; i < seq_len; i--) { ++seq[i]; if (seq[i] != 0) { return 1; @@ -145,64 +170,111 @@ int ssl_record_sequence_update(uint8_t *seq, size_t seq_len) { } size_t ssl_record_prefix_len(const SSL *ssl) { - if (SSL_IS_DTLS(ssl)) { - return DTLS1_RT_HEADER_LENGTH + - SSL_AEAD_CTX_explicit_nonce_len(ssl->s3->aead_read_ctx); + size_t header_len; + if (SSL_is_dtls(ssl)) { + header_len = DTLS1_RT_HEADER_LENGTH; + } else if (ssl_uses_short_header(ssl, evp_aead_open)) { + header_len = 2; } else { - return SSL3_RT_HEADER_LENGTH + - SSL_AEAD_CTX_explicit_nonce_len(ssl->s3->aead_read_ctx); + header_len = SSL3_RT_HEADER_LENGTH; } + + return header_len + SSL_AEAD_CTX_explicit_nonce_len(ssl->s3->aead_read_ctx); } -size_t ssl_seal_prefix_len(const SSL *ssl) { - if (SSL_IS_DTLS(ssl)) { +size_t ssl_seal_align_prefix_len(const SSL *ssl) { + if (SSL_is_dtls(ssl)) { return DTLS1_RT_HEADER_LENGTH + SSL_AEAD_CTX_explicit_nonce_len(ssl->s3->aead_write_ctx); + } + + size_t header_len; + if (ssl_uses_short_header(ssl, evp_aead_seal)) { + header_len = 2; } else { - size_t ret = SSL3_RT_HEADER_LENGTH + - SSL_AEAD_CTX_explicit_nonce_len(ssl->s3->aead_write_ctx); - if (ssl_needs_record_splitting(ssl)) { - ret += SSL3_RT_HEADER_LENGTH; - ret += ssl_cipher_get_record_split_len(ssl->s3->aead_write_ctx->cipher); - } - return ret; + header_len = SSL3_RT_HEADER_LENGTH; + } + + size_t ret = + header_len + SSL_AEAD_CTX_explicit_nonce_len(ssl->s3->aead_write_ctx); + if (ssl_needs_record_splitting(ssl)) { + ret += header_len; + ret += ssl_cipher_get_record_split_len(ssl->s3->aead_write_ctx->cipher); } + return ret; } -size_t ssl_max_seal_overhead(const SSL *ssl) { - if (SSL_IS_DTLS(ssl)) { - return DTLS1_RT_HEADER_LENGTH + - SSL_AEAD_CTX_max_overhead(ssl->s3->aead_write_ctx); - } else { - size_t ret = SSL3_RT_HEADER_LENGTH + - SSL_AEAD_CTX_max_overhead(ssl->s3->aead_write_ctx); - if (ssl_needs_record_splitting(ssl)) { - ret *= 2; - } - return ret; +size_t SSL_max_seal_overhead(const SSL *ssl) { + if (SSL_is_dtls(ssl)) { + return dtls_max_seal_overhead(ssl, dtls1_use_current_epoch); + } + + size_t ret = + ssl_uses_short_header(ssl, evp_aead_seal) ? 2 : SSL3_RT_HEADER_LENGTH; + ret += SSL_AEAD_CTX_max_overhead(ssl->s3->aead_write_ctx); + /* TLS 1.3 needs an extra byte for the encrypted record type. */ + if (ssl->s3->have_version && + ssl3_protocol_version(ssl) >= TLS1_3_VERSION) { + ret += 1; } + if (ssl_needs_record_splitting(ssl)) { + ret *= 2; + } + return ret; } -enum ssl_open_record_t tls_open_record( - SSL *ssl, uint8_t *out_type, uint8_t *out, size_t *out_len, - size_t *out_consumed, uint8_t *out_alert, size_t max_out, const uint8_t *in, - size_t in_len) { +enum ssl_open_record_t tls_open_record(SSL *ssl, uint8_t *out_type, CBS *out, + size_t *out_consumed, uint8_t *out_alert, + uint8_t *in, size_t in_len) { + *out_consumed = 0; + CBS cbs; CBS_init(&cbs, in, in_len); /* Decode the record header. */ uint8_t type; uint16_t version, ciphertext_len; - if (!CBS_get_u8(&cbs, &type) || - !CBS_get_u16(&cbs, &version) || - !CBS_get_u16(&cbs, &ciphertext_len)) { - *out_consumed = SSL3_RT_HEADER_LENGTH; - return ssl_open_record_partial; + size_t header_len; + if (ssl_uses_short_header(ssl, evp_aead_open)) { + if (!CBS_get_u16(&cbs, &ciphertext_len)) { + *out_consumed = 2; + return ssl_open_record_partial; + } + + if ((ciphertext_len & 0x8000) == 0) { + OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + *out_alert = SSL_AD_DECODE_ERROR; + return ssl_open_record_error; + } + + ciphertext_len &= 0x7fff; + type = SSL3_RT_APPLICATION_DATA; + version = TLS1_VERSION; + header_len = 2; + } else { + if (!CBS_get_u8(&cbs, &type) || + !CBS_get_u16(&cbs, &version) || + !CBS_get_u16(&cbs, &ciphertext_len)) { + *out_consumed = SSL3_RT_HEADER_LENGTH; + return ssl_open_record_partial; + } + header_len = SSL3_RT_HEADER_LENGTH; + } + + int version_ok; + if (ssl->s3->aead_read_ctx == NULL) { + /* Only check the first byte. Enforcing beyond that can prevent decoding + * version negotiation failure alerts. */ + version_ok = (version >> 8) == SSL3_VERSION_MAJOR; + } else if (ssl3_protocol_version(ssl) < TLS1_3_VERSION) { + /* Earlier versions of TLS switch the record version. */ + version_ok = version == ssl->version; + } else { + /* Starting TLS 1.3, the version field is frozen at {3, 1}. */ + version_ok = version == TLS1_VERSION; } - /* Check the version. */ - if ((ssl->s3->have_version && version != ssl->version) || - (version >> 8) != SSL3_VERSION_MAJOR) { + if (!version_ok) { OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_VERSION_NUMBER); *out_alert = SSL_AD_PROTOCOL_VERSION; return ssl_open_record_error; @@ -218,38 +290,73 @@ enum ssl_open_record_t tls_open_record( /* Extract the body. */ CBS body; if (!CBS_get_bytes(&cbs, &body, ciphertext_len)) { - *out_consumed = SSL3_RT_HEADER_LENGTH + (size_t)ciphertext_len; + *out_consumed = header_len + (size_t)ciphertext_len; return ssl_open_record_partial; } - if (ssl->msg_callback != NULL) { - ssl->msg_callback(0 /* read */, 0, SSL3_RT_HEADER, in, - SSL3_RT_HEADER_LENGTH, ssl, ssl->msg_callback_arg); + ssl_do_msg_callback(ssl, 0 /* read */, SSL3_RT_HEADER, in, header_len); + + *out_consumed = in_len - CBS_len(&cbs); + + /* Skip early data received when expecting a second ClientHello if we rejected + * 0RTT. */ + if (ssl->s3->skip_early_data && + ssl->s3->aead_read_ctx == NULL && + type == SSL3_RT_APPLICATION_DATA) { + goto skipped_data; } - /* Decrypt the body. */ - size_t plaintext_len; - if (!SSL_AEAD_CTX_open(ssl->s3->aead_read_ctx, out, &plaintext_len, max_out, - type, version, ssl->s3->read_sequence, CBS_data(&body), + /* Decrypt the body in-place. */ + if (!SSL_AEAD_CTX_open(ssl->s3->aead_read_ctx, out, type, version, + ssl->s3->read_sequence, (uint8_t *)CBS_data(&body), CBS_len(&body))) { + if (ssl->s3->skip_early_data && + ssl->s3->aead_read_ctx != NULL) { + ERR_clear_error(); + goto skipped_data; + } + OPENSSL_PUT_ERROR(SSL, SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC); *out_alert = SSL_AD_BAD_RECORD_MAC; return ssl_open_record_error; } + + ssl->s3->skip_early_data = 0; + if (!ssl_record_sequence_update(ssl->s3->read_sequence, 8)) { *out_alert = SSL_AD_INTERNAL_ERROR; return ssl_open_record_error; } + /* TLS 1.3 hides the record type inside the encrypted data. */ + if (ssl->s3->have_version && + ssl3_protocol_version(ssl) >= TLS1_3_VERSION && + ssl->s3->aead_read_ctx != NULL) { + /* The outer record type is always application_data. */ + if (type != SSL3_RT_APPLICATION_DATA) { + OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_OUTER_RECORD_TYPE); + *out_alert = SSL_AD_DECODE_ERROR; + return ssl_open_record_error; + } + + do { + if (!CBS_get_last_u8(out, &type)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC); + *out_alert = SSL_AD_DECRYPT_ERROR; + return ssl_open_record_error; + } + } while (type == 0); + } + /* Check the plaintext length. */ - if (plaintext_len > SSL3_RT_MAX_PLAIN_LENGTH) { + if (CBS_len(out) > SSL3_RT_MAX_PLAIN_LENGTH) { OPENSSL_PUT_ERROR(SSL, SSL_R_DATA_LENGTH_TOO_LONG); *out_alert = SSL_AD_RECORD_OVERFLOW; return ssl_open_record_error; } /* Limit the number of consecutive empty records. */ - if (plaintext_len == 0) { + if (CBS_len(out) == 0) { ssl->s3->empty_record_count++; if (ssl->s3->empty_record_count > kMaxEmptyRecords) { OPENSSL_PUT_ERROR(SSL, SSL_R_TOO_MANY_EMPTY_FRAGMENTS); @@ -262,80 +369,115 @@ enum ssl_open_record_t tls_open_record( ssl->s3->empty_record_count = 0; } + if (type == SSL3_RT_ALERT) { + return ssl_process_alert(ssl, out_alert, CBS_data(out), CBS_len(out)); + } + + ssl->s3->warning_alert_count = 0; + *out_type = type; - *out_len = plaintext_len; - *out_consumed = in_len - CBS_len(&cbs); return ssl_open_record_success; + +skipped_data: + ssl->s3->early_data_skipped += *out_consumed; + if (ssl->s3->early_data_skipped < *out_consumed) { + ssl->s3->early_data_skipped = kMaxEarlyDataSkipped + 1; + } + + if (ssl->s3->early_data_skipped > kMaxEarlyDataSkipped) { + OPENSSL_PUT_ERROR(SSL, SSL_R_TOO_MUCH_SKIPPED_EARLY_DATA); + *out_alert = SSL_AD_UNEXPECTED_MESSAGE; + return ssl_open_record_error; + } + + return ssl_open_record_discard; } static int do_seal_record(SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out, uint8_t type, const uint8_t *in, size_t in_len) { - if (max_out < SSL3_RT_HEADER_LENGTH) { - OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFER_TOO_SMALL); - return 0; + assert(!buffers_alias(in, in_len, out, max_out)); + + const int short_header = ssl_uses_short_header(ssl, evp_aead_seal); + size_t header_len = short_header ? 2 : SSL3_RT_HEADER_LENGTH; + + /* TLS 1.3 hides the actual record type inside the encrypted data. */ + if (ssl->s3->have_version && + ssl3_protocol_version(ssl) >= TLS1_3_VERSION && + ssl->s3->aead_write_ctx != NULL) { + if (in_len > in_len + header_len + 1 || max_out < in_len + header_len + 1) { + OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFER_TOO_SMALL); + return 0; + } + + OPENSSL_memcpy(out + header_len, in, in_len); + out[header_len + in_len] = type; + in = out + header_len; + type = SSL3_RT_APPLICATION_DATA; + in_len++; } - /* Check the record header does not alias any part of the input. - * |SSL_AEAD_CTX_seal| will internally enforce other aliasing requirements. */ - if (in < out + SSL3_RT_HEADER_LENGTH && out < in + in_len) { - OPENSSL_PUT_ERROR(SSL, SSL_R_OUTPUT_ALIASES_INPUT); + + if (max_out < header_len) { + OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFER_TOO_SMALL); return 0; } - out[0] = type; + /* The TLS record-layer version number is meaningless and, starting in + * TLS 1.3, is frozen at TLS 1.0. But for historical reasons, SSL 3.0 + * ClientHellos should use SSL 3.0 and pre-TLS-1.3 expects the version + * to change after version negotiation. */ + uint16_t wire_version = TLS1_VERSION; + if (ssl->version == SSL3_VERSION || + (ssl->s3->have_version && ssl3_protocol_version(ssl) < TLS1_3_VERSION)) { + wire_version = ssl->version; + } - /* Some servers hang if initial ClientHello is larger than 256 bytes and - * record version number > TLS 1.0. */ - uint16_t wire_version = ssl->version; - if (!ssl->s3->have_version && ssl->version > SSL3_VERSION) { - wire_version = TLS1_VERSION; + /* Write the non-length portions of the header. */ + if (!short_header) { + out[0] = type; + out[1] = wire_version >> 8; + out[2] = wire_version & 0xff; + out += 3; + max_out -= 3; } - out[1] = wire_version >> 8; - out[2] = wire_version & 0xff; + /* Write the ciphertext, leaving two bytes for the length. */ size_t ciphertext_len; - if (!SSL_AEAD_CTX_seal(ssl->s3->aead_write_ctx, out + SSL3_RT_HEADER_LENGTH, - &ciphertext_len, max_out - SSL3_RT_HEADER_LENGTH, - type, wire_version, ssl->s3->write_sequence, in, - in_len) || + if (!SSL_AEAD_CTX_seal(ssl->s3->aead_write_ctx, out + 2, &ciphertext_len, + max_out - 2, type, wire_version, + ssl->s3->write_sequence, in, in_len) || !ssl_record_sequence_update(ssl->s3->write_sequence, 8)) { return 0; } - if (ciphertext_len >= 1 << 16) { + /* Fill in the length. */ + if (ciphertext_len >= 1 << 15) { OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW); return 0; } - out[3] = ciphertext_len >> 8; - out[4] = ciphertext_len & 0xff; - - *out_len = SSL3_RT_HEADER_LENGTH + ciphertext_len; - - if (ssl->msg_callback) { - ssl->msg_callback(1 /* write */, 0, SSL3_RT_HEADER, out, - SSL3_RT_HEADER_LENGTH, ssl, ssl->msg_callback_arg); + out[0] = ciphertext_len >> 8; + out[1] = ciphertext_len & 0xff; + if (short_header) { + out[0] |= 0x80; } + *out_len = header_len + ciphertext_len; + + ssl_do_msg_callback(ssl, 1 /* write */, SSL3_RT_HEADER, out, header_len); return 1; } int tls_seal_record(SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out, uint8_t type, const uint8_t *in, size_t in_len) { + if (buffers_alias(in, in_len, out, max_out)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_OUTPUT_ALIASES_INPUT); + return 0; + } + size_t frag_len = 0; if (type == SSL3_RT_APPLICATION_DATA && in_len > 1 && ssl_needs_record_splitting(ssl)) { - /* |do_seal_record| will notice if it clobbers |in[0]|, but not if it - * aliases the rest of |in|. */ - if (in + 1 <= out && out < in + in_len) { - OPENSSL_PUT_ERROR(SSL, SSL_R_OUTPUT_ALIASES_INPUT); - return 0; - } - /* Ensure |do_seal_record| does not write beyond |in[0]|. */ - size_t frag_max_out = max_out; - if (out <= in + 1 && in + 1 < out + frag_max_out) { - frag_max_out = (size_t)(in + 1 - out); - } - if (!do_seal_record(ssl, out, &frag_len, frag_max_out, type, in, 1)) { + if (!do_seal_record(ssl, out, &frag_len, max_out, type, in, 1)) { return 0; } in++; @@ -343,9 +485,12 @@ int tls_seal_record(SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out, out += frag_len; max_out -= frag_len; + assert(!ssl_uses_short_header(ssl, evp_aead_seal)); +#if !defined(BORINGSSL_UNSAFE_FUZZER_MODE) assert(SSL3_RT_HEADER_LENGTH + ssl_cipher_get_record_split_len( ssl->s3->aead_write_ctx->cipher) == frag_len); +#endif } if (!do_seal_record(ssl, out, out_len, max_out, type, in, in_len)) { @@ -355,25 +500,57 @@ int tls_seal_record(SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out, return 1; } -void ssl_set_read_state(SSL *ssl, SSL_AEAD_CTX *aead_ctx) { - if (SSL_IS_DTLS(ssl)) { - ssl->d1->r_epoch++; - memset(&ssl->d1->bitmap, 0, sizeof(ssl->d1->bitmap)); +enum ssl_open_record_t ssl_process_alert(SSL *ssl, uint8_t *out_alert, + const uint8_t *in, size_t in_len) { + /* Alerts records may not contain fragmented or multiple alerts. */ + if (in_len != 2) { + *out_alert = SSL_AD_DECODE_ERROR; + OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ALERT); + return ssl_open_record_error; } - memset(ssl->s3->read_sequence, 0, sizeof(ssl->s3->read_sequence)); - SSL_AEAD_CTX_free(ssl->s3->aead_read_ctx); - ssl->s3->aead_read_ctx = aead_ctx; -} + ssl_do_msg_callback(ssl, 0 /* read */, SSL3_RT_ALERT, in, in_len); + + const uint8_t alert_level = in[0]; + const uint8_t alert_descr = in[1]; + + uint16_t alert = (alert_level << 8) | alert_descr; + ssl_do_info_callback(ssl, SSL_CB_READ_ALERT, alert); + + if (alert_level == SSL3_AL_WARNING) { + if (alert_descr == SSL_AD_CLOSE_NOTIFY) { + ssl->s3->recv_shutdown = ssl_shutdown_close_notify; + return ssl_open_record_close_notify; + } + + /* Warning alerts do not exist in TLS 1.3. */ + if (ssl->s3->have_version && + ssl3_protocol_version(ssl) >= TLS1_3_VERSION) { + *out_alert = SSL_AD_DECODE_ERROR; + OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ALERT); + return ssl_open_record_error; + } + + ssl->s3->warning_alert_count++; + if (ssl->s3->warning_alert_count > kMaxWarningAlerts) { + *out_alert = SSL_AD_UNEXPECTED_MESSAGE; + OPENSSL_PUT_ERROR(SSL, SSL_R_TOO_MANY_WARNING_ALERTS); + return ssl_open_record_error; + } + return ssl_open_record_discard; + } + + if (alert_level == SSL3_AL_FATAL) { + ssl->s3->recv_shutdown = ssl_shutdown_fatal_alert; -void ssl_set_write_state(SSL *ssl, SSL_AEAD_CTX *aead_ctx) { - if (SSL_IS_DTLS(ssl)) { - ssl->d1->w_epoch++; - memcpy(ssl->d1->last_write_sequence, ssl->s3->write_sequence, - sizeof(ssl->s3->write_sequence)); + char tmp[16]; + OPENSSL_PUT_ERROR(SSL, SSL_AD_REASON_OFFSET + alert_descr); + BIO_snprintf(tmp, sizeof(tmp), "%d", alert_descr); + ERR_add_error_data(2, "SSL alert number ", tmp); + return ssl_open_record_fatal_alert; } - memset(ssl->s3->write_sequence, 0, sizeof(ssl->s3->write_sequence)); - SSL_AEAD_CTX_free(ssl->s3->aead_write_ctx); - ssl->s3->aead_write_ctx = aead_ctx; + *out_alert = SSL_AD_ILLEGAL_PARAMETER; + OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_ALERT_TYPE); + return ssl_open_record_error; } diff --git a/Sources/CgRPC/grpc/byte_buffer.h b/Sources/CgRPC/grpc/byte_buffer.h index 395ebef74..55e191da3 100644 --- a/Sources/CgRPC/grpc/byte_buffer.h +++ b/Sources/CgRPC/grpc/byte_buffer.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/grpc/byte_buffer_reader.h b/Sources/CgRPC/grpc/byte_buffer_reader.h index e95bf2f80..6bd078478 100644 --- a/Sources/CgRPC/grpc/byte_buffer_reader.h +++ b/Sources/CgRPC/grpc/byte_buffer_reader.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/grpc/census.h b/Sources/CgRPC/grpc/census.h index 62ff45d89..de8e7a661 100644 --- a/Sources/CgRPC/grpc/census.h +++ b/Sources/CgRPC/grpc/census.h @@ -1,37 +1,22 @@ /* * - * Copyright 2015-2016, Google Inc. - * All rights reserved. + * Copyright 2015-2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ -/* RPC-internal Census API's. These are designed to be generic enough that +/** RPC-internal Census API's. These are designed to be generic enough that * they can (ultimately) be used in many different RPC systems (with differing * implementations). */ @@ -44,12 +29,12 @@ extern "C" { #endif -/* Identify census features that can be enabled via census_initialize(). */ +/** Identify census features that can be enabled via census_initialize(). */ enum census_features { - CENSUS_FEATURE_NONE = 0, /* Do not enable census. */ - CENSUS_FEATURE_TRACING = 1, /* Enable census tracing. */ - CENSUS_FEATURE_STATS = 2, /* Enable Census stats collection. */ - CENSUS_FEATURE_CPU = 4, /* Enable Census CPU usage collection. */ + CENSUS_FEATURE_NONE = 0, /** Do not enable census. */ + CENSUS_FEATURE_TRACING = 1, /** Enable census tracing. */ + CENSUS_FEATURE_STATS = 2, /** Enable Census stats collection. */ + CENSUS_FEATURE_CPU = 4, /** Enable Census CPU usage collection. */ CENSUS_FEATURE_ALL = CENSUS_FEATURE_TRACING | CENSUS_FEATURE_STATS | CENSUS_FEATURE_CPU }; @@ -82,7 +67,7 @@ CENSUSAPI int census_enabled(void); metrics will be recorded. Keys are unique within a context. */ typedef struct census_context census_context; -/* A tag is a key:value pair. Both keys and values are nil-terminated strings, +/** A tag is a key:value pair. Both keys and values are nil-terminated strings, containing printable ASCII characters (decimal 32-126). Keys must be at least one character in length. Both keys and values can have at most CENSUS_MAX_TAG_KB_LEN characters (including the terminating nil). The @@ -97,36 +82,36 @@ typedef struct { uint8_t flags; } census_tag; -/* Maximum length of a tag's key or value. */ +/** Maximum length of a tag's key or value. */ #define CENSUS_MAX_TAG_KV_LEN 255 -/* Maximum number of propagatable tags. */ +/** Maximum number of propagatable tags. */ #define CENSUS_MAX_PROPAGATED_TAGS 255 -/* Tag flags. */ -#define CENSUS_TAG_PROPAGATE 1 /* Tag should be propagated over RPC */ -#define CENSUS_TAG_STATS 2 /* Tag will be used for statistics aggregation */ -#define CENSUS_TAG_RESERVED 4 /* Reserved for internal use. */ -/* Flag values 4,8,16,32,64,128 are reserved for future/internal use. Clients +/** Tag flags. */ +#define CENSUS_TAG_PROPAGATE 1 /** Tag should be propagated over RPC */ +#define CENSUS_TAG_STATS 2 /** Tag will be used for statistics aggregation */ +#define CENSUS_TAG_RESERVED 4 /** Reserved for internal use. */ +/** Flag values 4,8,16,32,64,128 are reserved for future/internal use. Clients should not use or rely on their values. */ #define CENSUS_TAG_IS_PROPAGATED(flags) (flags & CENSUS_TAG_PROPAGATE) #define CENSUS_TAG_IS_STATS(flags) (flags & CENSUS_TAG_STATS) -/* An instance of this structure is kept by every context, and records the +/** An instance of this structure is kept by every context, and records the basic information associated with the creation of that context. */ typedef struct { - int n_propagated_tags; /* number of propagated tags */ - int n_local_tags; /* number of non-propagated (local) tags */ - int n_deleted_tags; /* number of tags that were deleted */ - int n_added_tags; /* number of tags that were added */ - int n_modified_tags; /* number of tags that were modified */ - int n_invalid_tags; /* number of tags with bad keys or values (e.g. + int n_propagated_tags; /** number of propagated tags */ + int n_local_tags; /** number of non-propagated (local) tags */ + int n_deleted_tags; /** number of tags that were deleted */ + int n_added_tags; /** number of tags that were added */ + int n_modified_tags; /** number of tags that were modified */ + int n_invalid_tags; /** number of tags with bad keys or values (e.g. longer than CENSUS_MAX_TAG_KV_LEN) */ - int n_ignored_tags; /* number of tags ignored because of + int n_ignored_tags; /** number of tags ignored because of CENSUS_MAX_PROPAGATED_TAGS limit. */ } census_context_status; -/* Create a new context, adding and removing tags from an existing context. +/** Create a new context, adding and removing tags from an existing context. This will copy all tags from the 'tags' input, so it is recommended to add as many tags in a single operation as is practical for the client. @param base Base context to build upon. Can be NULL. @@ -148,15 +133,15 @@ CENSUSAPI census_context *census_context_create( const census_context *base, const census_tag *tags, int ntags, census_context_status const **status); -/* Destroy a context. Once this function has been called, the context cannot +/** Destroy a context. Once this function has been called, the context cannot be reused. */ CENSUSAPI void census_context_destroy(census_context *context); -/* Get a pointer to the original status from the context creation. */ +/** Get a pointer to the original status from the context creation. */ CENSUSAPI const census_context_status *census_context_get_status( const census_context *context); -/* Structure used for iterating over the tegs in a context. API clients should +/** Structure used for iterating over the tags in a context. API clients should not use or reference internal fields - neither their contents or presence/absence are guaranteed. */ typedef struct { @@ -166,25 +151,25 @@ typedef struct { char *kvm; } census_context_iterator; -/* Initialize a census_tag_iterator. Must be called before first use. */ +/** Initialize a census_tag_iterator. Must be called before first use. */ CENSUSAPI void census_context_initialize_iterator( const census_context *context, census_context_iterator *iterator); -/* Get the contents of the "next" tag in the context. If there are no more +/** Get the contents of the "next" tag in the context. If there are no more tags, returns 0 (and 'tag' contents will be unchanged), otherwise returns 1. */ CENSUSAPI int census_context_next_tag(census_context_iterator *iterator, census_tag *tag); -/* Get a context tag by key. Returns 0 if the key is not present. */ +/** Get a context tag by key. Returns 0 if the key is not present. */ CENSUSAPI int census_context_get_tag(const census_context *context, const char *key, census_tag *tag); -/* Tag set encode/decode functionality. These functionas are intended +/** Tag set encode/decode functionality. These functions are intended for use by RPC systems only, for purposes of transmitting/receiving contexts. */ -/* Encode a context into a buffer. +/** Encode a context into a buffer. @param context context to be encoded @param buffer buffer into which the context will be encoded. @param buf_size number of available bytes in buffer. @@ -193,26 +178,26 @@ CENSUSAPI int census_context_get_tag(const census_context *context, CENSUSAPI size_t census_context_encode(const census_context *context, char *buffer, size_t buf_size); -/* Decode context buffer encoded with census_context_encode(). Returns NULL +/** Decode context buffer encoded with census_context_encode(). Returns NULL if there is an error in parsing either buffer. */ CENSUSAPI census_context *census_context_decode(const char *buffer, size_t size); -/* Distributed traces can have a number of options. */ +/** Distributed traces can have a number of options. */ enum census_trace_mask_values { - CENSUS_TRACE_MASK_NONE = 0, /* Default, empty flags */ - CENSUS_TRACE_MASK_IS_SAMPLED = 1 /* RPC tracing enabled for this context. */ + CENSUS_TRACE_MASK_NONE = 0, /** Default, empty flags */ + CENSUS_TRACE_MASK_IS_SAMPLED = 1 /** RPC tracing enabled for this context. */ }; /** Get the current trace mask associated with this context. The value returned - will be the logical or of census_trace_mask_values values. */ + will be the logical OR of census_trace_mask_values values. */ CENSUSAPI int census_trace_mask(const census_context *context); /** Set the trace mask associated with a context. */ CENSUSAPI void census_set_trace_mask(int trace_mask); -/* The concept of "operation" is a fundamental concept for Census. In an RPC - system, and operation typcially represents a single RPC, or a significant +/** The concept of "operation" is a fundamental concept for Census. In an RPC + system, an operation typically represents a single RPC, or a significant sub-part thereof (e.g. a single logical "read" RPC to a distributed storage system might do several other actions in parallel, from looking up metadata indices to making requests of other services - each of these could be a @@ -238,7 +223,7 @@ CENSUSAPI void census_set_trace_mask(int trace_mask); at which an operation begins. */ typedef struct { - /* Use gpr_timespec for default implementation. High performance + /** Use gpr_timespec for default implementation. High performance * implementations should use a cycle-counter based timestamp. */ gpr_timespec ts; } census_timestamp; @@ -362,7 +347,7 @@ CENSUSAPI census_context *census_start_server_rpc_op( @param context The base context. Can be NULL. @param family Family name to associate with the trace - @param name Name within family to associated with traces/stats + @param name Name within family to associate with traces/stats @param trace_mask An OR of census_trace_mask_values values. Only used if context is NULL. @@ -398,12 +383,12 @@ CENSUSAPI void census_trace_print(census_context *context, uint32_t type, /** Trace record. */ typedef struct { - census_timestamp timestamp; /* Time of record creation */ - uint64_t trace_id; /* Trace ID associated with record */ - uint64_t op_id; /* Operation ID associated with record */ - uint32_t type; /* Type (as used in census_trace_print() */ - const char *buffer; /* Buffer (from census_trace_print() */ - size_t buf_size; /* Number of bytes inside buffer */ + census_timestamp timestamp; /** Time of record creation */ + uint64_t trace_id; /** Trace ID associated with record */ + uint64_t op_id; /** Operation ID associated with record */ + uint32_t type; /** Type (as used in census_trace_print() */ + const char *buffer; /** Buffer (from census_trace_print() */ + size_t buf_size; /** Number of bytes inside buffer */ } census_trace_record; /** Start a scan of existing trace records. While a scan is ongoing, addition @@ -431,7 +416,7 @@ CENSUSAPI int census_get_trace_record(census_trace_record *trace_record); /** End a scan previously started by census_trace_scan_start() */ CENSUSAPI void census_trace_scan_end(); -/* Core stats collection API's. The following concepts are used: +/** Core stats collection API's. The following concepts are used: * Resource: Users record measurements for a single resource. Examples include RPC latency, CPU seconds consumed, and bytes transmitted. * Aggregation: An aggregation of a set of measurements. Census supports the @@ -450,30 +435,30 @@ CENSUSAPI void census_trace_scan_end(); implementations. The proto definitions can be found in src/proto/census. */ -/* Define a new resource. `resource_pb` should contain an encoded Resource +/** Define a new resource. `resource_pb` should contain an encoded Resource protobuf, `resource_pb_size` being the size of the buffer. Returns a -ve value on error, or a positive (>= 0) resource id (for use in census_delete_resource() and census_record_values()). In order to be valid, a - resource must have a name, and at least one numerator in it's unit type. The + resource must have a name, and at least one numerator in its unit type. The resource name must be unique, and an error will be returned if it is not. */ CENSUSAPI int32_t census_define_resource(const uint8_t *resource_pb, size_t resource_pb_size); -/* Delete a resource created by census_define_resource(). */ +/** Delete a resource created by census_define_resource(). */ CENSUSAPI void census_delete_resource(int32_t resource_id); -/* Determine the id of a resource, given it's name. returns -1 if the resource +/** Determine the id of a resource, given its name. returns -1 if the resource does not exist. */ CENSUSAPI int32_t census_resource_id(const char *name); -/* A single value to be recorded comprises two parts: an ID for the particular +/** A single value to be recorded comprises two parts: an ID for the particular * resource and the value to be recorded against it. */ typedef struct { int32_t resource_id; double value; } census_value; -/* Record new usage values against the given context. */ +/** Record new usage values against the given context. */ CENSUSAPI void census_record_values(census_context *context, census_value *values, size_t nvalues); diff --git a/Sources/CgRPC/grpc/compression.h b/Sources/CgRPC/grpc/compression.h index 5f285cdcd..d47074c9b 100644 --- a/Sources/CgRPC/grpc/compression.h +++ b/Sources/CgRPC/grpc/compression.h @@ -1,44 +1,30 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 GRPC_COMPRESSION_H #define GRPC_COMPRESSION_H -#include - #include +#include + #include +#include #ifdef __cplusplus extern "C" { @@ -48,8 +34,7 @@ extern "C" { * grpc_compression_algorithm instance, updating \a algorithm. Returns 1 upon * success, 0 otherwise. */ GRPCAPI int grpc_compression_algorithm_parse( - const char *name, size_t name_length, - grpc_compression_algorithm *algorithm); + grpc_slice value, grpc_compression_algorithm *algorithm); /** Updates \a name with the encoding name corresponding to a valid \a * algorithm. Note that \a name is statically allocated and must *not* be freed. diff --git a/Sources/CgRPC/grpc/grpc.h b/Sources/CgRPC/grpc/grpc.h index 898f4d533..943d6e489 100644 --- a/Sources/CgRPC/grpc/grpc.h +++ b/Sources/CgRPC/grpc/grpc.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015-2016, Google Inc. - * All rights reserved. + * Copyright 2015-2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -93,8 +78,26 @@ GRPCAPI const char *grpc_version_string(void); /** Return a string specifying what the 'g' in gRPC stands for */ GRPCAPI const char *grpc_g_stands_for(void); +/** Returns the completion queue factory based on the attributes. MAY return a + NULL if no factory can be found */ +GRPCAPI const grpc_completion_queue_factory * +grpc_completion_queue_factory_lookup( + const grpc_completion_queue_attributes *attributes); + +/** Helper function to create a completion queue with grpc_cq_completion_type + of GRPC_CQ_NEXT and grpc_cq_polling_type of GRPC_CQ_DEFAULT_POLLING */ +GRPCAPI grpc_completion_queue *grpc_completion_queue_create_for_next( + void *reserved); + +/** Helper function to create a completion queue with grpc_cq_completion_type + of GRPC_CQ_PLUCK and grpc_cq_polling_type of GRPC_CQ_DEFAULT_POLLING */ +GRPCAPI grpc_completion_queue *grpc_completion_queue_create_for_pluck( + void *reserved); + /** Create a completion queue */ -GRPCAPI grpc_completion_queue *grpc_completion_queue_create(void *reserved); +GRPCAPI grpc_completion_queue *grpc_completion_queue_create( + const grpc_completion_queue_factory *factory, + const grpc_completion_queue_attributes *attributes, void *reserved); /** Blocks until an event is available, the completion queue is being shut down, or deadline is reached. @@ -160,6 +163,12 @@ GRPCAPI void grpc_alarm_destroy(grpc_alarm *alarm); GRPCAPI grpc_connectivity_state grpc_channel_check_connectivity_state( grpc_channel *channel, int try_to_connect); +/** Number of active "external connectivity state watchers" attached to a + * channel. + * Useful for testing. **/ +GRPCAPI int grpc_channel_num_external_connectivity_watchers( + grpc_channel *channel); + /** Watch for a change in connectivity state. Once the channel connectivity state is different from last_observed_state, tag will be enqueued on cq with success=1. @@ -178,8 +187,8 @@ GRPCAPI void grpc_channel_watch_connectivity_state( possible values). */ GRPCAPI grpc_call *grpc_channel_create_call( grpc_channel *channel, grpc_call *parent_call, uint32_t propagation_mask, - grpc_completion_queue *completion_queue, const char *method, - const char *host, gpr_timespec deadline, void *reserved); + grpc_completion_queue *completion_queue, grpc_slice method, + const grpc_slice *host, gpr_timespec deadline, void *reserved); /** Ping the channels peer (load balanced channels will select one sub-channel to ping); if the channel is not connected, posts a failed. */ @@ -198,6 +207,10 @@ GRPCAPI grpc_call *grpc_channel_create_registered_call( grpc_completion_queue *completion_queue, void *registered_call_handle, gpr_timespec deadline, void *reserved); +/** Allocate memory in the grpc_call arena: this memory is automatically + discarded at call completion */ +GRPCAPI void *grpc_call_arena_alloc(grpc_call *call, size_t size); + /** Start a batch of operations defined in the array ops; when complete, post a completion of type 'tag' to the completion queue bound to the call. The order of ops specified in the batch has no significance. @@ -231,12 +244,12 @@ GRPCAPI char *grpc_call_get_peer(grpc_call *call); struct census_context; -/* Set census context for a call; Must be called before first call to +/** Set census context for a call; Must be called before first call to grpc_call_start_batch(). */ GRPCAPI void grpc_census_call_set_context(grpc_call *call, struct census_context *context); -/* Retrieve the calls current census context. */ +/** Retrieve the calls current census context. */ GRPCAPI struct census_context *grpc_census_call_get_context(grpc_call *call); /** Return a newly allocated string representing the target a channel was @@ -265,7 +278,7 @@ GRPCAPI grpc_channel *grpc_lame_client_channel_create( /** Close and destroy a grpc channel */ GRPCAPI void grpc_channel_destroy(grpc_channel *channel); -/* Error handling for grpc_call +/** Error handling for grpc_call Most grpc_call functions return a grpc_error. If the error is not GRPC_OK then the operation failed due to some unsatisfied precondition. If a grpc_call fails, it's guaranteed that no change to the call state @@ -274,7 +287,7 @@ GRPCAPI void grpc_channel_destroy(grpc_channel *channel); /** Called by clients to cancel an RPC on the server. Can be called multiple times, from any thread. THREAD-SAFETY grpc_call_cancel and grpc_call_cancel_with_status - are thread-safe, and can be called at any point before grpc_call_destroy + are thread-safe, and can be called at any point before grpc_call_unref is called.*/ GRPCAPI grpc_call_error grpc_call_cancel(grpc_call *call, void *reserved); @@ -283,15 +296,23 @@ GRPCAPI grpc_call_error grpc_call_cancel(grpc_call *call, void *reserved); If a status has not been received for the call, set it to the status code and description passed in. Importantly, this function does not send status nor description to the - remote endpoint. */ + remote endpoint. + Note that \a description doesn't need be a static string. + It doesn't need to be alive after the call to + grpc_call_cancel_with_status completes. + */ GRPCAPI grpc_call_error grpc_call_cancel_with_status(grpc_call *call, grpc_status_code status, const char *description, void *reserved); -/** Destroy a call. - THREAD SAFETY: grpc_call_destroy is thread-compatible */ -GRPCAPI void grpc_call_destroy(grpc_call *call); +/** Ref a call. + THREAD SAFETY: grpc_call_unref is thread-compatible */ +GRPCAPI void grpc_call_ref(grpc_call *call); + +/** Unref a call. + THREAD SAFETY: grpc_call_unref is thread-compatible */ +GRPCAPI void grpc_call_unref(grpc_call *call); /** Request notification of a new call. Once a call is received, a notification tagged with \a tag_new is added to @@ -352,15 +373,6 @@ GRPCAPI void grpc_server_register_completion_queue(grpc_server *server, grpc_completion_queue *cq, void *reserved); -/** Register a non-listening completion queue with the server. This API is - similar to grpc_server_register_completion_queue except that the server will - not use this completion_queue to listen to any incoming channels. - - Registering a non-listening completion queue will have negative performance - impact and hence this API is not recommended for production use cases. */ -GRPCAPI void grpc_server_register_non_listening_completion_queue( - grpc_server *server, grpc_completion_queue *q, void *reserved); - /** Add a HTTP2 over plaintext over tcp listener. Returns bound port number on success, 0 on failure. REQUIRES: server not started */ @@ -402,14 +414,14 @@ GRPCAPI void grpc_server_destroy(grpc_server *server); GRPCAPI int grpc_tracer_set_enabled(const char *name, int enabled); /** Check whether a metadata key is legal (will be accepted by core) */ -GRPCAPI int grpc_header_key_is_legal(const char *key, size_t length); +GRPCAPI int grpc_header_key_is_legal(grpc_slice slice); /** Check whether a non-binary metadata value is legal (will be accepted by core) */ -GRPCAPI int grpc_header_nonbin_value_is_legal(const char *value, size_t length); +GRPCAPI int grpc_header_nonbin_value_is_legal(grpc_slice slice); /** Check whether a metadata key corresponds to a binary value */ -GRPCAPI int grpc_is_binary_header(const char *key, size_t length); +GRPCAPI int grpc_is_binary_header(grpc_slice slice); /** Convert grpc_call_error values to a string */ GRPCAPI const char *grpc_call_error_to_string(grpc_call_error error); diff --git a/Sources/CgRPC/grpc/grpc_posix.h b/Sources/CgRPC/grpc/grpc_posix.h index a8c031548..c7429eaea 100644 --- a/Sources/CgRPC/grpc/grpc_posix.h +++ b/Sources/CgRPC/grpc/grpc_posix.h @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/grpc/grpc_security.h b/Sources/CgRPC/grpc/grpc_security.h index 79199cc5d..2005e25df 100644 --- a/Sources/CgRPC/grpc/grpc_security.h +++ b/Sources/CgRPC/grpc/grpc_security.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -42,7 +27,7 @@ extern "C" { #endif -/* --- Authentication Context. --- */ +/** --- Authentication Context. --- */ typedef struct grpc_auth_context grpc_auth_context; @@ -52,84 +37,84 @@ typedef struct grpc_auth_property_iterator { const char *name; } grpc_auth_property_iterator; -/* value, if not NULL, is guaranteed to be NULL terminated. */ +/** value, if not NULL, is guaranteed to be NULL terminated. */ typedef struct grpc_auth_property { char *name; char *value; size_t value_length; } grpc_auth_property; -/* Returns NULL when the iterator is at the end. */ +/** Returns NULL when the iterator is at the end. */ GRPCAPI const grpc_auth_property *grpc_auth_property_iterator_next( grpc_auth_property_iterator *it); -/* Iterates over the auth context. */ +/** Iterates over the auth context. */ GRPCAPI grpc_auth_property_iterator grpc_auth_context_property_iterator(const grpc_auth_context *ctx); -/* Gets the peer identity. Returns an empty iterator (first _next will return +/** Gets the peer identity. Returns an empty iterator (first _next will return NULL) if the peer is not authenticated. */ GRPCAPI grpc_auth_property_iterator grpc_auth_context_peer_identity(const grpc_auth_context *ctx); -/* Finds a property in the context. May return an empty iterator (first _next +/** Finds a property in the context. May return an empty iterator (first _next will return NULL) if no property with this name was found in the context. */ GRPCAPI grpc_auth_property_iterator grpc_auth_context_find_properties_by_name( const grpc_auth_context *ctx, const char *name); -/* Gets the name of the property that indicates the peer identity. Will return +/** Gets the name of the property that indicates the peer identity. Will return NULL if the peer is not authenticated. */ GRPCAPI const char *grpc_auth_context_peer_identity_property_name( const grpc_auth_context *ctx); -/* Returns 1 if the peer is authenticated, 0 otherwise. */ +/** Returns 1 if the peer is authenticated, 0 otherwise. */ GRPCAPI int grpc_auth_context_peer_is_authenticated( const grpc_auth_context *ctx); -/* Gets the auth context from the call. Caller needs to call +/** Gets the auth context from the call. Caller needs to call grpc_auth_context_release on the returned context. */ GRPCAPI grpc_auth_context *grpc_call_auth_context(grpc_call *call); -/* Releases the auth context returned from grpc_call_auth_context. */ +/** Releases the auth context returned from grpc_call_auth_context. */ GRPCAPI void grpc_auth_context_release(grpc_auth_context *context); -/* -- +/** -- The following auth context methods should only be called by a server metadata processor to set properties extracted from auth metadata. -- */ -/* Add a property. */ +/** Add a property. */ GRPCAPI void grpc_auth_context_add_property(grpc_auth_context *ctx, const char *name, const char *value, size_t value_length); -/* Add a C string property. */ +/** Add a C string property. */ GRPCAPI void grpc_auth_context_add_cstring_property(grpc_auth_context *ctx, const char *name, const char *value); -/* Sets the property name. Returns 1 if successful or 0 in case of failure +/** Sets the property name. Returns 1 if successful or 0 in case of failure (which means that no property with this name exists). */ GRPCAPI int grpc_auth_context_set_peer_identity_property_name( grpc_auth_context *ctx, const char *name); -/* --- grpc_channel_credentials object. --- +/** --- grpc_channel_credentials object. --- A channel credentials object represents a way to authenticate a client on a channel. */ typedef struct grpc_channel_credentials grpc_channel_credentials; -/* Releases a channel credentials object. +/** Releases a channel credentials object. The creator of the credentials object is responsible for its release. */ GRPCAPI void grpc_channel_credentials_release(grpc_channel_credentials *creds); -/* Creates default credentials to connect to a google gRPC service. +/** Creates default credentials to connect to a google gRPC service. WARNING: Do NOT use this credentials to connect to a non-google service as this could result in an oauth2 token leak. */ GRPCAPI grpc_channel_credentials *grpc_google_default_credentials_create(void); -/* Callback for getting the SSL roots override from the application. +/** Callback for getting the SSL roots override from the application. In case of success, *pem_roots_certs must be set to a NULL terminated string containing the list of PEM encoded root certificates. The ownership is passed to the core and freed (laster by the core) with gpr_free. @@ -138,7 +123,7 @@ GRPCAPI grpc_channel_credentials *grpc_google_default_credentials_create(void); typedef grpc_ssl_roots_override_result (*grpc_ssl_roots_override_callback)( char **pem_root_certs); -/* Setup a callback to override the default TLS/SSL roots. +/** Setup a callback to override the default TLS/SSL roots. This function is not thread-safe and must be called at initialization time before any ssl credentials are created to have the desired side effect. If GRPC_DEFAULT_SSL_ROOTS_FILE_PATH environment is set to a valid path, the @@ -146,19 +131,19 @@ typedef grpc_ssl_roots_override_result (*grpc_ssl_roots_override_callback)( GRPCAPI void grpc_set_ssl_roots_override_callback( grpc_ssl_roots_override_callback cb); -/* Object that holds a private key / certificate chain pair in PEM format. */ +/** Object that holds a private key / certificate chain pair in PEM format. */ typedef struct { - /* private_key is the NULL-terminated string containing the PEM encoding of + /** private_key is the NULL-terminated string containing the PEM encoding of the client's private key. */ const char *private_key; - /* cert_chain is the NULL-terminated string containing the PEM encoding of + /** cert_chain is the NULL-terminated string containing the PEM encoding of the client's certificate chain. */ const char *cert_chain; } grpc_ssl_pem_key_cert_pair; -/* Creates an SSL credentials object. - - pem_roots_cert is the NULL-terminated string containing the PEM encoding +/** Creates an SSL credentials object. + - pem_root_certs is the NULL-terminated string containing the PEM encoding of the server root certificates. If this parameter is NULL, the implementation will first try to dereference the file pointed by the GRPC_DEFAULT_SSL_ROOTS_FILE_PATH environment variable, and if that fails, @@ -172,7 +157,7 @@ GRPCAPI grpc_channel_credentials *grpc_ssl_credentials_create( const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pair, void *reserved); -/* --- grpc_call_credentials object. +/** --- grpc_call_credentials object. A call credentials object represents a way to authenticate on a particular call. These credentials can be composed with a channel credentials object @@ -180,21 +165,21 @@ GRPCAPI grpc_channel_credentials *grpc_ssl_credentials_create( typedef struct grpc_call_credentials grpc_call_credentials; -/* Releases a call credentials object. +/** Releases a call credentials object. The creator of the credentials object is responsible for its release. */ GRPCAPI void grpc_call_credentials_release(grpc_call_credentials *creds); -/* Creates a composite channel credentials object. */ +/** Creates a composite channel credentials object. */ GRPCAPI grpc_channel_credentials *grpc_composite_channel_credentials_create( grpc_channel_credentials *channel_creds, grpc_call_credentials *call_creds, void *reserved); -/* Creates a composite call credentials object. */ +/** Creates a composite call credentials object. */ GRPCAPI grpc_call_credentials *grpc_composite_call_credentials_create( grpc_call_credentials *creds1, grpc_call_credentials *creds2, void *reserved); -/* Creates a compute engine credentials object for connecting to Google. +/** Creates a compute engine credentials object for connecting to Google. WARNING: Do NOT use this credentials to connect to a non-google service as this could result in an oauth2 token leak. */ GRPCAPI grpc_call_credentials *grpc_google_compute_engine_credentials_create( @@ -202,7 +187,7 @@ GRPCAPI grpc_call_credentials *grpc_google_compute_engine_credentials_create( GRPCAPI gpr_timespec grpc_max_auth_token_lifetime(); -/* Creates a JWT credentials object. May return NULL if the input is invalid. +/** Creates a JWT credentials object. May return NULL if the input is invalid. - json_key is the JSON key string containing the client's private key. - token_lifetime is the lifetime of each Json Web Token (JWT) created with this credentials. It should not exceed grpc_max_auth_token_lifetime or @@ -212,7 +197,7 @@ grpc_service_account_jwt_access_credentials_create(const char *json_key, gpr_timespec token_lifetime, void *reserved); -/* Creates an Oauth2 Refresh Token credentials object for connecting to Google. +/** Creates an Oauth2 Refresh Token credentials object for connecting to Google. May return NULL if the input is invalid. WARNING: Do NOT use this credentials to connect to a non-google service as this could result in an oauth2 token leak. @@ -221,17 +206,17 @@ grpc_service_account_jwt_access_credentials_create(const char *json_key, GRPCAPI grpc_call_credentials *grpc_google_refresh_token_credentials_create( const char *json_refresh_token, void *reserved); -/* Creates an Oauth2 Access Token credentials with an access token that was +/** Creates an Oauth2 Access Token credentials with an access token that was aquired by an out of band mechanism. */ GRPCAPI grpc_call_credentials *grpc_access_token_credentials_create( const char *access_token, void *reserved); -/* Creates an IAM credentials object for connecting to Google. */ +/** Creates an IAM credentials object for connecting to Google. */ GRPCAPI grpc_call_credentials *grpc_google_iam_credentials_create( const char *authorization_token, const char *authority_selector, void *reserved); -/* Callback function to be called by the metadata credentials plugin +/** Callback function to be called by the metadata credentials plugin implementation when the metadata is ready. - user_data is the opaque pointer that was passed in the get_metadata method of the grpc_metadata_credentials_plugin (see below). @@ -246,31 +231,31 @@ typedef void (*grpc_credentials_plugin_metadata_cb)( void *user_data, const grpc_metadata *creds_md, size_t num_creds_md, grpc_status_code status, const char *error_details); -/* Context that can be used by metadata credentials plugin in order to create +/** Context that can be used by metadata credentials plugin in order to create auth related metadata. */ typedef struct { - /* The fully qualifed service url. */ + /** The fully qualifed service url. */ const char *service_url; - /* The method name of the RPC being called (not fully qualified). + /** The method name of the RPC being called (not fully qualified). The fully qualified method name can be built from the service_url: full_qualified_method_name = ctx->service_url + '/' + ctx->method_name. */ const char *method_name; - /* The auth_context of the channel which gives the server's identity. */ + /** The auth_context of the channel which gives the server's identity. */ const grpc_auth_context *channel_auth_context; - /* Reserved for future use. */ + /** Reserved for future use. */ void *reserved; } grpc_auth_metadata_context; -/* grpc_metadata_credentials plugin is an API user provided structure used to +/** grpc_metadata_credentials plugin is an API user provided structure used to create grpc_credentials objects that can be set on a channel (composed) or a call. See grpc_credentials_metadata_create_from_plugin below. The grpc client stack will call the get_metadata method of the plugin for every call in scope for the credentials created from it. */ typedef struct { - /* The implementation of this method has to be non-blocking. + /** The implementation of this method has to be non-blocking. - context is the information that can be used by the plugin to create auth metadata. - cb is the callback that needs to be called when the metadata is ready. @@ -278,39 +263,39 @@ typedef struct { void (*get_metadata)(void *state, grpc_auth_metadata_context context, grpc_credentials_plugin_metadata_cb cb, void *user_data); - /* Destroys the plugin state. */ + /** Destroys the plugin state. */ void (*destroy)(void *state); - /* State that will be set as the first parameter of the methods above. */ + /** State that will be set as the first parameter of the methods above. */ void *state; - /* Type of credentials that this plugin is implementing. */ + /** Type of credentials that this plugin is implementing. */ const char *type; } grpc_metadata_credentials_plugin; -/* Creates a credentials object from a plugin. */ +/** Creates a credentials object from a plugin. */ GRPCAPI grpc_call_credentials *grpc_metadata_credentials_create_from_plugin( grpc_metadata_credentials_plugin plugin, void *reserved); -/* --- Secure channel creation. --- */ +/** --- Secure channel creation. --- */ -/* Creates a secure channel using the passed-in credentials. */ +/** Creates a secure channel using the passed-in credentials. */ GRPCAPI grpc_channel *grpc_secure_channel_create( grpc_channel_credentials *creds, const char *target, const grpc_channel_args *args, void *reserved); -/* --- grpc_server_credentials object. --- +/** --- grpc_server_credentials object. --- A server credentials object represents a way to authenticate a server. */ typedef struct grpc_server_credentials grpc_server_credentials; -/* Releases a server_credentials object. +/** Releases a server_credentials object. The creator of the server_credentials object is responsible for its release. */ GRPCAPI void grpc_server_credentials_release(grpc_server_credentials *creds); -/* Deprecated in favor of grpc_ssl_server_credentials_create_ex. +/** Deprecated in favor of grpc_ssl_server_credentials_create_ex. Creates an SSL server_credentials object. - pem_roots_cert is the NULL-terminated string containing the PEM encoding of the client root certificates. This parameter may be NULL if the server does @@ -326,7 +311,7 @@ GRPCAPI grpc_server_credentials *grpc_ssl_server_credentials_create( const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pairs, size_t num_key_cert_pairs, int force_client_auth, void *reserved); -/* Same as grpc_ssl_server_credentials_create method except uses +/** Same as grpc_ssl_server_credentials_create method except uses grpc_ssl_client_certificate_request_type enum to support more ways to authenticate client cerificates.*/ GRPCAPI grpc_server_credentials *grpc_ssl_server_credentials_create_ex( @@ -335,25 +320,25 @@ GRPCAPI grpc_server_credentials *grpc_ssl_server_credentials_create_ex( grpc_ssl_client_certificate_request_type client_certificate_request, void *reserved); -/* --- Server-side secure ports. --- */ +/** --- Server-side secure ports. --- */ -/* Add a HTTP2 over an encrypted link over tcp listener. +/** Add a HTTP2 over an encrypted link over tcp listener. Returns bound port number on success, 0 on failure. REQUIRES: server not started */ GRPCAPI int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr, grpc_server_credentials *creds); -/* --- Call specific credentials. --- */ +/** --- Call specific credentials. --- */ -/* Sets a credentials to a call. Can only be called on the client side before +/** Sets a credentials to a call. Can only be called on the client side before grpc_call_start_batch. */ GRPCAPI grpc_call_error grpc_call_set_credentials(grpc_call *call, grpc_call_credentials *creds); -/* --- Auth Metadata Processing --- */ +/** --- Auth Metadata Processing --- */ -/* Callback function that is called when the metadata processing is done. +/** Callback function that is called when the metadata processing is done. - Consumed metadata will be removed from the set of metadata available on the call. consumed_md may be NULL if no metadata has been consumed. - Response metadata will be set on the response. response_md may be NULL. @@ -367,9 +352,9 @@ typedef void (*grpc_process_auth_metadata_done_cb)( const grpc_metadata *response_md, size_t num_response_md, grpc_status_code status, const char *error_details); -/* Pluggable server-side metadata processor object. */ +/** Pluggable server-side metadata processor object. */ typedef struct { - /* The context object is read/write: it contains the properties of the + /** The context object is read/write: it contains the properties of the channel peer and it is the job of the process function to augment it with properties derived from the passed-in metadata. The lifetime of these objects is guaranteed until cb is invoked. */ diff --git a/Sources/CgRPC/grpc/grpc_security_constants.h b/Sources/CgRPC/grpc/grpc_security_constants.h index da05c5a97..fde300dfb 100644 --- a/Sources/CgRPC/grpc/grpc_security_constants.h +++ b/Sources/CgRPC/grpc/grpc_security_constants.h @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -45,30 +30,30 @@ extern "C" { #define GRPC_X509_SAN_PROPERTY_NAME "x509_subject_alternative_name" #define GRPC_X509_PEM_CERT_PROPERTY_NAME "x509_pem_cert" -/* Environment variable that points to the default SSL roots file. This file +/** Environment variable that points to the default SSL roots file. This file must be a PEM encoded file with all the roots such as the one that can be downloaded from https://pki.google.com/roots.pem. */ #define GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR \ "GRPC_DEFAULT_SSL_ROOTS_FILE_PATH" -/* Environment variable that points to the google default application +/** Environment variable that points to the google default application credentials json key or refresh token. Used in the grpc_google_default_credentials_create function. */ #define GRPC_GOOGLE_CREDENTIALS_ENV_VAR "GOOGLE_APPLICATION_CREDENTIALS" -/* Results for the SSL roots override callback. */ +/** Results for the SSL roots override callback. */ typedef enum { GRPC_SSL_ROOTS_OVERRIDE_OK, - GRPC_SSL_ROOTS_OVERRIDE_FAIL_PERMANENTLY, /* Do not try fallback options. */ + GRPC_SSL_ROOTS_OVERRIDE_FAIL_PERMANENTLY, /** Do not try fallback options. */ GRPC_SSL_ROOTS_OVERRIDE_FAIL } grpc_ssl_roots_override_result; typedef enum { - /* Server does not request client certificate. A client can present a self + /** Server does not request client certificate. A client can present a self signed or signed certificates if it wishes to do so and they would be accepted. */ GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE, - /* Server requests client certificate but does not enforce that the client + /** Server requests client certificate but does not enforce that the client presents a certificate. If the client presents a certificate, the client authentication is left to @@ -77,7 +62,7 @@ typedef enum { The key cert pair should still be valid for the SSL connection to be established. */ GRPC_SSL_REQUEST_CLIENT_CERTIFICATE_BUT_DONT_VERIFY, - /* Server requests client certificate but does not enforce that the client + /** Server requests client certificate but does not enforce that the client presents a certificate. If the client presents a certificate, the client authentication is done by @@ -87,7 +72,7 @@ typedef enum { The key cert pair should still be valid for the SSL connection to be established. */ GRPC_SSL_REQUEST_CLIENT_CERTIFICATE_AND_VERIFY, - /* Server requests client certificate but enforces that the client presents a + /** Server requests client certificate but enforces that the client presents a certificate. If the client presents a certificate, the client authentication is left to @@ -96,7 +81,7 @@ typedef enum { The key cert pair should still be valid for the SSL connection to be established. */ GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_BUT_DONT_VERIFY, - /* Server requests client certificate but enforces that the client presents a + /** Server requests client certificate but enforces that the client presents a certificate. The cerificate presented by the client is verified by grpc framework (The diff --git a/Sources/CgRPC/grpc/impl/codegen/atm.h b/Sources/CgRPC/grpc/impl/codegen/atm.h index ae00fb0f1..2cfd22ab6 100644 --- a/Sources/CgRPC/grpc/impl/codegen/atm.h +++ b/Sources/CgRPC/grpc/impl/codegen/atm.h @@ -1,40 +1,25 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 GRPC_IMPL_CODEGEN_ATM_H #define GRPC_IMPL_CODEGEN_ATM_H -/* This interface provides atomic operations and barriers. +/** This interface provides atomic operations and barriers. It is internal to gpr support code and should not be used outside it. If an operation with acquire semantics precedes another memory access by the @@ -75,6 +60,7 @@ int gpr_atm_no_barrier_cas(gpr_atm *p, gpr_atm o, gpr_atm n); int gpr_atm_acq_cas(gpr_atm *p, gpr_atm o, gpr_atm n); int gpr_atm_rel_cas(gpr_atm *p, gpr_atm o, gpr_atm n); + int gpr_atm_full_cas(gpr_atm *p, gpr_atm o, gpr_atm n); // Atomically, set *p=n and return the old value of *p gpr_atm gpr_atm_full_xchg(gpr_atm *p, gpr_atm n); @@ -92,4 +78,9 @@ #error could not determine platform for atm #endif +/** Adds \a delta to \a *value, clamping the result to the range specified + by \a min and \a max. Returns the new value. */ +gpr_atm gpr_atm_no_barrier_clamped_add(gpr_atm *value, gpr_atm delta, + gpr_atm min, gpr_atm max); + #endif /* GRPC_IMPL_CODEGEN_ATM_H */ diff --git a/Sources/CgRPC/grpc/impl/codegen/atm_gcc_atomic.h b/Sources/CgRPC/grpc/impl/codegen/atm_gcc_atomic.h index 7d4ae98cf..1793ec22b 100644 --- a/Sources/CgRPC/grpc/impl/codegen/atm_gcc_atomic.h +++ b/Sources/CgRPC/grpc/impl/codegen/atm_gcc_atomic.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -39,6 +24,21 @@ #include typedef intptr_t gpr_atm; +#define GPR_ATM_MAX INTPTR_MAX + +#ifdef GPR_LOW_LEVEL_COUNTERS +extern gpr_atm gpr_counter_atm_cas; +extern gpr_atm gpr_counter_atm_add; +#define GPR_ATM_INC_COUNTER(counter) \ + __atomic_fetch_add(&counter, 1, __ATOMIC_RELAXED) +#define GPR_ATM_INC_CAS_THEN(blah) \ + (GPR_ATM_INC_COUNTER(gpr_counter_atm_cas), blah) +#define GPR_ATM_INC_ADD_THEN(blah) \ + (GPR_ATM_INC_COUNTER(gpr_counter_atm_add), blah) +#else +#define GPR_ATM_INC_CAS_THEN(blah) blah +#define GPR_ATM_INC_ADD_THEN(blah) blah +#endif #define gpr_atm_full_barrier() (__atomic_thread_fence(__ATOMIC_SEQ_CST)) @@ -50,25 +50,33 @@ typedef intptr_t gpr_atm; (__atomic_store_n((p), (intptr_t)(value), __ATOMIC_RELAXED)) #define gpr_atm_no_barrier_fetch_add(p, delta) \ - (__atomic_fetch_add((p), (intptr_t)(delta), __ATOMIC_RELAXED)) + GPR_ATM_INC_ADD_THEN( \ + __atomic_fetch_add((p), (intptr_t)(delta), __ATOMIC_RELAXED)) #define gpr_atm_full_fetch_add(p, delta) \ - (__atomic_fetch_add((p), (intptr_t)(delta), __ATOMIC_ACQ_REL)) + GPR_ATM_INC_ADD_THEN( \ + __atomic_fetch_add((p), (intptr_t)(delta), __ATOMIC_ACQ_REL)) static __inline int gpr_atm_no_barrier_cas(gpr_atm *p, gpr_atm o, gpr_atm n) { - return __atomic_compare_exchange_n(p, &o, n, 0, __ATOMIC_RELAXED, - __ATOMIC_RELAXED); + return GPR_ATM_INC_CAS_THEN(__atomic_compare_exchange_n( + p, &o, n, 0, __ATOMIC_RELAXED, __ATOMIC_RELAXED)); } static __inline int gpr_atm_acq_cas(gpr_atm *p, gpr_atm o, gpr_atm n) { - return __atomic_compare_exchange_n(p, &o, n, 0, __ATOMIC_ACQUIRE, - __ATOMIC_RELAXED); + return GPR_ATM_INC_CAS_THEN(__atomic_compare_exchange_n( + p, &o, n, 0, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED)); } static __inline int gpr_atm_rel_cas(gpr_atm *p, gpr_atm o, gpr_atm n) { - return __atomic_compare_exchange_n(p, &o, n, 0, __ATOMIC_RELEASE, - __ATOMIC_RELAXED); + return GPR_ATM_INC_CAS_THEN(__atomic_compare_exchange_n( + p, &o, n, 0, __ATOMIC_RELEASE, __ATOMIC_RELAXED)); +} + +static __inline int gpr_atm_full_cas(gpr_atm *p, gpr_atm o, gpr_atm n) { + return GPR_ATM_INC_CAS_THEN(__atomic_compare_exchange_n( + p, &o, n, 0, __ATOMIC_ACQ_REL, __ATOMIC_RELAXED)); } -#define gpr_atm_full_xchg(p, n) __atomic_exchange_n((p), (n), __ATOMIC_ACQ_REL) +#define gpr_atm_full_xchg(p, n) \ + GPR_ATM_INC_CAS_THEN(__atomic_exchange_n((p), (n), __ATOMIC_ACQ_REL)) #endif /* GRPC_IMPL_CODEGEN_ATM_GCC_ATOMIC_H */ diff --git a/Sources/CgRPC/grpc/impl/codegen/atm_gcc_sync.h b/Sources/CgRPC/grpc/impl/codegen/atm_gcc_sync.h index 9aa2b4318..27ae0f63d 100644 --- a/Sources/CgRPC/grpc/impl/codegen/atm_gcc_sync.h +++ b/Sources/CgRPC/grpc/impl/codegen/atm_gcc_sync.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -39,6 +24,7 @@ #include typedef intptr_t gpr_atm; +#define GPR_ATM_MAX INTPTR_MAX #define GPR_ATM_COMPILE_BARRIER_() __asm__ __volatile__("" : : : "memory") @@ -83,6 +69,7 @@ static __inline void gpr_atm_no_barrier_store(gpr_atm *p, gpr_atm value) { #define gpr_atm_no_barrier_cas(p, o, n) gpr_atm_acq_cas((p), (o), (n)) #define gpr_atm_acq_cas(p, o, n) (__sync_bool_compare_and_swap((p), (o), (n))) #define gpr_atm_rel_cas(p, o, n) gpr_atm_acq_cas((p), (o), (n)) +#define gpr_atm_full_cas(p, o, n) gpr_atm_acq_cas((p), (o), (n)) static __inline gpr_atm gpr_atm_full_xchg(gpr_atm *p, gpr_atm n) { gpr_atm cur; diff --git a/Sources/CgRPC/grpc/impl/codegen/atm_windows.h b/Sources/CgRPC/grpc/impl/codegen/atm_windows.h index 0ab70b95c..dfcaa4cc3 100644 --- a/Sources/CgRPC/grpc/impl/codegen/atm_windows.h +++ b/Sources/CgRPC/grpc/impl/codegen/atm_windows.h @@ -1,43 +1,29 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 GRPC_IMPL_CODEGEN_ATM_WINDOWS_H #define GRPC_IMPL_CODEGEN_ATM_WINDOWS_H -/* Win32 variant of atm_platform.h */ +/** Win32 variant of atm_platform.h */ #include typedef intptr_t gpr_atm; +#define GPR_ATM_MAX INTPTR_MAX #define gpr_atm_full_barrier MemoryBarrier @@ -63,7 +49,7 @@ static __inline void gpr_atm_no_barrier_store(gpr_atm *p, gpr_atm value) { } static __inline int gpr_atm_no_barrier_cas(gpr_atm *p, gpr_atm o, gpr_atm n) { -/* InterlockedCompareExchangePointerNoFence() not available on vista or +/** InterlockedCompareExchangePointerNoFence() not available on vista or windows7 */ #ifdef GPR_ARCH_64 return o == (gpr_atm)InterlockedCompareExchangeAcquire64( @@ -94,9 +80,19 @@ static __inline int gpr_atm_rel_cas(gpr_atm *p, gpr_atm o, gpr_atm n) { #endif } +static __inline int gpr_atm_full_cas(gpr_atm *p, gpr_atm o, gpr_atm n) { +#ifdef GPR_ARCH_64 + return o == (gpr_atm)InterlockedCompareExchange64((volatile LONGLONG *)p, + (LONGLONG)n, (LONGLONG)o); +#else + return o == (gpr_atm)InterlockedCompareExchange((volatile LONG *)p, (LONG)n, + (LONG)o); +#endif +} + static __inline gpr_atm gpr_atm_no_barrier_fetch_add(gpr_atm *p, gpr_atm delta) { - /* Use the CAS operation to get pointer-sized fetch and add */ + /** Use the CAS operation to get pointer-sized fetch and add */ gpr_atm old; do { old = *p; @@ -105,7 +101,7 @@ static __inline gpr_atm gpr_atm_no_barrier_fetch_add(gpr_atm *p, } static __inline gpr_atm gpr_atm_full_fetch_add(gpr_atm *p, gpr_atm delta) { - /* Use a CAS operation to get pointer-sized fetch and add */ + /** Use a CAS operation to get pointer-sized fetch and add */ gpr_atm old; #ifdef GPR_ARCH_64 do { diff --git a/Sources/CgRPC/grpc/impl/codegen/byte_buffer_reader.h b/Sources/CgRPC/grpc/impl/codegen/byte_buffer_reader.h index 85a486414..dc0f15496 100644 --- a/Sources/CgRPC/grpc/impl/codegen/byte_buffer_reader.h +++ b/Sources/CgRPC/grpc/impl/codegen/byte_buffer_reader.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -43,9 +28,9 @@ struct grpc_byte_buffer; struct grpc_byte_buffer_reader { struct grpc_byte_buffer *buffer_in; struct grpc_byte_buffer *buffer_out; - /* Different current objects correspond to different types of byte buffers */ - union { - /* Index into a slice buffer's array of slices */ + /** Different current objects correspond to different types of byte buffers */ + union grpc_byte_buffer_reader_current { + /** Index into a slice buffer's array of slices */ unsigned index; } current; }; diff --git a/Sources/CgRPC/grpc/impl/codegen/compression_types.h b/Sources/CgRPC/grpc/impl/codegen/compression_types.h index 170d99f43..f1b2de3f7 100644 --- a/Sources/CgRPC/grpc/impl/codegen/compression_types.h +++ b/Sources/CgRPC/grpc/impl/codegen/compression_types.h @@ -1,41 +1,25 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 GRPC_IMPL_CODEGEN_COMPRESSION_TYPES_H #define GRPC_IMPL_CODEGEN_COMPRESSION_TYPES_H -#include -#include +#include #ifdef __cplusplus extern "C" { @@ -68,7 +52,7 @@ extern "C" { "grpc.compression_enabled_algorithms_bitset" /** \} */ -/* The various compression algorithms supported by gRPC */ +/** The various compression algorithms supported by gRPC */ typedef enum { GRPC_COMPRESS_NONE = 0, GRPC_COMPRESS_DEFLATE, @@ -100,16 +84,16 @@ typedef struct grpc_compression_options { * behind \a GRPC_COMPRESSION_CHANNEL_DEFAULT_LEVEL. If present, takes * precedence over \a default_algorithm. * TODO(dgq): currently only available for server channels. */ - struct { - bool is_set; + struct grpc_compression_options_default_level { + int is_set; grpc_compression_level level; } default_level; /** The default channel compression algorithm. It'll be used in the absence of * call specific settings. This option corresponds to the channel argument key * behind \a GRPC_COMPRESSION_CHANNEL_DEFAULT_ALGORITHM. */ - struct { - bool is_set; + struct grpc_compression_options_default_algorithm { + int is_set; grpc_compression_algorithm algorithm; } default_algorithm; diff --git a/Sources/CgRPC/grpc/impl/codegen/connectivity_state.h b/Sources/CgRPC/grpc/impl/codegen/connectivity_state.h index c6d1a3340..545b4fdbc 100644 --- a/Sources/CgRPC/grpc/impl/codegen/connectivity_state.h +++ b/Sources/CgRPC/grpc/impl/codegen/connectivity_state.h @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/grpc/impl/codegen/exec_ctx_fwd.h b/Sources/CgRPC/grpc/impl/codegen/exec_ctx_fwd.h new file mode 100644 index 000000000..005ff14e7 --- /dev/null +++ b/Sources/CgRPC/grpc/impl/codegen/exec_ctx_fwd.h @@ -0,0 +1,26 @@ +/* + * + * Copyright 2016 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 GRPC_IMPL_CODEGEN_EXEC_CTX_FWD_H +#define GRPC_IMPL_CODEGEN_EXEC_CTX_FWD_H + +/* forward declaration for exec_ctx.h */ +struct grpc_exec_ctx; +typedef struct grpc_exec_ctx grpc_exec_ctx; + +#endif /* GRPC_IMPL_CODEGEN_EXEC_CTX_FWD_H */ diff --git a/Sources/CgRPC/grpc/impl/codegen/gpr_slice.h b/Sources/CgRPC/grpc/impl/codegen/gpr_slice.h new file mode 100644 index 000000000..89fa72d5f --- /dev/null +++ b/Sources/CgRPC/grpc/impl/codegen/gpr_slice.h @@ -0,0 +1,69 @@ +/* + * + * Copyright 2016 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 GRPC_IMPL_CODEGEN_GPR_SLICE_H +#define GRPC_IMPL_CODEGEN_GPR_SLICE_H + +/** WARNING: Please do not use this header. This was added as a temporary + * measure to not break some of the external projects that depend on + * gpr_slice_* functions. We are actively working on moving all the + * gpr_slice_* references to grpc_slice_* and this file will be removed + */ + +/* TODO (sreek) - Allowed by default but will be very soon turned off */ +#define GRPC_ALLOW_GPR_SLICE_FUNCTIONS 1 + +#ifdef GRPC_ALLOW_GPR_SLICE_FUNCTIONS + +#define gpr_slice_refcount grpc_slice_refcount +#define gpr_slice grpc_slice +#define gpr_slice_buffer grpc_slice_buffer + +#define gpr_slice_ref grpc_slice_ref +#define gpr_slice_unref grpc_slice_unref +#define gpr_slice_new grpc_slice_new +#define gpr_slice_new_with_user_data grpc_slice_new_with_user_data +#define gpr_slice_new_with_len grpc_slice_new_with_len +#define gpr_slice_malloc grpc_slice_malloc +#define gpr_slice_from_copied_string grpc_slice_from_copied_string +#define gpr_slice_from_copied_buffer grpc_slice_from_copied_buffer +#define gpr_slice_from_static_string grpc_slice_from_static_string +#define gpr_slice_sub grpc_slice_sub +#define gpr_slice_sub_no_ref grpc_slice_sub_no_ref +#define gpr_slice_split_tail grpc_slice_split_tail +#define gpr_slice_split_head grpc_slice_split_head +#define gpr_slice_cmp grpc_slice_cmp +#define gpr_slice_str_cmp grpc_slice_str_cmp + +#define gpr_slice_buffer grpc_slice_buffer +#define gpr_slice_buffer_init grpc_slice_buffer_init +#define gpr_slice_buffer_destroy grpc_slice_buffer_destroy +#define gpr_slice_buffer_add grpc_slice_buffer_add +#define gpr_slice_buffer_add_indexed grpc_slice_buffer_add_indexed +#define gpr_slice_buffer_addn grpc_slice_buffer_addn +#define gpr_slice_buffer_tiny_add grpc_slice_buffer_tiny_add +#define gpr_slice_buffer_pop grpc_slice_buffer_pop +#define gpr_slice_buffer_reset_and_unref grpc_slice_buffer_reset_and_unref +#define gpr_slice_buffer_swap grpc_slice_buffer_swap +#define gpr_slice_buffer_move_into grpc_slice_buffer_move_into +#define gpr_slice_buffer_trim_end grpc_slice_buffer_trim_end +#define gpr_slice_buffer_move_first grpc_slice_buffer_move_first +#define gpr_slice_buffer_take_first grpc_slice_buffer_take_first + +#endif /* GRPC_ALLOW_GPR_SLICE_FUNCTIONS */ + +#endif /* GRPC_IMPL_CODEGEN_GPR_SLICE_H */ diff --git a/Sources/CgRPC/grpc/impl/codegen/gpr_types.h b/Sources/CgRPC/grpc/impl/codegen/gpr_types.h index ed9976f42..d7bb54527 100644 --- a/Sources/CgRPC/grpc/impl/codegen/gpr_types.h +++ b/Sources/CgRPC/grpc/impl/codegen/gpr_types.h @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -37,28 +22,27 @@ #include #include -#include #ifdef __cplusplus extern "C" { #endif -/* The clocks we support. */ +/** The clocks we support. */ typedef enum { - /* Monotonic clock. Epoch undefined. Always moves forwards. */ + /** Monotonic clock. Epoch undefined. Always moves forwards. */ GPR_CLOCK_MONOTONIC = 0, - /* Realtime clock. May jump forwards or backwards. Settable by + /** Realtime clock. May jump forwards or backwards. Settable by the system administrator. Has its epoch at 0:00:00 UTC 1 Jan 1970. */ GPR_CLOCK_REALTIME, - /* CPU cycle time obtained by rdtsc instruction on x86 platforms. Epoch + /** CPU cycle time obtained by rdtsc instruction on x86 platforms. Epoch undefined. Degrades to GPR_CLOCK_REALTIME on other platforms. */ GPR_CLOCK_PRECISE, - /* Unmeasurable clock type: no base, created by taking the difference + /** Unmeasurable clock type: no base, created by taking the difference between two times */ GPR_TIMESPAN } gpr_clock_type; -/* Analogous to struct timespec. On some machines, absolute times may be in +/** Analogous to struct timespec. On some machines, absolute times may be in * local time. */ typedef struct gpr_timespec { int64_t tv_sec; diff --git a/Sources/CgRPC/grpc/impl/codegen/grpc_types.h b/Sources/CgRPC/grpc/impl/codegen/grpc_types.h index 4471ccf74..8813ec8f3 100644 --- a/Sources/CgRPC/grpc/impl/codegen/grpc_types.h +++ b/Sources/CgRPC/grpc/impl/codegen/grpc_types.h @@ -1,47 +1,33 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 GRPC_IMPL_CODEGEN_GRPC_TYPES_H #define GRPC_IMPL_CODEGEN_GRPC_TYPES_H -#include -#include +#include #include +#include +#include +#include #include #include -#include #ifdef __cplusplus extern "C" { @@ -49,25 +35,25 @@ extern "C" { typedef enum { GRPC_BB_RAW - /* Future types may include GRPC_BB_PROTOBUF, etc. */ + /** Future types may include GRPC_BB_PROTOBUF, etc. */ } grpc_byte_buffer_type; typedef struct grpc_byte_buffer { void *reserved; grpc_byte_buffer_type type; - union { - struct { + union grpc_byte_buffer_data { + struct /* internal */ { void *reserved[8]; } reserved; - struct { + struct grpc_compressed_buffer { grpc_compression_algorithm compression; grpc_slice_buffer slice_buffer; } raw; } data; } grpc_byte_buffer; -/** Completion Queues enable notification of the completion of asynchronous - actions. */ +/** Completion Queues enable notification of the completion of + * asynchronous actions. */ typedef struct grpc_completion_queue grpc_completion_queue; /** An alarm associated with a completion queue. */ @@ -87,6 +73,9 @@ typedef struct grpc_call grpc_call; /** The Socket Mutator interface allows changes on socket options */ typedef struct grpc_socket_mutator grpc_socket_mutator; +/** The Socket Factory interface creates and binds sockets */ +typedef struct grpc_socket_factory grpc_socket_factory; + /** Type specifier for grpc_arg */ typedef enum { GRPC_ARG_STRING, @@ -96,7 +85,7 @@ typedef enum { typedef struct grpc_arg_pointer_vtable { void *(*copy)(void *p); - void (*destroy)(void *p); + void (*destroy)(grpc_exec_ctx *exec_ctx, void *p); int (*cmp)(void *p, void *q); } grpc_arg_pointer_vtable; @@ -115,10 +104,10 @@ typedef struct grpc_arg_pointer_vtable { typedef struct { grpc_arg_type type; char *key; - union { + union grpc_arg_value { char *string; int integer; - struct { + struct grpc_arg_pointer { void *p; const grpc_arg_pointer_vtable *vtable; } pointer; @@ -130,9 +119,9 @@ typedef struct { Used to set optional channel-level configuration. These configuration options are modelled as key-value pairs as defined by grpc_arg; keys are strings to allow easy backwards-compatible extension - by arbitrary parties. - All evaluation is performed at channel creation time (i.e. the values in - this structure need only live through the creation invocation). + by arbitrary parties. All evaluation is performed at channel creation + time (i.e. the values in this structure need only live through the + creation invocation). See the description of the \ref grpc_arg_keys "available args" for more details. */ @@ -149,18 +138,37 @@ typedef struct { #define GRPC_ARG_ENABLE_CENSUS "grpc.census" /** If non-zero, enable load reporting. */ #define GRPC_ARG_ENABLE_LOAD_REPORTING "grpc.loadreporting" +/** Request that optional features default to off (regardless of what they + usually default to) - to enable tight control over what gets enabled */ +#define GRPC_ARG_MINIMAL_STACK "grpc.minimal_stack" /** Maximum number of concurrent incoming streams to allow on a http2 connection. Int valued. */ #define GRPC_ARG_MAX_CONCURRENT_STREAMS "grpc.max_concurrent_streams" /** Maximum message length that the channel can receive. Int valued, bytes. -1 means unlimited. */ #define GRPC_ARG_MAX_RECEIVE_MESSAGE_LENGTH "grpc.max_receive_message_length" -/** \deprecated For backward compatibility. */ +/** \deprecated For backward compatibility. + * Use GRPC_ARG_MAX_RECEIVE_MESSAGE_LENGTH instead. */ #define GRPC_ARG_MAX_MESSAGE_LENGTH GRPC_ARG_MAX_RECEIVE_MESSAGE_LENGTH /** Maximum message length that the channel can send. Int valued, bytes. -1 means unlimited. */ #define GRPC_ARG_MAX_SEND_MESSAGE_LENGTH "grpc.max_send_message_length" -/** Initial sequence number for http2 transports. Int valued. */ +/** Maximum time that a channel may have no outstanding rpcs. Int valued, + milliseconds. INT_MAX means unlimited. */ +#define GRPC_ARG_MAX_CONNECTION_IDLE_MS "grpc.max_connection_idle_ms" +/** Maximum time that a channel may exist. Int valued, milliseconds. + * INT_MAX means unlimited. */ +#define GRPC_ARG_MAX_CONNECTION_AGE_MS "grpc.max_connection_age_ms" +/** Grace period after the chennel reaches its max age. Int valued, + milliseconds. INT_MAX means unlimited. */ +#define GRPC_ARG_MAX_CONNECTION_AGE_GRACE_MS "grpc.max_connection_age_grace_ms" +/** Enable/disable support for per-message compression. Defaults to 1, unless + GRPC_ARG_MINIMAL_STACK is enabled, in which case it defaults to 0. */ +#define GRPC_ARG_ENABLE_PER_MESSAGE_COMPRESSION "grpc.per_message_compression" +/** Enable/disable support for deadline checking. Defaults to 1, unless + GRPC_ARG_MINIMAL_STACK is enabled, in which case it defaults to 0 */ +#define GRPC_ARG_ENABLE_DEADLINE_CHECKS "grpc.enable_deadline_checking" +/** Initial stream ID for http2 transports. Int valued. */ #define GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER \ "grpc.http2.initial_sequence_number" /** Amount to read ahead on individual streams. Defaults to 64kb, larger @@ -175,10 +183,46 @@ typedef struct { #define GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_ENCODER \ "grpc.http2.hpack_table_size.encoder" /** How big a frame are we willing to receive via HTTP2. - Min 16384, max 16777215. - Larger values give lower CPU usage for large messages, but more head of line - blocking for small messages. */ + Min 16384, max 16777215. Larger values give lower CPU usage for large + messages, but more head of line blocking for small messages. */ #define GRPC_ARG_HTTP2_MAX_FRAME_SIZE "grpc.http2.max_frame_size" +/** Should BDP probing be performed? */ +#define GRPC_ARG_HTTP2_BDP_PROBE "grpc.http2.bdp_probe" +/** Minimum time (in milliseconds) between successive ping frames being sent */ +#define GRPC_ARG_HTTP2_MIN_TIME_BETWEEN_PINGS_MS \ + "grpc.http2.min_time_between_pings_ms" +/** Channel arg to override the http2 :scheme header */ +#define GRPC_ARG_HTTP2_SCHEME "grpc.http2_scheme" +/** How many pings can we send before needing to send a data frame or header + frame? (0 indicates that an infinite number of pings can be sent without + sending a data frame or header frame) */ +#define GRPC_ARG_HTTP2_MAX_PINGS_WITHOUT_DATA \ + "grpc.http2.max_pings_without_data" +/** How many misbehaving pings the server can bear before sending goaway and + closing the transport? (0 indicates that the server can bear an infinite + number of misbehaving pings) */ +#define GRPC_ARG_HTTP2_MAX_PING_STRIKES "grpc.http2.max_ping_strikes" +/** Minimum allowed time between two pings without sending any data frame. Int + valued, seconds */ +#define GRPC_ARG_HTTP2_MIN_PING_INTERVAL_WITHOUT_DATA_MS \ + "grpc.http2.min_ping_interval_without_data_ms" +/** How much data are we willing to queue up per stream if + GRPC_WRITE_BUFFER_HINT is set? This is an upper bound */ +#define GRPC_ARG_HTTP2_WRITE_BUFFER_SIZE "grpc.http2.write_buffer_size" +/** Should we allow receipt of true-binary data on http2 connections? + Defaults to on (1) */ +#define GRPC_ARG_HTTP2_ENABLE_TRUE_BINARY "grpc.http2.true_binary" +/** After a duration of this time the client/server pings its peer to see if the + transport is still alive. Int valued, milliseconds. */ +#define GRPC_ARG_KEEPALIVE_TIME_MS "grpc.keepalive_time_ms" +/** After waiting for a duration of this time, if the keepalive ping sender does + not receive the ping ack, it will close the transport. Int valued, + milliseconds. */ +#define GRPC_ARG_KEEPALIVE_TIMEOUT_MS "grpc.keepalive_timeout_ms" +/** Is it permissible to send keepalive pings without any outstanding streams. + Int valued, 0(false)/1(true). */ +#define GRPC_ARG_KEEPALIVE_PERMIT_WITHOUT_CALLS \ + "grpc.keepalive_permit_without_calls" /** Default authority to pass if none specified on call construction. A string. * */ #define GRPC_ARG_DEFAULT_AUTHORITY "grpc.default_authority" @@ -188,32 +232,73 @@ typedef struct { /** Secondary user agent: goes at the end of the user-agent metadata sent on each request. A string. */ #define GRPC_ARG_SECONDARY_USER_AGENT_STRING "grpc.secondary_user_agent" +/** The minimum time between subsequent connection attempts, in ms */ +#define GRPC_ARG_MIN_RECONNECT_BACKOFF_MS "grpc.min_reconnect_backoff_ms" /** The maximum time between subsequent connection attempts, in ms */ #define GRPC_ARG_MAX_RECONNECT_BACKOFF_MS "grpc.max_reconnect_backoff_ms" /** The time between the first and second connection attempts, in ms */ #define GRPC_ARG_INITIAL_RECONNECT_BACKOFF_MS \ "grpc.initial_reconnect_backoff_ms" -/* The caller of the secure_channel_create functions may override the target - name used for SSL host name checking using this channel argument which is of - type \a GRPC_ARG_STRING. This *should* be used for testing only. - If this argument is not specified, the name used for SSL host name checking - will be the target parameter (assuming that the secure channel is an SSL - channel). If this parameter is specified and the underlying is not an SSL - channel, it will just be ignored. */ +/** This *should* be used for testing only. + The caller of the secure_channel_create functions may override the target + name used for SSL host name checking using this channel argument which is of + type \a GRPC_ARG_STRING. If this argument is not specified, the name used + for SSL host name checking will be the target parameter (assuming that the + secure channel is an SSL channel). If this parameter is specified and the + underlying is not an SSL channel, it will just be ignored. */ #define GRPC_SSL_TARGET_NAME_OVERRIDE_ARG "grpc.ssl_target_name_override" -/* Maximum metadata size, in bytes. */ +/** Maximum metadata size, in bytes. Note this limit applies to the max sum of + all metadata key-value entries in a batch of headers. */ #define GRPC_ARG_MAX_METADATA_SIZE "grpc.max_metadata_size" /** If non-zero, allow the use of SO_REUSEPORT if it's available (default 1) */ #define GRPC_ARG_ALLOW_REUSEPORT "grpc.so_reuseport" -/** If non-zero, a pointer to a buffer pool (use grpc_resource_quota_arg_vtable - to fetch an appropriate pointer arg vtable) */ +/** If non-zero, a pointer to a buffer pool (a pointer of type + * grpc_resource_quota*). (use grpc_resource_quota_arg_vtable() to fetch an + * appropriate pointer arg vtable) */ #define GRPC_ARG_RESOURCE_QUOTA "grpc.resource_quota" -/** Service config data in JSON form. Not intended for use outside of tests. */ +/** If non-zero, expand wildcard addresses to a list of local addresses. */ +#define GRPC_ARG_EXPAND_WILDCARD_ADDRS "grpc.expand_wildcard_addrs" +/** Service config data in JSON form. + This value will be ignored if the name resolver returns a service config. */ #define GRPC_ARG_SERVICE_CONFIG "grpc.service_config" +/** Disable looking up the service config via the name resolver. */ +#define GRPC_ARG_SERVICE_CONFIG_DISABLE_RESOLUTION \ + "grpc.service_config_disable_resolution" /** LB policy name. */ #define GRPC_ARG_LB_POLICY_NAME "grpc.lb_policy_name" /** The grpc_socket_mutator instance that set the socket options. A pointer. */ #define GRPC_ARG_SOCKET_MUTATOR "grpc.socket_mutator" +/** The grpc_socket_factory instance to create and bind sockets. A pointer. */ +#define GRPC_ARG_SOCKET_FACTORY "grpc.socket_factory" +/** If non-zero, Cronet transport will coalesce packets to fewer frames + * when possible. */ +#define GRPC_ARG_USE_CRONET_PACKET_COALESCING \ + "grpc.use_cronet_packet_coalescing" +/** Channel arg (integer) setting how large a slice to try and read from the + wire each time recvmsg (or equivalent) is called **/ +#define GRPC_ARG_TCP_READ_CHUNK_SIZE "grpc.experimental.tcp_read_chunk_size" +/** Note this is not a "channel arg" key. This is the default slice size to use + * when trying to read from the wire if the GRPC_ARG_TCP_READ_CHUNK_SIZE + * channel arg is unspecified. */ +#define GRPC_TCP_DEFAULT_READ_SLICE_SIZE 8192 +#define GRPC_ARG_TCP_MIN_READ_CHUNK_SIZE \ + "grpc.experimental.tcp_min_read_chunk_size" +#define GRPC_ARG_TCP_MAX_READ_CHUNK_SIZE \ + "grpc.experimental.tcp_max_read_chunk_size" +/* Timeout in milliseconds to use for calls to the grpclb load balancer. + If 0 or unset, the balancer calls will have no deadline. */ +#define GRPC_ARG_GRPCLB_CALL_TIMEOUT_MS "grpc.grpclb_timeout_ms" +/** If non-zero, grpc server's cronet compression workaround will be enabled */ +#define GRPC_ARG_WORKAROUND_CRONET_COMPRESSION \ + "grpc.workaround.cronet_compression" +/** String defining the optimization target for a channel. + Can be: "latency" - attempt to minimize latency at the cost of throughput + "blend" - try to balance latency and throughput + "throughput" - attempt to maximize throughput at the expense of + latency + Defaults to "blend". In the current implementation "blend" is equivalent to + "latency". */ +#define GRPC_ARG_OPTIMIZATION_TARGET "grpc.optimization_target" /** \} */ /** Result of a grpc call. If the caller satisfies the prerequisites of a @@ -246,21 +331,23 @@ typedef enum grpc_call_error { GRPC_CALL_ERROR_INVALID_METADATA, /** invalid message was passed to this call */ GRPC_CALL_ERROR_INVALID_MESSAGE, - /** completion queue for notification has not been registered with the - server */ + /** completion queue for notification has not been registered + * with the server */ GRPC_CALL_ERROR_NOT_SERVER_COMPLETION_QUEUE, /** this batch of operations leads to more operations than allowed */ GRPC_CALL_ERROR_BATCH_TOO_BIG, /** payload type requested is not the type registered */ - GRPC_CALL_ERROR_PAYLOAD_TYPE_MISMATCH + GRPC_CALL_ERROR_PAYLOAD_TYPE_MISMATCH, + /** completion queue has been shutdown */ + GRPC_CALL_ERROR_COMPLETION_QUEUE_SHUTDOWN } grpc_call_error; -/* Default send/receive message size limits in bytes. -1 for unlimited. */ -/* TODO(roth) Make this match the default receive limit after next release */ +/** Default send/receive message size limits in bytes. -1 for unlimited. */ +/** TODO(roth) Make this match the default receive limit after next release */ #define GRPC_DEFAULT_MAX_SEND_MESSAGE_LENGTH -1 #define GRPC_DEFAULT_MAX_RECV_MESSAGE_LENGTH (4 * 1024 * 1024) -/* Write Flags: */ +/** Write Flags: */ /** Hint that the write may be buffered and need not go out on the wire immediately. GRPC is free to buffer the message until the next non-buffered write, or until writes_done, but it need not buffer completely or at all. */ @@ -271,7 +358,7 @@ typedef enum grpc_call_error { /** Mask of all valid flags. */ #define GRPC_WRITE_USED_MASK (GRPC_WRITE_BUFFER_HINT | GRPC_WRITE_NO_COMPRESS) -/* Initial metadata flags */ +/** Initial metadata flags */ /** Signal that the call is idempotent */ #define GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST (0x00000010u) /** Signal that the call should not return UNAVAILABLE before it has started */ @@ -281,25 +368,30 @@ typedef enum grpc_call_error { /** Signal that GRPC_INITIAL_METADATA_WAIT_FOR_READY was explicitly set by the calling application. */ #define GRPC_INITIAL_METADATA_WAIT_FOR_READY_EXPLICITLY_SET (0x00000080u) +/** Signal that the initial metadata should be corked */ +#define GRPC_INITIAL_METADATA_CORKED (0x00000100u) /** Mask of all valid flags */ -#define GRPC_INITIAL_METADATA_USED_MASK \ - (GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST | \ - GRPC_INITIAL_METADATA_WAIT_FOR_READY | \ - GRPC_INITIAL_METADATA_CACHEABLE_REQUEST | \ - GRPC_INITIAL_METADATA_WAIT_FOR_READY_EXPLICITLY_SET) +#define GRPC_INITIAL_METADATA_USED_MASK \ + (GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST | \ + GRPC_INITIAL_METADATA_WAIT_FOR_READY | \ + GRPC_INITIAL_METADATA_CACHEABLE_REQUEST | \ + GRPC_INITIAL_METADATA_WAIT_FOR_READY_EXPLICITLY_SET | \ + GRPC_INITIAL_METADATA_CORKED) /** A single metadata element */ typedef struct grpc_metadata { - const char *key; - const char *value; - size_t value_length; + /** the key, value values are expected to line up with grpc_mdelem: if + changing them, update metadata.h at the same time. */ + grpc_slice key; + grpc_slice value; + uint32_t flags; /** The following fields are reserved for grpc internal use. There is no need to initialize them, and they will be set to garbage during calls to grpc. */ - struct { + struct /* internal */ { void *obfuscated[4]; } internal_data; } grpc_metadata; @@ -320,8 +412,11 @@ typedef enum grpc_completion_type { typedef struct grpc_event { /** The type of the completion. */ grpc_completion_type type; - /** non-zero if the operation was successful, 0 upon failure. - Only GRPC_OP_COMPLETE can succeed or fail. */ + /** If the grpc_completion_type is GRPC_OP_COMPLETE, this field indicates + whether the operation was successful or not; 0 in case of failure and + non-zero in case of success. + If grpc_completion_type is GRPC_QUEUE_SHUTDOWN or GRPC_QUEUE_TIMEOUT, this + field is guaranteed to be 0 */ int success; /** The tag passed to grpc_call_start_batch etc to start this operation. Only GRPC_OP_COMPLETE has a tag. */ @@ -335,10 +430,8 @@ typedef struct { } grpc_metadata_array; typedef struct { - char *method; - size_t method_capacity; - char *host; - size_t host_capacity; + grpc_slice method; + grpc_slice host; gpr_timespec deadline; uint32_t flags; void *reserved; @@ -356,15 +449,13 @@ typedef enum { GRPC_OP_SEND_MESSAGE, /** Send a close from the client: one and only one instance MUST be sent from the client, unless the call was cancelled - in which case this can be - skipped. - This op completes after all bytes for the call (including the close) - have passed outgoing flow control. */ + skipped. This op completes after all bytes for the call + (including the close) have passed outgoing flow control. */ GRPC_OP_SEND_CLOSE_FROM_CLIENT, /** Send status from the server: one and only one instance MUST be sent from the server unless the call was cancelled - in which case this can be - skipped. - This op completes after all bytes for the call (including the status) - have passed outgoing flow control. */ + skipped. This op completes after all bytes for the call + (including the status) have passed outgoing flow control. */ GRPC_OP_SEND_STATUS_FROM_SERVER, /** Receive initial metadata: one and only one MUST be made on the client, must not be made on the server. @@ -382,10 +473,10 @@ typedef enum { This op completes after all activity on the call has completed. */ GRPC_OP_RECV_STATUS_ON_CLIENT, /** Receive close on the server: one and only one must be made on the - server. - This op completes after the close has been received by the server. - This operation always succeeds, meaning ops paired with this operation - will also appear to succeed, even though they may not have. */ + server. This op completes after the close has been received by the + server. This operation always succeeds, meaning ops paired with + this operation will also appear to succeed, even though they may not + have. */ GRPC_OP_RECV_CLOSE_ON_SERVER } grpc_op_type; @@ -400,71 +491,58 @@ typedef struct grpc_op { uint32_t flags; /** Reserved for future usage */ void *reserved; - union { + union grpc_op_data { /** Reserved for future usage */ - struct { + struct /* internal */ { void *reserved[8]; } reserved; - struct { + struct grpc_op_send_initial_metadata { size_t count; grpc_metadata *metadata; /** If \a is_set, \a compression_level will be used for the call. * Otherwise, \a compression_level won't be considered */ - struct { + struct grpc_op_send_initial_metadata_maybe_compression_level { uint8_t is_set; grpc_compression_level level; } maybe_compression_level; } send_initial_metadata; - struct grpc_byte_buffer *send_message; - struct { + struct grpc_op_send_message { + struct grpc_byte_buffer *send_message; + } send_message; + struct grpc_op_send_status_from_server { size_t trailing_metadata_count; grpc_metadata *trailing_metadata; grpc_status_code status; - const char *status_details; + /** optional: set to NULL if no details need sending, non-NULL if they do + * pointer will not be retained past the start_batch call + */ + grpc_slice *status_details; } send_status_from_server; /** ownership of the array is with the caller, but ownership of the elements stays with the call object (ie key, value members are owned by the call object, recv_initial_metadata->array is owned by the caller). After the operation completes, call grpc_metadata_array_destroy on this value, or reuse it in a future op. */ - grpc_metadata_array *recv_initial_metadata; + struct grpc_op_recv_initial_metadata { + grpc_metadata_array *recv_initial_metadata; + } recv_initial_metadata; /** ownership of the byte buffer is moved to the caller; the caller must call grpc_byte_buffer_destroy on this value, or reuse it in a future op. */ - struct grpc_byte_buffer **recv_message; - struct { + struct grpc_op_recv_message { + struct grpc_byte_buffer **recv_message; + } recv_message; + struct grpc_op_recv_status_on_client { /** ownership of the array is with the caller, but ownership of the elements stays with the call object (ie key, value members are owned by the call object, trailing_metadata->array is owned by the caller). After the operation completes, call grpc_metadata_array_destroy on - this - value, or reuse it in a future op. */ + this value, or reuse it in a future op. */ grpc_metadata_array *trailing_metadata; grpc_status_code *status; - /** status_details is a buffer owned by the application before the op - completes and after the op has completed. During the operation - status_details may be reallocated to a size larger than - *status_details_capacity, in which case *status_details_capacity will - be updated with the new array capacity. - - Pre-allocating space: - size_t my_capacity = 8; - char *my_details = gpr_malloc(my_capacity); - x.status_details = &my_details; - x.status_details_capacity = &my_capacity; - - Not pre-allocating space: - size_t my_capacity = 0; - char *my_details = NULL; - x.status_details = &my_details; - x.status_details_capacity = &my_capacity; - - After the call: - gpr_free(my_details); */ - char **status_details; - size_t *status_details_capacity; + grpc_slice *status_details; } recv_status_on_client; - struct { + struct grpc_op_recv_close_on_server { /** out argument, set to 1 if the call failed in any way (seen as a cancellation on the server), or 0 if the call succeeded */ int *cancelled; @@ -474,16 +552,65 @@ typedef struct grpc_op { /** Information requested from the channel. */ typedef struct { - /* If non-NULL, will be set to point to a string indicating the LB + /** If non-NULL, will be set to point to a string indicating the LB * policy name. Caller takes ownership. */ char **lb_policy_name; - /* If non-NULL, will be set to point to a string containing the + /** If non-NULL, will be set to point to a string containing the * service config used by the channel in JSON form. */ char **service_config_json; } grpc_channel_info; typedef struct grpc_resource_quota grpc_resource_quota; +/** Completion queues internally MAY maintain a set of file descriptors in a + structure called 'pollset'. This enum specifies if a completion queue has an + associated pollset and any restrictions on the type of file descriptors that + can be present in the pollset. + + I/O progress can only be made when grpc_completion_queue_next() or + grpc_completion_queue_pluck() are called on the completion queue (unless the + grpc_cq_polling_type is GRPC_CQ_NON_POLLING) and hence it is very important + to actively call these APIs */ +typedef enum { + /** The completion queue will have an associated pollset and there is no + restriction on the type of file descriptors the pollset may contain */ + GRPC_CQ_DEFAULT_POLLING, + + /** Similar to GRPC_CQ_DEFAULT_POLLING except that the completion queues will + not contain any 'listening file descriptors' (i.e file descriptors used to + listen to incoming channels) */ + GRPC_CQ_NON_LISTENING, + + /** The completion queue will not have an associated pollset. Note that + grpc_completion_queue_next() or grpc_completion_queue_pluck() MUST still + be called to pop events from the completion queue; it is not required to + call them actively to make I/O progress */ + GRPC_CQ_NON_POLLING +} grpc_cq_polling_type; + +/** Specifies the type of APIs to use to pop events from the completion queue */ +typedef enum { + /** Events are popped out by calling grpc_completion_queue_next() API ONLY */ + GRPC_CQ_NEXT, + + /** Events are popped out by calling grpc_completion_queue_pluck() API ONLY*/ + GRPC_CQ_PLUCK +} grpc_cq_completion_type; + +#define GRPC_CQ_CURRENT_VERSION 1 +typedef struct grpc_completion_queue_attributes { + /** The version number of this structure. More fields might be added to this + structure in future. */ + int version; /** Set to GRPC_CQ_CURRENT_VERSION */ + + grpc_cq_completion_type cq_completion_type; + + grpc_cq_polling_type cq_polling_type; +} grpc_completion_queue_attributes; + +/** The completion queue factory structure is opaque to the callers of grpc */ +typedef struct grpc_completion_queue_factory grpc_completion_queue_factory; + #ifdef __cplusplus } #endif diff --git a/Sources/CgRPC/grpc/impl/codegen/port_platform.h b/Sources/CgRPC/grpc/impl/codegen/port_platform.h index cd989d664..a7e72a78e 100644 --- a/Sources/CgRPC/grpc/impl/codegen/port_platform.h +++ b/Sources/CgRPC/grpc/impl/codegen/port_platform.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -157,7 +142,6 @@ #define GPR_GETPID_IN_UNISTD_H 1 #define GPR_SUPPORT_CHANNELS_FROM_FD 1 #elif defined(__linux__) -#define GPR_POSIX_CRASH_HANDLER 1 #define GPR_PLATFORM_STRING "linux" #ifndef _BSD_SOURCE #define _BSD_SOURCE @@ -187,6 +171,11 @@ #else /* _LP64 */ #define GPR_ARCH_32 1 #endif /* _LP64 */ +#ifdef __GLIBC__ +#define GPR_POSIX_CRASH_HANDLER 1 +#else /* musl libc */ +#define GPR_MUSL_LIBC_COMPAT 1 +#endif #elif defined(__APPLE__) #include #include @@ -286,6 +275,12 @@ #endif #endif /* GPR_NO_AUTODETECT_PLATFORM */ +#if defined(__has_include) +#if __has_include() +#define GRPC_HAS_CXX11_ATOMIC +#endif /* __has_include() */ +#endif /* defined(__has_include) */ + #ifndef GPR_PLATFORM_STRING #warning "GPR_PLATFORM_STRING not auto-detected" #define GPR_PLATFORM_STRING "unknown" @@ -297,6 +292,10 @@ #endif #ifdef _MSC_VER +#ifdef _PYTHON_MSVC +// The Python 3.5 Windows runtime is missing InetNtop +#define GPR_WIN_INET_NTOP +#endif // _PYTHON_MSVC #if _MSC_VER < 1700 typedef __int8 int8_t; typedef __int16 int16_t; @@ -360,11 +359,21 @@ typedef unsigned __int64 uint64_t; power of two */ #define GPR_MAX_ALIGNMENT 16 +#ifndef GRPC_ARES +#ifdef GPR_WINDOWS +#define GRPC_ARES 0 +#else +#define GRPC_ARES 0 +#endif +#endif + #ifndef GRPC_MUST_USE_RESULT -#ifdef __GNUC__ +#if defined(__GNUC__) && !defined(__MINGW32__) #define GRPC_MUST_USE_RESULT __attribute__((warn_unused_result)) +#define GPR_ALIGN_STRUCT(n) __attribute__((aligned(n))) #else #define GRPC_MUST_USE_RESULT +#define GPR_ALIGN_STRUCT(n) #endif #endif diff --git a/Sources/CgRPC/grpc/impl/codegen/propagation_bits.h b/Sources/CgRPC/grpc/impl/codegen/propagation_bits.h index 4b6455876..824bdbd8c 100644 --- a/Sources/CgRPC/grpc/impl/codegen/propagation_bits.h +++ b/Sources/CgRPC/grpc/impl/codegen/propagation_bits.h @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -40,7 +25,7 @@ extern "C" { #endif -/* Propagation bits: this can be bitwise or-ed to form propagation_mask for +/** Propagation bits: this can be bitwise or-ed to form propagation_mask for * grpc_call */ /** Propagate deadline */ #define GRPC_PROPAGATE_DEADLINE ((uint32_t)1) @@ -50,7 +35,7 @@ extern "C" { /** Propagate cancellation */ #define GRPC_PROPAGATE_CANCELLATION ((uint32_t)8) -/* Default propagation mask: clients of the core API are encouraged to encode +/** Default propagation mask: clients of the core API are encouraged to encode deltas from this in their implementations... ie write: GRPC_PROPAGATE_DEFAULTS & ~GRPC_PROPAGATE_DEADLINE to disable deadline propagation. Doing so gives flexibility in the future to define new diff --git a/Sources/CgRPC/grpc/impl/codegen/slice.h b/Sources/CgRPC/grpc/impl/codegen/slice.h index 774ba0e95..a04c683a5 100644 --- a/Sources/CgRPC/grpc/impl/codegen/slice.h +++ b/Sources/CgRPC/grpc/impl/codegen/slice.h @@ -1,43 +1,34 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 GRPC_IMPL_CODEGEN_SLICE_H #define GRPC_IMPL_CODEGEN_SLICE_H +#include + #include -#include -/* Slice API +#include +#include + +typedef struct grpc_slice grpc_slice; + +/** Slice API A slice represents a contiguous reference counted array of bytes. It is cheap to take references to a slice, and it is cheap to create a @@ -50,19 +41,30 @@ reference ownership semantics (who should call unref?) and mutability constraints (is the callee allowed to modify the slice?) */ -/* Reference count container for grpc_slice. Contains function pointers to +typedef struct grpc_slice_refcount_vtable { + void (*ref)(void *); + void (*unref)(grpc_exec_ctx *exec_ctx, void *); + int (*eq)(grpc_slice a, grpc_slice b); + uint32_t (*hash)(grpc_slice slice); +} grpc_slice_refcount_vtable; + +/** Reference count container for grpc_slice. Contains function pointers to increment and decrement reference counts. Implementations should cleanup when the reference count drops to zero. Typically client code should not touch this, and use grpc_slice_malloc, grpc_slice_new, or grpc_slice_new_with_len instead. */ typedef struct grpc_slice_refcount { - void (*ref)(void *); - void (*unref)(void *); + const grpc_slice_refcount_vtable *vtable; + /** If a subset of this slice is taken, use this pointer for the refcount. + Typically points back to the refcount itself, however iterning + implementations can use this to avoid a verification step on each hash + or equality check */ + struct grpc_slice_refcount *sub_refcount; } grpc_slice_refcount; #define GRPC_SLICE_INLINED_SIZE (sizeof(size_t) + sizeof(uint8_t *) - 1) -/* A grpc_slice s, if initialized, represents the byte range +/** A grpc_slice s, if initialized, represents the byte range s.bytes[0..s.length-1]. It can have an associated ref count which has a destruction routine to be run @@ -71,34 +73,39 @@ typedef struct grpc_slice_refcount { If the slice does not have a refcount, it represents an inlined small piece of data that is copied by value. */ -typedef struct grpc_slice { +struct grpc_slice { struct grpc_slice_refcount *refcount; - union { - struct { + union grpc_slice_data { + struct grpc_slice_refcounted { uint8_t *bytes; size_t length; } refcounted; - struct { + struct grpc_slice_inlined { uint8_t length; uint8_t bytes[GRPC_SLICE_INLINED_SIZE]; } inlined; } data; -} grpc_slice; +}; #define GRPC_SLICE_BUFFER_INLINE_ELEMENTS 8 -/* Represents an expandable array of slices, to be interpreted as a +/** Represents an expandable array of slices, to be interpreted as a single item. */ typedef struct { - /* slices in the array */ + /** This is for internal use only. External users (i.e any code outside grpc + * core) MUST NOT use this field */ + grpc_slice *base_slices; + + /** slices in the array (Points to the first valid grpc_slice in the array) */ grpc_slice *slices; - /* the number of slices in the array */ + /** the number of slices in the array */ size_t count; - /* the number of slices allocated in the array */ + /** the number of slices allocated in the array. External users (i.e any code + * outside grpc core) MUST NOT use this field */ size_t capacity; - /* the combined length of all slices in the array */ + /** the combined length of all slices in the array */ size_t length; - /* inlined elements to avoid allocations */ + /** inlined elements to avoid allocations */ grpc_slice inlined[GRPC_SLICE_BUFFER_INLINE_ELEMENTS]; } grpc_slice_buffer; @@ -115,4 +122,22 @@ typedef struct { GRPC_SLICE_START_PTR(slice) + GRPC_SLICE_LENGTH(slice) #define GRPC_SLICE_IS_EMPTY(slice) (GRPC_SLICE_LENGTH(slice) == 0) +#ifdef GRPC_ALLOW_GPR_SLICE_FUNCTIONS + +/* Duplicate GPR_* definitions */ +#define GPR_SLICE_START_PTR(slice) \ + ((slice).refcount ? (slice).data.refcounted.bytes \ + : (slice).data.inlined.bytes) +#define GPR_SLICE_LENGTH(slice) \ + ((slice).refcount ? (slice).data.refcounted.length \ + : (slice).data.inlined.length) +#define GPR_SLICE_SET_LENGTH(slice, newlen) \ + ((slice).refcount ? ((slice).data.refcounted.length = (size_t)(newlen)) \ + : ((slice).data.inlined.length = (uint8_t)(newlen))) +#define GPR_SLICE_END_PTR(slice) \ + GRPC_SLICE_START_PTR(slice) + GRPC_SLICE_LENGTH(slice) +#define GPR_SLICE_IS_EMPTY(slice) (GRPC_SLICE_LENGTH(slice) == 0) + +#endif /* GRPC_ALLOW_GPR_SLICE_FUNCTIONS */ + #endif /* GRPC_IMPL_CODEGEN_SLICE_H */ diff --git a/Sources/CgRPC/grpc/impl/codegen/status.h b/Sources/CgRPC/grpc/impl/codegen/status.h index 29e4570f7..9bc3dc956 100644 --- a/Sources/CgRPC/grpc/impl/codegen/status.h +++ b/Sources/CgRPC/grpc/impl/codegen/status.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -39,40 +24,40 @@ extern "C" { #endif typedef enum { - /* Not an error; returned on success */ + /** Not an error; returned on success */ GRPC_STATUS_OK = 0, - /* The operation was cancelled (typically by the caller). */ + /** The operation was cancelled (typically by the caller). */ GRPC_STATUS_CANCELLED = 1, - /* Unknown error. An example of where this error may be returned is + /** Unknown error. An example of where this error may be returned is if a Status value received from another address space belongs to an error-space that is not known in this address space. Also errors raised by APIs that do not return enough error information may be converted to this error. */ GRPC_STATUS_UNKNOWN = 2, - /* Client specified an invalid argument. Note that this differs + /** Client specified an invalid argument. Note that this differs from FAILED_PRECONDITION. INVALID_ARGUMENT indicates arguments that are problematic regardless of the state of the system (e.g., a malformed file name). */ GRPC_STATUS_INVALID_ARGUMENT = 3, - /* Deadline expired before operation could complete. For operations + /** Deadline expired before operation could complete. For operations that change the state of the system, this error may be returned even if the operation has completed successfully. For example, a successful response from a server could have been delayed long enough for the deadline to expire. */ GRPC_STATUS_DEADLINE_EXCEEDED = 4, - /* Some requested entity (e.g., file or directory) was not found. */ + /** Some requested entity (e.g., file or directory) was not found. */ GRPC_STATUS_NOT_FOUND = 5, - /* Some entity that we attempted to create (e.g., file or directory) + /** Some entity that we attempted to create (e.g., file or directory) already exists. */ GRPC_STATUS_ALREADY_EXISTS = 6, - /* The caller does not have permission to execute the specified + /** The caller does not have permission to execute the specified operation. PERMISSION_DENIED must not be used for rejections caused by exhausting some resource (use RESOURCE_EXHAUSTED instead for those errors). PERMISSION_DENIED must not be @@ -80,15 +65,15 @@ typedef enum { instead for those errors). */ GRPC_STATUS_PERMISSION_DENIED = 7, - /* The request does not have valid authentication credentials for the + /** The request does not have valid authentication credentials for the operation. */ GRPC_STATUS_UNAUTHENTICATED = 16, - /* Some resource has been exhausted, perhaps a per-user quota, or + /** Some resource has been exhausted, perhaps a per-user quota, or perhaps the entire file system is out of space. */ GRPC_STATUS_RESOURCE_EXHAUSTED = 8, - /* Operation was rejected because the system is not in a state + /** Operation was rejected because the system is not in a state required for the operation's execution. For example, directory to be deleted may be non-empty, an rmdir operation is applied to a non-directory, etc. @@ -109,14 +94,14 @@ typedef enum { read-modify-write on the same resource. */ GRPC_STATUS_FAILED_PRECONDITION = 9, - /* The operation was aborted, typically due to a concurrency issue + /** The operation was aborted, typically due to a concurrency issue like sequencer check failures, transaction aborts, etc. See litmus test above for deciding between FAILED_PRECONDITION, ABORTED, and UNAVAILABLE. */ GRPC_STATUS_ABORTED = 10, - /* Operation was attempted past the valid range. E.g., seeking or + /** Operation was attempted past the valid range. E.g., seeking or reading past end of file. Unlike INVALID_ARGUMENT, this error indicates a problem that may @@ -133,26 +118,31 @@ typedef enum { they are done. */ GRPC_STATUS_OUT_OF_RANGE = 11, - /* Operation is not implemented or not supported/enabled in this service. */ + /** Operation is not implemented or not supported/enabled in this service. */ GRPC_STATUS_UNIMPLEMENTED = 12, - /* Internal errors. Means some invariants expected by underlying + /** Internal errors. Means some invariants expected by underlying system has been broken. If you see one of these errors, something is very broken. */ GRPC_STATUS_INTERNAL = 13, - /* The service is currently unavailable. This is a most likely a + /** The service is currently unavailable. This is a most likely a transient condition and may be corrected by retrying with a backoff. + WARNING: Although data MIGHT not have been transmitted when this + status occurs, there is NOT A GUARANTEE that the server has not seen + anything. So in general it is unsafe to retry on this status code + if the call is non-idempotent. + See litmus test above for deciding between FAILED_PRECONDITION, ABORTED, and UNAVAILABLE. */ GRPC_STATUS_UNAVAILABLE = 14, - /* Unrecoverable data loss or corruption. */ + /** Unrecoverable data loss or corruption. */ GRPC_STATUS_DATA_LOSS = 15, - /* Force users to include a default branch: */ + /** Force users to include a default branch: */ GRPC_STATUS__DO_NOT_USE = -1 } grpc_status_code; diff --git a/Sources/CgRPC/grpc/impl/codegen/sync.h b/Sources/CgRPC/grpc/impl/codegen/sync.h index 96aec0c2c..de4e99be6 100644 --- a/Sources/CgRPC/grpc/impl/codegen/sync.h +++ b/Sources/CgRPC/grpc/impl/codegen/sync.h @@ -1,39 +1,24 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 GRPC_IMPL_CODEGEN_SYNC_H #define GRPC_IMPL_CODEGEN_SYNC_H -/* Synchronization primitives for GPR. +/** Synchronization primitives for GPR. The type gpr_mu provides a non-reentrant mutex (lock). @@ -52,6 +37,10 @@ provides no memory barriers. */ +#ifdef __cplusplus +extern "C" { +#endif + /* Platform-specific type declarations of gpr_mu and gpr_cv. */ #include #include @@ -64,4 +53,8 @@ #error Unable to determine platform for sync #endif +#ifdef __cplusplus +} +#endif + #endif /* GRPC_IMPL_CODEGEN_SYNC_H */ diff --git a/Sources/CgRPC/grpc/impl/codegen/sync_generic.h b/Sources/CgRPC/grpc/impl/codegen/sync_generic.h index 75e85ae73..e1eea5429 100644 --- a/Sources/CgRPC/grpc/impl/codegen/sync_generic.h +++ b/Sources/CgRPC/grpc/impl/codegen/sync_generic.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/grpc/impl/codegen/sync_posix.h b/Sources/CgRPC/grpc/impl/codegen/sync_posix.h index 3d08cc35e..6a3aed92c 100644 --- a/Sources/CgRPC/grpc/impl/codegen/sync_posix.h +++ b/Sources/CgRPC/grpc/impl/codegen/sync_posix.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/grpc/impl/codegen/sync_windows.h b/Sources/CgRPC/grpc/impl/codegen/sync_windows.h index aa4e5153d..39b127603 100644 --- a/Sources/CgRPC/grpc/impl/codegen/sync_windows.h +++ b/Sources/CgRPC/grpc/impl/codegen/sync_windows.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/grpc/load_reporting.h b/Sources/CgRPC/grpc/load_reporting.h new file mode 100644 index 000000000..55f50ea85 --- /dev/null +++ b/Sources/CgRPC/grpc/load_reporting.h @@ -0,0 +1,48 @@ +/* + * + * Copyright 2017 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 GRPC_LOAD_REPORTING_H +#define GRPC_LOAD_REPORTING_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** Metadata key for the gRPC LB load balancer token. + * + * The value corresponding to this key is an opaque token that is given to the + * frontend as part of each pick; the frontend sends this token to the backend + * in each request it sends when using that pick. The token is used by the + * backend to verify the request and to allow the backend to report load to the + * gRPC LB system. */ +#define GRPC_LB_TOKEN_MD_KEY "lb-token" + +/** Metadata key for gRPC LB cost reporting. + * + * The value corresponding to this key is an opaque binary blob reported by the + * backend as part of its trailing metadata containing cost information for the + * call. */ +#define GRPC_LB_COST_MD_KEY "lb-cost-bin" + +#ifdef __cplusplus +} +#endif + +#endif /* GRPC_LOAD_REPORTING_H */ diff --git a/Sources/CgRPC/grpc/slice.h b/Sources/CgRPC/grpc/slice.h index 1f181aae1..9d2a9fbc8 100644 --- a/Sources/CgRPC/grpc/slice.h +++ b/Sources/CgRPC/grpc/slice.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -41,11 +26,11 @@ extern "C" { #endif -/* Increment the refcount of s. Requires slice is initialized. +/** Increment the refcount of s. Requires slice is initialized. Returns s. */ GPRAPI grpc_slice grpc_slice_ref(grpc_slice s); -/* Decrement the ref count of s. If the ref count of s reaches zero, all +/** Decrement the ref count of s. If the ref count of s reaches zero, all slices sharing the ref count are destroyed, and considered no longer initialized. If s is ultimately derived from a call to grpc_slice_new(start, len, dest) where dest!=NULL , then (*dest)(start) is called, else if s is @@ -53,12 +38,15 @@ GPRAPI grpc_slice grpc_slice_ref(grpc_slice s); where dest!=NULL , then (*dest)(start, len). Requires s initialized. */ GPRAPI void grpc_slice_unref(grpc_slice s); -/* Create a slice pointing at some data. Calls malloc to allocate a refcount +/** Copy slice - create a new slice that contains the same data as s */ +GPRAPI grpc_slice grpc_slice_copy(grpc_slice s); + +/** Create a slice pointing at some data. Calls malloc to allocate a refcount for the object, and arranges that destroy will be called with the pointer passed in at destruction. */ GPRAPI grpc_slice grpc_slice_new(void *p, size_t len, void (*destroy)(void *)); -/* Equivalent to grpc_slice_new, but with a separate pointer that is +/** Equivalent to grpc_slice_new, but with a separate pointer that is passed to the destroy function. This function can be useful when the data is part of a larger structure that must be destroyed when the data is no longer needed. */ @@ -66,17 +54,30 @@ GPRAPI grpc_slice grpc_slice_new_with_user_data(void *p, size_t len, void (*destroy)(void *), void *user_data); -/* Equivalent to grpc_slice_new, but with a two argument destroy function that +/** Equivalent to grpc_slice_new, but with a two argument destroy function that also takes the slice length. */ GPRAPI grpc_slice grpc_slice_new_with_len(void *p, size_t len, void (*destroy)(void *, size_t)); -/* Equivalent to grpc_slice_new(malloc(len), len, free), but saves one malloc() +/** Equivalent to grpc_slice_new(malloc(len), len, free), but saves one malloc() call. Aborts if malloc() fails. */ GPRAPI grpc_slice grpc_slice_malloc(size_t length); +GPRAPI grpc_slice grpc_slice_malloc_large(size_t length); + +#define GRPC_SLICE_MALLOC(len) \ + ((len) <= GRPC_SLICE_INLINED_SIZE \ + ? (grpc_slice){.refcount = NULL, \ + .data.inlined = {.length = (uint8_t)(len)}} \ + : grpc_slice_malloc_large((len))) + +/** Intern a slice: + + The return value for two invocations of this function with the same sequence + of bytes is a slice which points to the same memory. */ +GPRAPI grpc_slice grpc_slice_intern(grpc_slice slice); -/* Create a slice by copying a string. +/** Create a slice by copying a string. Does not preserve null terminators. Equivalent to: size_t len = strlen(source); @@ -84,47 +85,89 @@ GPRAPI grpc_slice grpc_slice_malloc(size_t length); memcpy(slice->data, source, len); */ GPRAPI grpc_slice grpc_slice_from_copied_string(const char *source); -/* Create a slice by copying a buffer. +/** Create a slice by copying a buffer. Equivalent to: grpc_slice slice = grpc_slice_malloc(len); memcpy(slice->data, source, len); */ GPRAPI grpc_slice grpc_slice_from_copied_buffer(const char *source, size_t len); -/* Create a slice pointing to constant memory */ +/** Create a slice pointing to constant memory */ GPRAPI grpc_slice grpc_slice_from_static_string(const char *source); -/* Return a result slice derived from s, which shares a ref count with s, where - result.data==s.data+begin, and result.length==end-begin. - The ref count of s is increased by one. +/** Create a slice pointing to constant memory */ +GPRAPI grpc_slice grpc_slice_from_static_buffer(const void *source, size_t len); + +/** Return a result slice derived from s, which shares a ref count with \a s, + where result.data==s.data+begin, and result.length==end-begin. The ref count + of \a s is increased by one. Do not assign result back to \a s. Requires s initialized, begin <= end, begin <= s.length, and end <= source->length. */ GPRAPI grpc_slice grpc_slice_sub(grpc_slice s, size_t begin, size_t end); -/* The same as grpc_slice_sub, but without altering the ref count */ +/** The same as grpc_slice_sub, but without altering the ref count */ GPRAPI grpc_slice grpc_slice_sub_no_ref(grpc_slice s, size_t begin, size_t end); -/* Splits s into two: modifies s to be s[0:split], and returns a new slice, +/** Splits s into two: modifies s to be s[0:split], and returns a new slice, sharing a refcount with s, that contains s[split:s.length]. Requires s intialized, split <= s.length */ GPRAPI grpc_slice grpc_slice_split_tail(grpc_slice *s, size_t split); -/* Splits s into two: modifies s to be s[split:s.length], and returns a new +typedef enum { + GRPC_SLICE_REF_TAIL = 1, + GRPC_SLICE_REF_HEAD = 2, + GRPC_SLICE_REF_BOTH = 1 + 2 +} grpc_slice_ref_whom; + +/** The same as grpc_slice_split_tail, but with an option to skip altering + * refcounts (grpc_slice_split_tail_maybe_ref(..., true) is equivalent to + * grpc_slice_split_tail(...)) */ +GPRAPI grpc_slice grpc_slice_split_tail_maybe_ref(grpc_slice *s, size_t split, + grpc_slice_ref_whom ref_whom); + +/** Splits s into two: modifies s to be s[split:s.length], and returns a new slice, sharing a refcount with s, that contains s[0:split]. Requires s intialized, split <= s.length */ GPRAPI grpc_slice grpc_slice_split_head(grpc_slice *s, size_t split); -GPRAPI grpc_slice gpr_empty_slice(void); +GPRAPI grpc_slice grpc_empty_slice(void); + +GPRAPI uint32_t grpc_slice_default_hash_impl(grpc_slice s); +GPRAPI int grpc_slice_default_eq_impl(grpc_slice a, grpc_slice b); -/* Returns <0 if a < b, ==0 if a == b, >0 if a > b +GPRAPI int grpc_slice_eq(grpc_slice a, grpc_slice b); + +/** Returns <0 if a < b, ==0 if a == b, >0 if a > b The order is arbitrary, and is not guaranteed to be stable across different versions of the API. */ GPRAPI int grpc_slice_cmp(grpc_slice a, grpc_slice b); GPRAPI int grpc_slice_str_cmp(grpc_slice a, const char *b); +GPRAPI int grpc_slice_buf_cmp(grpc_slice a, const void *b, size_t blen); + +/** return non-zero if the first blen bytes of a are equal to b */ +GPRAPI int grpc_slice_buf_start_eq(grpc_slice a, const void *b, size_t blen); + +/** return the index of the last instance of \a c in \a s, or -1 if not found */ +GPRAPI int grpc_slice_rchr(grpc_slice s, char c); +GPRAPI int grpc_slice_chr(grpc_slice s, char c); + +/** return the index of the first occurance of \a needle in \a haystack, or -1 + if it's not found */ +GPRAPI int grpc_slice_slice(grpc_slice haystack, grpc_slice needle); -/* Do two slices point at the same memory, with the same length +GPRAPI uint32_t grpc_slice_hash(grpc_slice s); + +/** Do two slices point at the same memory, with the same length If a or b is inlined, actually compares data */ GPRAPI int grpc_slice_is_equivalent(grpc_slice a, grpc_slice b); +/** Return a slice pointing to newly allocated memory that has the same contents + * as \a s */ +GPRAPI grpc_slice grpc_slice_dup(grpc_slice a); + +/** Return a copy of slice as a C string. Offers no protection against embedded + NULL's. Returned string must be freed with gpr_free. */ +GPRAPI char *grpc_slice_to_c_string(grpc_slice s); + #ifdef __cplusplus } #endif diff --git a/Sources/CgRPC/grpc/slice_buffer.h b/Sources/CgRPC/grpc/slice_buffer.h index f1de653af..de4b86f77 100644 --- a/Sources/CgRPC/grpc/slice_buffer.h +++ b/Sources/CgRPC/grpc/slice_buffer.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -40,15 +25,15 @@ extern "C" { #endif -/* initialize a slice buffer */ +/** initialize a slice buffer */ GPRAPI void grpc_slice_buffer_init(grpc_slice_buffer *sb); -/* destroy a slice buffer - unrefs any held elements */ +/** destroy a slice buffer - unrefs any held elements */ GPRAPI void grpc_slice_buffer_destroy(grpc_slice_buffer *sb); -/* Add an element to a slice buffer - takes ownership of the slice. +/** Add an element to a slice buffer - takes ownership of the slice. This function is allowed to concatenate the passed in slice to the end of some other slice if desired by the slice buffer. */ GPRAPI void grpc_slice_buffer_add(grpc_slice_buffer *sb, grpc_slice slice); -/* add an element to a slice buffer - takes ownership of the slice and returns +/** add an element to a slice buffer - takes ownership of the slice and returns the index of the slice. Guarantees that the slice will not be concatenated at the end of another slice (i.e. the data for this slice will begin at the first byte of the @@ -59,26 +44,37 @@ GPRAPI size_t grpc_slice_buffer_add_indexed(grpc_slice_buffer *sb, grpc_slice slice); GPRAPI void grpc_slice_buffer_addn(grpc_slice_buffer *sb, grpc_slice *slices, size_t n); -/* add a very small (less than 8 bytes) amount of data to the end of a slice +/** add a very small (less than 8 bytes) amount of data to the end of a slice buffer: returns a pointer into which to add the data */ GPRAPI uint8_t *grpc_slice_buffer_tiny_add(grpc_slice_buffer *sb, size_t len); -/* pop the last buffer, but don't unref it */ +/** pop the last buffer, but don't unref it */ GPRAPI void grpc_slice_buffer_pop(grpc_slice_buffer *sb); -/* clear a slice buffer, unref all elements */ +/** clear a slice buffer, unref all elements */ GPRAPI void grpc_slice_buffer_reset_and_unref(grpc_slice_buffer *sb); -/* swap the contents of two slice buffers */ +/** swap the contents of two slice buffers */ GPRAPI void grpc_slice_buffer_swap(grpc_slice_buffer *a, grpc_slice_buffer *b); -/* move all of the elements of src into dst */ +/** move all of the elements of src into dst */ GPRAPI void grpc_slice_buffer_move_into(grpc_slice_buffer *src, grpc_slice_buffer *dst); -/* remove n bytes from the end of a slice buffer */ +/** remove n bytes from the end of a slice buffer */ GPRAPI void grpc_slice_buffer_trim_end(grpc_slice_buffer *src, size_t n, grpc_slice_buffer *garbage); -/* move the first n bytes of src into dst */ +/** move the first n bytes of src into dst */ GPRAPI void grpc_slice_buffer_move_first(grpc_slice_buffer *src, size_t n, grpc_slice_buffer *dst); -/* take the first slice in the slice buffer */ +/** move the first n bytes of src into dst without adding references */ +GPRAPI void grpc_slice_buffer_move_first_no_ref(grpc_slice_buffer *src, + size_t n, + grpc_slice_buffer *dst); +/** move the first n bytes of src into dst (copying them) */ +GPRAPI void grpc_slice_buffer_move_first_into_buffer(grpc_exec_ctx *exec_ctx, + grpc_slice_buffer *src, + size_t n, void *dst); +/** take the first slice in the slice buffer */ GPRAPI grpc_slice grpc_slice_buffer_take_first(grpc_slice_buffer *src); +/** undo the above with (a possibly different) \a slice */ +GPRAPI void grpc_slice_buffer_undo_take_first(grpc_slice_buffer *src, + grpc_slice slice); #ifdef __cplusplus } diff --git a/Sources/CgRPC/grpc/status.h b/Sources/CgRPC/grpc/status.h index 67719b5e2..9d8f50bc0 100644 --- a/Sources/CgRPC/grpc/status.h +++ b/Sources/CgRPC/grpc/status.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/grpc/support/alloc.h b/Sources/CgRPC/grpc/support/alloc.h index 7209bec01..4b59e137f 100644 --- a/Sources/CgRPC/grpc/support/alloc.h +++ b/Sources/CgRPC/grpc/support/alloc.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -44,28 +29,32 @@ extern "C" { typedef struct gpr_allocation_functions { void *(*malloc_fn)(size_t size); + void *(*zalloc_fn)(size_t size); /** if NULL, uses malloc_fn then memset */ void *(*realloc_fn)(void *ptr, size_t size); void (*free_fn)(void *ptr); } gpr_allocation_functions; -/* malloc. +/** malloc. * If size==0, always returns NULL. Otherwise this function never returns NULL. * The pointer returned is suitably aligned for any kind of variable it could * contain. */ GPRAPI void *gpr_malloc(size_t size); -/* free */ +/** like malloc, but zero all bytes before returning them */ +GPRAPI void *gpr_zalloc(size_t size); +/** free */ GPRAPI void gpr_free(void *ptr); -/* realloc, never returns NULL */ +/** realloc, never returns NULL */ GPRAPI void *gpr_realloc(void *p, size_t size); -/* aligned malloc, never returns NULL, will align to 1 << alignment_log */ +/** aligned malloc, never returns NULL, will align to 1 << alignment_log */ GPRAPI void *gpr_malloc_aligned(size_t size, size_t alignment_log); -/* free memory allocated by gpr_malloc_aligned */ +/** free memory allocated by gpr_malloc_aligned */ GPRAPI void gpr_free_aligned(void *ptr); /** Request the family of allocation functions in \a functions be used. NOTE * that this request will be honored in a *best effort* basis and that no - * guarantees are made about the default functions (eg, malloc) being called. */ + * guarantees are made about the default functions (eg, malloc) being called. + * The functions.free_fn implementation must be a no-op for NULL input. */ GPRAPI void gpr_set_allocation_functions(gpr_allocation_functions functions); /** Return the family of allocation functions currently in effect. */ diff --git a/Sources/CgRPC/grpc/support/atm.h b/Sources/CgRPC/grpc/support/atm.h index a52e2fb4e..b3afa520a 100644 --- a/Sources/CgRPC/grpc/support/atm.h +++ b/Sources/CgRPC/grpc/support/atm.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/grpc/support/atm_gcc_atomic.h b/Sources/CgRPC/grpc/support/atm_gcc_atomic.h index ceda791df..e7b5ec402 100644 --- a/Sources/CgRPC/grpc/support/atm_gcc_atomic.h +++ b/Sources/CgRPC/grpc/support/atm_gcc_atomic.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/grpc/support/atm_gcc_sync.h b/Sources/CgRPC/grpc/support/atm_gcc_sync.h index b996d4a73..728489770 100644 --- a/Sources/CgRPC/grpc/support/atm_gcc_sync.h +++ b/Sources/CgRPC/grpc/support/atm_gcc_sync.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/grpc/support/atm_windows.h b/Sources/CgRPC/grpc/support/atm_windows.h index 6aec5b721..554c59a83 100644 --- a/Sources/CgRPC/grpc/support/atm_windows.h +++ b/Sources/CgRPC/grpc/support/atm_windows.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/grpc/support/avl.h b/Sources/CgRPC/grpc/support/avl.h index f5bf32c71..d53ff5d90 100644 --- a/Sources/CgRPC/grpc/support/avl.h +++ b/Sources/CgRPC/grpc/support/avl.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -46,18 +31,23 @@ typedef struct gpr_avl_node { long height; } gpr_avl_node; +/** vtable for the AVL tree + * The optional user_data is propagated from the top level gpr_avl_XXX API. + * From the same API call, multiple vtable functions may be called multiple + * times. + */ typedef struct gpr_avl_vtable { /** destroy a key */ - void (*destroy_key)(void *key); + void (*destroy_key)(void *key, void *user_data); /** copy a key, returning new value */ - void *(*copy_key)(void *key); + void *(*copy_key)(void *key, void *user_data); /** compare key1, key2; return <0 if key1 < key2, >0 if key1 > key2, 0 if key1 == key2 */ - long (*compare_keys)(void *key1, void *key2); + long (*compare_keys)(void *key1, void *key2, void *user_data); /** destroy a value */ - void (*destroy_value)(void *value); + void (*destroy_value)(void *value, void *user_data); /** copy a value */ - void *(*copy_value)(void *value); + void *(*copy_value)(void *value, void *user_data); } gpr_avl_vtable; /** "pointer" to an AVL tree - this is a reference @@ -68,29 +58,36 @@ typedef struct gpr_avl { gpr_avl_node *root; } gpr_avl; -/** create an immutable AVL tree */ +/** Create an immutable AVL tree. */ GPRAPI gpr_avl gpr_avl_create(const gpr_avl_vtable *vtable); -/** add a reference to an existing tree - returns - the tree as a convenience */ -GPRAPI gpr_avl gpr_avl_ref(gpr_avl avl); -/** remove a reference to a tree - destroying it if there - are no references left */ -GPRAPI void gpr_avl_unref(gpr_avl avl); -/** return a new tree with (key, value) added to avl. +/** Add a reference to an existing tree - returns + the tree as a convenience. The optional user_data will be passed to vtable + functions. */ +GPRAPI gpr_avl gpr_avl_ref(gpr_avl avl, void *user_data); +/** Remove a reference to a tree - destroying it if there + are no references left. The optional user_data will be passed to vtable + functions. */ +GPRAPI void gpr_avl_unref(gpr_avl avl, void *user_data); +/** Return a new tree with (key, value) added to avl. implicitly unrefs avl to allow easy chaining. if key exists in avl, the new tree's key entry updated - (i.e. a duplicate is not created) */ -GPRAPI gpr_avl gpr_avl_add(gpr_avl avl, void *key, void *value); -/** return a new tree with key deleted - implicitly unrefs avl to allow easy chaining. */ -GPRAPI gpr_avl gpr_avl_remove(gpr_avl avl, void *key); -/** lookup key, and return the associated value. - does not mutate avl. - returns NULL if key is not found. */ -GPRAPI void *gpr_avl_get(gpr_avl avl, void *key); + (i.e. a duplicate is not created). The optional user_data will be passed to + vtable functions. */ +GPRAPI gpr_avl gpr_avl_add(gpr_avl avl, void *key, void *value, + void *user_data); +/** Return a new tree with key deleted + implicitly unrefs avl to allow easy chaining. The optional user_data will be + passed to vtable functions. */ +GPRAPI gpr_avl gpr_avl_remove(gpr_avl avl, void *key, void *user_data); +/** Lookup key, and return the associated value. + Does not mutate avl. + Returns NULL if key is not found. The optional user_data will be passed to + vtable functions.*/ +GPRAPI void *gpr_avl_get(gpr_avl avl, void *key, void *user_data); /** Return 1 if avl contains key, 0 otherwise; if it has the key, sets *value to - its value*/ -GPRAPI int gpr_avl_maybe_get(gpr_avl avl, void *key, void **value); + its value. THe optional user_data will be passed to vtable functions. */ +GPRAPI int gpr_avl_maybe_get(gpr_avl avl, void *key, void **value, + void *user_data); /** Return 1 if avl is empty, 0 otherwise */ GPRAPI int gpr_avl_is_empty(gpr_avl avl); diff --git a/Sources/CgRPC/grpc/support/cmdline.h b/Sources/CgRPC/grpc/support/cmdline.h index 5b7bc8259..9f46491b3 100644 --- a/Sources/CgRPC/grpc/support/cmdline.h +++ b/Sources/CgRPC/grpc/support/cmdline.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -40,7 +25,7 @@ extern "C" { #endif -/* Simple command line parser. +/** Simple command line parser. Supports flags that can be specified as -foo, --foo, --no-foo, -no-foo, etc And integers, strings that can be specified as -foo=4, -foo blah, etc @@ -68,32 +53,32 @@ extern "C" { typedef struct gpr_cmdline gpr_cmdline; -/* Construct a command line parser: takes a short description of the tool +/** Construct a command line parser: takes a short description of the tool doing the parsing */ GPRAPI gpr_cmdline *gpr_cmdline_create(const char *description); -/* Add an integer parameter, with a name (used on the command line) and some +/** Add an integer parameter, with a name (used on the command line) and some helpful text (used in the command usage) */ GPRAPI void gpr_cmdline_add_int(gpr_cmdline *cl, const char *name, const char *help, int *value); -/* The same, for a boolean flag */ +/** The same, for a boolean flag */ GPRAPI void gpr_cmdline_add_flag(gpr_cmdline *cl, const char *name, const char *help, int *value); -/* And for a string */ +/** And for a string */ GPRAPI void gpr_cmdline_add_string(gpr_cmdline *cl, const char *name, const char *help, char **value); -/* Set a callback for non-named arguments */ +/** Set a callback for non-named arguments */ GPRAPI void gpr_cmdline_on_extra_arg( gpr_cmdline *cl, const char *name, const char *help, void (*on_extra_arg)(void *user_data, const char *arg), void *user_data); -/* Enable surviving failure: default behavior is to exit the process */ +/** Enable surviving failure: default behavior is to exit the process */ GPRAPI void gpr_cmdline_set_survive_failure(gpr_cmdline *cl); -/* Parse the command line; returns 1 on success, on failure either dies +/** Parse the command line; returns 1 on success, on failure either dies (by default) or returns 0 if gpr_cmdline_set_survive_failure() has been called */ GPRAPI int gpr_cmdline_parse(gpr_cmdline *cl, int argc, char **argv); -/* Destroy the parser */ +/** Destroy the parser */ GPRAPI void gpr_cmdline_destroy(gpr_cmdline *cl); -/* Get a string describing usage */ +/** Get a string describing usage */ GPRAPI char *gpr_cmdline_usage_string(gpr_cmdline *cl, const char *argv0); #ifdef __cplusplus diff --git a/Sources/CgRPC/grpc/support/cpu.h b/Sources/CgRPC/grpc/support/cpu.h index 6734feb39..f0e898e85 100644 --- a/Sources/CgRPC/grpc/support/cpu.h +++ b/Sources/CgRPC/grpc/support/cpu.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -40,13 +25,13 @@ extern "C" { #endif -/* Interface providing CPU information for currently running system */ +/** Interface providing CPU information for currently running system */ -/* Return the number of CPU cores on the current system. Will return 0 if +/** Return the number of CPU cores on the current system. Will return 0 if the information is not available. */ GPRAPI unsigned gpr_cpu_num_cores(void); -/* Return the CPU on which the current thread is executing; N.B. This should +/** Return the CPU on which the current thread is executing; N.B. This should be considered advisory only - it is possible that the thread is switched to a different CPU at any time. Returns a value in range [0, gpr_cpu_num_cores() - 1] */ diff --git a/Sources/CgRPC/grpc/support/histogram.h b/Sources/CgRPC/grpc/support/histogram.h index c54503852..8489daa27 100644 --- a/Sources/CgRPC/grpc/support/histogram.h +++ b/Sources/CgRPC/grpc/support/histogram.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -48,7 +33,7 @@ GPRAPI gpr_histogram *gpr_histogram_create(double resolution, GPRAPI void gpr_histogram_destroy(gpr_histogram *h); GPRAPI void gpr_histogram_add(gpr_histogram *h, double x); -/* The following merges the second histogram into the first. It only works +/** The following merges the second histogram into the first. It only works if they have the same buckets and resolution. Returns 0 on failure, 1 on success */ GPRAPI int gpr_histogram_merge(gpr_histogram *dst, const gpr_histogram *src); diff --git a/Sources/CgRPC/grpc/support/host_port.h b/Sources/CgRPC/grpc/support/host_port.h index 15819543a..41592dfe2 100644 --- a/Sources/CgRPC/grpc/support/host_port.h +++ b/Sources/CgRPC/grpc/support/host_port.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -40,7 +25,7 @@ extern "C" { #endif -/* Given a host and port, creates a newly-allocated string of the form +/** Given a host and port, creates a newly-allocated string of the form "host:port" or "[ho:st]:port", depending on whether the host contains colons like an IPv6 literal. If the host is already bracketed, then additional brackets will not be added. @@ -52,7 +37,7 @@ extern "C" { In the unlikely event of an error, returns -1 and sets *out to NULL. */ GPRAPI int gpr_join_host_port(char **out, const char *host, int port); -/* Given a name in the form "host:port" or "[ho:st]:port", split into hostname +/** Given a name in the form "host:port" or "[ho:st]:port", split into hostname and port number, into newly allocated strings, which must later be destroyed using gpr_free(). Return 1 on success, 0 on failure. Guarantees *host and *port == NULL on diff --git a/Sources/CgRPC/grpc/support/log.h b/Sources/CgRPC/grpc/support/log.h index 88346cc9f..a22fb6a6e 100644 --- a/Sources/CgRPC/grpc/support/log.h +++ b/Sources/CgRPC/grpc/support/log.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -44,7 +29,7 @@ extern "C" { #endif -/* GPR log API. +/** GPR log API. Usage (within grpc): @@ -54,7 +39,7 @@ extern "C" { gpr_log(GPR_INFO, "hello world"); gpr_log(GPR_ERROR, "%d %s!!", argument1, argument2); */ -/* The severity of a log message - use the #defines below when calling into +/** The severity of a log message - use the #defines below when calling into gpr_log to additionally supply file and line data */ typedef enum gpr_log_severity { GPR_LOG_SEVERITY_DEBUG, @@ -64,15 +49,15 @@ typedef enum gpr_log_severity { #define GPR_LOG_VERBOSITY_UNSET -1 -/* Returns a string representation of the log severity */ -const char *gpr_log_severity_string(gpr_log_severity severity); +/** Returns a string representation of the log severity */ +GPRAPI const char *gpr_log_severity_string(gpr_log_severity severity); -/* Macros to build log contexts at various severity levels */ +/** Macros to build log contexts at various severity levels */ #define GPR_DEBUG __FILE__, __LINE__, GPR_LOG_SEVERITY_DEBUG #define GPR_INFO __FILE__, __LINE__, GPR_LOG_SEVERITY_INFO #define GPR_ERROR __FILE__, __LINE__, GPR_LOG_SEVERITY_ERROR -/* Log a message. It's advised to use GPR_xxx above to generate the context +/** Log a message. It's advised to use GPR_xxx above to generate the context * for each message */ GPRAPI void gpr_log(const char *file, int line, gpr_log_severity severity, const char *format, ...) GPR_PRINT_FORMAT_CHECK(4, 5); @@ -80,12 +65,12 @@ GPRAPI void gpr_log(const char *file, int line, gpr_log_severity severity, GPRAPI void gpr_log_message(const char *file, int line, gpr_log_severity severity, const char *message); -/* Set global log verbosity */ +/** Set global log verbosity */ GPRAPI void gpr_set_log_verbosity(gpr_log_severity min_severity_to_print); GPRAPI void gpr_log_verbosity_init(); -/* Log overrides: applications can use this API to intercept logging calls +/** Log overrides: applications can use this API to intercept logging calls and use their own implementations */ typedef struct { @@ -98,7 +83,7 @@ typedef struct { typedef void (*gpr_log_func)(gpr_log_func_args *args); GPRAPI void gpr_set_log_function(gpr_log_func func); -/* abort() the process if x is zero, having written a line to the log. +/** abort() the process if x is zero, having written a line to the log. Intended for internal invariants. If the error can be recovered from, without the possibility of corruption, or might best be reflected via diff --git a/Sources/CgRPC/grpc/support/log_windows.h b/Sources/CgRPC/grpc/support/log_windows.h index 12bf8cc1f..b530fd50d 100644 --- a/Sources/CgRPC/grpc/support/log_windows.h +++ b/Sources/CgRPC/grpc/support/log_windows.h @@ -1,44 +1,31 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 GRPC_SUPPORT_LOG_WINDOWS_H #define GRPC_SUPPORT_LOG_WINDOWS_H +#include + #ifdef __cplusplus extern "C" { #endif -/* Returns a string allocated with gpr_malloc that contains a UTF-8 +/** Returns a string allocated with gpr_malloc that contains a UTF-8 * formatted error message, corresponding to the error messageid. * Use in conjunction with GetLastError() et al. */ diff --git a/Sources/CgRPC/grpc/support/port_platform.h b/Sources/CgRPC/grpc/support/port_platform.h index 7465a0e45..26025dcd9 100644 --- a/Sources/CgRPC/grpc/support/port_platform.h +++ b/Sources/CgRPC/grpc/support/port_platform.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/grpc/support/string_util.h b/Sources/CgRPC/grpc/support/string_util.h index 5ab983d15..c4fc159d0 100644 --- a/Sources/CgRPC/grpc/support/string_util.h +++ b/Sources/CgRPC/grpc/support/string_util.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -40,13 +25,13 @@ extern "C" { #endif -/* String utility functions */ +/** String utility functions */ -/* Returns a copy of src that can be passed to gpr_free(). +/** Returns a copy of src that can be passed to gpr_free(). If allocation fails or if src is NULL, returns NULL. */ GPRAPI char *gpr_strdup(const char *src); -/* printf to a newly-allocated string. The set of supported formats may vary +/** printf to a newly-allocated string. The set of supported formats may vary between platforms. On success, returns the number of bytes printed (excluding the final '\0'), diff --git a/Sources/CgRPC/grpc/support/subprocess.h b/Sources/CgRPC/grpc/support/subprocess.h index 2baa43ece..c06e62963 100644 --- a/Sources/CgRPC/grpc/support/subprocess.h +++ b/Sources/CgRPC/grpc/support/subprocess.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -42,13 +27,13 @@ extern "C" { typedef struct gpr_subprocess gpr_subprocess; -/* .exe on windows, empty on unices */ +/** .exe on windows, empty on unices */ GPRAPI const char *gpr_subprocess_binary_extension(); GPRAPI gpr_subprocess *gpr_subprocess_create(int argc, const char **argv); -/* if subprocess has not been joined, kill it */ +/** if subprocess has not been joined, kill it */ GPRAPI void gpr_subprocess_destroy(gpr_subprocess *p); -/* returns exit status; can be called at most once */ +/** returns exit status; can be called at most once */ GPRAPI int gpr_subprocess_join(gpr_subprocess *p); GPRAPI void gpr_subprocess_interrupt(gpr_subprocess *p); diff --git a/Sources/CgRPC/grpc/support/sync.h b/Sources/CgRPC/grpc/support/sync.h index a7bbb38c2..fe8a59a5d 100644 --- a/Sources/CgRPC/grpc/support/sync.h +++ b/Sources/CgRPC/grpc/support/sync.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -41,49 +26,49 @@ extern "C" { #endif -/* --- Mutex interface --- +/** --- Mutex interface --- At most one thread may hold an exclusive lock on a mutex at any given time. Actions taken by a thread that holds a mutex exclusively happen after actions taken by all previous holders of the mutex. Variables of type gpr_mu are uninitialized when first declared. */ -/* Initialize *mu. Requires: *mu uninitialized. */ +/** Initialize *mu. Requires: *mu uninitialized. */ GPRAPI void gpr_mu_init(gpr_mu *mu); -/* Cause *mu no longer to be initialized, freeing any memory in use. Requires: +/** Cause *mu no longer to be initialized, freeing any memory in use. Requires: *mu initialized; no other concurrent operation on *mu. */ GPRAPI void gpr_mu_destroy(gpr_mu *mu); -/* Wait until no thread has a lock on *mu, cause the calling thread to own an +/** Wait until no thread has a lock on *mu, cause the calling thread to own an exclusive lock on *mu, then return. May block indefinitely or crash if the calling thread has a lock on *mu. Requires: *mu initialized. */ GPRAPI void gpr_mu_lock(gpr_mu *mu); -/* Release an exclusive lock on *mu held by the calling thread. Requires: *mu +/** Release an exclusive lock on *mu held by the calling thread. Requires: *mu initialized; the calling thread holds an exclusive lock on *mu. */ GPRAPI void gpr_mu_unlock(gpr_mu *mu); -/* Without blocking, attempt to acquire an exclusive lock on *mu for the +/** Without blocking, attempt to acquire an exclusive lock on *mu for the calling thread, then return non-zero iff success. Fail, if any thread holds the lock; succeeds with high probability if no thread holds the lock. Requires: *mu initialized. */ GPRAPI int gpr_mu_trylock(gpr_mu *mu); -/* --- Condition variable interface --- +/** --- Condition variable interface --- A while-loop should be used with gpr_cv_wait() when waiting for conditions to become true. See the example below. Variables of type gpr_cv are uninitialized when first declared. */ -/* Initialize *cv. Requires: *cv uninitialized. */ +/** Initialize *cv. Requires: *cv uninitialized. */ GPRAPI void gpr_cv_init(gpr_cv *cv); -/* Cause *cv no longer to be initialized, freeing any memory in use. Requires: +/** Cause *cv no longer to be initialized, freeing any memory in use. Requires: *cv initialized; no other concurrent operation on *cv.*/ GPRAPI void gpr_cv_destroy(gpr_cv *cv); -/* Atomically release *mu and wait on *cv. When the calling thread is woken +/** Atomically release *mu and wait on *cv. When the calling thread is woken from *cv or the deadline abs_deadline is exceeded, execute gpr_mu_lock(mu) and return whether the deadline was exceeded. Use abs_deadline==gpr_inf_future for no deadline. abs_deadline can be either @@ -92,79 +77,83 @@ GPRAPI void gpr_cv_destroy(gpr_cv *cv); holds an exclusive lock on *mu. */ GPRAPI int gpr_cv_wait(gpr_cv *cv, gpr_mu *mu, gpr_timespec abs_deadline); -/* If any threads are waiting on *cv, wake at least one. +/** If any threads are waiting on *cv, wake at least one. Clients may treat this as an optimization of gpr_cv_broadcast() for use in the case where waking more than one waiter is not useful. Requires: *cv initialized. */ GPRAPI void gpr_cv_signal(gpr_cv *cv); -/* Wake all threads waiting on *cv. Requires: *cv initialized. */ +/** Wake all threads waiting on *cv. Requires: *cv initialized. */ GPRAPI void gpr_cv_broadcast(gpr_cv *cv); -/* --- One-time initialization --- +/** --- One-time initialization --- gpr_once must be declared with static storage class, and initialized with GPR_ONCE_INIT. e.g., static gpr_once once_var = GPR_ONCE_INIT; */ -/* Ensure that (*init_routine)() has been called exactly once (for the +/** Ensure that (*init_routine)() has been called exactly once (for the specified gpr_once instance) and then return. If multiple threads call gpr_once() on the same gpr_once instance, one of them will call (*init_routine)(), and the others will block until that call finishes.*/ GPRAPI void gpr_once_init(gpr_once *once, void (*init_routine)(void)); -/* --- One-time event notification --- +/** --- One-time event notification --- These operations act on a gpr_event, which should be initialized with gpr_ev_init(), or with GPR_EVENT_INIT if static, e.g., static gpr_event event_var = GPR_EVENT_INIT; It requires no destruction. */ -/* Initialize *ev. */ +/** Initialize *ev. */ GPRAPI void gpr_event_init(gpr_event *ev); -/* Set *ev so that gpr_event_get() and gpr_event_wait() will return value. +/** Set *ev so that gpr_event_get() and gpr_event_wait() will return value. Requires: *ev initialized; value != NULL; no prior or concurrent calls to gpr_event_set(ev, ...) since initialization. */ GPRAPI void gpr_event_set(gpr_event *ev, void *value); -/* Return the value set by gpr_event_set(ev, ...), or NULL if no such call has +/** Return the value set by gpr_event_set(ev, ...), or NULL if no such call has completed. If the result is non-NULL, all operations that occurred prior to the gpr_event_set(ev, ...) set will be visible after this call returns. Requires: *ev initialized. This operation is faster than acquiring a mutex on most platforms. */ GPRAPI void *gpr_event_get(gpr_event *ev); -/* Wait until *ev is set by gpr_event_set(ev, ...), or abs_deadline is +/** Wait until *ev is set by gpr_event_set(ev, ...), or abs_deadline is exceeded, then return gpr_event_get(ev). Requires: *ev initialized. Use abs_deadline==gpr_inf_future for no deadline. When the event has been signalled before the call, this operation is faster than acquiring a mutex on most platforms. */ GPRAPI void *gpr_event_wait(gpr_event *ev, gpr_timespec abs_deadline); -/* --- Reference counting --- +/** --- Reference counting --- These calls act on the type gpr_refcount. It requires no destruction. */ -/* Initialize *r to value n. */ +/** Initialize *r to value n. */ GPRAPI void gpr_ref_init(gpr_refcount *r, int n); -/* Increment the reference count *r. Requires *r initialized. */ +/** Increment the reference count *r. Requires *r initialized. */ GPRAPI void gpr_ref(gpr_refcount *r); -/* Increment the reference count *r. Requires *r initialized. +/** Increment the reference count *r. Requires *r initialized. Crashes if refcount is zero */ GPRAPI void gpr_ref_non_zero(gpr_refcount *r); -/* Increment the reference count *r by n. Requires *r initialized, n > 0. */ +/** Increment the reference count *r by n. Requires *r initialized, n > 0. */ GPRAPI void gpr_refn(gpr_refcount *r, int n); -/* Decrement the reference count *r and return non-zero iff it has reached +/** Decrement the reference count *r and return non-zero iff it has reached zero. . Requires *r initialized. */ GPRAPI int gpr_unref(gpr_refcount *r); -/* --- Stats counters --- +/** Return non-zero iff the reference count of *r is one, and thus is owned + by exactly one object. */ +GPRAPI int gpr_ref_is_unique(gpr_refcount *r); + +/** --- Stats counters --- These calls act on the integral type gpr_stats_counter. It requires no destruction. Static instances may be initialized with @@ -172,16 +161,16 @@ GPRAPI int gpr_unref(gpr_refcount *r); Beware: These operations do not imply memory barriers. Do not use them to synchronize other events. */ -/* Initialize *c to the value n. */ +/** Initialize *c to the value n. */ GPRAPI void gpr_stats_init(gpr_stats_counter *c, intptr_t n); -/* *c += inc. Requires: *c initialized. */ +/** *c += inc. Requires: *c initialized. */ GPRAPI void gpr_stats_inc(gpr_stats_counter *c, intptr_t inc); -/* Return *c. Requires: *c initialized. */ +/** Return *c. Requires: *c initialized. */ GPRAPI intptr_t gpr_stats_read(const gpr_stats_counter *c); -/* ==================Example use of interface=================== +/** ==================Example use of interface=================== A producer-consumer queue of up to N integers, illustrating the use of the calls in this interface. */ #if 0 diff --git a/Sources/CgRPC/grpc/support/sync_generic.h b/Sources/CgRPC/grpc/support/sync_generic.h index d74b5d8e8..970b7a5d9 100644 --- a/Sources/CgRPC/grpc/support/sync_generic.h +++ b/Sources/CgRPC/grpc/support/sync_generic.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/grpc/support/sync_posix.h b/Sources/CgRPC/grpc/support/sync_posix.h index 19aca03f0..482a6004e 100644 --- a/Sources/CgRPC/grpc/support/sync_posix.h +++ b/Sources/CgRPC/grpc/support/sync_posix.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/grpc/support/sync_windows.h b/Sources/CgRPC/grpc/support/sync_windows.h index 0624e0c3b..90ce8b776 100644 --- a/Sources/CgRPC/grpc/support/sync_windows.h +++ b/Sources/CgRPC/grpc/support/sync_windows.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/grpc/support/thd.h b/Sources/CgRPC/grpc/support/thd.h index 051428879..25bd8f123 100644 --- a/Sources/CgRPC/grpc/support/thd.h +++ b/Sources/CgRPC/grpc/support/thd.h @@ -1,39 +1,24 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 GRPC_SUPPORT_THD_H #define GRPC_SUPPORT_THD_H -/* Thread interface for GPR. +/** Thread interface for GPR. Types gpr_thd_id a thread identifier. @@ -50,37 +35,37 @@ extern "C" { typedef uintptr_t gpr_thd_id; -/* Thread creation options. */ +/** Thread creation options. */ typedef struct { - int flags; /* Opaque field. Get and set with accessors below. */ + int flags; /** Opaque field. Get and set with accessors below. */ } gpr_thd_options; -/* Create a new thread running (*thd_body)(arg) and place its thread identifier +/** Create a new thread running (*thd_body)(arg) and place its thread identifier in *t, and return true. If there are insufficient resources, return false. If options==NULL, default options are used. The thread is immediately runnable, and exits when (*thd_body)() returns. */ GPRAPI int gpr_thd_new(gpr_thd_id *t, void (*thd_body)(void *arg), void *arg, const gpr_thd_options *options); -/* Return a gpr_thd_options struct with all fields set to defaults. */ +/** Return a gpr_thd_options struct with all fields set to defaults. */ GPRAPI gpr_thd_options gpr_thd_options_default(void); -/* Set the thread to become detached on startup - this is the default. */ +/** Set the thread to become detached on startup - this is the default. */ GPRAPI void gpr_thd_options_set_detached(gpr_thd_options *options); -/* Set the thread to become joinable - mutually exclusive with detached. */ +/** Set the thread to become joinable - mutually exclusive with detached. */ GPRAPI void gpr_thd_options_set_joinable(gpr_thd_options *options); -/* Returns non-zero if the option detached is set. */ +/** Returns non-zero if the option detached is set. */ GPRAPI int gpr_thd_options_is_detached(const gpr_thd_options *options); -/* Returns non-zero if the option joinable is set. */ +/** Returns non-zero if the option joinable is set. */ GPRAPI int gpr_thd_options_is_joinable(const gpr_thd_options *options); -/* Returns the identifier of the current thread. */ +/** Returns the identifier of the current thread. */ GPRAPI gpr_thd_id gpr_thd_currentid(void); -/* Blocks until the specified thread properly terminates. +/** Blocks until the specified thread properly terminates. Calling this on a detached thread has unpredictable results. */ GPRAPI void gpr_thd_join(gpr_thd_id t); diff --git a/Sources/CgRPC/grpc/support/time.h b/Sources/CgRPC/grpc/support/time.h index 66bcfca6e..62d354aaf 100644 --- a/Sources/CgRPC/grpc/support/time.h +++ b/Sources/CgRPC/grpc/support/time.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -43,11 +28,11 @@ extern "C" { #endif -/* Time constants. */ +/** Time constants. */ GPRAPI gpr_timespec -gpr_time_0(gpr_clock_type type); /* The zero time interval. */ -GPRAPI gpr_timespec gpr_inf_future(gpr_clock_type type); /* The far future */ -GPRAPI gpr_timespec gpr_inf_past(gpr_clock_type type); /* The far past. */ +gpr_time_0(gpr_clock_type type); /** The zero time interval. */ +GPRAPI gpr_timespec gpr_inf_future(gpr_clock_type type); /** The far future */ +GPRAPI gpr_timespec gpr_inf_past(gpr_clock_type type); /** The far past. */ #define GPR_MS_PER_SEC 1000 #define GPR_US_PER_SEC 1000000 @@ -56,28 +41,28 @@ GPRAPI gpr_timespec gpr_inf_past(gpr_clock_type type); /* The far past. */ #define GPR_NS_PER_US 1000 #define GPR_US_PER_MS 1000 -/* initialize time subsystem */ +/** initialize time subsystem */ GPRAPI void gpr_time_init(void); -/* Return the current time measured from the given clocks epoch. */ +/** Return the current time measured from the given clocks epoch. */ GPRAPI gpr_timespec gpr_now(gpr_clock_type clock); -/* Convert a timespec from one clock to another */ +/** Convert a timespec from one clock to another */ GPRAPI gpr_timespec gpr_convert_clock_type(gpr_timespec t, gpr_clock_type target_clock); -/* Return -ve, 0, or +ve according to whether a < b, a == b, or a > b +/** Return -ve, 0, or +ve according to whether a < b, a == b, or a > b respectively. */ GPRAPI int gpr_time_cmp(gpr_timespec a, gpr_timespec b); GPRAPI gpr_timespec gpr_time_max(gpr_timespec a, gpr_timespec b); GPRAPI gpr_timespec gpr_time_min(gpr_timespec a, gpr_timespec b); -/* Add and subtract times. Calculations saturate at infinities. */ +/** Add and subtract times. Calculations saturate at infinities. */ GPRAPI gpr_timespec gpr_time_add(gpr_timespec a, gpr_timespec b); GPRAPI gpr_timespec gpr_time_sub(gpr_timespec a, gpr_timespec b); -/* Return a timespec representing a given number of time units. INT64_MIN is +/** Return a timespec representing a given number of time units. INT64_MIN is interpreted as gpr_inf_past, and INT64_MAX as gpr_inf_future. */ GPRAPI gpr_timespec gpr_time_from_micros(int64_t x, gpr_clock_type clock_type); GPRAPI gpr_timespec gpr_time_from_nanos(int64_t x, gpr_clock_type clock_type); @@ -88,12 +73,12 @@ GPRAPI gpr_timespec gpr_time_from_hours(int64_t x, gpr_clock_type clock_type); GPRAPI int32_t gpr_time_to_millis(gpr_timespec timespec); -/* Return 1 if two times are equal or within threshold of each other, +/** Return 1 if two times are equal or within threshold of each other, 0 otherwise */ GPRAPI int gpr_time_similar(gpr_timespec a, gpr_timespec b, gpr_timespec threshold); -/* Sleep until at least 'until' - an absolute timeout */ +/** Sleep until at least 'until' - an absolute timeout */ GPRAPI void gpr_sleep_until(gpr_timespec until); GPRAPI double gpr_timespec_to_micros(gpr_timespec t); diff --git a/Sources/CgRPC/grpc/support/tls.h b/Sources/CgRPC/grpc/support/tls.h index a45e1f0a4..8519a8350 100644 --- a/Sources/CgRPC/grpc/support/tls.h +++ b/Sources/CgRPC/grpc/support/tls.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -36,7 +21,7 @@ #include -/* Thread local storage. +/** Thread local storage. A minimal wrapper that should be implementable across many compilers, and implementable efficiently across most modern compilers. @@ -58,7 +43,7 @@ gpr_tls_set(&foo, new_value); Accessing a thread local: - current_value = gpr_tls_get(&foo, value); + current_value = gpr_tls_get(&foo); ALL functions here may be implemented as macros. */ diff --git a/Sources/CgRPC/grpc/support/tls_gcc.h b/Sources/CgRPC/grpc/support/tls_gcc.h index a47275f6f..e6d8c0144 100644 --- a/Sources/CgRPC/grpc/support/tls_gcc.h +++ b/Sources/CgRPC/grpc/support/tls_gcc.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -38,7 +23,7 @@ #include -/* Thread local storage based on gcc compiler primitives. +/** Thread local storage based on gcc compiler primitives. #include tls.h to use this - and see that file for documentation */ #ifndef NDEBUG @@ -58,7 +43,7 @@ struct gpr_gcc_thread_local { *((tls)->inited) = true; \ } while (0) -/* It is allowed to call gpr_tls_init after gpr_tls_destroy is called. */ +/** It is allowed to call gpr_tls_init after gpr_tls_destroy is called. */ #define gpr_tls_destroy(tls) \ do { \ GPR_ASSERT(*((tls)->inited)); \ diff --git a/Sources/CgRPC/grpc/support/tls_msvc.h b/Sources/CgRPC/grpc/support/tls_msvc.h index efc653b4e..e5f2205fc 100644 --- a/Sources/CgRPC/grpc/support/tls_msvc.h +++ b/Sources/CgRPC/grpc/support/tls_msvc.h @@ -1,40 +1,25 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 GRPC_SUPPORT_TLS_MSVC_H #define GRPC_SUPPORT_TLS_MSVC_H -/* Thread local storage based on ms visual c compiler primitives. +/** Thread local storage based on ms visual c compiler primitives. #include tls.h to use this - and see that file for documentation */ struct gpr_msvc_thread_local { diff --git a/Sources/CgRPC/grpc/support/tls_pthread.h b/Sources/CgRPC/grpc/support/tls_pthread.h index e681da2ec..a68b45569 100644 --- a/Sources/CgRPC/grpc/support/tls_pthread.h +++ b/Sources/CgRPC/grpc/support/tls_pthread.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -37,7 +22,7 @@ #include /* for GPR_ASSERT */ #include -/* Thread local storage based on pthread library calls. +/** Thread local storage based on pthread library calls. #include tls.h to use this - and see that file for documentation */ struct gpr_pthread_thread_local { diff --git a/Sources/CgRPC/grpc/support/useful.h b/Sources/CgRPC/grpc/support/useful.h index 003e096cf..bd66d3bb2 100644 --- a/Sources/CgRPC/grpc/support/useful.h +++ b/Sources/CgRPC/grpc/support/useful.h @@ -1,45 +1,30 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 GRPC_SUPPORT_USEFUL_H #define GRPC_SUPPORT_USEFUL_H -/* useful macros that don't belong anywhere else */ +/** useful macros that don't belong anywhere else */ #define GPR_MIN(a, b) ((a) < (b) ? (a) : (b)) #define GPR_MAX(a, b) ((a) > (b) ? (a) : (b)) #define GPR_CLAMP(a, min, max) ((a) < (min) ? (min) : (a) > (max) ? (max) : (a)) -/* rotl, rotr assume x is unsigned */ +/** rotl, rotr assume x is unsigned */ #define GPR_ROTL(x, n) (((x) << (n)) | ((x) >> (sizeof(x) * 8 - (n)))) #define GPR_ROTR(x, n) (((x) >> (n)) | ((x) << (sizeof(x) * 8 - (n)))) @@ -74,4 +59,7 @@ #define GPR_ICMP(a, b) ((a) < (b) ? -1 : ((a) > (b) ? 1 : 0)) +#define GPR_HASH_POINTER(x, range) \ + ((((size_t)x) >> 4) ^ (((size_t)x) >> 9) ^ (((size_t)x) >> 14)) % (range) + #endif /* GRPC_SUPPORT_USEFUL_H */ diff --git a/Sources/CgRPC/grpc/support/workaround_list.h b/Sources/CgRPC/grpc/support/workaround_list.h new file mode 100644 index 000000000..e28dfa143 --- /dev/null +++ b/Sources/CgRPC/grpc/support/workaround_list.h @@ -0,0 +1,31 @@ +/* + * + * 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 GRPC_SUPPORT_WORKAROUND_LIST_H +#define GRPC_SUPPORT_WORKAROUND_LIST_H + +/* The list of IDs of server workarounds currently maintained by gRPC. For + * explanation and detailed descriptions of workarounds, see + * /doc/workarounds.md + */ +typedef enum { + GRPC_WORKAROUND_ID_CRONET_COMPRESSION = 0, + GRPC_MAX_WORKAROUND_ID +} grpc_workaround_list; + +#endif /* GRPC_SUPPORT_WORKAROUND_LIST_H */ diff --git a/Sources/CgRPC/include/CgRPC.h b/Sources/CgRPC/include/CgRPC.h index 07a241a81..734dc0754 100644 --- a/Sources/CgRPC/include/CgRPC.h +++ b/Sources/CgRPC/include/CgRPC.h @@ -109,6 +109,9 @@ void grpc_init(); void grpc_shutdown(); const char *grpc_version_string(); +// helper +void cgrpc_free_copied_string(const char *string); + // channel support cgrpc_channel *cgrpc_channel_create(const char *address); cgrpc_channel *cgrpc_channel_create_secure(const char *address, @@ -147,8 +150,8 @@ cgrpc_completion_queue *cgrpc_handler_get_completion_queue(cgrpc_handler *h); grpc_call_error cgrpc_handler_request_call(cgrpc_handler *h, cgrpc_metadata_array *metadata, long tag); -const char *cgrpc_handler_host(cgrpc_handler *h); -const char *cgrpc_handler_method(cgrpc_handler *h); +const char *cgrpc_handler_copy_host(cgrpc_handler *h); +const char *cgrpc_handler_copy_method(cgrpc_handler *h); const char *cgrpc_handler_call_peer(cgrpc_handler *h); // call support @@ -165,8 +168,8 @@ void cgrpc_operations_add_operation(cgrpc_operations *call, cgrpc_observer *obse cgrpc_metadata_array *cgrpc_metadata_array_create(); void cgrpc_metadata_array_destroy(cgrpc_metadata_array *array); size_t cgrpc_metadata_array_get_count(cgrpc_metadata_array *array); -const char *cgrpc_metadata_array_get_key_at_index(cgrpc_metadata_array *array, size_t index); -const char *cgrpc_metadata_array_get_value_at_index(cgrpc_metadata_array *array, size_t index); +const char *cgrpc_metadata_array_copy_key_at_index(cgrpc_metadata_array *array, size_t index); +const char *cgrpc_metadata_array_copy_value_at_index(cgrpc_metadata_array *array, size_t index); void cgrpc_metadata_array_move_metadata(cgrpc_metadata_array *dest, cgrpc_metadata_array *src); void cgrpc_metadata_array_append_metadata(cgrpc_metadata_array *metadata, const char *key, const char *value); @@ -233,7 +236,7 @@ cgrpc_metadata_array *cgrpc_observer_recv_status_on_client_get_metadata long cgrpc_observer_recv_status_on_client_get_status (cgrpc_observer_recv_status_on_client *observer); -const char *cgrpc_observer_recv_status_on_client_get_status_details +const char *cgrpc_observer_recv_status_on_client_copy_status_details (cgrpc_observer_recv_status_on_client *observer); // GRPC_OP_RECV_CLOSE_ON_SERVER diff --git a/Sources/CgRPC/shim/byte_buffer.c b/Sources/CgRPC/shim/byte_buffer.c index 6510cb624..afda33f94 100644 --- a/Sources/CgRPC/shim/byte_buffer.c +++ b/Sources/CgRPC/shim/byte_buffer.c @@ -18,6 +18,7 @@ #include "internal.h" #include "cgrpc.h" +#include #include #include #include diff --git a/Sources/CgRPC/shim/call.c b/Sources/CgRPC/shim/call.c index 6b25d435d..85008b757 100644 --- a/Sources/CgRPC/shim/call.c +++ b/Sources/CgRPC/shim/call.c @@ -21,7 +21,7 @@ #include void cgrpc_call_destroy(cgrpc_call *call) { - grpc_call_destroy(call->call); + //grpc_call_destroy(call->call); free(call); } diff --git a/Sources/CgRPC/shim/cgrpc.h b/Sources/CgRPC/shim/cgrpc.h index 07a241a81..734dc0754 100644 --- a/Sources/CgRPC/shim/cgrpc.h +++ b/Sources/CgRPC/shim/cgrpc.h @@ -109,6 +109,9 @@ void grpc_init(); void grpc_shutdown(); const char *grpc_version_string(); +// helper +void cgrpc_free_copied_string(const char *string); + // channel support cgrpc_channel *cgrpc_channel_create(const char *address); cgrpc_channel *cgrpc_channel_create_secure(const char *address, @@ -147,8 +150,8 @@ cgrpc_completion_queue *cgrpc_handler_get_completion_queue(cgrpc_handler *h); grpc_call_error cgrpc_handler_request_call(cgrpc_handler *h, cgrpc_metadata_array *metadata, long tag); -const char *cgrpc_handler_host(cgrpc_handler *h); -const char *cgrpc_handler_method(cgrpc_handler *h); +const char *cgrpc_handler_copy_host(cgrpc_handler *h); +const char *cgrpc_handler_copy_method(cgrpc_handler *h); const char *cgrpc_handler_call_peer(cgrpc_handler *h); // call support @@ -165,8 +168,8 @@ void cgrpc_operations_add_operation(cgrpc_operations *call, cgrpc_observer *obse cgrpc_metadata_array *cgrpc_metadata_array_create(); void cgrpc_metadata_array_destroy(cgrpc_metadata_array *array); size_t cgrpc_metadata_array_get_count(cgrpc_metadata_array *array); -const char *cgrpc_metadata_array_get_key_at_index(cgrpc_metadata_array *array, size_t index); -const char *cgrpc_metadata_array_get_value_at_index(cgrpc_metadata_array *array, size_t index); +const char *cgrpc_metadata_array_copy_key_at_index(cgrpc_metadata_array *array, size_t index); +const char *cgrpc_metadata_array_copy_value_at_index(cgrpc_metadata_array *array, size_t index); void cgrpc_metadata_array_move_metadata(cgrpc_metadata_array *dest, cgrpc_metadata_array *src); void cgrpc_metadata_array_append_metadata(cgrpc_metadata_array *metadata, const char *key, const char *value); @@ -233,7 +236,7 @@ cgrpc_metadata_array *cgrpc_observer_recv_status_on_client_get_metadata long cgrpc_observer_recv_status_on_client_get_status (cgrpc_observer_recv_status_on_client *observer); -const char *cgrpc_observer_recv_status_on_client_get_status_details +const char *cgrpc_observer_recv_status_on_client_copy_status_details (cgrpc_observer_recv_status_on_client *observer); // GRPC_OP_RECV_CLOSE_ON_SERVER diff --git a/Sources/CgRPC/shim/channel.c b/Sources/CgRPC/shim/channel.c index 7b1069b72..619433e42 100644 --- a/Sources/CgRPC/shim/channel.c +++ b/Sources/CgRPC/shim/channel.c @@ -29,7 +29,7 @@ cgrpc_channel *cgrpc_channel_create(const char *address) { grpc_channel_args channel_args; channel_args.num_args = 0; c->channel = grpc_insecure_channel_create(address, &channel_args, NULL); - c->completion_queue = grpc_completion_queue_create(NULL); + c->completion_queue = grpc_completion_queue_create_for_next(NULL); return c; } @@ -61,7 +61,7 @@ cgrpc_channel *cgrpc_channel_create_secure(const char *address, grpc_channel_credentials *creds = grpc_ssl_credentials_create(pem_root_certs, NULL, NULL); c->channel = grpc_secure_channel_create(creds, address, channelArgs, NULL); - c->completion_queue = grpc_completion_queue_create(NULL); + c->completion_queue = grpc_completion_queue_create_for_next(NULL); return c; } @@ -76,18 +76,21 @@ void cgrpc_channel_destroy(cgrpc_channel *c) { free(c); } +grpc_slice host_slice; + cgrpc_call *cgrpc_channel_create_call(cgrpc_channel *channel, const char *method, const char *host, double timeout) { // create call + host_slice = grpc_slice_from_copied_string(host); gpr_timespec deadline = cgrpc_deadline_in_seconds_from_now(timeout); grpc_call *channel_call = grpc_channel_create_call(channel->channel, NULL, GRPC_PROPAGATE_DEFAULTS, channel->completion_queue, - method, - host, + grpc_slice_from_copied_string(method), + &host_slice, deadline, NULL); cgrpc_call *call = (cgrpc_call *) malloc(sizeof(cgrpc_call)); diff --git a/Sources/CgRPC/shim/handler.c b/Sources/CgRPC/shim/handler.c index 18695552c..dc61bcbc2 100644 --- a/Sources/CgRPC/shim/handler.c +++ b/Sources/CgRPC/shim/handler.c @@ -27,7 +27,7 @@ cgrpc_handler *cgrpc_handler_create_with_server(cgrpc_server *server) { handler->server = server; grpc_metadata_array_init(&(handler->request_metadata_recv)); grpc_call_details_init(&(handler->call_details)); - handler->completion_queue = grpc_completion_queue_create(NULL); + handler->completion_queue = grpc_completion_queue_create_for_next(NULL); return handler; } @@ -38,17 +38,25 @@ void cgrpc_handler_destroy(cgrpc_handler *h) { grpc_metadata_array_destroy(&(h->request_metadata_recv)); grpc_call_details_destroy(&(h->call_details)); if (h->server_call) { - grpc_call_destroy(h->server_call); + //grpc_call_destroy(h->server_call); } free(h); } -const char *cgrpc_handler_host(cgrpc_handler *h) { - return h->call_details.host; +const char *cgrpc_handler_copy_host(cgrpc_handler *h) { + int length = GRPC_SLICE_LENGTH(h->call_details.host); + char *str = (char *) malloc(length + 1); + memcpy(str, GRPC_SLICE_START_PTR(h->call_details.host), length); + str[length] = 0; + return str; } -const char *cgrpc_handler_method(cgrpc_handler *h) { - return h->call_details.method; +const char *cgrpc_handler_copy_method(cgrpc_handler *h) { + int length = GRPC_SLICE_LENGTH(h->call_details.method); + char *str = (char *) malloc(length + 1); + memcpy(str, GRPC_SLICE_START_PTR(h->call_details.method), length); + str[length] = 0; + return str; } const char *cgrpc_handler_call_peer(cgrpc_handler *h) { diff --git a/Sources/CgRPC/shim/internal.c b/Sources/CgRPC/shim/internal.c index 4ad16e3c6..6f13128fc 100644 --- a/Sources/CgRPC/shim/internal.c +++ b/Sources/CgRPC/shim/internal.c @@ -25,3 +25,7 @@ gpr_timespec cgrpc_deadline_in_seconds_from_now(float seconds) { return gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), gpr_time_from_millis((int64_t)(1e3 * seconds), GPR_TIMESPAN)); } + +void cgrpc_free_copied_string(const char *string) { + free(string); +} \ No newline at end of file diff --git a/Sources/CgRPC/shim/internal.h b/Sources/CgRPC/shim/internal.h index 85a2b5c24..162afb4d7 100644 --- a/Sources/CgRPC/shim/internal.h +++ b/Sources/CgRPC/shim/internal.h @@ -78,7 +78,7 @@ typedef struct { grpc_op_type op_type; grpc_metadata_array trailing_metadata; grpc_status_code status; - char *status_details; + grpc_slice status_details; } cgrpc_observer_send_status_from_server; typedef struct { @@ -95,7 +95,7 @@ typedef struct { grpc_op_type op_type; grpc_metadata_array trailing_metadata_recv; grpc_status_code server_status; - char *server_details; + grpc_slice server_details; size_t server_details_capacity; } cgrpc_observer_recv_status_on_client; diff --git a/Sources/CgRPC/shim/metadata.c b/Sources/CgRPC/shim/metadata.c index cfd683bd5..8dc38324f 100644 --- a/Sources/CgRPC/shim/metadata.c +++ b/Sources/CgRPC/shim/metadata.c @@ -33,12 +33,31 @@ size_t cgrpc_metadata_array_get_count(cgrpc_metadata_array *array) { return array->count; } -const char *cgrpc_metadata_array_get_key_at_index(cgrpc_metadata_array *array, size_t index) { - return array->metadata[index].key; +const char *cgrpc_metadata_array_copy_key_at_index(cgrpc_metadata_array *array, size_t index) { + int length = GRPC_SLICE_LENGTH(array->metadata[index].key); + char *str = (char *) malloc(length + 1); + memcpy(str, GRPC_SLICE_START_PTR(array->metadata[index].key), length); + str[length] = 0; + return str; } -const char *cgrpc_metadata_array_get_value_at_index(cgrpc_metadata_array *array, size_t index) { - return array->metadata[index].value; +const char *cgrpc_metadata_array_copy_value_at_index(cgrpc_metadata_array *array, size_t index) { + int length = GRPC_SLICE_LENGTH(array->metadata[index].value); + char *str = (char *) malloc(length + 1); + memcpy(str, GRPC_SLICE_START_PTR(array->metadata[index].value), length); + str[length] = 0; + return str; +} + +int cgrpc_metadata_array_get_value_length_at_index(cgrpc_metadata_array *array, size_t index) { + return GRPC_SLICE_LENGTH(array->metadata[index].value); + /* + int length = GRPC_SLICE_LENGTH(array->metadata[index].value); + char *str = (char *) malloc(length + 1); + memcpy(str, GRPC_SLICE_START_PTR(array->metadata[index].value), length); + str[length] = 0; + return str; +*/ } void cgrpc_metadata_array_move_metadata(cgrpc_metadata_array *destination, @@ -60,9 +79,8 @@ void cgrpc_metadata_array_append_metadata(cgrpc_metadata_array *metadata, const } if (metadata->count < metadata->capacity) { size_t i = metadata->count; - metadata->metadata[i].key = strdup(key); - metadata->metadata[i].value = strdup(value); - metadata->metadata[i].value_length = strlen(value); + metadata->metadata[i].key = grpc_slice_from_copied_string(key); + metadata->metadata[i].value = grpc_slice_from_copied_string(value); metadata->count++; } } diff --git a/Sources/CgRPC/shim/observers.c b/Sources/CgRPC/shim/observers.c index ca110d078..0159d0b80 100644 --- a/Sources/CgRPC/shim/observers.c +++ b/Sources/CgRPC/shim/observers.c @@ -97,7 +97,7 @@ void cgrpc_observer_apply(cgrpc_observer *observer, grpc_op *op) { } case GRPC_OP_SEND_MESSAGE: { cgrpc_observer_send_message *obs = (cgrpc_observer_send_message *) observer; - op->data.send_message = obs->request_payload; + op->data.send_message.send_message = obs->request_payload; break; } case GRPC_OP_SEND_CLOSE_FROM_CLIENT: { @@ -108,30 +108,29 @@ void cgrpc_observer_apply(cgrpc_observer *observer, grpc_op *op) { op->data.send_status_from_server.trailing_metadata_count = obs->trailing_metadata.count; op->data.send_status_from_server.trailing_metadata = obs->trailing_metadata.metadata; op->data.send_status_from_server.status = obs->status; - op->data.send_status_from_server.status_details = obs->status_details; + op->data.send_status_from_server.status_details = &obs->status_details; break; } case GRPC_OP_RECV_INITIAL_METADATA: { cgrpc_observer_recv_initial_metadata *obs = (cgrpc_observer_recv_initial_metadata *) observer; grpc_metadata_array_init(&(obs->initial_metadata_recv)); - op->data.recv_initial_metadata = &(obs->initial_metadata_recv); + op->data.recv_initial_metadata.recv_initial_metadata = &(obs->initial_metadata_recv); break; } case GRPC_OP_RECV_MESSAGE: { cgrpc_observer_recv_message *obs = (cgrpc_observer_recv_message *) observer; - op->data.recv_message = &(obs->response_payload_recv); + op->data.recv_message.recv_message = &(obs->response_payload_recv); break; } case GRPC_OP_RECV_STATUS_ON_CLIENT: { cgrpc_observer_recv_status_on_client *obs = (cgrpc_observer_recv_status_on_client *) observer; grpc_metadata_array_init(&(obs->trailing_metadata_recv)); obs->server_status = GRPC_STATUS_OK; - obs->server_details = NULL; + obs->server_details = grpc_slice_from_copied_string(""); obs->server_details_capacity = 0; op->data.recv_status_on_client.trailing_metadata = &(obs->trailing_metadata_recv); op->data.recv_status_on_client.status = &(obs->server_status); op->data.recv_status_on_client.status_details = &(obs->server_details); - op->data.recv_status_on_client.status_details_capacity = &(obs->server_details_capacity); break; } case GRPC_OP_RECV_CLOSE_ON_SERVER: { @@ -185,7 +184,6 @@ void cgrpc_observer_destroy(cgrpc_observer *observer) { } case GRPC_OP_RECV_STATUS_ON_CLIENT: { cgrpc_observer_recv_status_on_client *obs = (cgrpc_observer_recv_status_on_client *) observer; - free(obs->server_details); grpc_metadata_array_destroy(&(obs->trailing_metadata_recv)); free(obs); break; @@ -224,7 +222,7 @@ void cgrpc_observer_send_status_from_server_set_status(cgrpc_observer_send_statu } void cgrpc_observer_send_status_from_server_set_status_details(cgrpc_observer_send_status_from_server *observer, const char *statusDetails) { - observer->status_details = strdup(statusDetails); + observer->status_details = grpc_slice_from_copied_string(statusDetails); } cgrpc_metadata_array *cgrpc_observer_recv_status_on_client_get_metadata(cgrpc_observer_recv_status_on_client *observer) { @@ -237,8 +235,12 @@ long cgrpc_observer_recv_status_on_client_get_status(cgrpc_observer_recv_status_ return observer->server_status; } -const char *cgrpc_observer_recv_status_on_client_get_status_details(cgrpc_observer_recv_status_on_client *observer) { - return observer->server_details; +const char *cgrpc_observer_recv_status_on_client_copy_status_details(cgrpc_observer_recv_status_on_client *observer) { + int length = GRPC_SLICE_LENGTH(observer->server_details); + char *str = (char *) malloc(length + 1); + memcpy(str, GRPC_SLICE_START_PTR(observer->server_details), length); + str[length] = 0; + return str; } int cgrpc_observer_recv_close_on_server_get_was_cancelled(cgrpc_observer_recv_close_on_server *observer) { diff --git a/Sources/CgRPC/shim/server.c b/Sources/CgRPC/shim/server.c index 50a587350..184452802 100644 --- a/Sources/CgRPC/shim/server.c +++ b/Sources/CgRPC/shim/server.c @@ -24,7 +24,7 @@ cgrpc_server *cgrpc_server_create(const char *address) { cgrpc_server *server = (cgrpc_server *) malloc(sizeof (cgrpc_server)); server->server = grpc_server_create(NULL, NULL); - server->completion_queue = grpc_completion_queue_create(NULL); + server->completion_queue = grpc_completion_queue_create_for_next(NULL); grpc_server_register_completion_queue(server->server, server->completion_queue, NULL); // prepare the server to listen server->port = grpc_server_add_insecure_http2_port(server->server, address); @@ -36,7 +36,7 @@ cgrpc_server *cgrpc_server_create_secure(const char *address, const char *cert_chain) { cgrpc_server *server = (cgrpc_server *) malloc(sizeof (cgrpc_server)); server->server = grpc_server_create(NULL, NULL); - server->completion_queue = grpc_completion_queue_create(NULL); + server->completion_queue = grpc_completion_queue_create_for_next(NULL); grpc_server_register_completion_queue(server->server, server->completion_queue, NULL); grpc_ssl_pem_key_cert_pair server_credentials; @@ -65,12 +65,14 @@ void cgrpc_server_destroy(cgrpc_server *server) { grpc_server_shutdown_and_notify(server->server, server->completion_queue, cgrpc_create_tag(1000)); - grpc_event completion_event = - grpc_completion_queue_pluck(server->completion_queue, - cgrpc_create_tag(1000), - cgrpc_deadline_in_seconds_from_now(5), - NULL); - assert(completion_event.type == GRPC_OP_COMPLETE); + while (1) { + double timeout = 5; + gpr_timespec deadline = cgrpc_deadline_in_seconds_from_now(timeout); + grpc_event completion_event = grpc_completion_queue_next(server->completion_queue, deadline, NULL); + if (completion_event.type == GRPC_OP_COMPLETE) { + break; + } + } grpc_server_destroy(server->server); server->server = NULL; diff --git a/Sources/CgRPC/src/core/ext/census/aggregation.h b/Sources/CgRPC/src/core/ext/census/aggregation.h index 45f789c77..1ba7953ec 100644 --- a/Sources/CgRPC/src/core/ext/census/aggregation.h +++ b/Sources/CgRPC/src/core/ext/census/aggregation.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/ext/census/base_resources.c b/Sources/CgRPC/src/core/ext/census/base_resources.c index f9aa4bb99..2114bf04c 100644 --- a/Sources/CgRPC/src/core/ext/census/base_resources.c +++ b/Sources/CgRPC/src/core/ext/census/base_resources.c @@ -1,32 +1,17 @@ /* - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/ext/census/base_resources.h b/Sources/CgRPC/src/core/ext/census/base_resources.h index e5a7696db..78a4d1fae 100644 --- a/Sources/CgRPC/src/core/ext/census/base_resources.h +++ b/Sources/CgRPC/src/core/ext/census/base_resources.h @@ -1,32 +1,17 @@ /* - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/ext/census/census_interface.h b/Sources/CgRPC/src/core/ext/census/census_interface.h index 57e75f56e..a42b68ad6 100644 --- a/Sources/CgRPC/src/core/ext/census/census_interface.h +++ b/Sources/CgRPC/src/core/ext/census/census_interface.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/ext/census/census_rpc_stats.h b/Sources/CgRPC/src/core/ext/census/census_rpc_stats.h index 7e4d8d164..8004ade37 100644 --- a/Sources/CgRPC/src/core/ext/census/census_rpc_stats.h +++ b/Sources/CgRPC/src/core/ext/census/census_rpc_stats.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/ext/census/context.c b/Sources/CgRPC/src/core/ext/census/context.c index 0dfc4ecbf..1019b287d 100644 --- a/Sources/CgRPC/src/core/ext/census/context.c +++ b/Sources/CgRPC/src/core/ext/census/context.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -200,7 +185,7 @@ static bool tag_set_add_tag(struct tag_set *tags, const census_tag *tag, // allocate new memory if needed tags->kvm_size += 2 * CENSUS_MAX_TAG_KV_LEN + TAG_HEADER_SIZE; char *new_kvm = gpr_malloc(tags->kvm_size); - memcpy(new_kvm, tags->kvm, tags->kvm_used); + if (tags->kvm_used > 0) memcpy(new_kvm, tags->kvm, tags->kvm_used); gpr_free(tags->kvm); tags->kvm = new_kvm; } diff --git a/Sources/CgRPC/src/core/ext/census/gen/census.pb.c b/Sources/CgRPC/src/core/ext/census/gen/census.pb.c index 647f0635b..88efa7366 100644 --- a/Sources/CgRPC/src/core/ext/census/gen/census.pb.c +++ b/Sources/CgRPC/src/core/ext/census/gen/census.pb.c @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ /* Automatically generated nanopb constant definitions */ diff --git a/Sources/CgRPC/src/core/ext/census/gen/census.pb.h b/Sources/CgRPC/src/core/ext/census/gen/census.pb.h index dae583f33..5f2833566 100644 --- a/Sources/CgRPC/src/core/ext/census/gen/census.pb.h +++ b/Sources/CgRPC/src/core/ext/census/gen/census.pb.h @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ /* Automatically generated nanopb header */ @@ -292,4 +277,4 @@ extern const pb_field_t google_census_Metric_fields[5]; } /* extern "C" */ #endif -#endif +#endif /* GRPC_CORE_EXT_CENSUS_GEN_CENSUS_PB_H */ diff --git a/Sources/CgRPC/src/core/ext/census/gen/trace_context.pb.c b/Sources/CgRPC/src/core/ext/census/gen/trace_context.pb.c index c8aea324c..b5c3d52a7 100644 --- a/Sources/CgRPC/src/core/ext/census/gen/trace_context.pb.c +++ b/Sources/CgRPC/src/core/ext/census/gen/trace_context.pb.c @@ -1,81 +1,39 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2017 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.3.5-dev */ +/* Generated by nanopb-0.3.7-dev at Fri Jan 20 16:14:22 2017. */ #include "src/core/ext/census/gen/trace_context.pb.h" +/* @@protoc_insertion_point(includes) */ #if PB_PROTO_HEADER_VERSION != 30 #error Regenerate this file with the current version of nanopb generator. #endif -const pb_field_t google_trace_TraceId_fields[3] = { - PB_FIELD( 1, FIXED64 , OPTIONAL, STATIC , FIRST, google_trace_TraceId, hi, hi, 0), - PB_FIELD( 2, FIXED64 , OPTIONAL, STATIC , OTHER, google_trace_TraceId, lo, hi, 0), +const pb_field_t google_trace_TraceContext_fields[5] = { + PB_FIELD( 1, FIXED64 , OPTIONAL, STATIC , FIRST, google_trace_TraceContext, trace_id_hi, trace_id_hi, 0), + PB_FIELD( 2, FIXED64 , OPTIONAL, STATIC , OTHER, google_trace_TraceContext, trace_id_lo, trace_id_hi, 0), + PB_FIELD( 3, FIXED64 , OPTIONAL, STATIC , OTHER, google_trace_TraceContext, span_id, trace_id_lo, 0), + PB_FIELD( 4, FIXED32 , OPTIONAL, STATIC , OTHER, google_trace_TraceContext, span_options, span_id, 0), PB_LAST_FIELD }; -const pb_field_t google_trace_TraceContext_fields[4] = { - PB_FIELD( 1, MESSAGE , OPTIONAL, STATIC , FIRST, google_trace_TraceContext, trace_id, trace_id, &google_trace_TraceId_fields), - PB_FIELD( 2, FIXED64 , OPTIONAL, STATIC , OTHER, google_trace_TraceContext, span_id, trace_id, 0), - PB_FIELD( 3, BOOL , OPTIONAL, STATIC , OTHER, google_trace_TraceContext, is_sampled, span_id, 0), - PB_LAST_FIELD -}; - - -/* Check that field information fits in pb_field_t */ -#if !defined(PB_FIELD_32BIT) -/* If you get an error here, it means that you need to define PB_FIELD_32BIT - * compile-time option. You can do that in pb.h or on compiler command line. - * - * The reason you need to do this is that some of your messages contain tag - * numbers or field sizes that are larger than what can fit in 8 or 16 bit - * field descriptors. - */ -PB_STATIC_ASSERT((pb_membersize(google_trace_TraceContext, trace_id) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_google_trace_TraceId_google_trace_TraceContext) -#endif - -#if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT) -/* If you get an error here, it means that you need to define PB_FIELD_16BIT - * compile-time option. You can do that in pb.h or on compiler command line. - * - * The reason you need to do this is that some of your messages contain tag - * numbers or field sizes that are larger than what can fit in the default - * 8 bit descriptors. - */ -PB_STATIC_ASSERT((pb_membersize(google_trace_TraceContext, trace_id) < 256), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_google_trace_TraceId_google_trace_TraceContext) -#endif - +/* @@protoc_insertion_point(eof) */ diff --git a/Sources/CgRPC/src/core/ext/census/gen/trace_context.pb.h b/Sources/CgRPC/src/core/ext/census/gen/trace_context.pb.h index 263c4c58c..181925dc9 100644 --- a/Sources/CgRPC/src/core/ext/census/gen/trace_context.pb.h +++ b/Sources/CgRPC/src/core/ext/census/gen/trace_context.pb.h @@ -1,41 +1,28 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2017 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.3.5-dev */ +/* Generated by nanopb-0.3.7-dev at Fri Jan 20 16:14:22 2017. */ #ifndef GRPC_CORE_EXT_CENSUS_GEN_TRACE_CONTEXT_PB_H #define GRPC_CORE_EXT_CENSUS_GEN_TRACE_CONTEXT_PB_H #include "third_party/nanopb/pb.h" + +/* @@protoc_insertion_point(includes) */ #if PB_PROTO_HEADER_VERSION != 30 #error Regenerate this file with the current version of nanopb generator. #endif @@ -45,44 +32,35 @@ extern "C" { #endif /* Struct definitions */ -typedef struct _google_trace_TraceId { - bool has_hi; - uint64_t hi; - bool has_lo; - uint64_t lo; -} google_trace_TraceId; - typedef struct _google_trace_TraceContext { - bool has_trace_id; - google_trace_TraceId trace_id; + bool has_trace_id_hi; + uint64_t trace_id_hi; + bool has_trace_id_lo; + uint64_t trace_id_lo; bool has_span_id; uint64_t span_id; - bool has_is_sampled; - bool is_sampled; + bool has_span_options; + uint32_t span_options; +/* @@protoc_insertion_point(struct:google_trace_TraceContext) */ } google_trace_TraceContext; /* Default values for struct fields */ /* Initializer values for message structs */ -#define google_trace_TraceId_init_default {false, 0, false, 0} -#define google_trace_TraceContext_init_default {false, google_trace_TraceId_init_default, false, 0, false, 0} -#define google_trace_TraceId_init_zero {false, 0, false, 0} -#define google_trace_TraceContext_init_zero {false, google_trace_TraceId_init_zero, false, 0, false, 0} +#define google_trace_TraceContext_init_default {false, 0, false, 0, false, 0, false, 0} +#define google_trace_TraceContext_init_zero {false, 0, false, 0, false, 0, false, 0} /* Field tags (for use in manual encoding/decoding) */ -#define google_trace_TraceId_hi_tag 1 -#define google_trace_TraceId_lo_tag 2 -#define google_trace_TraceContext_trace_id_tag 1 -#define google_trace_TraceContext_span_id_tag 2 -#define google_trace_TraceContext_is_sampled_tag 3 +#define google_trace_TraceContext_trace_id_hi_tag 1 +#define google_trace_TraceContext_trace_id_lo_tag 2 +#define google_trace_TraceContext_span_id_tag 3 +#define google_trace_TraceContext_span_options_tag 4 /* Struct field encoding specification for nanopb */ -extern const pb_field_t google_trace_TraceId_fields[3]; -extern const pb_field_t google_trace_TraceContext_fields[4]; +extern const pb_field_t google_trace_TraceContext_fields[5]; /* Maximum encoded size of messages (where known) */ -#define google_trace_TraceId_size 18 -#define google_trace_TraceContext_size 31 +#define google_trace_TraceContext_size 32 /* Message IDs (where set with "msgid" option) */ #ifdef PB_MSGID @@ -95,5 +73,6 @@ extern const pb_field_t google_trace_TraceContext_fields[4]; #ifdef __cplusplus } /* extern "C" */ #endif +/* @@protoc_insertion_point(eof) */ -#endif +#endif /* GRPC_CORE_EXT_CENSUS_GEN_TRACE_CONTEXT_PB_H */ diff --git a/Sources/CgRPC/src/core/ext/census/grpc_context.c b/Sources/CgRPC/src/core/ext/census/grpc_context.c index 98285ab2d..0bfba63a5 100644 --- a/Sources/CgRPC/src/core/ext/census/grpc_context.c +++ b/Sources/CgRPC/src/core/ext/census/grpc_context.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/ext/census/grpc_filter.c b/Sources/CgRPC/src/core/ext/census/grpc_filter.c index 3e8acc85e..13fe2e6b1 100644 --- a/Sources/CgRPC/src/core/ext/census/grpc_filter.c +++ b/Sources/CgRPC/src/core/ext/census/grpc_filter.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -67,26 +52,25 @@ static void extract_and_annotate_method_tag(grpc_metadata_batch *md, channel_data *chand) { grpc_linked_mdelem *m; for (m = md->list.head; m != NULL; m = m->next) { - if (m->md->key == GRPC_MDSTR_PATH) { - gpr_log(GPR_DEBUG, "%s", - (const char *)GRPC_SLICE_START_PTR(m->md->value->slice)); + if (grpc_slice_eq(GRPC_MDKEY(m->md), GRPC_MDSTR_PATH)) { /* Add method tag here */ } } } static void client_mutate_op(grpc_call_element *elem, - grpc_transport_stream_op *op) { + grpc_transport_stream_op_batch *op) { call_data *calld = elem->call_data; channel_data *chand = elem->channel_data; if (op->send_initial_metadata) { - extract_and_annotate_method_tag(op->send_initial_metadata, calld, chand); + extract_and_annotate_method_tag( + op->payload->send_initial_metadata.send_initial_metadata, calld, chand); } } static void client_start_transport_op(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, - grpc_transport_stream_op *op) { + grpc_transport_stream_op_batch *op) { client_mutate_op(elem, op); grpc_call_next_op(exec_ctx, elem, op); } @@ -105,19 +89,22 @@ static void server_on_done_recv(grpc_exec_ctx *exec_ctx, void *ptr, } static void server_mutate_op(grpc_call_element *elem, - grpc_transport_stream_op *op) { + grpc_transport_stream_op_batch *op) { call_data *calld = elem->call_data; if (op->recv_initial_metadata) { /* substitute our callback for the op callback */ - calld->recv_initial_metadata = op->recv_initial_metadata; - calld->on_done_recv = op->recv_initial_metadata_ready; - op->recv_initial_metadata_ready = &calld->finish_recv; + calld->recv_initial_metadata = + op->payload->recv_initial_metadata.recv_initial_metadata; + calld->on_done_recv = + op->payload->recv_initial_metadata.recv_initial_metadata_ready; + op->payload->recv_initial_metadata.recv_initial_metadata_ready = + &calld->finish_recv; } } static void server_start_transport_op(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, - grpc_transport_stream_op *op) { + grpc_transport_stream_op_batch *op) { /* TODO(ctiller): this code fails. I don't know why. I expect it's incomplete, and someone should look at it soon. @@ -129,7 +116,7 @@ static void server_start_transport_op(grpc_exec_ctx *exec_ctx, static grpc_error *client_init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, - grpc_call_element_args *args) { + const grpc_call_element_args *args) { call_data *d = elem->call_data; GPR_ASSERT(d != NULL); memset(d, 0, sizeof(*d)); @@ -140,7 +127,7 @@ static grpc_error *client_init_call_elem(grpc_exec_ctx *exec_ctx, static void client_destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, const grpc_call_final_info *final_info, - void *ignored) { + grpc_closure *ignored) { call_data *d = elem->call_data; GPR_ASSERT(d != NULL); /* TODO(hongyu): record rpc client stats and census_rpc_end_op here */ @@ -148,20 +135,21 @@ static void client_destroy_call_elem(grpc_exec_ctx *exec_ctx, static grpc_error *server_init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, - grpc_call_element_args *args) { + const grpc_call_element_args *args) { call_data *d = elem->call_data; GPR_ASSERT(d != NULL); memset(d, 0, sizeof(*d)); d->start_ts = args->start_time; /* TODO(hongyu): call census_tracing_start_op here. */ - grpc_closure_init(&d->finish_recv, server_on_done_recv, elem); + GRPC_CLOSURE_INIT(&d->finish_recv, server_on_done_recv, elem, + grpc_schedule_on_exec_ctx); return GRPC_ERROR_NONE; } static void server_destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, const grpc_call_final_info *final_info, - void *ignored) { + grpc_closure *ignored) { call_data *d = elem->call_data; GPR_ASSERT(d != NULL); /* TODO(hongyu): record rpc server stats and census_tracing_end_op here */ diff --git a/Sources/CgRPC/src/core/ext/census/grpc_filter.h b/Sources/CgRPC/src/core/ext/census/grpc_filter.h index a39bd8222..baa7bb931 100644 --- a/Sources/CgRPC/src/core/ext/census/grpc_filter.h +++ b/Sources/CgRPC/src/core/ext/census/grpc_filter.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/ext/census/grpc_plugin.c b/Sources/CgRPC/src/core/ext/census/grpc_plugin.c index e43ceafd0..c0efe5afb 100644 --- a/Sources/CgRPC/src/core/ext/census/grpc_plugin.c +++ b/Sources/CgRPC/src/core/ext/census/grpc_plugin.c @@ -1,36 +1,23 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 + #include #include @@ -48,10 +35,11 @@ static bool is_census_enabled(const grpc_channel_args *a) { return a->args[i].value.integer != 0 && census_enabled(); } } - return census_enabled(); + return census_enabled() && !grpc_channel_args_want_minimal_stack(a); } -static bool maybe_add_census_filter(grpc_channel_stack_builder *builder, +static bool maybe_add_census_filter(grpc_exec_ctx *exec_ctx, + grpc_channel_stack_builder *builder, void *arg) { const grpc_channel_args *args = grpc_channel_stack_builder_get_channel_arguments(builder); diff --git a/Sources/CgRPC/src/core/ext/census/initialize.c b/Sources/CgRPC/src/core/ext/census/initialize.c index 55cbbe8e9..165a1221d 100644 --- a/Sources/CgRPC/src/core/ext/census/initialize.c +++ b/Sources/CgRPC/src/core/ext/census/initialize.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/ext/census/intrusive_hash_map.c b/Sources/CgRPC/src/core/ext/census/intrusive_hash_map.c new file mode 100644 index 000000000..793048696 --- /dev/null +++ b/Sources/CgRPC/src/core/ext/census/intrusive_hash_map.c @@ -0,0 +1,305 @@ +/* + * + * Copyright 2017 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 "src/core/ext/census/intrusive_hash_map.h" +#include + +extern bool hm_index_compare(const hm_index *A, const hm_index *B); + +/* Simple hashing function that takes lower 32 bits. */ +static __inline uint32_t chunked_vector_hasher(uint64_t key) { + return (uint32_t)key; +} + +/* Vector chunks are 1MiB divided by pointer size. */ +static const size_t VECTOR_CHUNK_SIZE = (1 << 20) / sizeof(void *); + +/* Helper functions which return buckets from the chunked vector. */ +static __inline void **get_mutable_bucket(const chunked_vector *buckets, + uint32_t index) { + if (index < VECTOR_CHUNK_SIZE) { + return &buckets->first_[index]; + } + size_t rest_index = (index - VECTOR_CHUNK_SIZE) / VECTOR_CHUNK_SIZE; + return &buckets->rest_[rest_index][index % VECTOR_CHUNK_SIZE]; +} + +static __inline void *get_bucket(const chunked_vector *buckets, + uint32_t index) { + if (index < VECTOR_CHUNK_SIZE) { + return buckets->first_[index]; + } + size_t rest_index = (index - VECTOR_CHUNK_SIZE) / VECTOR_CHUNK_SIZE; + return buckets->rest_[rest_index][index % VECTOR_CHUNK_SIZE]; +} + +/* Helper function. */ +static __inline size_t RestSize(const chunked_vector *vec) { + return (vec->size_ <= VECTOR_CHUNK_SIZE) + ? 0 + : (vec->size_ - VECTOR_CHUNK_SIZE - 1) / VECTOR_CHUNK_SIZE + 1; +} + +/* Initialize chunked vector to size of 0. */ +static void chunked_vector_init(chunked_vector *vec) { + vec->size_ = 0; + vec->first_ = NULL; + vec->rest_ = NULL; +} + +/* Clear chunked vector and free all memory that has been allocated then + initialize chunked vector. */ +static void chunked_vector_clear(chunked_vector *vec) { + if (vec->first_ != NULL) { + gpr_free(vec->first_); + } + if (vec->rest_ != NULL) { + size_t rest_size = RestSize(vec); + for (size_t i = 0; i < rest_size; ++i) { + if (vec->rest_[i] != NULL) { + gpr_free(vec->rest_[i]); + } + } + gpr_free(vec->rest_); + } + chunked_vector_init(vec); +} + +/* Clear chunked vector and then resize it to n entries. Allow the first 1MB to + be read w/o an extra cache miss. The rest of the elements are stored in an + array of arrays to avoid large mallocs. */ +static void chunked_vector_reset(chunked_vector *vec, size_t n) { + chunked_vector_clear(vec); + vec->size_ = n; + if (n <= VECTOR_CHUNK_SIZE) { + vec->first_ = (void **)gpr_malloc(sizeof(void *) * n); + memset(vec->first_, 0, sizeof(void *) * n); + } else { + vec->first_ = (void **)gpr_malloc(sizeof(void *) * VECTOR_CHUNK_SIZE); + memset(vec->first_, 0, sizeof(void *) * VECTOR_CHUNK_SIZE); + size_t rest_size = RestSize(vec); + vec->rest_ = (void ***)gpr_malloc(sizeof(void **) * rest_size); + memset(vec->rest_, 0, sizeof(void **) * rest_size); + int i = 0; + n -= VECTOR_CHUNK_SIZE; + while (n > 0) { + size_t this_size = GPR_MIN(n, VECTOR_CHUNK_SIZE); + vec->rest_[i] = (void **)gpr_malloc(sizeof(void *) * this_size); + memset(vec->rest_[i], 0, sizeof(void *) * this_size); + n -= this_size; + ++i; + } + } +} + +void intrusive_hash_map_init(intrusive_hash_map *hash_map, + uint32_t initial_log2_table_size) { + hash_map->log2_num_buckets = initial_log2_table_size; + hash_map->num_items = 0; + uint32_t num_buckets = (uint32_t)1 << hash_map->log2_num_buckets; + hash_map->extend_threshold = num_buckets >> 1; + chunked_vector_init(&hash_map->buckets); + chunked_vector_reset(&hash_map->buckets, num_buckets); + hash_map->hash_mask = num_buckets - 1; +} + +bool intrusive_hash_map_empty(const intrusive_hash_map *hash_map) { + return hash_map->num_items == 0; +} + +size_t intrusive_hash_map_size(const intrusive_hash_map *hash_map) { + return hash_map->num_items; +} + +void intrusive_hash_map_end(const intrusive_hash_map *hash_map, hm_index *idx) { + idx->bucket_index = (uint32_t)hash_map->buckets.size_; + GPR_ASSERT(idx->bucket_index <= UINT32_MAX); + idx->item = NULL; +} + +void intrusive_hash_map_next(const intrusive_hash_map *hash_map, + hm_index *idx) { + idx->item = idx->item->hash_link; + while (idx->item == NULL) { + idx->bucket_index++; + if (idx->bucket_index >= hash_map->buckets.size_) { + /* Reached end of table. */ + idx->item = NULL; + return; + } + idx->item = (hm_item *)get_bucket(&hash_map->buckets, idx->bucket_index); + } +} + +void intrusive_hash_map_begin(const intrusive_hash_map *hash_map, + hm_index *idx) { + for (uint32_t i = 0; i < hash_map->buckets.size_; ++i) { + if (get_bucket(&hash_map->buckets, i) != NULL) { + idx->bucket_index = i; + idx->item = (hm_item *)get_bucket(&hash_map->buckets, i); + return; + } + } + intrusive_hash_map_end(hash_map, idx); +} + +hm_item *intrusive_hash_map_find(const intrusive_hash_map *hash_map, + uint64_t key) { + uint32_t index = chunked_vector_hasher(key) & hash_map->hash_mask; + + hm_item *p = (hm_item *)get_bucket(&hash_map->buckets, index); + while (p != NULL) { + if (key == p->key) { + return p; + } + p = p->hash_link; + } + return NULL; +} + +hm_item *intrusive_hash_map_erase(intrusive_hash_map *hash_map, uint64_t key) { + uint32_t index = chunked_vector_hasher(key) & hash_map->hash_mask; + + hm_item **slot = (hm_item **)get_mutable_bucket(&hash_map->buckets, index); + hm_item *p = *slot; + if (p == NULL) { + return NULL; + } + + if (key == p->key) { + *slot = p->hash_link; + p->hash_link = NULL; + hash_map->num_items--; + return p; + } + + hm_item *prev = p; + p = p->hash_link; + + while (p) { + if (key == p->key) { + prev->hash_link = p->hash_link; + p->hash_link = NULL; + hash_map->num_items--; + return p; + } + prev = p; + p = p->hash_link; + } + return NULL; +} + +/* Insert an hm_item* into the underlying chunked vector. hash_mask is + * array_size-1. Returns true if it is a new hm_item and false if the hm_item + * already existed. + */ +static __inline bool intrusive_hash_map_internal_insert(chunked_vector *buckets, + uint32_t hash_mask, + hm_item *item) { + const uint64_t key = item->key; + uint32_t index = chunked_vector_hasher(key) & hash_mask; + hm_item **slot = (hm_item **)get_mutable_bucket(buckets, index); + hm_item *p = *slot; + item->hash_link = p; + + /* Check to see if key already exists. */ + while (p) { + if (p->key == key) { + return false; + } + p = p->hash_link; + } + + /* Otherwise add new entry. */ + *slot = item; + return true; +} + +/* Extend the allocated number of elements in the hash map by a factor of 2. */ +void intrusive_hash_map_extend(intrusive_hash_map *hash_map) { + uint32_t new_log2_num_buckets = 1 + hash_map->log2_num_buckets; + uint32_t new_num_buckets = (uint32_t)1 << new_log2_num_buckets; + GPR_ASSERT(new_num_buckets <= UINT32_MAX && new_num_buckets > 0); + chunked_vector new_buckets; + chunked_vector_init(&new_buckets); + chunked_vector_reset(&new_buckets, new_num_buckets); + uint32_t new_hash_mask = new_num_buckets - 1; + + hm_index cur_idx; + hm_index end_idx; + intrusive_hash_map_end(hash_map, &end_idx); + intrusive_hash_map_begin(hash_map, &cur_idx); + while (!hm_index_compare(&cur_idx, &end_idx)) { + hm_item *new_item = cur_idx.item; + intrusive_hash_map_next(hash_map, &cur_idx); + intrusive_hash_map_internal_insert(&new_buckets, new_hash_mask, new_item); + } + + /* Set values for new chunked_vector. extend_threshold is set to half of + * new_num_buckets. */ + hash_map->log2_num_buckets = new_log2_num_buckets; + chunked_vector_clear(&hash_map->buckets); + hash_map->buckets = new_buckets; + hash_map->hash_mask = new_hash_mask; + hash_map->extend_threshold = new_num_buckets >> 1; +} + +/* Insert a hm_item. The hm_item must remain live until it is removed from the + table. This object does not take the ownership of hm_item. The caller must + remove this hm_item from the table and delete it before this table is + deleted. If hm_item exists already num_items is not changed. */ +bool intrusive_hash_map_insert(intrusive_hash_map *hash_map, hm_item *item) { + if (hash_map->num_items >= hash_map->extend_threshold) { + intrusive_hash_map_extend(hash_map); + } + if (intrusive_hash_map_internal_insert(&hash_map->buckets, + hash_map->hash_mask, item)) { + hash_map->num_items++; + return true; + } + return false; +} + +void intrusive_hash_map_clear(intrusive_hash_map *hash_map, + void (*free_object)(void *)) { + hm_index cur; + hm_index end; + intrusive_hash_map_end(hash_map, &end); + intrusive_hash_map_begin(hash_map, &cur); + + while (!hm_index_compare(&cur, &end)) { + hm_index next = cur; + intrusive_hash_map_next(hash_map, &next); + if (cur.item != NULL) { + hm_item *item = intrusive_hash_map_erase(hash_map, cur.item->key); + (*free_object)((void *)item); + gpr_free(item); + } + cur = next; + } +} + +void intrusive_hash_map_free(intrusive_hash_map *hash_map, + void (*free_object)(void *)) { + intrusive_hash_map_clear(hash_map, (*free_object)); + hash_map->num_items = 0; + hash_map->extend_threshold = 0; + hash_map->log2_num_buckets = 0; + hash_map->hash_mask = 0; + chunked_vector_clear(&hash_map->buckets); +} diff --git a/Sources/CgRPC/src/core/ext/census/intrusive_hash_map.h b/Sources/CgRPC/src/core/ext/census/intrusive_hash_map.h new file mode 100644 index 000000000..f50de4fab --- /dev/null +++ b/Sources/CgRPC/src/core/ext/census/intrusive_hash_map.h @@ -0,0 +1,152 @@ +/* + * + * Copyright 2017 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 GRPC_CORE_EXT_CENSUS_INTRUSIVE_HASH_MAP_H +#define GRPC_CORE_EXT_CENSUS_INTRUSIVE_HASH_MAP_H + +#include "src/core/ext/census/intrusive_hash_map_internal.h" + +/* intrusive_hash_map is a fast chained hash table. This hash map is faster than + * a dense hash map when the application calls insert and erase more often than + * find. When the workload is dominated by find() a dense hash map may be + * faster. + * + * intrusive_hash_map uses an intrusive header placed within a user defined + * struct. The header field IHM_key MUST be set to a valid value before + * insertion into the hash map or undefined behavior may occur. The header field + * IHM_hash_link MUST to be set to NULL initially. + * + * EXAMPLE USAGE: + * + * typedef struct string_item { + * INTRUSIVE_HASH_MAP_HEADER; + * // User data. + * char *str_buf; + * uint16_t len; + * } string_item; + * + * static string_item *make_string_item(uint64_t key, const char *buf, + * uint16_t len) { + * string_item *item = (string_item *)gpr_malloc(sizeof(string_item)); + * item->IHM_key = key; + * item->IHM_hash_link = NULL; + * item->len = len; + * item->str_buf = (char *)malloc(len); + * memcpy(item->str_buf, buf, len); + * return item; + * } + * + * intrusive_hash_map hash_map; + * intrusive_hash_map_init(&hash_map, 4); + * string_item *new_item1 = make_string_item(10, "test1", 5); + * bool ok = intrusive_hash_map_insert(&hash_map, (hm_item *)new_item1); + * + * string_item *item1 = + * (string_item *)intrusive_hash_map_find(&hash_map, 10); + */ + +/* Hash map item. Stores key and a pointer to the actual object. A user defined + * version of this can be passed in provided the first 2 entries (key and + * hash_link) are the same. These entries must be first in the user defined + * struct. Pointer to struct will need to be cast as (hm_item *) when passed to + * hash map. This allows it to be intrusive. */ +typedef struct hm_item { + uint64_t key; + struct hm_item *hash_link; + /* Optional user defined data after this. */ +} hm_item; + +/* Macro provided for ease of use. This must be first in the user defined + * struct (i.e. uint64_t key and hm_item * must be the first two elements in + * that order). */ +#define INTRUSIVE_HASH_MAP_HEADER \ + uint64_t IHM_key; \ + struct hm_item *IHM_hash_link + +/* Index struct which acts as a pseudo-iterator within the hash map. */ +typedef struct hm_index { + uint32_t bucket_index; // hash map bucket index. + hm_item *item; // Pointer to hm_item within the hash map. +} hm_index; + +/* Returns true if two hm_indices point to the same object within the hash map + * and false otherwise. */ +__inline bool hm_index_compare(const hm_index *A, const hm_index *B) { + return (A->item == B->item && A->bucket_index == B->bucket_index); +} + +/* + * Helper functions for iterating over the hash map. + */ + +/* On return idx will contain an invalid index which is always equal to + * hash_map->buckets.size_ */ +void intrusive_hash_map_end(const intrusive_hash_map *hash_map, hm_index *idx); + +/* Iterates index to the next valid entry in the hash map and stores the + * index within idx. If end of table is reached, idx will contain the same + * values as if intrusive_hash_map_end() was called. */ +void intrusive_hash_map_next(const intrusive_hash_map *hash_map, hm_index *idx); + +/* On return, idx will contain the index of the first non-null entry in the hash + * map. If the hash map is empty, idx will contain the same values as if + * intrusive_hash_map_end() was called. */ +void intrusive_hash_map_begin(const intrusive_hash_map *hash_map, + hm_index *idx); + +/* Initialize intrusive hash map data structure. This must be called before + * the hash map can be used. The initial size of an intrusive hash map will be + * 2^initial_log2_map_size (valid range is [0, 31]). */ +void intrusive_hash_map_init(intrusive_hash_map *hash_map, + uint32_t initial_log2_map_size); + +/* Returns true if the hash map is empty and false otherwise. */ +bool intrusive_hash_map_empty(const intrusive_hash_map *hash_map); + +/* Returns the number of elements currently in the hash map. */ +size_t intrusive_hash_map_size(const intrusive_hash_map *hash_map); + +/* Find a hm_item within the hash map by key. Returns NULL if item was not + * found. */ +hm_item *intrusive_hash_map_find(const intrusive_hash_map *hash_map, + uint64_t key); + +/* Erase the hm_item that corresponds with key. If the hm_item is found, return + * the pointer to the hm_item. Else returns NULL. */ +hm_item *intrusive_hash_map_erase(intrusive_hash_map *hash_map, uint64_t key); + +/* Attempts to insert a new hm_item into the hash map. If an element with the + * same key already exists, it will not insert the new item and return false. + * Otherwise, it will insert the new item and return true. */ +bool intrusive_hash_map_insert(intrusive_hash_map *hash_map, hm_item *item); + +/* Clears entire contents of the hash map, but leaves internal data structure + * untouched. Second argument takes a function pointer to a function that will + * free the object designated by the user and pointed to by hash_map->value. */ +void intrusive_hash_map_clear(intrusive_hash_map *hash_map, + void (*free_object)(void *)); + +/* Erase all contents of hash map and free the memory. Hash map is invalid + * after calling this function and cannot be used until it has been + * reinitialized (intrusive_hash_map_init()). This function takes a function + * pointer to a function that will free the object designated by the user and + * pointed to by hash_map->value. */ +void intrusive_hash_map_free(intrusive_hash_map *hash_map, + void (*free_object)(void *)); + +#endif /* GRPC_CORE_EXT_CENSUS_INTRUSIVE_HASH_MAP_H */ diff --git a/Sources/CgRPC/src/core/ext/census/intrusive_hash_map_internal.h b/Sources/CgRPC/src/core/ext/census/intrusive_hash_map_internal.h new file mode 100644 index 000000000..e9c81fc85 --- /dev/null +++ b/Sources/CgRPC/src/core/ext/census/intrusive_hash_map_internal.h @@ -0,0 +1,48 @@ +/* + * + * Copyright 2017 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 GRPC_CORE_EXT_CENSUS_INTRUSIVE_HASH_MAP_INTERNAL_H +#define GRPC_CORE_EXT_CENSUS_INTRUSIVE_HASH_MAP_INTERNAL_H + +#include +#include +#include +#include + +/* The chunked vector is a data structure that allocates buckets for use in the + * hash map. ChunkedVector is logically equivalent to T*[N] (cast void* as + * T*). It's internally implemented as an array of 1MB arrays to avoid + * allocating large consecutive memory chunks. This is an internal data + * structure that should never be accessed directly. */ +typedef struct chunked_vector { + size_t size_; + void **first_; + void ***rest_; +} chunked_vector; + +/* Core intrusive hash map data structure. All internal elements are managed by + * functions and should not be altered manually. */ +typedef struct intrusive_hash_map { + uint32_t num_items; + uint32_t extend_threshold; + uint32_t log2_num_buckets; + uint32_t hash_mask; + chunked_vector buckets; +} intrusive_hash_map; + +#endif /* GRPC_CORE_EXT_CENSUS_INTRUSIVE_HASH_MAP_INTERNAL_H */ diff --git a/Sources/CgRPC/src/core/ext/census/mlog.c b/Sources/CgRPC/src/core/ext/census/mlog.c index 698b7096a..937ceb101 100644 --- a/Sources/CgRPC/src/core/ext/census/mlog.c +++ b/Sources/CgRPC/src/core/ext/census/mlog.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/ext/census/mlog.h b/Sources/CgRPC/src/core/ext/census/mlog.h index 18805ad99..6f3125944 100644 --- a/Sources/CgRPC/src/core/ext/census/mlog.h +++ b/Sources/CgRPC/src/core/ext/census/mlog.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/ext/census/operation.c b/Sources/CgRPC/src/core/ext/census/operation.c index 5c5870437..be88ac74e 100644 --- a/Sources/CgRPC/src/core/ext/census/operation.c +++ b/Sources/CgRPC/src/core/ext/census/operation.c @@ -1,32 +1,17 @@ /* - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/ext/census/placeholders.c b/Sources/CgRPC/src/core/ext/census/placeholders.c index 9f99c5bdc..bed9837ee 100644 --- a/Sources/CgRPC/src/core/ext/census/placeholders.c +++ b/Sources/CgRPC/src/core/ext/census/placeholders.c @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/ext/census/resource.c b/Sources/CgRPC/src/core/ext/census/resource.c index ed44f004f..1a676f0e1 100644 --- a/Sources/CgRPC/src/core/ext/census/resource.c +++ b/Sources/CgRPC/src/core/ext/census/resource.c @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -223,7 +208,9 @@ size_t allocate_resource(void) { if (n_resources == n_defined_resources) { size_t new_n_resources = n_resources ? n_resources * 2 : 2; resource **new_resources = gpr_malloc(new_n_resources * sizeof(resource *)); - memcpy(new_resources, resources, n_resources * sizeof(resource *)); + if (n_resources != 0) { + memcpy(new_resources, resources, n_resources * sizeof(resource *)); + } memset(new_resources + n_resources, 0, (new_n_resources - n_resources) * sizeof(resource *)); gpr_free(resources); diff --git a/Sources/CgRPC/src/core/ext/census/resource.h b/Sources/CgRPC/src/core/ext/census/resource.h index 591bff07d..b8bda2c72 100644 --- a/Sources/CgRPC/src/core/ext/census/resource.h +++ b/Sources/CgRPC/src/core/ext/census/resource.h @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/ext/census/rpc_metric_id.h b/Sources/CgRPC/src/core/ext/census/rpc_metric_id.h index 888ec500a..ea493d728 100644 --- a/Sources/CgRPC/src/core/ext/census/rpc_metric_id.h +++ b/Sources/CgRPC/src/core/ext/census/rpc_metric_id.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/ext/census/trace_context.c b/Sources/CgRPC/src/core/ext/census/trace_context.c index fbb20d344..af92ae6d9 100644 --- a/Sources/CgRPC/src/core/ext/census/trace_context.c +++ b/Sources/CgRPC/src/core/ext/census/trace_context.c @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -73,7 +58,7 @@ bool decode_trace_context(google_trace_TraceContext *ctxt, uint8_t *buffer, } // check fields - if (!ctxt->has_trace_id) { + if (!ctxt->has_trace_id_hi || !ctxt->has_trace_id_lo) { gpr_log(GPR_DEBUG, "Invalid TraceContext: missing trace_id"); return false; } diff --git a/Sources/CgRPC/src/core/ext/census/trace_context.h b/Sources/CgRPC/src/core/ext/census/trace_context.h index 1cb5e26ea..a7233e6a2 100644 --- a/Sources/CgRPC/src/core/ext/census/trace_context.h +++ b/Sources/CgRPC/src/core/ext/census/trace_context.h @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -38,6 +23,9 @@ #include "src/core/ext/census/gen/trace_context.pb.h" +/* Span option flags. */ +#define SPAN_OPTIONS_IS_SAMPLED 0x01 + /* Maximum number of bytes required to encode a TraceContext (31) 1 byte for trace_id field 1 byte for trace_id length diff --git a/Sources/CgRPC/src/core/ext/census/trace_label.h b/Sources/CgRPC/src/core/ext/census/trace_label.h new file mode 100644 index 000000000..97ce399eb --- /dev/null +++ b/Sources/CgRPC/src/core/ext/census/trace_label.h @@ -0,0 +1,46 @@ +/* + * + * Copyright 2016 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 GRPC_CORE_EXT_CENSUS_TRACE_LABEL_H +#define GRPC_CORE_EXT_CENSUS_TRACE_LABEL_H + +#include "src/core/ext/census/trace_string.h" + +/* Trace label (key/value pair) stores a label name and the label value. The + value can be one of trace_string/int64_t/bool. */ +typedef struct trace_label { + trace_string key; + enum label_type { + /* Unknown value for debugging/error purposes */ + LABEL_UNKNOWN = 0, + /* A string value */ + LABEL_STRING = 1, + /* An integer value. */ + LABEL_INT = 2, + /* A boolean value. */ + LABEL_BOOL = 3, + } value_type; + + union value { + trace_string label_str; + int64_t label_int; + bool label_bool; + } value; +} trace_label; + +#endif /* GRPC_CORE_EXT_CENSUS_TRACE_LABEL_H */ diff --git a/Sources/CgRPC/src/core/ext/census/trace_propagation.h b/Sources/CgRPC/src/core/ext/census/trace_propagation.h new file mode 100644 index 000000000..eecfcb7d0 --- /dev/null +++ b/Sources/CgRPC/src/core/ext/census/trace_propagation.h @@ -0,0 +1,48 @@ +/* + * + * Copyright 2016 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 GRPC_CORE_EXT_CENSUS_TRACE_PROPAGATION_H +#define GRPC_CORE_EXT_CENSUS_TRACE_PROPAGATION_H + +#include "src/core/ext/census/tracing.h" + +/* Encoding and decoding functions for receiving and sending trace contexts + over the wire. Only RPC libraries should be calling these + functions. These functions return the number of bytes encoded/decoded + (0 if a failure has occurred). buf_size indicates the size of the + input/output buffer. trace_span_context is a struct that includes the + trace ID, span ID, and a set of option flags (is_sampled, etc.). */ + +/* Converts a span context to a binary byte buffer. */ +size_t trace_span_context_to_binary(const trace_span_context *ctxt, + uint8_t *buf, size_t buf_size); + +/* Reads a binary byte buffer and populates a span context structure. */ +size_t binary_to_trace_span_context(const uint8_t *buf, size_t buf_size, + trace_span_context *ctxt); + +/* Converts a span context to an http metadata compatible string. */ +size_t trace_span_context_to_http_format(const trace_span_context *ctxt, + char *buf, size_t buf_size); + +/* Reads an http metadata compatible string and populates a span context + structure. */ +size_t http_format_to_trace_span_context(const char *buf, size_t buf_size, + trace_span_context *ctxt); + +#endif /* GRPC_CORE_EXT_CENSUS_TRACE_PROPAGATION_H */ diff --git a/Sources/CgRPC/src/core/ext/census/trace_status.h b/Sources/CgRPC/src/core/ext/census/trace_status.h new file mode 100644 index 000000000..dd83d3f72 --- /dev/null +++ b/Sources/CgRPC/src/core/ext/census/trace_status.h @@ -0,0 +1,30 @@ +/* + * + * Copyright 2016 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 GRPC_CORE_EXT_CENSUS_TRACE_STATUS_H +#define GRPC_CORE_EXT_CENSUS_TRACE_STATUS_H + +#include "src/core/ext/census/trace_string.h" + +/* Stores a status code and status message for a trace. */ +typedef struct trace_status { + int64_t errorCode; + trace_string errorMessage; +} trace_status; + +#endif /* GRPC_CORE_EXT_CENSUS_TRACE_STATUS_H */ diff --git a/Sources/CgRPC/src/core/ext/census/trace_string.h b/Sources/CgRPC/src/core/ext/census/trace_string.h new file mode 100644 index 000000000..e4da3f590 --- /dev/null +++ b/Sources/CgRPC/src/core/ext/census/trace_string.h @@ -0,0 +1,35 @@ +/* + * + * Copyright 2016 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 GRPC_CORE_EXT_CENSUS_TRACE_STRING_H +#define GRPC_CORE_EXT_CENSUS_TRACE_STRING_H + +#include + +/* String struct for tracing messages. Since this is a C API, we do not have + access to a string class. This is intended for use by higher level + languages which wrap around the C API, as most of them have a string class. + This will also be more efficient when copying, as we have an explicitly + specified length. Also, grpc_slice has reference counting which allows for + interning. */ +typedef struct trace_string { + char *string; + size_t length; +} trace_string; + +#endif /* GRPC_CORE_EXT_CENSUS_TRACE_STRING_H */ diff --git a/Sources/CgRPC/src/core/ext/census/tracing.c b/Sources/CgRPC/src/core/ext/census/tracing.c index 8f0e12296..823c681ab 100644 --- a/Sources/CgRPC/src/core/ext/census/tracing.c +++ b/Sources/CgRPC/src/core/ext/census/tracing.c @@ -1,49 +1,55 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 "src/core/ext/census/tracing.h" +#include "src/core/ext/census/tracing.h" #include +#include +#include +#include "src/core/ext/census/mlog.h" -/* TODO(aveitch): These are all placeholder implementations. */ +void trace_start_span(const trace_span_context *span_ctxt, + const trace_string name, const start_span_options *opts, + trace_span_context *new_span_ctxt, + bool has_remote_parent) { + // Noop implementation. +} -// int census_trace_mask(const census_context *context) { -// return CENSUS_TRACE_MASK_NONE; -// } +void trace_add_span_annotation(const trace_string description, + const trace_label *labels, const size_t n_labels, + trace_span_context *span_ctxt) { + // Noop implementation. +} -// void census_set_trace_mask(int trace_mask) {} +void trace_add_span_network_event_annotation(const trace_string description, + const trace_label *labels, + const size_t n_labels, + const gpr_timespec timestamp, + bool sent, uint64_t id, + trace_span_context *span_ctxt) { + // Noop implementation. +} -// void census_trace_print(census_context *context, uint32_t type, -// const char *buffer, size_t n) {} +void trace_add_span_labels(const trace_label *labels, const size_t n_labels, + trace_span_context *span_ctxt) { + // Noop implementation. +} -// void SetTracerParams(const Params& params); +void trace_end_span(const trace_status *status, trace_span_context *span_ctxt) { + // Noop implementation. +} diff --git a/Sources/CgRPC/src/core/ext/census/tracing.h b/Sources/CgRPC/src/core/ext/census/tracing.h new file mode 100644 index 000000000..038c9e279 --- /dev/null +++ b/Sources/CgRPC/src/core/ext/census/tracing.h @@ -0,0 +1,109 @@ +/* + * + * Copyright 2016 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 GRPC_CORE_EXT_CENSUS_TRACING_H +#define GRPC_CORE_EXT_CENSUS_TRACING_H + +#include +#include +#include "src/core/ext/census/trace_context.h" +#include "src/core/ext/census/trace_label.h" +#include "src/core/ext/census/trace_status.h" + +/* This is the low level tracing API that other languages will interface with. + This is not intended to be accessed by the end-user, therefore it has been + designed with performance in mind rather than ease of use. */ + +/* The tracing level. */ +enum TraceLevel { + /* Annotations on this context will be silently discarded. */ + NO_TRACING = 0, + /* Annotations will not be saved to a persistent store. They will be + available via local APIs only. This setting is not propagated to child + spans. */ + TRANSIENT_TRACING = 1, + /* Annotations are recorded for the entire distributed trace and they are + saved to a persistent store. This setting is propagated to child spans. */ + PERSISTENT_TRACING = 2, +}; + +typedef struct trace_span_context { + /* Trace span context stores Span ID, Trace ID, and option flags. */ + /* Trace ID is 128 bits split into 2 64-bit chunks (hi and lo). */ + uint64_t trace_id_hi; + uint64_t trace_id_lo; + /* Span ID is 64 bits. */ + uint64_t span_id; + /* Span-options is 32-bit value which contains flag options. */ + uint32_t span_options; +} trace_span_context; + +typedef struct start_span_options { + /* If set, this will override the Span.local_start_time for the Span. */ + gpr_timespec local_start_timestamp; + + /* Linked spans can be used to identify spans that are linked to this span in + a different trace. This can be used (for example) in batching operations, + where a single batch handler processes multiple requests from different + traces. If set, points to a list of Spans are linked to the created Span.*/ + trace_span_context *linked_spans; + /* The number of linked spans. */ + size_t n_linked_spans; +} start_span_options; + +/* Create a new child Span (or root if parent is NULL), with parent being the + designated Span. The child span will have the provided name and starting + span options (optional). The bool has_remote_parent marks whether the + context refers to a remote parent span or not. */ +void trace_start_span(const trace_span_context *span_ctxt, + const trace_string name, const start_span_options *opts, + trace_span_context *new_span_ctxt, + bool has_remote_parent); + +/* Add a new Annotation to the Span. Annotations consist of a description + (trace_string) and a set of n labels (trace_label). This can be populated + with arbitrary user data. */ +void trace_add_span_annotation(const trace_string description, + const trace_label *labels, const size_t n_labels, + trace_span_context *span_ctxt); + +/* Add a new NetworkEvent annotation to a Span. This function is only intended + to be used by RPC systems (either client or server), not by higher level + applications. The timestamp type will be system-defined, the sent argument + designates whether this is a network send event (client request, server + reply)or receive (server request, client reply). The id argument corresponds + to Span.Annotation.NetworkEvent.id from the data model, and serves to uniquely + identify each network message. */ +void trace_add_span_network_event(const trace_string description, + const trace_label *labels, + const size_t n_labels, + const gpr_timespec timestamp, bool sent, + uint64_t id, trace_span_context *span_ctxt); + +/* Add a set of labels to the Span. These will correspond to the field +Span.labels in the data model. */ +void trace_add_span_labels(const trace_label *labels, const size_t n_labels, + trace_span_context *span_ctxt); + +/* Mark the end of Span Execution with the given status. Only the timing of the +first EndSpan call for a given Span will be recorded, and implementations are +free to ignore all further calls using the Span. EndSpanOptions can +optionally be NULL. */ +void trace_end_span(const trace_status *status, trace_span_context *span_ctxt); + +#endif /* GRPC_CORE_EXT_CENSUS_TRACING_H */ diff --git a/Sources/CgRPC/src/core/ext/client_channel/client_channel.c b/Sources/CgRPC/src/core/ext/client_channel/client_channel.c deleted file mode 100644 index 9d4633842..000000000 --- a/Sources/CgRPC/src/core/ext/client_channel/client_channel.c +++ /dev/null @@ -1,1212 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include "src/core/ext/client_channel/client_channel.h" - -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "src/core/ext/client_channel/lb_policy_registry.h" -#include "src/core/ext/client_channel/resolver_registry.h" -#include "src/core/ext/client_channel/subchannel.h" -#include "src/core/lib/channel/channel_args.h" -#include "src/core/lib/channel/connected_channel.h" -#include "src/core/lib/channel/deadline_filter.h" -#include "src/core/lib/iomgr/iomgr.h" -#include "src/core/lib/iomgr/polling_entity.h" -#include "src/core/lib/profiling/timers.h" -#include "src/core/lib/support/string.h" -#include "src/core/lib/surface/channel.h" -#include "src/core/lib/transport/connectivity_state.h" -#include "src/core/lib/transport/metadata.h" -#include "src/core/lib/transport/metadata_batch.h" -#include "src/core/lib/transport/service_config.h" -#include "src/core/lib/transport/static_metadata.h" - -/* Client channel implementation */ - -/************************************************************************* - * METHOD-CONFIG TABLE - */ - -typedef enum { - WAIT_FOR_READY_UNSET, - WAIT_FOR_READY_FALSE, - WAIT_FOR_READY_TRUE -} wait_for_ready_value; - -typedef struct method_parameters { - gpr_timespec timeout; - wait_for_ready_value wait_for_ready; -} method_parameters; - -static void *method_parameters_copy(void *value) { - void *new_value = gpr_malloc(sizeof(method_parameters)); - memcpy(new_value, value, sizeof(method_parameters)); - return new_value; -} - -static const grpc_mdstr_hash_table_vtable method_parameters_vtable = { - gpr_free, method_parameters_copy}; - -static void *method_parameters_create_from_json(const grpc_json *json) { - wait_for_ready_value wait_for_ready = WAIT_FOR_READY_UNSET; - gpr_timespec timeout = {0, 0, GPR_TIMESPAN}; - for (grpc_json *field = json->child; field != NULL; field = field->next) { - if (field->key == NULL) continue; - if (strcmp(field->key, "waitForReady") == 0) { - if (wait_for_ready != WAIT_FOR_READY_UNSET) return NULL; // Duplicate. - if (field->type != GRPC_JSON_TRUE && field->type != GRPC_JSON_FALSE) { - return NULL; - } - wait_for_ready = field->type == GRPC_JSON_TRUE ? WAIT_FOR_READY_TRUE - : WAIT_FOR_READY_FALSE; - } else if (strcmp(field->key, "timeout") == 0) { - if (timeout.tv_sec > 0 || timeout.tv_nsec > 0) return NULL; // Duplicate. - if (field->type != GRPC_JSON_STRING) return NULL; - size_t len = strlen(field->value); - if (field->value[len - 1] != 's') return NULL; - char *buf = gpr_strdup(field->value); - buf[len - 1] = '\0'; // Remove trailing 's'. - char *decimal_point = strchr(buf, '.'); - if (decimal_point != NULL) { - *decimal_point = '\0'; - timeout.tv_nsec = gpr_parse_nonnegative_int(decimal_point + 1); - if (timeout.tv_nsec == -1) { - gpr_free(buf); - return NULL; - } - // There should always be exactly 3, 6, or 9 fractional digits. - int multiplier = 1; - switch (strlen(decimal_point + 1)) { - case 9: - break; - case 6: - multiplier *= 1000; - break; - case 3: - multiplier *= 1000000; - break; - default: // Unsupported number of digits. - gpr_free(buf); - return NULL; - } - timeout.tv_nsec *= multiplier; - } - timeout.tv_sec = gpr_parse_nonnegative_int(buf); - if (timeout.tv_sec == -1) return NULL; - gpr_free(buf); - } - } - method_parameters *value = gpr_malloc(sizeof(method_parameters)); - value->timeout = timeout; - value->wait_for_ready = wait_for_ready; - return value; -} - -/************************************************************************* - * CHANNEL-WIDE FUNCTIONS - */ - -typedef struct client_channel_channel_data { - /** resolver for this channel */ - grpc_resolver *resolver; - /** have we started resolving this channel */ - bool started_resolving; - /** client channel factory */ - grpc_client_channel_factory *client_channel_factory; - - /** mutex protecting all variables below in this data structure */ - gpr_mu mu; - /** currently active load balancer */ - char *lb_policy_name; - grpc_lb_policy *lb_policy; - /** service config in JSON form */ - char *service_config_json; - /** maps method names to method_parameters structs */ - grpc_mdstr_hash_table *method_params_table; - /** incoming resolver result - set by resolver.next() */ - grpc_channel_args *resolver_result; - /** a list of closures that are all waiting for config to come in */ - grpc_closure_list waiting_for_config_closures; - /** resolver callback */ - grpc_closure on_resolver_result_changed; - /** connectivity state being tracked */ - grpc_connectivity_state_tracker state_tracker; - /** when an lb_policy arrives, should we try to exit idle */ - bool exit_idle_when_lb_policy_arrives; - /** owning stack */ - grpc_channel_stack *owning_stack; - /** interested parties (owned) */ - grpc_pollset_set *interested_parties; -} channel_data; - -/** We create one watcher for each new lb_policy that is returned from a - resolver, to watch for state changes from the lb_policy. When a state - change is seen, we update the channel, and create a new watcher. */ -typedef struct { - channel_data *chand; - grpc_closure on_changed; - grpc_connectivity_state state; - grpc_lb_policy *lb_policy; -} lb_policy_connectivity_watcher; - -static void watch_lb_policy(grpc_exec_ctx *exec_ctx, channel_data *chand, - grpc_lb_policy *lb_policy, - grpc_connectivity_state current_state); - -static void set_channel_connectivity_state_locked(grpc_exec_ctx *exec_ctx, - channel_data *chand, - grpc_connectivity_state state, - grpc_error *error, - const char *reason) { - if ((state == GRPC_CHANNEL_TRANSIENT_FAILURE || - state == GRPC_CHANNEL_SHUTDOWN) && - chand->lb_policy != NULL) { - /* cancel picks with wait_for_ready=false */ - grpc_lb_policy_cancel_picks( - exec_ctx, chand->lb_policy, - /* mask= */ GRPC_INITIAL_METADATA_WAIT_FOR_READY, - /* check= */ 0, GRPC_ERROR_REF(error)); - } - grpc_connectivity_state_set(exec_ctx, &chand->state_tracker, state, error, - reason); -} - -static void on_lb_policy_state_changed_locked(grpc_exec_ctx *exec_ctx, - lb_policy_connectivity_watcher *w, - grpc_error *error) { - grpc_connectivity_state publish_state = w->state; - /* check if the notification is for a stale policy */ - if (w->lb_policy != w->chand->lb_policy) return; - - if (publish_state == GRPC_CHANNEL_SHUTDOWN && w->chand->resolver != NULL) { - publish_state = GRPC_CHANNEL_TRANSIENT_FAILURE; - grpc_resolver_channel_saw_error(exec_ctx, w->chand->resolver); - GRPC_LB_POLICY_UNREF(exec_ctx, w->chand->lb_policy, "channel"); - w->chand->lb_policy = NULL; - } - set_channel_connectivity_state_locked(exec_ctx, w->chand, publish_state, - GRPC_ERROR_REF(error), "lb_changed"); - if (w->state != GRPC_CHANNEL_SHUTDOWN) { - watch_lb_policy(exec_ctx, w->chand, w->lb_policy, w->state); - } -} - -static void on_lb_policy_state_changed(grpc_exec_ctx *exec_ctx, void *arg, - grpc_error *error) { - lb_policy_connectivity_watcher *w = arg; - - gpr_mu_lock(&w->chand->mu); - on_lb_policy_state_changed_locked(exec_ctx, w, error); - gpr_mu_unlock(&w->chand->mu); - - GRPC_CHANNEL_STACK_UNREF(exec_ctx, w->chand->owning_stack, "watch_lb_policy"); - gpr_free(w); -} - -static void watch_lb_policy(grpc_exec_ctx *exec_ctx, channel_data *chand, - grpc_lb_policy *lb_policy, - grpc_connectivity_state current_state) { - lb_policy_connectivity_watcher *w = gpr_malloc(sizeof(*w)); - GRPC_CHANNEL_STACK_REF(chand->owning_stack, "watch_lb_policy"); - - w->chand = chand; - grpc_closure_init(&w->on_changed, on_lb_policy_state_changed, w); - w->state = current_state; - w->lb_policy = lb_policy; - grpc_lb_policy_notify_on_state_change(exec_ctx, lb_policy, &w->state, - &w->on_changed); -} - -static void on_resolver_result_changed(grpc_exec_ctx *exec_ctx, void *arg, - grpc_error *error) { - channel_data *chand = arg; - char *lb_policy_name = NULL; - grpc_lb_policy *lb_policy = NULL; - grpc_lb_policy *old_lb_policy; - grpc_mdstr_hash_table *method_params_table = NULL; - grpc_connectivity_state state = GRPC_CHANNEL_TRANSIENT_FAILURE; - bool exit_idle = false; - grpc_error *state_error = GRPC_ERROR_CREATE("No load balancing policy"); - char *service_config_json = NULL; - - if (chand->resolver_result != NULL) { - // Find LB policy name. - const grpc_arg *channel_arg = - grpc_channel_args_find(chand->resolver_result, GRPC_ARG_LB_POLICY_NAME); - if (channel_arg != NULL) { - GPR_ASSERT(channel_arg->type == GRPC_ARG_STRING); - lb_policy_name = channel_arg->value.string; - } - // Special case: If all of the addresses are balancer addresses, - // assume that we should use the grpclb policy, regardless of what the - // resolver actually specified. - channel_arg = - grpc_channel_args_find(chand->resolver_result, GRPC_ARG_LB_ADDRESSES); - if (channel_arg != NULL) { - GPR_ASSERT(channel_arg->type == GRPC_ARG_POINTER); - grpc_lb_addresses *addresses = channel_arg->value.pointer.p; - bool found_backend_address = false; - for (size_t i = 0; i < addresses->num_addresses; ++i) { - if (!addresses->addresses[i].is_balancer) { - found_backend_address = true; - break; - } - } - if (!found_backend_address) { - if (lb_policy_name != NULL && strcmp(lb_policy_name, "grpclb") != 0) { - gpr_log(GPR_INFO, - "resolver requested LB policy %s but provided only balancer " - "addresses, no backend addresses -- forcing use of grpclb LB " - "policy", - lb_policy_name); - } - lb_policy_name = "grpclb"; - } - } - // Use pick_first if nothing was specified and we didn't select grpclb - // above. - if (lb_policy_name == NULL) lb_policy_name = "pick_first"; - // Instantiate LB policy. - grpc_lb_policy_args lb_policy_args; - lb_policy_args.args = chand->resolver_result; - lb_policy_args.client_channel_factory = chand->client_channel_factory; - lb_policy = - grpc_lb_policy_create(exec_ctx, lb_policy_name, &lb_policy_args); - if (lb_policy != NULL) { - GRPC_LB_POLICY_REF(lb_policy, "config_change"); - GRPC_ERROR_UNREF(state_error); - state = - grpc_lb_policy_check_connectivity(exec_ctx, lb_policy, &state_error); - } - // Find service config. - channel_arg = - grpc_channel_args_find(chand->resolver_result, GRPC_ARG_SERVICE_CONFIG); - if (channel_arg != NULL) { - GPR_ASSERT(channel_arg->type == GRPC_ARG_STRING); - service_config_json = gpr_strdup(channel_arg->value.string); - grpc_service_config *service_config = - grpc_service_config_create(service_config_json); - if (service_config != NULL) { - method_params_table = grpc_service_config_create_method_config_table( - service_config, method_parameters_create_from_json, - &method_parameters_vtable); - grpc_service_config_destroy(service_config); - } - } - // Before we clean up, save a copy of lb_policy_name, since it might - // be pointing to data inside chand->resolver_result. - // The copy will be saved in chand->lb_policy_name below. - lb_policy_name = gpr_strdup(lb_policy_name); - grpc_channel_args_destroy(chand->resolver_result); - chand->resolver_result = NULL; - } - - if (lb_policy != NULL) { - grpc_pollset_set_add_pollset_set(exec_ctx, lb_policy->interested_parties, - chand->interested_parties); - } - - gpr_mu_lock(&chand->mu); - if (lb_policy_name != NULL) { - gpr_free(chand->lb_policy_name); - chand->lb_policy_name = lb_policy_name; - } - old_lb_policy = chand->lb_policy; - chand->lb_policy = lb_policy; - if (service_config_json != NULL) { - gpr_free(chand->service_config_json); - chand->service_config_json = service_config_json; - } - if (chand->method_params_table != NULL) { - grpc_mdstr_hash_table_unref(chand->method_params_table); - } - chand->method_params_table = method_params_table; - if (lb_policy != NULL) { - grpc_exec_ctx_enqueue_list(exec_ctx, &chand->waiting_for_config_closures, - NULL); - } else if (chand->resolver == NULL /* disconnected */) { - grpc_closure_list_fail_all( - &chand->waiting_for_config_closures, - GRPC_ERROR_CREATE_REFERENCING("Channel disconnected", &error, 1)); - grpc_exec_ctx_enqueue_list(exec_ctx, &chand->waiting_for_config_closures, - NULL); - } - if (lb_policy != NULL && chand->exit_idle_when_lb_policy_arrives) { - GRPC_LB_POLICY_REF(lb_policy, "exit_idle"); - exit_idle = true; - chand->exit_idle_when_lb_policy_arrives = false; - } - - if (error == GRPC_ERROR_NONE && chand->resolver) { - set_channel_connectivity_state_locked( - exec_ctx, chand, state, GRPC_ERROR_REF(state_error), "new_lb+resolver"); - if (lb_policy != NULL) { - watch_lb_policy(exec_ctx, chand, lb_policy, state); - } - GRPC_CHANNEL_STACK_REF(chand->owning_stack, "resolver"); - grpc_resolver_next(exec_ctx, chand->resolver, &chand->resolver_result, - &chand->on_resolver_result_changed); - gpr_mu_unlock(&chand->mu); - } else { - if (chand->resolver != NULL) { - grpc_resolver_shutdown(exec_ctx, chand->resolver); - GRPC_RESOLVER_UNREF(exec_ctx, chand->resolver, "channel"); - chand->resolver = NULL; - } - grpc_error *refs[] = {error, state_error}; - set_channel_connectivity_state_locked( - exec_ctx, chand, GRPC_CHANNEL_SHUTDOWN, - GRPC_ERROR_CREATE_REFERENCING("Got config after disconnection", refs, - GPR_ARRAY_SIZE(refs)), - "resolver_gone"); - gpr_mu_unlock(&chand->mu); - } - - if (exit_idle) { - grpc_lb_policy_exit_idle(exec_ctx, lb_policy); - GRPC_LB_POLICY_UNREF(exec_ctx, lb_policy, "exit_idle"); - } - - if (old_lb_policy != NULL) { - grpc_pollset_set_del_pollset_set( - exec_ctx, old_lb_policy->interested_parties, chand->interested_parties); - GRPC_LB_POLICY_UNREF(exec_ctx, old_lb_policy, "channel"); - } - - if (lb_policy != NULL) { - GRPC_LB_POLICY_UNREF(exec_ctx, lb_policy, "config_change"); - } - - GRPC_CHANNEL_STACK_UNREF(exec_ctx, chand->owning_stack, "resolver"); - GRPC_ERROR_UNREF(state_error); -} - -static void cc_start_transport_op(grpc_exec_ctx *exec_ctx, - grpc_channel_element *elem, - grpc_transport_op *op) { - channel_data *chand = elem->channel_data; - - grpc_exec_ctx_sched(exec_ctx, op->on_consumed, GRPC_ERROR_NONE, NULL); - - GPR_ASSERT(op->set_accept_stream == false); - if (op->bind_pollset != NULL) { - grpc_pollset_set_add_pollset(exec_ctx, chand->interested_parties, - op->bind_pollset); - } - - gpr_mu_lock(&chand->mu); - if (op->on_connectivity_state_change != NULL) { - grpc_connectivity_state_notify_on_state_change( - exec_ctx, &chand->state_tracker, op->connectivity_state, - op->on_connectivity_state_change); - op->on_connectivity_state_change = NULL; - op->connectivity_state = NULL; - } - - if (op->send_ping != NULL) { - if (chand->lb_policy == NULL) { - grpc_exec_ctx_sched(exec_ctx, op->send_ping, - GRPC_ERROR_CREATE("Ping with no load balancing"), - NULL); - } else { - grpc_lb_policy_ping_one(exec_ctx, chand->lb_policy, op->send_ping); - op->bind_pollset = NULL; - } - op->send_ping = NULL; - } - - if (op->disconnect_with_error != GRPC_ERROR_NONE) { - if (chand->resolver != NULL) { - set_channel_connectivity_state_locked( - exec_ctx, chand, GRPC_CHANNEL_SHUTDOWN, - GRPC_ERROR_REF(op->disconnect_with_error), "disconnect"); - grpc_resolver_shutdown(exec_ctx, chand->resolver); - GRPC_RESOLVER_UNREF(exec_ctx, chand->resolver, "channel"); - chand->resolver = NULL; - if (!chand->started_resolving) { - grpc_closure_list_fail_all(&chand->waiting_for_config_closures, - GRPC_ERROR_REF(op->disconnect_with_error)); - grpc_exec_ctx_enqueue_list(exec_ctx, - &chand->waiting_for_config_closures, NULL); - } - if (chand->lb_policy != NULL) { - grpc_pollset_set_del_pollset_set(exec_ctx, - chand->lb_policy->interested_parties, - chand->interested_parties); - GRPC_LB_POLICY_UNREF(exec_ctx, chand->lb_policy, "channel"); - chand->lb_policy = NULL; - } - } - GRPC_ERROR_UNREF(op->disconnect_with_error); - } - gpr_mu_unlock(&chand->mu); -} - -static void cc_get_channel_info(grpc_exec_ctx *exec_ctx, - grpc_channel_element *elem, - const grpc_channel_info *info) { - channel_data *chand = elem->channel_data; - gpr_mu_lock(&chand->mu); - if (info->lb_policy_name != NULL) { - *info->lb_policy_name = chand->lb_policy_name == NULL - ? NULL - : gpr_strdup(chand->lb_policy_name); - } - if (info->service_config_json != NULL) { - *info->service_config_json = chand->service_config_json == NULL - ? NULL - : gpr_strdup(chand->service_config_json); - } - gpr_mu_unlock(&chand->mu); -} - -/* Constructor for channel_data */ -static grpc_error *cc_init_channel_elem(grpc_exec_ctx *exec_ctx, - grpc_channel_element *elem, - grpc_channel_element_args *args) { - channel_data *chand = elem->channel_data; - memset(chand, 0, sizeof(*chand)); - GPR_ASSERT(args->is_last); - GPR_ASSERT(elem->filter == &grpc_client_channel_filter); - // Initialize data members. - gpr_mu_init(&chand->mu); - chand->owning_stack = args->channel_stack; - grpc_closure_init(&chand->on_resolver_result_changed, - on_resolver_result_changed, chand); - chand->interested_parties = grpc_pollset_set_create(); - grpc_connectivity_state_init(&chand->state_tracker, GRPC_CHANNEL_IDLE, - "client_channel"); - // Record client channel factory. - const grpc_arg *arg = grpc_channel_args_find(args->channel_args, - GRPC_ARG_CLIENT_CHANNEL_FACTORY); - GPR_ASSERT(arg != NULL); - GPR_ASSERT(arg->type == GRPC_ARG_POINTER); - grpc_client_channel_factory_ref(arg->value.pointer.p); - chand->client_channel_factory = arg->value.pointer.p; - // Instantiate resolver. - arg = grpc_channel_args_find(args->channel_args, GRPC_ARG_SERVER_URI); - GPR_ASSERT(arg != NULL); - GPR_ASSERT(arg->type == GRPC_ARG_STRING); - chand->resolver = - grpc_resolver_create(exec_ctx, arg->value.string, args->channel_args, - chand->interested_parties); - if (chand->resolver == NULL) { - return GRPC_ERROR_CREATE("resolver creation failed"); - } - return GRPC_ERROR_NONE; -} - -/* Destructor for channel_data */ -static void cc_destroy_channel_elem(grpc_exec_ctx *exec_ctx, - grpc_channel_element *elem) { - channel_data *chand = elem->channel_data; - - if (chand->resolver != NULL) { - grpc_resolver_shutdown(exec_ctx, chand->resolver); - GRPC_RESOLVER_UNREF(exec_ctx, chand->resolver, "channel"); - } - if (chand->client_channel_factory != NULL) { - grpc_client_channel_factory_unref(exec_ctx, chand->client_channel_factory); - } - if (chand->lb_policy != NULL) { - grpc_pollset_set_del_pollset_set(exec_ctx, - chand->lb_policy->interested_parties, - chand->interested_parties); - GRPC_LB_POLICY_UNREF(exec_ctx, chand->lb_policy, "channel"); - } - gpr_free(chand->lb_policy_name); - gpr_free(chand->service_config_json); - if (chand->method_params_table != NULL) { - grpc_mdstr_hash_table_unref(chand->method_params_table); - } - grpc_connectivity_state_destroy(exec_ctx, &chand->state_tracker); - grpc_pollset_set_destroy(chand->interested_parties); - gpr_mu_destroy(&chand->mu); -} - -/************************************************************************* - * PER-CALL FUNCTIONS - */ - -#define GET_CALL(call_data) \ - ((grpc_subchannel_call *)(gpr_atm_acq_load(&(call_data)->subchannel_call))) - -#define CANCELLED_CALL ((grpc_subchannel_call *)1) - -typedef enum { - GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING, - GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL -} subchannel_creation_phase; - -/** Call data. Holds a pointer to grpc_subchannel_call and the - associated machinery to create such a pointer. - Handles queueing of stream ops until a call object is ready, waiting - for initial metadata before trying to create a call object, - and handling cancellation gracefully. */ -typedef struct client_channel_call_data { - // State for handling deadlines. - // The code in deadline_filter.c requires this to be the first field. - // TODO(roth): This is slightly sub-optimal in that grpc_deadline_state - // and this struct both independently store a pointer to the call - // stack and each has its own mutex. If/when we have time, find a way - // to avoid this without breaking the grpc_deadline_state abstraction. - grpc_deadline_state deadline_state; - - grpc_mdstr *path; // Request path. - gpr_timespec call_start_time; - gpr_timespec deadline; - wait_for_ready_value wait_for_ready_from_service_config; - grpc_closure read_service_config; - - grpc_error *cancel_error; - - /** either 0 for no call, 1 for cancelled, or a pointer to a - grpc_subchannel_call */ - gpr_atm subchannel_call; - - gpr_mu mu; - - subchannel_creation_phase creation_phase; - grpc_connected_subchannel *connected_subchannel; - grpc_polling_entity *pollent; - - grpc_transport_stream_op **waiting_ops; - size_t waiting_ops_count; - size_t waiting_ops_capacity; - - grpc_closure next_step; - - grpc_call_stack *owning_call; - - grpc_linked_mdelem lb_token_mdelem; -} call_data; - -static void add_waiting_locked(call_data *calld, grpc_transport_stream_op *op) { - GPR_TIMER_BEGIN("add_waiting_locked", 0); - if (calld->waiting_ops_count == calld->waiting_ops_capacity) { - calld->waiting_ops_capacity = GPR_MAX(3, 2 * calld->waiting_ops_capacity); - calld->waiting_ops = - gpr_realloc(calld->waiting_ops, - calld->waiting_ops_capacity * sizeof(*calld->waiting_ops)); - } - calld->waiting_ops[calld->waiting_ops_count++] = op; - GPR_TIMER_END("add_waiting_locked", 0); -} - -static void fail_locked(grpc_exec_ctx *exec_ctx, call_data *calld, - grpc_error *error) { - size_t i; - for (i = 0; i < calld->waiting_ops_count; i++) { - grpc_transport_stream_op_finish_with_failure( - exec_ctx, calld->waiting_ops[i], GRPC_ERROR_REF(error)); - } - calld->waiting_ops_count = 0; - GRPC_ERROR_UNREF(error); -} - -typedef struct { - grpc_transport_stream_op **ops; - size_t nops; - grpc_subchannel_call *call; -} retry_ops_args; - -static void retry_ops(grpc_exec_ctx *exec_ctx, void *args, grpc_error *error) { - retry_ops_args *a = args; - size_t i; - for (i = 0; i < a->nops; i++) { - grpc_subchannel_call_process_op(exec_ctx, a->call, a->ops[i]); - } - GRPC_SUBCHANNEL_CALL_UNREF(exec_ctx, a->call, "retry_ops"); - gpr_free(a->ops); - gpr_free(a); -} - -static void retry_waiting_locked(grpc_exec_ctx *exec_ctx, call_data *calld) { - if (calld->waiting_ops_count == 0) { - return; - } - - retry_ops_args *a = gpr_malloc(sizeof(*a)); - a->ops = calld->waiting_ops; - a->nops = calld->waiting_ops_count; - a->call = GET_CALL(calld); - if (a->call == CANCELLED_CALL) { - gpr_free(a); - fail_locked(exec_ctx, calld, GRPC_ERROR_CANCELLED); - return; - } - calld->waiting_ops = NULL; - calld->waiting_ops_count = 0; - calld->waiting_ops_capacity = 0; - GRPC_SUBCHANNEL_CALL_REF(a->call, "retry_ops"); - grpc_exec_ctx_sched(exec_ctx, grpc_closure_create(retry_ops, a), - GRPC_ERROR_NONE, NULL); -} - -static void subchannel_ready(grpc_exec_ctx *exec_ctx, void *arg, - grpc_error *error) { - grpc_call_element *elem = arg; - call_data *calld = elem->call_data; - channel_data *chand = elem->channel_data; - gpr_mu_lock(&calld->mu); - GPR_ASSERT(calld->creation_phase == - GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL); - grpc_polling_entity_del_from_pollset_set(exec_ctx, calld->pollent, - chand->interested_parties); - calld->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING; - if (calld->connected_subchannel == NULL) { - gpr_atm_no_barrier_store(&calld->subchannel_call, 1); - fail_locked(exec_ctx, calld, GRPC_ERROR_CREATE_REFERENCING( - "Failed to create subchannel", &error, 1)); - } else if (GET_CALL(calld) == CANCELLED_CALL) { - /* already cancelled before subchannel became ready */ - grpc_error *cancellation_error = GRPC_ERROR_CREATE_REFERENCING( - "Cancelled before creating subchannel", &error, 1); - /* if due to deadline, attach the deadline exceeded status to the error */ - if (gpr_time_cmp(calld->deadline, gpr_now(GPR_CLOCK_MONOTONIC)) < 0) { - cancellation_error = - grpc_error_set_int(cancellation_error, GRPC_ERROR_INT_GRPC_STATUS, - GRPC_STATUS_DEADLINE_EXCEEDED); - } - fail_locked(exec_ctx, calld, cancellation_error); - } else { - /* Create call on subchannel. */ - grpc_subchannel_call *subchannel_call = NULL; - grpc_error *new_error = grpc_connected_subchannel_create_call( - exec_ctx, calld->connected_subchannel, calld->pollent, calld->path, - calld->call_start_time, calld->deadline, &subchannel_call); - if (new_error != GRPC_ERROR_NONE) { - new_error = grpc_error_add_child(new_error, error); - subchannel_call = CANCELLED_CALL; - fail_locked(exec_ctx, calld, new_error); - } - gpr_atm_rel_store(&calld->subchannel_call, - (gpr_atm)(uintptr_t)subchannel_call); - retry_waiting_locked(exec_ctx, calld); - } - gpr_mu_unlock(&calld->mu); - GRPC_CALL_STACK_UNREF(exec_ctx, calld->owning_call, "pick_subchannel"); -} - -static char *cc_get_peer(grpc_exec_ctx *exec_ctx, grpc_call_element *elem) { - call_data *calld = elem->call_data; - grpc_subchannel_call *subchannel_call = GET_CALL(calld); - if (subchannel_call == NULL || subchannel_call == CANCELLED_CALL) { - return NULL; - } else { - return grpc_subchannel_call_get_peer(exec_ctx, subchannel_call); - } -} - -typedef struct { - grpc_metadata_batch *initial_metadata; - uint32_t initial_metadata_flags; - grpc_connected_subchannel **connected_subchannel; - grpc_closure *on_ready; - grpc_call_element *elem; - grpc_closure closure; -} continue_picking_args; - -/** Return true if subchannel is available immediately (in which case on_ready - should not be called), or false otherwise (in which case on_ready should be - called when the subchannel is available). */ -static bool pick_subchannel(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, - grpc_metadata_batch *initial_metadata, - uint32_t initial_metadata_flags, - grpc_connected_subchannel **connected_subchannel, - grpc_closure *on_ready, grpc_error *error); - -static void continue_picking(grpc_exec_ctx *exec_ctx, void *arg, - grpc_error *error) { - continue_picking_args *cpa = arg; - if (cpa->connected_subchannel == NULL) { - /* cancelled, do nothing */ - } else if (error != GRPC_ERROR_NONE) { - grpc_exec_ctx_sched(exec_ctx, cpa->on_ready, GRPC_ERROR_REF(error), NULL); - } else { - call_data *calld = cpa->elem->call_data; - gpr_mu_lock(&calld->mu); - if (pick_subchannel(exec_ctx, cpa->elem, cpa->initial_metadata, - cpa->initial_metadata_flags, cpa->connected_subchannel, - cpa->on_ready, GRPC_ERROR_NONE)) { - grpc_exec_ctx_sched(exec_ctx, cpa->on_ready, GRPC_ERROR_NONE, NULL); - } - gpr_mu_unlock(&calld->mu); - } - gpr_free(cpa); -} - -static bool pick_subchannel(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, - grpc_metadata_batch *initial_metadata, - uint32_t initial_metadata_flags, - grpc_connected_subchannel **connected_subchannel, - grpc_closure *on_ready, grpc_error *error) { - GPR_TIMER_BEGIN("pick_subchannel", 0); - - channel_data *chand = elem->channel_data; - call_data *calld = elem->call_data; - continue_picking_args *cpa; - grpc_closure *closure; - - GPR_ASSERT(connected_subchannel); - - gpr_mu_lock(&chand->mu); - if (initial_metadata == NULL) { - if (chand->lb_policy != NULL) { - grpc_lb_policy_cancel_pick(exec_ctx, chand->lb_policy, - connected_subchannel, GRPC_ERROR_REF(error)); - } - for (closure = chand->waiting_for_config_closures.head; closure != NULL; - closure = closure->next_data.next) { - cpa = closure->cb_arg; - if (cpa->connected_subchannel == connected_subchannel) { - cpa->connected_subchannel = NULL; - grpc_exec_ctx_sched( - exec_ctx, cpa->on_ready, - GRPC_ERROR_CREATE_REFERENCING("Pick cancelled", &error, 1), NULL); - } - } - gpr_mu_unlock(&chand->mu); - GPR_TIMER_END("pick_subchannel", 0); - GRPC_ERROR_UNREF(error); - return true; - } - GPR_ASSERT(error == GRPC_ERROR_NONE); - if (chand->lb_policy != NULL) { - grpc_lb_policy *lb_policy = chand->lb_policy; - GRPC_LB_POLICY_REF(lb_policy, "pick_subchannel"); - gpr_mu_unlock(&chand->mu); - // If the application explicitly set wait_for_ready, use that. - // Otherwise, if the service config specified a value for this - // method, use that. - const bool wait_for_ready_set_from_api = - initial_metadata_flags & - GRPC_INITIAL_METADATA_WAIT_FOR_READY_EXPLICITLY_SET; - const bool wait_for_ready_set_from_service_config = - calld->wait_for_ready_from_service_config != WAIT_FOR_READY_UNSET; - if (!wait_for_ready_set_from_api && - wait_for_ready_set_from_service_config) { - if (calld->wait_for_ready_from_service_config == WAIT_FOR_READY_TRUE) { - initial_metadata_flags |= GRPC_INITIAL_METADATA_WAIT_FOR_READY; - } else { - initial_metadata_flags &= ~GRPC_INITIAL_METADATA_WAIT_FOR_READY; - } - } - const grpc_lb_policy_pick_args inputs = { - initial_metadata, initial_metadata_flags, &calld->lb_token_mdelem, - gpr_inf_future(GPR_CLOCK_MONOTONIC)}; - const bool result = grpc_lb_policy_pick( - exec_ctx, lb_policy, &inputs, connected_subchannel, NULL, on_ready); - GRPC_LB_POLICY_UNREF(exec_ctx, lb_policy, "pick_subchannel"); - GPR_TIMER_END("pick_subchannel", 0); - return result; - } - if (chand->resolver != NULL && !chand->started_resolving) { - chand->started_resolving = true; - GRPC_CHANNEL_STACK_REF(chand->owning_stack, "resolver"); - grpc_resolver_next(exec_ctx, chand->resolver, &chand->resolver_result, - &chand->on_resolver_result_changed); - } - if (chand->resolver != NULL) { - cpa = gpr_malloc(sizeof(*cpa)); - cpa->initial_metadata = initial_metadata; - cpa->initial_metadata_flags = initial_metadata_flags; - cpa->connected_subchannel = connected_subchannel; - cpa->on_ready = on_ready; - cpa->elem = elem; - grpc_closure_init(&cpa->closure, continue_picking, cpa); - grpc_closure_list_append(&chand->waiting_for_config_closures, &cpa->closure, - GRPC_ERROR_NONE); - } else { - grpc_exec_ctx_sched(exec_ctx, on_ready, GRPC_ERROR_CREATE("Disconnected"), - NULL); - } - gpr_mu_unlock(&chand->mu); - - GPR_TIMER_END("pick_subchannel", 0); - return false; -} - -// The logic here is fairly complicated, due to (a) the fact that we -// need to handle the case where we receive the send op before the -// initial metadata op, and (b) the need for efficiency, especially in -// the streaming case. -// TODO(ctiller): Explain this more thoroughly. -static void cc_start_transport_stream_op(grpc_exec_ctx *exec_ctx, - grpc_call_element *elem, - grpc_transport_stream_op *op) { - call_data *calld = elem->call_data; - channel_data *chand = elem->channel_data; - GRPC_CALL_LOG_OP(GPR_INFO, elem, op); - grpc_deadline_state_client_start_transport_stream_op(exec_ctx, elem, op); - /* try to (atomically) get the call */ - grpc_subchannel_call *call = GET_CALL(calld); - GPR_TIMER_BEGIN("cc_start_transport_stream_op", 0); - if (call == CANCELLED_CALL) { - grpc_transport_stream_op_finish_with_failure( - exec_ctx, op, GRPC_ERROR_REF(calld->cancel_error)); - GPR_TIMER_END("cc_start_transport_stream_op", 0); - return; - } - if (call != NULL) { - grpc_subchannel_call_process_op(exec_ctx, call, op); - GPR_TIMER_END("cc_start_transport_stream_op", 0); - return; - } - /* we failed; lock and figure out what to do */ - gpr_mu_lock(&calld->mu); -retry: - /* need to recheck that another thread hasn't set the call */ - call = GET_CALL(calld); - if (call == CANCELLED_CALL) { - gpr_mu_unlock(&calld->mu); - grpc_transport_stream_op_finish_with_failure( - exec_ctx, op, GRPC_ERROR_REF(calld->cancel_error)); - GPR_TIMER_END("cc_start_transport_stream_op", 0); - return; - } - if (call != NULL) { - gpr_mu_unlock(&calld->mu); - grpc_subchannel_call_process_op(exec_ctx, call, op); - GPR_TIMER_END("cc_start_transport_stream_op", 0); - return; - } - /* if this is a cancellation, then we can raise our cancelled flag */ - if (op->cancel_error != GRPC_ERROR_NONE) { - if (!gpr_atm_rel_cas(&calld->subchannel_call, 0, - (gpr_atm)(uintptr_t)CANCELLED_CALL)) { - goto retry; - } else { - // Stash a copy of cancel_error in our call data, so that we can use - // it for subsequent operations. This ensures that if the call is - // cancelled before any ops are passed down (e.g., if the deadline - // is in the past when the call starts), we can return the right - // error to the caller when the first op does get passed down. - calld->cancel_error = GRPC_ERROR_REF(op->cancel_error); - switch (calld->creation_phase) { - case GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING: - fail_locked(exec_ctx, calld, GRPC_ERROR_REF(op->cancel_error)); - break; - case GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL: - pick_subchannel(exec_ctx, elem, NULL, 0, &calld->connected_subchannel, - NULL, GRPC_ERROR_REF(op->cancel_error)); - break; - } - gpr_mu_unlock(&calld->mu); - grpc_transport_stream_op_finish_with_failure( - exec_ctx, op, GRPC_ERROR_REF(op->cancel_error)); - GPR_TIMER_END("cc_start_transport_stream_op", 0); - return; - } - } - /* if we don't have a subchannel, try to get one */ - if (calld->creation_phase == GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING && - calld->connected_subchannel == NULL && - op->send_initial_metadata != NULL) { - calld->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL; - grpc_closure_init(&calld->next_step, subchannel_ready, elem); - GRPC_CALL_STACK_REF(calld->owning_call, "pick_subchannel"); - /* If a subchannel is not available immediately, the polling entity from - call_data should be provided to channel_data's interested_parties, so - that IO of the lb_policy and resolver could be done under it. */ - if (pick_subchannel(exec_ctx, elem, op->send_initial_metadata, - op->send_initial_metadata_flags, - &calld->connected_subchannel, &calld->next_step, - GRPC_ERROR_NONE)) { - calld->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING; - GRPC_CALL_STACK_UNREF(exec_ctx, calld->owning_call, "pick_subchannel"); - } else { - grpc_polling_entity_add_to_pollset_set(exec_ctx, calld->pollent, - chand->interested_parties); - } - } - /* if we've got a subchannel, then let's ask it to create a call */ - if (calld->creation_phase == GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING && - calld->connected_subchannel != NULL) { - grpc_subchannel_call *subchannel_call = NULL; - grpc_error *error = grpc_connected_subchannel_create_call( - exec_ctx, calld->connected_subchannel, calld->pollent, calld->path, - calld->call_start_time, calld->deadline, &subchannel_call); - if (error != GRPC_ERROR_NONE) { - subchannel_call = CANCELLED_CALL; - fail_locked(exec_ctx, calld, GRPC_ERROR_REF(error)); - grpc_transport_stream_op_finish_with_failure(exec_ctx, op, error); - } - gpr_atm_rel_store(&calld->subchannel_call, - (gpr_atm)(uintptr_t)subchannel_call); - retry_waiting_locked(exec_ctx, calld); - goto retry; - } - /* nothing to be done but wait */ - add_waiting_locked(calld, op); - gpr_mu_unlock(&calld->mu); - GPR_TIMER_END("cc_start_transport_stream_op", 0); -} - -// Gets data from the service config. Invoked when the resolver returns -// its initial result. -static void read_service_config(grpc_exec_ctx *exec_ctx, void *arg, - grpc_error *error) { - grpc_call_element *elem = arg; - channel_data *chand = elem->channel_data; - call_data *calld = elem->call_data; - // If this is an error, there's no point in looking at the service config. - if (error == GRPC_ERROR_NONE) { - // Get the method config table from channel data. - gpr_mu_lock(&chand->mu); - grpc_mdstr_hash_table *method_params_table = NULL; - if (chand->method_params_table != NULL) { - method_params_table = - grpc_mdstr_hash_table_ref(chand->method_params_table); - } - gpr_mu_unlock(&chand->mu); - // If the method config table was present, use it. - if (method_params_table != NULL) { - const method_parameters *method_params = - grpc_method_config_table_get(method_params_table, calld->path); - if (method_params != NULL) { - const bool have_method_timeout = - gpr_time_cmp(method_params->timeout, gpr_time_0(GPR_TIMESPAN)) != 0; - if (have_method_timeout || - method_params->wait_for_ready != WAIT_FOR_READY_UNSET) { - gpr_mu_lock(&calld->mu); - if (have_method_timeout) { - const gpr_timespec per_method_deadline = - gpr_time_add(calld->call_start_time, method_params->timeout); - if (gpr_time_cmp(per_method_deadline, calld->deadline) < 0) { - calld->deadline = per_method_deadline; - // Reset deadline timer. - grpc_deadline_state_reset(exec_ctx, elem, calld->deadline); - } - } - if (method_params->wait_for_ready != WAIT_FOR_READY_UNSET) { - calld->wait_for_ready_from_service_config = - method_params->wait_for_ready; - } - gpr_mu_unlock(&calld->mu); - } - } - grpc_mdstr_hash_table_unref(method_params_table); - } - } - GRPC_CALL_STACK_UNREF(exec_ctx, calld->owning_call, "read_service_config"); -} - -/* Constructor for call_data */ -static grpc_error *cc_init_call_elem(grpc_exec_ctx *exec_ctx, - grpc_call_element *elem, - grpc_call_element_args *args) { - channel_data *chand = elem->channel_data; - call_data *calld = elem->call_data; - // Initialize data members. - grpc_deadline_state_init(exec_ctx, elem, args->call_stack); - calld->path = GRPC_MDSTR_REF(args->path); - calld->call_start_time = args->start_time; - calld->deadline = gpr_convert_clock_type(args->deadline, GPR_CLOCK_MONOTONIC); - calld->wait_for_ready_from_service_config = WAIT_FOR_READY_UNSET; - calld->cancel_error = GRPC_ERROR_NONE; - gpr_atm_rel_store(&calld->subchannel_call, 0); - gpr_mu_init(&calld->mu); - calld->connected_subchannel = NULL; - calld->waiting_ops = NULL; - calld->waiting_ops_count = 0; - calld->waiting_ops_capacity = 0; - calld->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING; - calld->owning_call = args->call_stack; - calld->pollent = NULL; - // If the resolver has already returned results, then we can access - // the service config parameters immediately. Otherwise, we need to - // defer that work until the resolver returns an initial result. - // TODO(roth): This code is almost but not quite identical to the code - // in read_service_config() above. It would be nice to find a way to - // combine them, to avoid having to maintain it twice. - gpr_mu_lock(&chand->mu); - if (chand->lb_policy != NULL) { - // We already have a resolver result, so check for service config. - if (chand->method_params_table != NULL) { - grpc_mdstr_hash_table *method_params_table = - grpc_mdstr_hash_table_ref(chand->method_params_table); - gpr_mu_unlock(&chand->mu); - method_parameters *method_params = - grpc_method_config_table_get(method_params_table, args->path); - if (method_params != NULL) { - if (gpr_time_cmp(method_params->timeout, - gpr_time_0(GPR_CLOCK_MONOTONIC)) != 0) { - gpr_timespec per_method_deadline = - gpr_time_add(calld->call_start_time, method_params->timeout); - calld->deadline = gpr_time_min(calld->deadline, per_method_deadline); - } - if (method_params->wait_for_ready != WAIT_FOR_READY_UNSET) { - calld->wait_for_ready_from_service_config = - method_params->wait_for_ready; - } - } - grpc_mdstr_hash_table_unref(method_params_table); - } else { - gpr_mu_unlock(&chand->mu); - } - } else { - // We don't yet have a resolver result, so register a callback to - // get the service config data once the resolver returns. - // Take a reference to the call stack to be owned by the callback. - GRPC_CALL_STACK_REF(calld->owning_call, "read_service_config"); - grpc_closure_init(&calld->read_service_config, read_service_config, elem); - grpc_closure_list_append(&chand->waiting_for_config_closures, - &calld->read_service_config, GRPC_ERROR_NONE); - gpr_mu_unlock(&chand->mu); - } - // Start the deadline timer with the current deadline value. If we - // do not yet have service config data, then the timer may be reset - // later. - grpc_deadline_state_start(exec_ctx, elem, calld->deadline); - return GRPC_ERROR_NONE; -} - -/* Destructor for call_data */ -static void cc_destroy_call_elem(grpc_exec_ctx *exec_ctx, - grpc_call_element *elem, - const grpc_call_final_info *final_info, - void *and_free_memory) { - call_data *calld = elem->call_data; - grpc_deadline_state_destroy(exec_ctx, elem); - GRPC_MDSTR_UNREF(calld->path); - GRPC_ERROR_UNREF(calld->cancel_error); - grpc_subchannel_call *call = GET_CALL(calld); - if (call != NULL && call != CANCELLED_CALL) { - GRPC_SUBCHANNEL_CALL_UNREF(exec_ctx, call, "client_channel_destroy_call"); - } - GPR_ASSERT(calld->creation_phase == GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING); - gpr_mu_destroy(&calld->mu); - GPR_ASSERT(calld->waiting_ops_count == 0); - if (calld->connected_subchannel != NULL) { - GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, calld->connected_subchannel, - "picked"); - } - gpr_free(calld->waiting_ops); - gpr_free(and_free_memory); -} - -static void cc_set_pollset_or_pollset_set(grpc_exec_ctx *exec_ctx, - grpc_call_element *elem, - grpc_polling_entity *pollent) { - call_data *calld = elem->call_data; - calld->pollent = pollent; -} - -/************************************************************************* - * EXPORTED SYMBOLS - */ - -const grpc_channel_filter grpc_client_channel_filter = { - cc_start_transport_stream_op, - cc_start_transport_op, - sizeof(call_data), - cc_init_call_elem, - cc_set_pollset_or_pollset_set, - cc_destroy_call_elem, - sizeof(channel_data), - cc_init_channel_elem, - cc_destroy_channel_elem, - cc_get_peer, - cc_get_channel_info, - "client-channel", -}; - -grpc_connectivity_state grpc_client_channel_check_connectivity_state( - grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, int try_to_connect) { - channel_data *chand = elem->channel_data; - grpc_connectivity_state out; - gpr_mu_lock(&chand->mu); - out = grpc_connectivity_state_check(&chand->state_tracker, NULL); - if (out == GRPC_CHANNEL_IDLE && try_to_connect) { - if (chand->lb_policy != NULL) { - grpc_lb_policy_exit_idle(exec_ctx, chand->lb_policy); - } else { - chand->exit_idle_when_lb_policy_arrives = true; - if (!chand->started_resolving && chand->resolver != NULL) { - GRPC_CHANNEL_STACK_REF(chand->owning_stack, "resolver"); - chand->started_resolving = true; - grpc_resolver_next(exec_ctx, chand->resolver, &chand->resolver_result, - &chand->on_resolver_result_changed); - } - } - } - gpr_mu_unlock(&chand->mu); - return out; -} - -typedef struct { - channel_data *chand; - grpc_pollset *pollset; - grpc_closure *on_complete; - grpc_closure my_closure; -} external_connectivity_watcher; - -static void on_external_watch_complete(grpc_exec_ctx *exec_ctx, void *arg, - grpc_error *error) { - external_connectivity_watcher *w = arg; - grpc_closure *follow_up = w->on_complete; - grpc_pollset_set_del_pollset(exec_ctx, w->chand->interested_parties, - w->pollset); - GRPC_CHANNEL_STACK_UNREF(exec_ctx, w->chand->owning_stack, - "external_connectivity_watcher"); - gpr_free(w); - follow_up->cb(exec_ctx, follow_up->cb_arg, error); -} - -void grpc_client_channel_watch_connectivity_state( - grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, grpc_pollset *pollset, - grpc_connectivity_state *state, grpc_closure *on_complete) { - channel_data *chand = elem->channel_data; - external_connectivity_watcher *w = gpr_malloc(sizeof(*w)); - w->chand = chand; - w->pollset = pollset; - w->on_complete = on_complete; - grpc_pollset_set_add_pollset(exec_ctx, chand->interested_parties, pollset); - grpc_closure_init(&w->my_closure, on_external_watch_complete, w); - GRPC_CHANNEL_STACK_REF(w->chand->owning_stack, - "external_connectivity_watcher"); - gpr_mu_lock(&chand->mu); - grpc_connectivity_state_notify_on_state_change( - exec_ctx, &chand->state_tracker, state, &w->my_closure); - gpr_mu_unlock(&chand->mu); -} diff --git a/Sources/CgRPC/src/core/ext/client_channel/client_channel.h b/Sources/CgRPC/src/core/ext/client_channel/client_channel.h deleted file mode 100644 index f02587d0c..000000000 --- a/Sources/CgRPC/src/core/ext/client_channel/client_channel.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#ifndef GRPC_CORE_EXT_CLIENT_CHANNEL_CLIENT_CHANNEL_H -#define GRPC_CORE_EXT_CLIENT_CHANNEL_CLIENT_CHANNEL_H - -#include "src/core/ext/client_channel/client_channel_factory.h" -#include "src/core/ext/client_channel/resolver.h" -#include "src/core/lib/channel/channel_stack.h" - -// Channel arg key for server URI string. -#define GRPC_ARG_SERVER_URI "grpc.server_uri" - -/* A client channel is a channel that begins disconnected, and can connect - to some endpoint on demand. If that endpoint disconnects, it will be - connected to again later. - - Calls on a disconnected client channel are queued until a connection is - established. */ - -extern const grpc_channel_filter grpc_client_channel_filter; - -grpc_connectivity_state grpc_client_channel_check_connectivity_state( - grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, int try_to_connect); - -void grpc_client_channel_watch_connectivity_state( - grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, grpc_pollset *pollset, - grpc_connectivity_state *state, grpc_closure *on_complete); - -#endif /* GRPC_CORE_EXT_CLIENT_CHANNEL_CLIENT_CHANNEL_H */ diff --git a/Sources/CgRPC/src/core/ext/client_channel/client_channel_factory.c b/Sources/CgRPC/src/core/ext/client_channel/client_channel_factory.c deleted file mode 100644 index 4eb35dfcf..000000000 --- a/Sources/CgRPC/src/core/ext/client_channel/client_channel_factory.c +++ /dev/null @@ -1,89 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include "src/core/ext/client_channel/client_channel_factory.h" - -void grpc_client_channel_factory_ref(grpc_client_channel_factory* factory) { - factory->vtable->ref(factory); -} - -void grpc_client_channel_factory_unref(grpc_exec_ctx* exec_ctx, - grpc_client_channel_factory* factory) { - factory->vtable->unref(exec_ctx, factory); -} - -grpc_subchannel* grpc_client_channel_factory_create_subchannel( - grpc_exec_ctx* exec_ctx, grpc_client_channel_factory* factory, - const grpc_subchannel_args* args) { - return factory->vtable->create_subchannel(exec_ctx, factory, args); -} - -grpc_channel* grpc_client_channel_factory_create_channel( - grpc_exec_ctx* exec_ctx, grpc_client_channel_factory* factory, - const char* target, grpc_client_channel_type type, - const grpc_channel_args* args) { - return factory->vtable->create_client_channel(exec_ctx, factory, target, type, - args); -} - -static void* factory_arg_copy(void* factory) { - grpc_client_channel_factory_ref(factory); - return factory; -} - -static void factory_arg_destroy(void* factory) { - // TODO(roth): Remove local exec_ctx when - // https://github.com/grpc/grpc/pull/8705 is merged. - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - grpc_client_channel_factory_unref(&exec_ctx, factory); - grpc_exec_ctx_finish(&exec_ctx); -} - -static int factory_arg_cmp(void* factory1, void* factory2) { - if (factory1 < factory2) return -1; - if (factory1 > factory2) return 1; - return 0; -} - -static const grpc_arg_pointer_vtable factory_arg_vtable = { - factory_arg_copy, factory_arg_destroy, factory_arg_cmp}; - -grpc_arg grpc_client_channel_factory_create_channel_arg( - grpc_client_channel_factory* factory) { - grpc_arg arg; - arg.type = GRPC_ARG_POINTER; - arg.key = GRPC_ARG_CLIENT_CHANNEL_FACTORY; - arg.value.pointer.p = factory; - arg.value.pointer.vtable = &factory_arg_vtable; - return arg; -} diff --git a/Sources/CgRPC/src/core/ext/client_channel/client_channel_plugin.c b/Sources/CgRPC/src/core/ext/client_channel/client_channel_plugin.c deleted file mode 100644 index a3e507984..000000000 --- a/Sources/CgRPC/src/core/ext/client_channel/client_channel_plugin.c +++ /dev/null @@ -1,91 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include -#include -#include - -#include - -#include "src/core/ext/client_channel/client_channel.h" -#include "src/core/ext/client_channel/lb_policy_registry.h" -#include "src/core/ext/client_channel/resolver_registry.h" -#include "src/core/ext/client_channel/subchannel_index.h" -#include "src/core/lib/surface/channel_init.h" - -static bool append_filter(grpc_channel_stack_builder *builder, void *arg) { - return grpc_channel_stack_builder_append_filter( - builder, (const grpc_channel_filter *)arg, NULL, NULL); -} - -static bool set_default_host_if_unset(grpc_channel_stack_builder *builder, - void *unused) { - const grpc_channel_args *args = - grpc_channel_stack_builder_get_channel_arguments(builder); - for (size_t i = 0; i < args->num_args; i++) { - if (0 == strcmp(args->args[i].key, GRPC_ARG_DEFAULT_AUTHORITY) || - 0 == strcmp(args->args[i].key, GRPC_SSL_TARGET_NAME_OVERRIDE_ARG)) { - return true; - } - } - char *default_authority = grpc_get_default_authority( - grpc_channel_stack_builder_get_target(builder)); - if (default_authority != NULL) { - grpc_arg arg; - arg.type = GRPC_ARG_STRING; - arg.key = GRPC_ARG_DEFAULT_AUTHORITY; - arg.value.string = default_authority; - grpc_channel_args *new_args = grpc_channel_args_copy_and_add(args, &arg, 1); - grpc_channel_stack_builder_set_channel_arguments(builder, new_args); - gpr_free(default_authority); - grpc_channel_args_destroy(new_args); - } - return true; -} - -void grpc_client_channel_init(void) { - grpc_lb_policy_registry_init(); - grpc_resolver_registry_init(); - grpc_subchannel_index_init(); - grpc_channel_init_register_stage(GRPC_CLIENT_CHANNEL, INT_MIN, - set_default_host_if_unset, NULL); - grpc_channel_init_register_stage(GRPC_CLIENT_CHANNEL, INT_MAX, append_filter, - (void *)&grpc_client_channel_filter); -} - -void grpc_client_channel_shutdown(void) { - grpc_subchannel_index_shutdown(); - grpc_channel_init_shutdown(); - grpc_resolver_registry_shutdown(); - grpc_lb_policy_registry_shutdown(); -} diff --git a/Sources/CgRPC/src/core/ext/client_channel/connector.c b/Sources/CgRPC/src/core/ext/client_channel/connector.c deleted file mode 100644 index 0582e5b37..000000000 --- a/Sources/CgRPC/src/core/ext/client_channel/connector.c +++ /dev/null @@ -1,55 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include "src/core/ext/client_channel/connector.h" - -grpc_connector* grpc_connector_ref(grpc_connector* connector) { - connector->vtable->ref(connector); - return connector; -} - -void grpc_connector_unref(grpc_exec_ctx* exec_ctx, grpc_connector* connector) { - connector->vtable->unref(exec_ctx, connector); -} - -void grpc_connector_connect(grpc_exec_ctx* exec_ctx, grpc_connector* connector, - const grpc_connect_in_args* in_args, - grpc_connect_out_args* out_args, - grpc_closure* notify) { - connector->vtable->connect(exec_ctx, connector, in_args, out_args, notify); -} - -void grpc_connector_shutdown(grpc_exec_ctx* exec_ctx, - grpc_connector* connector) { - connector->vtable->shutdown(exec_ctx, connector); -} diff --git a/Sources/CgRPC/src/core/ext/client_channel/connector.h b/Sources/CgRPC/src/core/ext/client_channel/connector.h deleted file mode 100644 index 3de061620..000000000 --- a/Sources/CgRPC/src/core/ext/client_channel/connector.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#ifndef GRPC_CORE_EXT_CLIENT_CHANNEL_CONNECTOR_H -#define GRPC_CORE_EXT_CLIENT_CHANNEL_CONNECTOR_H - -#include "src/core/lib/channel/channel_stack.h" -#include "src/core/lib/iomgr/resolve_address.h" -#include "src/core/lib/transport/transport.h" - -typedef struct grpc_connector grpc_connector; -typedef struct grpc_connector_vtable grpc_connector_vtable; - -struct grpc_connector { - const grpc_connector_vtable *vtable; -}; - -typedef struct { - /** set of pollsets interested in this connection */ - grpc_pollset_set *interested_parties; - /** address to connect to */ - const grpc_resolved_address *addr; - size_t addr_len; - /** initial connect string to send */ - grpc_slice initial_connect_string; - /** deadline for connection */ - gpr_timespec deadline; - /** channel arguments (to be passed to transport) */ - const grpc_channel_args *channel_args; -} grpc_connect_in_args; - -typedef struct { - /** the connected transport */ - grpc_transport *transport; - - /** channel arguments (to be passed to the filters) */ - grpc_channel_args *channel_args; -} grpc_connect_out_args; - -struct grpc_connector_vtable { - void (*ref)(grpc_connector *connector); - void (*unref)(grpc_exec_ctx *exec_ctx, grpc_connector *connector); - /** Implementation of grpc_connector_shutdown */ - void (*shutdown)(grpc_exec_ctx *exec_ctx, grpc_connector *connector); - /** Implementation of grpc_connector_connect */ - void (*connect)(grpc_exec_ctx *exec_ctx, grpc_connector *connector, - const grpc_connect_in_args *in_args, - grpc_connect_out_args *out_args, grpc_closure *notify); -}; - -grpc_connector *grpc_connector_ref(grpc_connector *connector); -void grpc_connector_unref(grpc_exec_ctx *exec_ctx, grpc_connector *connector); -/** Connect using the connector: max one outstanding call at a time */ -void grpc_connector_connect(grpc_exec_ctx *exec_ctx, grpc_connector *connector, - const grpc_connect_in_args *in_args, - grpc_connect_out_args *out_args, - grpc_closure *notify); -/** Cancel any pending connection */ -void grpc_connector_shutdown(grpc_exec_ctx *exec_ctx, - grpc_connector *connector); - -#endif /* GRPC_CORE_EXT_CLIENT_CHANNEL_CONNECTOR_H */ diff --git a/Sources/CgRPC/src/core/ext/client_channel/default_initial_connect_string.c b/Sources/CgRPC/src/core/ext/client_channel/default_initial_connect_string.c deleted file mode 100644 index 6db82d84e..000000000 --- a/Sources/CgRPC/src/core/ext/client_channel/default_initial_connect_string.c +++ /dev/null @@ -1,38 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include -#include "src/core/lib/iomgr/resolve_address.h" - -void grpc_set_default_initial_connect_string(grpc_resolved_address **addr, - grpc_slice *initial_str) {} diff --git a/Sources/CgRPC/src/core/ext/client_channel/http_connect_handshaker.h b/Sources/CgRPC/src/core/ext/client_channel/http_connect_handshaker.h deleted file mode 100644 index ea293852e..000000000 --- a/Sources/CgRPC/src/core/ext/client_channel/http_connect_handshaker.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * - * Copyright 2016, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#ifndef GRPC_CORE_EXT_CLIENT_CHANNEL_HTTP_CONNECT_HANDSHAKER_H -#define GRPC_CORE_EXT_CLIENT_CHANNEL_HTTP_CONNECT_HANDSHAKER_H - -#include "src/core/lib/channel/handshaker.h" - -/// Does NOT take ownership of \a proxy_server. -grpc_handshaker* grpc_http_connect_handshaker_create(const char* proxy_server); - -/// Returns the name of the proxy to use, or NULL if no proxy is configured. -/// Caller takes ownership of result. -char* grpc_get_http_proxy_server(); - -#endif /* GRPC_CORE_EXT_CLIENT_CHANNEL_HTTP_CONNECT_HANDSHAKER_H */ diff --git a/Sources/CgRPC/src/core/ext/client_channel/initial_connect_string.c b/Sources/CgRPC/src/core/ext/client_channel/initial_connect_string.c deleted file mode 100644 index 8ebd06c45..000000000 --- a/Sources/CgRPC/src/core/ext/client_channel/initial_connect_string.c +++ /dev/null @@ -1,52 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include "src/core/ext/client_channel/initial_connect_string.h" - -#include - -extern void grpc_set_default_initial_connect_string( - grpc_resolved_address **addr, grpc_slice *initial_str); - -static grpc_set_initial_connect_string_func g_set_initial_connect_string_func = - grpc_set_default_initial_connect_string; - -void grpc_test_set_initial_connect_string_function( - grpc_set_initial_connect_string_func func) { - g_set_initial_connect_string_func = func; -} - -void grpc_set_initial_connect_string(grpc_resolved_address **addr, - grpc_slice *initial_str) { - g_set_initial_connect_string_func(addr, initial_str); -} diff --git a/Sources/CgRPC/src/core/ext/client_channel/initial_connect_string.h b/Sources/CgRPC/src/core/ext/client_channel/initial_connect_string.h deleted file mode 100644 index 876abea40..000000000 --- a/Sources/CgRPC/src/core/ext/client_channel/initial_connect_string.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#ifndef GRPC_CORE_EXT_CLIENT_CHANNEL_INITIAL_CONNECT_STRING_H -#define GRPC_CORE_EXT_CLIENT_CHANNEL_INITIAL_CONNECT_STRING_H - -#include -#include "src/core/lib/iomgr/resolve_address.h" - -typedef void (*grpc_set_initial_connect_string_func)( - grpc_resolved_address **addr, grpc_slice *initial_str); - -void grpc_test_set_initial_connect_string_function( - grpc_set_initial_connect_string_func func); - -/** Set a string to be sent once connected. Optionally reset addr. */ -void grpc_set_initial_connect_string(grpc_resolved_address **addr, - grpc_slice *connect_string); - -#endif /* GRPC_CORE_EXT_CLIENT_CHANNEL_INITIAL_CONNECT_STRING_H */ diff --git a/Sources/CgRPC/src/core/ext/client_channel/lb_policy.c b/Sources/CgRPC/src/core/ext/client_channel/lb_policy.c deleted file mode 100644 index 45ee72e2f..000000000 --- a/Sources/CgRPC/src/core/ext/client_channel/lb_policy.c +++ /dev/null @@ -1,146 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include "src/core/ext/client_channel/lb_policy.h" - -#define WEAK_REF_BITS 16 - -void grpc_lb_policy_init(grpc_lb_policy *policy, - const grpc_lb_policy_vtable *vtable) { - policy->vtable = vtable; - gpr_atm_no_barrier_store(&policy->ref_pair, 1 << WEAK_REF_BITS); - policy->interested_parties = grpc_pollset_set_create(); -} - -#ifdef GRPC_LB_POLICY_REFCOUNT_DEBUG -#define REF_FUNC_EXTRA_ARGS , const char *file, int line, const char *reason -#define REF_MUTATE_EXTRA_ARGS REF_FUNC_EXTRA_ARGS, const char *purpose -#define REF_FUNC_PASS_ARGS(new_reason) , file, line, new_reason -#define REF_MUTATE_PASS_ARGS(purpose) , file, line, reason, purpose -#else -#define REF_FUNC_EXTRA_ARGS -#define REF_MUTATE_EXTRA_ARGS -#define REF_FUNC_PASS_ARGS(new_reason) -#define REF_MUTATE_PASS_ARGS(x) -#endif - -static gpr_atm ref_mutate(grpc_lb_policy *c, gpr_atm delta, - int barrier REF_MUTATE_EXTRA_ARGS) { - gpr_atm old_val = barrier ? gpr_atm_full_fetch_add(&c->ref_pair, delta) - : gpr_atm_no_barrier_fetch_add(&c->ref_pair, delta); -#ifdef GRPC_LB_POLICY_REFCOUNT_DEBUG - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, - "LB_POLICY: 0x%" PRIxPTR " %12s 0x%" PRIxPTR " -> 0x%" PRIxPTR - " [%s]", - (intptr_t)c, purpose, old_val, old_val + delta, reason); -#endif - return old_val; -} - -void grpc_lb_policy_ref(grpc_lb_policy *policy REF_FUNC_EXTRA_ARGS) { - ref_mutate(policy, 1 << WEAK_REF_BITS, 0 REF_MUTATE_PASS_ARGS("STRONG_REF")); -} - -void grpc_lb_policy_unref(grpc_exec_ctx *exec_ctx, - grpc_lb_policy *policy REF_FUNC_EXTRA_ARGS) { - gpr_atm old_val = - ref_mutate(policy, (gpr_atm)1 - (gpr_atm)(1 << WEAK_REF_BITS), - 1 REF_MUTATE_PASS_ARGS("STRONG_UNREF")); - gpr_atm mask = ~(gpr_atm)((1 << WEAK_REF_BITS) - 1); - gpr_atm check = 1 << WEAK_REF_BITS; - if ((old_val & mask) == check) { - policy->vtable->shutdown(exec_ctx, policy); - } - grpc_lb_policy_weak_unref(exec_ctx, - policy REF_FUNC_PASS_ARGS("strong-unref")); -} - -void grpc_lb_policy_weak_ref(grpc_lb_policy *policy REF_FUNC_EXTRA_ARGS) { - ref_mutate(policy, 1, 0 REF_MUTATE_PASS_ARGS("WEAK_REF")); -} - -void grpc_lb_policy_weak_unref(grpc_exec_ctx *exec_ctx, - grpc_lb_policy *policy REF_FUNC_EXTRA_ARGS) { - gpr_atm old_val = - ref_mutate(policy, -(gpr_atm)1, 1 REF_MUTATE_PASS_ARGS("WEAK_UNREF")); - if (old_val == 1) { - grpc_pollset_set_destroy(policy->interested_parties); - policy->vtable->destroy(exec_ctx, policy); - } -} - -int grpc_lb_policy_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, - const grpc_lb_policy_pick_args *pick_args, - grpc_connected_subchannel **target, void **user_data, - grpc_closure *on_complete) { - return policy->vtable->pick(exec_ctx, policy, pick_args, target, user_data, - on_complete); -} - -void grpc_lb_policy_cancel_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, - grpc_connected_subchannel **target, - grpc_error *error) { - policy->vtable->cancel_pick(exec_ctx, policy, target, error); -} - -void grpc_lb_policy_cancel_picks(grpc_exec_ctx *exec_ctx, - grpc_lb_policy *policy, - uint32_t initial_metadata_flags_mask, - uint32_t initial_metadata_flags_eq, - grpc_error *error) { - policy->vtable->cancel_picks(exec_ctx, policy, initial_metadata_flags_mask, - initial_metadata_flags_eq, error); -} - -void grpc_lb_policy_exit_idle(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy) { - policy->vtable->exit_idle(exec_ctx, policy); -} - -void grpc_lb_policy_ping_one(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, - grpc_closure *closure) { - policy->vtable->ping_one(exec_ctx, policy, closure); -} - -void grpc_lb_policy_notify_on_state_change(grpc_exec_ctx *exec_ctx, - grpc_lb_policy *policy, - grpc_connectivity_state *state, - grpc_closure *closure) { - policy->vtable->notify_on_state_change(exec_ctx, policy, state, closure); -} - -grpc_connectivity_state grpc_lb_policy_check_connectivity( - grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, - grpc_error **connectivity_error) { - return policy->vtable->check_connectivity(exec_ctx, policy, - connectivity_error); -} diff --git a/Sources/CgRPC/src/core/ext/client_channel/lb_policy_registry.c b/Sources/CgRPC/src/core/ext/client_channel/lb_policy_registry.c deleted file mode 100644 index 90c149d94..000000000 --- a/Sources/CgRPC/src/core/ext/client_channel/lb_policy_registry.c +++ /dev/null @@ -1,85 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include "src/core/ext/client_channel/lb_policy_registry.h" - -#include - -#include "src/core/lib/support/string.h" - -#define MAX_POLICIES 10 - -static grpc_lb_policy_factory *g_all_of_the_lb_policies[MAX_POLICIES]; -static int g_number_of_lb_policies = 0; - -void grpc_lb_policy_registry_init(void) { g_number_of_lb_policies = 0; } - -void grpc_lb_policy_registry_shutdown(void) { - int i; - for (i = 0; i < g_number_of_lb_policies; i++) { - grpc_lb_policy_factory_unref(g_all_of_the_lb_policies[i]); - } -} - -void grpc_register_lb_policy(grpc_lb_policy_factory *factory) { - int i; - for (i = 0; i < g_number_of_lb_policies; i++) { - GPR_ASSERT(0 != gpr_stricmp(factory->vtable->name, - g_all_of_the_lb_policies[i]->vtable->name)); - } - GPR_ASSERT(g_number_of_lb_policies != MAX_POLICIES); - grpc_lb_policy_factory_ref(factory); - g_all_of_the_lb_policies[g_number_of_lb_policies++] = factory; -} - -static grpc_lb_policy_factory *lookup_factory(const char *name) { - int i; - - if (name == NULL) return NULL; - - for (i = 0; i < g_number_of_lb_policies; i++) { - if (0 == gpr_stricmp(name, g_all_of_the_lb_policies[i]->vtable->name)) { - return g_all_of_the_lb_policies[i]; - } - } - - return NULL; -} - -grpc_lb_policy *grpc_lb_policy_create(grpc_exec_ctx *exec_ctx, const char *name, - grpc_lb_policy_args *args) { - grpc_lb_policy_factory *factory = lookup_factory(name); - grpc_lb_policy *lb_policy = - grpc_lb_policy_factory_create_lb_policy(exec_ctx, factory, args); - return lb_policy; -} diff --git a/Sources/CgRPC/src/core/ext/client_channel/lb_policy_registry.h b/Sources/CgRPC/src/core/ext/client_channel/lb_policy_registry.h deleted file mode 100644 index 21c468e02..000000000 --- a/Sources/CgRPC/src/core/ext/client_channel/lb_policy_registry.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#ifndef GRPC_CORE_EXT_CLIENT_CHANNEL_LB_POLICY_REGISTRY_H -#define GRPC_CORE_EXT_CLIENT_CHANNEL_LB_POLICY_REGISTRY_H - -#include "src/core/ext/client_channel/lb_policy_factory.h" -#include "src/core/lib/iomgr/exec_ctx.h" - -/** Initialize the registry and set \a default_factory as the factory to be - * returned when no name is provided in a lookup */ -void grpc_lb_policy_registry_init(void); -void grpc_lb_policy_registry_shutdown(void); - -/** Register a LB policy factory. */ -void grpc_register_lb_policy(grpc_lb_policy_factory *factory); - -/** Create a \a grpc_lb_policy instance. - * - * If \a name is NULL, the default factory from \a grpc_lb_policy_registry_init - * will be returned. */ -grpc_lb_policy *grpc_lb_policy_create(grpc_exec_ctx *exec_ctx, const char *name, - grpc_lb_policy_args *args); - -#endif /* GRPC_CORE_EXT_CLIENT_CHANNEL_LB_POLICY_REGISTRY_H */ diff --git a/Sources/CgRPC/src/core/ext/client_channel/parse_address.c b/Sources/CgRPC/src/core/ext/client_channel/parse_address.c deleted file mode 100644 index b1d55ad0f..000000000 --- a/Sources/CgRPC/src/core/ext/client_channel/parse_address.c +++ /dev/null @@ -1,144 +0,0 @@ -/* - * - * Copyright 2016, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include "src/core/ext/client_channel/parse_address.h" -#include "src/core/lib/iomgr/sockaddr.h" - -#include -#include -#ifdef GRPC_HAVE_UNIX_SOCKET -#include -#endif - -#include -#include -#include -#include - -#ifdef GRPC_HAVE_UNIX_SOCKET - -int parse_unix(grpc_uri *uri, grpc_resolved_address *resolved_addr) { - struct sockaddr_un *un = (struct sockaddr_un *)resolved_addr->addr; - - un->sun_family = AF_UNIX; - strcpy(un->sun_path, uri->path); - resolved_addr->len = strlen(un->sun_path) + sizeof(un->sun_family) + 1; - - return 1; -} - -#else /* GRPC_HAVE_UNIX_SOCKET */ - -int parse_unix(grpc_uri *uri, grpc_resolved_address *resolved_addr) { abort(); } - -#endif /* GRPC_HAVE_UNIX_SOCKET */ - -int parse_ipv4(grpc_uri *uri, grpc_resolved_address *resolved_addr) { - const char *host_port = uri->path; - char *host; - char *port; - int port_num; - int result = 0; - struct sockaddr_in *in = (struct sockaddr_in *)resolved_addr->addr; - - if (*host_port == '/') ++host_port; - if (!gpr_split_host_port(host_port, &host, &port)) { - return 0; - } - - memset(resolved_addr, 0, sizeof(grpc_resolved_address)); - resolved_addr->len = sizeof(struct sockaddr_in); - in->sin_family = AF_INET; - if (inet_pton(AF_INET, host, &in->sin_addr) == 0) { - gpr_log(GPR_ERROR, "invalid ipv4 address: '%s'", host); - goto done; - } - - if (port != NULL) { - if (sscanf(port, "%d", &port_num) != 1 || port_num < 0 || - port_num > 65535) { - gpr_log(GPR_ERROR, "invalid ipv4 port: '%s'", port); - goto done; - } - in->sin_port = htons((uint16_t)port_num); - } else { - gpr_log(GPR_ERROR, "no port given for ipv4 scheme"); - goto done; - } - - result = 1; -done: - gpr_free(host); - gpr_free(port); - return result; -} - -int parse_ipv6(grpc_uri *uri, grpc_resolved_address *resolved_addr) { - const char *host_port = uri->path; - char *host; - char *port; - int port_num; - int result = 0; - struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)resolved_addr->addr; - - if (*host_port == '/') ++host_port; - if (!gpr_split_host_port(host_port, &host, &port)) { - return 0; - } - - memset(in6, 0, sizeof(*in6)); - resolved_addr->len = sizeof(*in6); - in6->sin6_family = AF_INET6; - if (inet_pton(AF_INET6, host, &in6->sin6_addr) == 0) { - gpr_log(GPR_ERROR, "invalid ipv6 address: '%s'", host); - goto done; - } - - if (port != NULL) { - if (sscanf(port, "%d", &port_num) != 1 || port_num < 0 || - port_num > 65535) { - gpr_log(GPR_ERROR, "invalid ipv6 port: '%s'", port); - goto done; - } - in6->sin6_port = htons((uint16_t)port_num); - } else { - gpr_log(GPR_ERROR, "no port given for ipv6 scheme"); - goto done; - } - - result = 1; -done: - gpr_free(host); - gpr_free(port); - return result; -} diff --git a/Sources/CgRPC/src/core/ext/client_channel/parse_address.h b/Sources/CgRPC/src/core/ext/client_channel/parse_address.h deleted file mode 100644 index bf99c5298..000000000 --- a/Sources/CgRPC/src/core/ext/client_channel/parse_address.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#ifndef GRPC_CORE_EXT_CLIENT_CHANNEL_PARSE_ADDRESS_H -#define GRPC_CORE_EXT_CLIENT_CHANNEL_PARSE_ADDRESS_H - -#include - -#include "src/core/ext/client_channel/uri_parser.h" -#include "src/core/lib/iomgr/resolve_address.h" - -/** Populate \a addr and \a len from \a uri, whose path is expected to contain a - * unix socket path. Returns true upon success. */ -int parse_unix(grpc_uri *uri, grpc_resolved_address *resolved_addr); - -/** Populate /a addr and \a len from \a uri, whose path is expected to contain a - * host:port pair. Returns true upon success. */ -int parse_ipv4(grpc_uri *uri, grpc_resolved_address *resolved_addr); - -/** Populate /a addr and \a len from \a uri, whose path is expected to contain a - * host:port pair. Returns true upon success. */ -int parse_ipv6(grpc_uri *uri, grpc_resolved_address *resolved_addr); - -#endif /* GRPC_CORE_EXT_CLIENT_CHANNEL_PARSE_ADDRESS_H */ diff --git a/Sources/CgRPC/src/core/ext/client_channel/resolver.c b/Sources/CgRPC/src/core/ext/client_channel/resolver.c deleted file mode 100644 index 2ae4fe862..000000000 --- a/Sources/CgRPC/src/core/ext/client_channel/resolver.c +++ /dev/null @@ -1,81 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include "src/core/ext/client_channel/resolver.h" - -void grpc_resolver_init(grpc_resolver *resolver, - const grpc_resolver_vtable *vtable) { - resolver->vtable = vtable; - gpr_ref_init(&resolver->refs, 1); -} - -#ifdef GRPC_RESOLVER_REFCOUNT_DEBUG -void grpc_resolver_ref(grpc_resolver *resolver, grpc_closure_list *closure_list, - const char *file, int line, const char *reason) { - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "RESOLVER:%p ref %d -> %d %s", - resolver, (int)resolver->refs.count, (int)resolver->refs.count + 1, - reason); -#else -void grpc_resolver_ref(grpc_resolver *resolver) { -#endif - gpr_ref(&resolver->refs); -} - -#ifdef GRPC_RESOLVER_REFCOUNT_DEBUG -void grpc_resolver_unref(grpc_resolver *resolver, - grpc_closure_list *closure_list, const char *file, - int line, const char *reason) { - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "RESOLVER:%p unref %d -> %d %s", - resolver, (int)resolver->refs.count, (int)resolver->refs.count - 1, - reason); -#else -void grpc_resolver_unref(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver) { -#endif - if (gpr_unref(&resolver->refs)) { - resolver->vtable->destroy(exec_ctx, resolver); - } -} - -void grpc_resolver_shutdown(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver) { - resolver->vtable->shutdown(exec_ctx, resolver); -} - -void grpc_resolver_channel_saw_error(grpc_exec_ctx *exec_ctx, - grpc_resolver *resolver) { - resolver->vtable->channel_saw_error(exec_ctx, resolver); -} - -void grpc_resolver_next(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver, - grpc_channel_args **result, grpc_closure *on_complete) { - resolver->vtable->next(exec_ctx, resolver, result, on_complete); -} diff --git a/Sources/CgRPC/src/core/ext/client_channel/resolver.h b/Sources/CgRPC/src/core/ext/client_channel/resolver.h deleted file mode 100644 index 96ece92b9..000000000 --- a/Sources/CgRPC/src/core/ext/client_channel/resolver.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#ifndef GRPC_CORE_EXT_CLIENT_CHANNEL_RESOLVER_H -#define GRPC_CORE_EXT_CLIENT_CHANNEL_RESOLVER_H - -#include "src/core/ext/client_channel/subchannel.h" -#include "src/core/lib/iomgr/iomgr.h" - -typedef struct grpc_resolver grpc_resolver; -typedef struct grpc_resolver_vtable grpc_resolver_vtable; - -/** \a grpc_resolver provides \a grpc_channel_args objects to its caller */ -struct grpc_resolver { - const grpc_resolver_vtable *vtable; - gpr_refcount refs; -}; - -struct grpc_resolver_vtable { - void (*destroy)(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver); - void (*shutdown)(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver); - void (*channel_saw_error)(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver); - void (*next)(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver, - grpc_channel_args **result, grpc_closure *on_complete); -}; - -#ifdef GRPC_RESOLVER_REFCOUNT_DEBUG -#define GRPC_RESOLVER_REF(p, r) grpc_resolver_ref((p), __FILE__, __LINE__, (r)) -#define GRPC_RESOLVER_UNREF(cl, p, r) \ - grpc_resolver_unref((cl), (p), __FILE__, __LINE__, (r)) -void grpc_resolver_ref(grpc_resolver *policy, const char *file, int line, - const char *reason); -void grpc_resolver_unref(grpc_resolver *policy, grpc_closure_list *closure_list, - const char *file, int line, const char *reason); -#else -#define GRPC_RESOLVER_REF(p, r) grpc_resolver_ref((p)) -#define GRPC_RESOLVER_UNREF(cl, p, r) grpc_resolver_unref((cl), (p)) -void grpc_resolver_ref(grpc_resolver *policy); -void grpc_resolver_unref(grpc_exec_ctx *exec_ctx, grpc_resolver *policy); -#endif - -void grpc_resolver_init(grpc_resolver *resolver, - const grpc_resolver_vtable *vtable); - -void grpc_resolver_shutdown(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver); - -/** Notification that the channel has seen an error on some address. - Can be used as a hint that re-resolution is desirable soon. */ -void grpc_resolver_channel_saw_error(grpc_exec_ctx *exec_ctx, - grpc_resolver *resolver); - -/** Get the next result from the resolver. Expected to set \a *result with - new channel args and then schedule \a on_complete for execution. - - If resolution is fatally broken, set \a *result to NULL and - schedule \a on_complete. */ -void grpc_resolver_next(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver, - grpc_channel_args **result, grpc_closure *on_complete); - -#endif /* GRPC_CORE_EXT_CLIENT_CHANNEL_RESOLVER_H */ diff --git a/Sources/CgRPC/src/core/ext/client_channel/resolver_factory.c b/Sources/CgRPC/src/core/ext/client_channel/resolver_factory.c deleted file mode 100644 index 00bbb92dd..000000000 --- a/Sources/CgRPC/src/core/ext/client_channel/resolver_factory.c +++ /dev/null @@ -1,56 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include "src/core/ext/client_channel/resolver_factory.h" - -void grpc_resolver_factory_ref(grpc_resolver_factory* factory) { - factory->vtable->ref(factory); -} - -void grpc_resolver_factory_unref(grpc_resolver_factory* factory) { - factory->vtable->unref(factory); -} - -/** Create a resolver instance for a name */ -grpc_resolver* grpc_resolver_factory_create_resolver( - grpc_exec_ctx* exec_ctx, grpc_resolver_factory* factory, - grpc_resolver_args* args) { - if (factory == NULL) return NULL; - return factory->vtable->create_resolver(exec_ctx, factory, args); -} - -char* grpc_resolver_factory_get_default_authority( - grpc_resolver_factory* factory, grpc_uri* uri) { - if (factory == NULL) return NULL; - return factory->vtable->get_default_authority(factory, uri); -} diff --git a/Sources/CgRPC/src/core/ext/client_channel/resolver_factory.h b/Sources/CgRPC/src/core/ext/client_channel/resolver_factory.h deleted file mode 100644 index 3792ddca1..000000000 --- a/Sources/CgRPC/src/core/ext/client_channel/resolver_factory.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#ifndef GRPC_CORE_EXT_CLIENT_CHANNEL_RESOLVER_FACTORY_H -#define GRPC_CORE_EXT_CLIENT_CHANNEL_RESOLVER_FACTORY_H - -#include "src/core/ext/client_channel/client_channel_factory.h" -#include "src/core/ext/client_channel/resolver.h" -#include "src/core/ext/client_channel/uri_parser.h" -#include "src/core/lib/iomgr/pollset_set.h" - -typedef struct grpc_resolver_factory grpc_resolver_factory; -typedef struct grpc_resolver_factory_vtable grpc_resolver_factory_vtable; - -struct grpc_resolver_factory { - const grpc_resolver_factory_vtable *vtable; -}; - -typedef struct grpc_resolver_args { - grpc_uri *uri; - const grpc_channel_args *args; - grpc_pollset_set *pollset_set; -} grpc_resolver_args; - -struct grpc_resolver_factory_vtable { - void (*ref)(grpc_resolver_factory *factory); - void (*unref)(grpc_resolver_factory *factory); - - /** Implementation of grpc_resolver_factory_create_resolver */ - grpc_resolver *(*create_resolver)(grpc_exec_ctx *exec_ctx, - grpc_resolver_factory *factory, - grpc_resolver_args *args); - - /** Implementation of grpc_resolver_factory_get_default_authority */ - char *(*get_default_authority)(grpc_resolver_factory *factory, grpc_uri *uri); - - /** URI scheme that this factory implements */ - const char *scheme; -}; - -void grpc_resolver_factory_ref(grpc_resolver_factory *resolver); -void grpc_resolver_factory_unref(grpc_resolver_factory *resolver); - -/** Create a resolver instance for a name */ -grpc_resolver *grpc_resolver_factory_create_resolver( - grpc_exec_ctx *exec_ctx, grpc_resolver_factory *factory, - grpc_resolver_args *args); - -/** Return a (freshly allocated with gpr_malloc) string representing - the default authority to use for this scheme. */ -char *grpc_resolver_factory_get_default_authority( - grpc_resolver_factory *factory, grpc_uri *uri); - -#endif /* GRPC_CORE_EXT_CLIENT_CHANNEL_RESOLVER_FACTORY_H */ diff --git a/Sources/CgRPC/src/core/ext/client_channel/resolver_registry.h b/Sources/CgRPC/src/core/ext/client_channel/resolver_registry.h deleted file mode 100644 index 4fb16131d..000000000 --- a/Sources/CgRPC/src/core/ext/client_channel/resolver_registry.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#ifndef GRPC_CORE_EXT_CLIENT_CHANNEL_RESOLVER_REGISTRY_H -#define GRPC_CORE_EXT_CLIENT_CHANNEL_RESOLVER_REGISTRY_H - -#include "src/core/ext/client_channel/resolver_factory.h" -#include "src/core/lib/iomgr/pollset_set.h" - -void grpc_resolver_registry_init(); -void grpc_resolver_registry_shutdown(void); - -/** Set the default URI prefix to \a default_prefix. */ -void grpc_resolver_registry_set_default_prefix(const char *default_prefix); - -/** Register a resolver type. - URI's of \a scheme will be resolved with the given resolver. - If \a priority is greater than zero, then the resolver will be eligible - to resolve names that are passed in with no scheme. Higher priority - resolvers will be tried before lower priority schemes. */ -void grpc_register_resolver_type(grpc_resolver_factory *factory); - -/** Create a resolver given \a target. - First tries to parse \a target as a URI. If this succeeds, tries - to locate a registered resolver factory based on the URI scheme. - If parsing or location fails, prefixes default_prefix from - grpc_resolver_registry_init to target, and tries again (if default_prefix - was not NULL). - If a resolver factory was found, use it to instantiate a resolver and - return it. - If a resolver factory was not found, return NULL. - \a args is a set of channel arguments to be included in the result - (typically the set of arguments passed in from the client API). */ -grpc_resolver *grpc_resolver_create(grpc_exec_ctx *exec_ctx, const char *target, - const grpc_channel_args *args, - grpc_pollset_set *pollset_set); - -/** Find a resolver factory given a name and return an (owned-by-the-caller) - * reference to it */ -grpc_resolver_factory *grpc_resolver_factory_lookup(const char *name); - -/** Given a target, return a (freshly allocated with gpr_malloc) string - representing the default authority to pass from a client. */ -char *grpc_get_default_authority(const char *target); - -/** Returns a newly allocated string containing \a target, adding the - default prefix if needed. */ -char *grpc_resolver_factory_add_default_prefix_if_needed(const char *target); - -#endif /* GRPC_CORE_EXT_CLIENT_CHANNEL_RESOLVER_REGISTRY_H */ diff --git a/Sources/CgRPC/src/core/ext/client_channel/subchannel_index.c b/Sources/CgRPC/src/core/ext/client_channel/subchannel_index.c deleted file mode 100644 index a1ba5e945..000000000 --- a/Sources/CgRPC/src/core/ext/client_channel/subchannel_index.c +++ /dev/null @@ -1,274 +0,0 @@ -// -// -// Copyright 2016, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// - -#include "src/core/ext/client_channel/subchannel_index.h" - -#include -#include - -#include -#include -#include -#include - -#include "src/core/lib/channel/channel_args.h" - -// a map of subchannel_key --> subchannel, used for detecting connections -// to the same destination in order to share them -static gpr_avl g_subchannel_index; - -static gpr_mu g_mu; - -struct grpc_subchannel_key { - grpc_connector *connector; - grpc_subchannel_args args; -}; - -GPR_TLS_DECL(subchannel_index_exec_ctx); - -static void enter_ctx(grpc_exec_ctx *exec_ctx) { - GPR_ASSERT(gpr_tls_get(&subchannel_index_exec_ctx) == 0); - gpr_tls_set(&subchannel_index_exec_ctx, (intptr_t)exec_ctx); -} - -static void leave_ctx(grpc_exec_ctx *exec_ctx) { - GPR_ASSERT(gpr_tls_get(&subchannel_index_exec_ctx) == (intptr_t)exec_ctx); - gpr_tls_set(&subchannel_index_exec_ctx, 0); -} - -static grpc_exec_ctx *current_ctx() { - grpc_exec_ctx *c = (grpc_exec_ctx *)gpr_tls_get(&subchannel_index_exec_ctx); - GPR_ASSERT(c != NULL); - return c; -} - -static grpc_subchannel_key *create_key( - grpc_connector *connector, const grpc_subchannel_args *args, - grpc_channel_args *(*copy_channel_args)(const grpc_channel_args *args)) { - grpc_subchannel_key *k = gpr_malloc(sizeof(*k)); - k->connector = grpc_connector_ref(connector); - k->args.filter_count = args->filter_count; - if (k->args.filter_count > 0) { - k->args.filters = - gpr_malloc(sizeof(*k->args.filters) * k->args.filter_count); - memcpy((grpc_channel_filter *)k->args.filters, args->filters, - sizeof(*k->args.filters) * k->args.filter_count); - } else { - k->args.filters = NULL; - } - k->args.addr = gpr_malloc(sizeof(grpc_resolved_address)); - k->args.addr->len = args->addr->len; - if (k->args.addr->len > 0) { - memcpy(k->args.addr, args->addr, sizeof(grpc_resolved_address)); - } - k->args.args = copy_channel_args(args->args); - return k; -} - -grpc_subchannel_key *grpc_subchannel_key_create( - grpc_connector *connector, const grpc_subchannel_args *args) { - return create_key(connector, args, grpc_channel_args_normalize); -} - -static grpc_subchannel_key *subchannel_key_copy(grpc_subchannel_key *k) { - return create_key(k->connector, &k->args, grpc_channel_args_copy); -} - -static int subchannel_key_compare(grpc_subchannel_key *a, - grpc_subchannel_key *b) { - int c = GPR_ICMP(a->connector, b->connector); - if (c != 0) return c; - c = GPR_ICMP(a->args.addr->len, b->args.addr->len); - if (c != 0) return c; - c = GPR_ICMP(a->args.filter_count, b->args.filter_count); - if (c != 0) return c; - if (a->args.addr->len) { - c = memcmp(a->args.addr->addr, b->args.addr->addr, a->args.addr->len); - if (c != 0) return c; - } - if (a->args.filter_count > 0) { - c = memcmp(a->args.filters, b->args.filters, - a->args.filter_count * sizeof(*a->args.filters)); - if (c != 0) return c; - } - return grpc_channel_args_compare(a->args.args, b->args.args); -} - -void grpc_subchannel_key_destroy(grpc_exec_ctx *exec_ctx, - grpc_subchannel_key *k) { - grpc_connector_unref(exec_ctx, k->connector); - gpr_free((grpc_channel_args *)k->args.filters); - grpc_channel_args_destroy((grpc_channel_args *)k->args.args); - gpr_free(k->args.addr); - gpr_free(k); -} - -static void sck_avl_destroy(void *p) { - grpc_subchannel_key_destroy(current_ctx(), p); -} - -static void *sck_avl_copy(void *p) { return subchannel_key_copy(p); } - -static long sck_avl_compare(void *a, void *b) { - return subchannel_key_compare(a, b); -} - -static void scv_avl_destroy(void *p) { - GRPC_SUBCHANNEL_WEAK_UNREF(current_ctx(), p, "subchannel_index"); -} - -static void *scv_avl_copy(void *p) { - GRPC_SUBCHANNEL_WEAK_REF(p, "subchannel_index"); - return p; -} - -static const gpr_avl_vtable subchannel_avl_vtable = { - .destroy_key = sck_avl_destroy, - .copy_key = sck_avl_copy, - .compare_keys = sck_avl_compare, - .destroy_value = scv_avl_destroy, - .copy_value = scv_avl_copy}; - -void grpc_subchannel_index_init(void) { - g_subchannel_index = gpr_avl_create(&subchannel_avl_vtable); - gpr_mu_init(&g_mu); - gpr_tls_init(&subchannel_index_exec_ctx); -} - -void grpc_subchannel_index_shutdown(void) { - gpr_mu_destroy(&g_mu); - gpr_avl_unref(g_subchannel_index); - gpr_tls_destroy(&subchannel_index_exec_ctx); -} - -grpc_subchannel *grpc_subchannel_index_find(grpc_exec_ctx *exec_ctx, - grpc_subchannel_key *key) { - enter_ctx(exec_ctx); - - // Lock, and take a reference to the subchannel index. - // We don't need to do the search under a lock as avl's are immutable. - gpr_mu_lock(&g_mu); - gpr_avl index = gpr_avl_ref(g_subchannel_index); - gpr_mu_unlock(&g_mu); - - grpc_subchannel *c = - GRPC_SUBCHANNEL_REF_FROM_WEAK_REF(gpr_avl_get(index, key), "index_find"); - gpr_avl_unref(index); - - leave_ctx(exec_ctx); - return c; -} - -grpc_subchannel *grpc_subchannel_index_register(grpc_exec_ctx *exec_ctx, - grpc_subchannel_key *key, - grpc_subchannel *constructed) { - enter_ctx(exec_ctx); - - grpc_subchannel *c = NULL; - - while (c == NULL) { - // Compare and swap loop: - // - take a reference to the current index - gpr_mu_lock(&g_mu); - gpr_avl index = gpr_avl_ref(g_subchannel_index); - gpr_mu_unlock(&g_mu); - - // - Check to see if a subchannel already exists - c = gpr_avl_get(index, key); - if (c != NULL) { - // yes -> we're done - GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, constructed, "index_register"); - } else { - // no -> update the avl and compare/swap - gpr_avl updated = - gpr_avl_add(gpr_avl_ref(index), subchannel_key_copy(key), - GRPC_SUBCHANNEL_WEAK_REF(constructed, "index_register")); - - // it may happen (but it's expected to be unlikely) - // that some other thread has changed the index: - // compare/swap here to check that, and retry as necessary - gpr_mu_lock(&g_mu); - if (index.root == g_subchannel_index.root) { - GPR_SWAP(gpr_avl, updated, g_subchannel_index); - c = constructed; - } - gpr_mu_unlock(&g_mu); - - gpr_avl_unref(updated); - } - gpr_avl_unref(index); - } - - leave_ctx(exec_ctx); - - return c; -} - -void grpc_subchannel_index_unregister(grpc_exec_ctx *exec_ctx, - grpc_subchannel_key *key, - grpc_subchannel *constructed) { - enter_ctx(exec_ctx); - - bool done = false; - while (!done) { - // Compare and swap loop: - // - take a reference to the current index - gpr_mu_lock(&g_mu); - gpr_avl index = gpr_avl_ref(g_subchannel_index); - gpr_mu_unlock(&g_mu); - - // Check to see if this key still refers to the previously - // registered subchannel - grpc_subchannel *c = gpr_avl_get(index, key); - if (c != constructed) { - gpr_avl_unref(index); - break; - } - - // compare and swap the update (some other thread may have - // mutated the index behind us) - gpr_avl updated = gpr_avl_remove(gpr_avl_ref(index), key); - - gpr_mu_lock(&g_mu); - if (index.root == g_subchannel_index.root) { - GPR_SWAP(gpr_avl, updated, g_subchannel_index); - done = true; - } - gpr_mu_unlock(&g_mu); - - gpr_avl_unref(updated); - gpr_avl_unref(index); - } - - leave_ctx(exec_ctx); -} diff --git a/Sources/CgRPC/src/core/ext/client_channel/subchannel_index.h b/Sources/CgRPC/src/core/ext/client_channel/subchannel_index.h deleted file mode 100644 index a67bd5e21..000000000 --- a/Sources/CgRPC/src/core/ext/client_channel/subchannel_index.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * - * Copyright 2016, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#ifndef GRPC_CORE_EXT_CLIENT_CHANNEL_SUBCHANNEL_INDEX_H -#define GRPC_CORE_EXT_CLIENT_CHANNEL_SUBCHANNEL_INDEX_H - -#include "src/core/ext/client_channel/connector.h" -#include "src/core/ext/client_channel/subchannel.h" - -/** \file Provides an index of active subchannels so that they can be - shared amongst channels */ - -typedef struct grpc_subchannel_key grpc_subchannel_key; - -/** Create a key that can be used to uniquely identify a subchannel */ -grpc_subchannel_key *grpc_subchannel_key_create( - grpc_connector *con, const grpc_subchannel_args *args); - -/** Destroy a subchannel key */ -void grpc_subchannel_key_destroy(grpc_exec_ctx *exec_ctx, - grpc_subchannel_key *key); - -/** Given a subchannel key, find the subchannel registered for it. - Returns NULL if no such channel exists. - Thread-safe. */ -grpc_subchannel *grpc_subchannel_index_find(grpc_exec_ctx *exec_ctx, - grpc_subchannel_key *key); - -/** Register a subchannel against a key. - Takes ownership of \a constructed. - Returns the registered subchannel. This may be different from - \a constructed in the case of a registration race. */ -grpc_subchannel *grpc_subchannel_index_register(grpc_exec_ctx *exec_ctx, - grpc_subchannel_key *key, - grpc_subchannel *constructed); - -/** Remove \a constructed as the registered subchannel for \a key. */ -void grpc_subchannel_index_unregister(grpc_exec_ctx *exec_ctx, - grpc_subchannel_key *key, - grpc_subchannel *constructed); - -/** Initialize the subchannel index (global) */ -void grpc_subchannel_index_init(void); -/** Shutdown the subchannel index (global) */ -void grpc_subchannel_index_shutdown(void); - -#endif /* GRPC_CORE_EXT_CLIENT_CHANNEL_SUBCHANNEL_INDEX_H */ diff --git a/Sources/CgRPC/src/core/ext/client_channel/uri_parser.h b/Sources/CgRPC/src/core/ext/client_channel/uri_parser.h deleted file mode 100644 index 5fe0e8f35..000000000 --- a/Sources/CgRPC/src/core/ext/client_channel/uri_parser.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#ifndef GRPC_CORE_EXT_CLIENT_CHANNEL_URI_PARSER_H -#define GRPC_CORE_EXT_CLIENT_CHANNEL_URI_PARSER_H - -#include - -typedef struct { - char *scheme; - char *authority; - char *path; - char *query; - /** Query substrings separated by '&' */ - char **query_parts; - /** Number of elements in \a query_parts and \a query_parts_values */ - size_t num_query_parts; - /** Split each query part by '='. NULL if not present. */ - char **query_parts_values; - char *fragment; -} grpc_uri; - -/** parse a uri, return NULL on failure */ -grpc_uri *grpc_uri_parse(const char *uri_text, int suppress_errors); - -/** return the part of a query string after the '=' in "?key=xxx&...", or NULL - * if key is not present */ -const char *grpc_uri_get_query_arg(const grpc_uri *uri, const char *key); - -/** destroy a uri */ -void grpc_uri_destroy(grpc_uri *uri); - -#endif /* GRPC_CORE_EXT_CLIENT_CHANNEL_URI_PARSER_H */ diff --git a/Sources/CgRPC/src/core/ext/client_channel/channel_connectivity.c b/Sources/CgRPC/src/core/ext/filters/client_channel/channel_connectivity.c similarity index 59% rename from Sources/CgRPC/src/core/ext/client_channel/channel_connectivity.c rename to Sources/CgRPC/src/core/ext/filters/client_channel/channel_connectivity.c index 9797e6656..b83c95275 100644 --- a/Sources/CgRPC/src/core/ext/client_channel/channel_connectivity.c +++ b/Sources/CgRPC/src/core/ext/filters/client_channel/channel_connectivity.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -36,7 +21,7 @@ #include #include -#include "src/core/ext/client_channel/client_channel.h" +#include "src/core/ext/filters/client_channel/client_channel.h" #include "src/core/lib/iomgr/timer.h" #include "src/core/lib/surface/api_trace.h" #include "src/core/lib/surface/completion_queue.h" @@ -67,20 +52,22 @@ grpc_connectivity_state grpc_channel_check_connectivity_state( typedef enum { WAITING, - CALLING_BACK, + READY_TO_CALL_BACK, CALLING_BACK_AND_FINISHED, - CALLED_BACK } callback_phase; typedef struct { gpr_mu mu; callback_phase phase; grpc_closure on_complete; + grpc_closure on_timeout; + grpc_closure watcher_timer_init; grpc_timer alarm; grpc_connectivity_state state; grpc_completion_queue *cq; grpc_cq_completion completion_storage; grpc_channel *channel; + grpc_error *error; void *tag; } state_watcher; @@ -104,11 +91,8 @@ static void finished_completion(grpc_exec_ctx *exec_ctx, void *pw, gpr_mu_lock(&w->mu); switch (w->phase) { case WAITING: - case CALLED_BACK: + case READY_TO_CALL_BACK: GPR_UNREACHABLE_CODE(return ); - case CALLING_BACK: - w->phase = CALLED_BACK; - break; case CALLING_BACK_AND_FINISHED: delete = 1; break; @@ -122,49 +106,56 @@ static void finished_completion(grpc_exec_ctx *exec_ctx, void *pw, static void partly_done(grpc_exec_ctx *exec_ctx, state_watcher *w, bool due_to_completion, grpc_error *error) { - int delete = 0; - if (due_to_completion) { grpc_timer_cancel(exec_ctx, &w->alarm); + } else { + grpc_channel_element *client_channel_elem = grpc_channel_stack_last_element( + grpc_channel_get_channel_stack(w->channel)); + grpc_client_channel_watch_connectivity_state( + exec_ctx, client_channel_elem, + grpc_polling_entity_create_from_pollset(grpc_cq_pollset(w->cq)), NULL, + &w->on_complete, NULL); } gpr_mu_lock(&w->mu); if (due_to_completion) { - if (grpc_trace_operation_failures) { + if (GRPC_TRACER_ON(grpc_trace_operation_failures)) { GRPC_LOG_IF_ERROR("watch_completion_error", GRPC_ERROR_REF(error)); } GRPC_ERROR_UNREF(error); error = GRPC_ERROR_NONE; } else { if (error == GRPC_ERROR_NONE) { - error = - GRPC_ERROR_CREATE("Timed out waiting for connection state change"); + error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "Timed out waiting for connection state change"); } else if (error == GRPC_ERROR_CANCELLED) { error = GRPC_ERROR_NONE; } } switch (w->phase) { case WAITING: - w->phase = CALLING_BACK; - grpc_cq_end_op(exec_ctx, w->cq, w->tag, GRPC_ERROR_REF(error), - finished_completion, w, &w->completion_storage); + GRPC_ERROR_REF(error); + w->error = error; + w->phase = READY_TO_CALL_BACK; break; - case CALLING_BACK: + case READY_TO_CALL_BACK: + if (error != GRPC_ERROR_NONE) { + GPR_ASSERT(!due_to_completion); + GRPC_ERROR_UNREF(w->error); + GRPC_ERROR_REF(error); + w->error = error; + } w->phase = CALLING_BACK_AND_FINISHED; + grpc_cq_end_op(exec_ctx, w->cq, w->tag, w->error, finished_completion, w, + &w->completion_storage); break; case CALLING_BACK_AND_FINISHED: GPR_UNREACHABLE_CODE(return ); - case CALLED_BACK: - delete = 1; break; } gpr_mu_unlock(&w->mu); - if (delete) { - delete_state_watcher(exec_ctx, w); - } - GRPC_ERROR_UNREF(error); } @@ -178,6 +169,28 @@ static void timeout_complete(grpc_exec_ctx *exec_ctx, void *pw, partly_done(exec_ctx, pw, false, GRPC_ERROR_REF(error)); } +int grpc_channel_num_external_connectivity_watchers(grpc_channel *channel) { + grpc_channel_element *client_channel_elem = + grpc_channel_stack_last_element(grpc_channel_get_channel_stack(channel)); + return grpc_client_channel_num_external_connectivity_watchers( + client_channel_elem); +} + +typedef struct watcher_timer_init_arg { + state_watcher *w; + gpr_timespec deadline; +} watcher_timer_init_arg; + +static void watcher_timer_init(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error_ignored) { + watcher_timer_init_arg *wa = (watcher_timer_init_arg *)arg; + + grpc_timer_init(exec_ctx, &wa->w->alarm, + gpr_convert_clock_type(wa->deadline, GPR_CLOCK_MONOTONIC), + &wa->w->on_timeout, gpr_now(GPR_CLOCK_MONOTONIC)); + gpr_free(wa); +} + void grpc_channel_watch_connectivity_state( grpc_channel *channel, grpc_connectivity_state last_observed_state, gpr_timespec deadline, grpc_completion_queue *cq, void *tag) { @@ -195,25 +208,32 @@ void grpc_channel_watch_connectivity_state( 7, (channel, (int)last_observed_state, deadline.tv_sec, deadline.tv_nsec, (int)deadline.clock_type, cq, tag)); - grpc_cq_begin_op(cq, tag); + GPR_ASSERT(grpc_cq_begin_op(cq, tag)); gpr_mu_init(&w->mu); - grpc_closure_init(&w->on_complete, watch_complete, w); + GRPC_CLOSURE_INIT(&w->on_complete, watch_complete, w, + grpc_schedule_on_exec_ctx); + GRPC_CLOSURE_INIT(&w->on_timeout, timeout_complete, w, + grpc_schedule_on_exec_ctx); w->phase = WAITING; w->state = last_observed_state; w->cq = cq; w->tag = tag; w->channel = channel; + w->error = NULL; - grpc_timer_init(&exec_ctx, &w->alarm, - gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC), - timeout_complete, w, gpr_now(GPR_CLOCK_MONOTONIC)); + watcher_timer_init_arg *wa = gpr_malloc(sizeof(watcher_timer_init_arg)); + wa->w = w; + wa->deadline = deadline; + GRPC_CLOSURE_INIT(&w->watcher_timer_init, watcher_timer_init, wa, + grpc_schedule_on_exec_ctx); if (client_channel_elem->filter == &grpc_client_channel_filter) { GRPC_CHANNEL_INTERNAL_REF(channel, "watch_channel_connectivity"); - grpc_client_channel_watch_connectivity_state(&exec_ctx, client_channel_elem, - grpc_cq_pollset(cq), &w->state, - &w->on_complete); + grpc_client_channel_watch_connectivity_state( + &exec_ctx, client_channel_elem, + grpc_polling_entity_create_from_pollset(grpc_cq_pollset(cq)), &w->state, + &w->on_complete, &w->watcher_timer_init); } else { abort(); } diff --git a/Sources/CgRPC/src/core/ext/filters/client_channel/client_channel.c b/Sources/CgRPC/src/core/ext/filters/client_channel/client_channel.c new file mode 100644 index 000000000..58e31d7b4 --- /dev/null +++ b/Sources/CgRPC/src/core/ext/filters/client_channel/client_channel.c @@ -0,0 +1,1678 @@ +/* + * + * 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 "src/core/ext/filters/client_channel/client_channel.h" + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "src/core/ext/filters/client_channel/http_connect_handshaker.h" +#include "src/core/ext/filters/client_channel/lb_policy_registry.h" +#include "src/core/ext/filters/client_channel/proxy_mapper_registry.h" +#include "src/core/ext/filters/client_channel/resolver_registry.h" +#include "src/core/ext/filters/client_channel/retry_throttle.h" +#include "src/core/ext/filters/client_channel/subchannel.h" +#include "src/core/ext/filters/deadline/deadline_filter.h" +#include "src/core/lib/channel/channel_args.h" +#include "src/core/lib/channel/connected_channel.h" +#include "src/core/lib/iomgr/combiner.h" +#include "src/core/lib/iomgr/iomgr.h" +#include "src/core/lib/iomgr/polling_entity.h" +#include "src/core/lib/profiling/timers.h" +#include "src/core/lib/slice/slice_internal.h" +#include "src/core/lib/support/string.h" +#include "src/core/lib/surface/channel.h" +#include "src/core/lib/transport/connectivity_state.h" +#include "src/core/lib/transport/metadata.h" +#include "src/core/lib/transport/metadata_batch.h" +#include "src/core/lib/transport/service_config.h" +#include "src/core/lib/transport/static_metadata.h" + +/* Client channel implementation */ + +grpc_tracer_flag grpc_client_channel_trace = + GRPC_TRACER_INITIALIZER(false, "client_channel"); + +/************************************************************************* + * METHOD-CONFIG TABLE + */ + +typedef enum { + /* zero so it can be default initialized */ + WAIT_FOR_READY_UNSET = 0, + WAIT_FOR_READY_FALSE, + WAIT_FOR_READY_TRUE +} wait_for_ready_value; + +typedef struct { + gpr_refcount refs; + gpr_timespec timeout; + wait_for_ready_value wait_for_ready; +} method_parameters; + +static method_parameters *method_parameters_ref( + method_parameters *method_params) { + gpr_ref(&method_params->refs); + return method_params; +} + +static void method_parameters_unref(method_parameters *method_params) { + if (gpr_unref(&method_params->refs)) { + gpr_free(method_params); + } +} + +static void method_parameters_free(grpc_exec_ctx *exec_ctx, void *value) { + method_parameters_unref(value); +} + +static bool parse_wait_for_ready(grpc_json *field, + wait_for_ready_value *wait_for_ready) { + if (field->type != GRPC_JSON_TRUE && field->type != GRPC_JSON_FALSE) { + return false; + } + *wait_for_ready = field->type == GRPC_JSON_TRUE ? WAIT_FOR_READY_TRUE + : WAIT_FOR_READY_FALSE; + return true; +} + +static bool parse_timeout(grpc_json *field, gpr_timespec *timeout) { + if (field->type != GRPC_JSON_STRING) return false; + size_t len = strlen(field->value); + if (field->value[len - 1] != 's') return false; + char *buf = gpr_strdup(field->value); + buf[len - 1] = '\0'; // Remove trailing 's'. + char *decimal_point = strchr(buf, '.'); + if (decimal_point != NULL) { + *decimal_point = '\0'; + timeout->tv_nsec = gpr_parse_nonnegative_int(decimal_point + 1); + if (timeout->tv_nsec == -1) { + gpr_free(buf); + return false; + } + // There should always be exactly 3, 6, or 9 fractional digits. + int multiplier = 1; + switch (strlen(decimal_point + 1)) { + case 9: + break; + case 6: + multiplier *= 1000; + break; + case 3: + multiplier *= 1000000; + break; + default: // Unsupported number of digits. + gpr_free(buf); + return false; + } + timeout->tv_nsec *= multiplier; + } + timeout->tv_sec = gpr_parse_nonnegative_int(buf); + gpr_free(buf); + if (timeout->tv_sec == -1) return false; + return true; +} + +static void *method_parameters_create_from_json(const grpc_json *json) { + wait_for_ready_value wait_for_ready = WAIT_FOR_READY_UNSET; + gpr_timespec timeout = {0, 0, GPR_TIMESPAN}; + for (grpc_json *field = json->child; field != NULL; field = field->next) { + if (field->key == NULL) continue; + if (strcmp(field->key, "waitForReady") == 0) { + if (wait_for_ready != WAIT_FOR_READY_UNSET) return NULL; // Duplicate. + if (!parse_wait_for_ready(field, &wait_for_ready)) return NULL; + } else if (strcmp(field->key, "timeout") == 0) { + if (timeout.tv_sec > 0 || timeout.tv_nsec > 0) return NULL; // Duplicate. + if (!parse_timeout(field, &timeout)) return NULL; + } + } + method_parameters *value = gpr_malloc(sizeof(method_parameters)); + gpr_ref_init(&value->refs, 1); + value->timeout = timeout; + value->wait_for_ready = wait_for_ready; + return value; +} + +struct external_connectivity_watcher; + +/************************************************************************* + * CHANNEL-WIDE FUNCTIONS + */ + +typedef struct client_channel_channel_data { + /** resolver for this channel */ + grpc_resolver *resolver; + /** have we started resolving this channel */ + bool started_resolving; + /** is deadline checking enabled? */ + bool deadline_checking_enabled; + /** client channel factory */ + grpc_client_channel_factory *client_channel_factory; + + /** combiner protecting all variables below in this data structure */ + grpc_combiner *combiner; + /** currently active load balancer */ + grpc_lb_policy *lb_policy; + /** retry throttle data */ + grpc_server_retry_throttle_data *retry_throttle_data; + /** maps method names to method_parameters structs */ + grpc_slice_hash_table *method_params_table; + /** incoming resolver result - set by resolver.next() */ + grpc_channel_args *resolver_result; + /** a list of closures that are all waiting for resolver result to come in */ + grpc_closure_list waiting_for_resolver_result_closures; + /** resolver callback */ + grpc_closure on_resolver_result_changed; + /** connectivity state being tracked */ + grpc_connectivity_state_tracker state_tracker; + /** when an lb_policy arrives, should we try to exit idle */ + bool exit_idle_when_lb_policy_arrives; + /** owning stack */ + grpc_channel_stack *owning_stack; + /** interested parties (owned) */ + grpc_pollset_set *interested_parties; + + /* external_connectivity_watcher_list head is guarded by its own mutex, since + * counts need to be grabbed immediately without polling on a cq */ + gpr_mu external_connectivity_watcher_list_mu; + struct external_connectivity_watcher *external_connectivity_watcher_list_head; + + /* the following properties are guarded by a mutex since API's require them + to be instantaneously available */ + gpr_mu info_mu; + char *info_lb_policy_name; + /** service config in JSON form */ + char *info_service_config_json; +} channel_data; + +/** We create one watcher for each new lb_policy that is returned from a + resolver, to watch for state changes from the lb_policy. When a state + change is seen, we update the channel, and create a new watcher. */ +typedef struct { + channel_data *chand; + grpc_closure on_changed; + grpc_connectivity_state state; + grpc_lb_policy *lb_policy; +} lb_policy_connectivity_watcher; + +static void watch_lb_policy_locked(grpc_exec_ctx *exec_ctx, channel_data *chand, + grpc_lb_policy *lb_policy, + grpc_connectivity_state current_state); + +static void set_channel_connectivity_state_locked(grpc_exec_ctx *exec_ctx, + channel_data *chand, + grpc_connectivity_state state, + grpc_error *error, + const char *reason) { + /* TODO: Improve failure handling: + * - Make it possible for policies to return GRPC_CHANNEL_TRANSIENT_FAILURE. + * - Hand over pending picks from old policies during the switch that happens + * when resolver provides an update. */ + if (chand->lb_policy != NULL) { + if (state == GRPC_CHANNEL_TRANSIENT_FAILURE) { + /* cancel picks with wait_for_ready=false */ + grpc_lb_policy_cancel_picks_locked( + exec_ctx, chand->lb_policy, + /* mask= */ GRPC_INITIAL_METADATA_WAIT_FOR_READY, + /* check= */ 0, GRPC_ERROR_REF(error)); + } else if (state == GRPC_CHANNEL_SHUTDOWN) { + /* cancel all picks */ + grpc_lb_policy_cancel_picks_locked(exec_ctx, chand->lb_policy, + /* mask= */ 0, /* check= */ 0, + GRPC_ERROR_REF(error)); + } + } + if (GRPC_TRACER_ON(grpc_client_channel_trace)) { + gpr_log(GPR_DEBUG, "chand=%p: setting connectivity state to %s", chand, + grpc_connectivity_state_name(state)); + } + grpc_connectivity_state_set(exec_ctx, &chand->state_tracker, state, error, + reason); +} + +static void on_lb_policy_state_changed_locked(grpc_exec_ctx *exec_ctx, + void *arg, grpc_error *error) { + lb_policy_connectivity_watcher *w = arg; + grpc_connectivity_state publish_state = w->state; + /* check if the notification is for the latest policy */ + if (w->lb_policy == w->chand->lb_policy) { + if (GRPC_TRACER_ON(grpc_client_channel_trace)) { + gpr_log(GPR_DEBUG, "chand=%p: lb_policy=%p state changed to %s", w->chand, + w->lb_policy, grpc_connectivity_state_name(w->state)); + } + if (publish_state == GRPC_CHANNEL_SHUTDOWN && w->chand->resolver != NULL) { + publish_state = GRPC_CHANNEL_TRANSIENT_FAILURE; + grpc_resolver_channel_saw_error_locked(exec_ctx, w->chand->resolver); + GRPC_LB_POLICY_UNREF(exec_ctx, w->chand->lb_policy, "channel"); + w->chand->lb_policy = NULL; + } + set_channel_connectivity_state_locked(exec_ctx, w->chand, publish_state, + GRPC_ERROR_REF(error), "lb_changed"); + if (w->state != GRPC_CHANNEL_SHUTDOWN) { + watch_lb_policy_locked(exec_ctx, w->chand, w->lb_policy, w->state); + } + } + GRPC_CHANNEL_STACK_UNREF(exec_ctx, w->chand->owning_stack, "watch_lb_policy"); + gpr_free(w); +} + +static void watch_lb_policy_locked(grpc_exec_ctx *exec_ctx, channel_data *chand, + grpc_lb_policy *lb_policy, + grpc_connectivity_state current_state) { + lb_policy_connectivity_watcher *w = gpr_malloc(sizeof(*w)); + GRPC_CHANNEL_STACK_REF(chand->owning_stack, "watch_lb_policy"); + w->chand = chand; + GRPC_CLOSURE_INIT(&w->on_changed, on_lb_policy_state_changed_locked, w, + grpc_combiner_scheduler(chand->combiner)); + w->state = current_state; + w->lb_policy = lb_policy; + grpc_lb_policy_notify_on_state_change_locked(exec_ctx, lb_policy, &w->state, + &w->on_changed); +} + +static void start_resolving_locked(grpc_exec_ctx *exec_ctx, + channel_data *chand) { + if (GRPC_TRACER_ON(grpc_client_channel_trace)) { + gpr_log(GPR_DEBUG, "chand=%p: starting name resolution", chand); + } + GPR_ASSERT(!chand->started_resolving); + chand->started_resolving = true; + GRPC_CHANNEL_STACK_REF(chand->owning_stack, "resolver"); + grpc_resolver_next_locked(exec_ctx, chand->resolver, &chand->resolver_result, + &chand->on_resolver_result_changed); +} + +typedef struct { + char *server_name; + grpc_server_retry_throttle_data *retry_throttle_data; +} service_config_parsing_state; + +static void parse_retry_throttle_params(const grpc_json *field, void *arg) { + service_config_parsing_state *parsing_state = arg; + if (strcmp(field->key, "retryThrottling") == 0) { + if (parsing_state->retry_throttle_data != NULL) return; // Duplicate. + if (field->type != GRPC_JSON_OBJECT) return; + int max_milli_tokens = 0; + int milli_token_ratio = 0; + for (grpc_json *sub_field = field->child; sub_field != NULL; + sub_field = sub_field->next) { + if (sub_field->key == NULL) return; + if (strcmp(sub_field->key, "maxTokens") == 0) { + if (max_milli_tokens != 0) return; // Duplicate. + if (sub_field->type != GRPC_JSON_NUMBER) return; + max_milli_tokens = gpr_parse_nonnegative_int(sub_field->value); + if (max_milli_tokens == -1) return; + max_milli_tokens *= 1000; + } else if (strcmp(sub_field->key, "tokenRatio") == 0) { + if (milli_token_ratio != 0) return; // Duplicate. + if (sub_field->type != GRPC_JSON_NUMBER) return; + // We support up to 3 decimal digits. + size_t whole_len = strlen(sub_field->value); + uint32_t multiplier = 1; + uint32_t decimal_value = 0; + const char *decimal_point = strchr(sub_field->value, '.'); + if (decimal_point != NULL) { + whole_len = (size_t)(decimal_point - sub_field->value); + multiplier = 1000; + size_t decimal_len = strlen(decimal_point + 1); + if (decimal_len > 3) decimal_len = 3; + if (!gpr_parse_bytes_to_uint32(decimal_point + 1, decimal_len, + &decimal_value)) { + return; + } + uint32_t decimal_multiplier = 1; + for (size_t i = 0; i < (3 - decimal_len); ++i) { + decimal_multiplier *= 10; + } + decimal_value *= decimal_multiplier; + } + uint32_t whole_value; + if (!gpr_parse_bytes_to_uint32(sub_field->value, whole_len, + &whole_value)) { + return; + } + milli_token_ratio = (int)((whole_value * multiplier) + decimal_value); + if (milli_token_ratio <= 0) return; + } + } + parsing_state->retry_throttle_data = + grpc_retry_throttle_map_get_data_for_server( + parsing_state->server_name, max_milli_tokens, milli_token_ratio); + } +} + +static void on_resolver_result_changed_locked(grpc_exec_ctx *exec_ctx, + void *arg, grpc_error *error) { + channel_data *chand = arg; + if (GRPC_TRACER_ON(grpc_client_channel_trace)) { + gpr_log(GPR_DEBUG, "chand=%p: got resolver result: error=%s", chand, + grpc_error_string(error)); + } + // Extract the following fields from the resolver result, if non-NULL. + bool lb_policy_updated = false; + char *lb_policy_name = NULL; + bool lb_policy_name_changed = false; + grpc_lb_policy *new_lb_policy = NULL; + char *service_config_json = NULL; + grpc_server_retry_throttle_data *retry_throttle_data = NULL; + grpc_slice_hash_table *method_params_table = NULL; + if (chand->resolver_result != NULL) { + // Find LB policy name. + const grpc_arg *channel_arg = + grpc_channel_args_find(chand->resolver_result, GRPC_ARG_LB_POLICY_NAME); + if (channel_arg != NULL) { + GPR_ASSERT(channel_arg->type == GRPC_ARG_STRING); + lb_policy_name = channel_arg->value.string; + } + // Special case: If at least one balancer address is present, we use + // the grpclb policy, regardless of what the resolver actually specified. + channel_arg = + grpc_channel_args_find(chand->resolver_result, GRPC_ARG_LB_ADDRESSES); + if (channel_arg != NULL && channel_arg->type == GRPC_ARG_POINTER) { + grpc_lb_addresses *addresses = channel_arg->value.pointer.p; + bool found_balancer_address = false; + for (size_t i = 0; i < addresses->num_addresses; ++i) { + if (addresses->addresses[i].is_balancer) { + found_balancer_address = true; + break; + } + } + if (found_balancer_address) { + if (lb_policy_name != NULL && strcmp(lb_policy_name, "grpclb") != 0) { + gpr_log(GPR_INFO, + "resolver requested LB policy %s but provided at least one " + "balancer address -- forcing use of grpclb LB policy", + lb_policy_name); + } + lb_policy_name = "grpclb"; + } + } + // Use pick_first if nothing was specified and we didn't select grpclb + // above. + if (lb_policy_name == NULL) lb_policy_name = "pick_first"; + grpc_lb_policy_args lb_policy_args; + lb_policy_args.args = chand->resolver_result; + lb_policy_args.client_channel_factory = chand->client_channel_factory; + lb_policy_args.combiner = chand->combiner; + // Check to see if we're already using the right LB policy. + // Note: It's safe to use chand->info_lb_policy_name here without + // taking a lock on chand->info_mu, because this function is the + // only thing that modifies its value, and it can only be invoked + // once at any given time. + lb_policy_name_changed = + chand->info_lb_policy_name == NULL || + strcmp(chand->info_lb_policy_name, lb_policy_name) != 0; + if (chand->lb_policy != NULL && !lb_policy_name_changed) { + // Continue using the same LB policy. Update with new addresses. + lb_policy_updated = true; + grpc_lb_policy_update_locked(exec_ctx, chand->lb_policy, &lb_policy_args); + } else { + // Instantiate new LB policy. + new_lb_policy = + grpc_lb_policy_create(exec_ctx, lb_policy_name, &lb_policy_args); + if (new_lb_policy == NULL) { + gpr_log(GPR_ERROR, "could not create LB policy \"%s\"", lb_policy_name); + } + } + // Find service config. + channel_arg = + grpc_channel_args_find(chand->resolver_result, GRPC_ARG_SERVICE_CONFIG); + if (channel_arg != NULL) { + GPR_ASSERT(channel_arg->type == GRPC_ARG_STRING); + service_config_json = gpr_strdup(channel_arg->value.string); + grpc_service_config *service_config = + grpc_service_config_create(service_config_json); + if (service_config != NULL) { + channel_arg = + grpc_channel_args_find(chand->resolver_result, GRPC_ARG_SERVER_URI); + GPR_ASSERT(channel_arg != NULL); + GPR_ASSERT(channel_arg->type == GRPC_ARG_STRING); + grpc_uri *uri = + grpc_uri_parse(exec_ctx, channel_arg->value.string, true); + GPR_ASSERT(uri->path[0] != '\0'); + service_config_parsing_state parsing_state; + memset(&parsing_state, 0, sizeof(parsing_state)); + parsing_state.server_name = + uri->path[0] == '/' ? uri->path + 1 : uri->path; + grpc_service_config_parse_global_params( + service_config, parse_retry_throttle_params, &parsing_state); + grpc_uri_destroy(uri); + retry_throttle_data = parsing_state.retry_throttle_data; + method_params_table = grpc_service_config_create_method_config_table( + exec_ctx, service_config, method_parameters_create_from_json, + method_parameters_free); + grpc_service_config_destroy(service_config); + } + } + // Before we clean up, save a copy of lb_policy_name, since it might + // be pointing to data inside chand->resolver_result. + // The copy will be saved in chand->lb_policy_name below. + lb_policy_name = gpr_strdup(lb_policy_name); + grpc_channel_args_destroy(exec_ctx, chand->resolver_result); + chand->resolver_result = NULL; + } + if (GRPC_TRACER_ON(grpc_client_channel_trace)) { + gpr_log(GPR_DEBUG, + "chand=%p: resolver result: lb_policy_name=\"%s\"%s, " + "service_config=\"%s\"", + chand, lb_policy_name, lb_policy_name_changed ? " (changed)" : "", + service_config_json); + } + // Now swap out fields in chand. Note that the new values may still + // be NULL if (e.g.) the resolver failed to return results or the + // results did not contain the necessary data. + // + // First, swap out the data used by cc_get_channel_info(). + gpr_mu_lock(&chand->info_mu); + if (lb_policy_name != NULL) { + gpr_free(chand->info_lb_policy_name); + chand->info_lb_policy_name = lb_policy_name; + } + if (service_config_json != NULL) { + gpr_free(chand->info_service_config_json); + chand->info_service_config_json = service_config_json; + } + gpr_mu_unlock(&chand->info_mu); + // Swap out the retry throttle data. + if (chand->retry_throttle_data != NULL) { + grpc_server_retry_throttle_data_unref(chand->retry_throttle_data); + } + chand->retry_throttle_data = retry_throttle_data; + // Swap out the method params table. + if (chand->method_params_table != NULL) { + grpc_slice_hash_table_unref(exec_ctx, chand->method_params_table); + } + chand->method_params_table = method_params_table; + // If we have a new LB policy or are shutting down (in which case + // new_lb_policy will be NULL), swap out the LB policy, unreffing the + // old one and removing its fds from chand->interested_parties. + // Note that we do NOT do this if either (a) we updated the existing + // LB policy above or (b) we failed to create the new LB policy (in + // which case we want to continue using the most recent one we had). + if (new_lb_policy != NULL || error != GRPC_ERROR_NONE || + chand->resolver == NULL) { + if (chand->lb_policy != NULL) { + if (GRPC_TRACER_ON(grpc_client_channel_trace)) { + gpr_log(GPR_DEBUG, "chand=%p: unreffing lb_policy=%p", chand, + chand->lb_policy); + } + grpc_pollset_set_del_pollset_set(exec_ctx, + chand->lb_policy->interested_parties, + chand->interested_parties); + GRPC_LB_POLICY_UNREF(exec_ctx, chand->lb_policy, "channel"); + } + chand->lb_policy = new_lb_policy; + } + // Now that we've swapped out the relevant fields of chand, check for + // error or shutdown. + if (error != GRPC_ERROR_NONE || chand->resolver == NULL) { + if (GRPC_TRACER_ON(grpc_client_channel_trace)) { + gpr_log(GPR_DEBUG, "chand=%p: shutting down", chand); + } + if (chand->resolver != NULL) { + if (GRPC_TRACER_ON(grpc_client_channel_trace)) { + gpr_log(GPR_DEBUG, "chand=%p: shutting down resolver", chand); + } + grpc_resolver_shutdown_locked(exec_ctx, chand->resolver); + GRPC_RESOLVER_UNREF(exec_ctx, chand->resolver, "channel"); + chand->resolver = NULL; + } + set_channel_connectivity_state_locked( + exec_ctx, chand, GRPC_CHANNEL_SHUTDOWN, + GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( + "Got resolver result after disconnection", &error, 1), + "resolver_gone"); + GRPC_CHANNEL_STACK_UNREF(exec_ctx, chand->owning_stack, "resolver"); + grpc_closure_list_fail_all(&chand->waiting_for_resolver_result_closures, + GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( + "Channel disconnected", &error, 1)); + GRPC_CLOSURE_LIST_SCHED(exec_ctx, + &chand->waiting_for_resolver_result_closures); + } else { // Not shutting down. + grpc_connectivity_state state = GRPC_CHANNEL_TRANSIENT_FAILURE; + grpc_error *state_error = + GRPC_ERROR_CREATE_FROM_STATIC_STRING("No load balancing policy"); + if (new_lb_policy != NULL) { + if (GRPC_TRACER_ON(grpc_client_channel_trace)) { + gpr_log(GPR_DEBUG, "chand=%p: initializing new LB policy", chand); + } + GRPC_ERROR_UNREF(state_error); + state = grpc_lb_policy_check_connectivity_locked(exec_ctx, new_lb_policy, + &state_error); + grpc_pollset_set_add_pollset_set(exec_ctx, + new_lb_policy->interested_parties, + chand->interested_parties); + GRPC_CLOSURE_LIST_SCHED(exec_ctx, + &chand->waiting_for_resolver_result_closures); + if (chand->exit_idle_when_lb_policy_arrives) { + grpc_lb_policy_exit_idle_locked(exec_ctx, new_lb_policy); + chand->exit_idle_when_lb_policy_arrives = false; + } + watch_lb_policy_locked(exec_ctx, chand, new_lb_policy, state); + } + if (!lb_policy_updated) { + set_channel_connectivity_state_locked(exec_ctx, chand, state, + GRPC_ERROR_REF(state_error), + "new_lb+resolver"); + } + grpc_resolver_next_locked(exec_ctx, chand->resolver, + &chand->resolver_result, + &chand->on_resolver_result_changed); + GRPC_ERROR_UNREF(state_error); + } +} + +static void start_transport_op_locked(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error_ignored) { + grpc_transport_op *op = arg; + grpc_channel_element *elem = op->handler_private.extra_arg; + channel_data *chand = elem->channel_data; + + if (op->on_connectivity_state_change != NULL) { + grpc_connectivity_state_notify_on_state_change( + exec_ctx, &chand->state_tracker, op->connectivity_state, + op->on_connectivity_state_change); + op->on_connectivity_state_change = NULL; + op->connectivity_state = NULL; + } + + if (op->send_ping != NULL) { + if (chand->lb_policy == NULL) { + GRPC_CLOSURE_SCHED( + exec_ctx, op->send_ping, + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Ping with no load balancing")); + } else { + grpc_lb_policy_ping_one_locked(exec_ctx, chand->lb_policy, op->send_ping); + op->bind_pollset = NULL; + } + op->send_ping = NULL; + } + + if (op->disconnect_with_error != GRPC_ERROR_NONE) { + if (chand->resolver != NULL) { + set_channel_connectivity_state_locked( + exec_ctx, chand, GRPC_CHANNEL_SHUTDOWN, + GRPC_ERROR_REF(op->disconnect_with_error), "disconnect"); + grpc_resolver_shutdown_locked(exec_ctx, chand->resolver); + GRPC_RESOLVER_UNREF(exec_ctx, chand->resolver, "channel"); + chand->resolver = NULL; + if (!chand->started_resolving) { + grpc_closure_list_fail_all(&chand->waiting_for_resolver_result_closures, + GRPC_ERROR_REF(op->disconnect_with_error)); + GRPC_CLOSURE_LIST_SCHED(exec_ctx, + &chand->waiting_for_resolver_result_closures); + } + if (chand->lb_policy != NULL) { + grpc_pollset_set_del_pollset_set(exec_ctx, + chand->lb_policy->interested_parties, + chand->interested_parties); + GRPC_LB_POLICY_UNREF(exec_ctx, chand->lb_policy, "channel"); + chand->lb_policy = NULL; + } + } + GRPC_ERROR_UNREF(op->disconnect_with_error); + } + GRPC_CHANNEL_STACK_UNREF(exec_ctx, chand->owning_stack, "start_transport_op"); + + GRPC_CLOSURE_SCHED(exec_ctx, op->on_consumed, GRPC_ERROR_NONE); +} + +static void cc_start_transport_op(grpc_exec_ctx *exec_ctx, + grpc_channel_element *elem, + grpc_transport_op *op) { + channel_data *chand = elem->channel_data; + + GPR_ASSERT(op->set_accept_stream == false); + if (op->bind_pollset != NULL) { + grpc_pollset_set_add_pollset(exec_ctx, chand->interested_parties, + op->bind_pollset); + } + + op->handler_private.extra_arg = elem; + GRPC_CHANNEL_STACK_REF(chand->owning_stack, "start_transport_op"); + GRPC_CLOSURE_SCHED( + exec_ctx, + GRPC_CLOSURE_INIT(&op->handler_private.closure, start_transport_op_locked, + op, grpc_combiner_scheduler(chand->combiner)), + GRPC_ERROR_NONE); +} + +static void cc_get_channel_info(grpc_exec_ctx *exec_ctx, + grpc_channel_element *elem, + const grpc_channel_info *info) { + channel_data *chand = elem->channel_data; + gpr_mu_lock(&chand->info_mu); + if (info->lb_policy_name != NULL) { + *info->lb_policy_name = chand->info_lb_policy_name == NULL + ? NULL + : gpr_strdup(chand->info_lb_policy_name); + } + if (info->service_config_json != NULL) { + *info->service_config_json = + chand->info_service_config_json == NULL + ? NULL + : gpr_strdup(chand->info_service_config_json); + } + gpr_mu_unlock(&chand->info_mu); +} + +/* Constructor for channel_data */ +static grpc_error *cc_init_channel_elem(grpc_exec_ctx *exec_ctx, + grpc_channel_element *elem, + grpc_channel_element_args *args) { + channel_data *chand = elem->channel_data; + GPR_ASSERT(args->is_last); + GPR_ASSERT(elem->filter == &grpc_client_channel_filter); + // Initialize data members. + chand->combiner = grpc_combiner_create(); + gpr_mu_init(&chand->info_mu); + gpr_mu_init(&chand->external_connectivity_watcher_list_mu); + + gpr_mu_lock(&chand->external_connectivity_watcher_list_mu); + chand->external_connectivity_watcher_list_head = NULL; + gpr_mu_unlock(&chand->external_connectivity_watcher_list_mu); + + chand->owning_stack = args->channel_stack; + GRPC_CLOSURE_INIT(&chand->on_resolver_result_changed, + on_resolver_result_changed_locked, chand, + grpc_combiner_scheduler(chand->combiner)); + chand->interested_parties = grpc_pollset_set_create(); + grpc_connectivity_state_init(&chand->state_tracker, GRPC_CHANNEL_IDLE, + "client_channel"); + // Record client channel factory. + const grpc_arg *arg = grpc_channel_args_find(args->channel_args, + GRPC_ARG_CLIENT_CHANNEL_FACTORY); + if (arg == NULL) { + return GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "Missing client channel factory in args for client channel filter"); + } + if (arg->type != GRPC_ARG_POINTER) { + return GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "client channel factory arg must be a pointer"); + } + grpc_client_channel_factory_ref(arg->value.pointer.p); + chand->client_channel_factory = arg->value.pointer.p; + // Get server name to resolve, using proxy mapper if needed. + arg = grpc_channel_args_find(args->channel_args, GRPC_ARG_SERVER_URI); + if (arg == NULL) { + return GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "Missing server uri in args for client channel filter"); + } + if (arg->type != GRPC_ARG_STRING) { + return GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "server uri arg must be a string"); + } + char *proxy_name = NULL; + grpc_channel_args *new_args = NULL; + grpc_proxy_mappers_map_name(exec_ctx, arg->value.string, args->channel_args, + &proxy_name, &new_args); + // Instantiate resolver. + chand->resolver = grpc_resolver_create( + exec_ctx, proxy_name != NULL ? proxy_name : arg->value.string, + new_args != NULL ? new_args : args->channel_args, + chand->interested_parties, chand->combiner); + if (proxy_name != NULL) gpr_free(proxy_name); + if (new_args != NULL) grpc_channel_args_destroy(exec_ctx, new_args); + if (chand->resolver == NULL) { + return GRPC_ERROR_CREATE_FROM_STATIC_STRING("resolver creation failed"); + } + chand->deadline_checking_enabled = + grpc_deadline_checking_enabled(args->channel_args); + return GRPC_ERROR_NONE; +} + +static void shutdown_resolver_locked(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error) { + grpc_resolver *resolver = arg; + grpc_resolver_shutdown_locked(exec_ctx, resolver); + GRPC_RESOLVER_UNREF(exec_ctx, resolver, "channel"); +} + +/* Destructor for channel_data */ +static void cc_destroy_channel_elem(grpc_exec_ctx *exec_ctx, + grpc_channel_element *elem) { + channel_data *chand = elem->channel_data; + if (chand->resolver != NULL) { + GRPC_CLOSURE_SCHED( + exec_ctx, GRPC_CLOSURE_CREATE(shutdown_resolver_locked, chand->resolver, + grpc_combiner_scheduler(chand->combiner)), + GRPC_ERROR_NONE); + } + if (chand->client_channel_factory != NULL) { + grpc_client_channel_factory_unref(exec_ctx, chand->client_channel_factory); + } + if (chand->lb_policy != NULL) { + grpc_pollset_set_del_pollset_set(exec_ctx, + chand->lb_policy->interested_parties, + chand->interested_parties); + GRPC_LB_POLICY_UNREF(exec_ctx, chand->lb_policy, "channel"); + } + gpr_free(chand->info_lb_policy_name); + gpr_free(chand->info_service_config_json); + if (chand->retry_throttle_data != NULL) { + grpc_server_retry_throttle_data_unref(chand->retry_throttle_data); + } + if (chand->method_params_table != NULL) { + grpc_slice_hash_table_unref(exec_ctx, chand->method_params_table); + } + grpc_connectivity_state_destroy(exec_ctx, &chand->state_tracker); + grpc_pollset_set_destroy(exec_ctx, chand->interested_parties); + GRPC_COMBINER_UNREF(exec_ctx, chand->combiner, "client_channel"); + gpr_mu_destroy(&chand->info_mu); + gpr_mu_destroy(&chand->external_connectivity_watcher_list_mu); +} + +/************************************************************************* + * PER-CALL FUNCTIONS + */ + +// Max number of batches that can be pending on a call at any given +// time. This includes: +// recv_initial_metadata +// send_initial_metadata +// recv_message +// send_message +// recv_trailing_metadata +// send_trailing_metadata +#define MAX_WAITING_BATCHES 6 + +/** Call data. Holds a pointer to grpc_subchannel_call and the + associated machinery to create such a pointer. + Handles queueing of stream ops until a call object is ready, waiting + for initial metadata before trying to create a call object, + and handling cancellation gracefully. */ +typedef struct client_channel_call_data { + // State for handling deadlines. + // The code in deadline_filter.c requires this to be the first field. + // TODO(roth): This is slightly sub-optimal in that grpc_deadline_state + // and this struct both independently store a pointer to the call + // stack and each has its own mutex. If/when we have time, find a way + // to avoid this without breaking the grpc_deadline_state abstraction. + grpc_deadline_state deadline_state; + + grpc_slice path; // Request path. + gpr_timespec call_start_time; + gpr_timespec deadline; + grpc_server_retry_throttle_data *retry_throttle_data; + method_parameters *method_params; + + /** either 0 for no call, a pointer to a grpc_subchannel_call (if the lowest + bit is 0), or a pointer to an error (if the lowest bit is 1) */ + gpr_atm subchannel_call_or_error; + gpr_arena *arena; + + grpc_lb_policy *lb_policy; // Holds ref while LB pick is pending. + grpc_closure lb_pick_closure; + + grpc_connected_subchannel *connected_subchannel; + grpc_call_context_element subchannel_call_context[GRPC_CONTEXT_COUNT]; + grpc_polling_entity *pollent; + + grpc_transport_stream_op_batch *waiting_for_pick_batches[MAX_WAITING_BATCHES]; + size_t waiting_for_pick_batches_count; + + grpc_transport_stream_op_batch_payload *initial_metadata_payload; + + grpc_call_stack *owning_call; + + grpc_linked_mdelem lb_token_mdelem; + + grpc_closure on_complete; + grpc_closure *original_on_complete; +} call_data; + +typedef struct { + grpc_subchannel_call *subchannel_call; + grpc_error *error; +} call_or_error; + +static call_or_error get_call_or_error(call_data *p) { + gpr_atm c = gpr_atm_acq_load(&p->subchannel_call_or_error); + if (c == 0) + return (call_or_error){NULL, NULL}; + else if (c & 1) + return (call_or_error){NULL, (grpc_error *)((c) & ~(gpr_atm)1)}; + else + return (call_or_error){(grpc_subchannel_call *)c, NULL}; +} + +static bool set_call_or_error(call_data *p, call_or_error coe) { + // this should always be under a lock + call_or_error existing = get_call_or_error(p); + if (existing.error != GRPC_ERROR_NONE) { + GRPC_ERROR_UNREF(coe.error); + return false; + } + GPR_ASSERT(existing.subchannel_call == NULL); + if (coe.error != GRPC_ERROR_NONE) { + GPR_ASSERT(coe.subchannel_call == NULL); + gpr_atm_rel_store(&p->subchannel_call_or_error, 1 | (gpr_atm)coe.error); + } else { + GPR_ASSERT(coe.subchannel_call != NULL); + gpr_atm_rel_store(&p->subchannel_call_or_error, + (gpr_atm)coe.subchannel_call); + } + return true; +} + +grpc_subchannel_call *grpc_client_channel_get_subchannel_call( + grpc_call_element *call_elem) { + return get_call_or_error(call_elem->call_data).subchannel_call; +} + +static void waiting_for_pick_batches_add_locked( + call_data *calld, grpc_transport_stream_op_batch *batch) { + GPR_ASSERT(calld->waiting_for_pick_batches_count < MAX_WAITING_BATCHES); + calld->waiting_for_pick_batches[calld->waiting_for_pick_batches_count++] = + batch; +} + +static void waiting_for_pick_batches_fail_locked(grpc_exec_ctx *exec_ctx, + grpc_call_element *elem, + grpc_error *error) { + call_data *calld = elem->call_data; + if (GRPC_TRACER_ON(grpc_client_channel_trace)) { + gpr_log(GPR_DEBUG, + "chand=%p calld=%p: failing %" PRIdPTR " pending batches: %s", + elem->channel_data, calld, calld->waiting_for_pick_batches_count, + grpc_error_string(error)); + } + for (size_t i = 0; i < calld->waiting_for_pick_batches_count; ++i) { + grpc_transport_stream_op_batch_finish_with_failure( + exec_ctx, calld->waiting_for_pick_batches[i], GRPC_ERROR_REF(error)); + } + calld->waiting_for_pick_batches_count = 0; + GRPC_ERROR_UNREF(error); +} + +static void waiting_for_pick_batches_resume_locked(grpc_exec_ctx *exec_ctx, + grpc_call_element *elem) { + call_data *calld = elem->call_data; + if (calld->waiting_for_pick_batches_count == 0) return; + call_or_error coe = get_call_or_error(calld); + if (coe.error != GRPC_ERROR_NONE) { + waiting_for_pick_batches_fail_locked(exec_ctx, elem, + GRPC_ERROR_REF(coe.error)); + return; + } + if (GRPC_TRACER_ON(grpc_client_channel_trace)) { + gpr_log(GPR_DEBUG, "chand=%p calld=%p: sending %" PRIdPTR + " pending batches to subchannel_call=%p", + elem->channel_data, calld, calld->waiting_for_pick_batches_count, + coe.subchannel_call); + } + for (size_t i = 0; i < calld->waiting_for_pick_batches_count; ++i) { + grpc_subchannel_call_process_op(exec_ctx, coe.subchannel_call, + calld->waiting_for_pick_batches[i]); + } + calld->waiting_for_pick_batches_count = 0; +} + +// Applies service config to the call. Must be invoked once we know +// that the resolver has returned results to the channel. +static void apply_service_config_to_call_locked(grpc_exec_ctx *exec_ctx, + grpc_call_element *elem) { + channel_data *chand = elem->channel_data; + call_data *calld = elem->call_data; + if (GRPC_TRACER_ON(grpc_client_channel_trace)) { + gpr_log(GPR_DEBUG, "chand=%p calld=%p: applying service config to call", + chand, calld); + } + if (chand->retry_throttle_data != NULL) { + calld->retry_throttle_data = + grpc_server_retry_throttle_data_ref(chand->retry_throttle_data); + } + if (chand->method_params_table != NULL) { + calld->method_params = grpc_method_config_table_get( + exec_ctx, chand->method_params_table, calld->path); + if (calld->method_params != NULL) { + method_parameters_ref(calld->method_params); + // If the deadline from the service config is shorter than the one + // from the client API, reset the deadline timer. + if (chand->deadline_checking_enabled && + gpr_time_cmp(calld->method_params->timeout, + gpr_time_0(GPR_TIMESPAN)) != 0) { + const gpr_timespec per_method_deadline = + gpr_time_add(calld->call_start_time, calld->method_params->timeout); + if (gpr_time_cmp(per_method_deadline, calld->deadline) < 0) { + calld->deadline = per_method_deadline; + grpc_deadline_state_reset(exec_ctx, elem, calld->deadline); + } + } + } + } +} + +static void create_subchannel_call_locked(grpc_exec_ctx *exec_ctx, + grpc_call_element *elem, + grpc_error *error) { + call_data *calld = elem->call_data; + grpc_subchannel_call *subchannel_call = NULL; + const grpc_connected_subchannel_call_args call_args = { + .pollent = calld->pollent, + .path = calld->path, + .start_time = calld->call_start_time, + .deadline = calld->deadline, + .arena = calld->arena, + .context = calld->subchannel_call_context}; + grpc_error *new_error = grpc_connected_subchannel_create_call( + exec_ctx, calld->connected_subchannel, &call_args, &subchannel_call); + if (GRPC_TRACER_ON(grpc_client_channel_trace)) { + gpr_log(GPR_DEBUG, "chand=%p calld=%p: create subchannel_call=%p: error=%s", + elem->channel_data, calld, subchannel_call, + grpc_error_string(new_error)); + } + GPR_ASSERT(set_call_or_error( + calld, (call_or_error){.subchannel_call = subchannel_call})); + if (new_error != GRPC_ERROR_NONE) { + new_error = grpc_error_add_child(new_error, error); + waiting_for_pick_batches_fail_locked(exec_ctx, elem, new_error); + } else { + waiting_for_pick_batches_resume_locked(exec_ctx, elem); + } + GRPC_ERROR_UNREF(error); +} + +static void subchannel_ready_locked(grpc_exec_ctx *exec_ctx, + grpc_call_element *elem, + grpc_error *error) { + call_data *calld = elem->call_data; + channel_data *chand = elem->channel_data; + grpc_polling_entity_del_from_pollset_set(exec_ctx, calld->pollent, + chand->interested_parties); + call_or_error coe = get_call_or_error(calld); + if (calld->connected_subchannel == NULL) { + // Failed to create subchannel. + grpc_error *failure = + error == GRPC_ERROR_NONE + ? GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "Call dropped by load balancing policy") + : GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( + "Failed to create subchannel", &error, 1); + if (GRPC_TRACER_ON(grpc_client_channel_trace)) { + gpr_log(GPR_DEBUG, + "chand=%p calld=%p: failed to create subchannel: error=%s", chand, + calld, grpc_error_string(failure)); + } + set_call_or_error(calld, (call_or_error){.error = GRPC_ERROR_REF(failure)}); + waiting_for_pick_batches_fail_locked(exec_ctx, elem, failure); + } else if (coe.error != GRPC_ERROR_NONE) { + /* already cancelled before subchannel became ready */ + grpc_error *child_errors[] = {error, coe.error}; + grpc_error *cancellation_error = + GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( + "Cancelled before creating subchannel", child_errors, + GPR_ARRAY_SIZE(child_errors)); + /* if due to deadline, attach the deadline exceeded status to the error */ + if (gpr_time_cmp(calld->deadline, gpr_now(GPR_CLOCK_MONOTONIC)) < 0) { + cancellation_error = + grpc_error_set_int(cancellation_error, GRPC_ERROR_INT_GRPC_STATUS, + GRPC_STATUS_DEADLINE_EXCEEDED); + } + if (GRPC_TRACER_ON(grpc_client_channel_trace)) { + gpr_log(GPR_DEBUG, + "chand=%p calld=%p: cancelled before subchannel became ready: %s", + chand, calld, grpc_error_string(cancellation_error)); + } + waiting_for_pick_batches_fail_locked(exec_ctx, elem, cancellation_error); + } else { + /* Create call on subchannel. */ + create_subchannel_call_locked(exec_ctx, elem, GRPC_ERROR_REF(error)); + } + GRPC_CALL_STACK_UNREF(exec_ctx, calld->owning_call, "pick_subchannel"); + GRPC_ERROR_UNREF(error); +} + +static char *cc_get_peer(grpc_exec_ctx *exec_ctx, grpc_call_element *elem) { + call_data *calld = elem->call_data; + grpc_subchannel_call *subchannel_call = + get_call_or_error(calld).subchannel_call; + if (subchannel_call == NULL) { + return NULL; + } else { + return grpc_subchannel_call_get_peer(exec_ctx, subchannel_call); + } +} + +/** Return true if subchannel is available immediately (in which case + subchannel_ready_locked() should not be called), or false otherwise (in + which case subchannel_ready_locked() should be called when the subchannel + is available). */ +static bool pick_subchannel_locked(grpc_exec_ctx *exec_ctx, + grpc_call_element *elem); + +typedef struct { + grpc_call_element *elem; + bool cancelled; + grpc_closure closure; +} pick_after_resolver_result_args; + +static void pick_after_resolver_result_done_locked(grpc_exec_ctx *exec_ctx, + void *arg, + grpc_error *error) { + pick_after_resolver_result_args *args = arg; + if (args->cancelled) { + /* cancelled, do nothing */ + if (GRPC_TRACER_ON(grpc_client_channel_trace)) { + gpr_log(GPR_DEBUG, "call cancelled before resolver result"); + } + } else { + channel_data *chand = args->elem->channel_data; + call_data *calld = args->elem->call_data; + if (error != GRPC_ERROR_NONE) { + if (GRPC_TRACER_ON(grpc_client_channel_trace)) { + gpr_log(GPR_DEBUG, "chand=%p calld=%p: resolver failed to return data", + chand, calld); + } + subchannel_ready_locked(exec_ctx, args->elem, GRPC_ERROR_REF(error)); + } else { + if (GRPC_TRACER_ON(grpc_client_channel_trace)) { + gpr_log(GPR_DEBUG, "chand=%p calld=%p: resolver returned, doing pick", + chand, calld); + } + if (pick_subchannel_locked(exec_ctx, args->elem)) { + subchannel_ready_locked(exec_ctx, args->elem, GRPC_ERROR_NONE); + } + } + } + gpr_free(args); +} + +static void pick_after_resolver_result_start_locked(grpc_exec_ctx *exec_ctx, + grpc_call_element *elem) { + channel_data *chand = elem->channel_data; + call_data *calld = elem->call_data; + if (GRPC_TRACER_ON(grpc_client_channel_trace)) { + gpr_log(GPR_DEBUG, + "chand=%p calld=%p: deferring pick pending resolver result", chand, + calld); + } + pick_after_resolver_result_args *args = + (pick_after_resolver_result_args *)gpr_zalloc(sizeof(*args)); + args->elem = elem; + GRPC_CLOSURE_INIT(&args->closure, pick_after_resolver_result_done_locked, + args, grpc_combiner_scheduler(chand->combiner)); + grpc_closure_list_append(&chand->waiting_for_resolver_result_closures, + &args->closure, GRPC_ERROR_NONE); +} + +static void pick_after_resolver_result_cancel_locked(grpc_exec_ctx *exec_ctx, + grpc_call_element *elem, + grpc_error *error) { + channel_data *chand = elem->channel_data; + call_data *calld = elem->call_data; + // If we don't yet have a resolver result, then a closure for + // pick_after_resolver_result_done_locked() will have been added to + // chand->waiting_for_resolver_result_closures, and it may not be invoked + // until after this call has been destroyed. We mark the operation as + // cancelled, so that when pick_after_resolver_result_done_locked() + // is called, it will be a no-op. We also immediately invoke + // subchannel_ready_locked() to propagate the error back to the caller. + for (grpc_closure *closure = chand->waiting_for_resolver_result_closures.head; + closure != NULL; closure = closure->next_data.next) { + pick_after_resolver_result_args *args = closure->cb_arg; + if (!args->cancelled && args->elem == elem) { + if (GRPC_TRACER_ON(grpc_client_channel_trace)) { + gpr_log(GPR_DEBUG, + "chand=%p calld=%p: " + "cancelling pick waiting for resolver result", + chand, calld); + } + args->cancelled = true; + subchannel_ready_locked(exec_ctx, elem, + GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( + "Pick cancelled", &error, 1)); + } + } + GRPC_ERROR_UNREF(error); +} + +// Callback invoked by grpc_lb_policy_pick_locked() for async picks. +// Unrefs the LB policy after invoking subchannel_ready_locked(). +static void pick_callback_done_locked(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error) { + grpc_call_element *elem = arg; + channel_data *chand = elem->channel_data; + call_data *calld = elem->call_data; + if (GRPC_TRACER_ON(grpc_client_channel_trace)) { + gpr_log(GPR_DEBUG, "chand=%p calld=%p: pick completed asynchronously", + chand, calld); + } + GPR_ASSERT(calld->lb_policy != NULL); + GRPC_LB_POLICY_UNREF(exec_ctx, calld->lb_policy, "pick_subchannel"); + calld->lb_policy = NULL; + subchannel_ready_locked(exec_ctx, elem, GRPC_ERROR_REF(error)); +} + +// Takes a ref to chand->lb_policy and calls grpc_lb_policy_pick_locked(). +// If the pick was completed synchronously, unrefs the LB policy and +// returns true. +static bool pick_callback_start_locked(grpc_exec_ctx *exec_ctx, + grpc_call_element *elem, + const grpc_lb_policy_pick_args *inputs) { + channel_data *chand = elem->channel_data; + call_data *calld = elem->call_data; + if (GRPC_TRACER_ON(grpc_client_channel_trace)) { + gpr_log(GPR_DEBUG, "chand=%p calld=%p: starting pick on lb_policy=%p", + chand, calld, chand->lb_policy); + } + // Keep a ref to the LB policy in calld while the pick is pending. + GRPC_LB_POLICY_REF(chand->lb_policy, "pick_subchannel"); + calld->lb_policy = chand->lb_policy; + GRPC_CLOSURE_INIT(&calld->lb_pick_closure, pick_callback_done_locked, elem, + grpc_combiner_scheduler(chand->combiner)); + const bool pick_done = grpc_lb_policy_pick_locked( + exec_ctx, chand->lb_policy, inputs, &calld->connected_subchannel, + calld->subchannel_call_context, NULL, &calld->lb_pick_closure); + if (pick_done) { + /* synchronous grpc_lb_policy_pick call. Unref the LB policy. */ + if (GRPC_TRACER_ON(grpc_client_channel_trace)) { + gpr_log(GPR_DEBUG, "chand=%p calld=%p: pick completed synchronously", + chand, calld); + } + GRPC_LB_POLICY_UNREF(exec_ctx, calld->lb_policy, "pick_subchannel"); + calld->lb_policy = NULL; + } + return pick_done; +} + +static void pick_callback_cancel_locked(grpc_exec_ctx *exec_ctx, + grpc_call_element *elem, + grpc_error *error) { + channel_data *chand = elem->channel_data; + call_data *calld = elem->call_data; + GPR_ASSERT(calld->lb_policy != NULL); + if (GRPC_TRACER_ON(grpc_client_channel_trace)) { + gpr_log(GPR_DEBUG, "chand=%p calld=%p: cancelling pick from LB policy %p", + chand, calld, calld->lb_policy); + } + grpc_lb_policy_cancel_pick_locked(exec_ctx, calld->lb_policy, + &calld->connected_subchannel, error); +} + +static bool pick_subchannel_locked(grpc_exec_ctx *exec_ctx, + grpc_call_element *elem) { + GPR_TIMER_BEGIN("pick_subchannel", 0); + channel_data *chand = elem->channel_data; + call_data *calld = elem->call_data; + bool pick_done = false; + if (chand->lb_policy != NULL) { + apply_service_config_to_call_locked(exec_ctx, elem); + // If the application explicitly set wait_for_ready, use that. + // Otherwise, if the service config specified a value for this + // method, use that. + uint32_t initial_metadata_flags = + calld->initial_metadata_payload->send_initial_metadata + .send_initial_metadata_flags; + const bool wait_for_ready_set_from_api = + initial_metadata_flags & + GRPC_INITIAL_METADATA_WAIT_FOR_READY_EXPLICITLY_SET; + const bool wait_for_ready_set_from_service_config = + calld->method_params != NULL && + calld->method_params->wait_for_ready != WAIT_FOR_READY_UNSET; + if (!wait_for_ready_set_from_api && + wait_for_ready_set_from_service_config) { + if (calld->method_params->wait_for_ready == WAIT_FOR_READY_TRUE) { + initial_metadata_flags |= GRPC_INITIAL_METADATA_WAIT_FOR_READY; + } else { + initial_metadata_flags &= ~GRPC_INITIAL_METADATA_WAIT_FOR_READY; + } + } + const grpc_lb_policy_pick_args inputs = { + calld->initial_metadata_payload->send_initial_metadata + .send_initial_metadata, + initial_metadata_flags, &calld->lb_token_mdelem}; + pick_done = pick_callback_start_locked(exec_ctx, elem, &inputs); + } else if (chand->resolver != NULL) { + if (!chand->started_resolving) { + start_resolving_locked(exec_ctx, chand); + } + pick_after_resolver_result_start_locked(exec_ctx, elem); + } else { + subchannel_ready_locked( + exec_ctx, elem, GRPC_ERROR_CREATE_FROM_STATIC_STRING("Disconnected")); + } + GPR_TIMER_END("pick_subchannel", 0); + return pick_done; +} + +static void start_transport_stream_op_batch_locked(grpc_exec_ctx *exec_ctx, + void *arg, + grpc_error *error_ignored) { + GPR_TIMER_BEGIN("start_transport_stream_op_batch_locked", 0); + grpc_transport_stream_op_batch *batch = arg; + grpc_call_element *elem = batch->handler_private.extra_arg; + call_data *calld = elem->call_data; + channel_data *chand = elem->channel_data; + /* need to recheck that another thread hasn't set the call */ + call_or_error coe = get_call_or_error(calld); + if (coe.error != GRPC_ERROR_NONE) { + if (GRPC_TRACER_ON(grpc_client_channel_trace)) { + gpr_log(GPR_DEBUG, "chand=%p calld=%p: failing batch with error: %s", + chand, calld, grpc_error_string(coe.error)); + } + grpc_transport_stream_op_batch_finish_with_failure( + exec_ctx, batch, GRPC_ERROR_REF(coe.error)); + goto done; + } + if (coe.subchannel_call != NULL) { + if (GRPC_TRACER_ON(grpc_client_channel_trace)) { + gpr_log(GPR_DEBUG, + "chand=%p calld=%p: sending batch to subchannel_call=%p", chand, + calld, coe.subchannel_call); + } + grpc_subchannel_call_process_op(exec_ctx, coe.subchannel_call, batch); + goto done; + } + // Add to waiting-for-pick list. If we succeed in getting a + // subchannel call below, we'll handle this batch (along with any + // other waiting batches) in waiting_for_pick_batches_resume_locked(). + waiting_for_pick_batches_add_locked(calld, batch); + // If this is a cancellation, cancel the pending pick (if any) and + // fail any pending batches. + if (batch->cancel_stream) { + grpc_error *error = batch->payload->cancel_stream.cancel_error; + if (GRPC_TRACER_ON(grpc_client_channel_trace)) { + gpr_log(GPR_DEBUG, "chand=%p calld=%p: recording cancel_error=%s", chand, + calld, grpc_error_string(error)); + } + /* Stash a copy of cancel_error in our call data, so that we can use + it for subsequent operations. This ensures that if the call is + cancelled before any batches are passed down (e.g., if the deadline + is in the past when the call starts), we can return the right + error to the caller when the first batch does get passed down. */ + set_call_or_error(calld, (call_or_error){.error = GRPC_ERROR_REF(error)}); + if (calld->lb_policy != NULL) { + pick_callback_cancel_locked(exec_ctx, elem, GRPC_ERROR_REF(error)); + } else { + pick_after_resolver_result_cancel_locked(exec_ctx, elem, + GRPC_ERROR_REF(error)); + } + waiting_for_pick_batches_fail_locked(exec_ctx, elem, GRPC_ERROR_REF(error)); + goto done; + } + /* if we don't have a subchannel, try to get one */ + if (batch->send_initial_metadata) { + GPR_ASSERT(calld->connected_subchannel == NULL); + calld->initial_metadata_payload = batch->payload; + GRPC_CALL_STACK_REF(calld->owning_call, "pick_subchannel"); + /* If a subchannel is not available immediately, the polling entity from + call_data should be provided to channel_data's interested_parties, so + that IO of the lb_policy and resolver could be done under it. */ + if (pick_subchannel_locked(exec_ctx, elem)) { + // Pick was returned synchronously. + GRPC_CALL_STACK_UNREF(exec_ctx, calld->owning_call, "pick_subchannel"); + if (calld->connected_subchannel == NULL) { + grpc_error *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "Call dropped by load balancing policy"); + set_call_or_error(calld, + (call_or_error){.error = GRPC_ERROR_REF(error)}); + waiting_for_pick_batches_fail_locked(exec_ctx, elem, error); + } else { + // Create subchannel call. + create_subchannel_call_locked(exec_ctx, elem, GRPC_ERROR_NONE); + } + } else { + grpc_polling_entity_add_to_pollset_set(exec_ctx, calld->pollent, + chand->interested_parties); + } + } +done: + GRPC_CALL_STACK_UNREF(exec_ctx, calld->owning_call, + "start_transport_stream_op_batch"); + GPR_TIMER_END("start_transport_stream_op_batch_locked", 0); +} + +static void on_complete(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { + grpc_call_element *elem = arg; + call_data *calld = elem->call_data; + if (calld->retry_throttle_data != NULL) { + if (error == GRPC_ERROR_NONE) { + grpc_server_retry_throttle_data_record_success( + calld->retry_throttle_data); + } else { + // TODO(roth): In a subsequent PR, check the return value here and + // decide whether or not to retry. Note that we should only + // record failures whose statuses match the configured retryable + // or non-fatal status codes. + grpc_server_retry_throttle_data_record_failure( + calld->retry_throttle_data); + } + } + GRPC_CLOSURE_RUN(exec_ctx, calld->original_on_complete, + GRPC_ERROR_REF(error)); +} + +/* The logic here is fairly complicated, due to (a) the fact that we + need to handle the case where we receive the send op before the + initial metadata op, and (b) the need for efficiency, especially in + the streaming case. + + We use double-checked locking to initially see if initialization has been + performed. If it has not, we acquire the combiner and perform initialization. + If it has, we proceed on the fast path. */ +static void cc_start_transport_stream_op_batch( + grpc_exec_ctx *exec_ctx, grpc_call_element *elem, + grpc_transport_stream_op_batch *batch) { + call_data *calld = elem->call_data; + channel_data *chand = elem->channel_data; + if (GRPC_TRACER_ON(grpc_client_channel_trace) || + GRPC_TRACER_ON(grpc_trace_channel)) { + grpc_call_log_op(GPR_INFO, elem, batch); + } + if (chand->deadline_checking_enabled) { + grpc_deadline_state_client_start_transport_stream_op_batch(exec_ctx, elem, + batch); + } + // Intercept on_complete for recv_trailing_metadata so that we can + // check retry throttle status. + if (batch->recv_trailing_metadata) { + GPR_ASSERT(batch->on_complete != NULL); + calld->original_on_complete = batch->on_complete; + GRPC_CLOSURE_INIT(&calld->on_complete, on_complete, elem, + grpc_schedule_on_exec_ctx); + batch->on_complete = &calld->on_complete; + } + /* try to (atomically) get the call */ + call_or_error coe = get_call_or_error(calld); + GPR_TIMER_BEGIN("cc_start_transport_stream_op_batch", 0); + if (coe.error != GRPC_ERROR_NONE) { + if (GRPC_TRACER_ON(grpc_client_channel_trace)) { + gpr_log(GPR_DEBUG, "chand=%p calld=%p: failing batch with error: %s", + chand, calld, grpc_error_string(coe.error)); + } + grpc_transport_stream_op_batch_finish_with_failure( + exec_ctx, batch, GRPC_ERROR_REF(coe.error)); + goto done; + } + if (coe.subchannel_call != NULL) { + if (GRPC_TRACER_ON(grpc_client_channel_trace)) { + gpr_log(GPR_DEBUG, + "chand=%p calld=%p: sending batch to subchannel_call=%p", chand, + calld, coe.subchannel_call); + } + grpc_subchannel_call_process_op(exec_ctx, coe.subchannel_call, batch); + goto done; + } + /* we failed; lock and figure out what to do */ + if (GRPC_TRACER_ON(grpc_client_channel_trace)) { + gpr_log(GPR_DEBUG, "chand=%p calld=%p: entering combiner", chand, calld); + } + GRPC_CALL_STACK_REF(calld->owning_call, "start_transport_stream_op_batch"); + batch->handler_private.extra_arg = elem; + GRPC_CLOSURE_SCHED( + exec_ctx, GRPC_CLOSURE_INIT(&batch->handler_private.closure, + start_transport_stream_op_batch_locked, batch, + grpc_combiner_scheduler(chand->combiner)), + GRPC_ERROR_NONE); +done: + GPR_TIMER_END("cc_start_transport_stream_op_batch", 0); +} + +/* Constructor for call_data */ +static grpc_error *cc_init_call_elem(grpc_exec_ctx *exec_ctx, + grpc_call_element *elem, + const grpc_call_element_args *args) { + call_data *calld = elem->call_data; + channel_data *chand = elem->channel_data; + // Initialize data members. + calld->path = grpc_slice_ref_internal(args->path); + calld->call_start_time = args->start_time; + calld->deadline = gpr_convert_clock_type(args->deadline, GPR_CLOCK_MONOTONIC); + calld->owning_call = args->call_stack; + calld->arena = args->arena; + if (chand->deadline_checking_enabled) { + grpc_deadline_state_init(exec_ctx, elem, args->call_stack, calld->deadline); + } + return GRPC_ERROR_NONE; +} + +/* Destructor for call_data */ +static void cc_destroy_call_elem(grpc_exec_ctx *exec_ctx, + grpc_call_element *elem, + const grpc_call_final_info *final_info, + grpc_closure *then_schedule_closure) { + call_data *calld = elem->call_data; + channel_data *chand = elem->channel_data; + if (chand->deadline_checking_enabled) { + grpc_deadline_state_destroy(exec_ctx, elem); + } + grpc_slice_unref_internal(exec_ctx, calld->path); + if (calld->method_params != NULL) { + method_parameters_unref(calld->method_params); + } + call_or_error coe = get_call_or_error(calld); + GRPC_ERROR_UNREF(coe.error); + if (coe.subchannel_call != NULL) { + grpc_subchannel_call_set_cleanup_closure(coe.subchannel_call, + then_schedule_closure); + then_schedule_closure = NULL; + GRPC_SUBCHANNEL_CALL_UNREF(exec_ctx, coe.subchannel_call, + "client_channel_destroy_call"); + } + GPR_ASSERT(calld->lb_policy == NULL); + GPR_ASSERT(calld->waiting_for_pick_batches_count == 0); + if (calld->connected_subchannel != NULL) { + GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, calld->connected_subchannel, + "picked"); + } + for (size_t i = 0; i < GRPC_CONTEXT_COUNT; ++i) { + if (calld->subchannel_call_context[i].value != NULL) { + calld->subchannel_call_context[i].destroy( + calld->subchannel_call_context[i].value); + } + } + GRPC_CLOSURE_SCHED(exec_ctx, then_schedule_closure, GRPC_ERROR_NONE); +} + +static void cc_set_pollset_or_pollset_set(grpc_exec_ctx *exec_ctx, + grpc_call_element *elem, + grpc_polling_entity *pollent) { + call_data *calld = elem->call_data; + calld->pollent = pollent; +} + +/************************************************************************* + * EXPORTED SYMBOLS + */ + +const grpc_channel_filter grpc_client_channel_filter = { + cc_start_transport_stream_op_batch, + cc_start_transport_op, + sizeof(call_data), + cc_init_call_elem, + cc_set_pollset_or_pollset_set, + cc_destroy_call_elem, + sizeof(channel_data), + cc_init_channel_elem, + cc_destroy_channel_elem, + cc_get_peer, + cc_get_channel_info, + "client-channel", +}; + +static void try_to_connect_locked(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error_ignored) { + channel_data *chand = arg; + if (chand->lb_policy != NULL) { + grpc_lb_policy_exit_idle_locked(exec_ctx, chand->lb_policy); + } else { + chand->exit_idle_when_lb_policy_arrives = true; + if (!chand->started_resolving && chand->resolver != NULL) { + start_resolving_locked(exec_ctx, chand); + } + } + GRPC_CHANNEL_STACK_UNREF(exec_ctx, chand->owning_stack, "try_to_connect"); +} + +grpc_connectivity_state grpc_client_channel_check_connectivity_state( + grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, int try_to_connect) { + channel_data *chand = elem->channel_data; + grpc_connectivity_state out = + grpc_connectivity_state_check(&chand->state_tracker); + if (out == GRPC_CHANNEL_IDLE && try_to_connect) { + GRPC_CHANNEL_STACK_REF(chand->owning_stack, "try_to_connect"); + GRPC_CLOSURE_SCHED( + exec_ctx, GRPC_CLOSURE_CREATE(try_to_connect_locked, chand, + grpc_combiner_scheduler(chand->combiner)), + GRPC_ERROR_NONE); + } + return out; +} + +typedef struct external_connectivity_watcher { + channel_data *chand; + grpc_polling_entity pollent; + grpc_closure *on_complete; + grpc_closure *watcher_timer_init; + grpc_connectivity_state *state; + grpc_closure my_closure; + struct external_connectivity_watcher *next; +} external_connectivity_watcher; + +static external_connectivity_watcher *lookup_external_connectivity_watcher( + channel_data *chand, grpc_closure *on_complete) { + gpr_mu_lock(&chand->external_connectivity_watcher_list_mu); + external_connectivity_watcher *w = + chand->external_connectivity_watcher_list_head; + while (w != NULL && w->on_complete != on_complete) { + w = w->next; + } + gpr_mu_unlock(&chand->external_connectivity_watcher_list_mu); + return w; +} + +static void external_connectivity_watcher_list_append( + channel_data *chand, external_connectivity_watcher *w) { + GPR_ASSERT(!lookup_external_connectivity_watcher(chand, w->on_complete)); + + gpr_mu_lock(&w->chand->external_connectivity_watcher_list_mu); + GPR_ASSERT(!w->next); + w->next = chand->external_connectivity_watcher_list_head; + chand->external_connectivity_watcher_list_head = w; + gpr_mu_unlock(&w->chand->external_connectivity_watcher_list_mu); +} + +static void external_connectivity_watcher_list_remove( + channel_data *chand, external_connectivity_watcher *too_remove) { + GPR_ASSERT( + lookup_external_connectivity_watcher(chand, too_remove->on_complete)); + gpr_mu_lock(&chand->external_connectivity_watcher_list_mu); + if (too_remove == chand->external_connectivity_watcher_list_head) { + chand->external_connectivity_watcher_list_head = too_remove->next; + gpr_mu_unlock(&chand->external_connectivity_watcher_list_mu); + return; + } + external_connectivity_watcher *w = + chand->external_connectivity_watcher_list_head; + while (w != NULL) { + if (w->next == too_remove) { + w->next = w->next->next; + gpr_mu_unlock(&chand->external_connectivity_watcher_list_mu); + return; + } + w = w->next; + } + GPR_UNREACHABLE_CODE(return ); +} + +int grpc_client_channel_num_external_connectivity_watchers( + grpc_channel_element *elem) { + channel_data *chand = elem->channel_data; + int count = 0; + + gpr_mu_lock(&chand->external_connectivity_watcher_list_mu); + external_connectivity_watcher *w = + chand->external_connectivity_watcher_list_head; + while (w != NULL) { + count++; + w = w->next; + } + gpr_mu_unlock(&chand->external_connectivity_watcher_list_mu); + + return count; +} + +static void on_external_watch_complete(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error) { + external_connectivity_watcher *w = arg; + grpc_closure *follow_up = w->on_complete; + grpc_polling_entity_del_from_pollset_set(exec_ctx, &w->pollent, + w->chand->interested_parties); + GRPC_CHANNEL_STACK_UNREF(exec_ctx, w->chand->owning_stack, + "external_connectivity_watcher"); + external_connectivity_watcher_list_remove(w->chand, w); + gpr_free(w); + GRPC_CLOSURE_RUN(exec_ctx, follow_up, GRPC_ERROR_REF(error)); +} + +static void watch_connectivity_state_locked(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error_ignored) { + external_connectivity_watcher *w = arg; + external_connectivity_watcher *found = NULL; + if (w->state != NULL) { + external_connectivity_watcher_list_append(w->chand, w); + GRPC_CLOSURE_RUN(exec_ctx, w->watcher_timer_init, GRPC_ERROR_NONE); + GRPC_CLOSURE_INIT(&w->my_closure, on_external_watch_complete, w, + grpc_schedule_on_exec_ctx); + grpc_connectivity_state_notify_on_state_change( + exec_ctx, &w->chand->state_tracker, w->state, &w->my_closure); + } else { + GPR_ASSERT(w->watcher_timer_init == NULL); + found = lookup_external_connectivity_watcher(w->chand, w->on_complete); + if (found) { + GPR_ASSERT(found->on_complete == w->on_complete); + grpc_connectivity_state_notify_on_state_change( + exec_ctx, &found->chand->state_tracker, NULL, &found->my_closure); + } + grpc_polling_entity_del_from_pollset_set(exec_ctx, &w->pollent, + w->chand->interested_parties); + GRPC_CHANNEL_STACK_UNREF(exec_ctx, w->chand->owning_stack, + "external_connectivity_watcher"); + gpr_free(w); + } +} + +void grpc_client_channel_watch_connectivity_state( + grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, + grpc_polling_entity pollent, grpc_connectivity_state *state, + grpc_closure *closure, grpc_closure *watcher_timer_init) { + channel_data *chand = elem->channel_data; + external_connectivity_watcher *w = gpr_zalloc(sizeof(*w)); + w->chand = chand; + w->pollent = pollent; + w->on_complete = closure; + w->state = state; + w->watcher_timer_init = watcher_timer_init; + grpc_polling_entity_add_to_pollset_set(exec_ctx, &w->pollent, + chand->interested_parties); + GRPC_CHANNEL_STACK_REF(w->chand->owning_stack, + "external_connectivity_watcher"); + GRPC_CLOSURE_SCHED( + exec_ctx, + GRPC_CLOSURE_INIT(&w->my_closure, watch_connectivity_state_locked, w, + grpc_combiner_scheduler(chand->combiner)), + GRPC_ERROR_NONE); +} diff --git a/Sources/CgRPC/src/core/ext/filters/client_channel/client_channel.h b/Sources/CgRPC/src/core/ext/filters/client_channel/client_channel.h new file mode 100644 index 000000000..c99f0092e --- /dev/null +++ b/Sources/CgRPC/src/core/ext/filters/client_channel/client_channel.h @@ -0,0 +1,55 @@ +/* + * + * 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 GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_CLIENT_CHANNEL_H +#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_CLIENT_CHANNEL_H + +#include "src/core/ext/filters/client_channel/client_channel_factory.h" +#include "src/core/ext/filters/client_channel/resolver.h" +#include "src/core/lib/channel/channel_stack.h" + +extern grpc_tracer_flag grpc_client_channel_trace; + +// Channel arg key for server URI string. +#define GRPC_ARG_SERVER_URI "grpc.server_uri" + +/* A client channel is a channel that begins disconnected, and can connect + to some endpoint on demand. If that endpoint disconnects, it will be + connected to again later. + + Calls on a disconnected client channel are queued until a connection is + established. */ + +extern const grpc_channel_filter grpc_client_channel_filter; + +grpc_connectivity_state grpc_client_channel_check_connectivity_state( + grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, int try_to_connect); + +int grpc_client_channel_num_external_connectivity_watchers( + grpc_channel_element *elem); + +void grpc_client_channel_watch_connectivity_state( + grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, + grpc_polling_entity pollent, grpc_connectivity_state *state, + grpc_closure *on_complete, grpc_closure *watcher_timer_init); + +/* Debug helper: pull the subchannel call from a call stack element */ +grpc_subchannel_call *grpc_client_channel_get_subchannel_call( + grpc_call_element *elem); + +#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_CLIENT_CHANNEL_H */ diff --git a/Sources/CgRPC/src/core/ext/filters/client_channel/client_channel_factory.c b/Sources/CgRPC/src/core/ext/filters/client_channel/client_channel_factory.c new file mode 100644 index 000000000..7220a8639 --- /dev/null +++ b/Sources/CgRPC/src/core/ext/filters/client_channel/client_channel_factory.c @@ -0,0 +1,69 @@ +/* + * + * 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 "src/core/ext/filters/client_channel/client_channel_factory.h" +#include "src/core/lib/channel/channel_args.h" + +void grpc_client_channel_factory_ref(grpc_client_channel_factory* factory) { + factory->vtable->ref(factory); +} + +void grpc_client_channel_factory_unref(grpc_exec_ctx* exec_ctx, + grpc_client_channel_factory* factory) { + factory->vtable->unref(exec_ctx, factory); +} + +grpc_subchannel* grpc_client_channel_factory_create_subchannel( + grpc_exec_ctx* exec_ctx, grpc_client_channel_factory* factory, + const grpc_subchannel_args* args) { + return factory->vtable->create_subchannel(exec_ctx, factory, args); +} + +grpc_channel* grpc_client_channel_factory_create_channel( + grpc_exec_ctx* exec_ctx, grpc_client_channel_factory* factory, + const char* target, grpc_client_channel_type type, + const grpc_channel_args* args) { + return factory->vtable->create_client_channel(exec_ctx, factory, target, type, + args); +} + +static void* factory_arg_copy(void* factory) { + grpc_client_channel_factory_ref(factory); + return factory; +} + +static void factory_arg_destroy(grpc_exec_ctx* exec_ctx, void* factory) { + // TODO(roth): Remove local exec_ctx when + // https://github.com/grpc/grpc/pull/8705 is merged. + grpc_client_channel_factory_unref(exec_ctx, factory); +} + +static int factory_arg_cmp(void* factory1, void* factory2) { + if (factory1 < factory2) return -1; + if (factory1 > factory2) return 1; + return 0; +} + +static const grpc_arg_pointer_vtable factory_arg_vtable = { + factory_arg_copy, factory_arg_destroy, factory_arg_cmp}; + +grpc_arg grpc_client_channel_factory_create_channel_arg( + grpc_client_channel_factory* factory) { + return grpc_channel_arg_pointer_create(GRPC_ARG_CLIENT_CHANNEL_FACTORY, + factory, &factory_arg_vtable); +} diff --git a/Sources/CgRPC/src/core/ext/client_channel/client_channel_factory.h b/Sources/CgRPC/src/core/ext/filters/client_channel/client_channel_factory.h similarity index 57% rename from Sources/CgRPC/src/core/ext/client_channel/client_channel_factory.h rename to Sources/CgRPC/src/core/ext/filters/client_channel/client_channel_factory.h index bf2764b53..ce6266c76 100644 --- a/Sources/CgRPC/src/core/ext/client_channel/client_channel_factory.h +++ b/Sources/CgRPC/src/core/ext/filters/client_channel/client_channel_factory.h @@ -1,42 +1,27 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 GRPC_CORE_EXT_CLIENT_CHANNEL_CLIENT_CHANNEL_FACTORY_H -#define GRPC_CORE_EXT_CLIENT_CHANNEL_CLIENT_CHANNEL_FACTORY_H +#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_CLIENT_CHANNEL_FACTORY_H +#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_CLIENT_CHANNEL_FACTORY_H #include -#include "src/core/ext/client_channel/subchannel.h" +#include "src/core/ext/filters/client_channel/subchannel.h" #include "src/core/lib/channel/channel_stack.h" // Channel arg key for client channel factory. @@ -89,4 +74,4 @@ grpc_channel *grpc_client_channel_factory_create_channel( grpc_arg grpc_client_channel_factory_create_channel_arg( grpc_client_channel_factory *factory); -#endif /* GRPC_CORE_EXT_CLIENT_CHANNEL_CLIENT_CHANNEL_FACTORY_H */ +#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_CLIENT_CHANNEL_FACTORY_H */ diff --git a/Sources/CgRPC/src/core/ext/filters/client_channel/client_channel_plugin.c b/Sources/CgRPC/src/core/ext/filters/client_channel/client_channel_plugin.c new file mode 100644 index 000000000..c32e83d01 --- /dev/null +++ b/Sources/CgRPC/src/core/ext/filters/client_channel/client_channel_plugin.c @@ -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 + +#include +#include +#include + +#include + +#include "src/core/ext/filters/client_channel/client_channel.h" +#include "src/core/ext/filters/client_channel/http_connect_handshaker.h" +#include "src/core/ext/filters/client_channel/http_proxy.h" +#include "src/core/ext/filters/client_channel/lb_policy_registry.h" +#include "src/core/ext/filters/client_channel/proxy_mapper_registry.h" +#include "src/core/ext/filters/client_channel/resolver_registry.h" +#include "src/core/ext/filters/client_channel/retry_throttle.h" +#include "src/core/ext/filters/client_channel/subchannel_index.h" +#include "src/core/lib/surface/channel_init.h" + +static bool append_filter(grpc_exec_ctx *exec_ctx, + grpc_channel_stack_builder *builder, void *arg) { + return grpc_channel_stack_builder_append_filter( + builder, (const grpc_channel_filter *)arg, NULL, NULL); +} + +static bool set_default_host_if_unset(grpc_exec_ctx *exec_ctx, + grpc_channel_stack_builder *builder, + void *unused) { + const grpc_channel_args *args = + grpc_channel_stack_builder_get_channel_arguments(builder); + for (size_t i = 0; i < args->num_args; i++) { + if (0 == strcmp(args->args[i].key, GRPC_ARG_DEFAULT_AUTHORITY) || + 0 == strcmp(args->args[i].key, GRPC_SSL_TARGET_NAME_OVERRIDE_ARG)) { + return true; + } + } + char *default_authority = grpc_get_default_authority( + exec_ctx, grpc_channel_stack_builder_get_target(builder)); + if (default_authority != NULL) { + grpc_arg arg = grpc_channel_arg_string_create(GRPC_ARG_DEFAULT_AUTHORITY, + default_authority); + grpc_channel_args *new_args = grpc_channel_args_copy_and_add(args, &arg, 1); + grpc_channel_stack_builder_set_channel_arguments(exec_ctx, builder, + new_args); + gpr_free(default_authority); + grpc_channel_args_destroy(exec_ctx, new_args); + } + return true; +} + +void grpc_client_channel_init(void) { + grpc_lb_policy_registry_init(); + grpc_resolver_registry_init(); + grpc_retry_throttle_map_init(); + grpc_proxy_mapper_registry_init(); + grpc_register_http_proxy_mapper(); + grpc_subchannel_index_init(); + grpc_channel_init_register_stage(GRPC_CLIENT_CHANNEL, INT_MIN, + set_default_host_if_unset, NULL); + grpc_channel_init_register_stage( + GRPC_CLIENT_CHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, append_filter, + (void *)&grpc_client_channel_filter); + grpc_http_connect_register_handshaker_factory(); + grpc_register_tracer(&grpc_client_channel_trace); +#ifndef NDEBUG + grpc_register_tracer(&grpc_trace_resolver_refcount); +#endif +} + +void grpc_client_channel_shutdown(void) { + grpc_subchannel_index_shutdown(); + grpc_channel_init_shutdown(); + grpc_proxy_mapper_registry_shutdown(); + grpc_retry_throttle_map_shutdown(); + grpc_resolver_registry_shutdown(); + grpc_lb_policy_registry_shutdown(); +} diff --git a/Sources/CgRPC/src/core/ext/filters/client_channel/connector.c b/Sources/CgRPC/src/core/ext/filters/client_channel/connector.c new file mode 100644 index 000000000..c258468e5 --- /dev/null +++ b/Sources/CgRPC/src/core/ext/filters/client_channel/connector.c @@ -0,0 +1,40 @@ +/* + * + * 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 "src/core/ext/filters/client_channel/connector.h" + +grpc_connector* grpc_connector_ref(grpc_connector* connector) { + connector->vtable->ref(connector); + return connector; +} + +void grpc_connector_unref(grpc_exec_ctx* exec_ctx, grpc_connector* connector) { + connector->vtable->unref(exec_ctx, connector); +} + +void grpc_connector_connect(grpc_exec_ctx* exec_ctx, grpc_connector* connector, + const grpc_connect_in_args* in_args, + grpc_connect_out_args* out_args, + grpc_closure* notify) { + connector->vtable->connect(exec_ctx, connector, in_args, out_args, notify); +} + +void grpc_connector_shutdown(grpc_exec_ctx* exec_ctx, grpc_connector* connector, + grpc_error* why) { + connector->vtable->shutdown(exec_ctx, connector, why); +} diff --git a/Sources/CgRPC/src/core/ext/filters/client_channel/connector.h b/Sources/CgRPC/src/core/ext/filters/client_channel/connector.h new file mode 100644 index 000000000..7f3d4a1cc --- /dev/null +++ b/Sources/CgRPC/src/core/ext/filters/client_channel/connector.h @@ -0,0 +1,73 @@ +/* + * + * 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 GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_CONNECTOR_H +#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_CONNECTOR_H + +#include "src/core/lib/channel/channel_stack.h" +#include "src/core/lib/iomgr/resolve_address.h" +#include "src/core/lib/transport/transport.h" + +typedef struct grpc_connector grpc_connector; +typedef struct grpc_connector_vtable grpc_connector_vtable; + +struct grpc_connector { + const grpc_connector_vtable *vtable; +}; + +typedef struct { + /** set of pollsets interested in this connection */ + grpc_pollset_set *interested_parties; + /** deadline for connection */ + gpr_timespec deadline; + /** channel arguments (to be passed to transport) */ + const grpc_channel_args *channel_args; +} grpc_connect_in_args; + +typedef struct { + /** the connected transport */ + grpc_transport *transport; + + /** channel arguments (to be passed to the filters) */ + grpc_channel_args *channel_args; +} grpc_connect_out_args; + +struct grpc_connector_vtable { + void (*ref)(grpc_connector *connector); + void (*unref)(grpc_exec_ctx *exec_ctx, grpc_connector *connector); + /** Implementation of grpc_connector_shutdown */ + void (*shutdown)(grpc_exec_ctx *exec_ctx, grpc_connector *connector, + grpc_error *why); + /** Implementation of grpc_connector_connect */ + void (*connect)(grpc_exec_ctx *exec_ctx, grpc_connector *connector, + const grpc_connect_in_args *in_args, + grpc_connect_out_args *out_args, grpc_closure *notify); +}; + +grpc_connector *grpc_connector_ref(grpc_connector *connector); +void grpc_connector_unref(grpc_exec_ctx *exec_ctx, grpc_connector *connector); +/** Connect using the connector: max one outstanding call at a time */ +void grpc_connector_connect(grpc_exec_ctx *exec_ctx, grpc_connector *connector, + const grpc_connect_in_args *in_args, + grpc_connect_out_args *out_args, + grpc_closure *notify); +/** Cancel any pending connection */ +void grpc_connector_shutdown(grpc_exec_ctx *exec_ctx, grpc_connector *connector, + grpc_error *why); + +#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_CONNECTOR_H */ diff --git a/Sources/CgRPC/src/core/ext/client_channel/http_connect_handshaker.c b/Sources/CgRPC/src/core/ext/filters/client_channel/http_connect_handshaker.c similarity index 66% rename from Sources/CgRPC/src/core/ext/client_channel/http_connect_handshaker.c rename to Sources/CgRPC/src/core/ext/filters/client_channel/http_connect_handshaker.c index 76c78ee85..0952dc6d4 100644 --- a/Sources/CgRPC/src/core/ext/client_channel/http_connect_handshaker.c +++ b/Sources/CgRPC/src/core/ext/filters/client_channel/http_connect_handshaker.c @@ -1,37 +1,22 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 "src/core/ext/client_channel/http_connect_handshaker.h" +#include "src/core/ext/filters/client_channel/http_connect_handshaker.h" #include @@ -40,20 +25,21 @@ #include #include -#include "src/core/ext/client_channel/client_channel.h" -#include "src/core/ext/client_channel/resolver_registry.h" -#include "src/core/ext/client_channel/uri_parser.h" +#include "src/core/ext/filters/client_channel/client_channel.h" +#include "src/core/ext/filters/client_channel/resolver_registry.h" +#include "src/core/ext/filters/client_channel/uri_parser.h" #include "src/core/lib/channel/channel_args.h" +#include "src/core/lib/channel/handshaker_registry.h" #include "src/core/lib/http/format_request.h" #include "src/core/lib/http/parser.h" +#include "src/core/lib/slice/slice_internal.h" #include "src/core/lib/support/env.h" +#include "src/core/lib/support/string.h" typedef struct http_connect_handshaker { // Base class. Must be first. grpc_handshaker base; - char* proxy_server; - gpr_refcount refcount; gpr_mu mu; @@ -83,11 +69,11 @@ static void http_connect_handshaker_unref(grpc_exec_ctx* exec_ctx, grpc_endpoint_destroy(exec_ctx, handshaker->endpoint_to_destroy); } if (handshaker->read_buffer_to_destroy != NULL) { - grpc_slice_buffer_destroy(handshaker->read_buffer_to_destroy); + grpc_slice_buffer_destroy_internal(exec_ctx, + handshaker->read_buffer_to_destroy); gpr_free(handshaker->read_buffer_to_destroy); } - gpr_free(handshaker->proxy_server); - grpc_slice_buffer_destroy(&handshaker->write_buffer); + grpc_slice_buffer_destroy_internal(exec_ctx, &handshaker->write_buffer); grpc_http_parser_destroy(&handshaker->http_parser); grpc_http_response_destroy(&handshaker->http_response); gpr_free(handshaker); @@ -97,12 +83,12 @@ static void http_connect_handshaker_unref(grpc_exec_ctx* exec_ctx, // Set args fields to NULL, saving the endpoint and read buffer for // later destruction. static void cleanup_args_for_failure_locked( - http_connect_handshaker* handshaker) { + grpc_exec_ctx* exec_ctx, http_connect_handshaker* handshaker) { handshaker->endpoint_to_destroy = handshaker->args->endpoint; handshaker->args->endpoint = NULL; handshaker->read_buffer_to_destroy = handshaker->args->read_buffer; handshaker->args->read_buffer = NULL; - grpc_channel_args_destroy(handshaker->args->args); + grpc_channel_args_destroy(exec_ctx, handshaker->args->args); handshaker->args->args = NULL; } @@ -115,23 +101,24 @@ static void handshake_failed_locked(grpc_exec_ctx* exec_ctx, // If we were shut down after an endpoint operation succeeded but // before the endpoint callback was invoked, we need to generate our // own error. - error = GRPC_ERROR_CREATE("Handshaker shutdown"); + error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Handshaker shutdown"); } if (!handshaker->shutdown) { // TODO(ctiller): It is currently necessary to shutdown endpoints // before destroying them, even if we know that there are no // pending read/write callbacks. This should be fixed, at which // point this can be removed. - grpc_endpoint_shutdown(exec_ctx, handshaker->args->endpoint); + grpc_endpoint_shutdown(exec_ctx, handshaker->args->endpoint, + GRPC_ERROR_REF(error)); // Not shutting down, so the handshake failed. Clean up before // invoking the callback. - cleanup_args_for_failure_locked(handshaker); + cleanup_args_for_failure_locked(exec_ctx, handshaker); // Set shutdown to true so that subsequent calls to // http_connect_handshaker_shutdown() do nothing. handshaker->shutdown = true; } // Invoke callback. - grpc_exec_ctx_sched(exec_ctx, handshaker->on_handshake_done, error, NULL); + GRPC_CLOSURE_SCHED(exec_ctx, handshaker->on_handshake_done, error); } // Callback invoked when finished writing HTTP CONNECT request. @@ -193,7 +180,7 @@ static void on_read_done(grpc_exec_ctx* exec_ctx, void* arg, &handshaker->args->read_buffer->slices[i + 1], handshaker->args->read_buffer->count - i - 1); grpc_slice_buffer_swap(handshaker->args->read_buffer, &tmp_buffer); - grpc_slice_buffer_destroy(&tmp_buffer); + grpc_slice_buffer_destroy_internal(exec_ctx, &tmp_buffer); break; } } @@ -210,7 +197,8 @@ static void on_read_done(grpc_exec_ctx* exec_ctx, void* arg, // complete (e.g., handling chunked transfer encoding or looking // at the Content-Length: header). if (handshaker->http_parser.state != GRPC_HTTP_BODY) { - grpc_slice_buffer_reset_and_unref(handshaker->args->read_buffer); + grpc_slice_buffer_reset_and_unref_internal(exec_ctx, + handshaker->args->read_buffer); grpc_endpoint_read(exec_ctx, handshaker->args->endpoint, handshaker->args->read_buffer, &handshaker->response_read_closure); @@ -223,13 +211,13 @@ static void on_read_done(grpc_exec_ctx* exec_ctx, void* arg, char* msg; gpr_asprintf(&msg, "HTTP proxy returned response code %d", handshaker->http_response.status); - error = GRPC_ERROR_CREATE(msg); + error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg); gpr_free(msg); handshake_failed_locked(exec_ctx, handshaker, error); goto done; } // Success. Invoke handshake-done callback. - grpc_exec_ctx_sched(exec_ctx, handshaker->on_handshake_done, error, NULL); + GRPC_CLOSURE_SCHED(exec_ctx, handshaker->on_handshake_done, error); done: // Set shutdown to true so that subsequent calls to // http_connect_handshaker_shutdown() do nothing. @@ -249,15 +237,18 @@ static void http_connect_handshaker_destroy(grpc_exec_ctx* exec_ctx, } static void http_connect_handshaker_shutdown(grpc_exec_ctx* exec_ctx, - grpc_handshaker* handshaker_in) { + grpc_handshaker* handshaker_in, + grpc_error* why) { http_connect_handshaker* handshaker = (http_connect_handshaker*)handshaker_in; gpr_mu_lock(&handshaker->mu); if (!handshaker->shutdown) { handshaker->shutdown = true; - grpc_endpoint_shutdown(exec_ctx, handshaker->args->endpoint); - cleanup_args_for_failure_locked(handshaker); + grpc_endpoint_shutdown(exec_ctx, handshaker->args->endpoint, + GRPC_ERROR_REF(why)); + cleanup_args_for_failure_locked(exec_ctx, handshaker); } gpr_mu_unlock(&handshaker->mu); + GRPC_ERROR_UNREF(why); } static void http_connect_handshaker_do_handshake( @@ -265,82 +256,119 @@ static void http_connect_handshaker_do_handshake( grpc_tcp_server_acceptor* acceptor, grpc_closure* on_handshake_done, grpc_handshaker_args* args) { http_connect_handshaker* handshaker = (http_connect_handshaker*)handshaker_in; - // Get server name from channel args. - const grpc_arg* arg = grpc_channel_args_find(args->args, GRPC_ARG_SERVER_URI); - GPR_ASSERT(arg != NULL); + // Check for HTTP CONNECT channel arg. + // If not found, invoke on_handshake_done without doing anything. + const grpc_arg* arg = + grpc_channel_args_find(args->args, GRPC_ARG_HTTP_CONNECT_SERVER); + if (arg == NULL) { + // Set shutdown to true so that subsequent calls to + // http_connect_handshaker_shutdown() do nothing. + gpr_mu_lock(&handshaker->mu); + handshaker->shutdown = true; + gpr_mu_unlock(&handshaker->mu); + GRPC_CLOSURE_SCHED(exec_ctx, on_handshake_done, GRPC_ERROR_NONE); + return; + } GPR_ASSERT(arg->type == GRPC_ARG_STRING); - char* canonical_uri = - grpc_resolver_factory_add_default_prefix_if_needed(arg->value.string); - grpc_uri* uri = grpc_uri_parse(canonical_uri, 1); - char* server_name = uri->path; - if (server_name[0] == '/') ++server_name; + char* server_name = arg->value.string; + // Get headers from channel args. + arg = grpc_channel_args_find(args->args, GRPC_ARG_HTTP_CONNECT_HEADERS); + grpc_http_header* headers = NULL; + size_t num_headers = 0; + char** header_strings = NULL; + size_t num_header_strings = 0; + if (arg != NULL) { + GPR_ASSERT(arg->type == GRPC_ARG_STRING); + gpr_string_split(arg->value.string, "\n", &header_strings, + &num_header_strings); + headers = gpr_malloc(sizeof(grpc_http_header) * num_header_strings); + for (size_t i = 0; i < num_header_strings; ++i) { + char* sep = strchr(header_strings[i], ':'); + if (sep == NULL) { + gpr_log(GPR_ERROR, "skipping unparseable HTTP CONNECT header: %s", + header_strings[i]); + continue; + } + *sep = '\0'; + headers[num_headers].key = header_strings[i]; + headers[num_headers].value = sep + 1; + ++num_headers; + } + } // Save state in the handshaker object. gpr_mu_lock(&handshaker->mu); handshaker->args = args; handshaker->on_handshake_done = on_handshake_done; - // Send HTTP CONNECT request. + // Log connection via proxy. + char* proxy_name = grpc_endpoint_get_peer(args->endpoint); gpr_log(GPR_INFO, "Connecting to server %s via HTTP proxy %s", server_name, - handshaker->proxy_server); + proxy_name); + gpr_free(proxy_name); + // Construct HTTP CONNECT request. grpc_httpcli_request request; memset(&request, 0, sizeof(request)); request.host = server_name; request.http.method = "CONNECT"; request.http.path = server_name; + request.http.hdrs = headers; + request.http.hdr_count = num_headers; request.handshaker = &grpc_httpcli_plaintext; grpc_slice request_slice = grpc_httpcli_format_connect_request(&request); grpc_slice_buffer_add(&handshaker->write_buffer, request_slice); + // Clean up. + gpr_free(headers); + for (size_t i = 0; i < num_header_strings; ++i) { + gpr_free(header_strings[i]); + } + gpr_free(header_strings); // Take a new ref to be held by the write callback. gpr_ref(&handshaker->refcount); grpc_endpoint_write(exec_ctx, args->endpoint, &handshaker->write_buffer, &handshaker->request_done_closure); gpr_mu_unlock(&handshaker->mu); - // Clean up. - gpr_free(canonical_uri); - grpc_uri_destroy(uri); } static const grpc_handshaker_vtable http_connect_handshaker_vtable = { http_connect_handshaker_destroy, http_connect_handshaker_shutdown, http_connect_handshaker_do_handshake}; -grpc_handshaker* grpc_http_connect_handshaker_create(const char* proxy_server) { - GPR_ASSERT(proxy_server != NULL); +static grpc_handshaker* grpc_http_connect_handshaker_create() { http_connect_handshaker* handshaker = gpr_malloc(sizeof(*handshaker)); memset(handshaker, 0, sizeof(*handshaker)); grpc_handshaker_init(&http_connect_handshaker_vtable, &handshaker->base); gpr_mu_init(&handshaker->mu); gpr_ref_init(&handshaker->refcount, 1); - handshaker->proxy_server = gpr_strdup(proxy_server); grpc_slice_buffer_init(&handshaker->write_buffer); - grpc_closure_init(&handshaker->request_done_closure, on_write_done, - handshaker); - grpc_closure_init(&handshaker->response_read_closure, on_read_done, - handshaker); + GRPC_CLOSURE_INIT(&handshaker->request_done_closure, on_write_done, + handshaker, grpc_schedule_on_exec_ctx); + GRPC_CLOSURE_INIT(&handshaker->response_read_closure, on_read_done, + handshaker, grpc_schedule_on_exec_ctx); grpc_http_parser_init(&handshaker->http_parser, GRPC_HTTP_RESPONSE, &handshaker->http_response); return &handshaker->base; } -char* grpc_get_http_proxy_server() { - char* uri_str = gpr_getenv("http_proxy"); - if (uri_str == NULL) return NULL; - grpc_uri* uri = grpc_uri_parse(uri_str, false /* suppress_errors */); - char* proxy_name = NULL; - if (uri == NULL || uri->authority == NULL) { - gpr_log(GPR_ERROR, "cannot parse value of 'http_proxy' env var"); - goto done; - } - if (strcmp(uri->scheme, "http") != 0) { - gpr_log(GPR_ERROR, "'%s' scheme not supported in proxy URI", uri->scheme); - goto done; - } - if (strchr(uri->authority, '@') != NULL) { - gpr_log(GPR_ERROR, "userinfo not supported in proxy URI"); - goto done; - } - proxy_name = gpr_strdup(uri->authority); -done: - gpr_free(uri_str); - grpc_uri_destroy(uri); - return proxy_name; +// +// handshaker factory +// + +static void handshaker_factory_add_handshakers( + grpc_exec_ctx* exec_ctx, grpc_handshaker_factory* factory, + const grpc_channel_args* args, grpc_handshake_manager* handshake_mgr) { + grpc_handshake_manager_add(handshake_mgr, + grpc_http_connect_handshaker_create()); +} + +static void handshaker_factory_destroy(grpc_exec_ctx* exec_ctx, + grpc_handshaker_factory* factory) {} + +static const grpc_handshaker_factory_vtable handshaker_factory_vtable = { + handshaker_factory_add_handshakers, handshaker_factory_destroy}; + +static grpc_handshaker_factory handshaker_factory = { + &handshaker_factory_vtable}; + +void grpc_http_connect_register_handshaker_factory() { + grpc_handshaker_factory_register(true /* at_start */, HANDSHAKER_CLIENT, + &handshaker_factory); } diff --git a/Sources/CgRPC/src/core/ext/filters/client_channel/http_connect_handshaker.h b/Sources/CgRPC/src/core/ext/filters/client_channel/http_connect_handshaker.h new file mode 100644 index 000000000..928a23dc9 --- /dev/null +++ b/Sources/CgRPC/src/core/ext/filters/client_channel/http_connect_handshaker.h @@ -0,0 +1,34 @@ +/* + * + * Copyright 2016 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 GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_HTTP_CONNECT_HANDSHAKER_H +#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_HTTP_CONNECT_HANDSHAKER_H + +/// Channel arg indicating the server in HTTP CONNECT request (string). +/// The presence of this arg triggers the use of HTTP CONNECT. +#define GRPC_ARG_HTTP_CONNECT_SERVER "grpc.http_connect_server" + +/// Channel arg indicating HTTP CONNECT headers (string). +/// Multiple headers are separated by newlines. Key/value pairs are +/// seperated by colons. +#define GRPC_ARG_HTTP_CONNECT_HEADERS "grpc.http_connect_headers" + +/// Registers handshaker factory. +void grpc_http_connect_register_handshaker_factory(); + +#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_HTTP_CONNECT_HANDSHAKER_H */ diff --git a/Sources/CgRPC/src/core/ext/filters/client_channel/http_proxy.c b/Sources/CgRPC/src/core/ext/filters/client_channel/http_proxy.c new file mode 100644 index 000000000..ef3512ed8 --- /dev/null +++ b/Sources/CgRPC/src/core/ext/filters/client_channel/http_proxy.c @@ -0,0 +1,199 @@ +/* + * + * Copyright 2016 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 "src/core/ext/filters/client_channel/http_proxy.h" + +#include +#include + +#include +#include +#include +#include + +#include "src/core/ext/filters/client_channel/http_connect_handshaker.h" +#include "src/core/ext/filters/client_channel/proxy_mapper_registry.h" +#include "src/core/ext/filters/client_channel/uri_parser.h" +#include "src/core/lib/channel/channel_args.h" +#include "src/core/lib/slice/b64.h" +#include "src/core/lib/support/env.h" +#include "src/core/lib/support/string.h" + +/** + * Parses the 'http_proxy' env var and returns the proxy hostname to resolve or + * NULL on error. Also sets 'user_cred' to user credentials if present in the + * 'http_proxy' env var, otherwise leaves it unchanged. It is caller's + * responsibility to gpr_free user_cred. + */ +static char* get_http_proxy_server(grpc_exec_ctx* exec_ctx, char** user_cred) { + GPR_ASSERT(user_cred != NULL); + char* proxy_name = NULL; + char* uri_str = gpr_getenv("http_proxy"); + if (uri_str == NULL) return NULL; + grpc_uri* uri = + grpc_uri_parse(exec_ctx, uri_str, false /* suppress_errors */); + if (uri == NULL || uri->authority == NULL) { + gpr_log(GPR_ERROR, "cannot parse value of 'http_proxy' env var"); + goto done; + } + if (strcmp(uri->scheme, "http") != 0) { + gpr_log(GPR_ERROR, "'%s' scheme not supported in proxy URI", uri->scheme); + goto done; + } + /* Split on '@' to separate user credentials from host */ + char** authority_strs = NULL; + size_t authority_nstrs; + gpr_string_split(uri->authority, "@", &authority_strs, &authority_nstrs); + GPR_ASSERT(authority_nstrs != 0); /* should have at least 1 string */ + if (authority_nstrs == 1) { + /* User cred not present in authority */ + proxy_name = authority_strs[0]; + } else if (authority_nstrs == 2) { + /* User cred found */ + *user_cred = authority_strs[0]; + proxy_name = authority_strs[1]; + gpr_log(GPR_DEBUG, "userinfo found in proxy URI"); + } else { + /* Bad authority */ + for (size_t i = 0; i < authority_nstrs; i++) { + gpr_free(authority_strs[i]); + } + proxy_name = NULL; + } + gpr_free(authority_strs); +done: + gpr_free(uri_str); + grpc_uri_destroy(uri); + return proxy_name; +} + +static bool proxy_mapper_map_name(grpc_exec_ctx* exec_ctx, + grpc_proxy_mapper* mapper, + const char* server_uri, + const grpc_channel_args* args, + char** name_to_resolve, + grpc_channel_args** new_args) { + char* user_cred = NULL; + *name_to_resolve = get_http_proxy_server(exec_ctx, &user_cred); + if (*name_to_resolve == NULL) return false; + grpc_uri* uri = + grpc_uri_parse(exec_ctx, server_uri, false /* suppress_errors */); + if (uri == NULL || uri->path[0] == '\0') { + gpr_log(GPR_ERROR, + "'http_proxy' environment variable set, but cannot " + "parse server URI '%s' -- not using proxy", + server_uri); + if (uri != NULL) { + gpr_free(user_cred); + grpc_uri_destroy(uri); + } + return false; + } + if (strcmp(uri->scheme, "unix") == 0) { + gpr_log(GPR_INFO, "not using proxy for Unix domain socket '%s'", + server_uri); + gpr_free(user_cred); + grpc_uri_destroy(uri); + return false; + } + char* no_proxy_str = gpr_getenv("no_proxy"); + if (no_proxy_str != NULL) { + static const char* NO_PROXY_SEPARATOR = ","; + bool use_proxy = true; + char* server_host; + char* server_port; + if (!gpr_split_host_port(uri->path[0] == '/' ? uri->path + 1 : uri->path, + &server_host, &server_port)) { + gpr_log(GPR_INFO, + "unable to split host and port, not checking no_proxy list for " + "host '%s'", + server_uri); + } else { + size_t uri_len = strlen(server_host); + char** no_proxy_hosts; + size_t num_no_proxy_hosts; + gpr_string_split(no_proxy_str, NO_PROXY_SEPARATOR, &no_proxy_hosts, + &num_no_proxy_hosts); + for (size_t i = 0; i < num_no_proxy_hosts; i++) { + char* no_proxy_entry = no_proxy_hosts[i]; + size_t no_proxy_len = strlen(no_proxy_entry); + if (no_proxy_len <= uri_len && + gpr_stricmp(no_proxy_entry, &server_host[uri_len - no_proxy_len]) == + 0) { + gpr_log(GPR_INFO, "not using proxy for host in no_proxy list '%s'", + server_uri); + use_proxy = false; + break; + } + } + for (size_t i = 0; i < num_no_proxy_hosts; i++) { + gpr_free(no_proxy_hosts[i]); + } + gpr_free(no_proxy_hosts); + gpr_free(server_host); + gpr_free(server_port); + if (!use_proxy) { + grpc_uri_destroy(uri); + gpr_free(*name_to_resolve); + *name_to_resolve = NULL; + return false; + } + } + } + grpc_arg args_to_add[2]; + args_to_add[0] = grpc_channel_arg_string_create( + GRPC_ARG_HTTP_CONNECT_SERVER, + uri->path[0] == '/' ? uri->path + 1 : uri->path); + if (user_cred != NULL) { + /* Use base64 encoding for user credentials as stated in RFC 7617 */ + char* encoded_user_cred = + grpc_base64_encode(user_cred, strlen(user_cred), 0, 0); + char* header; + gpr_asprintf(&header, "Proxy-Authorization:Basic %s", encoded_user_cred); + gpr_free(encoded_user_cred); + args_to_add[1] = + grpc_channel_arg_string_create(GRPC_ARG_HTTP_CONNECT_HEADERS, header); + *new_args = grpc_channel_args_copy_and_add(args, args_to_add, 2); + gpr_free(header); + } else { + *new_args = grpc_channel_args_copy_and_add(args, args_to_add, 1); + } + gpr_free(user_cred); + grpc_uri_destroy(uri); + return true; +} + +static bool proxy_mapper_map_address(grpc_exec_ctx* exec_ctx, + grpc_proxy_mapper* mapper, + const grpc_resolved_address* address, + const grpc_channel_args* args, + grpc_resolved_address** new_address, + grpc_channel_args** new_args) { + return false; +} + +static void proxy_mapper_destroy(grpc_proxy_mapper* mapper) {} + +static const grpc_proxy_mapper_vtable proxy_mapper_vtable = { + proxy_mapper_map_name, proxy_mapper_map_address, proxy_mapper_destroy}; + +static grpc_proxy_mapper proxy_mapper = {&proxy_mapper_vtable}; + +void grpc_register_http_proxy_mapper() { + grpc_proxy_mapper_register(true /* at_start */, &proxy_mapper); +} diff --git a/Sources/CgRPC/src/core/ext/filters/client_channel/http_proxy.h b/Sources/CgRPC/src/core/ext/filters/client_channel/http_proxy.h new file mode 100644 index 000000000..34694931d --- /dev/null +++ b/Sources/CgRPC/src/core/ext/filters/client_channel/http_proxy.h @@ -0,0 +1,24 @@ +/* + * + * Copyright 2016 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 GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_HTTP_PROXY_H +#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_HTTP_PROXY_H + +void grpc_register_http_proxy_mapper(); + +#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_HTTP_PROXY_H */ diff --git a/Sources/CgRPC/src/core/ext/filters/client_channel/lb_policy.c b/Sources/CgRPC/src/core/ext/filters/client_channel/lb_policy.c new file mode 100644 index 000000000..dd95a135c --- /dev/null +++ b/Sources/CgRPC/src/core/ext/filters/client_channel/lb_policy.c @@ -0,0 +1,164 @@ +/* + * + * 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 "src/core/ext/filters/client_channel/lb_policy.h" +#include "src/core/lib/iomgr/combiner.h" + +#define WEAK_REF_BITS 16 + +#ifndef NDEBUG +grpc_tracer_flag grpc_trace_lb_policy_refcount = + GRPC_TRACER_INITIALIZER(false, "lb_policy_refcount"); +#endif + +void grpc_lb_policy_init(grpc_lb_policy *policy, + const grpc_lb_policy_vtable *vtable, + grpc_combiner *combiner) { + policy->vtable = vtable; + gpr_atm_no_barrier_store(&policy->ref_pair, 1 << WEAK_REF_BITS); + policy->interested_parties = grpc_pollset_set_create(); + policy->combiner = GRPC_COMBINER_REF(combiner, "lb_policy"); +} + +#ifndef NDEBUG +#define REF_FUNC_EXTRA_ARGS , const char *file, int line, const char *reason +#define REF_MUTATE_EXTRA_ARGS REF_FUNC_EXTRA_ARGS, const char *purpose +#define REF_FUNC_PASS_ARGS(new_reason) , file, line, new_reason +#define REF_MUTATE_PASS_ARGS(purpose) , file, line, reason, purpose +#else +#define REF_FUNC_EXTRA_ARGS +#define REF_MUTATE_EXTRA_ARGS +#define REF_FUNC_PASS_ARGS(new_reason) +#define REF_MUTATE_PASS_ARGS(x) +#endif + +static gpr_atm ref_mutate(grpc_lb_policy *c, gpr_atm delta, + int barrier REF_MUTATE_EXTRA_ARGS) { + gpr_atm old_val = barrier ? gpr_atm_full_fetch_add(&c->ref_pair, delta) + : gpr_atm_no_barrier_fetch_add(&c->ref_pair, delta); +#ifndef NDEBUG + if (GRPC_TRACER_ON(grpc_trace_lb_policy_refcount)) { + gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, + "LB_POLICY: %p %12s 0x%" PRIxPTR " -> 0x%" PRIxPTR " [%s]", c, + purpose, old_val, old_val + delta, reason); + } +#endif + return old_val; +} + +void grpc_lb_policy_ref(grpc_lb_policy *policy REF_FUNC_EXTRA_ARGS) { + ref_mutate(policy, 1 << WEAK_REF_BITS, 0 REF_MUTATE_PASS_ARGS("STRONG_REF")); +} + +static void shutdown_locked(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error) { + grpc_lb_policy *policy = arg; + policy->vtable->shutdown_locked(exec_ctx, policy); + GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, policy, "strong-unref"); +} + +void grpc_lb_policy_unref(grpc_exec_ctx *exec_ctx, + grpc_lb_policy *policy REF_FUNC_EXTRA_ARGS) { + gpr_atm old_val = + ref_mutate(policy, (gpr_atm)1 - (gpr_atm)(1 << WEAK_REF_BITS), + 1 REF_MUTATE_PASS_ARGS("STRONG_UNREF")); + gpr_atm mask = ~(gpr_atm)((1 << WEAK_REF_BITS) - 1); + gpr_atm check = 1 << WEAK_REF_BITS; + if ((old_val & mask) == check) { + GRPC_CLOSURE_SCHED(exec_ctx, GRPC_CLOSURE_CREATE( + shutdown_locked, policy, + grpc_combiner_scheduler(policy->combiner)), + GRPC_ERROR_NONE); + } else { + grpc_lb_policy_weak_unref(exec_ctx, + policy REF_FUNC_PASS_ARGS("strong-unref")); + } +} + +void grpc_lb_policy_weak_ref(grpc_lb_policy *policy REF_FUNC_EXTRA_ARGS) { + ref_mutate(policy, 1, 0 REF_MUTATE_PASS_ARGS("WEAK_REF")); +} + +void grpc_lb_policy_weak_unref(grpc_exec_ctx *exec_ctx, + grpc_lb_policy *policy REF_FUNC_EXTRA_ARGS) { + gpr_atm old_val = + ref_mutate(policy, -(gpr_atm)1, 1 REF_MUTATE_PASS_ARGS("WEAK_UNREF")); + if (old_val == 1) { + grpc_pollset_set_destroy(exec_ctx, policy->interested_parties); + grpc_combiner *combiner = policy->combiner; + policy->vtable->destroy(exec_ctx, policy); + GRPC_COMBINER_UNREF(exec_ctx, combiner, "lb_policy"); + } +} + +int grpc_lb_policy_pick_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, + const grpc_lb_policy_pick_args *pick_args, + grpc_connected_subchannel **target, + grpc_call_context_element *context, + void **user_data, grpc_closure *on_complete) { + return policy->vtable->pick_locked(exec_ctx, policy, pick_args, target, + context, user_data, on_complete); +} + +void grpc_lb_policy_cancel_pick_locked(grpc_exec_ctx *exec_ctx, + grpc_lb_policy *policy, + grpc_connected_subchannel **target, + grpc_error *error) { + policy->vtable->cancel_pick_locked(exec_ctx, policy, target, error); +} + +void grpc_lb_policy_cancel_picks_locked(grpc_exec_ctx *exec_ctx, + grpc_lb_policy *policy, + uint32_t initial_metadata_flags_mask, + uint32_t initial_metadata_flags_eq, + grpc_error *error) { + policy->vtable->cancel_picks_locked(exec_ctx, policy, + initial_metadata_flags_mask, + initial_metadata_flags_eq, error); +} + +void grpc_lb_policy_exit_idle_locked(grpc_exec_ctx *exec_ctx, + grpc_lb_policy *policy) { + policy->vtable->exit_idle_locked(exec_ctx, policy); +} + +void grpc_lb_policy_ping_one_locked(grpc_exec_ctx *exec_ctx, + grpc_lb_policy *policy, + grpc_closure *closure) { + policy->vtable->ping_one_locked(exec_ctx, policy, closure); +} + +void grpc_lb_policy_notify_on_state_change_locked( + grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, + grpc_connectivity_state *state, grpc_closure *closure) { + policy->vtable->notify_on_state_change_locked(exec_ctx, policy, state, + closure); +} + +grpc_connectivity_state grpc_lb_policy_check_connectivity_locked( + grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, + grpc_error **connectivity_error) { + return policy->vtable->check_connectivity_locked(exec_ctx, policy, + connectivity_error); +} + +void grpc_lb_policy_update_locked(grpc_exec_ctx *exec_ctx, + grpc_lb_policy *policy, + const grpc_lb_policy_args *lb_policy_args) { + policy->vtable->update_locked(exec_ctx, policy, lb_policy_args); +} diff --git a/Sources/CgRPC/src/core/ext/client_channel/lb_policy.h b/Sources/CgRPC/src/core/ext/filters/client_channel/lb_policy.h similarity index 53% rename from Sources/CgRPC/src/core/ext/client_channel/lb_policy.h rename to Sources/CgRPC/src/core/ext/filters/client_channel/lb_policy.h index 120c641ed..645d51e13 100644 --- a/Sources/CgRPC/src/core/ext/client_channel/lb_policy.h +++ b/Sources/CgRPC/src/core/ext/filters/client_channel/lb_policy.h @@ -1,40 +1,25 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 GRPC_CORE_EXT_CLIENT_CHANNEL_LB_POLICY_H -#define GRPC_CORE_EXT_CLIENT_CHANNEL_LB_POLICY_H +#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_H +#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_H -#include "src/core/ext/client_channel/subchannel.h" +#include "src/core/ext/filters/client_channel/subchannel.h" #include "src/core/lib/iomgr/polling_entity.h" #include "src/core/lib/transport/connectivity_state.h" @@ -42,15 +27,19 @@ is expected to be extended to contain some parameters) */ typedef struct grpc_lb_policy grpc_lb_policy; typedef struct grpc_lb_policy_vtable grpc_lb_policy_vtable; +typedef struct grpc_lb_policy_args grpc_lb_policy_args; -typedef void (*grpc_lb_completion)(void *cb_arg, grpc_subchannel *subchannel, - grpc_status_code status, const char *errmsg); +#ifndef NDEBUG +extern grpc_tracer_flag grpc_trace_lb_policy_refcount; +#endif struct grpc_lb_policy { const grpc_lb_policy_vtable *vtable; gpr_atm ref_pair; /* owned pointer to interested parties in load balancing decisions */ grpc_pollset_set *interested_parties; + /* combiner under which lb_policy actions take place */ + grpc_combiner *combiner; }; /** Extra arguments for an LB pick */ @@ -63,52 +52,55 @@ typedef struct grpc_lb_policy_pick_args { uint32_t initial_metadata_flags; /** Storage for LB token in \a initial_metadata, or NULL if not used */ grpc_linked_mdelem *lb_token_mdelem_storage; - /** Deadline for the call to the LB server */ - gpr_timespec deadline; } grpc_lb_policy_pick_args; struct grpc_lb_policy_vtable { void (*destroy)(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy); - void (*shutdown)(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy); + void (*shutdown_locked)(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy); /** \see grpc_lb_policy_pick */ - int (*pick)(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, - const grpc_lb_policy_pick_args *pick_args, - grpc_connected_subchannel **target, void **user_data, - grpc_closure *on_complete); + int (*pick_locked)(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, + const grpc_lb_policy_pick_args *pick_args, + grpc_connected_subchannel **target, + grpc_call_context_element *context, void **user_data, + grpc_closure *on_complete); /** \see grpc_lb_policy_cancel_pick */ - void (*cancel_pick)(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, - grpc_connected_subchannel **target, grpc_error *error); + void (*cancel_pick_locked)(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, + grpc_connected_subchannel **target, + grpc_error *error); /** \see grpc_lb_policy_cancel_picks */ - void (*cancel_picks)(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, - uint32_t initial_metadata_flags_mask, - uint32_t initial_metadata_flags_eq, grpc_error *error); + void (*cancel_picks_locked)(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, + uint32_t initial_metadata_flags_mask, + uint32_t initial_metadata_flags_eq, + grpc_error *error); /** \see grpc_lb_policy_ping_one */ - void (*ping_one)(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, - grpc_closure *closure); + void (*ping_one_locked)(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, + grpc_closure *closure); /** Try to enter a READY connectivity state */ - void (*exit_idle)(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy); + void (*exit_idle_locked)(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy); /** check the current connectivity of the lb_policy */ - grpc_connectivity_state (*check_connectivity)( + grpc_connectivity_state (*check_connectivity_locked)( grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, grpc_error **connectivity_error); /** call notify when the connectivity state of a channel changes from *state. Updates *state with the new state of the policy. Calling with a NULL \a state cancels the subscription. */ - void (*notify_on_state_change)(grpc_exec_ctx *exec_ctx, - grpc_lb_policy *policy, - grpc_connectivity_state *state, - grpc_closure *closure); + void (*notify_on_state_change_locked)(grpc_exec_ctx *exec_ctx, + grpc_lb_policy *policy, + grpc_connectivity_state *state, + grpc_closure *closure); + + void (*update_locked)(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, + const grpc_lb_policy_args *args); }; -/*#define GRPC_LB_POLICY_REFCOUNT_DEBUG*/ -#ifdef GRPC_LB_POLICY_REFCOUNT_DEBUG +#ifndef NDEBUG /* Strong references: the policy will shutdown when they reach zero */ #define GRPC_LB_POLICY_REF(p, r) \ @@ -144,13 +136,18 @@ void grpc_lb_policy_weak_unref(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy); /** called by concrete implementations to initialize the base struct */ void grpc_lb_policy_init(grpc_lb_policy *policy, - const grpc_lb_policy_vtable *vtable); + const grpc_lb_policy_vtable *vtable, + grpc_combiner *combiner); /** Finds an appropriate subchannel for a call, based on \a pick_args. - \a target will be set to the selected subchannel, or NULL on failure. + \a target will be set to the selected subchannel, or NULL on failure + or when the LB policy decides to drop the call. + Upon success, \a user_data will be set to whatever opaque information may need to be propagated from the LB policy, or NULL if not needed. + \a context will be populated with context to pass to the subchannel + call, if needed. If the pick succeeds and a result is known immediately, a non-zero value will be returned. Otherwise, \a on_complete will be invoked @@ -159,44 +156,52 @@ void grpc_lb_policy_init(grpc_lb_policy *policy, Any IO should be done under the \a interested_parties \a grpc_pollset_set in the \a grpc_lb_policy struct. */ -int grpc_lb_policy_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, - const grpc_lb_policy_pick_args *pick_args, - grpc_connected_subchannel **target, void **user_data, - grpc_closure *on_complete); +int grpc_lb_policy_pick_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, + const grpc_lb_policy_pick_args *pick_args, + grpc_connected_subchannel **target, + grpc_call_context_element *context, + void **user_data, grpc_closure *on_complete); /** Perform a connected subchannel ping (see \a grpc_connected_subchannel_ping) against one of the connected subchannels managed by \a policy. */ -void grpc_lb_policy_ping_one(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, - grpc_closure *closure); +void grpc_lb_policy_ping_one_locked(grpc_exec_ctx *exec_ctx, + grpc_lb_policy *policy, + grpc_closure *closure); /** Cancel picks for \a target. The \a on_complete callback of the pending picks will be invoked with \a *target set to NULL. */ -void grpc_lb_policy_cancel_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, - grpc_connected_subchannel **target, - grpc_error *error); +void grpc_lb_policy_cancel_pick_locked(grpc_exec_ctx *exec_ctx, + grpc_lb_policy *policy, + grpc_connected_subchannel **target, + grpc_error *error); /** Cancel all pending picks for which their \a initial_metadata_flags (as given in the call to \a grpc_lb_policy_pick) matches \a initial_metadata_flags_eq when AND'd with \a initial_metadata_flags_mask */ -void grpc_lb_policy_cancel_picks(grpc_exec_ctx *exec_ctx, - grpc_lb_policy *policy, - uint32_t initial_metadata_flags_mask, - uint32_t initial_metadata_flags_eq, - grpc_error *error); +void grpc_lb_policy_cancel_picks_locked(grpc_exec_ctx *exec_ctx, + grpc_lb_policy *policy, + uint32_t initial_metadata_flags_mask, + uint32_t initial_metadata_flags_eq, + grpc_error *error); /** Try to enter a READY connectivity state */ -void grpc_lb_policy_exit_idle(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy); +void grpc_lb_policy_exit_idle_locked(grpc_exec_ctx *exec_ctx, + grpc_lb_policy *policy); /* Call notify when the connectivity state of a channel changes from \a *state. * Updates \a *state with the new state of the policy */ -void grpc_lb_policy_notify_on_state_change(grpc_exec_ctx *exec_ctx, - grpc_lb_policy *policy, - grpc_connectivity_state *state, - grpc_closure *closure); +void grpc_lb_policy_notify_on_state_change_locked( + grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, + grpc_connectivity_state *state, grpc_closure *closure); -grpc_connectivity_state grpc_lb_policy_check_connectivity( +grpc_connectivity_state grpc_lb_policy_check_connectivity_locked( grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, grpc_error **connectivity_error); -#endif /* GRPC_CORE_EXT_CLIENT_CHANNEL_LB_POLICY_H */ +/** Update \a policy with \a lb_policy_args. */ +void grpc_lb_policy_update_locked(grpc_exec_ctx *exec_ctx, + grpc_lb_policy *policy, + const grpc_lb_policy_args *lb_policy_args); + +#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_H */ diff --git a/Sources/CgRPC/src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.c b/Sources/CgRPC/src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.c new file mode 100644 index 000000000..568bb2ba8 --- /dev/null +++ b/Sources/CgRPC/src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.c @@ -0,0 +1,137 @@ +/* + * + * Copyright 2017 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 "src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.h" + +#include +#include + +#include "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h" +#include "src/core/lib/iomgr/error.h" +#include "src/core/lib/profiling/timers.h" + +static grpc_error *init_channel_elem(grpc_exec_ctx *exec_ctx, + grpc_channel_element *elem, + grpc_channel_element_args *args) { + return GRPC_ERROR_NONE; +} + +static void destroy_channel_elem(grpc_exec_ctx *exec_ctx, + grpc_channel_element *elem) {} + +typedef struct { + // Stats object to update. + grpc_grpclb_client_stats *client_stats; + // State for intercepting send_initial_metadata. + grpc_closure on_complete_for_send; + grpc_closure *original_on_complete_for_send; + bool send_initial_metadata_succeeded; + // State for intercepting recv_initial_metadata. + grpc_closure recv_initial_metadata_ready; + grpc_closure *original_recv_initial_metadata_ready; + bool recv_initial_metadata_succeeded; +} call_data; + +static void on_complete_for_send(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error) { + call_data *calld = arg; + if (error == GRPC_ERROR_NONE) { + calld->send_initial_metadata_succeeded = true; + } + GRPC_CLOSURE_RUN(exec_ctx, calld->original_on_complete_for_send, + GRPC_ERROR_REF(error)); +} + +static void recv_initial_metadata_ready(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error) { + call_data *calld = arg; + if (error == GRPC_ERROR_NONE) { + calld->recv_initial_metadata_succeeded = true; + } + GRPC_CLOSURE_RUN(exec_ctx, calld->original_recv_initial_metadata_ready, + GRPC_ERROR_REF(error)); +} + +static grpc_error *init_call_elem(grpc_exec_ctx *exec_ctx, + grpc_call_element *elem, + const grpc_call_element_args *args) { + call_data *calld = elem->call_data; + // Get stats object from context and take a ref. + GPR_ASSERT(args->context != NULL); + GPR_ASSERT(args->context[GRPC_GRPCLB_CLIENT_STATS].value != NULL); + calld->client_stats = grpc_grpclb_client_stats_ref( + args->context[GRPC_GRPCLB_CLIENT_STATS].value); + // Record call started. + grpc_grpclb_client_stats_add_call_started(calld->client_stats); + return GRPC_ERROR_NONE; +} + +static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, + const grpc_call_final_info *final_info, + grpc_closure *ignored) { + call_data *calld = elem->call_data; + // Record call finished, optionally setting client_failed_to_send and + // received. + grpc_grpclb_client_stats_add_call_finished( + !calld->send_initial_metadata_succeeded /* client_failed_to_send */, + calld->recv_initial_metadata_succeeded /* known_received */, + calld->client_stats); + // All done, so unref the stats object. + grpc_grpclb_client_stats_unref(calld->client_stats); +} + +static void start_transport_stream_op_batch( + grpc_exec_ctx *exec_ctx, grpc_call_element *elem, + grpc_transport_stream_op_batch *batch) { + call_data *calld = elem->call_data; + GPR_TIMER_BEGIN("clr_start_transport_stream_op_batch", 0); + // Intercept send_initial_metadata. + if (batch->send_initial_metadata) { + calld->original_on_complete_for_send = batch->on_complete; + GRPC_CLOSURE_INIT(&calld->on_complete_for_send, on_complete_for_send, calld, + grpc_schedule_on_exec_ctx); + batch->on_complete = &calld->on_complete_for_send; + } + // Intercept recv_initial_metadata. + if (batch->recv_initial_metadata) { + calld->original_recv_initial_metadata_ready = + batch->payload->recv_initial_metadata.recv_initial_metadata_ready; + GRPC_CLOSURE_INIT(&calld->recv_initial_metadata_ready, + recv_initial_metadata_ready, calld, + grpc_schedule_on_exec_ctx); + batch->payload->recv_initial_metadata.recv_initial_metadata_ready = + &calld->recv_initial_metadata_ready; + } + // Chain to next filter. + grpc_call_next_op(exec_ctx, elem, batch); + GPR_TIMER_END("clr_start_transport_stream_op_batch", 0); +} + +const grpc_channel_filter grpc_client_load_reporting_filter = { + start_transport_stream_op_batch, + grpc_channel_next_op, + sizeof(call_data), + init_call_elem, + grpc_call_stack_ignore_set_pollset_or_pollset_set, + destroy_call_elem, + 0, // sizeof(channel_data) + init_channel_elem, + destroy_channel_elem, + grpc_call_next_get_peer, + grpc_channel_next_get_info, + "client_load_reporting"}; diff --git a/Sources/CgRPC/src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.h b/Sources/CgRPC/src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.h new file mode 100644 index 000000000..51e30b20b --- /dev/null +++ b/Sources/CgRPC/src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.h @@ -0,0 +1,27 @@ +/* + * + * Copyright 2017 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 GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_GRPCLB_CLIENT_LOAD_REPORTING_FILTER_H +#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_GRPCLB_CLIENT_LOAD_REPORTING_FILTER_H + +#include "src/core/lib/channel/channel_stack.h" + +extern const grpc_channel_filter grpc_client_load_reporting_filter; + +#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_GRPCLB_CLIENT_LOAD_REPORTING_FILTER_H \ + */ diff --git a/Sources/CgRPC/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.c b/Sources/CgRPC/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.c new file mode 100644 index 000000000..bb9217d84 --- /dev/null +++ b/Sources/CgRPC/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.c @@ -0,0 +1,1907 @@ +/* + * + * Copyright 2016 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. + * + */ + +/** Implementation of the gRPC LB policy. + * + * This policy takes as input a set of resolved addresses {a1..an} for which the + * LB set was set (it's the resolver's responsibility to ensure this). That is + * to say, {a1..an} represent a collection of LB servers. + * + * An internal channel (\a glb_lb_policy.lb_channel) is created over {a1..an}. + * This channel behaves just like a regular channel. In particular, the + * constructed URI over the addresses a1..an will use the default pick first + * policy to select from this list of LB server backends. + * + * The first time the policy gets a request for a pick, a ping, or to exit the + * idle state, \a query_for_backends_locked() is called. This function sets up + * and initiates the internal communication with the LB server. In particular, + * it's responsible for instantiating the internal *streaming* call to the LB + * server (whichever address from {a1..an} pick-first chose). This call is + * serviced by two callbacks, \a lb_on_server_status_received and \a + * lb_on_response_received. The former will be called when the call to the LB + * server completes. This can happen if the LB server closes the connection or + * if this policy itself cancels the call (for example because it's shutting + * down). If the internal call times out, the usual behavior of pick-first + * applies, continuing to pick from the list {a1..an}. + * + * Upon sucesss, the incoming \a LoadBalancingResponse is processed by \a + * res_recv. An invalid one results in the termination of the streaming call. A + * new streaming call should be created if possible, failing the original call + * otherwise. For a valid \a LoadBalancingResponse, the server list of actual + * backends is extracted. A Round Robin policy will be created from this list. + * There are two possible scenarios: + * + * 1. This is the first server list received. There was no previous instance of + * the Round Robin policy. \a rr_handover_locked() will instantiate the RR + * policy and perform all the pending operations over it. + * 2. There's already a RR policy instance active. We need to introduce the new + * one build from the new serverlist, but taking care not to disrupt the + * operations in progress over the old RR instance. This is done by + * decreasing the reference count on the old policy. The moment no more + * references are held on the old RR policy, it'll be destroyed and \a + * glb_rr_connectivity_changed notified with a \a GRPC_CHANNEL_SHUTDOWN + * state. At this point we can transition to a new RR instance safely, which + * is done once again via \a rr_handover_locked(). + * + * + * Once a RR policy instance is in place (and getting updated as described), + * calls to for a pick, a ping or a cancellation will be serviced right away by + * forwarding them to the RR instance. Any time there's no RR policy available + * (ie, right after the creation of the gRPCLB policy, if an empty serverlist is + * received, etc), pick/ping requests are added to a list of pending picks/pings + * to be flushed and serviced as part of \a rr_handover_locked() the moment the + * RR policy instance becomes available. + * + * \see https://github.com/grpc/grpc/blob/master/doc/load-balancing.md for the + * high level design and details. */ + +/* TODO(dgq): + * - Implement LB service forwarding (point 2c. in the doc's diagram). + */ + +/* With the addition of a libuv endpoint, sockaddr.h now includes uv.h when + using that endpoint. Because of various transitive includes in uv.h, + including windows.h on Windows, uv.h must be included before other system + headers. Therefore, sockaddr.h must always be included first */ +#include "src/core/lib/iomgr/sockaddr.h" + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "src/core/ext/filters/client_channel/client_channel.h" +#include "src/core/ext/filters/client_channel/client_channel_factory.h" +#include "src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.h" +#include "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h" +#include "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h" +#include "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h" +#include "src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h" +#include "src/core/ext/filters/client_channel/lb_policy_factory.h" +#include "src/core/ext/filters/client_channel/lb_policy_registry.h" +#include "src/core/ext/filters/client_channel/parse_address.h" +#include "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h" +#include "src/core/lib/channel/channel_args.h" +#include "src/core/lib/channel/channel_stack.h" +#include "src/core/lib/iomgr/combiner.h" +#include "src/core/lib/iomgr/sockaddr.h" +#include "src/core/lib/iomgr/sockaddr_utils.h" +#include "src/core/lib/iomgr/timer.h" +#include "src/core/lib/slice/slice_hash_table.h" +#include "src/core/lib/slice/slice_internal.h" +#include "src/core/lib/slice/slice_string_helpers.h" +#include "src/core/lib/support/backoff.h" +#include "src/core/lib/support/string.h" +#include "src/core/lib/surface/call.h" +#include "src/core/lib/surface/channel.h" +#include "src/core/lib/surface/channel_init.h" +#include "src/core/lib/transport/static_metadata.h" + +#define GRPC_GRPCLB_MIN_CONNECT_TIMEOUT_SECONDS 20 +#define GRPC_GRPCLB_INITIAL_CONNECT_BACKOFF_SECONDS 1 +#define GRPC_GRPCLB_RECONNECT_BACKOFF_MULTIPLIER 1.6 +#define GRPC_GRPCLB_RECONNECT_MAX_BACKOFF_SECONDS 120 +#define GRPC_GRPCLB_RECONNECT_JITTER 0.2 + +grpc_tracer_flag grpc_lb_glb_trace = GRPC_TRACER_INITIALIZER(false, "glb"); + +/* add lb_token of selected subchannel (address) to the call's initial + * metadata */ +static grpc_error *initial_metadata_add_lb_token( + grpc_exec_ctx *exec_ctx, grpc_metadata_batch *initial_metadata, + grpc_linked_mdelem *lb_token_mdelem_storage, grpc_mdelem lb_token) { + GPR_ASSERT(lb_token_mdelem_storage != NULL); + GPR_ASSERT(!GRPC_MDISNULL(lb_token)); + return grpc_metadata_batch_add_tail(exec_ctx, initial_metadata, + lb_token_mdelem_storage, lb_token); +} + +static void destroy_client_stats(void *arg) { + grpc_grpclb_client_stats_unref(arg); +} + +typedef struct wrapped_rr_closure_arg { + /* the closure instance using this struct as argument */ + grpc_closure wrapper_closure; + + /* the original closure. Usually a on_complete/notify cb for pick() and ping() + * calls against the internal RR instance, respectively. */ + grpc_closure *wrapped_closure; + + /* the pick's initial metadata, kept in order to append the LB token for the + * pick */ + grpc_metadata_batch *initial_metadata; + + /* the picked target, used to determine which LB token to add to the pick's + * initial metadata */ + grpc_connected_subchannel **target; + + /* the context to be populated for the subchannel call */ + grpc_call_context_element *context; + + /* Stats for client-side load reporting. Note that this holds a + * reference, which must be either passed on via context or unreffed. */ + grpc_grpclb_client_stats *client_stats; + + /* the LB token associated with the pick */ + grpc_mdelem lb_token; + + /* storage for the lb token initial metadata mdelem */ + grpc_linked_mdelem *lb_token_mdelem_storage; + + /* The RR instance related to the closure */ + grpc_lb_policy *rr_policy; + + /* heap memory to be freed upon closure execution. */ + void *free_when_done; +} wrapped_rr_closure_arg; + +/* The \a on_complete closure passed as part of the pick requires keeping a + * reference to its associated round robin instance. We wrap this closure in + * order to unref the round robin instance upon its invocation */ +static void wrapped_rr_closure(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error) { + wrapped_rr_closure_arg *wc_arg = arg; + + GPR_ASSERT(wc_arg->wrapped_closure != NULL); + GRPC_CLOSURE_SCHED(exec_ctx, wc_arg->wrapped_closure, GRPC_ERROR_REF(error)); + + if (wc_arg->rr_policy != NULL) { + /* if *target is NULL, no pick has been made by the RR policy (eg, all + * addresses failed to connect). There won't be any user_data/token + * available */ + if (*wc_arg->target != NULL) { + if (!GRPC_MDISNULL(wc_arg->lb_token)) { + initial_metadata_add_lb_token(exec_ctx, wc_arg->initial_metadata, + wc_arg->lb_token_mdelem_storage, + GRPC_MDELEM_REF(wc_arg->lb_token)); + } else { + gpr_log(GPR_ERROR, + "No LB token for connected subchannel pick %p (from RR " + "instance %p).", + (void *)*wc_arg->target, (void *)wc_arg->rr_policy); + abort(); + } + // Pass on client stats via context. Passes ownership of the reference. + GPR_ASSERT(wc_arg->client_stats != NULL); + wc_arg->context[GRPC_GRPCLB_CLIENT_STATS].value = wc_arg->client_stats; + wc_arg->context[GRPC_GRPCLB_CLIENT_STATS].destroy = destroy_client_stats; + } else { + grpc_grpclb_client_stats_unref(wc_arg->client_stats); + } + if (GRPC_TRACER_ON(grpc_lb_glb_trace)) { + gpr_log(GPR_INFO, "Unreffing RR %p", (void *)wc_arg->rr_policy); + } + GRPC_LB_POLICY_UNREF(exec_ctx, wc_arg->rr_policy, "wrapped_rr_closure"); + } + GPR_ASSERT(wc_arg->free_when_done != NULL); + gpr_free(wc_arg->free_when_done); +} + +/* Linked list of pending pick requests. It stores all information needed to + * eventually call (Round Robin's) pick() on them. They mainly stay pending + * waiting for the RR policy to be created/updated. + * + * One particularity is the wrapping of the user-provided \a on_complete closure + * (in \a wrapped_on_complete and \a wrapped_on_complete_arg). This is needed in + * order to correctly unref the RR policy instance upon completion of the pick. + * See \a wrapped_rr_closure for details. */ +typedef struct pending_pick { + struct pending_pick *next; + + /* original pick()'s arguments */ + grpc_lb_policy_pick_args pick_args; + + /* output argument where to store the pick()ed connected subchannel, or NULL + * upon error. */ + grpc_connected_subchannel **target; + + /* args for wrapped_on_complete */ + wrapped_rr_closure_arg wrapped_on_complete_arg; +} pending_pick; + +static void add_pending_pick(pending_pick **root, + const grpc_lb_policy_pick_args *pick_args, + grpc_connected_subchannel **target, + grpc_call_context_element *context, + grpc_closure *on_complete) { + pending_pick *pp = gpr_zalloc(sizeof(*pp)); + pp->next = *root; + pp->pick_args = *pick_args; + pp->target = target; + pp->wrapped_on_complete_arg.wrapped_closure = on_complete; + pp->wrapped_on_complete_arg.target = target; + pp->wrapped_on_complete_arg.context = context; + pp->wrapped_on_complete_arg.initial_metadata = pick_args->initial_metadata; + pp->wrapped_on_complete_arg.lb_token_mdelem_storage = + pick_args->lb_token_mdelem_storage; + pp->wrapped_on_complete_arg.free_when_done = pp; + GRPC_CLOSURE_INIT(&pp->wrapped_on_complete_arg.wrapper_closure, + wrapped_rr_closure, &pp->wrapped_on_complete_arg, + grpc_schedule_on_exec_ctx); + *root = pp; +} + +/* Same as the \a pending_pick struct but for ping operations */ +typedef struct pending_ping { + struct pending_ping *next; + + /* args for wrapped_notify */ + wrapped_rr_closure_arg wrapped_notify_arg; +} pending_ping; + +static void add_pending_ping(pending_ping **root, grpc_closure *notify) { + pending_ping *pping = gpr_zalloc(sizeof(*pping)); + pping->wrapped_notify_arg.wrapped_closure = notify; + pping->wrapped_notify_arg.free_when_done = pping; + pping->next = *root; + GRPC_CLOSURE_INIT(&pping->wrapped_notify_arg.wrapper_closure, + wrapped_rr_closure, &pping->wrapped_notify_arg, + grpc_schedule_on_exec_ctx); + *root = pping; +} + +/* + * glb_lb_policy + */ +typedef struct rr_connectivity_data rr_connectivity_data; +static const grpc_lb_policy_vtable glb_lb_policy_vtable; +typedef struct glb_lb_policy { + /** base policy: must be first */ + grpc_lb_policy base; + + /** who the client is trying to communicate with */ + const char *server_name; + grpc_client_channel_factory *cc_factory; + grpc_channel_args *args; + + /** timeout in milliseconds for the LB call. 0 means no deadline. */ + int lb_call_timeout_ms; + + /** for communicating with the LB server */ + grpc_channel *lb_channel; + + /** response generator to inject address updates into \a lb_channel */ + grpc_fake_resolver_response_generator *response_generator; + + /** the RR policy to use of the backend servers returned by the LB server */ + grpc_lb_policy *rr_policy; + + bool started_picking; + + /** our connectivity state tracker */ + grpc_connectivity_state_tracker state_tracker; + + /** connectivity state of the LB channel */ + grpc_connectivity_state lb_channel_connectivity; + + /** stores the deserialized response from the LB. May be NULL until one such + * response has arrived. */ + grpc_grpclb_serverlist *serverlist; + + /** Index into serverlist for next pick. + * If the server at this index is a drop, we return a drop. + * Otherwise, we delegate to the RR policy. */ + size_t serverlist_index; + + /** list of picks that are waiting on RR's policy connectivity */ + pending_pick *pending_picks; + + /** list of pings that are waiting on RR's policy connectivity */ + pending_ping *pending_pings; + + bool shutting_down; + + /** are we currently updating lb_call? */ + bool updating_lb_call; + + /** are we currently updating lb_channel? */ + bool updating_lb_channel; + + /** are we already watching the LB channel's connectivity? */ + bool watching_lb_channel; + + /** is \a lb_call_retry_timer active? */ + bool retry_timer_active; + + /** called upon changes to the LB channel's connectivity. */ + grpc_closure lb_channel_on_connectivity_changed; + + /** args from the latest update received while already updating, or NULL */ + grpc_lb_policy_args *pending_update_args; + + /************************************************************/ + /* client data associated with the LB server communication */ + /************************************************************/ + /* Finished sending initial request. */ + grpc_closure lb_on_sent_initial_request; + + /* Status from the LB server has been received. This signals the end of the LB + * call. */ + grpc_closure lb_on_server_status_received; + + /* A response from the LB server has been received. Process it */ + grpc_closure lb_on_response_received; + + /* LB call retry timer callback. */ + grpc_closure lb_on_call_retry; + + grpc_call *lb_call; /* streaming call to the LB server, */ + + grpc_metadata_array lb_initial_metadata_recv; /* initial MD from LB server */ + grpc_metadata_array + lb_trailing_metadata_recv; /* trailing MD from LB server */ + + /* what's being sent to the LB server. Note that its value may vary if the LB + * server indicates a redirect. */ + grpc_byte_buffer *lb_request_payload; + + /* response the LB server, if any. Processed in lb_on_response_received() */ + grpc_byte_buffer *lb_response_payload; + + /* call status code and details, set in lb_on_server_status_received() */ + grpc_status_code lb_call_status; + grpc_slice lb_call_status_details; + + /** LB call retry backoff state */ + gpr_backoff lb_call_backoff_state; + + /** LB call retry timer */ + grpc_timer lb_call_retry_timer; + + bool initial_request_sent; + bool seen_initial_response; + + /* Stats for client-side load reporting. Should be unreffed and + * recreated whenever lb_call is replaced. */ + grpc_grpclb_client_stats *client_stats; + /* Interval and timer for next client load report. */ + gpr_timespec client_stats_report_interval; + grpc_timer client_load_report_timer; + bool client_load_report_timer_pending; + bool last_client_load_report_counters_were_zero; + /* Closure used for either the load report timer or the callback for + * completion of sending the load report. */ + grpc_closure client_load_report_closure; + /* Client load report message payload. */ + grpc_byte_buffer *client_load_report_payload; +} glb_lb_policy; + +/* Keeps track and reacts to changes in connectivity of the RR instance */ +struct rr_connectivity_data { + grpc_closure on_change; + grpc_connectivity_state state; + glb_lb_policy *glb_policy; +}; + +static bool is_server_valid(const grpc_grpclb_server *server, size_t idx, + bool log) { + if (server->drop) return false; + const grpc_grpclb_ip_address *ip = &server->ip_address; + if (server->port >> 16 != 0) { + if (log) { + gpr_log(GPR_ERROR, + "Invalid port '%d' at index %lu of serverlist. Ignoring.", + server->port, (unsigned long)idx); + } + return false; + } + if (ip->size != 4 && ip->size != 16) { + if (log) { + gpr_log(GPR_ERROR, + "Expected IP to be 4 or 16 bytes, got %d at index %lu of " + "serverlist. Ignoring", + ip->size, (unsigned long)idx); + } + return false; + } + return true; +} + +/* vtable for LB tokens in grpc_lb_addresses. */ +static void *lb_token_copy(void *token) { + return token == NULL + ? NULL + : (void *)GRPC_MDELEM_REF((grpc_mdelem){(uintptr_t)token}).payload; +} +static void lb_token_destroy(grpc_exec_ctx *exec_ctx, void *token) { + if (token != NULL) { + GRPC_MDELEM_UNREF(exec_ctx, (grpc_mdelem){(uintptr_t)token}); + } +} +static int lb_token_cmp(void *token1, void *token2) { + if (token1 > token2) return 1; + if (token1 < token2) return -1; + return 0; +} +static const grpc_lb_user_data_vtable lb_token_vtable = { + lb_token_copy, lb_token_destroy, lb_token_cmp}; + +static void parse_server(const grpc_grpclb_server *server, + grpc_resolved_address *addr) { + memset(addr, 0, sizeof(*addr)); + if (server->drop) return; + const uint16_t netorder_port = htons((uint16_t)server->port); + /* the addresses are given in binary format (a in(6)_addr struct) in + * server->ip_address.bytes. */ + const grpc_grpclb_ip_address *ip = &server->ip_address; + if (ip->size == 4) { + addr->len = sizeof(struct sockaddr_in); + struct sockaddr_in *addr4 = (struct sockaddr_in *)&addr->addr; + addr4->sin_family = AF_INET; + memcpy(&addr4->sin_addr, ip->bytes, ip->size); + addr4->sin_port = netorder_port; + } else if (ip->size == 16) { + addr->len = sizeof(struct sockaddr_in6); + struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&addr->addr; + addr6->sin6_family = AF_INET6; + memcpy(&addr6->sin6_addr, ip->bytes, ip->size); + addr6->sin6_port = netorder_port; + } +} + +/* Returns addresses extracted from \a serverlist. */ +static grpc_lb_addresses *process_serverlist_locked( + grpc_exec_ctx *exec_ctx, const grpc_grpclb_serverlist *serverlist) { + size_t num_valid = 0; + /* first pass: count how many are valid in order to allocate the necessary + * memory in a single block */ + for (size_t i = 0; i < serverlist->num_servers; ++i) { + if (is_server_valid(serverlist->servers[i], i, true)) ++num_valid; + } + grpc_lb_addresses *lb_addresses = + grpc_lb_addresses_create(num_valid, &lb_token_vtable); + /* second pass: actually populate the addresses and LB tokens (aka user data + * to the outside world) to be read by the RR policy during its creation. + * Given that the validity tests are very cheap, they are performed again + * instead of marking the valid ones during the first pass, as this would + * incurr in an allocation due to the arbitrary number of server */ + size_t addr_idx = 0; + for (size_t sl_idx = 0; sl_idx < serverlist->num_servers; ++sl_idx) { + const grpc_grpclb_server *server = serverlist->servers[sl_idx]; + if (!is_server_valid(serverlist->servers[sl_idx], sl_idx, false)) continue; + GPR_ASSERT(addr_idx < num_valid); + /* address processing */ + grpc_resolved_address addr; + parse_server(server, &addr); + /* lb token processing */ + void *user_data; + if (server->has_load_balance_token) { + const size_t lb_token_max_length = + GPR_ARRAY_SIZE(server->load_balance_token); + const size_t lb_token_length = + 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); + user_data = (void *)grpc_mdelem_from_slices(exec_ctx, GRPC_MDSTR_LB_TOKEN, + lb_token_mdstr) + .payload; + } else { + char *uri = grpc_sockaddr_to_uri(&addr); + gpr_log(GPR_INFO, + "Missing LB token for backend address '%s'. The empty token will " + "be used instead", + uri); + gpr_free(uri); + user_data = (void *)GRPC_MDELEM_LB_TOKEN_EMPTY.payload; + } + + grpc_lb_addresses_set_address(lb_addresses, addr_idx, &addr.addr, addr.len, + false /* is_balancer */, + NULL /* balancer_name */, user_data); + ++addr_idx; + } + GPR_ASSERT(addr_idx == num_valid); + return lb_addresses; +} + +static void update_lb_connectivity_status_locked( + grpc_exec_ctx *exec_ctx, glb_lb_policy *glb_policy, + grpc_connectivity_state rr_state, grpc_error *rr_state_error) { + const grpc_connectivity_state curr_glb_state = + grpc_connectivity_state_check(&glb_policy->state_tracker); + + /* The new connectivity status is a function of the previous one and the new + * input coming from the status of the RR policy. + * + * current state (grpclb's) + * | + * v || I | C | R | TF | SD | <- new state (RR's) + * ===++====+=====+=====+======+======+ + * I || I | C | R | [I] | [I] | + * ---++----+-----+-----+------+------+ + * C || I | C | R | [C] | [C] | + * ---++----+-----+-----+------+------+ + * R || I | C | R | [R] | [R] | + * ---++----+-----+-----+------+------+ + * TF || I | C | R | [TF] | [TF] | + * ---++----+-----+-----+------+------+ + * SD || NA | NA | NA | NA | NA | (*) + * ---++----+-----+-----+------+------+ + * + * A [STATE] indicates that the old RR policy is kept. In those cases, STATE + * is the current state of grpclb, which is left untouched. + * + * In summary, if the new state is TRANSIENT_FAILURE or SHUTDOWN, stick to + * the previous RR instance. + * + * Note that the status is never updated to SHUTDOWN as a result of calling + * this function. Only glb_shutdown() has the power to set that state. + * + * (*) This function mustn't be called during shutting down. */ + GPR_ASSERT(curr_glb_state != GRPC_CHANNEL_SHUTDOWN); + + switch (rr_state) { + case GRPC_CHANNEL_TRANSIENT_FAILURE: + case GRPC_CHANNEL_SHUTDOWN: + GPR_ASSERT(rr_state_error != GRPC_ERROR_NONE); + break; + case GRPC_CHANNEL_INIT: + case GRPC_CHANNEL_IDLE: + case GRPC_CHANNEL_CONNECTING: + case GRPC_CHANNEL_READY: + GPR_ASSERT(rr_state_error == GRPC_ERROR_NONE); + } + + if (GRPC_TRACER_ON(grpc_lb_glb_trace)) { + gpr_log( + GPR_INFO, "Setting grpclb's state to %s from new RR policy %p state.", + grpc_connectivity_state_name(rr_state), (void *)glb_policy->rr_policy); + } + grpc_connectivity_state_set(exec_ctx, &glb_policy->state_tracker, rr_state, + rr_state_error, + "update_lb_connectivity_status_locked"); +} + +/* Perform a pick over \a glb_policy->rr_policy. Given that a pick can return + * immediately (ignoring its completion callback), we need to perform the + * cleanups this callback would otherwise be resposible for. + * If \a force_async is true, then we will manually schedule the + * completion callback even if the pick is available immediately. */ +static bool pick_from_internal_rr_locked( + grpc_exec_ctx *exec_ctx, glb_lb_policy *glb_policy, + const grpc_lb_policy_pick_args *pick_args, bool force_async, + grpc_connected_subchannel **target, wrapped_rr_closure_arg *wc_arg) { + // Look at the index into the serverlist to see if we should drop this call. + grpc_grpclb_server *server = + glb_policy->serverlist->servers[glb_policy->serverlist_index++]; + if (glb_policy->serverlist_index == glb_policy->serverlist->num_servers) { + glb_policy->serverlist_index = 0; // Wrap-around. + } + if (server->drop) { + // Not using the RR policy, so unref it. + if (GRPC_TRACER_ON(grpc_lb_glb_trace)) { + gpr_log(GPR_INFO, "Unreffing RR for drop (0x%" PRIxPTR ")", + (intptr_t)wc_arg->rr_policy); + } + GRPC_LB_POLICY_UNREF(exec_ctx, wc_arg->rr_policy, "glb_pick_sync"); + // Update client load reporting stats to indicate the number of + // dropped calls. Note that we have to do this here instead of in + // the client_load_reporting filter, because we do not create a + // subchannel call (and therefore no client_load_reporting filter) + // for dropped calls. + grpc_grpclb_client_stats_add_call_dropped_locked(server->load_balance_token, + wc_arg->client_stats); + grpc_grpclb_client_stats_unref(wc_arg->client_stats); + if (force_async) { + GPR_ASSERT(wc_arg->wrapped_closure != NULL); + GRPC_CLOSURE_SCHED(exec_ctx, wc_arg->wrapped_closure, GRPC_ERROR_NONE); + gpr_free(wc_arg->free_when_done); + return false; + } + gpr_free(wc_arg->free_when_done); + return true; + } + // Pick via the RR policy. + const bool pick_done = grpc_lb_policy_pick_locked( + exec_ctx, wc_arg->rr_policy, pick_args, target, wc_arg->context, + (void **)&wc_arg->lb_token, &wc_arg->wrapper_closure); + if (pick_done) { + /* synchronous grpc_lb_policy_pick call. Unref the RR policy. */ + if (GRPC_TRACER_ON(grpc_lb_glb_trace)) { + gpr_log(GPR_INFO, "Unreffing RR (0x%" PRIxPTR ")", + (intptr_t)wc_arg->rr_policy); + } + GRPC_LB_POLICY_UNREF(exec_ctx, wc_arg->rr_policy, "glb_pick_sync"); + /* add the load reporting initial metadata */ + initial_metadata_add_lb_token(exec_ctx, pick_args->initial_metadata, + pick_args->lb_token_mdelem_storage, + GRPC_MDELEM_REF(wc_arg->lb_token)); + // Pass on client stats via context. Passes ownership of the reference. + GPR_ASSERT(wc_arg->client_stats != NULL); + wc_arg->context[GRPC_GRPCLB_CLIENT_STATS].value = wc_arg->client_stats; + wc_arg->context[GRPC_GRPCLB_CLIENT_STATS].destroy = destroy_client_stats; + if (force_async) { + GPR_ASSERT(wc_arg->wrapped_closure != NULL); + GRPC_CLOSURE_SCHED(exec_ctx, wc_arg->wrapped_closure, GRPC_ERROR_NONE); + gpr_free(wc_arg->free_when_done); + return false; + } + gpr_free(wc_arg->free_when_done); + } + /* else, the pending pick will be registered and taken care of by the + * pending pick list inside the RR policy (glb_policy->rr_policy). + * Eventually, wrapped_on_complete will be called, which will -among other + * things- add the LB token to the call's initial metadata */ + return pick_done; +} + +static grpc_lb_policy_args *lb_policy_args_create(grpc_exec_ctx *exec_ctx, + glb_lb_policy *glb_policy) { + grpc_lb_addresses *addresses = + process_serverlist_locked(exec_ctx, glb_policy->serverlist); + GPR_ASSERT(addresses != NULL); + grpc_lb_policy_args *args = gpr_zalloc(sizeof(*args)); + args->client_channel_factory = glb_policy->cc_factory; + args->combiner = glb_policy->base.combiner; + // Replace the LB addresses in the channel args that we pass down to + // the subchannel. + static const char *keys_to_remove[] = {GRPC_ARG_LB_ADDRESSES}; + const grpc_arg arg = grpc_lb_addresses_create_channel_arg(addresses); + args->args = grpc_channel_args_copy_and_add_and_remove( + glb_policy->args, keys_to_remove, GPR_ARRAY_SIZE(keys_to_remove), &arg, + 1); + grpc_lb_addresses_destroy(exec_ctx, addresses); + return args; +} + +static void lb_policy_args_destroy(grpc_exec_ctx *exec_ctx, + grpc_lb_policy_args *args) { + grpc_channel_args_destroy(exec_ctx, args->args); + gpr_free(args); +} + +static void glb_rr_connectivity_changed_locked(grpc_exec_ctx *exec_ctx, + void *arg, grpc_error *error); +static void create_rr_locked(grpc_exec_ctx *exec_ctx, glb_lb_policy *glb_policy, + grpc_lb_policy_args *args) { + GPR_ASSERT(glb_policy->rr_policy == NULL); + + grpc_lb_policy *new_rr_policy = + grpc_lb_policy_create(exec_ctx, "round_robin", args); + if (new_rr_policy == NULL) { + gpr_log(GPR_ERROR, + "Failure creating a RoundRobin policy for serverlist update with " + "%lu entries. The previous RR instance (%p), if any, will continue " + "to be used. Future updates from the LB will attempt to create new " + "instances.", + (unsigned long)glb_policy->serverlist->num_servers, + (void *)glb_policy->rr_policy); + return; + } + glb_policy->rr_policy = new_rr_policy; + grpc_error *rr_state_error = NULL; + const grpc_connectivity_state rr_state = + grpc_lb_policy_check_connectivity_locked(exec_ctx, glb_policy->rr_policy, + &rr_state_error); + /* Connectivity state is a function of the RR policy updated/created */ + update_lb_connectivity_status_locked(exec_ctx, glb_policy, rr_state, + rr_state_error); + /* Add the gRPC LB's interested_parties pollset_set to that of the newly + * created RR policy. This will make the RR policy progress upon activity on + * gRPC LB, which in turn is tied to the application's call */ + grpc_pollset_set_add_pollset_set(exec_ctx, + glb_policy->rr_policy->interested_parties, + glb_policy->base.interested_parties); + + /* Allocate the data for the tracking of the new RR policy's connectivity. + * It'll be deallocated in glb_rr_connectivity_changed() */ + rr_connectivity_data *rr_connectivity = + gpr_zalloc(sizeof(rr_connectivity_data)); + GRPC_CLOSURE_INIT(&rr_connectivity->on_change, + glb_rr_connectivity_changed_locked, rr_connectivity, + grpc_combiner_scheduler(glb_policy->base.combiner)); + rr_connectivity->glb_policy = glb_policy; + rr_connectivity->state = rr_state; + + /* Subscribe to changes to the connectivity of the new RR */ + GRPC_LB_POLICY_WEAK_REF(&glb_policy->base, "glb_rr_connectivity_cb"); + grpc_lb_policy_notify_on_state_change_locked(exec_ctx, glb_policy->rr_policy, + &rr_connectivity->state, + &rr_connectivity->on_change); + grpc_lb_policy_exit_idle_locked(exec_ctx, glb_policy->rr_policy); + + /* Update picks and pings in wait */ + pending_pick *pp; + while ((pp = glb_policy->pending_picks)) { + glb_policy->pending_picks = pp->next; + GRPC_LB_POLICY_REF(glb_policy->rr_policy, "rr_handover_pending_pick"); + pp->wrapped_on_complete_arg.rr_policy = glb_policy->rr_policy; + pp->wrapped_on_complete_arg.client_stats = + grpc_grpclb_client_stats_ref(glb_policy->client_stats); + if (GRPC_TRACER_ON(grpc_lb_glb_trace)) { + gpr_log(GPR_INFO, "Pending pick about to (async) PICK from %p", + (void *)glb_policy->rr_policy); + } + pick_from_internal_rr_locked(exec_ctx, glb_policy, &pp->pick_args, + true /* force_async */, pp->target, + &pp->wrapped_on_complete_arg); + } + + pending_ping *pping; + while ((pping = glb_policy->pending_pings)) { + glb_policy->pending_pings = pping->next; + GRPC_LB_POLICY_REF(glb_policy->rr_policy, "rr_handover_pending_ping"); + pping->wrapped_notify_arg.rr_policy = glb_policy->rr_policy; + if (GRPC_TRACER_ON(grpc_lb_glb_trace)) { + gpr_log(GPR_INFO, "Pending ping about to PING from 0x%" PRIxPTR "", + (intptr_t)glb_policy->rr_policy); + } + grpc_lb_policy_ping_one_locked(exec_ctx, glb_policy->rr_policy, + &pping->wrapped_notify_arg.wrapper_closure); + } +} + +/* glb_policy->rr_policy may be NULL (initial handover) */ +static void rr_handover_locked(grpc_exec_ctx *exec_ctx, + glb_lb_policy *glb_policy) { + GPR_ASSERT(glb_policy->serverlist != NULL && + glb_policy->serverlist->num_servers > 0); + if (glb_policy->shutting_down) return; + grpc_lb_policy_args *args = lb_policy_args_create(exec_ctx, glb_policy); + GPR_ASSERT(args != NULL); + if (glb_policy->rr_policy != NULL) { + if (GRPC_TRACER_ON(grpc_lb_glb_trace)) { + gpr_log(GPR_DEBUG, "Updating Round Robin policy (%p)", + (void *)glb_policy->rr_policy); + } + grpc_lb_policy_update_locked(exec_ctx, glb_policy->rr_policy, args); + } else { + create_rr_locked(exec_ctx, glb_policy, args); + if (GRPC_TRACER_ON(grpc_lb_glb_trace)) { + gpr_log(GPR_DEBUG, "Created new Round Robin policy (%p)", + (void *)glb_policy->rr_policy); + } + } + lb_policy_args_destroy(exec_ctx, args); +} + +static void glb_rr_connectivity_changed_locked(grpc_exec_ctx *exec_ctx, + void *arg, grpc_error *error) { + rr_connectivity_data *rr_connectivity = arg; + glb_lb_policy *glb_policy = rr_connectivity->glb_policy; + if (glb_policy->shutting_down) { + GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &glb_policy->base, + "glb_rr_connectivity_cb"); + gpr_free(rr_connectivity); + return; + } + if (rr_connectivity->state == GRPC_CHANNEL_SHUTDOWN) { + /* An RR policy that has transitioned into the SHUTDOWN connectivity state + * should not be considered for picks or updates: the SHUTDOWN state is a + * sink, policies can't transition back from it. .*/ + GRPC_LB_POLICY_UNREF(exec_ctx, glb_policy->rr_policy, + "rr_connectivity_shutdown"); + glb_policy->rr_policy = NULL; + GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &glb_policy->base, + "glb_rr_connectivity_cb"); + gpr_free(rr_connectivity); + return; + } + /* rr state != SHUTDOWN && !glb_policy->shutting down: biz as usual */ + update_lb_connectivity_status_locked( + exec_ctx, glb_policy, rr_connectivity->state, GRPC_ERROR_REF(error)); + /* Resubscribe. Reuse the "glb_rr_connectivity_cb" weak ref. */ + grpc_lb_policy_notify_on_state_change_locked(exec_ctx, glb_policy->rr_policy, + &rr_connectivity->state, + &rr_connectivity->on_change); +} + +static void destroy_balancer_name(grpc_exec_ctx *exec_ctx, + void *balancer_name) { + gpr_free(balancer_name); +} + +static grpc_slice_hash_table_entry targets_info_entry_create( + const char *address, const char *balancer_name) { + grpc_slice_hash_table_entry entry; + entry.key = grpc_slice_from_copied_string(address); + entry.value = gpr_strdup(balancer_name); + return entry; +} + +static int balancer_name_cmp_fn(void *a, void *b) { + const char *a_str = a; + const char *b_str = b; + return strcmp(a_str, b_str); +} + +/* Returns the channel args for the LB channel, used to create a bidirectional + * stream for the reception of load balancing updates. + * + * Inputs: + * - \a addresses: corresponding to the balancers. + * - \a response_generator: in order to propagate updates from the resolver + * above the grpclb policy. + * - \a args: other args inherited from the grpclb policy. */ +static grpc_channel_args *build_lb_channel_args( + grpc_exec_ctx *exec_ctx, const grpc_lb_addresses *addresses, + grpc_fake_resolver_response_generator *response_generator, + const grpc_channel_args *args) { + size_t num_grpclb_addrs = 0; + for (size_t i = 0; i < addresses->num_addresses; ++i) { + if (addresses->addresses[i].is_balancer) ++num_grpclb_addrs; + } + /* All input addresses come from a resolver that claims they are LB services. + * It's the resolver's responsibility to make sure this policy is only + * instantiated and used in that case. Otherwise, something has gone wrong. */ + GPR_ASSERT(num_grpclb_addrs > 0); + grpc_lb_addresses *lb_addresses = + grpc_lb_addresses_create(num_grpclb_addrs, NULL); + grpc_slice_hash_table_entry *targets_info_entries = + gpr_zalloc(sizeof(*targets_info_entries) * num_grpclb_addrs); + + size_t lb_addresses_idx = 0; + for (size_t i = 0; i < addresses->num_addresses; ++i) { + if (!addresses->addresses[i].is_balancer) continue; + if (addresses->addresses[i].user_data != NULL) { + gpr_log(GPR_ERROR, + "This LB policy doesn't support user data. It will be ignored"); + } + char *addr_str; + GPR_ASSERT(grpc_sockaddr_to_string( + &addr_str, &addresses->addresses[i].address, true) > 0); + targets_info_entries[lb_addresses_idx] = targets_info_entry_create( + addr_str, addresses->addresses[i].balancer_name); + gpr_free(addr_str); + + grpc_lb_addresses_set_address( + lb_addresses, lb_addresses_idx++, addresses->addresses[i].address.addr, + addresses->addresses[i].address.len, false /* is balancer */, + addresses->addresses[i].balancer_name, NULL /* user data */); + } + GPR_ASSERT(num_grpclb_addrs == lb_addresses_idx); + grpc_slice_hash_table *targets_info = + grpc_slice_hash_table_create(num_grpclb_addrs, targets_info_entries, + destroy_balancer_name, balancer_name_cmp_fn); + gpr_free(targets_info_entries); + + grpc_channel_args *lb_channel_args = + grpc_lb_policy_grpclb_build_lb_channel_args(exec_ctx, targets_info, + response_generator, args); + + grpc_arg lb_channel_addresses_arg = + grpc_lb_addresses_create_channel_arg(lb_addresses); + + grpc_channel_args *result = grpc_channel_args_copy_and_add( + lb_channel_args, &lb_channel_addresses_arg, 1); + grpc_slice_hash_table_unref(exec_ctx, targets_info); + grpc_channel_args_destroy(exec_ctx, lb_channel_args); + grpc_lb_addresses_destroy(exec_ctx, lb_addresses); + return result; +} + +static void glb_lb_channel_on_connectivity_changed_cb(grpc_exec_ctx *exec_ctx, + void *arg, + grpc_error *error); +static grpc_lb_policy *glb_create(grpc_exec_ctx *exec_ctx, + grpc_lb_policy_factory *factory, + grpc_lb_policy_args *args) { + /* Count the number of gRPC-LB addresses. There must be at least one. + * TODO(roth): For now, we ignore non-balancer addresses, but in the + * future, we may change the behavior such that we fall back to using + * the non-balancer addresses if we cannot reach any balancers. In the + * fallback case, we should use the LB policy indicated by + * GRPC_ARG_LB_POLICY_NAME (although if that specifies grpclb or is + * unset, we should default to pick_first). */ + const grpc_arg *arg = + grpc_channel_args_find(args->args, GRPC_ARG_LB_ADDRESSES); + if (arg == NULL || arg->type != GRPC_ARG_POINTER) { + return NULL; + } + grpc_lb_addresses *addresses = arg->value.pointer.p; + size_t num_grpclb_addrs = 0; + for (size_t i = 0; i < addresses->num_addresses; ++i) { + if (addresses->addresses[i].is_balancer) ++num_grpclb_addrs; + } + if (num_grpclb_addrs == 0) return NULL; + + glb_lb_policy *glb_policy = gpr_zalloc(sizeof(*glb_policy)); + + /* Get server name. */ + arg = grpc_channel_args_find(args->args, GRPC_ARG_SERVER_URI); + GPR_ASSERT(arg != NULL); + GPR_ASSERT(arg->type == GRPC_ARG_STRING); + grpc_uri *uri = grpc_uri_parse(exec_ctx, arg->value.string, true); + GPR_ASSERT(uri->path[0] != '\0'); + glb_policy->server_name = + gpr_strdup(uri->path[0] == '/' ? uri->path + 1 : uri->path); + if (GRPC_TRACER_ON(grpc_lb_glb_trace)) { + gpr_log(GPR_INFO, "Will use '%s' as the server name for LB request.", + glb_policy->server_name); + } + grpc_uri_destroy(uri); + + glb_policy->cc_factory = args->client_channel_factory; + GPR_ASSERT(glb_policy->cc_factory != NULL); + + arg = grpc_channel_args_find(args->args, GRPC_ARG_GRPCLB_CALL_TIMEOUT_MS); + glb_policy->lb_call_timeout_ms = + grpc_channel_arg_get_integer(arg, (grpc_integer_options){0, 0, INT_MAX}); + + // Make sure that GRPC_ARG_LB_POLICY_NAME is set in channel args, + // since we use this to trigger the client_load_reporting filter. + grpc_arg new_arg = + grpc_channel_arg_string_create(GRPC_ARG_LB_POLICY_NAME, "grpclb"); + static const char *args_to_remove[] = {GRPC_ARG_LB_POLICY_NAME}; + glb_policy->args = grpc_channel_args_copy_and_add_and_remove( + args->args, args_to_remove, GPR_ARRAY_SIZE(args_to_remove), &new_arg, 1); + + /* Create a client channel over them to communicate with a LB service */ + glb_policy->response_generator = + grpc_fake_resolver_response_generator_create(); + grpc_channel_args *lb_channel_args = build_lb_channel_args( + exec_ctx, addresses, glb_policy->response_generator, args->args); + char *uri_str; + gpr_asprintf(&uri_str, "fake:///%s", glb_policy->server_name); + glb_policy->lb_channel = grpc_lb_policy_grpclb_create_lb_channel( + exec_ctx, uri_str, args->client_channel_factory, lb_channel_args); + + /* Propagate initial resolution */ + grpc_fake_resolver_response_generator_set_response( + exec_ctx, glb_policy->response_generator, lb_channel_args); + grpc_channel_args_destroy(exec_ctx, lb_channel_args); + gpr_free(uri_str); + if (glb_policy->lb_channel == NULL) { + gpr_free((void *)glb_policy->server_name); + grpc_channel_args_destroy(exec_ctx, glb_policy->args); + gpr_free(glb_policy); + return NULL; + } + GRPC_CLOSURE_INIT(&glb_policy->lb_channel_on_connectivity_changed, + glb_lb_channel_on_connectivity_changed_cb, glb_policy, + grpc_combiner_scheduler(args->combiner)); + grpc_lb_policy_init(&glb_policy->base, &glb_lb_policy_vtable, args->combiner); + grpc_connectivity_state_init(&glb_policy->state_tracker, GRPC_CHANNEL_IDLE, + "grpclb"); + return &glb_policy->base; +} + +static void glb_destroy(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) { + glb_lb_policy *glb_policy = (glb_lb_policy *)pol; + GPR_ASSERT(glb_policy->pending_picks == NULL); + GPR_ASSERT(glb_policy->pending_pings == NULL); + gpr_free((void *)glb_policy->server_name); + grpc_channel_args_destroy(exec_ctx, glb_policy->args); + if (glb_policy->client_stats != NULL) { + grpc_grpclb_client_stats_unref(glb_policy->client_stats); + } + grpc_connectivity_state_destroy(exec_ctx, &glb_policy->state_tracker); + if (glb_policy->serverlist != NULL) { + grpc_grpclb_destroy_serverlist(glb_policy->serverlist); + } + grpc_fake_resolver_response_generator_unref(glb_policy->response_generator); + if (glb_policy->pending_update_args != NULL) { + grpc_channel_args_destroy(exec_ctx, glb_policy->pending_update_args->args); + gpr_free(glb_policy->pending_update_args); + } + gpr_free(glb_policy); +} + +static void glb_shutdown_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) { + glb_lb_policy *glb_policy = (glb_lb_policy *)pol; + glb_policy->shutting_down = true; + + /* We need a copy of the lb_call pointer because we can't cancell the call + * while holding glb_policy->mu: lb_on_server_status_received, invoked due to + * the cancel, needs to acquire that same lock */ + grpc_call *lb_call = glb_policy->lb_call; + + /* glb_policy->lb_call and this local lb_call must be consistent at this point + * because glb_policy->lb_call is only assigned in lb_call_init_locked as part + * of query_for_backends_locked, which can only be invoked while + * glb_policy->shutting_down is false. */ + if (lb_call != NULL) { + grpc_call_cancel(lb_call, NULL); + /* lb_on_server_status_received will pick up the cancel and clean up */ + } + if (glb_policy->retry_timer_active) { + grpc_timer_cancel(exec_ctx, &glb_policy->lb_call_retry_timer); + glb_policy->retry_timer_active = false; + } + + pending_pick *pp = glb_policy->pending_picks; + glb_policy->pending_picks = NULL; + pending_ping *pping = glb_policy->pending_pings; + glb_policy->pending_pings = NULL; + if (glb_policy->rr_policy != NULL) { + GRPC_LB_POLICY_UNREF(exec_ctx, glb_policy->rr_policy, "glb_shutdown"); + } + // We destroy the LB channel here because + // glb_lb_channel_on_connectivity_changed_cb needs a valid glb_policy + // instance. Destroying the lb channel in glb_destroy would likely result in + // a callback invocation without a valid glb_policy arg. + if (glb_policy->lb_channel != NULL) { + grpc_channel_destroy(glb_policy->lb_channel); + glb_policy->lb_channel = NULL; + } + grpc_connectivity_state_set( + exec_ctx, &glb_policy->state_tracker, GRPC_CHANNEL_SHUTDOWN, + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Channel Shutdown"), "glb_shutdown"); + + while (pp != NULL) { + pending_pick *next = pp->next; + *pp->target = NULL; + GRPC_CLOSURE_SCHED(exec_ctx, &pp->wrapped_on_complete_arg.wrapper_closure, + GRPC_ERROR_NONE); + pp = next; + } + + while (pping != NULL) { + pending_ping *next = pping->next; + GRPC_CLOSURE_SCHED(exec_ctx, &pping->wrapped_notify_arg.wrapper_closure, + GRPC_ERROR_NONE); + pping = next; + } +} + +// Cancel a specific pending pick. +// +// A grpclb pick progresses as follows: +// - If there's a Round Robin policy (glb_policy->rr_policy) available, it'll be +// handed over to the RR policy (in create_rr_locked()). From that point +// onwards, it'll be RR's responsibility. For cancellations, that implies the +// pick needs also be cancelled by the RR instance. +// - Otherwise, without an RR instance, picks stay pending at this policy's +// level (grpclb), inside the glb_policy->pending_picks list. To cancel these, +// we invoke the completion closure and set *target to NULL right here. +static void glb_cancel_pick_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, + grpc_connected_subchannel **target, + grpc_error *error) { + glb_lb_policy *glb_policy = (glb_lb_policy *)pol; + pending_pick *pp = glb_policy->pending_picks; + glb_policy->pending_picks = NULL; + while (pp != NULL) { + pending_pick *next = pp->next; + if (pp->target == target) { + *target = NULL; + GRPC_CLOSURE_SCHED(exec_ctx, &pp->wrapped_on_complete_arg.wrapper_closure, + GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( + "Pick Cancelled", &error, 1)); + } else { + pp->next = glb_policy->pending_picks; + glb_policy->pending_picks = pp; + } + pp = next; + } + if (glb_policy->rr_policy != NULL) { + grpc_lb_policy_cancel_pick_locked(exec_ctx, glb_policy->rr_policy, target, + GRPC_ERROR_REF(error)); + } + GRPC_ERROR_UNREF(error); +} + +// Cancel all pending picks. +// +// A grpclb pick progresses as follows: +// - If there's a Round Robin policy (glb_policy->rr_policy) available, it'll be +// handed over to the RR policy (in create_rr_locked()). From that point +// onwards, it'll be RR's responsibility. For cancellations, that implies the +// pick needs also be cancelled by the RR instance. +// - Otherwise, without an RR instance, picks stay pending at this policy's +// level (grpclb), inside the glb_policy->pending_picks list. To cancel these, +// we invoke the completion closure and set *target to NULL right here. +static void glb_cancel_picks_locked(grpc_exec_ctx *exec_ctx, + grpc_lb_policy *pol, + uint32_t initial_metadata_flags_mask, + uint32_t initial_metadata_flags_eq, + grpc_error *error) { + glb_lb_policy *glb_policy = (glb_lb_policy *)pol; + pending_pick *pp = glb_policy->pending_picks; + glb_policy->pending_picks = NULL; + while (pp != NULL) { + pending_pick *next = pp->next; + if ((pp->pick_args.initial_metadata_flags & initial_metadata_flags_mask) == + initial_metadata_flags_eq) { + GRPC_CLOSURE_SCHED(exec_ctx, &pp->wrapped_on_complete_arg.wrapper_closure, + GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( + "Pick Cancelled", &error, 1)); + } else { + pp->next = glb_policy->pending_picks; + glb_policy->pending_picks = pp; + } + pp = next; + } + if (glb_policy->rr_policy != NULL) { + grpc_lb_policy_cancel_picks_locked( + exec_ctx, glb_policy->rr_policy, initial_metadata_flags_mask, + initial_metadata_flags_eq, GRPC_ERROR_REF(error)); + } + GRPC_ERROR_UNREF(error); +} + +static void query_for_backends_locked(grpc_exec_ctx *exec_ctx, + glb_lb_policy *glb_policy); +static void start_picking_locked(grpc_exec_ctx *exec_ctx, + glb_lb_policy *glb_policy) { + glb_policy->started_picking = true; + gpr_backoff_reset(&glb_policy->lb_call_backoff_state); + query_for_backends_locked(exec_ctx, glb_policy); +} + +static void glb_exit_idle_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) { + glb_lb_policy *glb_policy = (glb_lb_policy *)pol; + if (!glb_policy->started_picking) { + start_picking_locked(exec_ctx, glb_policy); + } +} + +static int glb_pick_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, + const grpc_lb_policy_pick_args *pick_args, + grpc_connected_subchannel **target, + grpc_call_context_element *context, void **user_data, + grpc_closure *on_complete) { + if (pick_args->lb_token_mdelem_storage == NULL) { + *target = NULL; + GRPC_CLOSURE_SCHED(exec_ctx, on_complete, + GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "No mdelem storage for the LB token. Load reporting " + "won't work without it. Failing")); + return 0; + } + + glb_lb_policy *glb_policy = (glb_lb_policy *)pol; + bool pick_done; + + if (glb_policy->rr_policy != NULL) { + if (GRPC_TRACER_ON(grpc_lb_glb_trace)) { + gpr_log(GPR_INFO, "grpclb %p about to PICK from RR %p", + (void *)glb_policy, (void *)glb_policy->rr_policy); + } + GRPC_LB_POLICY_REF(glb_policy->rr_policy, "glb_pick"); + + wrapped_rr_closure_arg *wc_arg = gpr_zalloc(sizeof(wrapped_rr_closure_arg)); + + GRPC_CLOSURE_INIT(&wc_arg->wrapper_closure, wrapped_rr_closure, wc_arg, + grpc_schedule_on_exec_ctx); + wc_arg->rr_policy = glb_policy->rr_policy; + wc_arg->target = target; + wc_arg->context = context; + GPR_ASSERT(glb_policy->client_stats != NULL); + wc_arg->client_stats = + grpc_grpclb_client_stats_ref(glb_policy->client_stats); + wc_arg->wrapped_closure = on_complete; + wc_arg->lb_token_mdelem_storage = pick_args->lb_token_mdelem_storage; + wc_arg->initial_metadata = pick_args->initial_metadata; + wc_arg->free_when_done = wc_arg; + pick_done = + pick_from_internal_rr_locked(exec_ctx, glb_policy, pick_args, + false /* force_async */, target, wc_arg); + } else { + if (GRPC_TRACER_ON(grpc_lb_glb_trace)) { + gpr_log(GPR_DEBUG, + "No RR policy in grpclb instance %p. Adding to grpclb's pending " + "picks", + (void *)(glb_policy)); + } + add_pending_pick(&glb_policy->pending_picks, pick_args, target, context, + on_complete); + + if (!glb_policy->started_picking) { + start_picking_locked(exec_ctx, glb_policy); + } + pick_done = false; + } + return pick_done; +} + +static grpc_connectivity_state glb_check_connectivity_locked( + grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, + grpc_error **connectivity_error) { + glb_lb_policy *glb_policy = (glb_lb_policy *)pol; + return grpc_connectivity_state_get(&glb_policy->state_tracker, + connectivity_error); +} + +static void glb_ping_one_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, + grpc_closure *closure) { + glb_lb_policy *glb_policy = (glb_lb_policy *)pol; + if (glb_policy->rr_policy) { + grpc_lb_policy_ping_one_locked(exec_ctx, glb_policy->rr_policy, closure); + } else { + add_pending_ping(&glb_policy->pending_pings, closure); + if (!glb_policy->started_picking) { + start_picking_locked(exec_ctx, glb_policy); + } + } +} + +static void glb_notify_on_state_change_locked(grpc_exec_ctx *exec_ctx, + grpc_lb_policy *pol, + grpc_connectivity_state *current, + grpc_closure *notify) { + glb_lb_policy *glb_policy = (glb_lb_policy *)pol; + grpc_connectivity_state_notify_on_state_change( + exec_ctx, &glb_policy->state_tracker, current, notify); +} + +static void send_client_load_report_locked(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error); + +static void schedule_next_client_load_report(grpc_exec_ctx *exec_ctx, + glb_lb_policy *glb_policy) { + const gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC); + const gpr_timespec next_client_load_report_time = + gpr_time_add(now, glb_policy->client_stats_report_interval); + GRPC_CLOSURE_INIT(&glb_policy->client_load_report_closure, + send_client_load_report_locked, glb_policy, + grpc_combiner_scheduler(glb_policy->base.combiner)); + grpc_timer_init(exec_ctx, &glb_policy->client_load_report_timer, + next_client_load_report_time, + &glb_policy->client_load_report_closure, now); +} + +static void client_load_report_done_locked(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error) { + glb_lb_policy *glb_policy = arg; + grpc_byte_buffer_destroy(glb_policy->client_load_report_payload); + glb_policy->client_load_report_payload = NULL; + if (error != GRPC_ERROR_NONE || glb_policy->lb_call == NULL) { + glb_policy->client_load_report_timer_pending = false; + GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &glb_policy->base, + "client_load_report"); + return; + } + schedule_next_client_load_report(exec_ctx, glb_policy); +} + +static void do_send_client_load_report_locked(grpc_exec_ctx *exec_ctx, + glb_lb_policy *glb_policy) { + grpc_op op; + memset(&op, 0, sizeof(op)); + op.op = GRPC_OP_SEND_MESSAGE; + op.data.send_message.send_message = glb_policy->client_load_report_payload; + GRPC_CLOSURE_INIT(&glb_policy->client_load_report_closure, + client_load_report_done_locked, glb_policy, + grpc_combiner_scheduler(glb_policy->base.combiner)); + grpc_call_error call_error = grpc_call_start_batch_and_execute( + exec_ctx, glb_policy->lb_call, &op, 1, + &glb_policy->client_load_report_closure); + GPR_ASSERT(GRPC_CALL_OK == call_error); +} + +static bool load_report_counters_are_zero(grpc_grpclb_request *request) { + grpc_grpclb_dropped_call_counts *drop_entries = + request->client_stats.calls_finished_with_drop.arg; + return request->client_stats.num_calls_started == 0 && + request->client_stats.num_calls_finished == 0 && + request->client_stats.num_calls_finished_with_client_failed_to_send == + 0 && + request->client_stats.num_calls_finished_known_received == 0 && + (drop_entries == NULL || drop_entries->num_entries == 0); +} + +static void send_client_load_report_locked(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error) { + glb_lb_policy *glb_policy = arg; + if (error == GRPC_ERROR_CANCELLED || glb_policy->lb_call == NULL) { + glb_policy->client_load_report_timer_pending = false; + GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &glb_policy->base, + "client_load_report"); + return; + } + // Construct message payload. + GPR_ASSERT(glb_policy->client_load_report_payload == NULL); + grpc_grpclb_request *request = + grpc_grpclb_load_report_request_create_locked(glb_policy->client_stats); + // Skip client load report if the counters were all zero in the last + // report and they are still zero in this one. + if (load_report_counters_are_zero(request)) { + if (glb_policy->last_client_load_report_counters_were_zero) { + grpc_grpclb_request_destroy(request); + schedule_next_client_load_report(exec_ctx, glb_policy); + return; + } + glb_policy->last_client_load_report_counters_were_zero = true; + } else { + glb_policy->last_client_load_report_counters_were_zero = false; + } + grpc_slice request_payload_slice = grpc_grpclb_request_encode(request); + glb_policy->client_load_report_payload = + grpc_raw_byte_buffer_create(&request_payload_slice, 1); + grpc_slice_unref_internal(exec_ctx, request_payload_slice); + grpc_grpclb_request_destroy(request); + // If we've already sent the initial request, then we can go ahead and + // sent the load report. Otherwise, we need to wait until the initial + // request has been sent to send this + // (see lb_on_sent_initial_request_locked() below). + if (glb_policy->initial_request_sent) { + do_send_client_load_report_locked(exec_ctx, glb_policy); + } +} + +static void lb_on_sent_initial_request_locked(grpc_exec_ctx *exec_ctx, + void *arg, grpc_error *error); +static void lb_on_server_status_received_locked(grpc_exec_ctx *exec_ctx, + void *arg, grpc_error *error); +static void lb_on_response_received_locked(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error); +static void lb_call_init_locked(grpc_exec_ctx *exec_ctx, + glb_lb_policy *glb_policy) { + GPR_ASSERT(glb_policy->server_name != NULL); + GPR_ASSERT(glb_policy->server_name[0] != '\0'); + GPR_ASSERT(glb_policy->lb_call == NULL); + GPR_ASSERT(!glb_policy->shutting_down); + + /* Note the following LB call progresses every time there's activity in \a + * glb_policy->base.interested_parties, which is comprised of the polling + * entities from \a client_channel. */ + grpc_slice host = grpc_slice_from_copied_string(glb_policy->server_name); + gpr_timespec deadline = + glb_policy->lb_call_timeout_ms == 0 + ? gpr_inf_future(GPR_CLOCK_MONOTONIC) + : gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), + gpr_time_from_millis(glb_policy->lb_call_timeout_ms, + GPR_TIMESPAN)); + glb_policy->lb_call = grpc_channel_create_pollset_set_call( + exec_ctx, glb_policy->lb_channel, NULL, GRPC_PROPAGATE_DEFAULTS, + glb_policy->base.interested_parties, + GRPC_MDSTR_SLASH_GRPC_DOT_LB_DOT_V1_DOT_LOADBALANCER_SLASH_BALANCELOAD, + &host, deadline, NULL); + grpc_slice_unref_internal(exec_ctx, host); + + if (glb_policy->client_stats != NULL) { + grpc_grpclb_client_stats_unref(glb_policy->client_stats); + } + glb_policy->client_stats = grpc_grpclb_client_stats_create(); + + grpc_metadata_array_init(&glb_policy->lb_initial_metadata_recv); + grpc_metadata_array_init(&glb_policy->lb_trailing_metadata_recv); + + grpc_grpclb_request *request = + grpc_grpclb_request_create(glb_policy->server_name); + grpc_slice request_payload_slice = grpc_grpclb_request_encode(request); + glb_policy->lb_request_payload = + grpc_raw_byte_buffer_create(&request_payload_slice, 1); + grpc_slice_unref_internal(exec_ctx, request_payload_slice); + grpc_grpclb_request_destroy(request); + + GRPC_CLOSURE_INIT(&glb_policy->lb_on_sent_initial_request, + lb_on_sent_initial_request_locked, glb_policy, + grpc_combiner_scheduler(glb_policy->base.combiner)); + GRPC_CLOSURE_INIT(&glb_policy->lb_on_server_status_received, + lb_on_server_status_received_locked, glb_policy, + grpc_combiner_scheduler(glb_policy->base.combiner)); + GRPC_CLOSURE_INIT(&glb_policy->lb_on_response_received, + lb_on_response_received_locked, glb_policy, + grpc_combiner_scheduler(glb_policy->base.combiner)); + + gpr_backoff_init(&glb_policy->lb_call_backoff_state, + GRPC_GRPCLB_INITIAL_CONNECT_BACKOFF_SECONDS, + GRPC_GRPCLB_RECONNECT_BACKOFF_MULTIPLIER, + GRPC_GRPCLB_RECONNECT_JITTER, + GRPC_GRPCLB_MIN_CONNECT_TIMEOUT_SECONDS * 1000, + GRPC_GRPCLB_RECONNECT_MAX_BACKOFF_SECONDS * 1000); + + glb_policy->initial_request_sent = false; + glb_policy->seen_initial_response = false; + glb_policy->last_client_load_report_counters_were_zero = false; +} + +static void lb_call_destroy_locked(grpc_exec_ctx *exec_ctx, + glb_lb_policy *glb_policy) { + GPR_ASSERT(glb_policy->lb_call != NULL); + grpc_call_unref(glb_policy->lb_call); + glb_policy->lb_call = NULL; + + grpc_metadata_array_destroy(&glb_policy->lb_initial_metadata_recv); + grpc_metadata_array_destroy(&glb_policy->lb_trailing_metadata_recv); + + grpc_byte_buffer_destroy(glb_policy->lb_request_payload); + grpc_slice_unref_internal(exec_ctx, glb_policy->lb_call_status_details); + + if (!glb_policy->client_load_report_timer_pending) { + grpc_timer_cancel(exec_ctx, &glb_policy->client_load_report_timer); + } +} + +/* + * Auxiliary functions and LB client callbacks. + */ +static void query_for_backends_locked(grpc_exec_ctx *exec_ctx, + glb_lb_policy *glb_policy) { + GPR_ASSERT(glb_policy->lb_channel != NULL); + if (glb_policy->shutting_down) return; + + lb_call_init_locked(exec_ctx, glb_policy); + + if (GRPC_TRACER_ON(grpc_lb_glb_trace)) { + gpr_log(GPR_INFO, + "Query for backends (grpclb: %p, lb_channel: %p, lb_call: %p)", + (void *)glb_policy, (void *)glb_policy->lb_channel, + (void *)glb_policy->lb_call); + } + GPR_ASSERT(glb_policy->lb_call != NULL); + + grpc_call_error call_error; + grpc_op ops[4]; + memset(ops, 0, sizeof(ops)); + + grpc_op *op = ops; + op->op = GRPC_OP_SEND_INITIAL_METADATA; + op->data.send_initial_metadata.count = 0; + op->flags = 0; + op->reserved = NULL; + op++; + op->op = GRPC_OP_RECV_INITIAL_METADATA; + op->data.recv_initial_metadata.recv_initial_metadata = + &glb_policy->lb_initial_metadata_recv; + op->flags = 0; + op->reserved = NULL; + op++; + GPR_ASSERT(glb_policy->lb_request_payload != NULL); + op->op = GRPC_OP_SEND_MESSAGE; + op->data.send_message.send_message = glb_policy->lb_request_payload; + op->flags = 0; + op->reserved = NULL; + op++; + /* take a weak ref (won't prevent calling of \a glb_shutdown if the strong ref + * count goes to zero) to be unref'd in lb_on_sent_initial_request_locked() */ + GRPC_LB_POLICY_WEAK_REF(&glb_policy->base, + "lb_on_sent_initial_request_locked"); + call_error = grpc_call_start_batch_and_execute( + exec_ctx, glb_policy->lb_call, ops, (size_t)(op - ops), + &glb_policy->lb_on_sent_initial_request); + GPR_ASSERT(GRPC_CALL_OK == call_error); + + op = ops; + op->op = GRPC_OP_RECV_STATUS_ON_CLIENT; + op->data.recv_status_on_client.trailing_metadata = + &glb_policy->lb_trailing_metadata_recv; + op->data.recv_status_on_client.status = &glb_policy->lb_call_status; + op->data.recv_status_on_client.status_details = + &glb_policy->lb_call_status_details; + op->flags = 0; + op->reserved = NULL; + op++; + /* take a weak ref (won't prevent calling of \a glb_shutdown if the strong ref + * count goes to zero) to be unref'd in lb_on_server_status_received_locked */ + GRPC_LB_POLICY_WEAK_REF(&glb_policy->base, + "lb_on_server_status_received_locked"); + call_error = grpc_call_start_batch_and_execute( + exec_ctx, glb_policy->lb_call, ops, (size_t)(op - ops), + &glb_policy->lb_on_server_status_received); + GPR_ASSERT(GRPC_CALL_OK == call_error); + + op = ops; + op->op = GRPC_OP_RECV_MESSAGE; + op->data.recv_message.recv_message = &glb_policy->lb_response_payload; + op->flags = 0; + op->reserved = NULL; + op++; + /* take another weak ref to be unref'd/reused in + * lb_on_response_received_locked */ + GRPC_LB_POLICY_WEAK_REF(&glb_policy->base, "lb_on_response_received_locked"); + call_error = grpc_call_start_batch_and_execute( + exec_ctx, glb_policy->lb_call, ops, (size_t)(op - ops), + &glb_policy->lb_on_response_received); + GPR_ASSERT(GRPC_CALL_OK == call_error); +} + +static void lb_on_sent_initial_request_locked(grpc_exec_ctx *exec_ctx, + void *arg, grpc_error *error) { + glb_lb_policy *glb_policy = arg; + glb_policy->initial_request_sent = true; + // If we attempted to send a client load report before the initial + // request was sent, send the load report now. + if (glb_policy->client_load_report_payload != NULL) { + do_send_client_load_report_locked(exec_ctx, glb_policy); + } + GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &glb_policy->base, + "lb_on_sent_initial_request_locked"); +} + +static void lb_on_response_received_locked(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error) { + glb_lb_policy *glb_policy = arg; + grpc_op ops[2]; + memset(ops, 0, sizeof(ops)); + grpc_op *op = ops; + if (glb_policy->lb_response_payload != NULL) { + gpr_backoff_reset(&glb_policy->lb_call_backoff_state); + /* Received data from the LB server. Look inside + * glb_policy->lb_response_payload, for a serverlist. */ + grpc_byte_buffer_reader bbr; + grpc_byte_buffer_reader_init(&bbr, glb_policy->lb_response_payload); + grpc_slice response_slice = grpc_byte_buffer_reader_readall(&bbr); + grpc_byte_buffer_destroy(glb_policy->lb_response_payload); + + grpc_grpclb_initial_response *response = NULL; + if (!glb_policy->seen_initial_response && + (response = grpc_grpclb_initial_response_parse(response_slice)) != + NULL) { + if (response->has_client_stats_report_interval) { + glb_policy->client_stats_report_interval = + gpr_time_max(gpr_time_from_seconds(1, GPR_TIMESPAN), + grpc_grpclb_duration_to_timespec( + &response->client_stats_report_interval)); + if (GRPC_TRACER_ON(grpc_lb_glb_trace)) { + gpr_log(GPR_INFO, + "received initial LB response message; " + "client load reporting interval = %" PRId64 ".%09d sec", + glb_policy->client_stats_report_interval.tv_sec, + glb_policy->client_stats_report_interval.tv_nsec); + } + /* take a weak ref (won't prevent calling of \a glb_shutdown() if the + * strong ref count goes to zero) to be unref'd in + * send_client_load_report_locked() */ + glb_policy->client_load_report_timer_pending = true; + GRPC_LB_POLICY_WEAK_REF(&glb_policy->base, "client_load_report"); + schedule_next_client_load_report(exec_ctx, glb_policy); + } else if (GRPC_TRACER_ON(grpc_lb_glb_trace)) { + gpr_log(GPR_INFO, + "received initial LB response message; " + "client load reporting NOT enabled"); + } + grpc_grpclb_initial_response_destroy(response); + glb_policy->seen_initial_response = true; + } else { + grpc_grpclb_serverlist *serverlist = + grpc_grpclb_response_parse_serverlist(response_slice); + if (serverlist != NULL) { + GPR_ASSERT(glb_policy->lb_call != NULL); + if (GRPC_TRACER_ON(grpc_lb_glb_trace)) { + gpr_log(GPR_INFO, "Serverlist with %lu servers received", + (unsigned long)serverlist->num_servers); + for (size_t i = 0; i < serverlist->num_servers; ++i) { + grpc_resolved_address addr; + parse_server(serverlist->servers[i], &addr); + char *ipport; + grpc_sockaddr_to_string(&ipport, &addr, false); + gpr_log(GPR_INFO, "Serverlist[%lu]: %s", (unsigned long)i, ipport); + gpr_free(ipport); + } + } + /* update serverlist */ + if (serverlist->num_servers > 0) { + if (grpc_grpclb_serverlist_equals(glb_policy->serverlist, + serverlist)) { + if (GRPC_TRACER_ON(grpc_lb_glb_trace)) { + gpr_log(GPR_INFO, + "Incoming server list identical to current, ignoring."); + } + grpc_grpclb_destroy_serverlist(serverlist); + } else { /* new serverlist */ + if (glb_policy->serverlist != NULL) { + /* dispose of the old serverlist */ + grpc_grpclb_destroy_serverlist(glb_policy->serverlist); + } + /* and update the copy in the glb_lb_policy instance. This + * serverlist instance will be destroyed either upon the next + * update or in glb_destroy() */ + glb_policy->serverlist = serverlist; + glb_policy->serverlist_index = 0; + rr_handover_locked(exec_ctx, glb_policy); + } + } else { + if (GRPC_TRACER_ON(grpc_lb_glb_trace)) { + gpr_log(GPR_INFO, + "Received empty server list. Picks will stay pending until " + "a response with > 0 servers is received"); + } + grpc_grpclb_destroy_serverlist(serverlist); + } + } else { /* serverlist == NULL */ + gpr_log(GPR_ERROR, "Invalid LB response received: '%s'. Ignoring.", + grpc_dump_slice(response_slice, GPR_DUMP_ASCII | GPR_DUMP_HEX)); + } + } + grpc_slice_unref_internal(exec_ctx, response_slice); + if (!glb_policy->shutting_down) { + /* keep listening for serverlist updates */ + op->op = GRPC_OP_RECV_MESSAGE; + op->data.recv_message.recv_message = &glb_policy->lb_response_payload; + op->flags = 0; + op->reserved = NULL; + op++; + /* reuse the "lb_on_response_received_locked" weak ref taken in + * query_for_backends_locked() */ + const grpc_call_error call_error = grpc_call_start_batch_and_execute( + exec_ctx, glb_policy->lb_call, ops, (size_t)(op - ops), + &glb_policy->lb_on_response_received); /* loop */ + GPR_ASSERT(GRPC_CALL_OK == call_error); + } + } else { /* empty payload: call cancelled. */ + /* dispose of the "lb_on_response_received_locked" weak ref taken in + * query_for_backends_locked() and reused in every reception loop */ + GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &glb_policy->base, + "lb_on_response_received_locked_empty_payload"); + } +} + +static void lb_call_on_retry_timer_locked(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error) { + glb_lb_policy *glb_policy = arg; + glb_policy->retry_timer_active = false; + if (!glb_policy->shutting_down && error == GRPC_ERROR_NONE) { + if (GRPC_TRACER_ON(grpc_lb_glb_trace)) { + gpr_log(GPR_INFO, "Restaring call to LB server (grpclb %p)", + (void *)glb_policy); + } + GPR_ASSERT(glb_policy->lb_call == NULL); + query_for_backends_locked(exec_ctx, glb_policy); + } + GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &glb_policy->base, "grpclb_retry_timer"); +} + +static void lb_on_server_status_received_locked(grpc_exec_ctx *exec_ctx, + void *arg, grpc_error *error) { + glb_lb_policy *glb_policy = arg; + GPR_ASSERT(glb_policy->lb_call != NULL); + if (GRPC_TRACER_ON(grpc_lb_glb_trace)) { + char *status_details = + grpc_slice_to_c_string(glb_policy->lb_call_status_details); + gpr_log(GPR_INFO, + "Status from LB server received. Status = %d, Details = '%s', " + "(call: %p), error %p", + glb_policy->lb_call_status, status_details, + (void *)glb_policy->lb_call, (void *)error); + gpr_free(status_details); + } + /* We need to perform cleanups no matter what. */ + lb_call_destroy_locked(exec_ctx, glb_policy); + if (glb_policy->started_picking && glb_policy->updating_lb_call) { + if (glb_policy->retry_timer_active) { + grpc_timer_cancel(exec_ctx, &glb_policy->lb_call_retry_timer); + } + if (!glb_policy->shutting_down) start_picking_locked(exec_ctx, glb_policy); + glb_policy->updating_lb_call = false; + } else if (!glb_policy->shutting_down) { + /* if we aren't shutting down, restart the LB client call after some time */ + gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC); + gpr_timespec next_try = + gpr_backoff_step(&glb_policy->lb_call_backoff_state, now); + if (GRPC_TRACER_ON(grpc_lb_glb_trace)) { + gpr_log(GPR_DEBUG, "Connection to LB server lost (grpclb: %p)...", + (void *)glb_policy); + gpr_timespec timeout = gpr_time_sub(next_try, now); + if (gpr_time_cmp(timeout, gpr_time_0(timeout.clock_type)) > 0) { + gpr_log(GPR_DEBUG, + "... retry_timer_active in %" PRId64 ".%09d seconds.", + timeout.tv_sec, timeout.tv_nsec); + } else { + gpr_log(GPR_DEBUG, "... retry_timer_active immediately."); + } + } + GRPC_LB_POLICY_WEAK_REF(&glb_policy->base, "grpclb_retry_timer"); + GRPC_CLOSURE_INIT(&glb_policy->lb_on_call_retry, + lb_call_on_retry_timer_locked, glb_policy, + grpc_combiner_scheduler(glb_policy->base.combiner)); + glb_policy->retry_timer_active = true; + grpc_timer_init(exec_ctx, &glb_policy->lb_call_retry_timer, next_try, + &glb_policy->lb_on_call_retry, now); + } + GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &glb_policy->base, + "lb_on_server_status_received_locked"); +} + +static void glb_update_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, + const grpc_lb_policy_args *args) { + glb_lb_policy *glb_policy = (glb_lb_policy *)policy; + if (glb_policy->updating_lb_channel) { + if (GRPC_TRACER_ON(grpc_lb_glb_trace)) { + gpr_log(GPR_INFO, + "Update already in progress for grpclb %p. Deferring update.", + (void *)glb_policy); + } + if (glb_policy->pending_update_args != NULL) { + grpc_channel_args_destroy(exec_ctx, + glb_policy->pending_update_args->args); + gpr_free(glb_policy->pending_update_args); + } + glb_policy->pending_update_args = + gpr_zalloc(sizeof(*glb_policy->pending_update_args)); + glb_policy->pending_update_args->client_channel_factory = + args->client_channel_factory; + glb_policy->pending_update_args->args = grpc_channel_args_copy(args->args); + glb_policy->pending_update_args->combiner = args->combiner; + return; + } + + glb_policy->updating_lb_channel = true; + // Propagate update to lb_channel (pick first). + const grpc_arg *arg = + grpc_channel_args_find(args->args, GRPC_ARG_LB_ADDRESSES); + if (arg == NULL || arg->type != GRPC_ARG_POINTER) { + if (glb_policy->lb_channel == NULL) { + // If we don't have a current channel to the LB, go into TRANSIENT + // FAILURE. + grpc_connectivity_state_set( + exec_ctx, &glb_policy->state_tracker, GRPC_CHANNEL_TRANSIENT_FAILURE, + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Missing update in args"), + "glb_update_missing"); + } else { + // otherwise, keep using the current LB channel (ignore this update). + gpr_log(GPR_ERROR, + "No valid LB addresses channel arg for grpclb %p update, " + "ignoring.", + (void *)glb_policy); + } + } + const grpc_lb_addresses *addresses = arg->value.pointer.p; + GPR_ASSERT(glb_policy->lb_channel != NULL); + grpc_channel_args *lb_channel_args = build_lb_channel_args( + exec_ctx, addresses, glb_policy->response_generator, args->args); + /* Propagate updates to the LB channel through the fake resolver */ + grpc_fake_resolver_response_generator_set_response( + exec_ctx, glb_policy->response_generator, lb_channel_args); + grpc_channel_args_destroy(exec_ctx, lb_channel_args); + + if (!glb_policy->watching_lb_channel) { + // Watch the LB channel connectivity for connection. + glb_policy->lb_channel_connectivity = grpc_channel_check_connectivity_state( + glb_policy->lb_channel, true /* try to connect */); + grpc_channel_element *client_channel_elem = grpc_channel_stack_last_element( + grpc_channel_get_channel_stack(glb_policy->lb_channel)); + GPR_ASSERT(client_channel_elem->filter == &grpc_client_channel_filter); + glb_policy->watching_lb_channel = true; + GRPC_LB_POLICY_WEAK_REF(&glb_policy->base, "watch_lb_channel_connectivity"); + grpc_client_channel_watch_connectivity_state( + exec_ctx, client_channel_elem, + grpc_polling_entity_create_from_pollset_set( + glb_policy->base.interested_parties), + &glb_policy->lb_channel_connectivity, + &glb_policy->lb_channel_on_connectivity_changed, NULL); + } +} + +// Invoked as part of the update process. It continues watching the LB channel +// until it shuts down or becomes READY. It's invoked even if the LB channel +// stayed READY throughout the update (for example if the update is identical). +static void glb_lb_channel_on_connectivity_changed_cb(grpc_exec_ctx *exec_ctx, + void *arg, + grpc_error *error) { + glb_lb_policy *glb_policy = arg; + if (glb_policy->shutting_down) goto done; + // Re-initialize the lb_call. This should also take care of updating the + // embedded RR policy. Note that the current RR policy, if any, will stay in + // effect until an update from the new lb_call is received. + switch (glb_policy->lb_channel_connectivity) { + case GRPC_CHANNEL_INIT: + case GRPC_CHANNEL_CONNECTING: + case GRPC_CHANNEL_TRANSIENT_FAILURE: { + /* resub. */ + grpc_channel_element *client_channel_elem = + grpc_channel_stack_last_element( + grpc_channel_get_channel_stack(glb_policy->lb_channel)); + GPR_ASSERT(client_channel_elem->filter == &grpc_client_channel_filter); + grpc_client_channel_watch_connectivity_state( + exec_ctx, client_channel_elem, + grpc_polling_entity_create_from_pollset_set( + glb_policy->base.interested_parties), + &glb_policy->lb_channel_connectivity, + &glb_policy->lb_channel_on_connectivity_changed, NULL); + break; + } + case GRPC_CHANNEL_IDLE: + // lb channel inactive (probably shutdown prior to update). Restart lb + // call to kick the lb channel into gear. + GPR_ASSERT(glb_policy->lb_call == NULL); + /* fallthrough */ + case GRPC_CHANNEL_READY: + if (glb_policy->lb_call != NULL) { + glb_policy->updating_lb_channel = false; + glb_policy->updating_lb_call = true; + grpc_call_cancel(glb_policy->lb_call, NULL); + // lb_on_server_status_received will pick up the cancel and reinit + // lb_call. + if (glb_policy->pending_update_args != NULL) { + grpc_lb_policy_args *args = glb_policy->pending_update_args; + glb_policy->pending_update_args = NULL; + glb_update_locked(exec_ctx, &glb_policy->base, args); + grpc_channel_args_destroy(exec_ctx, args->args); + gpr_free(args); + } + } else if (glb_policy->started_picking && !glb_policy->shutting_down) { + if (glb_policy->retry_timer_active) { + grpc_timer_cancel(exec_ctx, &glb_policy->lb_call_retry_timer); + glb_policy->retry_timer_active = false; + } + start_picking_locked(exec_ctx, glb_policy); + } + /* fallthrough */ + case GRPC_CHANNEL_SHUTDOWN: + done: + glb_policy->watching_lb_channel = false; + GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &glb_policy->base, + "watch_lb_channel_connectivity_cb_shutdown"); + break; + } +} + +/* Code wiring the policy with the rest of the core */ +static const grpc_lb_policy_vtable glb_lb_policy_vtable = { + glb_destroy, + glb_shutdown_locked, + glb_pick_locked, + glb_cancel_pick_locked, + glb_cancel_picks_locked, + glb_ping_one_locked, + glb_exit_idle_locked, + glb_check_connectivity_locked, + glb_notify_on_state_change_locked, + glb_update_locked}; + +static void glb_factory_ref(grpc_lb_policy_factory *factory) {} + +static void glb_factory_unref(grpc_lb_policy_factory *factory) {} + +static const grpc_lb_policy_factory_vtable glb_factory_vtable = { + glb_factory_ref, glb_factory_unref, glb_create, "grpclb"}; + +static grpc_lb_policy_factory glb_lb_policy_factory = {&glb_factory_vtable}; + +grpc_lb_policy_factory *grpc_glb_lb_factory_create() { + return &glb_lb_policy_factory; +} + +/* Plugin registration */ + +// Only add client_load_reporting filter if the grpclb LB policy is used. +static bool maybe_add_client_load_reporting_filter( + grpc_exec_ctx *exec_ctx, grpc_channel_stack_builder *builder, void *arg) { + const grpc_channel_args *args = + grpc_channel_stack_builder_get_channel_arguments(builder); + const grpc_arg *channel_arg = + grpc_channel_args_find(args, GRPC_ARG_LB_POLICY_NAME); + if (channel_arg != NULL && channel_arg->type == GRPC_ARG_STRING && + strcmp(channel_arg->value.string, "grpclb") == 0) { + return grpc_channel_stack_builder_append_filter( + builder, (const grpc_channel_filter *)arg, NULL, NULL); + } + return true; +} + +void grpc_lb_policy_grpclb_init() { + grpc_register_lb_policy(grpc_glb_lb_factory_create()); + grpc_register_tracer(&grpc_lb_glb_trace); +#ifndef NDEBUG + grpc_register_tracer(&grpc_trace_lb_policy_refcount); +#endif + grpc_channel_init_register_stage(GRPC_CLIENT_SUBCHANNEL, + GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, + maybe_add_client_load_reporting_filter, + (void *)&grpc_client_load_reporting_filter); +} + +void grpc_lb_policy_grpclb_shutdown() {} diff --git a/Sources/CgRPC/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h b/Sources/CgRPC/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h new file mode 100644 index 000000000..63ad66c5e --- /dev/null +++ b/Sources/CgRPC/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h @@ -0,0 +1,29 @@ +/* + * + * Copyright 2016 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 GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_GRPCLB_GRPCLB_H +#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_GRPCLB_GRPCLB_H + +#include "src/core/ext/filters/client_channel/lb_policy_factory.h" + +/** Returns a load balancing factory for the glb policy, which tries to connect + * to a load balancing server to decide the next successfully connected + * subchannel to pick. */ +grpc_lb_policy_factory *grpc_glb_lb_factory_create(); + +#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_GRPCLB_GRPCLB_H */ diff --git a/Sources/CgRPC/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h b/Sources/CgRPC/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h new file mode 100644 index 000000000..6120bf53f --- /dev/null +++ b/Sources/CgRPC/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h @@ -0,0 +1,44 @@ +/* + * + * Copyright 2017 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 GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_GRPCLB_GRPCLB_CHANNEL_H +#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_GRPCLB_GRPCLB_CHANNEL_H + +#include "src/core/ext/filters/client_channel/lb_policy_factory.h" +#include "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h" +#include "src/core/lib/slice/slice_hash_table.h" + +/** Create the channel used for communicating with an LB service. + * Note that an LB *service* may be comprised of several LB *servers*. + * + * \a lb_service_target_addresses is the target URI containing the addresses + * from resolving the LB service's name (eg, ipv4:10.0.0.1:1234,10.2.3.4:9876). + * \a client_channel_factory will be used for the creation of the LB channel, + * alongside the channel args passed in \a args. */ +grpc_channel *grpc_lb_policy_grpclb_create_lb_channel( + grpc_exec_ctx *exec_ctx, const char *lb_service_target_addresses, + grpc_client_channel_factory *client_channel_factory, + grpc_channel_args *args); + +grpc_channel_args *grpc_lb_policy_grpclb_build_lb_channel_args( + grpc_exec_ctx *exec_ctx, grpc_slice_hash_table *targets_info, + grpc_fake_resolver_response_generator *response_generator, + const grpc_channel_args *args); + +#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_GRPCLB_GRPCLB_CHANNEL_H \ + */ diff --git a/Sources/CgRPC/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.c b/Sources/CgRPC/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.c new file mode 100644 index 000000000..2681b2a07 --- /dev/null +++ b/Sources/CgRPC/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.c @@ -0,0 +1,99 @@ +/* + * + * Copyright 2017 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 +#include + +#include "src/core/ext/filters/client_channel/client_channel.h" +#include "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h" +#include "src/core/lib/channel/channel_args.h" +#include "src/core/lib/iomgr/sockaddr_utils.h" +#include "src/core/lib/security/credentials/credentials.h" +#include "src/core/lib/security/transport/lb_targets_info.h" +#include "src/core/lib/slice/slice_internal.h" +#include "src/core/lib/support/string.h" + +grpc_channel *grpc_lb_policy_grpclb_create_lb_channel( + grpc_exec_ctx *exec_ctx, const char *lb_service_target_addresses, + grpc_client_channel_factory *client_channel_factory, + grpc_channel_args *args) { + grpc_channel_args *new_args = args; + grpc_channel_credentials *channel_credentials = + grpc_channel_credentials_find_in_args(args); + if (channel_credentials != NULL) { + /* Substitute the channel credentials with a version without call + * credentials: the load balancer is not necessarily trusted to handle + * bearer token credentials */ + static const char *keys_to_remove[] = {GRPC_ARG_CHANNEL_CREDENTIALS}; + grpc_channel_credentials *creds_sans_call_creds = + grpc_channel_credentials_duplicate_without_call_credentials( + channel_credentials); + GPR_ASSERT(creds_sans_call_creds != NULL); + grpc_arg args_to_add[] = { + grpc_channel_credentials_to_arg(creds_sans_call_creds)}; + /* Create the new set of channel args */ + new_args = grpc_channel_args_copy_and_add_and_remove( + args, keys_to_remove, GPR_ARRAY_SIZE(keys_to_remove), args_to_add, + GPR_ARRAY_SIZE(args_to_add)); + grpc_channel_credentials_unref(exec_ctx, creds_sans_call_creds); + } + grpc_channel *lb_channel = grpc_client_channel_factory_create_channel( + exec_ctx, client_channel_factory, lb_service_target_addresses, + GRPC_CLIENT_CHANNEL_TYPE_LOAD_BALANCING, new_args); + if (channel_credentials != NULL) { + grpc_channel_args_destroy(exec_ctx, new_args); + } + return lb_channel; +} + +grpc_channel_args *grpc_lb_policy_grpclb_build_lb_channel_args( + grpc_exec_ctx *exec_ctx, grpc_slice_hash_table *targets_info, + grpc_fake_resolver_response_generator *response_generator, + const grpc_channel_args *args) { + const grpc_arg to_add[] = { + grpc_lb_targets_info_create_channel_arg(targets_info), + grpc_fake_resolver_response_generator_arg(response_generator)}; + /* We remove: + * + * - The channel arg for the LB policy name, since we want to use the default + * (pick_first) in this case. + * + * - The channel arg for the resolved addresses, since that will be generated + * by the name resolver used in the LB channel. Note that the LB channel + * will use the fake resolver, so this won't actually generate a query + * to DNS (or some other name service). However, the addresses returned by + * the fake resolver will have is_balancer=false, whereas our own + * addresses have is_balancer=true. We need the LB channel to return + * addresses with is_balancer=false so that it does not wind up recursively + * using the grpclb LB policy, as per the special case logic in + * client_channel.c. + * + * - The channel arg for the server URI, since that will be different for the + * LB channel than for the parent channel (the client channel factory will + * re-add this arg with the right value). + * + * - The fake resolver generator, because we are replacing it with the one + * from the grpclb policy, used to propagate updates to the LB channel. */ + static const char *keys_to_remove[] = { + GRPC_ARG_LB_POLICY_NAME, GRPC_ARG_LB_ADDRESSES, GRPC_ARG_SERVER_URI, + GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR}; + /* Add the targets info table to be used for secure naming */ + return grpc_channel_args_copy_and_add_and_remove( + args, keys_to_remove, GPR_ARRAY_SIZE(keys_to_remove), to_add, + GPR_ARRAY_SIZE(to_add)); +} diff --git a/Sources/CgRPC/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.c b/Sources/CgRPC/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.c new file mode 100644 index 000000000..5b6262314 --- /dev/null +++ b/Sources/CgRPC/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.c @@ -0,0 +1,149 @@ +/* + * + * Copyright 2017 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 "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h" + +#include + +#include +#include +#include +#include +#include + +#include "src/core/lib/channel/channel_args.h" + +#define GRPC_ARG_GRPCLB_CLIENT_STATS "grpc.grpclb_client_stats" + +struct grpc_grpclb_client_stats { + gpr_refcount refs; + // This field must only be accessed via *_locked() methods. + grpc_grpclb_dropped_call_counts* drop_token_counts; + // These fields may be accessed from multiple threads at a time. + gpr_atm num_calls_started; + gpr_atm num_calls_finished; + gpr_atm num_calls_finished_with_client_failed_to_send; + gpr_atm num_calls_finished_known_received; +}; + +grpc_grpclb_client_stats* grpc_grpclb_client_stats_create() { + grpc_grpclb_client_stats* client_stats = gpr_zalloc(sizeof(*client_stats)); + gpr_ref_init(&client_stats->refs, 1); + return client_stats; +} + +grpc_grpclb_client_stats* grpc_grpclb_client_stats_ref( + grpc_grpclb_client_stats* client_stats) { + gpr_ref(&client_stats->refs); + return client_stats; +} + +void grpc_grpclb_client_stats_unref(grpc_grpclb_client_stats* client_stats) { + if (gpr_unref(&client_stats->refs)) { + grpc_grpclb_dropped_call_counts_destroy(client_stats->drop_token_counts); + gpr_free(client_stats); + } +} + +void grpc_grpclb_client_stats_add_call_started( + grpc_grpclb_client_stats* client_stats) { + gpr_atm_full_fetch_add(&client_stats->num_calls_started, (gpr_atm)1); +} + +void grpc_grpclb_client_stats_add_call_finished( + bool finished_with_client_failed_to_send, bool finished_known_received, + grpc_grpclb_client_stats* client_stats) { + gpr_atm_full_fetch_add(&client_stats->num_calls_finished, (gpr_atm)1); + if (finished_with_client_failed_to_send) { + gpr_atm_full_fetch_add( + &client_stats->num_calls_finished_with_client_failed_to_send, + (gpr_atm)1); + } + if (finished_known_received) { + gpr_atm_full_fetch_add(&client_stats->num_calls_finished_known_received, + (gpr_atm)1); + } +} + +void grpc_grpclb_client_stats_add_call_dropped_locked( + char* token, grpc_grpclb_client_stats* client_stats) { + // Increment num_calls_started and num_calls_finished. + gpr_atm_full_fetch_add(&client_stats->num_calls_started, (gpr_atm)1); + gpr_atm_full_fetch_add(&client_stats->num_calls_finished, (gpr_atm)1); + // Record the drop. + if (client_stats->drop_token_counts == NULL) { + client_stats->drop_token_counts = + gpr_zalloc(sizeof(grpc_grpclb_dropped_call_counts)); + } + grpc_grpclb_dropped_call_counts* drop_token_counts = + client_stats->drop_token_counts; + for (size_t i = 0; i < drop_token_counts->num_entries; ++i) { + if (strcmp(drop_token_counts->token_counts[i].token, token) == 0) { + ++drop_token_counts->token_counts[i].count; + return; + } + } + // Not found, so add a new entry. We double the size of the array each time. + size_t new_num_entries = 2; + while (new_num_entries < drop_token_counts->num_entries + 1) { + new_num_entries *= 2; + } + drop_token_counts->token_counts = + gpr_realloc(drop_token_counts->token_counts, + new_num_entries * sizeof(grpc_grpclb_drop_token_count)); + grpc_grpclb_drop_token_count* new_entry = + &drop_token_counts->token_counts[drop_token_counts->num_entries++]; + new_entry->token = gpr_strdup(token); + new_entry->count = 1; +} + +static void atomic_get_and_reset_counter(int64_t* value, gpr_atm* counter) { + *value = (int64_t)gpr_atm_acq_load(counter); + gpr_atm_full_fetch_add(counter, (gpr_atm)(-*value)); +} + +void grpc_grpclb_client_stats_get_locked( + grpc_grpclb_client_stats* client_stats, int64_t* num_calls_started, + int64_t* num_calls_finished, + int64_t* num_calls_finished_with_client_failed_to_send, + int64_t* num_calls_finished_known_received, + grpc_grpclb_dropped_call_counts** drop_token_counts) { + atomic_get_and_reset_counter(num_calls_started, + &client_stats->num_calls_started); + atomic_get_and_reset_counter(num_calls_finished, + &client_stats->num_calls_finished); + atomic_get_and_reset_counter( + num_calls_finished_with_client_failed_to_send, + &client_stats->num_calls_finished_with_client_failed_to_send); + atomic_get_and_reset_counter( + num_calls_finished_known_received, + &client_stats->num_calls_finished_known_received); + *drop_token_counts = client_stats->drop_token_counts; + client_stats->drop_token_counts = NULL; +} + +void grpc_grpclb_dropped_call_counts_destroy( + grpc_grpclb_dropped_call_counts* drop_entries) { + if (drop_entries != NULL) { + for (size_t i = 0; i < drop_entries->num_entries; ++i) { + gpr_free(drop_entries->token_counts[i].token); + } + gpr_free(drop_entries->token_counts); + gpr_free(drop_entries); + } +} diff --git a/Sources/CgRPC/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h b/Sources/CgRPC/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h new file mode 100644 index 000000000..c51e2a431 --- /dev/null +++ b/Sources/CgRPC/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h @@ -0,0 +1,65 @@ +/* + * + * Copyright 2017 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 GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_GRPCLB_GRPCLB_CLIENT_STATS_H +#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_GRPCLB_GRPCLB_CLIENT_STATS_H + +#include + +#include + +typedef struct grpc_grpclb_client_stats grpc_grpclb_client_stats; + +typedef struct { + char* token; + int64_t count; +} grpc_grpclb_drop_token_count; + +typedef struct { + grpc_grpclb_drop_token_count* token_counts; + size_t num_entries; +} grpc_grpclb_dropped_call_counts; + +grpc_grpclb_client_stats* grpc_grpclb_client_stats_create(); +grpc_grpclb_client_stats* grpc_grpclb_client_stats_ref( + grpc_grpclb_client_stats* client_stats); +void grpc_grpclb_client_stats_unref(grpc_grpclb_client_stats* client_stats); + +void grpc_grpclb_client_stats_add_call_started( + grpc_grpclb_client_stats* client_stats); +void grpc_grpclb_client_stats_add_call_finished( + bool finished_with_client_failed_to_send, bool finished_known_received, + grpc_grpclb_client_stats* client_stats); + +// This method is not thread-safe; caller must synchronize. +void grpc_grpclb_client_stats_add_call_dropped_locked( + char* token, grpc_grpclb_client_stats* client_stats); + +// This method is not thread-safe; caller must synchronize. +void grpc_grpclb_client_stats_get_locked( + grpc_grpclb_client_stats* client_stats, int64_t* num_calls_started, + int64_t* num_calls_finished, + int64_t* num_calls_finished_with_client_failed_to_send, + int64_t* num_calls_finished_known_received, + grpc_grpclb_dropped_call_counts** drop_token_counts); + +void grpc_grpclb_dropped_call_counts_destroy( + grpc_grpclb_dropped_call_counts* drop_entries); + +#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_GRPCLB_GRPCLB_CLIENT_STATS_H \ + */ diff --git a/Sources/CgRPC/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.c b/Sources/CgRPC/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.c new file mode 100644 index 000000000..6fa29f326 --- /dev/null +++ b/Sources/CgRPC/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.c @@ -0,0 +1,303 @@ +/* + * + * Copyright 2016 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 "src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h" +#include "third_party/nanopb/pb_decode.h" +#include "third_party/nanopb/pb_encode.h" + +#include + +/* invoked once for every Server in ServerList */ +static bool count_serverlist(pb_istream_t *stream, const pb_field_t *field, + void **arg) { + grpc_grpclb_serverlist *sl = *arg; + grpc_grpclb_server server; + if (!pb_decode(stream, grpc_lb_v1_Server_fields, &server)) { + gpr_log(GPR_ERROR, "nanopb error: %s", PB_GET_ERROR(stream)); + return false; + } + ++sl->num_servers; + return true; +} + +typedef struct decode_serverlist_arg { + /* The decoding callback is invoked once per server in serverlist. Remember + * which index of the serverlist are we currently decoding */ + size_t decoding_idx; + /* The decoded serverlist */ + grpc_grpclb_serverlist *serverlist; +} decode_serverlist_arg; + +/* invoked once for every Server in ServerList */ +static bool decode_serverlist(pb_istream_t *stream, const pb_field_t *field, + void **arg) { + decode_serverlist_arg *dec_arg = *arg; + GPR_ASSERT(dec_arg->serverlist->num_servers >= dec_arg->decoding_idx); + grpc_grpclb_server *server = gpr_zalloc(sizeof(grpc_grpclb_server)); + if (!pb_decode(stream, grpc_lb_v1_Server_fields, server)) { + gpr_free(server); + gpr_log(GPR_ERROR, "nanopb error: %s", PB_GET_ERROR(stream)); + return false; + } + dec_arg->serverlist->servers[dec_arg->decoding_idx++] = server; + return true; +} + +grpc_grpclb_request *grpc_grpclb_request_create(const char *lb_service_name) { + grpc_grpclb_request *req = gpr_malloc(sizeof(grpc_grpclb_request)); + req->has_client_stats = false; + req->has_initial_request = true; + req->initial_request.has_name = true; + strncpy(req->initial_request.name, lb_service_name, + GRPC_GRPCLB_SERVICE_NAME_MAX_LENGTH); + return req; +} + +static void populate_timestamp(gpr_timespec timestamp, + struct _grpc_lb_v1_Timestamp *timestamp_pb) { + timestamp_pb->has_seconds = true; + timestamp_pb->seconds = timestamp.tv_sec; + timestamp_pb->has_nanos = true; + timestamp_pb->nanos = timestamp.tv_nsec; +} + +static bool encode_string(pb_ostream_t *stream, const pb_field_t *field, + void *const *arg) { + char *str = *arg; + if (!pb_encode_tag_for_field(stream, field)) return false; + return pb_encode_string(stream, (uint8_t *)str, strlen(str)); +} + +static bool encode_drops(pb_ostream_t *stream, const pb_field_t *field, + void *const *arg) { + grpc_grpclb_dropped_call_counts *drop_entries = *arg; + if (drop_entries == NULL) return true; + for (size_t i = 0; i < drop_entries->num_entries; ++i) { + if (!pb_encode_tag_for_field(stream, field)) return false; + grpc_lb_v1_ClientStatsPerToken drop_message; + drop_message.load_balance_token.funcs.encode = encode_string; + drop_message.load_balance_token.arg = drop_entries->token_counts[i].token; + drop_message.has_num_calls = true; + drop_message.num_calls = drop_entries->token_counts[i].count; + if (!pb_encode_submessage(stream, grpc_lb_v1_ClientStatsPerToken_fields, + &drop_message)) { + return false; + } + } + return true; +} + +grpc_grpclb_request *grpc_grpclb_load_report_request_create_locked( + grpc_grpclb_client_stats *client_stats) { + grpc_grpclb_request *req = gpr_zalloc(sizeof(grpc_grpclb_request)); + req->has_client_stats = true; + req->client_stats.has_timestamp = true; + populate_timestamp(gpr_now(GPR_CLOCK_REALTIME), &req->client_stats.timestamp); + req->client_stats.has_num_calls_started = true; + req->client_stats.has_num_calls_finished = true; + req->client_stats.has_num_calls_finished_with_client_failed_to_send = true; + req->client_stats.has_num_calls_finished_with_client_failed_to_send = true; + req->client_stats.has_num_calls_finished_known_received = true; + req->client_stats.calls_finished_with_drop.funcs.encode = encode_drops; + grpc_grpclb_client_stats_get_locked( + client_stats, &req->client_stats.num_calls_started, + &req->client_stats.num_calls_finished, + &req->client_stats.num_calls_finished_with_client_failed_to_send, + &req->client_stats.num_calls_finished_known_received, + (grpc_grpclb_dropped_call_counts **)&req->client_stats + .calls_finished_with_drop.arg); + return req; +} + +grpc_slice grpc_grpclb_request_encode(const grpc_grpclb_request *request) { + size_t encoded_length; + pb_ostream_t sizestream; + pb_ostream_t outputstream; + grpc_slice slice; + memset(&sizestream, 0, sizeof(pb_ostream_t)); + pb_encode(&sizestream, grpc_lb_v1_LoadBalanceRequest_fields, request); + encoded_length = sizestream.bytes_written; + + slice = GRPC_SLICE_MALLOC(encoded_length); + outputstream = + pb_ostream_from_buffer(GRPC_SLICE_START_PTR(slice), encoded_length); + GPR_ASSERT(pb_encode(&outputstream, grpc_lb_v1_LoadBalanceRequest_fields, + request) != 0); + return slice; +} + +void grpc_grpclb_request_destroy(grpc_grpclb_request *request) { + if (request->has_client_stats) { + grpc_grpclb_dropped_call_counts *drop_entries = + request->client_stats.calls_finished_with_drop.arg; + grpc_grpclb_dropped_call_counts_destroy(drop_entries); + } + gpr_free(request); +} + +typedef grpc_lb_v1_LoadBalanceResponse grpc_grpclb_response; +grpc_grpclb_initial_response *grpc_grpclb_initial_response_parse( + grpc_slice encoded_grpc_grpclb_response) { + pb_istream_t stream = + pb_istream_from_buffer(GRPC_SLICE_START_PTR(encoded_grpc_grpclb_response), + GRPC_SLICE_LENGTH(encoded_grpc_grpclb_response)); + grpc_grpclb_response res; + memset(&res, 0, sizeof(grpc_grpclb_response)); + if (!pb_decode(&stream, grpc_lb_v1_LoadBalanceResponse_fields, &res)) { + gpr_log(GPR_ERROR, "nanopb error: %s", PB_GET_ERROR(&stream)); + return NULL; + } + + if (!res.has_initial_response) return NULL; + + grpc_grpclb_initial_response *initial_res = + gpr_malloc(sizeof(grpc_grpclb_initial_response)); + memcpy(initial_res, &res.initial_response, + sizeof(grpc_grpclb_initial_response)); + + return initial_res; +} + +grpc_grpclb_serverlist *grpc_grpclb_response_parse_serverlist( + grpc_slice encoded_grpc_grpclb_response) { + pb_istream_t stream = + pb_istream_from_buffer(GRPC_SLICE_START_PTR(encoded_grpc_grpclb_response), + GRPC_SLICE_LENGTH(encoded_grpc_grpclb_response)); + pb_istream_t stream_at_start = stream; + grpc_grpclb_serverlist *sl = gpr_zalloc(sizeof(grpc_grpclb_serverlist)); + grpc_grpclb_response res; + memset(&res, 0, sizeof(grpc_grpclb_response)); + // First pass: count number of servers. + res.server_list.servers.funcs.decode = count_serverlist; + res.server_list.servers.arg = sl; + bool status = pb_decode(&stream, grpc_lb_v1_LoadBalanceResponse_fields, &res); + if (!status) { + gpr_free(sl); + gpr_log(GPR_ERROR, "nanopb error: %s", PB_GET_ERROR(&stream)); + return NULL; + } + // Second pass: populate servers. + if (sl->num_servers > 0) { + sl->servers = gpr_zalloc(sizeof(grpc_grpclb_server *) * sl->num_servers); + decode_serverlist_arg decode_arg; + memset(&decode_arg, 0, sizeof(decode_arg)); + decode_arg.serverlist = sl; + res.server_list.servers.funcs.decode = decode_serverlist; + res.server_list.servers.arg = &decode_arg; + status = pb_decode(&stream_at_start, grpc_lb_v1_LoadBalanceResponse_fields, + &res); + if (!status) { + grpc_grpclb_destroy_serverlist(sl); + gpr_log(GPR_ERROR, "nanopb error: %s", PB_GET_ERROR(&stream)); + return NULL; + } + } + if (res.server_list.has_expiration_interval) { + sl->expiration_interval = res.server_list.expiration_interval; + } + return sl; +} + +void grpc_grpclb_destroy_serverlist(grpc_grpclb_serverlist *serverlist) { + if (serverlist == NULL) { + return; + } + for (size_t i = 0; i < serverlist->num_servers; i++) { + gpr_free(serverlist->servers[i]); + } + gpr_free(serverlist->servers); + gpr_free(serverlist); +} + +grpc_grpclb_serverlist *grpc_grpclb_serverlist_copy( + const grpc_grpclb_serverlist *sl) { + grpc_grpclb_serverlist *copy = gpr_zalloc(sizeof(grpc_grpclb_serverlist)); + copy->num_servers = sl->num_servers; + memcpy(©->expiration_interval, &sl->expiration_interval, + sizeof(grpc_grpclb_duration)); + copy->servers = gpr_malloc(sizeof(grpc_grpclb_server *) * sl->num_servers); + for (size_t i = 0; i < sl->num_servers; i++) { + copy->servers[i] = gpr_malloc(sizeof(grpc_grpclb_server)); + memcpy(copy->servers[i], sl->servers[i], sizeof(grpc_grpclb_server)); + } + return copy; +} + +bool grpc_grpclb_serverlist_equals(const grpc_grpclb_serverlist *lhs, + const grpc_grpclb_serverlist *rhs) { + if (lhs == NULL || rhs == NULL) { + return false; + } + if (lhs->num_servers != rhs->num_servers) { + return false; + } + if (grpc_grpclb_duration_compare(&lhs->expiration_interval, + &rhs->expiration_interval) != 0) { + return false; + } + for (size_t i = 0; i < lhs->num_servers; i++) { + if (!grpc_grpclb_server_equals(lhs->servers[i], rhs->servers[i])) { + return false; + } + } + return true; +} + +bool grpc_grpclb_server_equals(const grpc_grpclb_server *lhs, + const grpc_grpclb_server *rhs) { + return memcmp(lhs, rhs, sizeof(grpc_grpclb_server)) == 0; +} + +int grpc_grpclb_duration_compare(const grpc_grpclb_duration *lhs, + const grpc_grpclb_duration *rhs) { + GPR_ASSERT(lhs && rhs); + if (lhs->has_seconds && rhs->has_seconds) { + if (lhs->seconds < rhs->seconds) return -1; + if (lhs->seconds > rhs->seconds) return 1; + } else if (lhs->has_seconds) { + return 1; + } else if (rhs->has_seconds) { + return -1; + } + + GPR_ASSERT(lhs->seconds == rhs->seconds); + if (lhs->has_nanos && rhs->has_nanos) { + if (lhs->nanos < rhs->nanos) return -1; + if (lhs->nanos > rhs->nanos) return 1; + } else if (lhs->has_nanos) { + return 1; + } else if (rhs->has_nanos) { + return -1; + } + + return 0; +} + +gpr_timespec grpc_grpclb_duration_to_timespec( + grpc_grpclb_duration *duration_pb) { + gpr_timespec duration; + duration.tv_sec = duration_pb->has_seconds ? duration_pb->seconds : 0; + duration.tv_nsec = duration_pb->has_nanos ? duration_pb->nanos : 0; + duration.clock_type = GPR_TIMESPAN; + return duration; +} + +void grpc_grpclb_initial_response_destroy( + grpc_grpclb_initial_response *response) { + gpr_free(response); +} diff --git a/Sources/CgRPC/src/core/ext/lb_policy/grpclb/load_balancer_api.h b/Sources/CgRPC/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h similarity index 55% rename from Sources/CgRPC/src/core/ext/lb_policy/grpclb/load_balancer_api.h rename to Sources/CgRPC/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h index b4c967e42..c4a98492c 100644 --- a/Sources/CgRPC/src/core/ext/lb_policy/grpclb/load_balancer_api.h +++ b/Sources/CgRPC/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h @@ -1,43 +1,29 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 GRPC_CORE_EXT_LB_POLICY_GRPCLB_LOAD_BALANCER_API_H -#define GRPC_CORE_EXT_LB_POLICY_GRPCLB_LOAD_BALANCER_API_H +#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_GRPCLB_LOAD_BALANCER_API_H +#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_GRPCLB_LOAD_BALANCER_API_H #include -#include "src/core/ext/client_channel/lb_policy_factory.h" -#include "src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h" +#include "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h" +#include "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h" +#include "src/core/ext/filters/client_channel/lb_policy_factory.h" #ifdef __cplusplus extern "C" { @@ -50,7 +36,7 @@ typedef grpc_lb_v1_LoadBalanceRequest grpc_grpclb_request; typedef grpc_lb_v1_InitialLoadBalanceResponse grpc_grpclb_initial_response; typedef grpc_lb_v1_Server grpc_grpclb_server; typedef grpc_lb_v1_Duration grpc_grpclb_duration; -typedef struct grpc_grpclb_serverlist { +typedef struct { grpc_grpclb_server **servers; size_t num_servers; grpc_grpclb_duration expiration_interval; @@ -58,6 +44,8 @@ typedef struct grpc_grpclb_serverlist { /** Create a request for a gRPC LB service under \a lb_service_name */ grpc_grpclb_request *grpc_grpclb_request_create(const char *lb_service_name); +grpc_grpclb_request *grpc_grpclb_load_report_request_create_locked( + grpc_grpclb_client_stats *client_stats); /** Protocol Buffers v3-encode \a request */ grpc_slice grpc_grpclb_request_encode(const grpc_grpclb_request *request); @@ -93,6 +81,9 @@ void grpc_grpclb_destroy_serverlist(grpc_grpclb_serverlist *serverlist); int grpc_grpclb_duration_compare(const grpc_grpclb_duration *lhs, const grpc_grpclb_duration *rhs); +gpr_timespec grpc_grpclb_duration_to_timespec( + grpc_grpclb_duration *duration_pb); + /** Destroy \a initial_response */ void grpc_grpclb_initial_response_destroy( grpc_grpclb_initial_response *response); @@ -101,4 +92,5 @@ void grpc_grpclb_initial_response_destroy( } #endif -#endif /* GRPC_CORE_EXT_LB_POLICY_GRPCLB_LOAD_BALANCER_API_H */ +#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_GRPCLB_LOAD_BALANCER_API_H \ + */ diff --git a/Sources/CgRPC/src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c b/Sources/CgRPC/src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c similarity index 55% rename from Sources/CgRPC/src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c rename to Sources/CgRPC/src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c index afecb716f..6a5d54c82 100644 --- a/Sources/CgRPC/src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c +++ b/Sources/CgRPC/src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c @@ -1,39 +1,7 @@ -/* - * - * Copyright 2016, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ /* Automatically generated nanopb constant definitions */ /* Generated by nanopb-0.3.7-dev */ -#include "src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h" +#include "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h" /* @@protoc_insertion_point(includes) */ #if PB_PROTO_HEADER_VERSION != 30 @@ -48,6 +16,12 @@ const pb_field_t grpc_lb_v1_Duration_fields[3] = { PB_LAST_FIELD }; +const pb_field_t grpc_lb_v1_Timestamp_fields[3] = { + PB_FIELD( 1, INT64 , OPTIONAL, STATIC , FIRST, grpc_lb_v1_Timestamp, seconds, seconds, 0), + PB_FIELD( 2, INT32 , OPTIONAL, STATIC , OTHER, grpc_lb_v1_Timestamp, nanos, seconds, 0), + PB_LAST_FIELD +}; + const pb_field_t grpc_lb_v1_LoadBalanceRequest_fields[3] = { PB_FIELD( 1, MESSAGE , OPTIONAL, STATIC , FIRST, grpc_lb_v1_LoadBalanceRequest, initial_request, initial_request, &grpc_lb_v1_InitialLoadBalanceRequest_fields), PB_FIELD( 2, MESSAGE , OPTIONAL, STATIC , OTHER, grpc_lb_v1_LoadBalanceRequest, client_stats, initial_request, &grpc_lb_v1_ClientStats_fields), @@ -59,10 +33,19 @@ const pb_field_t grpc_lb_v1_InitialLoadBalanceRequest_fields[2] = { PB_LAST_FIELD }; -const pb_field_t grpc_lb_v1_ClientStats_fields[4] = { - PB_FIELD( 1, INT64 , OPTIONAL, STATIC , FIRST, grpc_lb_v1_ClientStats, total_requests, total_requests, 0), - PB_FIELD( 2, INT64 , OPTIONAL, STATIC , OTHER, grpc_lb_v1_ClientStats, client_rpc_errors, total_requests, 0), - PB_FIELD( 3, INT64 , OPTIONAL, STATIC , OTHER, grpc_lb_v1_ClientStats, dropped_requests, client_rpc_errors, 0), +const pb_field_t grpc_lb_v1_ClientStatsPerToken_fields[3] = { + PB_FIELD( 1, STRING , OPTIONAL, CALLBACK, FIRST, grpc_lb_v1_ClientStatsPerToken, load_balance_token, load_balance_token, 0), + PB_FIELD( 2, INT64 , OPTIONAL, STATIC , OTHER, grpc_lb_v1_ClientStatsPerToken, num_calls, load_balance_token, 0), + PB_LAST_FIELD +}; + +const pb_field_t grpc_lb_v1_ClientStats_fields[7] = { + PB_FIELD( 1, MESSAGE , OPTIONAL, STATIC , FIRST, grpc_lb_v1_ClientStats, timestamp, timestamp, &grpc_lb_v1_Timestamp_fields), + PB_FIELD( 2, INT64 , OPTIONAL, STATIC , OTHER, grpc_lb_v1_ClientStats, num_calls_started, timestamp, 0), + PB_FIELD( 3, INT64 , OPTIONAL, STATIC , OTHER, grpc_lb_v1_ClientStats, num_calls_finished, num_calls_started, 0), + PB_FIELD( 6, INT64 , OPTIONAL, STATIC , OTHER, grpc_lb_v1_ClientStats, num_calls_finished_with_client_failed_to_send, num_calls_finished, 0), + PB_FIELD( 7, INT64 , OPTIONAL, STATIC , OTHER, grpc_lb_v1_ClientStats, num_calls_finished_known_received, num_calls_finished_with_client_failed_to_send, 0), + PB_FIELD( 8, MESSAGE , REPEATED, CALLBACK, OTHER, grpc_lb_v1_ClientStats, calls_finished_with_drop, num_calls_finished_known_received, &grpc_lb_v1_ClientStatsPerToken_fields), PB_LAST_FIELD }; @@ -88,7 +71,7 @@ const pb_field_t grpc_lb_v1_Server_fields[5] = { PB_FIELD( 1, BYTES , OPTIONAL, STATIC , FIRST, grpc_lb_v1_Server, ip_address, ip_address, 0), PB_FIELD( 2, INT32 , OPTIONAL, STATIC , OTHER, grpc_lb_v1_Server, port, ip_address, 0), PB_FIELD( 3, STRING , OPTIONAL, STATIC , OTHER, grpc_lb_v1_Server, load_balance_token, port, 0), - PB_FIELD( 4, BOOL , OPTIONAL, STATIC , OTHER, grpc_lb_v1_Server, drop_request, load_balance_token, 0), + PB_FIELD( 4, BOOL , OPTIONAL, STATIC , OTHER, grpc_lb_v1_Server, drop, load_balance_token, 0), PB_LAST_FIELD }; @@ -102,7 +85,7 @@ const pb_field_t grpc_lb_v1_Server_fields[5] = { * numbers or field sizes that are larger than what can fit in 8 or 16 bit * field descriptors. */ -PB_STATIC_ASSERT((pb_membersize(grpc_lb_v1_LoadBalanceRequest, initial_request) < 65536 && pb_membersize(grpc_lb_v1_LoadBalanceRequest, client_stats) < 65536 && pb_membersize(grpc_lb_v1_LoadBalanceResponse, initial_response) < 65536 && pb_membersize(grpc_lb_v1_LoadBalanceResponse, server_list) < 65536 && pb_membersize(grpc_lb_v1_InitialLoadBalanceResponse, client_stats_report_interval) < 65536 && pb_membersize(grpc_lb_v1_ServerList, servers) < 65536 && pb_membersize(grpc_lb_v1_ServerList, expiration_interval) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_grpc_lb_v1_Duration_grpc_lb_v1_LoadBalanceRequest_grpc_lb_v1_InitialLoadBalanceRequest_grpc_lb_v1_ClientStats_grpc_lb_v1_LoadBalanceResponse_grpc_lb_v1_InitialLoadBalanceResponse_grpc_lb_v1_ServerList_grpc_lb_v1_Server) +PB_STATIC_ASSERT((pb_membersize(grpc_lb_v1_LoadBalanceRequest, initial_request) < 65536 && pb_membersize(grpc_lb_v1_LoadBalanceRequest, client_stats) < 65536 && pb_membersize(grpc_lb_v1_ClientStats, timestamp) < 65536 && pb_membersize(grpc_lb_v1_ClientStats, calls_finished_with_drop) < 65536 && pb_membersize(grpc_lb_v1_LoadBalanceResponse, initial_response) < 65536 && pb_membersize(grpc_lb_v1_LoadBalanceResponse, server_list) < 65536 && pb_membersize(grpc_lb_v1_InitialLoadBalanceResponse, client_stats_report_interval) < 65536 && pb_membersize(grpc_lb_v1_ServerList, servers) < 65536 && pb_membersize(grpc_lb_v1_ServerList, expiration_interval) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_grpc_lb_v1_Duration_grpc_lb_v1_Timestamp_grpc_lb_v1_LoadBalanceRequest_grpc_lb_v1_InitialLoadBalanceRequest_grpc_lb_v1_ClientStatsPerToken_grpc_lb_v1_ClientStats_grpc_lb_v1_LoadBalanceResponse_grpc_lb_v1_InitialLoadBalanceResponse_grpc_lb_v1_ServerList_grpc_lb_v1_Server) #endif #if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT) @@ -113,7 +96,7 @@ PB_STATIC_ASSERT((pb_membersize(grpc_lb_v1_LoadBalanceRequest, initial_request) * numbers or field sizes that are larger than what can fit in the default * 8 bit descriptors. */ -PB_STATIC_ASSERT((pb_membersize(grpc_lb_v1_LoadBalanceRequest, initial_request) < 256 && pb_membersize(grpc_lb_v1_LoadBalanceRequest, client_stats) < 256 && pb_membersize(grpc_lb_v1_LoadBalanceResponse, initial_response) < 256 && pb_membersize(grpc_lb_v1_LoadBalanceResponse, server_list) < 256 && pb_membersize(grpc_lb_v1_InitialLoadBalanceResponse, client_stats_report_interval) < 256 && pb_membersize(grpc_lb_v1_ServerList, servers) < 256 && pb_membersize(grpc_lb_v1_ServerList, expiration_interval) < 256), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_grpc_lb_v1_Duration_grpc_lb_v1_LoadBalanceRequest_grpc_lb_v1_InitialLoadBalanceRequest_grpc_lb_v1_ClientStats_grpc_lb_v1_LoadBalanceResponse_grpc_lb_v1_InitialLoadBalanceResponse_grpc_lb_v1_ServerList_grpc_lb_v1_Server) +PB_STATIC_ASSERT((pb_membersize(grpc_lb_v1_LoadBalanceRequest, initial_request) < 256 && pb_membersize(grpc_lb_v1_LoadBalanceRequest, client_stats) < 256 && pb_membersize(grpc_lb_v1_ClientStats, timestamp) < 256 && pb_membersize(grpc_lb_v1_ClientStats, calls_finished_with_drop) < 256 && pb_membersize(grpc_lb_v1_LoadBalanceResponse, initial_response) < 256 && pb_membersize(grpc_lb_v1_LoadBalanceResponse, server_list) < 256 && pb_membersize(grpc_lb_v1_InitialLoadBalanceResponse, client_stats_report_interval) < 256 && pb_membersize(grpc_lb_v1_ServerList, servers) < 256 && pb_membersize(grpc_lb_v1_ServerList, expiration_interval) < 256), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_grpc_lb_v1_Duration_grpc_lb_v1_Timestamp_grpc_lb_v1_LoadBalanceRequest_grpc_lb_v1_InitialLoadBalanceRequest_grpc_lb_v1_ClientStatsPerToken_grpc_lb_v1_ClientStats_grpc_lb_v1_LoadBalanceResponse_grpc_lb_v1_InitialLoadBalanceResponse_grpc_lb_v1_ServerList_grpc_lb_v1_Server) #endif diff --git a/Sources/CgRPC/src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h b/Sources/CgRPC/src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h similarity index 69% rename from Sources/CgRPC/src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h rename to Sources/CgRPC/src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h index e36d0966f..93333d1ae 100644 --- a/Sources/CgRPC/src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h +++ b/Sources/CgRPC/src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h @@ -1,35 +1,3 @@ -/* - * - * Copyright 2016, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ /* Automatically generated nanopb header */ /* Generated by nanopb-0.3.7-dev */ @@ -46,15 +14,12 @@ extern "C" { #endif /* Struct definitions */ -typedef struct _grpc_lb_v1_ClientStats { - bool has_total_requests; - int64_t total_requests; - bool has_client_rpc_errors; - int64_t client_rpc_errors; - bool has_dropped_requests; - int64_t dropped_requests; -/* @@protoc_insertion_point(struct:grpc_lb_v1_ClientStats) */ -} grpc_lb_v1_ClientStats; +typedef struct _grpc_lb_v1_ClientStatsPerToken { + pb_callback_t load_balance_token; + bool has_num_calls; + int64_t num_calls; +/* @@protoc_insertion_point(struct:grpc_lb_v1_ClientStatsPerToken) */ +} grpc_lb_v1_ClientStatsPerToken; typedef struct _grpc_lb_v1_Duration { bool has_seconds; @@ -78,11 +43,34 @@ typedef struct _grpc_lb_v1_Server { int32_t port; bool has_load_balance_token; char load_balance_token[50]; - bool has_drop_request; - bool drop_request; + bool has_drop; + bool drop; /* @@protoc_insertion_point(struct:grpc_lb_v1_Server) */ } grpc_lb_v1_Server; +typedef struct _grpc_lb_v1_Timestamp { + bool has_seconds; + int64_t seconds; + bool has_nanos; + int32_t nanos; +/* @@protoc_insertion_point(struct:grpc_lb_v1_Timestamp) */ +} grpc_lb_v1_Timestamp; + +typedef struct _grpc_lb_v1_ClientStats { + bool has_timestamp; + grpc_lb_v1_Timestamp timestamp; + bool has_num_calls_started; + int64_t num_calls_started; + bool has_num_calls_finished; + int64_t num_calls_finished; + bool has_num_calls_finished_with_client_failed_to_send; + int64_t num_calls_finished_with_client_failed_to_send; + bool has_num_calls_finished_known_received; + int64_t num_calls_finished_known_received; + pb_callback_t calls_finished_with_drop; +/* @@protoc_insertion_point(struct:grpc_lb_v1_ClientStats) */ +} grpc_lb_v1_ClientStats; + typedef struct _grpc_lb_v1_InitialLoadBalanceResponse { bool has_load_balancer_delegate; char load_balancer_delegate[64]; @@ -91,6 +79,13 @@ typedef struct _grpc_lb_v1_InitialLoadBalanceResponse { /* @@protoc_insertion_point(struct:grpc_lb_v1_InitialLoadBalanceResponse) */ } grpc_lb_v1_InitialLoadBalanceResponse; +typedef struct _grpc_lb_v1_ServerList { + pb_callback_t servers; + bool has_expiration_interval; + grpc_lb_v1_Duration expiration_interval; +/* @@protoc_insertion_point(struct:grpc_lb_v1_ServerList) */ +} grpc_lb_v1_ServerList; + typedef struct _grpc_lb_v1_LoadBalanceRequest { bool has_initial_request; grpc_lb_v1_InitialLoadBalanceRequest initial_request; @@ -99,13 +94,6 @@ typedef struct _grpc_lb_v1_LoadBalanceRequest { /* @@protoc_insertion_point(struct:grpc_lb_v1_LoadBalanceRequest) */ } grpc_lb_v1_LoadBalanceRequest; -typedef struct _grpc_lb_v1_ServerList { - pb_callback_t servers; - bool has_expiration_interval; - grpc_lb_v1_Duration expiration_interval; -/* @@protoc_insertion_point(struct:grpc_lb_v1_ServerList) */ -} grpc_lb_v1_ServerList; - typedef struct _grpc_lb_v1_LoadBalanceResponse { bool has_initial_response; grpc_lb_v1_InitialLoadBalanceResponse initial_response; @@ -118,47 +106,60 @@ typedef struct _grpc_lb_v1_LoadBalanceResponse { /* Initializer values for message structs */ #define grpc_lb_v1_Duration_init_default {false, 0, false, 0} +#define grpc_lb_v1_Timestamp_init_default {false, 0, false, 0} #define grpc_lb_v1_LoadBalanceRequest_init_default {false, grpc_lb_v1_InitialLoadBalanceRequest_init_default, false, grpc_lb_v1_ClientStats_init_default} #define grpc_lb_v1_InitialLoadBalanceRequest_init_default {false, ""} -#define grpc_lb_v1_ClientStats_init_default {false, 0, false, 0, false, 0} +#define grpc_lb_v1_ClientStatsPerToken_init_default {{{NULL}, NULL}, false, 0} +#define grpc_lb_v1_ClientStats_init_default {false, grpc_lb_v1_Timestamp_init_default, false, 0, false, 0, false, 0, false, 0, {{NULL}, NULL}} #define grpc_lb_v1_LoadBalanceResponse_init_default {false, grpc_lb_v1_InitialLoadBalanceResponse_init_default, false, grpc_lb_v1_ServerList_init_default} #define grpc_lb_v1_InitialLoadBalanceResponse_init_default {false, "", false, grpc_lb_v1_Duration_init_default} #define grpc_lb_v1_ServerList_init_default {{{NULL}, NULL}, false, grpc_lb_v1_Duration_init_default} #define grpc_lb_v1_Server_init_default {false, {0, {0}}, false, 0, false, "", false, 0} #define grpc_lb_v1_Duration_init_zero {false, 0, false, 0} +#define grpc_lb_v1_Timestamp_init_zero {false, 0, false, 0} #define grpc_lb_v1_LoadBalanceRequest_init_zero {false, grpc_lb_v1_InitialLoadBalanceRequest_init_zero, false, grpc_lb_v1_ClientStats_init_zero} #define grpc_lb_v1_InitialLoadBalanceRequest_init_zero {false, ""} -#define grpc_lb_v1_ClientStats_init_zero {false, 0, false, 0, false, 0} +#define grpc_lb_v1_ClientStatsPerToken_init_zero {{{NULL}, NULL}, false, 0} +#define grpc_lb_v1_ClientStats_init_zero {false, grpc_lb_v1_Timestamp_init_zero, false, 0, false, 0, false, 0, false, 0, {{NULL}, NULL}} #define grpc_lb_v1_LoadBalanceResponse_init_zero {false, grpc_lb_v1_InitialLoadBalanceResponse_init_zero, false, grpc_lb_v1_ServerList_init_zero} #define grpc_lb_v1_InitialLoadBalanceResponse_init_zero {false, "", false, grpc_lb_v1_Duration_init_zero} #define grpc_lb_v1_ServerList_init_zero {{{NULL}, NULL}, false, grpc_lb_v1_Duration_init_zero} #define grpc_lb_v1_Server_init_zero {false, {0, {0}}, false, 0, false, "", false, 0} /* Field tags (for use in manual encoding/decoding) */ -#define grpc_lb_v1_ClientStats_total_requests_tag 1 -#define grpc_lb_v1_ClientStats_client_rpc_errors_tag 2 -#define grpc_lb_v1_ClientStats_dropped_requests_tag 3 +#define grpc_lb_v1_ClientStatsPerToken_load_balance_token_tag 1 +#define grpc_lb_v1_ClientStatsPerToken_num_calls_tag 2 #define grpc_lb_v1_Duration_seconds_tag 1 #define grpc_lb_v1_Duration_nanos_tag 2 #define grpc_lb_v1_InitialLoadBalanceRequest_name_tag 1 #define grpc_lb_v1_Server_ip_address_tag 1 #define grpc_lb_v1_Server_port_tag 2 #define grpc_lb_v1_Server_load_balance_token_tag 3 -#define grpc_lb_v1_Server_drop_request_tag 4 +#define grpc_lb_v1_Server_drop_tag 4 +#define grpc_lb_v1_Timestamp_seconds_tag 1 +#define grpc_lb_v1_Timestamp_nanos_tag 2 +#define grpc_lb_v1_ClientStats_timestamp_tag 1 +#define grpc_lb_v1_ClientStats_num_calls_started_tag 2 +#define grpc_lb_v1_ClientStats_num_calls_finished_tag 3 +#define grpc_lb_v1_ClientStats_num_calls_finished_with_client_failed_to_send_tag 6 +#define grpc_lb_v1_ClientStats_num_calls_finished_known_received_tag 7 +#define grpc_lb_v1_ClientStats_calls_finished_with_drop_tag 8 #define grpc_lb_v1_InitialLoadBalanceResponse_load_balancer_delegate_tag 1 #define grpc_lb_v1_InitialLoadBalanceResponse_client_stats_report_interval_tag 2 -#define grpc_lb_v1_LoadBalanceRequest_initial_request_tag 1 -#define grpc_lb_v1_LoadBalanceRequest_client_stats_tag 2 #define grpc_lb_v1_ServerList_servers_tag 1 #define grpc_lb_v1_ServerList_expiration_interval_tag 3 +#define grpc_lb_v1_LoadBalanceRequest_initial_request_tag 1 +#define grpc_lb_v1_LoadBalanceRequest_client_stats_tag 2 #define grpc_lb_v1_LoadBalanceResponse_initial_response_tag 1 #define grpc_lb_v1_LoadBalanceResponse_server_list_tag 2 /* Struct field encoding specification for nanopb */ extern const pb_field_t grpc_lb_v1_Duration_fields[3]; +extern const pb_field_t grpc_lb_v1_Timestamp_fields[3]; extern const pb_field_t grpc_lb_v1_LoadBalanceRequest_fields[3]; extern const pb_field_t grpc_lb_v1_InitialLoadBalanceRequest_fields[2]; -extern const pb_field_t grpc_lb_v1_ClientStats_fields[4]; +extern const pb_field_t grpc_lb_v1_ClientStatsPerToken_fields[3]; +extern const pb_field_t grpc_lb_v1_ClientStats_fields[7]; extern const pb_field_t grpc_lb_v1_LoadBalanceResponse_fields[3]; extern const pb_field_t grpc_lb_v1_InitialLoadBalanceResponse_fields[3]; extern const pb_field_t grpc_lb_v1_ServerList_fields[3]; @@ -166,9 +167,11 @@ extern const pb_field_t grpc_lb_v1_Server_fields[5]; /* Maximum encoded size of messages (where known) */ #define grpc_lb_v1_Duration_size 22 -#define grpc_lb_v1_LoadBalanceRequest_size 169 +#define grpc_lb_v1_Timestamp_size 22 +#define grpc_lb_v1_LoadBalanceRequest_size (140 + grpc_lb_v1_ClientStats_size) #define grpc_lb_v1_InitialLoadBalanceRequest_size 131 -#define grpc_lb_v1_ClientStats_size 33 +/* grpc_lb_v1_ClientStatsPerToken_size depends on runtime parameters */ +/* grpc_lb_v1_ClientStats_size depends on runtime parameters */ #define grpc_lb_v1_LoadBalanceResponse_size (98 + grpc_lb_v1_ServerList_size) #define grpc_lb_v1_InitialLoadBalanceResponse_size 90 /* grpc_lb_v1_ServerList_size depends on runtime parameters */ diff --git a/Sources/CgRPC/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.c b/Sources/CgRPC/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.c new file mode 100644 index 000000000..fd0fb41fb --- /dev/null +++ b/Sources/CgRPC/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.c @@ -0,0 +1,714 @@ +/* + * + * 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 + +#include + +#include "src/core/ext/filters/client_channel/lb_policy_registry.h" +#include "src/core/ext/filters/client_channel/subchannel.h" +#include "src/core/ext/filters/client_channel/subchannel_index.h" +#include "src/core/lib/channel/channel_args.h" +#include "src/core/lib/iomgr/combiner.h" +#include "src/core/lib/iomgr/sockaddr_utils.h" +#include "src/core/lib/transport/connectivity_state.h" + +grpc_tracer_flag grpc_lb_pick_first_trace = + GRPC_TRACER_INITIALIZER(false, "pick_first"); + +typedef struct pending_pick { + struct pending_pick *next; + uint32_t initial_metadata_flags; + grpc_connected_subchannel **target; + grpc_closure *on_complete; +} pending_pick; + +typedef struct { + /** base policy: must be first */ + grpc_lb_policy base; + /** all our subchannels */ + grpc_subchannel **subchannels; + grpc_subchannel **new_subchannels; + size_t num_subchannels; + size_t num_new_subchannels; + + grpc_closure connectivity_changed; + + /** remaining members are protected by the combiner */ + + /** the selected channel */ + grpc_connected_subchannel *selected; + + /** the subchannel key for \a selected, or NULL if \a selected not set */ + const grpc_subchannel_key *selected_key; + + /** have we started picking? */ + bool started_picking; + /** are we shut down? */ + bool shutdown; + /** are we updating the selected subchannel? */ + bool updating_selected; + /** are we updating the subchannel candidates? */ + bool updating_subchannels; + /** args from the latest update received while already updating, or NULL */ + grpc_lb_policy_args *pending_update_args; + /** which subchannel are we watching? */ + size_t checking_subchannel; + /** what is the connectivity of that channel? */ + grpc_connectivity_state checking_connectivity; + /** list of picks that are waiting on connectivity */ + pending_pick *pending_picks; + + /** our connectivity state tracker */ + grpc_connectivity_state_tracker state_tracker; +} pick_first_lb_policy; + +static void pf_destroy(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) { + pick_first_lb_policy *p = (pick_first_lb_policy *)pol; + GPR_ASSERT(p->pending_picks == NULL); + for (size_t i = 0; i < p->num_subchannels; i++) { + GRPC_SUBCHANNEL_UNREF(exec_ctx, p->subchannels[i], "pick_first_destroy"); + } + if (p->selected != NULL) { + GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, p->selected, + "picked_first_destroy"); + } + grpc_connectivity_state_destroy(exec_ctx, &p->state_tracker); + if (p->pending_update_args != NULL) { + grpc_channel_args_destroy(exec_ctx, p->pending_update_args->args); + gpr_free(p->pending_update_args); + } + gpr_free(p->subchannels); + gpr_free(p->new_subchannels); + gpr_free(p); + if (GRPC_TRACER_ON(grpc_lb_pick_first_trace)) { + gpr_log(GPR_DEBUG, "Pick First %p destroyed.", (void *)p); + } +} + +static void pf_shutdown_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) { + pick_first_lb_policy *p = (pick_first_lb_policy *)pol; + pending_pick *pp; + p->shutdown = true; + pp = p->pending_picks; + p->pending_picks = NULL; + grpc_connectivity_state_set( + exec_ctx, &p->state_tracker, GRPC_CHANNEL_SHUTDOWN, + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Channel shutdown"), "shutdown"); + /* cancel subscription */ + if (p->selected != NULL) { + grpc_connected_subchannel_notify_on_state_change( + exec_ctx, p->selected, NULL, NULL, &p->connectivity_changed); + } else if (p->num_subchannels > 0 && p->started_picking) { + grpc_subchannel_notify_on_state_change( + exec_ctx, p->subchannels[p->checking_subchannel], NULL, NULL, + &p->connectivity_changed); + } + while (pp != NULL) { + pending_pick *next = pp->next; + *pp->target = NULL; + GRPC_CLOSURE_SCHED(exec_ctx, pp->on_complete, GRPC_ERROR_NONE); + gpr_free(pp); + pp = next; + } +} + +static void pf_cancel_pick_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, + grpc_connected_subchannel **target, + grpc_error *error) { + pick_first_lb_policy *p = (pick_first_lb_policy *)pol; + pending_pick *pp; + pp = p->pending_picks; + p->pending_picks = NULL; + while (pp != NULL) { + pending_pick *next = pp->next; + if (pp->target == target) { + *target = NULL; + GRPC_CLOSURE_SCHED(exec_ctx, pp->on_complete, + GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( + "Pick Cancelled", &error, 1)); + gpr_free(pp); + } else { + pp->next = p->pending_picks; + p->pending_picks = pp; + } + pp = next; + } + GRPC_ERROR_UNREF(error); +} + +static void pf_cancel_picks_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, + uint32_t initial_metadata_flags_mask, + uint32_t initial_metadata_flags_eq, + grpc_error *error) { + pick_first_lb_policy *p = (pick_first_lb_policy *)pol; + pending_pick *pp; + pp = p->pending_picks; + p->pending_picks = NULL; + while (pp != NULL) { + pending_pick *next = pp->next; + if ((pp->initial_metadata_flags & initial_metadata_flags_mask) == + initial_metadata_flags_eq) { + GRPC_CLOSURE_SCHED(exec_ctx, pp->on_complete, + GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( + "Pick Cancelled", &error, 1)); + gpr_free(pp); + } else { + pp->next = p->pending_picks; + p->pending_picks = pp; + } + pp = next; + } + GRPC_ERROR_UNREF(error); +} + +static void start_picking_locked(grpc_exec_ctx *exec_ctx, + pick_first_lb_policy *p) { + p->started_picking = true; + if (p->subchannels != NULL) { + GPR_ASSERT(p->num_subchannels > 0); + p->checking_subchannel = 0; + p->checking_connectivity = GRPC_CHANNEL_IDLE; + GRPC_LB_POLICY_WEAK_REF(&p->base, "pick_first_connectivity"); + grpc_subchannel_notify_on_state_change( + exec_ctx, p->subchannels[p->checking_subchannel], + p->base.interested_parties, &p->checking_connectivity, + &p->connectivity_changed); + } +} + +static void pf_exit_idle_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) { + pick_first_lb_policy *p = (pick_first_lb_policy *)pol; + if (!p->started_picking) { + start_picking_locked(exec_ctx, p); + } +} + +static int pf_pick_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, + const grpc_lb_policy_pick_args *pick_args, + grpc_connected_subchannel **target, + grpc_call_context_element *context, void **user_data, + grpc_closure *on_complete) { + pick_first_lb_policy *p = (pick_first_lb_policy *)pol; + pending_pick *pp; + + /* Check atomically for a selected channel */ + if (p->selected != NULL) { + *target = GRPC_CONNECTED_SUBCHANNEL_REF(p->selected, "picked"); + return 1; + } + + /* No subchannel selected yet, so try again */ + if (!p->started_picking) { + start_picking_locked(exec_ctx, p); + } + pp = gpr_malloc(sizeof(*pp)); + pp->next = p->pending_picks; + pp->target = target; + pp->initial_metadata_flags = pick_args->initial_metadata_flags; + pp->on_complete = on_complete; + p->pending_picks = pp; + return 0; +} + +static void destroy_subchannels_locked(grpc_exec_ctx *exec_ctx, + pick_first_lb_policy *p) { + size_t num_subchannels = p->num_subchannels; + grpc_subchannel **subchannels = p->subchannels; + + p->num_subchannels = 0; + p->subchannels = NULL; + GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "destroy_subchannels"); + + for (size_t i = 0; i < num_subchannels; i++) { + GRPC_SUBCHANNEL_UNREF(exec_ctx, subchannels[i], "pick_first"); + } + gpr_free(subchannels); +} + +static grpc_connectivity_state pf_check_connectivity_locked( + grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, grpc_error **error) { + pick_first_lb_policy *p = (pick_first_lb_policy *)pol; + return grpc_connectivity_state_get(&p->state_tracker, error); +} + +static void pf_notify_on_state_change_locked(grpc_exec_ctx *exec_ctx, + grpc_lb_policy *pol, + grpc_connectivity_state *current, + grpc_closure *notify) { + pick_first_lb_policy *p = (pick_first_lb_policy *)pol; + grpc_connectivity_state_notify_on_state_change(exec_ctx, &p->state_tracker, + current, notify); +} + +static void pf_ping_one_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, + grpc_closure *closure) { + pick_first_lb_policy *p = (pick_first_lb_policy *)pol; + if (p->selected) { + grpc_connected_subchannel_ping(exec_ctx, p->selected, closure); + } else { + GRPC_CLOSURE_SCHED(exec_ctx, closure, + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Not connected")); + } +} + +/* unsubscribe all subchannels */ +static void stop_connectivity_watchers(grpc_exec_ctx *exec_ctx, + pick_first_lb_policy *p) { + if (p->num_subchannels > 0) { + GPR_ASSERT(p->selected == NULL); + if (GRPC_TRACER_ON(grpc_lb_pick_first_trace)) { + gpr_log(GPR_DEBUG, "Pick First %p unsubscribing from subchannel %p", + (void *)p, (void *)p->subchannels[p->checking_subchannel]); + } + grpc_subchannel_notify_on_state_change( + exec_ctx, p->subchannels[p->checking_subchannel], NULL, NULL, + &p->connectivity_changed); + p->updating_subchannels = true; + } else if (p->selected != NULL) { + if (GRPC_TRACER_ON(grpc_lb_pick_first_trace)) { + gpr_log(GPR_DEBUG, + "Pick First %p unsubscribing from selected subchannel %p", + (void *)p, (void *)p->selected); + } + grpc_connected_subchannel_notify_on_state_change( + exec_ctx, p->selected, NULL, NULL, &p->connectivity_changed); + p->updating_selected = true; + } +} + +/* true upon success */ +static void pf_update_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, + const grpc_lb_policy_args *args) { + pick_first_lb_policy *p = (pick_first_lb_policy *)policy; + /* Find the number of backend addresses. We ignore balancer + * addresses, since we don't know how to handle them. */ + const grpc_arg *arg = + grpc_channel_args_find(args->args, GRPC_ARG_LB_ADDRESSES); + if (arg == NULL || arg->type != GRPC_ARG_POINTER) { + if (p->subchannels == NULL) { + // If we don't have a current subchannel list, go into TRANSIENT FAILURE. + grpc_connectivity_state_set( + exec_ctx, &p->state_tracker, GRPC_CHANNEL_TRANSIENT_FAILURE, + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Missing update in args"), + "pf_update_missing"); + } else { + // otherwise, keep using the current subchannel list (ignore this update). + gpr_log(GPR_ERROR, + "No valid LB addresses channel arg for Pick First %p update, " + "ignoring.", + (void *)p); + } + return; + } + const grpc_lb_addresses *addresses = arg->value.pointer.p; + size_t num_addrs = 0; + for (size_t i = 0; i < addresses->num_addresses; i++) { + if (!addresses->addresses[i].is_balancer) ++num_addrs; + } + if (num_addrs == 0) { + // Empty update. Unsubscribe from all current subchannels and put the + // channel in TRANSIENT_FAILURE. + grpc_connectivity_state_set( + exec_ctx, &p->state_tracker, GRPC_CHANNEL_TRANSIENT_FAILURE, + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Empty update"), + "pf_update_empty"); + stop_connectivity_watchers(exec_ctx, p); + return; + } + if (GRPC_TRACER_ON(grpc_lb_pick_first_trace)) { + gpr_log(GPR_INFO, "Pick First %p received update with %lu addresses", + (void *)p, (unsigned long)num_addrs); + } + grpc_subchannel_args *sc_args = gpr_zalloc(sizeof(*sc_args) * num_addrs); + /* We remove the following keys in order for subchannel keys belonging to + * subchannels point to the same address to match. */ + static const char *keys_to_remove[] = {GRPC_ARG_SUBCHANNEL_ADDRESS, + GRPC_ARG_LB_ADDRESSES}; + size_t sc_args_count = 0; + + /* Create list of subchannel args for new addresses in \a args. */ + for (size_t i = 0; i < addresses->num_addresses; i++) { + if (addresses->addresses[i].is_balancer) continue; + if (addresses->addresses[i].user_data != NULL) { + gpr_log(GPR_ERROR, + "This LB policy doesn't support user data. It will be ignored"); + } + grpc_arg addr_arg = + grpc_create_subchannel_address_arg(&addresses->addresses[i].address); + grpc_channel_args *new_args = grpc_channel_args_copy_and_add_and_remove( + args->args, keys_to_remove, GPR_ARRAY_SIZE(keys_to_remove), &addr_arg, + 1); + gpr_free(addr_arg.value.string); + sc_args[sc_args_count++].args = new_args; + } + + /* Check if p->selected is amongst them. If so, we are done. */ + if (p->selected != NULL) { + GPR_ASSERT(p->selected_key != NULL); + for (size_t i = 0; i < sc_args_count; i++) { + grpc_subchannel_key *ith_sc_key = grpc_subchannel_key_create(&sc_args[i]); + const bool found_selected = + grpc_subchannel_key_compare(p->selected_key, ith_sc_key) == 0; + grpc_subchannel_key_destroy(exec_ctx, ith_sc_key); + if (found_selected) { + // The currently selected subchannel is in the update: we are done. + if (GRPC_TRACER_ON(grpc_lb_pick_first_trace)) { + gpr_log(GPR_INFO, + "Pick First %p found already selected subchannel %p amongst " + "updates. Update done.", + (void *)p, (void *)p->selected); + } + for (size_t j = 0; j < sc_args_count; j++) { + grpc_channel_args_destroy(exec_ctx, + (grpc_channel_args *)sc_args[j].args); + } + gpr_free(sc_args); + return; + } + } + } + // We only check for already running updates here because if the previous + // steps were successful, the update can be considered done without any + // interference (ie, no callbacks were scheduled). + if (p->updating_selected || p->updating_subchannels) { + if (GRPC_TRACER_ON(grpc_lb_pick_first_trace)) { + gpr_log(GPR_INFO, + "Update already in progress for pick first %p. Deferring update.", + (void *)p); + } + if (p->pending_update_args != NULL) { + grpc_channel_args_destroy(exec_ctx, p->pending_update_args->args); + gpr_free(p->pending_update_args); + } + p->pending_update_args = gpr_zalloc(sizeof(*p->pending_update_args)); + p->pending_update_args->client_channel_factory = + args->client_channel_factory; + p->pending_update_args->args = grpc_channel_args_copy(args->args); + p->pending_update_args->combiner = args->combiner; + return; + } + /* Create the subchannels for the new subchannel args/addresses. */ + grpc_subchannel **new_subchannels = + gpr_zalloc(sizeof(*new_subchannels) * sc_args_count); + size_t num_new_subchannels = 0; + for (size_t i = 0; i < sc_args_count; i++) { + grpc_subchannel *subchannel = grpc_client_channel_factory_create_subchannel( + exec_ctx, args->client_channel_factory, &sc_args[i]); + if (GRPC_TRACER_ON(grpc_lb_pick_first_trace)) { + char *address_uri = + grpc_sockaddr_to_uri(&addresses->addresses[i].address); + gpr_log(GPR_INFO, + "Pick First %p created subchannel %p for address uri %s", + (void *)p, (void *)subchannel, address_uri); + gpr_free(address_uri); + } + grpc_channel_args_destroy(exec_ctx, (grpc_channel_args *)sc_args[i].args); + if (subchannel != NULL) new_subchannels[num_new_subchannels++] = subchannel; + } + gpr_free(sc_args); + if (num_new_subchannels == 0) { + gpr_free(new_subchannels); + // Empty update. Unsubscribe from all current subchannels and put the + // channel in TRANSIENT_FAILURE. + grpc_connectivity_state_set( + exec_ctx, &p->state_tracker, GRPC_CHANNEL_TRANSIENT_FAILURE, + GRPC_ERROR_CREATE_FROM_STATIC_STRING("No valid addresses in update"), + "pf_update_no_valid_addresses"); + stop_connectivity_watchers(exec_ctx, p); + return; + } + + /* Destroy the current subchannels. Repurpose pf_shutdown/destroy. */ + stop_connectivity_watchers(exec_ctx, p); + + /* Save new subchannels. The switch over will happen in + * pf_connectivity_changed_locked */ + if (p->updating_selected || p->updating_subchannels) { + p->num_new_subchannels = num_new_subchannels; + p->new_subchannels = new_subchannels; + } else { /* nothing is updating. Get things moving from here */ + p->num_subchannels = num_new_subchannels; + p->subchannels = new_subchannels; + p->new_subchannels = NULL; + p->num_new_subchannels = 0; + if (p->started_picking) { + p->checking_subchannel = 0; + p->checking_connectivity = GRPC_CHANNEL_IDLE; + grpc_subchannel_notify_on_state_change( + exec_ctx, p->subchannels[p->checking_subchannel], + p->base.interested_parties, &p->checking_connectivity, + &p->connectivity_changed); + } + } +} + +static void pf_connectivity_changed_locked(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error) { + pick_first_lb_policy *p = arg; + grpc_subchannel *selected_subchannel; + pending_pick *pp; + + if (GRPC_TRACER_ON(grpc_lb_pick_first_trace)) { + gpr_log( + GPR_DEBUG, + "Pick First %p connectivity changed. Updating selected: %d; Updating " + "subchannels: %d; Checking %lu index (%lu total); State: %d; ", + (void *)p, p->updating_selected, p->updating_subchannels, + (unsigned long)p->checking_subchannel, + (unsigned long)p->num_subchannels, p->checking_connectivity); + } + bool restart = false; + if (p->updating_selected && error != GRPC_ERROR_NONE) { + /* Captured the unsubscription for p->selected */ + GPR_ASSERT(p->selected != NULL); + GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, p->selected, + "pf_update_connectivity"); + if (GRPC_TRACER_ON(grpc_lb_pick_first_trace)) { + gpr_log(GPR_DEBUG, "Pick First %p unreffing selected subchannel %p", + (void *)p, (void *)p->selected); + } + p->updating_selected = false; + if (p->num_new_subchannels == 0) { + p->selected = NULL; + return; + } + restart = true; + } + if (p->updating_subchannels && error != GRPC_ERROR_NONE) { + /* Captured the unsubscription for the checking subchannel */ + GPR_ASSERT(p->selected == NULL); + for (size_t i = 0; i < p->num_subchannels; i++) { + GRPC_SUBCHANNEL_UNREF(exec_ctx, p->subchannels[i], + "pf_update_connectivity"); + if (GRPC_TRACER_ON(grpc_lb_pick_first_trace)) { + gpr_log(GPR_DEBUG, "Pick First %p unreffing subchannel %p", (void *)p, + (void *)p->subchannels[i]); + } + } + gpr_free(p->subchannels); + p->subchannels = NULL; + p->num_subchannels = 0; + p->updating_subchannels = false; + if (p->num_new_subchannels == 0) return; + restart = true; + } + if (restart) { + p->selected = NULL; + p->selected_key = NULL; + GPR_ASSERT(p->new_subchannels != NULL); + GPR_ASSERT(p->num_new_subchannels > 0); + p->num_subchannels = p->num_new_subchannels; + p->subchannels = p->new_subchannels; + p->num_new_subchannels = 0; + p->new_subchannels = NULL; + if (p->started_picking) { + /* If we were picking, continue to do so over the new subchannels, + * starting from the 0th index. */ + p->checking_subchannel = 0; + p->checking_connectivity = GRPC_CHANNEL_IDLE; + /* reuses the weak ref from start_picking_locked */ + grpc_subchannel_notify_on_state_change( + exec_ctx, p->subchannels[p->checking_subchannel], + p->base.interested_parties, &p->checking_connectivity, + &p->connectivity_changed); + } + if (p->pending_update_args != NULL) { + const grpc_lb_policy_args *args = p->pending_update_args; + p->pending_update_args = NULL; + pf_update_locked(exec_ctx, &p->base, args); + } + return; + } + GRPC_ERROR_REF(error); + if (p->shutdown) { + GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "pick_first_connectivity"); + GRPC_ERROR_UNREF(error); + return; + } else if (p->selected != NULL) { + if (p->checking_connectivity == GRPC_CHANNEL_TRANSIENT_FAILURE) { + /* if the selected channel goes bad, we're done */ + p->checking_connectivity = GRPC_CHANNEL_SHUTDOWN; + } + grpc_connectivity_state_set(exec_ctx, &p->state_tracker, + p->checking_connectivity, GRPC_ERROR_REF(error), + "selected_changed"); + if (p->checking_connectivity != GRPC_CHANNEL_SHUTDOWN) { + grpc_connected_subchannel_notify_on_state_change( + exec_ctx, p->selected, p->base.interested_parties, + &p->checking_connectivity, &p->connectivity_changed); + } else { + GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "pick_first_connectivity"); + } + } else { + loop: + switch (p->checking_connectivity) { + case GRPC_CHANNEL_INIT: + GPR_UNREACHABLE_CODE(return ); + case GRPC_CHANNEL_READY: + grpc_connectivity_state_set(exec_ctx, &p->state_tracker, + GRPC_CHANNEL_READY, GRPC_ERROR_NONE, + "connecting_ready"); + selected_subchannel = p->subchannels[p->checking_subchannel]; + p->selected = GRPC_CONNECTED_SUBCHANNEL_REF( + grpc_subchannel_get_connected_subchannel(selected_subchannel), + "picked_first"); + + if (GRPC_TRACER_ON(grpc_lb_pick_first_trace)) { + gpr_log(GPR_INFO, + "Pick First %p selected subchannel %p (connected %p)", + (void *)p, (void *)selected_subchannel, (void *)p->selected); + } + p->selected_key = grpc_subchannel_get_key(selected_subchannel); + /* drop the pick list: we are connected now */ + GRPC_LB_POLICY_WEAK_REF(&p->base, "destroy_subchannels"); + destroy_subchannels_locked(exec_ctx, p); + /* update any calls that were waiting for a pick */ + while ((pp = p->pending_picks)) { + p->pending_picks = pp->next; + *pp->target = GRPC_CONNECTED_SUBCHANNEL_REF(p->selected, "picked"); + if (GRPC_TRACER_ON(grpc_lb_pick_first_trace)) { + gpr_log(GPR_INFO, + "Servicing pending pick with selected subchannel %p", + (void *)p->selected); + } + GRPC_CLOSURE_SCHED(exec_ctx, pp->on_complete, GRPC_ERROR_NONE); + gpr_free(pp); + } + grpc_connected_subchannel_notify_on_state_change( + exec_ctx, p->selected, p->base.interested_parties, + &p->checking_connectivity, &p->connectivity_changed); + break; + case GRPC_CHANNEL_TRANSIENT_FAILURE: + p->checking_subchannel = + (p->checking_subchannel + 1) % p->num_subchannels; + if (p->checking_subchannel == 0) { + /* only trigger transient failure when we've tried all alternatives + */ + grpc_connectivity_state_set( + exec_ctx, &p->state_tracker, GRPC_CHANNEL_TRANSIENT_FAILURE, + GRPC_ERROR_REF(error), "connecting_transient_failure"); + } + GRPC_ERROR_UNREF(error); + p->checking_connectivity = grpc_subchannel_check_connectivity( + p->subchannels[p->checking_subchannel], &error); + if (p->checking_connectivity == GRPC_CHANNEL_TRANSIENT_FAILURE) { + grpc_subchannel_notify_on_state_change( + exec_ctx, p->subchannels[p->checking_subchannel], + p->base.interested_parties, &p->checking_connectivity, + &p->connectivity_changed); + } else { + goto loop; + } + break; + case GRPC_CHANNEL_CONNECTING: + case GRPC_CHANNEL_IDLE: + grpc_connectivity_state_set( + exec_ctx, &p->state_tracker, GRPC_CHANNEL_CONNECTING, + GRPC_ERROR_REF(error), "connecting_changed"); + grpc_subchannel_notify_on_state_change( + exec_ctx, p->subchannels[p->checking_subchannel], + p->base.interested_parties, &p->checking_connectivity, + &p->connectivity_changed); + break; + case GRPC_CHANNEL_SHUTDOWN: + p->num_subchannels--; + GPR_SWAP(grpc_subchannel *, p->subchannels[p->checking_subchannel], + p->subchannels[p->num_subchannels]); + GRPC_SUBCHANNEL_UNREF(exec_ctx, p->subchannels[p->num_subchannels], + "pick_first"); + if (p->num_subchannels == 0) { + grpc_connectivity_state_set( + exec_ctx, &p->state_tracker, GRPC_CHANNEL_SHUTDOWN, + GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( + "Pick first exhausted channels", &error, 1), + "no_more_channels"); + while ((pp = p->pending_picks)) { + p->pending_picks = pp->next; + *pp->target = NULL; + GRPC_CLOSURE_SCHED(exec_ctx, pp->on_complete, GRPC_ERROR_NONE); + gpr_free(pp); + } + GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, + "pick_first_connectivity"); + } else { + grpc_connectivity_state_set( + exec_ctx, &p->state_tracker, GRPC_CHANNEL_TRANSIENT_FAILURE, + GRPC_ERROR_REF(error), "subchannel_failed"); + p->checking_subchannel %= p->num_subchannels; + GRPC_ERROR_UNREF(error); + p->checking_connectivity = grpc_subchannel_check_connectivity( + p->subchannels[p->checking_subchannel], &error); + goto loop; + } + } + } + + GRPC_ERROR_UNREF(error); +} + +static const grpc_lb_policy_vtable pick_first_lb_policy_vtable = { + pf_destroy, + pf_shutdown_locked, + pf_pick_locked, + pf_cancel_pick_locked, + pf_cancel_picks_locked, + pf_ping_one_locked, + pf_exit_idle_locked, + pf_check_connectivity_locked, + pf_notify_on_state_change_locked, + pf_update_locked}; + +static void pick_first_factory_ref(grpc_lb_policy_factory *factory) {} + +static void pick_first_factory_unref(grpc_lb_policy_factory *factory) {} + +static grpc_lb_policy *create_pick_first(grpc_exec_ctx *exec_ctx, + grpc_lb_policy_factory *factory, + grpc_lb_policy_args *args) { + GPR_ASSERT(args->client_channel_factory != NULL); + pick_first_lb_policy *p = gpr_zalloc(sizeof(*p)); + if (GRPC_TRACER_ON(grpc_lb_pick_first_trace)) { + gpr_log(GPR_DEBUG, "Pick First %p created.", (void *)p); + } + pf_update_locked(exec_ctx, &p->base, args); + grpc_lb_policy_init(&p->base, &pick_first_lb_policy_vtable, args->combiner); + GRPC_CLOSURE_INIT(&p->connectivity_changed, pf_connectivity_changed_locked, p, + grpc_combiner_scheduler(args->combiner)); + return &p->base; +} + +static const grpc_lb_policy_factory_vtable pick_first_factory_vtable = { + pick_first_factory_ref, pick_first_factory_unref, create_pick_first, + "pick_first"}; + +static grpc_lb_policy_factory pick_first_lb_policy_factory = { + &pick_first_factory_vtable}; + +static grpc_lb_policy_factory *pick_first_lb_factory_create() { + return &pick_first_lb_policy_factory; +} + +/* Plugin registration */ + +void grpc_lb_policy_pick_first_init() { + grpc_register_lb_policy(pick_first_lb_factory_create()); + grpc_register_tracer(&grpc_lb_pick_first_trace); +} + +void grpc_lb_policy_pick_first_shutdown() {} diff --git a/Sources/CgRPC/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.c b/Sources/CgRPC/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.c new file mode 100644 index 000000000..a7f7e9542 --- /dev/null +++ b/Sources/CgRPC/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.c @@ -0,0 +1,919 @@ +/* + * + * 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. + * + */ + +/** Round Robin Policy. + * + * Before every pick, the \a get_next_ready_subchannel_index_locked function + * returns the p->subchannel_list->subchannels index for next subchannel, + * respecting the relative + * order of the addresses provided upon creation or updates. Note however that + * updates will start picking from the beginning of the updated list. */ + +#include + +#include + +#include "src/core/ext/filters/client_channel/lb_policy_registry.h" +#include "src/core/ext/filters/client_channel/subchannel.h" +#include "src/core/lib/channel/channel_args.h" +#include "src/core/lib/debug/trace.h" +#include "src/core/lib/iomgr/combiner.h" +#include "src/core/lib/iomgr/sockaddr_utils.h" +#include "src/core/lib/transport/connectivity_state.h" +#include "src/core/lib/transport/static_metadata.h" + +grpc_tracer_flag grpc_lb_round_robin_trace = + GRPC_TRACER_INITIALIZER(false, "round_robin"); + +/** List of entities waiting for a pick. + * + * Once a pick is available, \a target is updated and \a on_complete called. */ +typedef struct pending_pick { + struct pending_pick *next; + + /* output argument where to store the pick()ed user_data. It'll be NULL if no + * such data is present or there's an error (the definite test for errors is + * \a target being NULL). */ + void **user_data; + + /* bitmask passed to pick() and used for selective cancelling. See + * grpc_lb_policy_cancel_picks() */ + uint32_t initial_metadata_flags; + + /* output argument where to store the pick()ed connected subchannel, or NULL + * upon error. */ + grpc_connected_subchannel **target; + + /* to be invoked once the pick() has completed (regardless of success) */ + grpc_closure *on_complete; +} pending_pick; + +typedef struct rr_subchannel_list rr_subchannel_list; +typedef struct round_robin_lb_policy { + /** base policy: must be first */ + grpc_lb_policy base; + + rr_subchannel_list *subchannel_list; + + /** have we started picking? */ + bool started_picking; + /** are we shutting down? */ + bool shutdown; + /** has the policy gotten into the GRPC_CHANNEL_SHUTDOWN? No picks can be + * service after this point, the policy will never transition out. */ + bool in_connectivity_shutdown; + /** List of picks that are waiting on connectivity */ + pending_pick *pending_picks; + + /** our connectivity state tracker */ + grpc_connectivity_state_tracker state_tracker; + + /** Index into subchannels for last pick. */ + size_t last_ready_subchannel_index; + + /** Latest version of the subchannel list. + * Subchannel connectivity callbacks will only promote updated subchannel + * lists if they equal \a latest_pending_subchannel_list. In other words, + * racing callbacks that reference outdated subchannel lists won't perform any + * update. */ + rr_subchannel_list *latest_pending_subchannel_list; +} round_robin_lb_policy; + +typedef struct { + /** backpointer to owning subchannel list */ + rr_subchannel_list *subchannel_list; + /** subchannel itself */ + grpc_subchannel *subchannel; + /** notification that connectivity has changed on subchannel */ + grpc_closure connectivity_changed_closure; + /** last observed connectivity. Not updated by + * \a grpc_subchannel_notify_on_state_change. Used to determine the previous + * state while processing the new state in \a rr_connectivity_changed */ + grpc_connectivity_state prev_connectivity_state; + /** current connectivity state. Updated by \a + * grpc_subchannel_notify_on_state_change */ + grpc_connectivity_state curr_connectivity_state; + /** connectivity state to be updated by the watcher, not guarded by + * the combiner. Will be moved to curr_connectivity_state inside of + * the combiner by rr_connectivity_changed_locked(). */ + grpc_connectivity_state pending_connectivity_state_unsafe; + /** the subchannel's target user data */ + void *user_data; + /** vtable to operate over \a user_data */ + const grpc_lb_user_data_vtable *user_data_vtable; +} subchannel_data; + +struct rr_subchannel_list { + /** backpointer to owning policy */ + round_robin_lb_policy *policy; + + /** all our subchannels */ + size_t num_subchannels; + subchannel_data *subchannels; + + /** how many subchannels are in state READY */ + size_t num_ready; + /** how many subchannels are in state TRANSIENT_FAILURE */ + size_t num_transient_failures; + /** how many subchannels are in state SHUTDOWN */ + size_t num_shutdown; + /** how many subchannels are in state IDLE */ + size_t num_idle; + + /** There will be one ref for each entry in subchannels for which there is a + * pending connectivity state watcher callback. */ + gpr_refcount refcount; + + /** Is this list shutting down? This may be true due to the shutdown of the + * policy itself or because a newer update has arrived while this one hadn't + * finished processing. */ + bool shutting_down; +}; + +static rr_subchannel_list *rr_subchannel_list_create(round_robin_lb_policy *p, + size_t num_subchannels) { + rr_subchannel_list *subchannel_list = gpr_zalloc(sizeof(*subchannel_list)); + subchannel_list->policy = p; + subchannel_list->subchannels = + gpr_zalloc(sizeof(subchannel_data) * num_subchannels); + subchannel_list->num_subchannels = num_subchannels; + gpr_ref_init(&subchannel_list->refcount, 1); + if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) { + gpr_log(GPR_INFO, "[RR %p] Created subchannel list %p for %lu subchannels", + (void *)p, (void *)subchannel_list, (unsigned long)num_subchannels); + } + return subchannel_list; +} + +static void rr_subchannel_list_destroy(grpc_exec_ctx *exec_ctx, + rr_subchannel_list *subchannel_list) { + GPR_ASSERT(subchannel_list->shutting_down); + if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) { + gpr_log(GPR_INFO, "[RR %p] Destroying subchannel_list %p", + (void *)subchannel_list->policy, (void *)subchannel_list); + } + for (size_t i = 0; i < subchannel_list->num_subchannels; i++) { + subchannel_data *sd = &subchannel_list->subchannels[i]; + if (sd->subchannel != NULL) { + GRPC_SUBCHANNEL_UNREF(exec_ctx, sd->subchannel, + "rr_subchannel_list_destroy"); + } + sd->subchannel = NULL; + if (sd->user_data != NULL) { + GPR_ASSERT(sd->user_data_vtable != NULL); + sd->user_data_vtable->destroy(exec_ctx, sd->user_data); + sd->user_data = NULL; + } + } + gpr_free(subchannel_list->subchannels); + gpr_free(subchannel_list); +} + +static void rr_subchannel_list_ref(rr_subchannel_list *subchannel_list, + const char *reason) { + gpr_ref_non_zero(&subchannel_list->refcount); + if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) { + const gpr_atm count = gpr_atm_acq_load(&subchannel_list->refcount.count); + gpr_log(GPR_INFO, "[RR %p] subchannel_list %p REF %lu->%lu (%s)", + (void *)subchannel_list->policy, (void *)subchannel_list, + (unsigned long)(count - 1), (unsigned long)count, reason); + } +} + +static void rr_subchannel_list_unref(grpc_exec_ctx *exec_ctx, + rr_subchannel_list *subchannel_list, + const char *reason) { + const bool done = gpr_unref(&subchannel_list->refcount); + if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) { + const gpr_atm count = gpr_atm_acq_load(&subchannel_list->refcount.count); + gpr_log(GPR_INFO, "[RR %p] subchannel_list %p UNREF %lu->%lu (%s)", + (void *)subchannel_list->policy, (void *)subchannel_list, + (unsigned long)(count + 1), (unsigned long)count, reason); + } + if (done) { + rr_subchannel_list_destroy(exec_ctx, subchannel_list); + } +} + +/** Mark \a subchannel_list as discarded. Unsubscribes all its subchannels. The + * watcher's callback will ultimately unref \a subchannel_list. */ +static void rr_subchannel_list_shutdown_and_unref( + grpc_exec_ctx *exec_ctx, rr_subchannel_list *subchannel_list, + const char *reason) { + GPR_ASSERT(!subchannel_list->shutting_down); + if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) { + gpr_log(GPR_DEBUG, "[RR %p] Shutting down subchannel_list %p (%s)", + (void *)subchannel_list->policy, (void *)subchannel_list, reason); + } + GPR_ASSERT(!subchannel_list->shutting_down); + subchannel_list->shutting_down = true; + for (size_t i = 0; i < subchannel_list->num_subchannels; i++) { + subchannel_data *sd = &subchannel_list->subchannels[i]; + if (sd->subchannel != NULL) { // if subchannel isn't shutdown, unsubscribe. + if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) { + gpr_log( + GPR_DEBUG, + "[RR %p] Unsubscribing from subchannel %p as part of shutting down " + "subchannel_list %p", + (void *)subchannel_list->policy, (void *)sd->subchannel, + (void *)subchannel_list); + } + grpc_subchannel_notify_on_state_change(exec_ctx, sd->subchannel, NULL, + NULL, + &sd->connectivity_changed_closure); + } + } + rr_subchannel_list_unref(exec_ctx, subchannel_list, reason); +} + +/** Returns the index into p->subchannel_list->subchannels of the next + * subchannel in READY state, or p->subchannel_list->num_subchannels if no + * subchannel is READY. + * + * Note that this function does *not* update p->last_ready_subchannel_index. + * The caller must do that if it returns a pick. */ +static size_t get_next_ready_subchannel_index_locked( + const round_robin_lb_policy *p) { + GPR_ASSERT(p->subchannel_list != NULL); + if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) { + gpr_log(GPR_INFO, + "[RR %p] getting next ready subchannel (out of %lu), " + "last_ready_subchannel_index=%lu", + (void *)p, (unsigned long)p->subchannel_list->num_subchannels, + (unsigned long)p->last_ready_subchannel_index); + } + for (size_t i = 0; i < p->subchannel_list->num_subchannels; ++i) { + const size_t index = (i + p->last_ready_subchannel_index + 1) % + p->subchannel_list->num_subchannels; + if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) { + gpr_log( + GPR_DEBUG, + "[RR %p] checking subchannel %p, subchannel_list %p, index %lu: " + "state=%s", + (void *)p, (void *)p->subchannel_list->subchannels[index].subchannel, + (void *)p->subchannel_list, (unsigned long)index, + grpc_connectivity_state_name( + p->subchannel_list->subchannels[index].curr_connectivity_state)); + } + if (p->subchannel_list->subchannels[index].curr_connectivity_state == + GRPC_CHANNEL_READY) { + if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) { + gpr_log(GPR_DEBUG, + "[RR %p] found next ready subchannel (%p) at index %lu of " + "subchannel_list %p", + (void *)p, + (void *)p->subchannel_list->subchannels[index].subchannel, + (unsigned long)index, (void *)p->subchannel_list); + } + return index; + } + } + if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) { + gpr_log(GPR_DEBUG, "[RR %p] no subchannels in ready state", (void *)p); + } + return p->subchannel_list->num_subchannels; +} + +// Sets p->last_ready_subchannel_index to last_ready_index. +static void update_last_ready_subchannel_index_locked(round_robin_lb_policy *p, + size_t last_ready_index) { + GPR_ASSERT(last_ready_index < p->subchannel_list->num_subchannels); + p->last_ready_subchannel_index = last_ready_index; + if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) { + gpr_log( + GPR_DEBUG, + "[RR %p] setting last_ready_subchannel_index=%lu (SC %p, CSC %p)", + (void *)p, (unsigned long)last_ready_index, + (void *)p->subchannel_list->subchannels[last_ready_index].subchannel, + (void *)grpc_subchannel_get_connected_subchannel( + p->subchannel_list->subchannels[last_ready_index].subchannel)); + } +} + +static void rr_destroy(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) { + round_robin_lb_policy *p = (round_robin_lb_policy *)pol; + if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) { + gpr_log(GPR_DEBUG, "[RR %p] Destroying Round Robin policy at %p", + (void *)pol, (void *)pol); + } + grpc_connectivity_state_destroy(exec_ctx, &p->state_tracker); + gpr_free(p); +} + +static void rr_shutdown_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) { + round_robin_lb_policy *p = (round_robin_lb_policy *)pol; + if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) { + gpr_log(GPR_DEBUG, "[RR %p] Shutting down Round Robin policy at %p", + (void *)pol, (void *)pol); + } + p->shutdown = true; + pending_pick *pp; + while ((pp = p->pending_picks)) { + p->pending_picks = pp->next; + *pp->target = NULL; + GRPC_CLOSURE_SCHED( + exec_ctx, pp->on_complete, + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Channel Shutdown")); + gpr_free(pp); + } + grpc_connectivity_state_set( + exec_ctx, &p->state_tracker, GRPC_CHANNEL_SHUTDOWN, + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Channel Shutdown"), "rr_shutdown"); + const bool latest_is_current = + p->subchannel_list == p->latest_pending_subchannel_list; + rr_subchannel_list_shutdown_and_unref(exec_ctx, p->subchannel_list, + "sl_shutdown_rr_shutdown"); + p->subchannel_list = NULL; + if (!latest_is_current && p->latest_pending_subchannel_list != NULL && + !p->latest_pending_subchannel_list->shutting_down) { + rr_subchannel_list_shutdown_and_unref(exec_ctx, + p->latest_pending_subchannel_list, + "sl_shutdown_pending_rr_shutdown"); + p->latest_pending_subchannel_list = NULL; + } +} + +static void rr_cancel_pick_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, + grpc_connected_subchannel **target, + grpc_error *error) { + round_robin_lb_policy *p = (round_robin_lb_policy *)pol; + pending_pick *pp = p->pending_picks; + p->pending_picks = NULL; + while (pp != NULL) { + pending_pick *next = pp->next; + if (pp->target == target) { + *target = NULL; + GRPC_CLOSURE_SCHED(exec_ctx, pp->on_complete, + GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( + "Pick cancelled", &error, 1)); + gpr_free(pp); + } else { + pp->next = p->pending_picks; + p->pending_picks = pp; + } + pp = next; + } + GRPC_ERROR_UNREF(error); +} + +static void rr_cancel_picks_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, + uint32_t initial_metadata_flags_mask, + uint32_t initial_metadata_flags_eq, + grpc_error *error) { + round_robin_lb_policy *p = (round_robin_lb_policy *)pol; + pending_pick *pp = p->pending_picks; + p->pending_picks = NULL; + while (pp != NULL) { + pending_pick *next = pp->next; + if ((pp->initial_metadata_flags & initial_metadata_flags_mask) == + initial_metadata_flags_eq) { + *pp->target = NULL; + GRPC_CLOSURE_SCHED(exec_ctx, pp->on_complete, + GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( + "Pick cancelled", &error, 1)); + gpr_free(pp); + } else { + pp->next = p->pending_picks; + p->pending_picks = pp; + } + pp = next; + } + GRPC_ERROR_UNREF(error); +} + +static void start_picking_locked(grpc_exec_ctx *exec_ctx, + round_robin_lb_policy *p) { + p->started_picking = true; + for (size_t i = 0; i < p->subchannel_list->num_subchannels; i++) { + subchannel_data *sd = &p->subchannel_list->subchannels[i]; + GRPC_LB_POLICY_WEAK_REF(&p->base, "start_picking_locked"); + rr_subchannel_list_ref(sd->subchannel_list, "started_picking"); + grpc_subchannel_notify_on_state_change( + exec_ctx, sd->subchannel, p->base.interested_parties, + &sd->pending_connectivity_state_unsafe, + &sd->connectivity_changed_closure); + } +} + +static void rr_exit_idle_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) { + round_robin_lb_policy *p = (round_robin_lb_policy *)pol; + if (!p->started_picking) { + start_picking_locked(exec_ctx, p); + } +} + +static int rr_pick_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, + const grpc_lb_policy_pick_args *pick_args, + grpc_connected_subchannel **target, + grpc_call_context_element *context, void **user_data, + grpc_closure *on_complete) { + round_robin_lb_policy *p = (round_robin_lb_policy *)pol; + GPR_ASSERT(!p->shutdown); + GPR_ASSERT(!p->in_connectivity_shutdown); + if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) { + gpr_log(GPR_INFO, "[RR %p] Trying to pick", (void *)pol); + } + if (p->subchannel_list != NULL) { + const size_t next_ready_index = get_next_ready_subchannel_index_locked(p); + if (next_ready_index < p->subchannel_list->num_subchannels) { + /* readily available, report right away */ + subchannel_data *sd = &p->subchannel_list->subchannels[next_ready_index]; + *target = GRPC_CONNECTED_SUBCHANNEL_REF( + grpc_subchannel_get_connected_subchannel(sd->subchannel), + "rr_picked"); + if (user_data != NULL) { + *user_data = sd->user_data; + } + if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) { + gpr_log( + GPR_DEBUG, + "[RR %p] Picked target <-- Subchannel %p (connected %p) (sl %p, " + "index %lu)", + (void *)p, (void *)sd->subchannel, (void *)*target, + (void *)sd->subchannel_list, (unsigned long)next_ready_index); + } + /* only advance the last picked pointer if the selection was used */ + update_last_ready_subchannel_index_locked(p, next_ready_index); + return 1; + } + } + /* no pick currently available. Save for later in list of pending picks */ + if (!p->started_picking) { + start_picking_locked(exec_ctx, p); + } + pending_pick *pp = gpr_malloc(sizeof(*pp)); + pp->next = p->pending_picks; + pp->target = target; + pp->on_complete = on_complete; + pp->initial_metadata_flags = pick_args->initial_metadata_flags; + pp->user_data = user_data; + p->pending_picks = pp; + return 0; +} + +static void update_state_counters_locked(subchannel_data *sd) { + rr_subchannel_list *subchannel_list = sd->subchannel_list; + if (sd->prev_connectivity_state == GRPC_CHANNEL_READY) { + GPR_ASSERT(subchannel_list->num_ready > 0); + --subchannel_list->num_ready; + } else if (sd->prev_connectivity_state == GRPC_CHANNEL_TRANSIENT_FAILURE) { + GPR_ASSERT(subchannel_list->num_transient_failures > 0); + --subchannel_list->num_transient_failures; + } else if (sd->prev_connectivity_state == GRPC_CHANNEL_SHUTDOWN) { + GPR_ASSERT(subchannel_list->num_shutdown > 0); + --subchannel_list->num_shutdown; + } else if (sd->prev_connectivity_state == GRPC_CHANNEL_IDLE) { + GPR_ASSERT(subchannel_list->num_idle > 0); + --subchannel_list->num_idle; + } + if (sd->curr_connectivity_state == GRPC_CHANNEL_READY) { + ++subchannel_list->num_ready; + } else if (sd->curr_connectivity_state == GRPC_CHANNEL_TRANSIENT_FAILURE) { + ++subchannel_list->num_transient_failures; + } else if (sd->curr_connectivity_state == GRPC_CHANNEL_SHUTDOWN) { + ++subchannel_list->num_shutdown; + } else if (sd->curr_connectivity_state == GRPC_CHANNEL_IDLE) { + ++subchannel_list->num_idle; + } +} + +/** Sets the policy's connectivity status based on that of the passed-in \a sd + * (the subchannel_data associted with the updated subchannel) and the + * subchannel list \a sd belongs to (sd->subchannel_list). \a error will only be + * used upon policy transition to TRANSIENT_FAILURE or SHUTDOWN. Returns the + * connectivity status set. */ +static grpc_connectivity_state update_lb_connectivity_status_locked( + grpc_exec_ctx *exec_ctx, subchannel_data *sd, grpc_error *error) { + /* In priority order. The first rule to match terminates the search (ie, if we + * are on rule n, all previous rules were unfulfilled). + * + * 1) RULE: ANY subchannel is READY => policy is READY. + * CHECK: At least one subchannel is ready iff p->ready_list is NOT empty. + * + * 2) RULE: ANY subchannel is CONNECTING => policy is CONNECTING. + * CHECK: sd->curr_connectivity_state == CONNECTING. + * + * 3) RULE: ALL subchannels are SHUTDOWN => policy is SHUTDOWN. + * CHECK: p->subchannel_list->num_shutdown == + * p->subchannel_list->num_subchannels. + * + * 4) RULE: ALL subchannels are TRANSIENT_FAILURE => policy is + * TRANSIENT_FAILURE. + * CHECK: p->num_transient_failures == p->subchannel_list->num_subchannels. + * + * 5) RULE: ALL subchannels are IDLE => policy is IDLE. + * CHECK: p->num_idle == p->subchannel_list->num_subchannels. + */ + grpc_connectivity_state new_state = sd->curr_connectivity_state; + rr_subchannel_list *subchannel_list = sd->subchannel_list; + round_robin_lb_policy *p = subchannel_list->policy; + if (subchannel_list->num_ready > 0) { /* 1) READY */ + grpc_connectivity_state_set(exec_ctx, &p->state_tracker, GRPC_CHANNEL_READY, + GRPC_ERROR_NONE, "rr_ready"); + new_state = GRPC_CHANNEL_READY; + } else if (sd->curr_connectivity_state == + GRPC_CHANNEL_CONNECTING) { /* 2) CONNECTING */ + grpc_connectivity_state_set(exec_ctx, &p->state_tracker, + GRPC_CHANNEL_CONNECTING, GRPC_ERROR_NONE, + "rr_connecting"); + new_state = GRPC_CHANNEL_CONNECTING; + } else if (p->subchannel_list->num_shutdown == + p->subchannel_list->num_subchannels) { /* 3) SHUTDOWN */ + grpc_connectivity_state_set(exec_ctx, &p->state_tracker, + GRPC_CHANNEL_SHUTDOWN, GRPC_ERROR_REF(error), + "rr_shutdown"); + p->in_connectivity_shutdown = true; + new_state = GRPC_CHANNEL_SHUTDOWN; + } else if (subchannel_list->num_transient_failures == + p->subchannel_list->num_subchannels) { /* 4) TRANSIENT_FAILURE */ + grpc_connectivity_state_set(exec_ctx, &p->state_tracker, + GRPC_CHANNEL_TRANSIENT_FAILURE, + GRPC_ERROR_REF(error), "rr_transient_failure"); + new_state = GRPC_CHANNEL_TRANSIENT_FAILURE; + } else if (subchannel_list->num_idle == + p->subchannel_list->num_subchannels) { /* 5) IDLE */ + grpc_connectivity_state_set(exec_ctx, &p->state_tracker, GRPC_CHANNEL_IDLE, + GRPC_ERROR_NONE, "rr_idle"); + new_state = GRPC_CHANNEL_IDLE; + } + GRPC_ERROR_UNREF(error); + return new_state; +} + +static void rr_connectivity_changed_locked(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error) { + subchannel_data *sd = arg; + round_robin_lb_policy *p = sd->subchannel_list->policy; + if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) { + gpr_log( + GPR_DEBUG, + "[RR %p] connectivity changed for subchannel %p, subchannel_list %p: " + "prev_state=%s new_state=%s p->shutdown=%d " + "sd->subchannel_list->shutting_down=%d error=%s", + (void *)p, (void *)sd->subchannel, (void *)sd->subchannel_list, + grpc_connectivity_state_name(sd->prev_connectivity_state), + grpc_connectivity_state_name(sd->pending_connectivity_state_unsafe), + p->shutdown, sd->subchannel_list->shutting_down, + grpc_error_string(error)); + } + // If the policy is shutting down, unref and return. + if (p->shutdown) { + rr_subchannel_list_unref(exec_ctx, sd->subchannel_list, + "pol_shutdown+started_picking"); + GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "pol_shutdown"); + return; + } + if (sd->subchannel_list->shutting_down && error == GRPC_ERROR_CANCELLED) { + // the subchannel list associated with sd has been discarded. This callback + // corresponds to the unsubscription. The unrefs correspond to the picking + // ref (start_picking_locked or update_started_picking). + rr_subchannel_list_unref(exec_ctx, sd->subchannel_list, + "sl_shutdown+started_picking"); + GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "sl_shutdown+picking"); + return; + } + // Dispose of outdated subchannel lists. + if (sd->subchannel_list != p->subchannel_list && + sd->subchannel_list != p->latest_pending_subchannel_list) { + char *reason = NULL; + if (sd->subchannel_list->shutting_down) { + reason = "sl_outdated_straggler"; + rr_subchannel_list_unref(exec_ctx, sd->subchannel_list, reason); + } else { + reason = "sl_outdated"; + rr_subchannel_list_shutdown_and_unref(exec_ctx, sd->subchannel_list, + reason); + } + GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, reason); + return; + } + // Now that we're inside the combiner, copy the pending connectivity + // state (which was set by the connectivity state watcher) to + // curr_connectivity_state, which is what we use inside of the combiner. + sd->curr_connectivity_state = sd->pending_connectivity_state_unsafe; + // Update state counters and determine new overall state. + update_state_counters_locked(sd); + sd->prev_connectivity_state = sd->curr_connectivity_state; + const grpc_connectivity_state new_policy_connectivity_state = + update_lb_connectivity_status_locked(exec_ctx, sd, GRPC_ERROR_REF(error)); + // If the sd's new state is SHUTDOWN, unref the subchannel, and if the new + // policy's state is SHUTDOWN, clean up. + if (sd->curr_connectivity_state == GRPC_CHANNEL_SHUTDOWN) { + GRPC_SUBCHANNEL_UNREF(exec_ctx, sd->subchannel, "rr_subchannel_shutdown"); + sd->subchannel = NULL; + if (sd->user_data != NULL) { + GPR_ASSERT(sd->user_data_vtable != NULL); + sd->user_data_vtable->destroy(exec_ctx, sd->user_data); + sd->user_data = NULL; + } + if (new_policy_connectivity_state == GRPC_CHANNEL_SHUTDOWN) { + // the policy is shutting down. Flush all the pending picks... + pending_pick *pp; + while ((pp = p->pending_picks)) { + p->pending_picks = pp->next; + *pp->target = NULL; + GRPC_CLOSURE_SCHED(exec_ctx, pp->on_complete, GRPC_ERROR_NONE); + gpr_free(pp); + } + } + rr_subchannel_list_unref(exec_ctx, sd->subchannel_list, + "sd_shutdown+started_picking"); + // unref the "rr_connectivity_update" weak ref from start_picking. + GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, + "rr_connectivity_sd_shutdown"); + } else { // sd not in SHUTDOWN + if (sd->curr_connectivity_state == GRPC_CHANNEL_READY) { + if (sd->subchannel_list != p->subchannel_list) { + // promote sd->subchannel_list to p->subchannel_list. + // sd->subchannel_list must be equal to + // p->latest_pending_subchannel_list because we have already filtered + // for sds belonging to outdated subchannel lists. + GPR_ASSERT(sd->subchannel_list == p->latest_pending_subchannel_list); + GPR_ASSERT(!sd->subchannel_list->shutting_down); + if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) { + const unsigned long num_subchannels = + p->subchannel_list != NULL + ? (unsigned long)p->subchannel_list->num_subchannels + : 0; + gpr_log(GPR_DEBUG, + "[RR %p] phasing out subchannel list %p (size %lu) in favor " + "of %p (size %lu)", + (void *)p, (void *)p->subchannel_list, num_subchannels, + (void *)sd->subchannel_list, num_subchannels); + } + if (p->subchannel_list != NULL) { + // dispose of the current subchannel_list + rr_subchannel_list_shutdown_and_unref(exec_ctx, p->subchannel_list, + "sl_phase_out_shutdown"); + } + p->subchannel_list = p->latest_pending_subchannel_list; + p->latest_pending_subchannel_list = NULL; + } + /* at this point we know there's at least one suitable subchannel. Go + * ahead and pick one and notify the pending suitors in + * p->pending_picks. This preemtively replicates rr_pick()'s actions. */ + const size_t next_ready_index = get_next_ready_subchannel_index_locked(p); + GPR_ASSERT(next_ready_index < p->subchannel_list->num_subchannels); + subchannel_data *selected = + &p->subchannel_list->subchannels[next_ready_index]; + if (p->pending_picks != NULL) { + // if the selected subchannel is going to be used for the pending + // picks, update the last picked pointer + update_last_ready_subchannel_index_locked(p, next_ready_index); + } + pending_pick *pp; + while ((pp = p->pending_picks)) { + p->pending_picks = pp->next; + *pp->target = GRPC_CONNECTED_SUBCHANNEL_REF( + grpc_subchannel_get_connected_subchannel(selected->subchannel), + "rr_picked"); + if (pp->user_data != NULL) { + *pp->user_data = selected->user_data; + } + if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) { + gpr_log(GPR_DEBUG, + "[RR %p] Fulfilling pending pick. Target <-- subchannel %p " + "(subchannel_list %p, index %lu)", + (void *)p, (void *)selected->subchannel, + (void *)p->subchannel_list, (unsigned long)next_ready_index); + } + GRPC_CLOSURE_SCHED(exec_ctx, pp->on_complete, GRPC_ERROR_NONE); + gpr_free(pp); + } + } + /* renew notification: reuses the "rr_connectivity_update" weak ref on the + * policy as well as the sd->subchannel_list ref. */ + grpc_subchannel_notify_on_state_change( + exec_ctx, sd->subchannel, p->base.interested_parties, + &sd->pending_connectivity_state_unsafe, + &sd->connectivity_changed_closure); + } +} + +static grpc_connectivity_state rr_check_connectivity_locked( + grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, grpc_error **error) { + round_robin_lb_policy *p = (round_robin_lb_policy *)pol; + return grpc_connectivity_state_get(&p->state_tracker, error); +} + +static void rr_notify_on_state_change_locked(grpc_exec_ctx *exec_ctx, + grpc_lb_policy *pol, + grpc_connectivity_state *current, + grpc_closure *notify) { + round_robin_lb_policy *p = (round_robin_lb_policy *)pol; + grpc_connectivity_state_notify_on_state_change(exec_ctx, &p->state_tracker, + current, notify); +} + +static void rr_ping_one_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, + grpc_closure *closure) { + round_robin_lb_policy *p = (round_robin_lb_policy *)pol; + const size_t next_ready_index = get_next_ready_subchannel_index_locked(p); + if (next_ready_index < p->subchannel_list->num_subchannels) { + subchannel_data *selected = + &p->subchannel_list->subchannels[next_ready_index]; + grpc_connected_subchannel *target = GRPC_CONNECTED_SUBCHANNEL_REF( + grpc_subchannel_get_connected_subchannel(selected->subchannel), + "rr_picked"); + grpc_connected_subchannel_ping(exec_ctx, target, closure); + GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, target, "rr_picked"); + } else { + GRPC_CLOSURE_SCHED(exec_ctx, closure, GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "Round Robin not connected")); + } +} + +static void rr_update_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, + const grpc_lb_policy_args *args) { + round_robin_lb_policy *p = (round_robin_lb_policy *)policy; + /* Find the number of backend addresses. We ignore balancer addresses, since + * we don't know how to handle them. */ + const grpc_arg *arg = + grpc_channel_args_find(args->args, GRPC_ARG_LB_ADDRESSES); + if (arg == NULL || arg->type != GRPC_ARG_POINTER) { + if (p->subchannel_list == NULL) { + // If we don't have a current subchannel list, go into TRANSIENT FAILURE. + grpc_connectivity_state_set( + exec_ctx, &p->state_tracker, GRPC_CHANNEL_TRANSIENT_FAILURE, + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Missing update in args"), + "rr_update_missing"); + } else { + // otherwise, keep using the current subchannel list (ignore this update). + gpr_log(GPR_ERROR, + "[RR %p] No valid LB addresses channel arg for update, ignoring.", + (void *)p); + } + return; + } + grpc_lb_addresses *addresses = arg->value.pointer.p; + size_t num_addrs = 0; + for (size_t i = 0; i < addresses->num_addresses; i++) { + if (!addresses->addresses[i].is_balancer) ++num_addrs; + } + rr_subchannel_list *subchannel_list = rr_subchannel_list_create(p, num_addrs); + if (num_addrs == 0) { + grpc_connectivity_state_set( + exec_ctx, &p->state_tracker, GRPC_CHANNEL_TRANSIENT_FAILURE, + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Empty update"), + "rr_update_empty"); + if (p->subchannel_list != NULL) { + rr_subchannel_list_shutdown_and_unref(exec_ctx, p->subchannel_list, + "sl_shutdown_empty_update"); + } + p->subchannel_list = subchannel_list; // empty list + return; + } + size_t subchannel_index = 0; + if (p->latest_pending_subchannel_list != NULL && p->started_picking) { + if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) { + gpr_log(GPR_DEBUG, + "[RR %p] Shutting down latest pending subchannel list %p, about " + "to be replaced by newer latest %p", + (void *)p, (void *)p->latest_pending_subchannel_list, + (void *)subchannel_list); + } + rr_subchannel_list_shutdown_and_unref( + exec_ctx, p->latest_pending_subchannel_list, "sl_outdated_dont_smash"); + } + p->latest_pending_subchannel_list = subchannel_list; + grpc_subchannel_args sc_args; + /* We need to remove the LB addresses in order to be able to compare the + * subchannel keys of subchannels from a different batch of addresses. */ + static const char *keys_to_remove[] = {GRPC_ARG_SUBCHANNEL_ADDRESS, + GRPC_ARG_LB_ADDRESSES}; + /* Create subchannels for addresses in the update. */ + for (size_t i = 0; i < addresses->num_addresses; i++) { + /* Skip balancer addresses, since we only know how to handle backends. */ + if (addresses->addresses[i].is_balancer) continue; + GPR_ASSERT(i < num_addrs); + memset(&sc_args, 0, sizeof(grpc_subchannel_args)); + grpc_arg addr_arg = + grpc_create_subchannel_address_arg(&addresses->addresses[i].address); + grpc_channel_args *new_args = grpc_channel_args_copy_and_add_and_remove( + args->args, keys_to_remove, GPR_ARRAY_SIZE(keys_to_remove), &addr_arg, + 1); + gpr_free(addr_arg.value.string); + sc_args.args = new_args; + grpc_subchannel *subchannel = grpc_client_channel_factory_create_subchannel( + exec_ctx, args->client_channel_factory, &sc_args); + if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) { + char *address_uri = + grpc_sockaddr_to_uri(&addresses->addresses[i].address); + gpr_log( + GPR_DEBUG, + "[RR %p] index %lu: Created subchannel %p for address uri %s into " + "subchannel_list %p", + (void *)p, (unsigned long)subchannel_index, (void *)subchannel, + address_uri, (void *)subchannel_list); + gpr_free(address_uri); + } + grpc_channel_args_destroy(exec_ctx, new_args); + + subchannel_data *sd = &subchannel_list->subchannels[subchannel_index++]; + sd->subchannel_list = subchannel_list; + sd->subchannel = subchannel; + GRPC_CLOSURE_INIT(&sd->connectivity_changed_closure, + rr_connectivity_changed_locked, sd, + grpc_combiner_scheduler(args->combiner)); + /* use some sentinel value outside of the range of + * grpc_connectivity_state to signal an undefined previous state. We + * won't be referring to this value again and it'll be overwritten after + * the first call to rr_connectivity_changed_locked */ + sd->prev_connectivity_state = GRPC_CHANNEL_INIT; + sd->curr_connectivity_state = GRPC_CHANNEL_IDLE; + sd->user_data_vtable = addresses->user_data_vtable; + if (sd->user_data_vtable != NULL) { + sd->user_data = + sd->user_data_vtable->copy(addresses->addresses[i].user_data); + } + if (p->started_picking) { + rr_subchannel_list_ref(sd->subchannel_list, "update_started_picking"); + GRPC_LB_POLICY_WEAK_REF(&p->base, "rr_connectivity_update"); + /* 2. Watch every new subchannel. A subchannel list becomes active the + * moment one of its subchannels is READY. At that moment, we swap + * p->subchannel_list for sd->subchannel_list, provided the subchannel + * list is still valid (ie, isn't shutting down) */ + grpc_subchannel_notify_on_state_change( + exec_ctx, sd->subchannel, p->base.interested_parties, + &sd->pending_connectivity_state_unsafe, + &sd->connectivity_changed_closure); + } + } + if (!p->started_picking) { + // The policy isn't picking yet. Save the update for later, disposing of + // previous version if any. + if (p->subchannel_list != NULL) { + rr_subchannel_list_shutdown_and_unref(exec_ctx, p->subchannel_list, + "rr_update_before_started_picking"); + } + p->subchannel_list = subchannel_list; + p->latest_pending_subchannel_list = NULL; + } +} + +static const grpc_lb_policy_vtable round_robin_lb_policy_vtable = { + rr_destroy, + rr_shutdown_locked, + rr_pick_locked, + rr_cancel_pick_locked, + rr_cancel_picks_locked, + rr_ping_one_locked, + rr_exit_idle_locked, + rr_check_connectivity_locked, + rr_notify_on_state_change_locked, + rr_update_locked}; + +static void round_robin_factory_ref(grpc_lb_policy_factory *factory) {} + +static void round_robin_factory_unref(grpc_lb_policy_factory *factory) {} + +static grpc_lb_policy *round_robin_create(grpc_exec_ctx *exec_ctx, + grpc_lb_policy_factory *factory, + grpc_lb_policy_args *args) { + GPR_ASSERT(args->client_channel_factory != NULL); + round_robin_lb_policy *p = gpr_zalloc(sizeof(*p)); + grpc_lb_policy_init(&p->base, &round_robin_lb_policy_vtable, args->combiner); + grpc_connectivity_state_init(&p->state_tracker, GRPC_CHANNEL_IDLE, + "round_robin"); + rr_update_locked(exec_ctx, &p->base, args); + if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) { + gpr_log(GPR_DEBUG, "[RR %p] Created with %lu subchannels", (void *)p, + (unsigned long)p->subchannel_list->num_subchannels); + } + return &p->base; +} + +static const grpc_lb_policy_factory_vtable round_robin_factory_vtable = { + round_robin_factory_ref, round_robin_factory_unref, round_robin_create, + "round_robin"}; + +static grpc_lb_policy_factory round_robin_lb_policy_factory = { + &round_robin_factory_vtable}; + +static grpc_lb_policy_factory *round_robin_lb_factory_create() { + return &round_robin_lb_policy_factory; +} + +/* Plugin registration */ + +void grpc_lb_policy_round_robin_init() { + grpc_register_lb_policy(round_robin_lb_factory_create()); + grpc_register_tracer(&grpc_lb_round_robin_trace); +} + +void grpc_lb_policy_round_robin_shutdown() {} diff --git a/Sources/CgRPC/src/core/ext/client_channel/lb_policy_factory.c b/Sources/CgRPC/src/core/ext/filters/client_channel/lb_policy_factory.c similarity index 64% rename from Sources/CgRPC/src/core/ext/client_channel/lb_policy_factory.c rename to Sources/CgRPC/src/core/ext/filters/client_channel/lb_policy_factory.c index 8a474c881..538d8d65e 100644 --- a/Sources/CgRPC/src/core/ext/client_channel/lb_policy_factory.c +++ b/Sources/CgRPC/src/core/ext/filters/client_channel/lb_policy_factory.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -36,16 +21,18 @@ #include #include -#include "src/core/ext/client_channel/lb_policy_factory.h" +#include "src/core/lib/channel/channel_args.h" + +#include "src/core/ext/filters/client_channel/lb_policy_factory.h" +#include "src/core/ext/filters/client_channel/parse_address.h" grpc_lb_addresses* grpc_lb_addresses_create( size_t num_addresses, const grpc_lb_user_data_vtable* user_data_vtable) { - grpc_lb_addresses* addresses = gpr_malloc(sizeof(grpc_lb_addresses)); + grpc_lb_addresses* addresses = gpr_zalloc(sizeof(grpc_lb_addresses)); addresses->num_addresses = num_addresses; addresses->user_data_vtable = user_data_vtable; const size_t addresses_size = sizeof(grpc_lb_address) * num_addresses; - addresses->addresses = gpr_malloc(addresses_size); - memset(addresses->addresses, 0, addresses_size); + addresses->addresses = gpr_zalloc(addresses_size); return addresses; } @@ -69,7 +56,7 @@ grpc_lb_addresses* grpc_lb_addresses_copy(const grpc_lb_addresses* addresses) { void grpc_lb_addresses_set_address(grpc_lb_addresses* addresses, size_t index, void* address, size_t address_len, - bool is_balancer, char* balancer_name, + bool is_balancer, const char* balancer_name, void* user_data) { GPR_ASSERT(index < addresses->num_addresses); if (user_data != NULL) GPR_ASSERT(addresses->user_data_vtable != NULL); @@ -77,10 +64,22 @@ void grpc_lb_addresses_set_address(grpc_lb_addresses* addresses, size_t index, memcpy(target->address.addr, address, address_len); target->address.len = address_len; target->is_balancer = is_balancer; - target->balancer_name = balancer_name; + target->balancer_name = gpr_strdup(balancer_name); target->user_data = user_data; } +bool grpc_lb_addresses_set_address_from_uri(grpc_lb_addresses* addresses, + size_t index, const grpc_uri* uri, + bool is_balancer, + const char* balancer_name, + void* user_data) { + grpc_resolved_address address; + if (!grpc_parse_uri(uri, &address)) return false; + grpc_lb_addresses_set_address(addresses, index, address.addr, address.len, + is_balancer, balancer_name, user_data); + return true; +} + int grpc_lb_addresses_cmp(const grpc_lb_addresses* addresses1, const grpc_lb_addresses* addresses2) { if (addresses1->num_addresses > addresses2->num_addresses) return 1; @@ -112,11 +111,13 @@ int grpc_lb_addresses_cmp(const grpc_lb_addresses* addresses1, return 0; } -void grpc_lb_addresses_destroy(grpc_lb_addresses* addresses) { +void grpc_lb_addresses_destroy(grpc_exec_ctx* exec_ctx, + grpc_lb_addresses* addresses) { for (size_t i = 0; i < addresses->num_addresses; ++i) { gpr_free(addresses->addresses[i].balancer_name); if (addresses->addresses[i].user_data != NULL) { - addresses->user_data_vtable->destroy(addresses->addresses[i].user_data); + addresses->user_data_vtable->destroy(exec_ctx, + addresses->addresses[i].user_data); } } gpr_free(addresses->addresses); @@ -126,8 +127,8 @@ void grpc_lb_addresses_destroy(grpc_lb_addresses* addresses) { static void* lb_addresses_copy(void* addresses) { return grpc_lb_addresses_copy(addresses); } -static void lb_addresses_destroy(void* addresses) { - grpc_lb_addresses_destroy(addresses); +static void lb_addresses_destroy(grpc_exec_ctx* exec_ctx, void* addresses) { + grpc_lb_addresses_destroy(exec_ctx, addresses); } static int lb_addresses_cmp(void* addresses1, void* addresses2) { return grpc_lb_addresses_cmp(addresses1, addresses2); @@ -137,12 +138,17 @@ static const grpc_arg_pointer_vtable lb_addresses_arg_vtable = { grpc_arg grpc_lb_addresses_create_channel_arg( const grpc_lb_addresses* addresses) { - grpc_arg arg; - arg.type = GRPC_ARG_POINTER; - arg.key = GRPC_ARG_LB_ADDRESSES; - arg.value.pointer.p = (void*)addresses; - arg.value.pointer.vtable = &lb_addresses_arg_vtable; - return arg; + return grpc_channel_arg_pointer_create( + GRPC_ARG_LB_ADDRESSES, (void*)addresses, &lb_addresses_arg_vtable); +} + +grpc_lb_addresses* grpc_lb_addresses_find_channel_arg( + const grpc_channel_args* channel_args) { + const grpc_arg* lb_addresses_arg = + grpc_channel_args_find(channel_args, GRPC_ARG_LB_ADDRESSES); + if (lb_addresses_arg == NULL || lb_addresses_arg->type != GRPC_ARG_POINTER) + return NULL; + return lb_addresses_arg->value.pointer.p; } void grpc_lb_policy_factory_ref(grpc_lb_policy_factory* factory) { diff --git a/Sources/CgRPC/src/core/ext/client_channel/lb_policy_factory.h b/Sources/CgRPC/src/core/ext/filters/client_channel/lb_policy_factory.h similarity index 61% rename from Sources/CgRPC/src/core/ext/client_channel/lb_policy_factory.h rename to Sources/CgRPC/src/core/ext/filters/client_channel/lb_policy_factory.h index 79b3dee25..9d9fb143d 100644 --- a/Sources/CgRPC/src/core/ext/client_channel/lb_policy_factory.h +++ b/Sources/CgRPC/src/core/ext/filters/client_channel/lb_policy_factory.h @@ -1,45 +1,31 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 GRPC_CORE_EXT_CLIENT_CHANNEL_LB_POLICY_FACTORY_H -#define GRPC_CORE_EXT_CLIENT_CHANNEL_LB_POLICY_FACTORY_H - -#include "src/core/ext/client_channel/client_channel_factory.h" -#include "src/core/ext/client_channel/lb_policy.h" +#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_FACTORY_H +#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_FACTORY_H #include "src/core/lib/iomgr/exec_ctx.h" #include "src/core/lib/iomgr/resolve_address.h" +#include "src/core/ext/filters/client_channel/client_channel_factory.h" +#include "src/core/ext/filters/client_channel/lb_policy.h" +#include "src/core/ext/filters/client_channel/uri_parser.h" + // Channel arg key for grpc_lb_addresses. #define GRPC_ARG_LB_ADDRESSES "grpc.lb_addresses" @@ -64,7 +50,7 @@ typedef struct grpc_lb_address { typedef struct grpc_lb_user_data_vtable { void *(*copy)(void *); - void (*destroy)(void *); + void (*destroy)(grpc_exec_ctx *exec_ctx, void *); int (*cmp)(void *, void *); } grpc_lb_user_data_vtable; @@ -88,25 +74,40 @@ grpc_lb_addresses *grpc_lb_addresses_copy(const grpc_lb_addresses *addresses); * Takes ownership of \a balancer_name. */ void grpc_lb_addresses_set_address(grpc_lb_addresses *addresses, size_t index, void *address, size_t address_len, - bool is_balancer, char *balancer_name, + bool is_balancer, const char *balancer_name, void *user_data); +/** Sets the value of the address at index \a index of \a addresses from \a uri. + * Returns true upon success, false otherwise. Takes ownership of \a + * balancer_name. */ +bool grpc_lb_addresses_set_address_from_uri(grpc_lb_addresses *addresses, + size_t index, const grpc_uri *uri, + bool is_balancer, + const char *balancer_name, + void *user_data); + /** Compares \a addresses1 and \a addresses2. */ int grpc_lb_addresses_cmp(const grpc_lb_addresses *addresses1, const grpc_lb_addresses *addresses2); /** Destroys \a addresses. */ -void grpc_lb_addresses_destroy(grpc_lb_addresses *addresses); +void grpc_lb_addresses_destroy(grpc_exec_ctx *exec_ctx, + grpc_lb_addresses *addresses); /** Returns a channel arg containing \a addresses. */ grpc_arg grpc_lb_addresses_create_channel_arg( const grpc_lb_addresses *addresses); +/** Returns the \a grpc_lb_addresses instance in \a channel_args or NULL */ +grpc_lb_addresses *grpc_lb_addresses_find_channel_arg( + const grpc_channel_args *channel_args); + /** Arguments passed to LB policies. */ -typedef struct grpc_lb_policy_args { +struct grpc_lb_policy_args { grpc_client_channel_factory *client_channel_factory; grpc_channel_args *args; -} grpc_lb_policy_args; + grpc_combiner *combiner; +}; struct grpc_lb_policy_factory_vtable { void (*ref)(grpc_lb_policy_factory *factory); @@ -129,4 +130,4 @@ grpc_lb_policy *grpc_lb_policy_factory_create_lb_policy( grpc_exec_ctx *exec_ctx, grpc_lb_policy_factory *factory, grpc_lb_policy_args *args); -#endif /* GRPC_CORE_EXT_CLIENT_CHANNEL_LB_POLICY_FACTORY_H */ +#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_FACTORY_H */ diff --git a/Sources/CgRPC/src/core/ext/filters/client_channel/lb_policy_registry.c b/Sources/CgRPC/src/core/ext/filters/client_channel/lb_policy_registry.c new file mode 100644 index 000000000..f2460f830 --- /dev/null +++ b/Sources/CgRPC/src/core/ext/filters/client_channel/lb_policy_registry.c @@ -0,0 +1,70 @@ +/* + * + * 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 "src/core/ext/filters/client_channel/lb_policy_registry.h" + +#include + +#include "src/core/lib/support/string.h" + +#define MAX_POLICIES 10 + +static grpc_lb_policy_factory *g_all_of_the_lb_policies[MAX_POLICIES]; +static int g_number_of_lb_policies = 0; + +void grpc_lb_policy_registry_init(void) { g_number_of_lb_policies = 0; } + +void grpc_lb_policy_registry_shutdown(void) { + int i; + for (i = 0; i < g_number_of_lb_policies; i++) { + grpc_lb_policy_factory_unref(g_all_of_the_lb_policies[i]); + } +} + +void grpc_register_lb_policy(grpc_lb_policy_factory *factory) { + int i; + for (i = 0; i < g_number_of_lb_policies; i++) { + GPR_ASSERT(0 != gpr_stricmp(factory->vtable->name, + g_all_of_the_lb_policies[i]->vtable->name)); + } + GPR_ASSERT(g_number_of_lb_policies != MAX_POLICIES); + grpc_lb_policy_factory_ref(factory); + g_all_of_the_lb_policies[g_number_of_lb_policies++] = factory; +} + +static grpc_lb_policy_factory *lookup_factory(const char *name) { + int i; + + if (name == NULL) return NULL; + + for (i = 0; i < g_number_of_lb_policies; i++) { + if (0 == gpr_stricmp(name, g_all_of_the_lb_policies[i]->vtable->name)) { + return g_all_of_the_lb_policies[i]; + } + } + + return NULL; +} + +grpc_lb_policy *grpc_lb_policy_create(grpc_exec_ctx *exec_ctx, const char *name, + grpc_lb_policy_args *args) { + grpc_lb_policy_factory *factory = lookup_factory(name); + grpc_lb_policy *lb_policy = + grpc_lb_policy_factory_create_lb_policy(exec_ctx, factory, args); + return lb_policy; +} diff --git a/Sources/CgRPC/src/core/ext/filters/client_channel/lb_policy_registry.h b/Sources/CgRPC/src/core/ext/filters/client_channel/lb_policy_registry.h new file mode 100644 index 000000000..f5995687c --- /dev/null +++ b/Sources/CgRPC/src/core/ext/filters/client_channel/lb_policy_registry.h @@ -0,0 +1,40 @@ +/* + * + * 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 GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_REGISTRY_H +#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_REGISTRY_H + +#include "src/core/ext/filters/client_channel/lb_policy_factory.h" +#include "src/core/lib/iomgr/exec_ctx.h" + +/** Initialize the registry and set \a default_factory as the factory to be + * returned when no name is provided in a lookup */ +void grpc_lb_policy_registry_init(void); +void grpc_lb_policy_registry_shutdown(void); + +/** Register a LB policy factory. */ +void grpc_register_lb_policy(grpc_lb_policy_factory *factory); + +/** Create a \a grpc_lb_policy instance. + * + * If \a name is NULL, the default factory from \a grpc_lb_policy_registry_init + * will be returned. */ +grpc_lb_policy *grpc_lb_policy_create(grpc_exec_ctx *exec_ctx, const char *name, + grpc_lb_policy_args *args); + +#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_REGISTRY_H */ diff --git a/Sources/CgRPC/src/core/ext/filters/client_channel/parse_address.c b/Sources/CgRPC/src/core/ext/filters/client_channel/parse_address.c new file mode 100644 index 000000000..2152b5a1e --- /dev/null +++ b/Sources/CgRPC/src/core/ext/filters/client_channel/parse_address.c @@ -0,0 +1,186 @@ +/* + * + * Copyright 2016 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 "src/core/ext/filters/client_channel/parse_address.h" +#include "src/core/lib/iomgr/sockaddr.h" + +#include +#include +#ifdef GRPC_HAVE_UNIX_SOCKET +#include +#endif + +#include +#include +#include +#include +#include "src/core/lib/support/string.h" + +#ifdef GRPC_HAVE_UNIX_SOCKET + +bool grpc_parse_unix(const grpc_uri *uri, + grpc_resolved_address *resolved_addr) { + if (strcmp("unix", uri->scheme) != 0) { + gpr_log(GPR_ERROR, "Expected 'unix' scheme, got '%s'", uri->scheme); + return false; + } + struct sockaddr_un *un = (struct sockaddr_un *)resolved_addr->addr; + const size_t maxlen = sizeof(un->sun_path); + const size_t path_len = strnlen(uri->path, maxlen); + if (path_len == maxlen) return false; + un->sun_family = AF_UNIX; + strcpy(un->sun_path, uri->path); + resolved_addr->len = sizeof(*un); + return true; +} + +#else /* GRPC_HAVE_UNIX_SOCKET */ + +bool grpc_parse_unix(const grpc_uri *uri, + grpc_resolved_address *resolved_addr) { + abort(); +} + +#endif /* GRPC_HAVE_UNIX_SOCKET */ + +bool grpc_parse_ipv4_hostport(const char *hostport, grpc_resolved_address *addr, + bool log_errors) { + bool success = false; + // Split host and port. + char *host; + char *port; + if (!gpr_split_host_port(hostport, &host, &port)) return false; + // Parse IP address. + memset(addr, 0, sizeof(*addr)); + addr->len = sizeof(struct sockaddr_in); + struct sockaddr_in *in = (struct sockaddr_in *)addr->addr; + in->sin_family = AF_INET; + if (inet_pton(AF_INET, host, &in->sin_addr) == 0) { + if (log_errors) gpr_log(GPR_ERROR, "invalid ipv4 address: '%s'", host); + goto done; + } + // Parse port. + if (port == NULL) { + if (log_errors) gpr_log(GPR_ERROR, "no port given for ipv4 scheme"); + goto done; + } + int port_num; + if (sscanf(port, "%d", &port_num) != 1 || port_num < 0 || port_num > 65535) { + if (log_errors) gpr_log(GPR_ERROR, "invalid ipv4 port: '%s'", port); + goto done; + } + in->sin_port = htons((uint16_t)port_num); + success = true; +done: + gpr_free(host); + gpr_free(port); + return success; +} + +bool grpc_parse_ipv4(const grpc_uri *uri, + grpc_resolved_address *resolved_addr) { + if (strcmp("ipv4", uri->scheme) != 0) { + gpr_log(GPR_ERROR, "Expected 'ipv4' scheme, got '%s'", uri->scheme); + return false; + } + const char *host_port = uri->path; + if (*host_port == '/') ++host_port; + return grpc_parse_ipv4_hostport(host_port, resolved_addr, + true /* log_errors */); +} + +bool grpc_parse_ipv6_hostport(const char *hostport, grpc_resolved_address *addr, + bool log_errors) { + bool success = false; + // Split host and port. + char *host; + char *port; + if (!gpr_split_host_port(hostport, &host, &port)) return false; + // Parse IP address. + memset(addr, 0, sizeof(*addr)); + addr->len = sizeof(struct sockaddr_in6); + struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)addr->addr; + in6->sin6_family = AF_INET6; + // Handle the RFC6874 syntax for IPv6 zone identifiers. + char *host_end = (char *)gpr_memrchr(host, '%', strlen(host)); + if (host_end != NULL) { + GPR_ASSERT(host_end >= host); + char host_without_scope[INET6_ADDRSTRLEN]; + size_t host_without_scope_len = (size_t)(host_end - host); + uint32_t sin6_scope_id = 0; + strncpy(host_without_scope, host, host_without_scope_len); + host_without_scope[host_without_scope_len] = '\0'; + if (inet_pton(AF_INET6, host_without_scope, &in6->sin6_addr) == 0) { + gpr_log(GPR_ERROR, "invalid ipv6 address: '%s'", host_without_scope); + goto done; + } + if (gpr_parse_bytes_to_uint32(host_end + 1, + strlen(host) - host_without_scope_len - 1, + &sin6_scope_id) == 0) { + gpr_log(GPR_ERROR, "invalid ipv6 scope id: '%s'", host_end + 1); + goto done; + } + // Handle "sin6_scope_id" being type "u_long". See grpc issue #10027. + in6->sin6_scope_id = sin6_scope_id; + } else { + if (inet_pton(AF_INET6, host, &in6->sin6_addr) == 0) { + gpr_log(GPR_ERROR, "invalid ipv6 address: '%s'", host); + goto done; + } + } + // Parse port. + if (port == NULL) { + if (log_errors) gpr_log(GPR_ERROR, "no port given for ipv6 scheme"); + goto done; + } + int port_num; + if (sscanf(port, "%d", &port_num) != 1 || port_num < 0 || port_num > 65535) { + if (log_errors) gpr_log(GPR_ERROR, "invalid ipv6 port: '%s'", port); + goto done; + } + in6->sin6_port = htons((uint16_t)port_num); + success = true; +done: + gpr_free(host); + gpr_free(port); + return success; +} + +bool grpc_parse_ipv6(const grpc_uri *uri, + grpc_resolved_address *resolved_addr) { + if (strcmp("ipv6", uri->scheme) != 0) { + gpr_log(GPR_ERROR, "Expected 'ipv6' scheme, got '%s'", uri->scheme); + return false; + } + const char *host_port = uri->path; + if (*host_port == '/') ++host_port; + return grpc_parse_ipv6_hostport(host_port, resolved_addr, + true /* log_errors */); +} + +bool grpc_parse_uri(const grpc_uri *uri, grpc_resolved_address *resolved_addr) { + if (strcmp("unix", uri->scheme) == 0) { + return grpc_parse_unix(uri, resolved_addr); + } else if (strcmp("ipv4", uri->scheme) == 0) { + return grpc_parse_ipv4(uri, resolved_addr); + } else if (strcmp("ipv6", uri->scheme) == 0) { + return grpc_parse_ipv6(uri, resolved_addr); + } + gpr_log(GPR_ERROR, "Can't parse scheme '%s'", uri->scheme); + return false; +} diff --git a/Sources/CgRPC/src/core/ext/filters/client_channel/parse_address.h b/Sources/CgRPC/src/core/ext/filters/client_channel/parse_address.h new file mode 100644 index 000000000..c90a827da --- /dev/null +++ b/Sources/CgRPC/src/core/ext/filters/client_channel/parse_address.h @@ -0,0 +1,48 @@ +/* + * + * 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 GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_PARSE_ADDRESS_H +#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_PARSE_ADDRESS_H + +#include + +#include "src/core/ext/filters/client_channel/uri_parser.h" +#include "src/core/lib/iomgr/resolve_address.h" + +/** Populate \a resolved_addr from \a uri, whose path is expected to contain a + * unix socket path. Returns true upon success. */ +bool grpc_parse_unix(const grpc_uri *uri, grpc_resolved_address *resolved_addr); + +/** Populate \a resolved_addr from \a uri, whose path is expected to contain an + * IPv4 host:port pair. Returns true upon success. */ +bool grpc_parse_ipv4(const grpc_uri *uri, grpc_resolved_address *resolved_addr); + +/** Populate \a resolved_addr from \a uri, whose path is expected to contain an + * IPv6 host:port pair. Returns true upon success. */ +bool grpc_parse_ipv6(const grpc_uri *uri, grpc_resolved_address *resolved_addr); + +/** Populate \a resolved_addr from \a uri. Returns true upon success. */ +bool grpc_parse_uri(const grpc_uri *uri, grpc_resolved_address *resolved_addr); + +/** Parse bare IPv4 or IPv6 "IP:port" strings. */ +bool grpc_parse_ipv4_hostport(const char *hostport, grpc_resolved_address *addr, + bool log_errors); +bool grpc_parse_ipv6_hostport(const char *hostport, grpc_resolved_address *addr, + bool log_errors); + +#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_PARSE_ADDRESS_H */ diff --git a/Sources/CgRPC/src/core/ext/filters/client_channel/proxy_mapper.c b/Sources/CgRPC/src/core/ext/filters/client_channel/proxy_mapper.c new file mode 100644 index 000000000..c6ea5fc68 --- /dev/null +++ b/Sources/CgRPC/src/core/ext/filters/client_channel/proxy_mapper.c @@ -0,0 +1,48 @@ +/* + * + * Copyright 2017 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 "src/core/ext/filters/client_channel/proxy_mapper.h" + +void grpc_proxy_mapper_init(const grpc_proxy_mapper_vtable* vtable, + grpc_proxy_mapper* mapper) { + mapper->vtable = vtable; +} + +bool grpc_proxy_mapper_map_name(grpc_exec_ctx* exec_ctx, + grpc_proxy_mapper* mapper, + const char* server_uri, + const grpc_channel_args* args, + char** name_to_resolve, + grpc_channel_args** new_args) { + return mapper->vtable->map_name(exec_ctx, mapper, server_uri, args, + name_to_resolve, new_args); +} + +bool grpc_proxy_mapper_map_address(grpc_exec_ctx* exec_ctx, + grpc_proxy_mapper* mapper, + const grpc_resolved_address* address, + const grpc_channel_args* args, + grpc_resolved_address** new_address, + grpc_channel_args** new_args) { + return mapper->vtable->map_address(exec_ctx, mapper, address, args, + new_address, new_args); +} + +void grpc_proxy_mapper_destroy(grpc_proxy_mapper* mapper) { + mapper->vtable->destroy(mapper); +} diff --git a/Sources/CgRPC/src/core/ext/filters/client_channel/proxy_mapper.h b/Sources/CgRPC/src/core/ext/filters/client_channel/proxy_mapper.h new file mode 100644 index 000000000..a13861cca --- /dev/null +++ b/Sources/CgRPC/src/core/ext/filters/client_channel/proxy_mapper.h @@ -0,0 +1,74 @@ +/* + * + * Copyright 2017 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 GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_PROXY_MAPPER_H +#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_PROXY_MAPPER_H + +#include + +#include + +#include "src/core/lib/iomgr/resolve_address.h" + +typedef struct grpc_proxy_mapper grpc_proxy_mapper; + +typedef struct { + /// Determines the proxy name to resolve for \a server_uri. + /// If no proxy is needed, returns false. + /// Otherwise, sets \a name_to_resolve, optionally sets \a new_args, + /// and returns true. + bool (*map_name)(grpc_exec_ctx* exec_ctx, grpc_proxy_mapper* mapper, + const char* server_uri, const grpc_channel_args* args, + char** name_to_resolve, grpc_channel_args** new_args); + /// Determines the proxy address to use to contact \a address. + /// If no proxy is needed, returns false. + /// Otherwise, sets \a new_address, optionally sets \a new_args, and + /// returns true. + bool (*map_address)(grpc_exec_ctx* exec_ctx, grpc_proxy_mapper* mapper, + const grpc_resolved_address* address, + const grpc_channel_args* args, + grpc_resolved_address** new_address, + grpc_channel_args** new_args); + /// Destroys \a mapper. + void (*destroy)(grpc_proxy_mapper* mapper); +} grpc_proxy_mapper_vtable; + +struct grpc_proxy_mapper { + const grpc_proxy_mapper_vtable* vtable; +}; + +void grpc_proxy_mapper_init(const grpc_proxy_mapper_vtable* vtable, + grpc_proxy_mapper* mapper); + +bool grpc_proxy_mapper_map_name(grpc_exec_ctx* exec_ctx, + grpc_proxy_mapper* mapper, + const char* server_uri, + const grpc_channel_args* args, + char** name_to_resolve, + grpc_channel_args** new_args); + +bool grpc_proxy_mapper_map_address(grpc_exec_ctx* exec_ctx, + grpc_proxy_mapper* mapper, + const grpc_resolved_address* address, + const grpc_channel_args* args, + grpc_resolved_address** new_address, + grpc_channel_args** new_args); + +void grpc_proxy_mapper_destroy(grpc_proxy_mapper* mapper); + +#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_PROXY_MAPPER_H */ diff --git a/Sources/CgRPC/src/core/ext/filters/client_channel/proxy_mapper_registry.c b/Sources/CgRPC/src/core/ext/filters/client_channel/proxy_mapper_registry.c new file mode 100644 index 000000000..5f43a0596 --- /dev/null +++ b/Sources/CgRPC/src/core/ext/filters/client_channel/proxy_mapper_registry.c @@ -0,0 +1,124 @@ +/* + * + * Copyright 2017 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 "src/core/ext/filters/client_channel/proxy_mapper_registry.h" + +#include + +#include + +// +// grpc_proxy_mapper_list +// + +typedef struct { + grpc_proxy_mapper** list; + size_t num_mappers; +} grpc_proxy_mapper_list; + +static void grpc_proxy_mapper_list_register(grpc_proxy_mapper_list* list, + bool at_start, + grpc_proxy_mapper* mapper) { + list->list = gpr_realloc( + list->list, (list->num_mappers + 1) * sizeof(grpc_proxy_mapper*)); + if (at_start) { + memmove(list->list + 1, list->list, + sizeof(grpc_proxy_mapper*) * list->num_mappers); + list->list[0] = mapper; + } else { + list->list[list->num_mappers] = mapper; + } + ++list->num_mappers; +} + +static bool grpc_proxy_mapper_list_map_name(grpc_exec_ctx* exec_ctx, + grpc_proxy_mapper_list* list, + const char* server_uri, + const grpc_channel_args* args, + char** name_to_resolve, + grpc_channel_args** new_args) { + for (size_t i = 0; i < list->num_mappers; ++i) { + if (grpc_proxy_mapper_map_name(exec_ctx, list->list[i], server_uri, args, + name_to_resolve, new_args)) { + return true; + } + } + return false; +} + +static bool grpc_proxy_mapper_list_map_address( + grpc_exec_ctx* exec_ctx, grpc_proxy_mapper_list* list, + const grpc_resolved_address* address, const grpc_channel_args* args, + grpc_resolved_address** new_address, grpc_channel_args** new_args) { + for (size_t i = 0; i < list->num_mappers; ++i) { + if (grpc_proxy_mapper_map_address(exec_ctx, list->list[i], address, args, + new_address, new_args)) { + return true; + } + } + return false; +} + +static void grpc_proxy_mapper_list_destroy(grpc_proxy_mapper_list* list) { + for (size_t i = 0; i < list->num_mappers; ++i) { + grpc_proxy_mapper_destroy(list->list[i]); + } + gpr_free(list->list); + // Clean up in case we re-initialze later. + // TODO(ctiller): This should ideally live in + // grpc_proxy_mapper_registry_init(). However, if we did this there, + // then we would do it AFTER we start registering proxy mappers from + // third-party plugins, so they'd never show up (and would leak memory). + // We probably need some sort of dependency system for plugins to fix + // this. + memset(list, 0, sizeof(*list)); +} + +// +// plugin +// + +static grpc_proxy_mapper_list g_proxy_mapper_list; + +void grpc_proxy_mapper_registry_init() {} + +void grpc_proxy_mapper_registry_shutdown() { + grpc_proxy_mapper_list_destroy(&g_proxy_mapper_list); +} + +void grpc_proxy_mapper_register(bool at_start, grpc_proxy_mapper* mapper) { + grpc_proxy_mapper_list_register(&g_proxy_mapper_list, at_start, mapper); +} + +bool grpc_proxy_mappers_map_name(grpc_exec_ctx* exec_ctx, + const char* server_uri, + const grpc_channel_args* args, + char** name_to_resolve, + grpc_channel_args** new_args) { + return grpc_proxy_mapper_list_map_name(exec_ctx, &g_proxy_mapper_list, + server_uri, args, name_to_resolve, + new_args); +} +bool grpc_proxy_mappers_map_address(grpc_exec_ctx* exec_ctx, + const grpc_resolved_address* address, + const grpc_channel_args* args, + grpc_resolved_address** new_address, + grpc_channel_args** new_args) { + return grpc_proxy_mapper_list_map_address( + exec_ctx, &g_proxy_mapper_list, address, args, new_address, new_args); +} diff --git a/Sources/CgRPC/src/core/ext/filters/client_channel/proxy_mapper_registry.h b/Sources/CgRPC/src/core/ext/filters/client_channel/proxy_mapper_registry.h new file mode 100644 index 000000000..99e54d1a7 --- /dev/null +++ b/Sources/CgRPC/src/core/ext/filters/client_channel/proxy_mapper_registry.h @@ -0,0 +1,44 @@ +/* + * + * Copyright 2017 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 GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_PROXY_MAPPER_REGISTRY_H +#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_PROXY_MAPPER_REGISTRY_H + +#include "src/core/ext/filters/client_channel/proxy_mapper.h" + +void grpc_proxy_mapper_registry_init(); +void grpc_proxy_mapper_registry_shutdown(); + +/// Registers a new proxy mapper. Takes ownership. +/// If \a at_start is true, the new mapper will be at the beginning of +/// the list. Otherwise, it will be added to the end. +void grpc_proxy_mapper_register(bool at_start, grpc_proxy_mapper* mapper); + +bool grpc_proxy_mappers_map_name(grpc_exec_ctx* exec_ctx, + const char* server_uri, + const grpc_channel_args* args, + char** name_to_resolve, + grpc_channel_args** new_args); + +bool grpc_proxy_mappers_map_address(grpc_exec_ctx* exec_ctx, + const grpc_resolved_address* address, + const grpc_channel_args* args, + grpc_resolved_address** new_address, + grpc_channel_args** new_args); + +#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_PROXY_MAPPER_REGISTRY_H */ diff --git a/Sources/CgRPC/src/core/ext/filters/client_channel/resolver.c b/Sources/CgRPC/src/core/ext/filters/client_channel/resolver.c new file mode 100644 index 000000000..8401504fc --- /dev/null +++ b/Sources/CgRPC/src/core/ext/filters/client_channel/resolver.c @@ -0,0 +1,83 @@ +/* + * + * 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 "src/core/ext/filters/client_channel/resolver.h" +#include "src/core/lib/iomgr/combiner.h" + +#ifndef NDEBUG +grpc_tracer_flag grpc_trace_resolver_refcount = + GRPC_TRACER_INITIALIZER(false, "resolver_refcount"); +#endif + +void grpc_resolver_init(grpc_resolver *resolver, + const grpc_resolver_vtable *vtable, + grpc_combiner *combiner) { + resolver->vtable = vtable; + resolver->combiner = GRPC_COMBINER_REF(combiner, "resolver"); + gpr_ref_init(&resolver->refs, 1); +} + +#ifndef NDEBUG +void grpc_resolver_ref(grpc_resolver *resolver, const char *file, int line, + const char *reason) { + if (GRPC_TRACER_ON(grpc_trace_resolver_refcount)) { + gpr_atm old_refs = gpr_atm_no_barrier_load(&resolver->refs.count); + gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, + "RESOLVER:%p ref %" PRIdPTR " -> %" PRIdPTR " %s", resolver, + old_refs, old_refs + 1, reason); + } +#else +void grpc_resolver_ref(grpc_resolver *resolver) { +#endif + gpr_ref(&resolver->refs); +} + +#ifndef NDEBUG +void grpc_resolver_unref(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver, + const char *file, int line, const char *reason) { + if (GRPC_TRACER_ON(grpc_trace_resolver_refcount)) { + gpr_atm old_refs = gpr_atm_no_barrier_load(&resolver->refs.count); + gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, + "RESOLVER:%p unref %" PRIdPTR " -> %" PRIdPTR " %s", resolver, + old_refs, old_refs - 1, reason); + } +#else +void grpc_resolver_unref(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver) { +#endif + if (gpr_unref(&resolver->refs)) { + grpc_combiner *combiner = resolver->combiner; + resolver->vtable->destroy(exec_ctx, resolver); + GRPC_COMBINER_UNREF(exec_ctx, combiner, "resolver"); + } +} + +void grpc_resolver_shutdown_locked(grpc_exec_ctx *exec_ctx, + grpc_resolver *resolver) { + resolver->vtable->shutdown_locked(exec_ctx, resolver); +} + +void grpc_resolver_channel_saw_error_locked(grpc_exec_ctx *exec_ctx, + grpc_resolver *resolver) { + resolver->vtable->channel_saw_error_locked(exec_ctx, resolver); +} + +void grpc_resolver_next_locked(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver, + grpc_channel_args **result, + grpc_closure *on_complete) { + resolver->vtable->next_locked(exec_ctx, resolver, result, on_complete); +} diff --git a/Sources/CgRPC/src/core/ext/filters/client_channel/resolver.h b/Sources/CgRPC/src/core/ext/filters/client_channel/resolver.h new file mode 100644 index 000000000..ae9c8f66f --- /dev/null +++ b/Sources/CgRPC/src/core/ext/filters/client_channel/resolver.h @@ -0,0 +1,90 @@ +/* + * + * 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 GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_H +#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_H + +#include "src/core/ext/filters/client_channel/subchannel.h" +#include "src/core/lib/iomgr/iomgr.h" + +typedef struct grpc_resolver grpc_resolver; +typedef struct grpc_resolver_vtable grpc_resolver_vtable; + +#ifndef NDEBUG +extern grpc_tracer_flag grpc_trace_resolver_refcount; +#endif + +/** \a grpc_resolver provides \a grpc_channel_args objects to its caller */ +struct grpc_resolver { + const grpc_resolver_vtable *vtable; + gpr_refcount refs; + grpc_combiner *combiner; +}; + +struct grpc_resolver_vtable { + void (*destroy)(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver); + void (*shutdown_locked)(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver); + void (*channel_saw_error_locked)(grpc_exec_ctx *exec_ctx, + grpc_resolver *resolver); + void (*next_locked)(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver, + grpc_channel_args **result, grpc_closure *on_complete); +}; + +#ifndef NDEBUG +#define GRPC_RESOLVER_REF(p, r) grpc_resolver_ref((p), __FILE__, __LINE__, (r)) +#define GRPC_RESOLVER_UNREF(e, p, r) \ + grpc_resolver_unref((e), (p), __FILE__, __LINE__, (r)) +void grpc_resolver_ref(grpc_resolver *policy, const char *file, int line, + const char *reason); +void grpc_resolver_unref(grpc_exec_ctx *exec_ctx, grpc_resolver *policy, + const char *file, int line, const char *reason); +#else +#define GRPC_RESOLVER_REF(p, r) grpc_resolver_ref((p)) +#define GRPC_RESOLVER_UNREF(e, p, r) grpc_resolver_unref((e), (p)) +void grpc_resolver_ref(grpc_resolver *policy); +void grpc_resolver_unref(grpc_exec_ctx *exec_ctx, grpc_resolver *policy); +#endif + +void grpc_resolver_init(grpc_resolver *resolver, + const grpc_resolver_vtable *vtable, + grpc_combiner *combiner); + +void grpc_resolver_shutdown_locked(grpc_exec_ctx *exec_ctx, + grpc_resolver *resolver); + +/** Notification that the channel has seen an error on some address. + Can be used as a hint that re-resolution is desirable soon. + + Must be called from the combiner passed as a resolver_arg at construction + time.*/ +void grpc_resolver_channel_saw_error_locked(grpc_exec_ctx *exec_ctx, + grpc_resolver *resolver); + +/** Get the next result from the resolver. Expected to set \a *result with + new channel args and then schedule \a on_complete for execution. + + If resolution is fatally broken, set \a *result to NULL and + schedule \a on_complete. + + Must be called from the combiner passed as a resolver_arg at construction + time.*/ +void grpc_resolver_next_locked(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver, + grpc_channel_args **result, + grpc_closure *on_complete); + +#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_H */ diff --git a/Sources/CgRPC/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.c b/Sources/CgRPC/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.c new file mode 100644 index 000000000..f1480bb1a --- /dev/null +++ b/Sources/CgRPC/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.c @@ -0,0 +1,457 @@ +/* + * + * 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 +#if GRPC_ARES == 1 && !defined(GRPC_UV) + +#include +#include +#include +#include + +#include +#include +#include + +#include "src/core/ext/filters/client_channel/http_connect_handshaker.h" +#include "src/core/ext/filters/client_channel/lb_policy_registry.h" +#include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h" +#include "src/core/ext/filters/client_channel/resolver_registry.h" +#include "src/core/lib/channel/channel_args.h" +#include "src/core/lib/iomgr/combiner.h" +#include "src/core/lib/iomgr/gethostname.h" +#include "src/core/lib/iomgr/resolve_address.h" +#include "src/core/lib/iomgr/timer.h" +#include "src/core/lib/json/json.h" +#include "src/core/lib/support/backoff.h" +#include "src/core/lib/support/env.h" +#include "src/core/lib/support/string.h" +#include "src/core/lib/transport/service_config.h" + +#define GRPC_DNS_MIN_CONNECT_TIMEOUT_SECONDS 1 +#define GRPC_DNS_INITIAL_CONNECT_BACKOFF_SECONDS 1 +#define GRPC_DNS_RECONNECT_BACKOFF_MULTIPLIER 1.6 +#define GRPC_DNS_RECONNECT_MAX_BACKOFF_SECONDS 120 +#define GRPC_DNS_RECONNECT_JITTER 0.2 + +typedef struct { + /** base class: must be first */ + grpc_resolver base; + /** DNS server to use (if not system default) */ + char *dns_server; + /** name to resolve (usually the same as target_name) */ + char *name_to_resolve; + /** default port to use */ + char *default_port; + /** channel args. */ + grpc_channel_args *channel_args; + /** whether to request the service config */ + bool request_service_config; + /** pollset_set to drive the name resolution process */ + grpc_pollset_set *interested_parties; + + /** Closures used by the combiner */ + grpc_closure dns_ares_on_retry_timer_locked; + grpc_closure dns_ares_on_resolved_locked; + + /** Combiner guarding the rest of the state */ + grpc_combiner *combiner; + /** are we currently resolving? */ + bool resolving; + /** the pending resolving request */ + grpc_ares_request *pending_request; + /** which version of the result have we published? */ + int published_version; + /** which version of the result is current? */ + int resolved_version; + /** pending next completion, or NULL */ + grpc_closure *next_completion; + /** target result address for next completion */ + grpc_channel_args **target_result; + /** current (fully resolved) result */ + grpc_channel_args *resolved_result; + /** retry timer */ + bool have_retry_timer; + grpc_timer retry_timer; + /** retry backoff state */ + gpr_backoff backoff_state; + + /** currently resolving addresses */ + grpc_lb_addresses *lb_addresses; + /** currently resolving service config */ + char *service_config_json; +} ares_dns_resolver; + +static void dns_ares_destroy(grpc_exec_ctx *exec_ctx, grpc_resolver *r); + +static void dns_ares_start_resolving_locked(grpc_exec_ctx *exec_ctx, + ares_dns_resolver *r); +static void dns_ares_maybe_finish_next_locked(grpc_exec_ctx *exec_ctx, + ares_dns_resolver *r); + +static void dns_ares_shutdown_locked(grpc_exec_ctx *exec_ctx, grpc_resolver *r); +static void dns_ares_channel_saw_error_locked(grpc_exec_ctx *exec_ctx, + grpc_resolver *r); +static void dns_ares_next_locked(grpc_exec_ctx *exec_ctx, grpc_resolver *r, + grpc_channel_args **target_result, + grpc_closure *on_complete); + +static const grpc_resolver_vtable dns_ares_resolver_vtable = { + dns_ares_destroy, dns_ares_shutdown_locked, + dns_ares_channel_saw_error_locked, dns_ares_next_locked}; + +static void dns_ares_shutdown_locked(grpc_exec_ctx *exec_ctx, + grpc_resolver *resolver) { + ares_dns_resolver *r = (ares_dns_resolver *)resolver; + if (r->have_retry_timer) { + grpc_timer_cancel(exec_ctx, &r->retry_timer); + } + if (r->pending_request != NULL) { + grpc_cancel_ares_request(exec_ctx, r->pending_request); + } + if (r->next_completion != NULL) { + *r->target_result = NULL; + GRPC_CLOSURE_SCHED( + exec_ctx, r->next_completion, + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Resolver Shutdown")); + r->next_completion = NULL; + } +} + +static void dns_ares_channel_saw_error_locked(grpc_exec_ctx *exec_ctx, + grpc_resolver *resolver) { + ares_dns_resolver *r = (ares_dns_resolver *)resolver; + if (!r->resolving) { + gpr_backoff_reset(&r->backoff_state); + dns_ares_start_resolving_locked(exec_ctx, r); + } +} + +static void dns_ares_on_retry_timer_locked(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error) { + ares_dns_resolver *r = arg; + r->have_retry_timer = false; + if (error == GRPC_ERROR_NONE) { + if (!r->resolving) { + dns_ares_start_resolving_locked(exec_ctx, r); + } + } + GRPC_RESOLVER_UNREF(exec_ctx, &r->base, "retry-timer"); +} + +static bool value_in_json_array(grpc_json *array, const char *value) { + for (grpc_json *entry = array->child; entry != NULL; entry = entry->next) { + if (entry->type == GRPC_JSON_STRING && strcmp(entry->value, value) == 0) { + return true; + } + } + return false; +} + +static char *choose_service_config(char *service_config_choice_json) { + grpc_json *choices_json = grpc_json_parse_string(service_config_choice_json); + if (choices_json == NULL || choices_json->type != GRPC_JSON_ARRAY) { + gpr_log(GPR_ERROR, "cannot parse service config JSON string"); + return NULL; + } + char *service_config = NULL; + for (grpc_json *choice = choices_json->child; choice != NULL; + choice = choice->next) { + if (choice->type != GRPC_JSON_OBJECT) { + gpr_log(GPR_ERROR, "cannot parse service config JSON string"); + break; + } + grpc_json *service_config_json = NULL; + for (grpc_json *field = choice->child; field != NULL; field = field->next) { + // Check client language, if specified. + if (strcmp(field->key, "clientLanguage") == 0) { + if (field->type != GRPC_JSON_ARRAY || + !value_in_json_array(field, "c++")) { + service_config_json = NULL; + break; + } + } + // Check client hostname, if specified. + if (strcmp(field->key, "clientHostname") == 0) { + char *hostname = grpc_gethostname(); + if (hostname == NULL || field->type != GRPC_JSON_ARRAY || + !value_in_json_array(field, hostname)) { + service_config_json = NULL; + break; + } + } + // Check percentage, if specified. + if (strcmp(field->key, "percentage") == 0) { + if (field->type != GRPC_JSON_NUMBER) { + service_config_json = NULL; + break; + } + int random_pct = rand() % 100; + int percentage; + if (sscanf(field->value, "%d", &percentage) != 1 || + random_pct > percentage) { + service_config_json = NULL; + break; + } + } + // Save service config. + if (strcmp(field->key, "serviceConfig") == 0) { + if (field->type == GRPC_JSON_OBJECT) { + service_config_json = field; + } + } + } + if (service_config_json != NULL) { + service_config = grpc_json_dump_to_string(service_config_json, 0); + break; + } + } + grpc_json_destroy(choices_json); + return service_config; +} + +static void dns_ares_on_resolved_locked(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error) { + ares_dns_resolver *r = arg; + grpc_channel_args *result = NULL; + GPR_ASSERT(r->resolving); + r->resolving = false; + r->pending_request = NULL; + if (r->lb_addresses != NULL) { + static const char *args_to_remove[2]; + size_t num_args_to_remove = 0; + grpc_arg new_args[3]; + size_t num_args_to_add = 0; + new_args[num_args_to_add++] = + grpc_lb_addresses_create_channel_arg(r->lb_addresses); + grpc_service_config *service_config = NULL; + char *service_config_string = NULL; + if (r->service_config_json != NULL) { + service_config_string = choose_service_config(r->service_config_json); + gpr_free(r->service_config_json); + if (service_config_string != NULL) { + gpr_log(GPR_INFO, "selected service config choice: %s", + service_config_string); + args_to_remove[num_args_to_remove++] = GRPC_ARG_SERVICE_CONFIG; + new_args[num_args_to_add++] = grpc_channel_arg_string_create( + GRPC_ARG_SERVICE_CONFIG, service_config_string); + service_config = grpc_service_config_create(service_config_string); + if (service_config != NULL) { + const char *lb_policy_name = + grpc_service_config_get_lb_policy_name(service_config); + if (lb_policy_name != NULL) { + args_to_remove[num_args_to_remove++] = GRPC_ARG_LB_POLICY_NAME; + new_args[num_args_to_add++] = grpc_channel_arg_string_create( + GRPC_ARG_LB_POLICY_NAME, (char *)lb_policy_name); + } + } + } + } + result = grpc_channel_args_copy_and_add_and_remove( + r->channel_args, args_to_remove, num_args_to_remove, new_args, + num_args_to_add); + if (service_config != NULL) grpc_service_config_destroy(service_config); + gpr_free(service_config_string); + grpc_lb_addresses_destroy(exec_ctx, r->lb_addresses); + } else { + const char *msg = grpc_error_string(error); + gpr_log(GPR_DEBUG, "dns resolution failed: %s", msg); + gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC); + gpr_timespec next_try = gpr_backoff_step(&r->backoff_state, now); + gpr_timespec timeout = gpr_time_sub(next_try, now); + gpr_log(GPR_INFO, "dns resolution failed (will retry): %s", + grpc_error_string(error)); + GPR_ASSERT(!r->have_retry_timer); + r->have_retry_timer = true; + GRPC_RESOLVER_REF(&r->base, "retry-timer"); + if (gpr_time_cmp(timeout, gpr_time_0(timeout.clock_type)) > 0) { + gpr_log(GPR_DEBUG, "retrying in %" PRId64 ".%09d seconds", timeout.tv_sec, + timeout.tv_nsec); + } else { + gpr_log(GPR_DEBUG, "retrying immediately"); + } + grpc_timer_init(exec_ctx, &r->retry_timer, next_try, + &r->dns_ares_on_retry_timer_locked, now); + } + if (r->resolved_result != NULL) { + grpc_channel_args_destroy(exec_ctx, r->resolved_result); + } + r->resolved_result = result; + r->resolved_version++; + dns_ares_maybe_finish_next_locked(exec_ctx, r); + GRPC_RESOLVER_UNREF(exec_ctx, &r->base, "dns-resolving"); +} + +static void dns_ares_next_locked(grpc_exec_ctx *exec_ctx, + grpc_resolver *resolver, + grpc_channel_args **target_result, + grpc_closure *on_complete) { + gpr_log(GPR_DEBUG, "dns_ares_next is called."); + ares_dns_resolver *r = (ares_dns_resolver *)resolver; + GPR_ASSERT(!r->next_completion); + r->next_completion = on_complete; + r->target_result = target_result; + if (r->resolved_version == 0 && !r->resolving) { + gpr_backoff_reset(&r->backoff_state); + dns_ares_start_resolving_locked(exec_ctx, r); + } else { + dns_ares_maybe_finish_next_locked(exec_ctx, r); + } +} + +static void dns_ares_start_resolving_locked(grpc_exec_ctx *exec_ctx, + ares_dns_resolver *r) { + GRPC_RESOLVER_REF(&r->base, "dns-resolving"); + GPR_ASSERT(!r->resolving); + r->resolving = true; + r->lb_addresses = NULL; + r->service_config_json = NULL; + r->pending_request = grpc_dns_lookup_ares( + exec_ctx, r->dns_server, r->name_to_resolve, r->default_port, + r->interested_parties, &r->dns_ares_on_resolved_locked, &r->lb_addresses, + true /* check_grpclb */, + r->request_service_config ? &r->service_config_json : NULL); +} + +static void dns_ares_maybe_finish_next_locked(grpc_exec_ctx *exec_ctx, + ares_dns_resolver *r) { + if (r->next_completion != NULL && + r->resolved_version != r->published_version) { + *r->target_result = r->resolved_result == NULL + ? NULL + : grpc_channel_args_copy(r->resolved_result); + gpr_log(GPR_DEBUG, "dns_ares_maybe_finish_next_locked"); + GRPC_CLOSURE_SCHED(exec_ctx, r->next_completion, GRPC_ERROR_NONE); + r->next_completion = NULL; + r->published_version = r->resolved_version; + } +} + +static void dns_ares_destroy(grpc_exec_ctx *exec_ctx, grpc_resolver *gr) { + gpr_log(GPR_DEBUG, "dns_ares_destroy"); + ares_dns_resolver *r = (ares_dns_resolver *)gr; + if (r->resolved_result != NULL) { + grpc_channel_args_destroy(exec_ctx, r->resolved_result); + } + grpc_pollset_set_destroy(exec_ctx, r->interested_parties); + gpr_free(r->dns_server); + gpr_free(r->name_to_resolve); + gpr_free(r->default_port); + grpc_channel_args_destroy(exec_ctx, r->channel_args); + gpr_free(r); +} + +static grpc_resolver *dns_ares_create(grpc_exec_ctx *exec_ctx, + grpc_resolver_args *args, + const char *default_port) { + /* Get name from args. */ + const char *path = args->uri->path; + if (path[0] == '/') ++path; + /* Create resolver. */ + ares_dns_resolver *r = gpr_zalloc(sizeof(ares_dns_resolver)); + grpc_resolver_init(&r->base, &dns_ares_resolver_vtable, args->combiner); + if (0 != strcmp(args->uri->authority, "")) { + r->dns_server = gpr_strdup(args->uri->authority); + } + r->name_to_resolve = gpr_strdup(path); + r->default_port = gpr_strdup(default_port); + r->channel_args = grpc_channel_args_copy(args->args); + const grpc_arg *arg = grpc_channel_args_find( + r->channel_args, GRPC_ARG_SERVICE_CONFIG_DISABLE_RESOLUTION); + r->request_service_config = !grpc_channel_arg_get_integer( + arg, (grpc_integer_options){false, false, true}); + r->interested_parties = grpc_pollset_set_create(); + if (args->pollset_set != NULL) { + grpc_pollset_set_add_pollset_set(exec_ctx, r->interested_parties, + args->pollset_set); + } + gpr_backoff_init(&r->backoff_state, GRPC_DNS_INITIAL_CONNECT_BACKOFF_SECONDS, + GRPC_DNS_RECONNECT_BACKOFF_MULTIPLIER, + GRPC_DNS_RECONNECT_JITTER, + GRPC_DNS_MIN_CONNECT_TIMEOUT_SECONDS * 1000, + GRPC_DNS_RECONNECT_MAX_BACKOFF_SECONDS * 1000); + GRPC_CLOSURE_INIT(&r->dns_ares_on_retry_timer_locked, + dns_ares_on_retry_timer_locked, r, + grpc_combiner_scheduler(r->base.combiner)); + GRPC_CLOSURE_INIT(&r->dns_ares_on_resolved_locked, + dns_ares_on_resolved_locked, r, + grpc_combiner_scheduler(r->base.combiner)); + return &r->base; +} + +/* + * FACTORY + */ + +static void dns_ares_factory_ref(grpc_resolver_factory *factory) {} + +static void dns_ares_factory_unref(grpc_resolver_factory *factory) {} + +static grpc_resolver *dns_factory_create_resolver( + grpc_exec_ctx *exec_ctx, grpc_resolver_factory *factory, + grpc_resolver_args *args) { + return dns_ares_create(exec_ctx, args, "https"); +} + +static char *dns_ares_factory_get_default_host_name( + grpc_resolver_factory *factory, grpc_uri *uri) { + const char *path = uri->path; + if (path[0] == '/') ++path; + return gpr_strdup(path); +} + +static const grpc_resolver_factory_vtable dns_ares_factory_vtable = { + dns_ares_factory_ref, dns_ares_factory_unref, dns_factory_create_resolver, + dns_ares_factory_get_default_host_name, "dns"}; +static grpc_resolver_factory dns_resolver_factory = {&dns_ares_factory_vtable}; + +static grpc_resolver_factory *dns_ares_resolver_factory_create() { + return &dns_resolver_factory; +} + +void grpc_resolver_dns_ares_init(void) { + char *resolver = 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 != NULL && gpr_stricmp(resolver, "ares") == 0) { + grpc_error *error = grpc_ares_init(); + if (error != GRPC_ERROR_NONE) { + GRPC_LOG_IF_ERROR("ares_library_init() failed", error); + return; + } + grpc_resolve_address = grpc_resolve_address_ares; + grpc_register_resolver_type(dns_ares_resolver_factory_create()); + } + gpr_free(resolver); +} + +void grpc_resolver_dns_ares_shutdown(void) { + char *resolver = gpr_getenv("GRPC_DNS_RESOLVER"); + if (resolver != NULL && gpr_stricmp(resolver, "ares") == 0) { + grpc_ares_cleanup(); + } + gpr_free(resolver); +} + +#else /* GRPC_ARES == 1 && !defined(GRPC_UV) */ + +void grpc_resolver_dns_ares_init(void) {} + +void grpc_resolver_dns_ares_shutdown(void) {} + +#endif /* GRPC_ARES == 1 && !defined(GRPC_UV) */ diff --git a/Sources/CgRPC/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h b/Sources/CgRPC/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h new file mode 100644 index 000000000..386012d2e --- /dev/null +++ b/Sources/CgRPC/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h @@ -0,0 +1,53 @@ +/* + * + * Copyright 2016 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 GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_DNS_C_ARES_GRPC_ARES_EV_DRIVER_H +#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_DNS_C_ARES_GRPC_ARES_EV_DRIVER_H + +#include "src/core/lib/iomgr/exec_ctx.h" +#include "src/core/lib/iomgr/pollset_set.h" + +typedef struct grpc_ares_ev_driver grpc_ares_ev_driver; + +/* Start \a ev_driver. It will keep working until all IO on its ares_channel is + done, or grpc_ares_ev_driver_destroy() is called. It may notify the callbacks + bound to its ares_channel when necessary. */ +void grpc_ares_ev_driver_start(grpc_exec_ctx *exec_ctx, + grpc_ares_ev_driver *ev_driver); + +/* Returns the ares_channel owned by \a ev_driver. To bind a c-ares query to + \a ev_driver, use the ares_channel owned by \a ev_driver as the arg of the + query. */ +ares_channel *grpc_ares_ev_driver_get_channel(grpc_ares_ev_driver *ev_driver); + +/* Creates a new grpc_ares_ev_driver. Returns GRPC_ERROR_NONE if \a ev_driver is + created successfully. */ +grpc_error *grpc_ares_ev_driver_create(grpc_ares_ev_driver **ev_driver, + grpc_pollset_set *pollset_set); + +/* Destroys \a ev_driver asynchronously. Pending lookups made on \a ev_driver + will be cancelled and their on_done callbacks will be invoked with a status + of ARES_ECANCELLED. */ +void grpc_ares_ev_driver_destroy(grpc_ares_ev_driver *ev_driver); + +/* Shutdown all the grpc_fds used by \a ev_driver */ +void grpc_ares_ev_driver_shutdown(grpc_exec_ctx *exec_ctx, + grpc_ares_ev_driver *ev_driver); + +#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_DNS_C_ARES_GRPC_ARES_EV_DRIVER_H \ + */ diff --git a/Sources/CgRPC/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c b/Sources/CgRPC/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c new file mode 100644 index 000000000..b696344ea --- /dev/null +++ b/Sources/CgRPC/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c @@ -0,0 +1,322 @@ +/* + * + * Copyright 2016 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 +#include "src/core/lib/iomgr/port.h" +#if GRPC_ARES == 1 && defined(GRPC_POSIX_SOCKET) + +#include + +#include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h" + +#include +#include +#include +#include +#include +#include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h" +#include "src/core/lib/iomgr/ev_posix.h" +#include "src/core/lib/iomgr/iomgr_internal.h" +#include "src/core/lib/iomgr/sockaddr_utils.h" +#include "src/core/lib/support/string.h" + +typedef struct fd_node { + /** the owner of this fd node */ + grpc_ares_ev_driver *ev_driver; + /** the grpc_fd owned by this fd node */ + grpc_fd *grpc_fd; + /** a closure wrapping on_readable_cb, which should be invoked when the + grpc_fd in this node becomes readable. */ + grpc_closure read_closure; + /** a closure wrapping on_writable_cb, which should be invoked when the + grpc_fd in this node becomes writable. */ + grpc_closure write_closure; + /** next fd node in the list */ + struct fd_node *next; + + /** mutex guarding the rest of the state */ + gpr_mu mu; + /** if the readable closure has been registered */ + bool readable_registered; + /** if the writable closure has been registered */ + bool writable_registered; +} fd_node; + +struct grpc_ares_ev_driver { + /** the ares_channel owned by this event driver */ + ares_channel channel; + /** pollset set for driving the IO events of the channel */ + grpc_pollset_set *pollset_set; + /** refcount of the event driver */ + gpr_refcount refs; + + /** mutex guarding the rest of the state */ + gpr_mu mu; + /** a list of grpc_fd that this event driver is currently using. */ + fd_node *fds; + /** is this event driver currently working? */ + bool working; + /** is this event driver being shut down */ + bool shutting_down; +}; + +static void grpc_ares_notify_on_event_locked(grpc_exec_ctx *exec_ctx, + 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); + 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); + if (gpr_unref(&ev_driver->refs)) { + gpr_log(GPR_DEBUG, "destroy ev_driver %" PRIuPTR, (uintptr_t)ev_driver); + GPR_ASSERT(ev_driver->fds == NULL); + gpr_mu_destroy(&ev_driver->mu); + ares_destroy(ev_driver->channel); + gpr_free(ev_driver); + } +} + +static void fd_node_destroy(grpc_exec_ctx *exec_ctx, fd_node *fdn) { + gpr_log(GPR_DEBUG, "delete fd: %d", grpc_fd_wrapped_fd(fdn->grpc_fd)); + GPR_ASSERT(!fdn->readable_registered); + GPR_ASSERT(!fdn->writable_registered); + gpr_mu_destroy(&fdn->mu); + grpc_pollset_set_del_fd(exec_ctx, fdn->ev_driver->pollset_set, fdn->grpc_fd); + /* c-ares library has closed the fd inside grpc_fd. This fd may be picked up + immediately by another thread, and should not be closed by the following + grpc_fd_orphan. */ + grpc_fd_orphan(exec_ctx, fdn->grpc_fd, NULL, NULL, true /* already_closed */, + "c-ares query finished"); + gpr_free(fdn); +} + +grpc_error *grpc_ares_ev_driver_create(grpc_ares_ev_driver **ev_driver, + grpc_pollset_set *pollset_set) { + *ev_driver = gpr_malloc(sizeof(grpc_ares_ev_driver)); + int status = ares_init(&(*ev_driver)->channel); + gpr_log(GPR_DEBUG, "grpc_ares_ev_driver_create"); + if (status != ARES_SUCCESS) { + char *err_msg; + gpr_asprintf(&err_msg, "Failed to init ares channel. C-ares error: %s", + ares_strerror(status)); + grpc_error *err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(err_msg); + gpr_free(err_msg); + gpr_free(*ev_driver); + return err; + } + gpr_mu_init(&(*ev_driver)->mu); + gpr_ref_init(&(*ev_driver)->refs, 1); + (*ev_driver)->pollset_set = pollset_set; + (*ev_driver)->fds = NULL; + (*ev_driver)->working = false; + (*ev_driver)->shutting_down = false; + return GRPC_ERROR_NONE; +} + +void grpc_ares_ev_driver_destroy(grpc_ares_ev_driver *ev_driver) { + // It's not safe to shut down remaining fds here directly, becauses + // ares_host_callback does not provide an exec_ctx. We mark the event driver + // as being shut down. If the event driver is working, + // grpc_ares_notify_on_event_locked will shut down the fds; if it's not + // working, there are no fds to shut down. + gpr_mu_lock(&ev_driver->mu); + ev_driver->shutting_down = true; + gpr_mu_unlock(&ev_driver->mu); + grpc_ares_ev_driver_unref(ev_driver); +} + +void grpc_ares_ev_driver_shutdown(grpc_exec_ctx *exec_ctx, + grpc_ares_ev_driver *ev_driver) { + gpr_mu_lock(&ev_driver->mu); + ev_driver->shutting_down = true; + fd_node *fn = ev_driver->fds; + while (fn != NULL) { + grpc_fd_shutdown( + exec_ctx, fn->grpc_fd, + GRPC_ERROR_CREATE_FROM_STATIC_STRING("grpc_ares_ev_driver_shutdown")); + fn = fn->next; + } + gpr_mu_unlock(&ev_driver->mu); +} + +// Search fd in the fd_node list head. This is an O(n) search, the max possible +// value of n is ARES_GETSOCK_MAXNUM (16). n is typically 1 - 2 in our tests. +static fd_node *pop_fd_node(fd_node **head, int fd) { + fd_node dummy_head; + dummy_head.next = *head; + fd_node *node = &dummy_head; + while (node->next != NULL) { + if (grpc_fd_wrapped_fd(node->next->grpc_fd) == fd) { + fd_node *ret = node->next; + node->next = node->next->next; + *head = dummy_head.next; + return ret; + } + node = node->next; + } + return NULL; +} + +static void on_readable_cb(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error) { + fd_node *fdn = arg; + grpc_ares_ev_driver *ev_driver = fdn->ev_driver; + gpr_mu_lock(&fdn->mu); + fdn->readable_registered = false; + gpr_mu_unlock(&fdn->mu); + + gpr_log(GPR_DEBUG, "readable on %d", grpc_fd_wrapped_fd(fdn->grpc_fd)); + if (error == GRPC_ERROR_NONE) { + ares_process_fd(ev_driver->channel, grpc_fd_wrapped_fd(fdn->grpc_fd), + ARES_SOCKET_BAD); + } else { + // If error is not GRPC_ERROR_NONE, it means the fd has been shutdown or + // timed out. The pending lookups made on this ev_driver will be cancelled + // by the following ares_cancel() and the on_done callbacks will be invoked + // with a status of ARES_ECANCELLED. The remaining file descriptors in this + // ev_driver will be cleaned up in the follwing + // grpc_ares_notify_on_event_locked(). + ares_cancel(ev_driver->channel); + } + gpr_mu_lock(&ev_driver->mu); + grpc_ares_notify_on_event_locked(exec_ctx, ev_driver); + gpr_mu_unlock(&ev_driver->mu); + grpc_ares_ev_driver_unref(ev_driver); +} + +static void on_writable_cb(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error) { + fd_node *fdn = arg; + grpc_ares_ev_driver *ev_driver = fdn->ev_driver; + gpr_mu_lock(&fdn->mu); + fdn->writable_registered = false; + gpr_mu_unlock(&fdn->mu); + + gpr_log(GPR_DEBUG, "writable on %d", grpc_fd_wrapped_fd(fdn->grpc_fd)); + if (error == GRPC_ERROR_NONE) { + ares_process_fd(ev_driver->channel, ARES_SOCKET_BAD, + grpc_fd_wrapped_fd(fdn->grpc_fd)); + } else { + // If error is not GRPC_ERROR_NONE, it means the fd has been shutdown or + // timed out. The pending lookups made on this ev_driver will be cancelled + // by the following ares_cancel() and the on_done callbacks will be invoked + // with a status of ARES_ECANCELLED. The remaining file descriptors in this + // ev_driver will be cleaned up in the follwing + // grpc_ares_notify_on_event_locked(). + ares_cancel(ev_driver->channel); + } + gpr_mu_lock(&ev_driver->mu); + grpc_ares_notify_on_event_locked(exec_ctx, ev_driver); + gpr_mu_unlock(&ev_driver->mu); + grpc_ares_ev_driver_unref(ev_driver); +} + +ares_channel *grpc_ares_ev_driver_get_channel(grpc_ares_ev_driver *ev_driver) { + return &ev_driver->channel; +} + +// Get the file descriptors used by the ev_driver's ares channel, register +// driver_closure with these filedescriptors. +static void grpc_ares_notify_on_event_locked(grpc_exec_ctx *exec_ctx, + grpc_ares_ev_driver *ev_driver) { + fd_node *new_list = NULL; + if (!ev_driver->shutting_down) { + ares_socket_t socks[ARES_GETSOCK_MAXNUM]; + int socks_bitmask = + ares_getsock(ev_driver->channel, socks, ARES_GETSOCK_MAXNUM); + for (size_t i = 0; i < ARES_GETSOCK_MAXNUM; i++) { + if (ARES_GETSOCK_READABLE(socks_bitmask, i) || + ARES_GETSOCK_WRITABLE(socks_bitmask, i)) { + fd_node *fdn = pop_fd_node(&ev_driver->fds, socks[i]); + // Create a new fd_node if sock[i] is not in the fd_node list. + if (fdn == NULL) { + char *fd_name; + gpr_asprintf(&fd_name, "ares_ev_driver-%" PRIuPTR, i); + fdn = gpr_malloc(sizeof(fd_node)); + gpr_log(GPR_DEBUG, "new fd: %d", socks[i]); + fdn->grpc_fd = grpc_fd_create(socks[i], fd_name); + fdn->ev_driver = ev_driver; + fdn->readable_registered = false; + fdn->writable_registered = false; + gpr_mu_init(&fdn->mu); + GRPC_CLOSURE_INIT(&fdn->read_closure, on_readable_cb, fdn, + grpc_schedule_on_exec_ctx); + GRPC_CLOSURE_INIT(&fdn->write_closure, on_writable_cb, fdn, + grpc_schedule_on_exec_ctx); + grpc_pollset_set_add_fd(exec_ctx, ev_driver->pollset_set, + fdn->grpc_fd); + gpr_free(fd_name); + } + fdn->next = new_list; + new_list = fdn; + gpr_mu_lock(&fdn->mu); + // Register read_closure if the socket is readable and read_closure has + // not been registered with this socket. + if (ARES_GETSOCK_READABLE(socks_bitmask, i) && + !fdn->readable_registered) { + grpc_ares_ev_driver_ref(ev_driver); + gpr_log(GPR_DEBUG, "notify read on: %d", + grpc_fd_wrapped_fd(fdn->grpc_fd)); + grpc_fd_notify_on_read(exec_ctx, fdn->grpc_fd, &fdn->read_closure); + fdn->readable_registered = true; + } + // Register write_closure if the socket is writable and write_closure + // has not been registered with this socket. + if (ARES_GETSOCK_WRITABLE(socks_bitmask, i) && + !fdn->writable_registered) { + gpr_log(GPR_DEBUG, "notify write on: %d", + grpc_fd_wrapped_fd(fdn->grpc_fd)); + grpc_ares_ev_driver_ref(ev_driver); + grpc_fd_notify_on_write(exec_ctx, fdn->grpc_fd, &fdn->write_closure); + fdn->writable_registered = true; + } + gpr_mu_unlock(&fdn->mu); + } + } + } + // Any remaining fds in ev_driver->fds were not returned by ares_getsock() and + // are therefore no longer in use, so they can be shut down and removed from + // the list. + while (ev_driver->fds != NULL) { + fd_node *cur = ev_driver->fds; + ev_driver->fds = ev_driver->fds->next; + fd_node_destroy(exec_ctx, cur); + } + ev_driver->fds = new_list; + // If the ev driver has no working fd, all the tasks are done. + if (new_list == NULL) { + ev_driver->working = false; + gpr_log(GPR_DEBUG, "ev driver stop working"); + } +} + +void grpc_ares_ev_driver_start(grpc_exec_ctx *exec_ctx, + grpc_ares_ev_driver *ev_driver) { + gpr_mu_lock(&ev_driver->mu); + if (!ev_driver->working) { + ev_driver->working = true; + grpc_ares_notify_on_event_locked(exec_ctx, ev_driver); + } + gpr_mu_unlock(&ev_driver->mu); +} + +#endif /* GRPC_ARES == 1 && defined(GRPC_POSIX_SOCKET) */ diff --git a/Sources/CgRPC/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.c b/Sources/CgRPC/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.c new file mode 100644 index 000000000..e65723a63 --- /dev/null +++ b/Sources/CgRPC/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.c @@ -0,0 +1,544 @@ +/* + * + * Copyright 2016 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 +#if GRPC_ARES == 1 && !defined(GRPC_UV) + +#include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h" +#include "src/core/lib/iomgr/sockaddr.h" +#include "src/core/lib/iomgr/socket_utils_posix.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "src/core/ext/filters/client_channel/parse_address.h" +#include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h" +#include "src/core/lib/iomgr/error.h" +#include "src/core/lib/iomgr/executor.h" +#include "src/core/lib/iomgr/iomgr_internal.h" +#include "src/core/lib/iomgr/nameser.h" +#include "src/core/lib/iomgr/sockaddr_utils.h" +#include "src/core/lib/support/string.h" + +static gpr_once g_basic_init = GPR_ONCE_INIT; +static gpr_mu g_init_mu; + +struct grpc_ares_request { + /** indicates the DNS server to use, if specified */ + struct ares_addr_port_node dns_server_addr; + /** following members are set in grpc_resolve_address_ares_impl */ + /** closure to call when the request completes */ + grpc_closure *on_done; + /** the pointer to receive the resolved addresses */ + grpc_lb_addresses **lb_addrs_out; + /** the pointer to receive the service config in JSON */ + char **service_config_json_out; + /** the evernt driver used by this request */ + grpc_ares_ev_driver *ev_driver; + /** number of ongoing queries */ + gpr_refcount pending_queries; + + /** mutex guarding the rest of the state */ + gpr_mu mu; + /** is there at least one successful query, set in on_done_cb */ + bool success; + /** the errors explaining the request failure, set in on_done_cb */ + grpc_error *error; +}; + +typedef struct grpc_ares_hostbyname_request { + /** following members are set in create_hostbyname_request */ + /** the top-level request instance */ + grpc_ares_request *parent_request; + /** host to resolve, parsed from the name to resolve */ + char *host; + /** port to fill in sockaddr_in, parsed from the name to resolve */ + uint16_t port; + /** is it a grpclb address */ + bool is_balancer; +} grpc_ares_hostbyname_request; + +static void do_basic_init(void) { gpr_mu_init(&g_init_mu); } + +static uint16_t strhtons(const char *port) { + if (strcmp(port, "http") == 0) { + return htons(80); + } else if (strcmp(port, "https") == 0) { + return htons(443); + } + return htons((unsigned short)atoi(port)); +} + +static void grpc_ares_request_ref(grpc_ares_request *r) { + gpr_ref(&r->pending_queries); +} + +static void grpc_ares_request_unref(grpc_exec_ctx *exec_ctx, + grpc_ares_request *r) { + /* If there are no pending queries, invoke on_done callback and destroy the + request */ + if (gpr_unref(&r->pending_queries)) { + /* TODO(zyc): Sort results with RFC6724 before invoking on_done. */ + if (exec_ctx == NULL) { + /* A new exec_ctx is created here, as the c-ares interface does not + provide one in ares_host_callback. It's safe to schedule on_done with + the newly created exec_ctx, since the caller has been warned not to + acquire locks in on_done. ares_dns_resolver is using combiner to + protect resources needed by on_done. */ + grpc_exec_ctx new_exec_ctx = GRPC_EXEC_CTX_INIT; + GRPC_CLOSURE_SCHED(&new_exec_ctx, r->on_done, r->error); + grpc_exec_ctx_finish(&new_exec_ctx); + } else { + GRPC_CLOSURE_SCHED(exec_ctx, r->on_done, r->error); + } + gpr_mu_destroy(&r->mu); + grpc_ares_ev_driver_destroy(r->ev_driver); + gpr_free(r); + } +} + +static grpc_ares_hostbyname_request *create_hostbyname_request( + grpc_ares_request *parent_request, char *host, uint16_t port, + bool is_balancer) { + grpc_ares_hostbyname_request *hr = + gpr_zalloc(sizeof(grpc_ares_hostbyname_request)); + hr->parent_request = parent_request; + hr->host = gpr_strdup(host); + hr->port = port; + hr->is_balancer = is_balancer; + grpc_ares_request_ref(parent_request); + return hr; +} + +static void destroy_hostbyname_request(grpc_exec_ctx *exec_ctx, + grpc_ares_hostbyname_request *hr) { + grpc_ares_request_unref(exec_ctx, hr->parent_request); + gpr_free(hr->host); + gpr_free(hr); +} + +static void on_hostbyname_done_cb(void *arg, int status, int timeouts, + struct hostent *hostent) { + grpc_ares_hostbyname_request *hr = (grpc_ares_hostbyname_request *)arg; + grpc_ares_request *r = hr->parent_request; + gpr_mu_lock(&r->mu); + if (status == ARES_SUCCESS) { + GRPC_ERROR_UNREF(r->error); + r->error = GRPC_ERROR_NONE; + r->success = true; + grpc_lb_addresses **lb_addresses = r->lb_addrs_out; + if (*lb_addresses == NULL) { + *lb_addresses = grpc_lb_addresses_create(0, NULL); + } + size_t prev_naddr = (*lb_addresses)->num_addresses; + size_t i; + for (i = 0; hostent->h_addr_list[i] != NULL; i++) { + } + (*lb_addresses)->num_addresses += i; + (*lb_addresses)->addresses = + gpr_realloc((*lb_addresses)->addresses, + sizeof(grpc_lb_address) * (*lb_addresses)->num_addresses); + for (i = prev_naddr; i < (*lb_addresses)->num_addresses; i++) { + switch (hostent->h_addrtype) { + case AF_INET6: { + size_t addr_len = sizeof(struct sockaddr_in6); + struct sockaddr_in6 addr; + memset(&addr, 0, addr_len); + memcpy(&addr.sin6_addr, hostent->h_addr_list[i - prev_naddr], + sizeof(struct in6_addr)); + addr.sin6_family = (sa_family_t)hostent->h_addrtype; + addr.sin6_port = hr->port; + grpc_lb_addresses_set_address( + *lb_addresses, i, &addr, addr_len, + hr->is_balancer /* is_balancer */, + hr->is_balancer ? strdup(hr->host) : NULL /* balancer_name */, + NULL /* user_data */); + 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); + break; + } + case AF_INET: { + size_t addr_len = sizeof(struct sockaddr_in); + struct sockaddr_in addr; + memset(&addr, 0, addr_len); + memcpy(&addr.sin_addr, hostent->h_addr_list[i - prev_naddr], + sizeof(struct in_addr)); + addr.sin_family = (sa_family_t)hostent->h_addrtype; + addr.sin_port = hr->port; + grpc_lb_addresses_set_address( + *lb_addresses, i, &addr, addr_len, + hr->is_balancer /* is_balancer */, + hr->is_balancer ? strdup(hr->host) : NULL /* balancer_name */, + NULL /* user_data */); + 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)); + break; + } + } + } + } else if (!r->success) { + char *error_msg; + gpr_asprintf(&error_msg, "C-ares status is not ARES_SUCCESS: %s", + ares_strerror(status)); + grpc_error *error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_msg); + gpr_free(error_msg); + if (r->error == GRPC_ERROR_NONE) { + r->error = error; + } else { + r->error = grpc_error_add_child(error, r->error); + } + } + gpr_mu_unlock(&r->mu); + destroy_hostbyname_request(NULL, hr); +} + +static void on_srv_query_done_cb(void *arg, int status, int timeouts, + unsigned char *abuf, int alen) { + grpc_ares_request *r = (grpc_ares_request *)arg; + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + gpr_log(GPR_DEBUG, "on_query_srv_done_cb"); + if (status == ARES_SUCCESS) { + gpr_log(GPR_DEBUG, "on_query_srv_done_cb ARES_SUCCESS"); + struct ares_srv_reply *reply; + const int parse_status = ares_parse_srv_reply(abuf, alen, &reply); + if (parse_status == ARES_SUCCESS) { + ares_channel *channel = grpc_ares_ev_driver_get_channel(r->ev_driver); + for (struct ares_srv_reply *srv_it = reply; srv_it != NULL; + srv_it = srv_it->next) { + if (grpc_ipv6_loopback_available()) { + grpc_ares_hostbyname_request *hr = create_hostbyname_request( + r, srv_it->host, htons(srv_it->port), true /* is_balancer */); + ares_gethostbyname(*channel, hr->host, AF_INET6, + on_hostbyname_done_cb, hr); + } + grpc_ares_hostbyname_request *hr = create_hostbyname_request( + r, srv_it->host, htons(srv_it->port), true /* is_balancer */); + ares_gethostbyname(*channel, hr->host, AF_INET, on_hostbyname_done_cb, + hr); + grpc_ares_ev_driver_start(&exec_ctx, r->ev_driver); + } + } + if (reply != NULL) { + ares_free_data(reply); + } + } else if (!r->success) { + char *error_msg; + gpr_asprintf(&error_msg, "C-ares status is not ARES_SUCCESS: %s", + ares_strerror(status)); + grpc_error *error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_msg); + gpr_free(error_msg); + if (r->error == GRPC_ERROR_NONE) { + r->error = error; + } else { + r->error = grpc_error_add_child(error, r->error); + } + } + grpc_ares_request_unref(&exec_ctx, r); + grpc_exec_ctx_finish(&exec_ctx); +} + +static const char g_service_config_attribute_prefix[] = "grpc_config="; + +static void on_txt_done_cb(void *arg, int status, int timeouts, + unsigned char *buf, int len) { + gpr_log(GPR_DEBUG, "on_txt_done_cb"); + char *error_msg; + grpc_ares_request *r = (grpc_ares_request *)arg; + gpr_mu_lock(&r->mu); + if (status != ARES_SUCCESS) goto fail; + struct ares_txt_ext *reply = NULL; + status = ares_parse_txt_reply_ext(buf, len, &reply); + if (status != ARES_SUCCESS) goto fail; + // Find service config in TXT record. + const size_t prefix_len = sizeof(g_service_config_attribute_prefix) - 1; + struct ares_txt_ext *result; + for (result = reply; result != NULL; result = result->next) { + if (result->record_start && + memcmp(result->txt, g_service_config_attribute_prefix, prefix_len) == + 0) { + break; + } + } + // Found a service config record. + if (result != NULL) { + size_t service_config_len = result->length - prefix_len; + *r->service_config_json_out = gpr_malloc(service_config_len + 1); + memcpy(*r->service_config_json_out, result->txt + prefix_len, + service_config_len); + for (result = result->next; result != NULL && !result->record_start; + result = result->next) { + *r->service_config_json_out = gpr_realloc( + *r->service_config_json_out, service_config_len + result->length + 1); + memcpy(*r->service_config_json_out + service_config_len, result->txt, + result->length); + 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); + } + // Clean up. + ares_free_data(reply); + goto done; +fail: + gpr_asprintf(&error_msg, "C-ares TXT lookup status is not ARES_SUCCESS: %s", + ares_strerror(status)); + grpc_error *error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_msg); + gpr_free(error_msg); + if (r->error == GRPC_ERROR_NONE) { + r->error = error; + } else { + r->error = grpc_error_add_child(error, r->error); + } +done: + gpr_mu_unlock(&r->mu); + grpc_ares_request_unref(NULL, r); +} + +static grpc_ares_request *grpc_dns_lookup_ares_impl( + grpc_exec_ctx *exec_ctx, const char *dns_server, const char *name, + const char *default_port, grpc_pollset_set *interested_parties, + grpc_closure *on_done, grpc_lb_addresses **addrs, bool check_grpclb, + char **service_config_json) { + grpc_error *error = GRPC_ERROR_NONE; + /* 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; + gpr_split_host_port(name, &host, &port); + if (host == NULL) { + error = grpc_error_set_str( + GRPC_ERROR_CREATE_FROM_STATIC_STRING("unparseable host:port"), + GRPC_ERROR_STR_TARGET_ADDRESS, grpc_slice_from_copied_string(name)); + goto error_cleanup; + } else if (port == NULL) { + if (default_port == NULL) { + error = grpc_error_set_str( + GRPC_ERROR_CREATE_FROM_STATIC_STRING("no port in name"), + GRPC_ERROR_STR_TARGET_ADDRESS, grpc_slice_from_copied_string(name)); + goto error_cleanup; + } + port = gpr_strdup(default_port); + } + + grpc_ares_ev_driver *ev_driver; + error = grpc_ares_ev_driver_create(&ev_driver, interested_parties); + if (error != GRPC_ERROR_NONE) goto error_cleanup; + + grpc_ares_request *r = gpr_zalloc(sizeof(grpc_ares_request)); + gpr_mu_init(&r->mu); + r->ev_driver = ev_driver; + r->on_done = on_done; + r->lb_addrs_out = addrs; + r->service_config_json_out = service_config_json; + r->success = false; + r->error = GRPC_ERROR_NONE; + ares_channel *channel = grpc_ares_ev_driver_get_channel(r->ev_driver); + + // If dns_server is specified, use it. + if (dns_server != NULL) { + gpr_log(GPR_INFO, "Using DNS server %s", dns_server); + grpc_resolved_address addr; + if (grpc_parse_ipv4_hostport(dns_server, &addr, false /* log_errors */)) { + r->dns_server_addr.family = AF_INET; + struct sockaddr_in *in = (struct sockaddr_in *)addr.addr; + memcpy(&r->dns_server_addr.addr.addr4, &in->sin_addr, + sizeof(struct in_addr)); + r->dns_server_addr.tcp_port = grpc_sockaddr_get_port(&addr); + r->dns_server_addr.udp_port = grpc_sockaddr_get_port(&addr); + } else if (grpc_parse_ipv6_hostport(dns_server, &addr, + false /* log_errors */)) { + r->dns_server_addr.family = AF_INET6; + struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)addr.addr; + memcpy(&r->dns_server_addr.addr.addr6, &in6->sin6_addr, + sizeof(struct in6_addr)); + r->dns_server_addr.tcp_port = grpc_sockaddr_get_port(&addr); + r->dns_server_addr.udp_port = grpc_sockaddr_get_port(&addr); + } else { + error = grpc_error_set_str( + GRPC_ERROR_CREATE_FROM_STATIC_STRING("cannot parse authority"), + GRPC_ERROR_STR_TARGET_ADDRESS, grpc_slice_from_copied_string(name)); + gpr_free(r); + goto error_cleanup; + } + int status = ares_set_servers_ports(*channel, &r->dns_server_addr); + if (status != ARES_SUCCESS) { + char *error_msg; + gpr_asprintf(&error_msg, "C-ares status is not ARES_SUCCESS: %s", + ares_strerror(status)); + error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_msg); + gpr_free(error_msg); + gpr_free(r); + goto error_cleanup; + } + } + gpr_ref_init(&r->pending_queries, 1); + if (grpc_ipv6_loopback_available()) { + grpc_ares_hostbyname_request *hr = create_hostbyname_request( + r, host, strhtons(port), false /* is_balancer */); + ares_gethostbyname(*channel, hr->host, AF_INET6, on_hostbyname_done_cb, hr); + } + grpc_ares_hostbyname_request *hr = create_hostbyname_request( + r, host, strhtons(port), false /* is_balancer */); + ares_gethostbyname(*channel, hr->host, AF_INET, on_hostbyname_done_cb, hr); + if (check_grpclb) { + /* Query the SRV record */ + grpc_ares_request_ref(r); + char *service_name; + gpr_asprintf(&service_name, "_grpclb._tcp.%s", host); + ares_query(*channel, service_name, ns_c_in, ns_t_srv, on_srv_query_done_cb, + r); + gpr_free(service_name); + } + if (service_config_json != NULL) { + grpc_ares_request_ref(r); + ares_search(*channel, hr->host, ns_c_in, ns_t_txt, on_txt_done_cb, r); + } + /* TODO(zyc): Handle CNAME records here. */ + grpc_ares_ev_driver_start(exec_ctx, r->ev_driver); + grpc_ares_request_unref(exec_ctx, r); + gpr_free(host); + gpr_free(port); + return r; + +error_cleanup: + GRPC_CLOSURE_SCHED(exec_ctx, on_done, error); + gpr_free(host); + gpr_free(port); + return NULL; +} + +grpc_ares_request *(*grpc_dns_lookup_ares)( + grpc_exec_ctx *exec_ctx, const char *dns_server, const char *name, + const char *default_port, grpc_pollset_set *interested_parties, + grpc_closure *on_done, grpc_lb_addresses **addrs, bool check_grpclb, + char **service_config_json) = grpc_dns_lookup_ares_impl; + +void grpc_cancel_ares_request(grpc_exec_ctx *exec_ctx, grpc_ares_request *r) { + if (grpc_dns_lookup_ares == grpc_dns_lookup_ares_impl) { + grpc_ares_ev_driver_shutdown(exec_ctx, r->ev_driver); + } +} + +grpc_error *grpc_ares_init(void) { + gpr_once_init(&g_basic_init, do_basic_init); + gpr_mu_lock(&g_init_mu); + int status = ares_library_init(ARES_LIB_INIT_ALL); + gpr_mu_unlock(&g_init_mu); + + if (status != ARES_SUCCESS) { + char *error_msg; + gpr_asprintf(&error_msg, "ares_library_init failed: %s", + ares_strerror(status)); + grpc_error *error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_msg); + gpr_free(error_msg); + return error; + } + return GRPC_ERROR_NONE; +} + +void grpc_ares_cleanup(void) { + gpr_mu_lock(&g_init_mu); + ares_library_cleanup(); + gpr_mu_unlock(&g_init_mu); +} + +/* + * grpc_resolve_address_ares related structs and functions + */ + +typedef struct grpc_resolve_address_ares_request { + /** the pointer to receive the resolved addresses */ + grpc_resolved_addresses **addrs_out; + /** currently resolving lb addresses */ + grpc_lb_addresses *lb_addrs; + /** closure to call when the resolve_address_ares request completes */ + grpc_closure *on_resolve_address_done; + /** a closure wrapping on_dns_lookup_done_cb, which should be invoked when the + grpc_dns_lookup_ares operation is done. */ + grpc_closure on_dns_lookup_done; +} grpc_resolve_address_ares_request; + +static void on_dns_lookup_done_cb(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error) { + grpc_resolve_address_ares_request *r = + (grpc_resolve_address_ares_request *)arg; + grpc_resolved_addresses **resolved_addresses = r->addrs_out; + if (r->lb_addrs == NULL || r->lb_addrs->num_addresses == 0) { + *resolved_addresses = NULL; + } else { + *resolved_addresses = gpr_zalloc(sizeof(grpc_resolved_addresses)); + (*resolved_addresses)->naddrs = r->lb_addrs->num_addresses; + (*resolved_addresses)->addrs = gpr_zalloc(sizeof(grpc_resolved_address) * + (*resolved_addresses)->naddrs); + for (size_t i = 0; i < (*resolved_addresses)->naddrs; i++) { + GPR_ASSERT(!r->lb_addrs->addresses[i].is_balancer); + memcpy(&(*resolved_addresses)->addrs[i], + &r->lb_addrs->addresses[i].address, sizeof(grpc_resolved_address)); + } + } + GRPC_CLOSURE_SCHED(exec_ctx, r->on_resolve_address_done, + GRPC_ERROR_REF(error)); + grpc_lb_addresses_destroy(exec_ctx, r->lb_addrs); + gpr_free(r); +} + +static void grpc_resolve_address_ares_impl(grpc_exec_ctx *exec_ctx, + const char *name, + const char *default_port, + grpc_pollset_set *interested_parties, + grpc_closure *on_done, + grpc_resolved_addresses **addrs) { + grpc_resolve_address_ares_request *r = + gpr_zalloc(sizeof(grpc_resolve_address_ares_request)); + r->addrs_out = addrs; + r->on_resolve_address_done = on_done; + GRPC_CLOSURE_INIT(&r->on_dns_lookup_done, on_dns_lookup_done_cb, r, + grpc_schedule_on_exec_ctx); + grpc_dns_lookup_ares(exec_ctx, NULL /* dns_server */, name, default_port, + interested_parties, &r->on_dns_lookup_done, &r->lb_addrs, + false /* check_grpclb */, + NULL /* service_config_json */); +} + +void (*grpc_resolve_address_ares)( + grpc_exec_ctx *exec_ctx, const char *name, const char *default_port, + grpc_pollset_set *interested_parties, grpc_closure *on_done, + grpc_resolved_addresses **addrs) = grpc_resolve_address_ares_impl; + +#endif /* GRPC_ARES == 1 && !defined(GRPC_UV) */ diff --git a/Sources/CgRPC/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h b/Sources/CgRPC/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h new file mode 100644 index 000000000..108333047 --- /dev/null +++ b/Sources/CgRPC/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h @@ -0,0 +1,69 @@ +/* + * + * Copyright 2016 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 GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_DNS_C_ARES_GRPC_ARES_WRAPPER_H +#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_DNS_C_ARES_GRPC_ARES_WRAPPER_H + +#include "src/core/ext/filters/client_channel/lb_policy_factory.h" +#include "src/core/lib/iomgr/exec_ctx.h" +#include "src/core/lib/iomgr/iomgr.h" +#include "src/core/lib/iomgr/polling_entity.h" +#include "src/core/lib/iomgr/resolve_address.h" + +typedef struct grpc_ares_request grpc_ares_request; + +/* Asynchronously resolve \a name. Use \a default_port if a port isn't + designated in \a name, otherwise use the port in \a name. grpc_ares_init() + must be called at least once before this function. \a on_done may be + called directly in this function without being scheduled with \a exec_ctx, + so it must not try to acquire locks that are being held by the caller. */ +extern void (*grpc_resolve_address_ares)(grpc_exec_ctx *exec_ctx, + const char *name, + const char *default_port, + grpc_pollset_set *interested_parties, + grpc_closure *on_done, + grpc_resolved_addresses **addresses); + +/* Asynchronously resolve \a name. It will try to resolve grpclb SRV records in + addition to the normal address records. For normal address records, it uses + \a default_port if a port isn't designated in \a name, otherwise it uses the + port in \a name. grpc_ares_init() must be called at least once before this + function. \a on_done may be called directly in this function without being + scheduled with \a exec_ctx, so it must not try to acquire locks that are + being held by the caller. */ +extern grpc_ares_request *(*grpc_dns_lookup_ares)( + grpc_exec_ctx *exec_ctx, const char *dns_server, const char *name, + const char *default_port, grpc_pollset_set *interested_parties, + grpc_closure *on_done, grpc_lb_addresses **addresses, bool check_grpclb, + char **service_config_json); + +/* Cancel the pending grpc_ares_request \a request */ +void grpc_cancel_ares_request(grpc_exec_ctx *exec_ctx, + grpc_ares_request *request); + +/* Initialize gRPC ares wrapper. Must be called at least once before + grpc_resolve_address_ares(). */ +grpc_error *grpc_ares_init(void); + +/* Uninitialized gRPC ares wrapper. If there was more than one previous call to + grpc_ares_init(), this function uninitializes the gRPC ares wrapper only if + it has been called the same number of times as grpc_ares_init(). */ +void grpc_ares_cleanup(void); + +#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_DNS_C_ARES_GRPC_ARES_WRAPPER_H \ + */ diff --git a/Sources/CgRPC/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.c b/Sources/CgRPC/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.c new file mode 100644 index 000000000..f2587c452 --- /dev/null +++ b/Sources/CgRPC/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.c @@ -0,0 +1,60 @@ +/* + * + * Copyright 2016-2017 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 +#if GRPC_ARES != 1 || defined(GRPC_UV) + +#include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h" + +struct grpc_ares_request { + char val; +}; + +static grpc_ares_request *grpc_dns_lookup_ares_impl( + grpc_exec_ctx *exec_ctx, const char *dns_server, const char *name, + const char *default_port, grpc_pollset_set *interested_parties, + grpc_closure *on_done, grpc_lb_addresses **addrs, bool check_grpclb, + char **service_config_json) { + return NULL; +} + +grpc_ares_request *(*grpc_dns_lookup_ares)( + grpc_exec_ctx *exec_ctx, const char *dns_server, const char *name, + const char *default_port, grpc_pollset_set *interested_parties, + grpc_closure *on_done, grpc_lb_addresses **addrs, bool check_grpclb, + char **service_config_json) = grpc_dns_lookup_ares_impl; + +void grpc_cancel_ares_request(grpc_exec_ctx *exec_ctx, grpc_ares_request *r) {} + +grpc_error *grpc_ares_init(void) { return GRPC_ERROR_NONE; } + +void grpc_ares_cleanup(void) {} + +static void grpc_resolve_address_ares_impl(grpc_exec_ctx *exec_ctx, + const char *name, + const char *default_port, + grpc_pollset_set *interested_parties, + grpc_closure *on_done, + grpc_resolved_addresses **addrs) {} + +void (*grpc_resolve_address_ares)( + grpc_exec_ctx *exec_ctx, const char *name, const char *default_port, + grpc_pollset_set *interested_parties, grpc_closure *on_done, + grpc_resolved_addresses **addrs) = grpc_resolve_address_ares_impl; + +#endif /* GRPC_ARES != 1 || defined(GRPC_UV) */ diff --git a/Sources/CgRPC/src/core/ext/resolver/dns/native/dns_resolver.c b/Sources/CgRPC/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.c similarity index 62% rename from Sources/CgRPC/src/core/ext/resolver/dns/native/dns_resolver.c rename to Sources/CgRPC/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.c index 2675fa931..5ea75f055 100644 --- a/Sources/CgRPC/src/core/ext/resolver/dns/native/dns_resolver.c +++ b/Sources/CgRPC/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -37,13 +22,14 @@ #include #include -#include "src/core/ext/client_channel/http_connect_handshaker.h" -#include "src/core/ext/client_channel/lb_policy_registry.h" -#include "src/core/ext/client_channel/resolver_registry.h" +#include "src/core/ext/filters/client_channel/lb_policy_registry.h" +#include "src/core/ext/filters/client_channel/resolver_registry.h" #include "src/core/lib/channel/channel_args.h" +#include "src/core/lib/iomgr/combiner.h" #include "src/core/lib/iomgr/resolve_address.h" #include "src/core/lib/iomgr/timer.h" #include "src/core/lib/support/backoff.h" +#include "src/core/lib/support/env.h" #include "src/core/lib/support/string.h" #define GRPC_DNS_MIN_CONNECT_TIMEOUT_SECONDS 1 @@ -64,8 +50,6 @@ typedef struct { /** pollset_set to drive the name resolution process */ grpc_pollset_set *interested_parties; - /** mutex guarding the rest of the state */ - gpr_mu mu; /** are we currently resolving? */ bool resolving; /** which version of the result have we published? */ @@ -81,6 +65,7 @@ typedef struct { /** retry timer */ bool have_retry_timer; grpc_timer retry_timer; + grpc_closure on_retry; /** retry backoff state */ gpr_backoff backoff_state; @@ -95,46 +80,45 @@ static void dns_start_resolving_locked(grpc_exec_ctx *exec_ctx, static void dns_maybe_finish_next_locked(grpc_exec_ctx *exec_ctx, dns_resolver *r); -static void dns_shutdown(grpc_exec_ctx *exec_ctx, grpc_resolver *r); -static void dns_channel_saw_error(grpc_exec_ctx *exec_ctx, grpc_resolver *r); -static void dns_next(grpc_exec_ctx *exec_ctx, grpc_resolver *r, - grpc_channel_args **target_result, - grpc_closure *on_complete); +static void dns_shutdown_locked(grpc_exec_ctx *exec_ctx, grpc_resolver *r); +static void dns_channel_saw_error_locked(grpc_exec_ctx *exec_ctx, + grpc_resolver *r); +static void dns_next_locked(grpc_exec_ctx *exec_ctx, grpc_resolver *r, + grpc_channel_args **target_result, + grpc_closure *on_complete); static const grpc_resolver_vtable dns_resolver_vtable = { - dns_destroy, dns_shutdown, dns_channel_saw_error, dns_next}; + dns_destroy, dns_shutdown_locked, dns_channel_saw_error_locked, + dns_next_locked}; -static void dns_shutdown(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver) { +static void dns_shutdown_locked(grpc_exec_ctx *exec_ctx, + grpc_resolver *resolver) { dns_resolver *r = (dns_resolver *)resolver; - gpr_mu_lock(&r->mu); if (r->have_retry_timer) { grpc_timer_cancel(exec_ctx, &r->retry_timer); } if (r->next_completion != NULL) { *r->target_result = NULL; - grpc_exec_ctx_sched(exec_ctx, r->next_completion, - GRPC_ERROR_CREATE("Resolver Shutdown"), NULL); + GRPC_CLOSURE_SCHED( + exec_ctx, r->next_completion, + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Resolver Shutdown")); r->next_completion = NULL; } - gpr_mu_unlock(&r->mu); } -static void dns_channel_saw_error(grpc_exec_ctx *exec_ctx, - grpc_resolver *resolver) { +static void dns_channel_saw_error_locked(grpc_exec_ctx *exec_ctx, + grpc_resolver *resolver) { dns_resolver *r = (dns_resolver *)resolver; - gpr_mu_lock(&r->mu); if (!r->resolving) { gpr_backoff_reset(&r->backoff_state); dns_start_resolving_locked(exec_ctx, r); } - gpr_mu_unlock(&r->mu); } -static void dns_next(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver, - grpc_channel_args **target_result, - grpc_closure *on_complete) { +static void dns_next_locked(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver, + grpc_channel_args **target_result, + grpc_closure *on_complete) { dns_resolver *r = (dns_resolver *)resolver; - gpr_mu_lock(&r->mu); GPR_ASSERT(!r->next_completion); r->next_completion = on_complete; r->target_result = target_result; @@ -144,30 +128,26 @@ static void dns_next(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver, } else { dns_maybe_finish_next_locked(exec_ctx, r); } - gpr_mu_unlock(&r->mu); } -static void dns_on_retry_timer(grpc_exec_ctx *exec_ctx, void *arg, - grpc_error *error) { - dns_resolver *r = arg; +static void dns_on_retry_timer_locked(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error) { + dns_resolver *r = (dns_resolver *)arg; - gpr_mu_lock(&r->mu); r->have_retry_timer = false; if (error == GRPC_ERROR_NONE) { if (!r->resolving) { dns_start_resolving_locked(exec_ctx, r); } } - gpr_mu_unlock(&r->mu); GRPC_RESOLVER_UNREF(exec_ctx, &r->base, "retry-timer"); } -static void dns_on_resolved(grpc_exec_ctx *exec_ctx, void *arg, - grpc_error *error) { - dns_resolver *r = arg; +static void dns_on_resolved_locked(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error) { + dns_resolver *r = (dns_resolver *)arg; grpc_channel_args *result = NULL; - gpr_mu_lock(&r->mu); GPR_ASSERT(r->resolving); r->resolving = false; if (r->addresses != NULL) { @@ -182,14 +162,13 @@ static void dns_on_resolved(grpc_exec_ctx *exec_ctx, void *arg, grpc_arg new_arg = grpc_lb_addresses_create_channel_arg(addresses); result = grpc_channel_args_copy_and_add(r->channel_args, &new_arg, 1); grpc_resolved_addresses_destroy(r->addresses); - grpc_lb_addresses_destroy(addresses); + grpc_lb_addresses_destroy(exec_ctx, addresses); } else { gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC); gpr_timespec next_try = gpr_backoff_step(&r->backoff_state, now); gpr_timespec timeout = gpr_time_sub(next_try, now); - const char *msg = grpc_error_string(error); - gpr_log(GPR_DEBUG, "dns resolution failed: %s", msg); - grpc_error_free_string(msg); + gpr_log(GPR_INFO, "dns resolution failed (will retry): %s", + grpc_error_string(error)); GPR_ASSERT(!r->have_retry_timer); r->have_retry_timer = true; GRPC_RESOLVER_REF(&r->base, "retry-timer"); @@ -199,16 +178,16 @@ static void dns_on_resolved(grpc_exec_ctx *exec_ctx, void *arg, } else { gpr_log(GPR_DEBUG, "retrying immediately"); } - grpc_timer_init(exec_ctx, &r->retry_timer, next_try, dns_on_retry_timer, r, - now); + GRPC_CLOSURE_INIT(&r->on_retry, dns_on_retry_timer_locked, r, + grpc_combiner_scheduler(r->base.combiner)); + grpc_timer_init(exec_ctx, &r->retry_timer, next_try, &r->on_retry, now); } if (r->resolved_result != NULL) { - grpc_channel_args_destroy(r->resolved_result); + grpc_channel_args_destroy(exec_ctx, r->resolved_result); } r->resolved_result = result; r->resolved_version++; dns_maybe_finish_next_locked(exec_ctx, r); - gpr_mu_unlock(&r->mu); GRPC_RESOLVER_UNREF(exec_ctx, &r->base, "dns-resolving"); } @@ -219,9 +198,11 @@ static void dns_start_resolving_locked(grpc_exec_ctx *exec_ctx, GPR_ASSERT(!r->resolving); r->resolving = true; r->addresses = NULL; - grpc_resolve_address(exec_ctx, r->name_to_resolve, r->default_port, - r->interested_parties, - grpc_closure_create(dns_on_resolved, r), &r->addresses); + grpc_resolve_address( + exec_ctx, r->name_to_resolve, r->default_port, r->interested_parties, + GRPC_CLOSURE_CREATE(dns_on_resolved_locked, r, + grpc_combiner_scheduler(r->base.combiner)), + &r->addresses); } static void dns_maybe_finish_next_locked(grpc_exec_ctx *exec_ctx, @@ -231,7 +212,7 @@ static void dns_maybe_finish_next_locked(grpc_exec_ctx *exec_ctx, *r->target_result = r->resolved_result == NULL ? NULL : grpc_channel_args_copy(r->resolved_result); - grpc_exec_ctx_sched(exec_ctx, r->next_completion, GRPC_ERROR_NONE, NULL); + GRPC_CLOSURE_SCHED(exec_ctx, r->next_completion, GRPC_ERROR_NONE); r->next_completion = NULL; r->published_version = r->resolved_version; } @@ -239,14 +220,13 @@ static void dns_maybe_finish_next_locked(grpc_exec_ctx *exec_ctx, static void dns_destroy(grpc_exec_ctx *exec_ctx, grpc_resolver *gr) { dns_resolver *r = (dns_resolver *)gr; - gpr_mu_destroy(&r->mu); if (r->resolved_result != NULL) { - grpc_channel_args_destroy(r->resolved_result); + grpc_channel_args_destroy(exec_ctx, r->resolved_result); } - grpc_pollset_set_destroy(r->interested_parties); + grpc_pollset_set_destroy(exec_ctx, r->interested_parties); gpr_free(r->name_to_resolve); gpr_free(r->default_port); - grpc_channel_args_destroy(r->channel_args); + grpc_channel_args_destroy(exec_ctx, r->channel_args); gpr_free(r); } @@ -258,16 +238,12 @@ static grpc_resolver *dns_create(grpc_exec_ctx *exec_ctx, return NULL; } // Get name from args. - const char *path = args->uri->path; + char *path = args->uri->path; if (path[0] == '/') ++path; - // Get proxy name, if any. - char *proxy_name = grpc_get_http_proxy_server(); // Create resolver. - dns_resolver *r = gpr_malloc(sizeof(dns_resolver)); - memset(r, 0, sizeof(*r)); - gpr_mu_init(&r->mu); - grpc_resolver_init(&r->base, &dns_resolver_vtable); - r->name_to_resolve = proxy_name == NULL ? gpr_strdup(path) : proxy_name; + dns_resolver *r = (dns_resolver *)gpr_zalloc(sizeof(dns_resolver)); + grpc_resolver_init(&r->base, &dns_resolver_vtable, args->combiner); + r->name_to_resolve = gpr_strdup(path); r->default_port = gpr_strdup(default_port); r->channel_args = grpc_channel_args_copy(args->args); r->interested_parties = grpc_pollset_set_create(); @@ -314,7 +290,21 @@ static grpc_resolver_factory *dns_resolver_factory_create() { } void grpc_resolver_dns_native_init(void) { - grpc_register_resolver_type(dns_resolver_factory_create()); + char *resolver = gpr_getenv("GRPC_DNS_RESOLVER"); + if (resolver != NULL && gpr_stricmp(resolver, "native") == 0) { + gpr_log(GPR_DEBUG, "Using native dns resolver"); + grpc_register_resolver_type(dns_resolver_factory_create()); + } else { + grpc_resolver_factory *existing_factory = + grpc_resolver_factory_lookup("dns"); + if (existing_factory == NULL) { + gpr_log(GPR_DEBUG, "Using native dns resolver"); + grpc_register_resolver_type(dns_resolver_factory_create()); + } else { + grpc_resolver_factory_unref(existing_factory); + } + } + gpr_free(resolver); } void grpc_resolver_dns_native_shutdown(void) {} diff --git a/Sources/CgRPC/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.c b/Sources/CgRPC/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.c new file mode 100644 index 000000000..56ed4371a --- /dev/null +++ b/Sources/CgRPC/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.c @@ -0,0 +1,254 @@ +// +// Copyright 2016 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. +// + +// This is similar to the sockaddr resolver, except that it supports a +// bunch of query args that are useful for dependency injection in tests. + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "src/core/ext/filters/client_channel/lb_policy_factory.h" +#include "src/core/ext/filters/client_channel/parse_address.h" +#include "src/core/ext/filters/client_channel/resolver_registry.h" +#include "src/core/lib/channel/channel_args.h" +#include "src/core/lib/iomgr/combiner.h" +#include "src/core/lib/iomgr/resolve_address.h" +#include "src/core/lib/iomgr/unix_sockets_posix.h" +#include "src/core/lib/slice/slice_internal.h" +#include "src/core/lib/slice/slice_string_helpers.h" +#include "src/core/lib/support/string.h" + +#include "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h" + +// +// fake_resolver +// + +typedef struct { + // base class -- must be first + grpc_resolver base; + + // passed-in parameters + grpc_channel_args* channel_args; + + // If not NULL, the next set of resolution results to be returned to + // grpc_resolver_next_locked()'s closure. + grpc_channel_args* next_results; + + // Results to use for the pretended re-resolution in + // fake_resolver_channel_saw_error_locked(). + grpc_channel_args* results_upon_error; + + // pending next completion, or NULL + grpc_closure* next_completion; + // target result address for next completion + grpc_channel_args** target_result; +} fake_resolver; + +static void fake_resolver_destroy(grpc_exec_ctx* exec_ctx, grpc_resolver* gr) { + fake_resolver* r = (fake_resolver*)gr; + grpc_channel_args_destroy(exec_ctx, r->next_results); + grpc_channel_args_destroy(exec_ctx, r->results_upon_error); + grpc_channel_args_destroy(exec_ctx, r->channel_args); + gpr_free(r); +} + +static void fake_resolver_shutdown_locked(grpc_exec_ctx* exec_ctx, + grpc_resolver* resolver) { + fake_resolver* r = (fake_resolver*)resolver; + if (r->next_completion != NULL) { + *r->target_result = NULL; + GRPC_CLOSURE_SCHED( + exec_ctx, r->next_completion, + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Resolver Shutdown")); + r->next_completion = NULL; + } +} + +static void fake_resolver_maybe_finish_next_locked(grpc_exec_ctx* exec_ctx, + fake_resolver* r) { + if (r->next_completion != NULL && r->next_results != NULL) { + *r->target_result = + grpc_channel_args_union(r->next_results, r->channel_args); + grpc_channel_args_destroy(exec_ctx, r->next_results); + r->next_results = NULL; + GRPC_CLOSURE_SCHED(exec_ctx, r->next_completion, GRPC_ERROR_NONE); + r->next_completion = NULL; + } +} + +static void fake_resolver_channel_saw_error_locked(grpc_exec_ctx* exec_ctx, + grpc_resolver* resolver) { + fake_resolver* r = (fake_resolver*)resolver; + if (r->next_results == NULL && r->results_upon_error != NULL) { + // Pretend we re-resolved. + r->next_results = grpc_channel_args_copy(r->results_upon_error); + } + fake_resolver_maybe_finish_next_locked(exec_ctx, r); +} + +static void fake_resolver_next_locked(grpc_exec_ctx* exec_ctx, + grpc_resolver* resolver, + grpc_channel_args** target_result, + grpc_closure* on_complete) { + fake_resolver* r = (fake_resolver*)resolver; + GPR_ASSERT(!r->next_completion); + r->next_completion = on_complete; + r->target_result = target_result; + fake_resolver_maybe_finish_next_locked(exec_ctx, r); +} + +static const grpc_resolver_vtable fake_resolver_vtable = { + fake_resolver_destroy, fake_resolver_shutdown_locked, + fake_resolver_channel_saw_error_locked, fake_resolver_next_locked}; + +struct grpc_fake_resolver_response_generator { + fake_resolver* resolver; // Set by the fake_resolver constructor to itself. + grpc_channel_args* next_response; + gpr_refcount refcount; +}; + +grpc_fake_resolver_response_generator* +grpc_fake_resolver_response_generator_create() { + grpc_fake_resolver_response_generator* generator = + (grpc_fake_resolver_response_generator*)gpr_zalloc(sizeof(*generator)); + gpr_ref_init(&generator->refcount, 1); + return generator; +} + +grpc_fake_resolver_response_generator* +grpc_fake_resolver_response_generator_ref( + grpc_fake_resolver_response_generator* generator) { + gpr_ref(&generator->refcount); + return generator; +} + +void grpc_fake_resolver_response_generator_unref( + grpc_fake_resolver_response_generator* generator) { + if (gpr_unref(&generator->refcount)) { + gpr_free(generator); + } +} + +static void set_response_cb(grpc_exec_ctx* exec_ctx, void* arg, + grpc_error* error) { + grpc_fake_resolver_response_generator* generator = + (grpc_fake_resolver_response_generator*)arg; + fake_resolver* r = generator->resolver; + if (r->next_results != NULL) { + grpc_channel_args_destroy(exec_ctx, r->next_results); + } + r->next_results = generator->next_response; + if (r->results_upon_error != NULL) { + grpc_channel_args_destroy(exec_ctx, r->results_upon_error); + } + r->results_upon_error = grpc_channel_args_copy(generator->next_response); + fake_resolver_maybe_finish_next_locked(exec_ctx, r); +} + +void grpc_fake_resolver_response_generator_set_response( + grpc_exec_ctx* exec_ctx, grpc_fake_resolver_response_generator* generator, + grpc_channel_args* next_response) { + GPR_ASSERT(generator->resolver != NULL); + generator->next_response = grpc_channel_args_copy(next_response); + GRPC_CLOSURE_SCHED( + exec_ctx, GRPC_CLOSURE_CREATE(set_response_cb, generator, + grpc_combiner_scheduler( + generator->resolver->base.combiner)), + GRPC_ERROR_NONE); +} + +static void* response_generator_arg_copy(void* p) { + return grpc_fake_resolver_response_generator_ref( + (grpc_fake_resolver_response_generator*)p); +} + +static void response_generator_arg_destroy(grpc_exec_ctx* exec_ctx, void* p) { + grpc_fake_resolver_response_generator_unref( + (grpc_fake_resolver_response_generator*)p); +} + +static int response_generator_cmp(void* a, void* b) { return GPR_ICMP(a, b); } + +static const grpc_arg_pointer_vtable response_generator_arg_vtable = { + response_generator_arg_copy, response_generator_arg_destroy, + response_generator_cmp}; + +grpc_arg grpc_fake_resolver_response_generator_arg( + grpc_fake_resolver_response_generator* generator) { + grpc_arg arg; + arg.type = GRPC_ARG_POINTER; + arg.key = GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR; + arg.value.pointer.p = generator; + arg.value.pointer.vtable = &response_generator_arg_vtable; + return arg; +} + +grpc_fake_resolver_response_generator* +grpc_fake_resolver_get_response_generator(const grpc_channel_args* args) { + const grpc_arg* arg = + grpc_channel_args_find(args, GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR); + if (arg == NULL || arg->type != GRPC_ARG_POINTER) return NULL; + return (grpc_fake_resolver_response_generator*)arg->value.pointer.p; +} + +// +// fake_resolver_factory +// + +static void fake_resolver_factory_ref(grpc_resolver_factory* factory) {} + +static void fake_resolver_factory_unref(grpc_resolver_factory* factory) {} + +static grpc_resolver* fake_resolver_create(grpc_exec_ctx* exec_ctx, + grpc_resolver_factory* factory, + grpc_resolver_args* args) { + fake_resolver* r = (fake_resolver*)gpr_zalloc(sizeof(*r)); + r->channel_args = grpc_channel_args_copy(args->args); + grpc_resolver_init(&r->base, &fake_resolver_vtable, args->combiner); + grpc_fake_resolver_response_generator* response_generator = + grpc_fake_resolver_get_response_generator(args->args); + if (response_generator != NULL) response_generator->resolver = r; + return &r->base; +} + +static char* fake_resolver_get_default_authority(grpc_resolver_factory* factory, + grpc_uri* uri) { + const char* path = uri->path; + if (path[0] == '/') ++path; + return gpr_strdup(path); +} + +static const grpc_resolver_factory_vtable fake_resolver_factory_vtable = { + fake_resolver_factory_ref, fake_resolver_factory_unref, + fake_resolver_create, fake_resolver_get_default_authority, "fake"}; + +static grpc_resolver_factory fake_resolver_factory = { + &fake_resolver_factory_vtable}; + +void grpc_resolver_fake_init(void) { + grpc_register_resolver_type(&fake_resolver_factory); +} + +void grpc_resolver_fake_shutdown(void) {} diff --git a/Sources/CgRPC/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h b/Sources/CgRPC/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h new file mode 100644 index 000000000..c084ef2a5 --- /dev/null +++ b/Sources/CgRPC/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h @@ -0,0 +1,60 @@ +// +// Copyright 2016 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 GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_FAKE_FAKE_RESOLVER_H +#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_FAKE_FAKE_RESOLVER_H + +#include "src/core/ext/filters/client_channel/lb_policy_factory.h" +#include "src/core/ext/filters/client_channel/uri_parser.h" +#include "src/core/lib/channel/channel_args.h" + +#define GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR \ + "grpc.fake_resolver.response_generator" + +void grpc_resolver_fake_init(); + +// Instances of \a grpc_fake_resolver_response_generator are passed to the +// fake resolver in a channel argument (see \a +// grpc_fake_resolver_response_generator_arg) in order to inject and trigger +// custom resolutions. See also \a +// grpc_fake_resolver_response_generator_set_response. +typedef struct grpc_fake_resolver_response_generator + grpc_fake_resolver_response_generator; +grpc_fake_resolver_response_generator* +grpc_fake_resolver_response_generator_create(); + +// Instruct the fake resolver associated with the \a response_generator instance +// to trigger a new resolution for \a uri and \a args. +void grpc_fake_resolver_response_generator_set_response( + grpc_exec_ctx* exec_ctx, grpc_fake_resolver_response_generator* generator, + grpc_channel_args* next_response); + +// Return a \a grpc_arg for a \a grpc_fake_resolver_response_generator instance. +grpc_arg grpc_fake_resolver_response_generator_arg( + grpc_fake_resolver_response_generator* generator); +// Return the \a grpc_fake_resolver_response_generator instance in \a args or +// NULL. +grpc_fake_resolver_response_generator* +grpc_fake_resolver_get_response_generator(const grpc_channel_args* args); + +grpc_fake_resolver_response_generator* +grpc_fake_resolver_response_generator_ref( + grpc_fake_resolver_response_generator* generator); +void grpc_fake_resolver_response_generator_unref( + grpc_fake_resolver_response_generator* generator); + +#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_FAKE_FAKE_RESOLVER_H \ + */ diff --git a/Sources/CgRPC/src/core/ext/resolver/sockaddr/sockaddr_resolver.c b/Sources/CgRPC/src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.c similarity index 58% rename from Sources/CgRPC/src/core/ext/resolver/sockaddr/sockaddr_resolver.c rename to Sources/CgRPC/src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.c index 88808c674..7ceb8f40a 100644 --- a/Sources/CgRPC/src/core/ext/resolver/sockaddr/sockaddr_resolver.c +++ b/Sources/CgRPC/src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015-2016, Google Inc. - * All rights reserved. + * Copyright 2015-2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -41,12 +26,14 @@ #include #include -#include "src/core/ext/client_channel/lb_policy_factory.h" -#include "src/core/ext/client_channel/parse_address.h" -#include "src/core/ext/client_channel/resolver_registry.h" +#include "src/core/ext/filters/client_channel/lb_policy_factory.h" +#include "src/core/ext/filters/client_channel/parse_address.h" +#include "src/core/ext/filters/client_channel/resolver_registry.h" #include "src/core/lib/channel/channel_args.h" +#include "src/core/lib/iomgr/combiner.h" #include "src/core/lib/iomgr/resolve_address.h" #include "src/core/lib/iomgr/unix_sockets_posix.h" +#include "src/core/lib/slice/slice_internal.h" #include "src/core/lib/slice/slice_string_helpers.h" #include "src/core/lib/support/string.h" @@ -57,8 +44,6 @@ typedef struct { grpc_lb_addresses *addresses; /** channel args */ grpc_channel_args *channel_args; - /** mutex guarding the rest of the state */ - gpr_mu mu; /** have we published? */ bool published; /** pending next completion, or NULL */ @@ -72,48 +57,45 @@ static void sockaddr_destroy(grpc_exec_ctx *exec_ctx, grpc_resolver *r); static void sockaddr_maybe_finish_next_locked(grpc_exec_ctx *exec_ctx, sockaddr_resolver *r); -static void sockaddr_shutdown(grpc_exec_ctx *exec_ctx, grpc_resolver *r); -static void sockaddr_channel_saw_error(grpc_exec_ctx *exec_ctx, - grpc_resolver *r); -static void sockaddr_next(grpc_exec_ctx *exec_ctx, grpc_resolver *r, - grpc_channel_args **target_result, - grpc_closure *on_complete); +static void sockaddr_shutdown_locked(grpc_exec_ctx *exec_ctx, grpc_resolver *r); +static void sockaddr_channel_saw_error_locked(grpc_exec_ctx *exec_ctx, + grpc_resolver *r); +static void sockaddr_next_locked(grpc_exec_ctx *exec_ctx, grpc_resolver *r, + grpc_channel_args **target_result, + grpc_closure *on_complete); static const grpc_resolver_vtable sockaddr_resolver_vtable = { - sockaddr_destroy, sockaddr_shutdown, sockaddr_channel_saw_error, - sockaddr_next}; + sockaddr_destroy, sockaddr_shutdown_locked, + sockaddr_channel_saw_error_locked, sockaddr_next_locked}; -static void sockaddr_shutdown(grpc_exec_ctx *exec_ctx, - grpc_resolver *resolver) { +static void sockaddr_shutdown_locked(grpc_exec_ctx *exec_ctx, + grpc_resolver *resolver) { sockaddr_resolver *r = (sockaddr_resolver *)resolver; - gpr_mu_lock(&r->mu); if (r->next_completion != NULL) { *r->target_result = NULL; - grpc_exec_ctx_sched(exec_ctx, r->next_completion, GRPC_ERROR_NONE, NULL); + GRPC_CLOSURE_SCHED( + exec_ctx, r->next_completion, + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Resolver Shutdown")); r->next_completion = NULL; } - gpr_mu_unlock(&r->mu); } -static void sockaddr_channel_saw_error(grpc_exec_ctx *exec_ctx, - grpc_resolver *resolver) { +static void sockaddr_channel_saw_error_locked(grpc_exec_ctx *exec_ctx, + grpc_resolver *resolver) { sockaddr_resolver *r = (sockaddr_resolver *)resolver; - gpr_mu_lock(&r->mu); r->published = false; sockaddr_maybe_finish_next_locked(exec_ctx, r); - gpr_mu_unlock(&r->mu); } -static void sockaddr_next(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver, - grpc_channel_args **target_result, - grpc_closure *on_complete) { +static void sockaddr_next_locked(grpc_exec_ctx *exec_ctx, + grpc_resolver *resolver, + grpc_channel_args **target_result, + grpc_closure *on_complete) { sockaddr_resolver *r = (sockaddr_resolver *)resolver; - gpr_mu_lock(&r->mu); GPR_ASSERT(!r->next_completion); r->next_completion = on_complete; r->target_result = target_result; sockaddr_maybe_finish_next_locked(exec_ctx, r); - gpr_mu_unlock(&r->mu); } static void sockaddr_maybe_finish_next_locked(grpc_exec_ctx *exec_ctx, @@ -123,16 +105,15 @@ static void sockaddr_maybe_finish_next_locked(grpc_exec_ctx *exec_ctx, grpc_arg arg = grpc_lb_addresses_create_channel_arg(r->addresses); *r->target_result = grpc_channel_args_copy_and_add(r->channel_args, &arg, 1); - grpc_exec_ctx_sched(exec_ctx, r->next_completion, GRPC_ERROR_NONE, NULL); + GRPC_CLOSURE_SCHED(exec_ctx, r->next_completion, GRPC_ERROR_NONE); r->next_completion = NULL; } } static void sockaddr_destroy(grpc_exec_ctx *exec_ctx, grpc_resolver *gr) { sockaddr_resolver *r = (sockaddr_resolver *)gr; - gpr_mu_destroy(&r->mu); - grpc_lb_addresses_destroy(r->addresses); - grpc_channel_args_destroy(r->channel_args); + grpc_lb_addresses_destroy(exec_ctx, r->addresses); + grpc_channel_args_destroy(exec_ctx, r->channel_args); gpr_free(r); } @@ -161,9 +142,10 @@ char *unix_get_default_authority(grpc_resolver_factory *factory, static void do_nothing(void *ignored) {} -static grpc_resolver *sockaddr_create(grpc_resolver_args *args, - int parse(grpc_uri *uri, - grpc_resolved_address *dst)) { +static grpc_resolver *sockaddr_create(grpc_exec_ctx *exec_ctx, + grpc_resolver_args *args, + bool parse(const grpc_uri *uri, + grpc_resolved_address *dst)) { if (0 != strcmp(args->uri->authority, "")) { gpr_log(GPR_ERROR, "authority based uri's not supported by the %s scheme", args->uri->scheme); @@ -180,7 +162,7 @@ static grpc_resolver *sockaddr_create(grpc_resolver_args *args, bool errors_found = false; for (size_t i = 0; i < addresses->num_addresses; i++) { grpc_uri ith_uri = *args->uri; - char *part_str = grpc_dump_slice(path_parts.slices[i], GPR_DUMP_ASCII); + char *part_str = grpc_slice_to_c_string(path_parts.slices[i]); ith_uri.path = part_str; if (!parse(&ith_uri, &addresses->addresses[i].address)) { errors_found = true; /* GPR_TRUE */ @@ -188,19 +170,18 @@ static grpc_resolver *sockaddr_create(grpc_resolver_args *args, gpr_free(part_str); if (errors_found) break; } - grpc_slice_buffer_destroy(&path_parts); - grpc_slice_unref(path_slice); + grpc_slice_buffer_destroy_internal(exec_ctx, &path_parts); + grpc_slice_unref_internal(exec_ctx, path_slice); if (errors_found) { - grpc_lb_addresses_destroy(addresses); + grpc_lb_addresses_destroy(exec_ctx, addresses); return NULL; } /* Instantiate resolver. */ - sockaddr_resolver *r = gpr_malloc(sizeof(sockaddr_resolver)); - memset(r, 0, sizeof(*r)); + sockaddr_resolver *r = + (sockaddr_resolver *)gpr_zalloc(sizeof(sockaddr_resolver)); r->addresses = addresses; r->channel_args = grpc_channel_args_copy(args->args); - gpr_mu_init(&r->mu); - grpc_resolver_init(&r->base, &sockaddr_resolver_vtable); + grpc_resolver_init(&r->base, &sockaddr_resolver_vtable, args->combiner); return &r->base; } @@ -216,7 +197,7 @@ static void sockaddr_factory_unref(grpc_resolver_factory *factory) {} static grpc_resolver *name##_factory_create_resolver( \ grpc_exec_ctx *exec_ctx, grpc_resolver_factory *factory, \ grpc_resolver_args *args) { \ - return sockaddr_create(args, parse_##name); \ + return sockaddr_create(exec_ctx, args, grpc_parse_##name); \ } \ static const grpc_resolver_factory_vtable name##_factory_vtable = { \ sockaddr_factory_ref, sockaddr_factory_unref, \ diff --git a/Sources/CgRPC/src/core/ext/filters/client_channel/resolver_factory.c b/Sources/CgRPC/src/core/ext/filters/client_channel/resolver_factory.c new file mode 100644 index 000000000..6f0a7c1e3 --- /dev/null +++ b/Sources/CgRPC/src/core/ext/filters/client_channel/resolver_factory.c @@ -0,0 +1,41 @@ +/* + * + * 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 "src/core/ext/filters/client_channel/resolver_factory.h" + +void grpc_resolver_factory_ref(grpc_resolver_factory* factory) { + factory->vtable->ref(factory); +} + +void grpc_resolver_factory_unref(grpc_resolver_factory* factory) { + factory->vtable->unref(factory); +} + +/** Create a resolver instance for a name */ +grpc_resolver* grpc_resolver_factory_create_resolver( + grpc_exec_ctx* exec_ctx, grpc_resolver_factory* factory, + grpc_resolver_args* args) { + if (factory == NULL) return NULL; + return factory->vtable->create_resolver(exec_ctx, factory, args); +} + +char* grpc_resolver_factory_get_default_authority( + grpc_resolver_factory* factory, grpc_uri* uri) { + if (factory == NULL) return NULL; + return factory->vtable->get_default_authority(factory, uri); +} diff --git a/Sources/CgRPC/src/core/ext/filters/client_channel/resolver_factory.h b/Sources/CgRPC/src/core/ext/filters/client_channel/resolver_factory.h new file mode 100644 index 000000000..6bd7929d4 --- /dev/null +++ b/Sources/CgRPC/src/core/ext/filters/client_channel/resolver_factory.h @@ -0,0 +1,70 @@ +/* + * + * 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 GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_FACTORY_H +#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_FACTORY_H + +#include "src/core/ext/filters/client_channel/client_channel_factory.h" +#include "src/core/ext/filters/client_channel/resolver.h" +#include "src/core/ext/filters/client_channel/uri_parser.h" +#include "src/core/lib/iomgr/pollset_set.h" + +typedef struct grpc_resolver_factory grpc_resolver_factory; +typedef struct grpc_resolver_factory_vtable grpc_resolver_factory_vtable; + +struct grpc_resolver_factory { + const grpc_resolver_factory_vtable *vtable; +}; + +typedef struct grpc_resolver_args { + grpc_uri *uri; + const grpc_channel_args *args; + grpc_pollset_set *pollset_set; + grpc_combiner *combiner; +} grpc_resolver_args; + +struct grpc_resolver_factory_vtable { + void (*ref)(grpc_resolver_factory *factory); + void (*unref)(grpc_resolver_factory *factory); + + /** Implementation of grpc_resolver_factory_create_resolver */ + grpc_resolver *(*create_resolver)(grpc_exec_ctx *exec_ctx, + grpc_resolver_factory *factory, + grpc_resolver_args *args); + + /** Implementation of grpc_resolver_factory_get_default_authority */ + char *(*get_default_authority)(grpc_resolver_factory *factory, grpc_uri *uri); + + /** URI scheme that this factory implements */ + const char *scheme; +}; + +void grpc_resolver_factory_ref(grpc_resolver_factory *resolver); +void grpc_resolver_factory_unref(grpc_resolver_factory *resolver); + +/** Create a resolver instance for a name */ +grpc_resolver *grpc_resolver_factory_create_resolver( + grpc_exec_ctx *exec_ctx, grpc_resolver_factory *factory, + grpc_resolver_args *args); + +/** Return a (freshly allocated with gpr_malloc) string representing + the default authority to use for this scheme. */ +char *grpc_resolver_factory_get_default_authority( + grpc_resolver_factory *factory, grpc_uri *uri); + +#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_FACTORY_H */ diff --git a/Sources/CgRPC/src/core/ext/client_channel/resolver_registry.c b/Sources/CgRPC/src/core/ext/filters/client_channel/resolver_registry.c similarity index 65% rename from Sources/CgRPC/src/core/ext/client_channel/resolver_registry.c rename to Sources/CgRPC/src/core/ext/filters/client_channel/resolver_registry.c index 5110a7cad..1a0fb0bc3 100644 --- a/Sources/CgRPC/src/core/ext/client_channel/resolver_registry.c +++ b/Sources/CgRPC/src/core/ext/filters/client_channel/resolver_registry.c @@ -1,37 +1,22 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 "src/core/ext/client_channel/resolver_registry.h" +#include "src/core/ext/filters/client_channel/resolver_registry.h" #include @@ -93,7 +78,6 @@ static grpc_resolver_factory *lookup_factory(const char *name) { return g_all_of_the_resolvers[i]; } } - return NULL; } @@ -108,22 +92,23 @@ static grpc_resolver_factory *lookup_factory_by_uri(grpc_uri *uri) { return lookup_factory(uri->scheme); } -static grpc_resolver_factory *resolve_factory(const char *target, +static grpc_resolver_factory *resolve_factory(grpc_exec_ctx *exec_ctx, + const char *target, grpc_uri **uri, char **canonical_target) { grpc_resolver_factory *factory = NULL; GPR_ASSERT(uri != NULL); - *uri = grpc_uri_parse(target, 1); + *uri = grpc_uri_parse(exec_ctx, target, 1); factory = lookup_factory_by_uri(*uri); if (factory == NULL) { grpc_uri_destroy(*uri); gpr_asprintf(canonical_target, "%s%s", g_default_resolver_prefix, target); - *uri = grpc_uri_parse(*canonical_target, 1); + *uri = grpc_uri_parse(exec_ctx, *canonical_target, 1); factory = lookup_factory_by_uri(*uri); if (factory == NULL) { - grpc_uri_destroy(grpc_uri_parse(target, 0)); - grpc_uri_destroy(grpc_uri_parse(*canonical_target, 0)); + grpc_uri_destroy(grpc_uri_parse(exec_ctx, target, 0)); + grpc_uri_destroy(grpc_uri_parse(exec_ctx, *canonical_target, 0)); gpr_log(GPR_ERROR, "don't know how to resolve '%s' or '%s'", target, *canonical_target); } @@ -133,17 +118,19 @@ static grpc_resolver_factory *resolve_factory(const char *target, grpc_resolver *grpc_resolver_create(grpc_exec_ctx *exec_ctx, const char *target, const grpc_channel_args *args, - grpc_pollset_set *pollset_set) { + grpc_pollset_set *pollset_set, + grpc_combiner *combiner) { grpc_uri *uri = NULL; char *canonical_target = NULL; grpc_resolver_factory *factory = - resolve_factory(target, &uri, &canonical_target); + resolve_factory(exec_ctx, target, &uri, &canonical_target); grpc_resolver *resolver; grpc_resolver_args resolver_args; memset(&resolver_args, 0, sizeof(resolver_args)); resolver_args.uri = uri; resolver_args.args = args; resolver_args.pollset_set = pollset_set; + resolver_args.combiner = combiner; resolver = grpc_resolver_factory_create_resolver(exec_ctx, factory, &resolver_args); grpc_uri_destroy(uri); @@ -151,21 +138,22 @@ grpc_resolver *grpc_resolver_create(grpc_exec_ctx *exec_ctx, const char *target, return resolver; } -char *grpc_get_default_authority(const char *target) { +char *grpc_get_default_authority(grpc_exec_ctx *exec_ctx, const char *target) { grpc_uri *uri = NULL; char *canonical_target = NULL; grpc_resolver_factory *factory = - resolve_factory(target, &uri, &canonical_target); + resolve_factory(exec_ctx, target, &uri, &canonical_target); char *authority = grpc_resolver_factory_get_default_authority(factory, uri); grpc_uri_destroy(uri); gpr_free(canonical_target); return authority; } -char *grpc_resolver_factory_add_default_prefix_if_needed(const char *target) { +char *grpc_resolver_factory_add_default_prefix_if_needed( + grpc_exec_ctx *exec_ctx, const char *target) { grpc_uri *uri = NULL; char *canonical_target = NULL; - resolve_factory(target, &uri, &canonical_target); + resolve_factory(exec_ctx, target, &uri, &canonical_target); grpc_uri_destroy(uri); return canonical_target == NULL ? gpr_strdup(target) : canonical_target; } diff --git a/Sources/CgRPC/src/core/ext/filters/client_channel/resolver_registry.h b/Sources/CgRPC/src/core/ext/filters/client_channel/resolver_registry.h new file mode 100644 index 000000000..692490543 --- /dev/null +++ b/Sources/CgRPC/src/core/ext/filters/client_channel/resolver_registry.h @@ -0,0 +1,69 @@ +/* + * + * 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 GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_REGISTRY_H +#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_REGISTRY_H + +#include "src/core/ext/filters/client_channel/resolver_factory.h" +#include "src/core/lib/iomgr/pollset_set.h" + +void grpc_resolver_registry_init(); +void grpc_resolver_registry_shutdown(void); + +/** Set the default URI prefix to \a default_prefix. */ +void grpc_resolver_registry_set_default_prefix(const char *default_prefix); + +/** Register a resolver type. + URI's of \a scheme will be resolved with the given resolver. + If \a priority is greater than zero, then the resolver will be eligible + to resolve names that are passed in with no scheme. Higher priority + resolvers will be tried before lower priority schemes. */ +void grpc_register_resolver_type(grpc_resolver_factory *factory); + +/** Create a resolver given \a target. + First tries to parse \a target as a URI. If this succeeds, tries + to locate a registered resolver factory based on the URI scheme. + If parsing or location fails, prefixes default_prefix from + grpc_resolver_registry_init to target, and tries again (if default_prefix + was not NULL). + If a resolver factory was found, use it to instantiate a resolver and + return it. + If a resolver factory was not found, return NULL. + \a args is a set of channel arguments to be included in the result + (typically the set of arguments passed in from the client API). + \a pollset_set is used to drive IO in the name resolution process, it + should not be NULL. */ +grpc_resolver *grpc_resolver_create(grpc_exec_ctx *exec_ctx, const char *target, + const grpc_channel_args *args, + grpc_pollset_set *pollset_set, + grpc_combiner *combiner); + +/** Find a resolver factory given a name and return an (owned-by-the-caller) + * reference to it */ +grpc_resolver_factory *grpc_resolver_factory_lookup(const char *name); + +/** Given a target, return a (freshly allocated with gpr_malloc) string + representing the default authority to pass from a client. */ +char *grpc_get_default_authority(grpc_exec_ctx *exec_ctx, const char *target); + +/** Returns a newly allocated string containing \a target, adding the + default prefix if needed. */ +char *grpc_resolver_factory_add_default_prefix_if_needed( + grpc_exec_ctx *exec_ctx, const char *target); + +#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_REGISTRY_H */ diff --git a/Sources/CgRPC/src/core/ext/filters/client_channel/retry_throttle.c b/Sources/CgRPC/src/core/ext/filters/client_channel/retry_throttle.c new file mode 100644 index 000000000..0c7a3ae65 --- /dev/null +++ b/Sources/CgRPC/src/core/ext/filters/client_channel/retry_throttle.c @@ -0,0 +1,199 @@ +/* + * + * Copyright 2017 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 "src/core/ext/filters/client_channel/retry_throttle.h" + +#include +#include + +#include +#include +#include +#include +#include + +// +// server_retry_throttle_data +// + +struct grpc_server_retry_throttle_data { + gpr_refcount refs; + int max_milli_tokens; + int milli_token_ratio; + gpr_atm milli_tokens; + // A pointer to the replacement for this grpc_server_retry_throttle_data + // entry. If non-NULL, then this entry is stale and must not be used. + // We hold a reference to the replacement. + gpr_atm replacement; +}; + +static void get_replacement_throttle_data_if_needed( + grpc_server_retry_throttle_data** throttle_data) { + while (true) { + grpc_server_retry_throttle_data* new_throttle_data = + (grpc_server_retry_throttle_data*)gpr_atm_acq_load( + &(*throttle_data)->replacement); + if (new_throttle_data == NULL) return; + *throttle_data = new_throttle_data; + } +} + +bool grpc_server_retry_throttle_data_record_failure( + grpc_server_retry_throttle_data* throttle_data) { + // First, check if we are stale and need to be replaced. + get_replacement_throttle_data_if_needed(&throttle_data); + // We decrement milli_tokens by 1000 (1 token) for each failure. + const int new_value = (int)gpr_atm_no_barrier_clamped_add( + &throttle_data->milli_tokens, (gpr_atm)-1000, (gpr_atm)0, + (gpr_atm)throttle_data->max_milli_tokens); + // Retries are allowed as long as the new value is above the threshold + // (max_milli_tokens / 2). + return new_value > throttle_data->max_milli_tokens / 2; +} + +void grpc_server_retry_throttle_data_record_success( + grpc_server_retry_throttle_data* throttle_data) { + // First, check if we are stale and need to be replaced. + get_replacement_throttle_data_if_needed(&throttle_data); + // We increment milli_tokens by milli_token_ratio for each success. + gpr_atm_no_barrier_clamped_add( + &throttle_data->milli_tokens, (gpr_atm)throttle_data->milli_token_ratio, + (gpr_atm)0, (gpr_atm)throttle_data->max_milli_tokens); +} + +grpc_server_retry_throttle_data* grpc_server_retry_throttle_data_ref( + grpc_server_retry_throttle_data* throttle_data) { + gpr_ref(&throttle_data->refs); + return throttle_data; +} + +void grpc_server_retry_throttle_data_unref( + grpc_server_retry_throttle_data* throttle_data) { + if (gpr_unref(&throttle_data->refs)) { + grpc_server_retry_throttle_data* replacement = + (grpc_server_retry_throttle_data*)gpr_atm_acq_load( + &throttle_data->replacement); + if (replacement != NULL) { + grpc_server_retry_throttle_data_unref(replacement); + } + gpr_free(throttle_data); + } +} + +static grpc_server_retry_throttle_data* grpc_server_retry_throttle_data_create( + int max_milli_tokens, int milli_token_ratio, + grpc_server_retry_throttle_data* old_throttle_data) { + grpc_server_retry_throttle_data* throttle_data = + gpr_malloc(sizeof(*throttle_data)); + memset(throttle_data, 0, sizeof(*throttle_data)); + gpr_ref_init(&throttle_data->refs, 1); + throttle_data->max_milli_tokens = max_milli_tokens; + throttle_data->milli_token_ratio = milli_token_ratio; + int initial_milli_tokens = max_milli_tokens; + // If there was a pre-existing entry for this server name, initialize + // the token count by scaling proportionately to the old data. This + // ensures that if we're already throttling retries on the old scale, + // we will start out doing the same thing on the new one. + if (old_throttle_data != NULL) { + double token_fraction = + (int)gpr_atm_acq_load(&old_throttle_data->milli_tokens) / + (double)old_throttle_data->max_milli_tokens; + initial_milli_tokens = (int)(token_fraction * max_milli_tokens); + } + gpr_atm_rel_store(&throttle_data->milli_tokens, + (gpr_atm)initial_milli_tokens); + // If there was a pre-existing entry, mark it as stale and give it a + // pointer to the new entry, which is its replacement. + if (old_throttle_data != NULL) { + grpc_server_retry_throttle_data_ref(throttle_data); + gpr_atm_rel_store(&old_throttle_data->replacement, (gpr_atm)throttle_data); + } + return throttle_data; +} + +// +// avl vtable for string -> server_retry_throttle_data map +// + +static void* copy_server_name(void* key, void* unused) { + return gpr_strdup(key); +} + +static long compare_server_name(void* key1, void* key2, void* unused) { + return strcmp(key1, key2); +} + +static void destroy_server_retry_throttle_data(void* value, void* unused) { + grpc_server_retry_throttle_data* throttle_data = value; + grpc_server_retry_throttle_data_unref(throttle_data); +} + +static void* copy_server_retry_throttle_data(void* value, void* unused) { + grpc_server_retry_throttle_data* throttle_data = value; + return grpc_server_retry_throttle_data_ref(throttle_data); +} + +static void destroy_server_name(void* key, void* unused) { gpr_free(key); } + +static const gpr_avl_vtable avl_vtable = { + destroy_server_name, copy_server_name, compare_server_name, + destroy_server_retry_throttle_data, copy_server_retry_throttle_data}; + +// +// server_retry_throttle_map +// + +static gpr_mu g_mu; +static gpr_avl g_avl; + +void grpc_retry_throttle_map_init() { + gpr_mu_init(&g_mu); + g_avl = gpr_avl_create(&avl_vtable); +} + +void grpc_retry_throttle_map_shutdown() { + gpr_mu_destroy(&g_mu); + gpr_avl_unref(g_avl, NULL); +} + +grpc_server_retry_throttle_data* grpc_retry_throttle_map_get_data_for_server( + const char* server_name, int max_milli_tokens, int milli_token_ratio) { + gpr_mu_lock(&g_mu); + grpc_server_retry_throttle_data* throttle_data = + gpr_avl_get(g_avl, (char*)server_name, NULL); + if (throttle_data == NULL) { + // Entry not found. Create a new one. + throttle_data = grpc_server_retry_throttle_data_create( + max_milli_tokens, milli_token_ratio, NULL); + g_avl = gpr_avl_add(g_avl, (char*)server_name, throttle_data, NULL); + } else { + if (throttle_data->max_milli_tokens != max_milli_tokens || + throttle_data->milli_token_ratio != milli_token_ratio) { + // Entry found but with old parameters. Create a new one based on + // the original one. + throttle_data = grpc_server_retry_throttle_data_create( + max_milli_tokens, milli_token_ratio, throttle_data); + g_avl = gpr_avl_add(g_avl, (char*)server_name, throttle_data, NULL); + } else { + // Entry found. Increase refcount. + grpc_server_retry_throttle_data_ref(throttle_data); + } + } + gpr_mu_unlock(&g_mu); + return throttle_data; +} diff --git a/Sources/CgRPC/src/core/ext/filters/client_channel/retry_throttle.h b/Sources/CgRPC/src/core/ext/filters/client_channel/retry_throttle.h new file mode 100644 index 000000000..bf99297e9 --- /dev/null +++ b/Sources/CgRPC/src/core/ext/filters/client_channel/retry_throttle.h @@ -0,0 +1,50 @@ +/* + * + * Copyright 2017 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 GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RETRY_THROTTLE_H +#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RETRY_THROTTLE_H + +#include + +/// Tracks retry throttling data for an individual server name. +typedef struct grpc_server_retry_throttle_data grpc_server_retry_throttle_data; + +/// Records a failure. Returns true if it's okay to send a retry. +bool grpc_server_retry_throttle_data_record_failure( + grpc_server_retry_throttle_data* throttle_data); +/// Records a success. +void grpc_server_retry_throttle_data_record_success( + grpc_server_retry_throttle_data* throttle_data); + +grpc_server_retry_throttle_data* grpc_server_retry_throttle_data_ref( + grpc_server_retry_throttle_data* throttle_data); +void grpc_server_retry_throttle_data_unref( + grpc_server_retry_throttle_data* throttle_data); + +/// Initializes global map of failure data for each server name. +void grpc_retry_throttle_map_init(); +/// Shuts down global map of failure data for each server name. +void grpc_retry_throttle_map_shutdown(); + +/// Returns a reference to the failure data for \a server_name, creating +/// a new entry if needed. +/// Caller must eventually unref via \a grpc_server_retry_throttle_data_unref(). +grpc_server_retry_throttle_data* grpc_retry_throttle_map_get_data_for_server( + const char* server_name, int max_milli_tokens, int milli_token_ratio); + +#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RETRY_THROTTLE_H */ diff --git a/Sources/CgRPC/src/core/ext/client_channel/subchannel.c b/Sources/CgRPC/src/core/ext/filters/client_channel/subchannel.c similarity index 74% rename from Sources/CgRPC/src/core/ext/client_channel/subchannel.c rename to Sources/CgRPC/src/core/ext/filters/client_channel/subchannel.c index f294e6939..578881933 100644 --- a/Sources/CgRPC/src/core/ext/client_channel/subchannel.c +++ b/Sources/CgRPC/src/core/ext/filters/client_channel/subchannel.c @@ -1,51 +1,41 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 "src/core/ext/client_channel/subchannel.h" +#include "src/core/ext/filters/client_channel/subchannel.h" #include #include #include #include +#include -#include "src/core/ext/client_channel/client_channel.h" -#include "src/core/ext/client_channel/initial_connect_string.h" -#include "src/core/ext/client_channel/subchannel_index.h" +#include "src/core/ext/filters/client_channel/client_channel.h" +#include "src/core/ext/filters/client_channel/parse_address.h" +#include "src/core/ext/filters/client_channel/proxy_mapper_registry.h" +#include "src/core/ext/filters/client_channel/subchannel_index.h" +#include "src/core/ext/filters/client_channel/uri_parser.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/channel/connected_channel.h" +#include "src/core/lib/iomgr/sockaddr_utils.h" #include "src/core/lib/iomgr/timer.h" #include "src/core/lib/profiling/timers.h" +#include "src/core/lib/slice/slice_internal.h" #include "src/core/lib/support/backoff.h" #include "src/core/lib/surface/channel.h" #include "src/core/lib/surface/channel_init.h" @@ -54,9 +44,9 @@ #define INTERNAL_REF_BITS 16 #define STRONG_REF_MASK (~(gpr_atm)((1 << INTERNAL_REF_BITS) - 1)) -#define GRPC_SUBCHANNEL_MIN_CONNECT_TIMEOUT_SECONDS 20 #define GRPC_SUBCHANNEL_INITIAL_CONNECT_BACKOFF_SECONDS 1 #define GRPC_SUBCHANNEL_RECONNECT_BACKOFF_MULTIPLIER 1.6 +#define GRPC_SUBCHANNEL_RECONNECT_MIN_BACKOFF_SECONDS 20 #define GRPC_SUBCHANNEL_RECONNECT_MAX_BACKOFF_SECONDS 120 #define GRPC_SUBCHANNEL_RECONNECT_JITTER 0.2 @@ -94,20 +84,18 @@ struct grpc_subchannel { size_t num_filters; /** channel arguments */ grpc_channel_args *args; - /** address to connect to */ - grpc_resolved_address *addr; grpc_subchannel_key *key; - /** initial string to send to peer */ - grpc_slice initial_connect_string; - /** set during connection */ grpc_connect_out_args connecting_result; /** callback for connection finishing */ grpc_closure connected; + /** callback for our alarm */ + grpc_closure on_alarm; + /** pollset_set tracking who's interested in a connection being setup */ grpc_pollset_set *pollset_set; @@ -141,6 +129,7 @@ struct grpc_subchannel { struct grpc_subchannel_call { grpc_connected_subchannel *connection; + grpc_closure *schedule_closure_after_destroy; }; #define SUBCHANNEL_CALL_TO_CALL_STACK(call) ((grpc_call_stack *)((call) + 1)) @@ -151,25 +140,13 @@ struct grpc_subchannel_call { static void subchannel_connected(grpc_exec_ctx *exec_ctx, void *subchannel, grpc_error *error); -#ifdef GRPC_STREAM_REFCOUNT_DEBUG +#ifndef NDEBUG #define REF_REASON reason -#define REF_LOG(name, p) \ - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "%s: %p ref %d -> %d %s", \ - (name), (p), (p)->refs.count, (p)->refs.count + 1, reason) -#define UNREF_LOG(name, p) \ - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "%s: %p unref %d -> %d %s", \ - (name), (p), (p)->refs.count, (p)->refs.count - 1, reason) #define REF_MUTATE_EXTRA_ARGS \ GRPC_SUBCHANNEL_REF_EXTRA_ARGS, const char *purpose #define REF_MUTATE_PURPOSE(x) , file, line, reason, x #else #define REF_REASON "" -#define REF_LOG(name, p) \ - do { \ - } while (0) -#define UNREF_LOG(name, p) \ - do { \ - } while (0) #define REF_MUTATE_EXTRA_ARGS #define REF_MUTATE_PURPOSE(x) #endif @@ -206,13 +183,12 @@ static void subchannel_destroy(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { grpc_subchannel *c = arg; gpr_free((void *)c->filters); - grpc_channel_args_destroy(c->args); - gpr_free(c->addr); - grpc_slice_unref(c->initial_connect_string); + grpc_channel_args_destroy(exec_ctx, c->args); grpc_connectivity_state_destroy(exec_ctx, &c->state_tracker); grpc_connector_unref(exec_ctx, c->connector); - grpc_pollset_set_destroy(c->pollset_set); + grpc_pollset_set_destroy(exec_ctx, c->pollset_set); grpc_subchannel_key_destroy(exec_ctx, c->key); + gpr_mu_destroy(&c->mu); gpr_free(c); } @@ -220,10 +196,12 @@ static gpr_atm ref_mutate(grpc_subchannel *c, gpr_atm delta, int barrier REF_MUTATE_EXTRA_ARGS) { gpr_atm old_val = barrier ? gpr_atm_full_fetch_add(&c->ref_pair, delta) : gpr_atm_no_barrier_fetch_add(&c->ref_pair, delta); -#ifdef GRPC_STREAM_REFCOUNT_DEBUG - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, - "SUBCHANNEL: %p %s 0x%08" PRIxPTR " -> 0x%08" PRIxPTR " [%s]", c, - purpose, old_val, old_val + delta, reason); +#ifndef NDEBUG + if (GRPC_TRACER_ON(grpc_trace_stream_refcount)) { + gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, + "SUBCHANNEL: %p %12s 0x%" PRIxPTR " -> 0x%" PRIxPTR " [%s]", c, + purpose, old_val, old_val + delta, reason); + } #endif return old_val; } @@ -267,7 +245,9 @@ static void disconnect(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) { gpr_mu_lock(&c->mu); GPR_ASSERT(!c->disconnected); c->disconnected = true; - grpc_connector_shutdown(exec_ctx, c->connector); + grpc_connector_shutdown( + exec_ctx, c->connector, + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Subchannel disconnected")); con = GET_CONNECTED_SUBCHANNEL(c, no_barrier); if (con != NULL) { GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, con, "connection"); @@ -279,6 +259,7 @@ static void disconnect(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) { void grpc_subchannel_unref(grpc_exec_ctx *exec_ctx, grpc_subchannel *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) { gpr_atm old_refs; + // add a weak ref and subtract a strong ref (atomically) old_refs = ref_mutate(c, (gpr_atm)1 - (gpr_atm)(1 << INTERNAL_REF_BITS), 1 REF_MUTATE_PURPOSE("STRONG_UNREF")); if ((old_refs & STRONG_REF_MASK) == (1 << INTERNAL_REF_BITS)) { @@ -293,23 +274,23 @@ void grpc_subchannel_weak_unref(grpc_exec_ctx *exec_ctx, gpr_atm old_refs; old_refs = ref_mutate(c, -(gpr_atm)1, 1 REF_MUTATE_PURPOSE("WEAK_UNREF")); if (old_refs == 1) { - grpc_exec_ctx_sched(exec_ctx, grpc_closure_create(subchannel_destroy, c), - GRPC_ERROR_NONE, NULL); + GRPC_CLOSURE_SCHED(exec_ctx, GRPC_CLOSURE_CREATE(subchannel_destroy, c, + grpc_schedule_on_exec_ctx), + GRPC_ERROR_NONE); } } grpc_subchannel *grpc_subchannel_create(grpc_exec_ctx *exec_ctx, grpc_connector *connector, const grpc_subchannel_args *args) { - grpc_subchannel_key *key = grpc_subchannel_key_create(connector, args); + grpc_subchannel_key *key = grpc_subchannel_key_create(args); grpc_subchannel *c = grpc_subchannel_index_find(exec_ctx, key); if (c) { grpc_subchannel_key_destroy(exec_ctx, key); return c; } - c = gpr_malloc(sizeof(*c)); - memset(c, 0, sizeof(*c)); + c = gpr_zalloc(sizeof(*c)); c->key = key; gpr_atm_no_barrier_store(&c->ref_pair, 1 << INTERNAL_REF_BITS); c->connector = connector; @@ -322,32 +303,51 @@ grpc_subchannel *grpc_subchannel_create(grpc_exec_ctx *exec_ctx, } else { c->filters = NULL; } - c->addr = gpr_malloc(sizeof(grpc_resolved_address)); - if (args->addr->len) - memcpy(c->addr, args->addr, sizeof(grpc_resolved_address)); c->pollset_set = grpc_pollset_set_create(); - grpc_set_initial_connect_string(&c->addr, &c->initial_connect_string); - c->args = grpc_channel_args_copy(args->args); + grpc_resolved_address *addr = gpr_malloc(sizeof(*addr)); + grpc_get_subchannel_address_arg(exec_ctx, args->args, addr); + grpc_resolved_address *new_address = NULL; + grpc_channel_args *new_args = NULL; + if (grpc_proxy_mappers_map_address(exec_ctx, addr, args->args, &new_address, + &new_args)) { + GPR_ASSERT(new_address != NULL); + gpr_free(addr); + addr = new_address; + } + static const char *keys_to_remove[] = {GRPC_ARG_SUBCHANNEL_ADDRESS}; + grpc_arg new_arg = grpc_create_subchannel_address_arg(addr); + gpr_free(addr); + c->args = grpc_channel_args_copy_and_add_and_remove( + new_args != NULL ? new_args : args->args, keys_to_remove, + GPR_ARRAY_SIZE(keys_to_remove), &new_arg, 1); + gpr_free(new_arg.value.string); + if (new_args != NULL) grpc_channel_args_destroy(exec_ctx, new_args); c->root_external_state_watcher.next = c->root_external_state_watcher.prev = &c->root_external_state_watcher; - grpc_closure_init(&c->connected, subchannel_connected, c); + GRPC_CLOSURE_INIT(&c->connected, subchannel_connected, c, + grpc_schedule_on_exec_ctx); grpc_connectivity_state_init(&c->state_tracker, GRPC_CHANNEL_IDLE, "subchannel"); int initial_backoff_ms = GRPC_SUBCHANNEL_INITIAL_CONNECT_BACKOFF_SECONDS * 1000; + int min_backoff_ms = GRPC_SUBCHANNEL_RECONNECT_MIN_BACKOFF_SECONDS * 1000; int max_backoff_ms = GRPC_SUBCHANNEL_RECONNECT_MAX_BACKOFF_SECONDS * 1000; - int min_backoff_ms = GRPC_SUBCHANNEL_MIN_CONNECT_TIMEOUT_SECONDS * 1000; bool fixed_reconnect_backoff = false; if (c->args) { for (size_t i = 0; i < c->args->num_args; i++) { if (0 == strcmp(c->args->args[i].key, "grpc.testing.fixed_reconnect_backoff_ms")) { - GPR_ASSERT(c->args->args[i].type == GRPC_ARG_INTEGER); fixed_reconnect_backoff = true; initial_backoff_ms = min_backoff_ms = max_backoff_ms = grpc_channel_arg_get_integer( &c->args->args[i], (grpc_integer_options){initial_backoff_ms, 100, INT_MAX}); + } else if (0 == strcmp(c->args->args[i].key, + GRPC_ARG_MIN_RECONNECT_BACKOFF_MS)) { + fixed_reconnect_backoff = false; + min_backoff_ms = grpc_channel_arg_get_integer( + &c->args->args[i], + (grpc_integer_options){min_backoff_ms, 100, INT_MAX}); } else if (0 == strcmp(c->args->args[i].key, GRPC_ARG_MAX_RECONNECT_BACKOFF_MS)) { fixed_reconnect_backoff = false; @@ -379,10 +379,8 @@ static void continue_connect_locked(grpc_exec_ctx *exec_ctx, grpc_connect_in_args args; args.interested_parties = c->pollset_set; - args.addr = c->addr; args.deadline = c->next_attempt; args.channel_args = c->args; - args.initial_connect_string = c->initial_connect_string; grpc_connectivity_state_set(exec_ctx, &c->state_tracker, GRPC_CHANNEL_CONNECTING, GRPC_ERROR_NONE, @@ -395,7 +393,7 @@ grpc_connectivity_state grpc_subchannel_check_connectivity(grpc_subchannel *c, grpc_error **error) { grpc_connectivity_state state; gpr_mu_lock(&c->mu); - state = grpc_connectivity_state_check(&c->state_tracker, error); + state = grpc_connectivity_state_get(&c->state_tracker, error); gpr_mu_unlock(&c->mu); return state; } @@ -414,7 +412,7 @@ static void on_external_state_watcher_done(grpc_exec_ctx *exec_ctx, void *arg, gpr_mu_unlock(&w->subchannel->mu); GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, w->subchannel, "external_state_watcher"); gpr_free(w); - follow_up->cb(exec_ctx, follow_up->cb_arg, error); + GRPC_CLOSURE_RUN(exec_ctx, follow_up, GRPC_ERROR_REF(error)); } static void on_alarm(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { @@ -422,7 +420,8 @@ static void on_alarm(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { gpr_mu_lock(&c->mu); c->have_alarm = false; if (c->disconnected) { - error = GRPC_ERROR_CREATE_REFERENCING("Disconnected", &error, 1); + error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING("Disconnected", + &error, 1); } else { GRPC_ERROR_REF(error); } @@ -480,7 +479,8 @@ static void maybe_start_connecting_locked(grpc_exec_ctx *exec_ctx, gpr_log(GPR_INFO, "Retry in %" PRId64 ".%09d seconds", time_til_next.tv_sec, time_til_next.tv_nsec); } - grpc_timer_init(exec_ctx, &c->alarm, c->next_attempt, on_alarm, c, now); + GRPC_CLOSURE_INIT(&c->on_alarm, on_alarm, c, grpc_schedule_on_exec_ctx); + grpc_timer_init(exec_ctx, &c->alarm, c->next_attempt, &c->on_alarm, now); } } @@ -505,7 +505,8 @@ void grpc_subchannel_notify_on_state_change( w->subchannel = c; w->pollset_set = interested_parties; w->notify = notify; - grpc_closure_init(&w->closure, on_external_state_watcher_done, w); + GRPC_CLOSURE_INIT(&w->closure, on_external_state_watcher_done, w, + grpc_schedule_on_exec_ctx); if (interested_parties != NULL) { grpc_pollset_set_add_pollset_set(exec_ctx, c->pollset_set, interested_parties); @@ -591,7 +592,7 @@ void grpc_connected_subchannel_ping(grpc_exec_ctx *exec_ctx, elem->filter->start_transport_op(exec_ctx, elem, op); } -static void publish_transport_locked(grpc_exec_ctx *exec_ctx, +static bool publish_transport_locked(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) { grpc_connected_subchannel *con; grpc_channel_stack *stk; @@ -600,23 +601,23 @@ static void publish_transport_locked(grpc_exec_ctx *exec_ctx, /* construct channel stack */ grpc_channel_stack_builder *builder = grpc_channel_stack_builder_create(); grpc_channel_stack_builder_set_channel_arguments( - builder, c->connecting_result.channel_args); + exec_ctx, builder, c->connecting_result.channel_args); grpc_channel_stack_builder_set_transport(builder, c->connecting_result.transport); if (!grpc_channel_init_create_stack(exec_ctx, builder, GRPC_CLIENT_SUBCHANNEL)) { - grpc_channel_stack_builder_destroy(builder); - abort(); /* TODO(ctiller): what to do here (previously we just crashed) */ + grpc_channel_stack_builder_destroy(exec_ctx, builder); + return false; } grpc_error *error = grpc_channel_stack_builder_finish( exec_ctx, builder, 0, 1, connection_destroy, NULL, (void **)&con); if (error != GRPC_ERROR_NONE) { - const char *msg = grpc_error_string(error); - gpr_log(GPR_ERROR, "error initializing subchannel stack: %s", msg); - grpc_error_free_string(msg); + grpc_transport_destroy(exec_ctx, c->connecting_result.transport); + gpr_log(GPR_ERROR, "error initializing subchannel stack: %s", + grpc_error_string(error)); GRPC_ERROR_UNREF(error); - abort(); /* TODO(ctiller): what to do here? */ + return false; } stk = CHANNEL_STACK_FROM_CONNECTION(con); memset(&c->connecting_result, 0, sizeof(c->connecting_result)); @@ -625,15 +626,14 @@ static void publish_transport_locked(grpc_exec_ctx *exec_ctx, sw_subchannel = gpr_malloc(sizeof(*sw_subchannel)); sw_subchannel->subchannel = c; sw_subchannel->connectivity_state = GRPC_CHANNEL_READY; - grpc_closure_init(&sw_subchannel->closure, subchannel_on_child_state_changed, - sw_subchannel); + GRPC_CLOSURE_INIT(&sw_subchannel->closure, subchannel_on_child_state_changed, + sw_subchannel, grpc_schedule_on_exec_ctx); if (c->disconnected) { gpr_free(sw_subchannel); grpc_channel_stack_destroy(exec_ctx, stk); gpr_free(con); - GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connecting"); - return; + return false; } /* publish */ @@ -655,6 +655,7 @@ static void publish_transport_locked(grpc_exec_ctx *exec_ctx, /* signal completion */ grpc_connectivity_state_set(exec_ctx, &c->state_tracker, GRPC_CHANNEL_READY, GRPC_ERROR_NONE, "connected"); + return true; } static void subchannel_connected(grpc_exec_ctx *exec_ctx, void *arg, @@ -665,28 +666,28 @@ static void subchannel_connected(grpc_exec_ctx *exec_ctx, void *arg, GRPC_SUBCHANNEL_WEAK_REF(c, "connected"); gpr_mu_lock(&c->mu); c->connecting = false; - if (c->connecting_result.transport != NULL) { - publish_transport_locked(exec_ctx, c); + if (c->connecting_result.transport != NULL && + publish_transport_locked(exec_ctx, c)) { + /* do nothing, transport was published */ } else if (c->disconnected) { GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connecting"); } else { grpc_connectivity_state_set( exec_ctx, &c->state_tracker, GRPC_CHANNEL_TRANSIENT_FAILURE, - grpc_error_set_int( - GRPC_ERROR_CREATE_REFERENCING("Connect Failed", &error, 1), - GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE), + grpc_error_set_int(GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( + "Connect Failed", &error, 1), + GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE), "connect_failed"); const char *errmsg = grpc_error_string(error); gpr_log(GPR_INFO, "Connect failed: %s", errmsg); - grpc_error_free_string(errmsg); maybe_start_connecting_locked(exec_ctx, c); GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connecting"); } gpr_mu_unlock(&c->mu); GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connected"); - grpc_channel_args_destroy(delete_channel_args); + grpc_channel_args_destroy(exec_ctx, delete_channel_args); } /* @@ -696,13 +697,22 @@ static void subchannel_connected(grpc_exec_ctx *exec_ctx, void *arg, static void subchannel_call_destroy(grpc_exec_ctx *exec_ctx, void *call, grpc_error *error) { grpc_subchannel_call *c = call; + GPR_ASSERT(c->schedule_closure_after_destroy != NULL); GPR_TIMER_BEGIN("grpc_subchannel_call_unref.destroy", 0); grpc_connected_subchannel *connection = c->connection; - grpc_call_stack_destroy(exec_ctx, SUBCHANNEL_CALL_TO_CALL_STACK(c), NULL, c); + grpc_call_stack_destroy(exec_ctx, SUBCHANNEL_CALL_TO_CALL_STACK(c), NULL, + c->schedule_closure_after_destroy); GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, connection, "subchannel_call"); GPR_TIMER_END("grpc_subchannel_call_unref.destroy", 0); } +void grpc_subchannel_call_set_cleanup_closure(grpc_subchannel_call *call, + grpc_closure *closure) { + GPR_ASSERT(call->schedule_closure_after_destroy == NULL); + GPR_ASSERT(closure != NULL); + call->schedule_closure_after_destroy = closure; +} + void grpc_subchannel_call_ref( grpc_subchannel_call *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) { GRPC_CALL_STACK_REF(SUBCHANNEL_CALL_TO_CALL_STACK(c), REF_REASON); @@ -723,11 +733,11 @@ char *grpc_subchannel_call_get_peer(grpc_exec_ctx *exec_ctx, void grpc_subchannel_call_process_op(grpc_exec_ctx *exec_ctx, grpc_subchannel_call *call, - grpc_transport_stream_op *op) { + grpc_transport_stream_op_batch *op) { GPR_TIMER_BEGIN("grpc_subchannel_call_process_op", 0); grpc_call_stack *call_stack = SUBCHANNEL_CALL_TO_CALL_STACK(call); grpc_call_element *top_elem = grpc_call_stack_element(call_stack, 0); - top_elem->filter->start_transport_stream_op(exec_ctx, top_elem, op); + top_elem->filter->start_transport_stream_op_batch(exec_ctx, top_elem, op); GPR_TIMER_END("grpc_subchannel_call_process_op", 0); } @@ -736,26 +746,35 @@ grpc_connected_subchannel *grpc_subchannel_get_connected_subchannel( return GET_CONNECTED_SUBCHANNEL(c, acq); } +const grpc_subchannel_key *grpc_subchannel_get_key( + const grpc_subchannel *subchannel) { + return subchannel->key; +} + grpc_error *grpc_connected_subchannel_create_call( grpc_exec_ctx *exec_ctx, grpc_connected_subchannel *con, - grpc_polling_entity *pollent, grpc_mdstr *path, gpr_timespec start_time, - gpr_timespec deadline, grpc_subchannel_call **call) { + const grpc_connected_subchannel_call_args *args, + grpc_subchannel_call **call) { grpc_channel_stack *chanstk = CHANNEL_STACK_FROM_CONNECTION(con); - *call = gpr_malloc(sizeof(grpc_subchannel_call) + chanstk->call_stack_size); + *call = gpr_arena_alloc( + args->arena, sizeof(grpc_subchannel_call) + chanstk->call_stack_size); grpc_call_stack *callstk = SUBCHANNEL_CALL_TO_CALL_STACK(*call); - (*call)->connection = con; // Ref is added below. - grpc_error *error = - grpc_call_stack_init(exec_ctx, chanstk, 1, subchannel_call_destroy, *call, - NULL, NULL, path, start_time, deadline, callstk); + (*call)->connection = GRPC_CONNECTED_SUBCHANNEL_REF(con, "subchannel_call"); + const grpc_call_element_args call_args = {.call_stack = callstk, + .server_transport_data = NULL, + .context = args->context, + .path = args->path, + .start_time = args->start_time, + .deadline = args->deadline, + .arena = args->arena}; + grpc_error *error = grpc_call_stack_init( + exec_ctx, chanstk, 1, subchannel_call_destroy, *call, &call_args); if (error != GRPC_ERROR_NONE) { const char *error_string = grpc_error_string(error); gpr_log(GPR_ERROR, "error: %s", error_string); - grpc_error_free_string(error_string); - gpr_free(*call); return error; } - GRPC_CONNECTED_SUBCHANNEL_REF(con, "subchannel_call"); - grpc_call_stack_set_pollset_or_pollset_set(exec_ctx, callstk, pollent); + grpc_call_stack_set_pollset_or_pollset_set(exec_ctx, callstk, args->pollent); return GRPC_ERROR_NONE; } @@ -763,3 +782,35 @@ grpc_call_stack *grpc_subchannel_call_get_call_stack( grpc_subchannel_call *subchannel_call) { return SUBCHANNEL_CALL_TO_CALL_STACK(subchannel_call); } + +static void grpc_uri_to_sockaddr(grpc_exec_ctx *exec_ctx, const char *uri_str, + grpc_resolved_address *addr) { + grpc_uri *uri = grpc_uri_parse(exec_ctx, uri_str, 0 /* suppress_errors */); + GPR_ASSERT(uri != NULL); + if (!grpc_parse_uri(uri, addr)) memset(addr, 0, sizeof(*addr)); + grpc_uri_destroy(uri); +} + +void grpc_get_subchannel_address_arg(grpc_exec_ctx *exec_ctx, + const grpc_channel_args *args, + grpc_resolved_address *addr) { + const char *addr_uri_str = grpc_get_subchannel_address_uri_arg(args); + memset(addr, 0, sizeof(*addr)); + if (*addr_uri_str != '\0') { + grpc_uri_to_sockaddr(exec_ctx, addr_uri_str, addr); + } +} + +const char *grpc_get_subchannel_address_uri_arg(const grpc_channel_args *args) { + const grpc_arg *addr_arg = + grpc_channel_args_find(args, GRPC_ARG_SUBCHANNEL_ADDRESS); + GPR_ASSERT(addr_arg != NULL); // Should have been set by LB policy. + GPR_ASSERT(addr_arg->type == GRPC_ARG_STRING); + return addr_arg->value.string; +} + +grpc_arg grpc_create_subchannel_address_arg(const grpc_resolved_address *addr) { + return grpc_channel_arg_string_create( + GRPC_ARG_SUBCHANNEL_ADDRESS, + addr->len > 0 ? grpc_sockaddr_to_uri(addr) : gpr_strdup("")); +} diff --git a/Sources/CgRPC/src/core/ext/client_channel/subchannel.h b/Sources/CgRPC/src/core/ext/filters/client_channel/subchannel.h similarity index 72% rename from Sources/CgRPC/src/core/ext/client_channel/subchannel.h rename to Sources/CgRPC/src/core/ext/filters/client_channel/subchannel.h index 24aa9f73d..6d2abb04d 100644 --- a/Sources/CgRPC/src/core/ext/client_channel/subchannel.h +++ b/Sources/CgRPC/src/core/ext/filters/client_channel/subchannel.h @@ -1,53 +1,43 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 GRPC_CORE_EXT_CLIENT_CHANNEL_SUBCHANNEL_H -#define GRPC_CORE_EXT_CLIENT_CHANNEL_SUBCHANNEL_H +#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_SUBCHANNEL_H +#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_SUBCHANNEL_H -#include "src/core/ext/client_channel/connector.h" +#include "src/core/ext/filters/client_channel/connector.h" #include "src/core/lib/channel/channel_stack.h" #include "src/core/lib/iomgr/polling_entity.h" +#include "src/core/lib/support/arena.h" #include "src/core/lib/transport/connectivity_state.h" #include "src/core/lib/transport/metadata.h" +// Channel arg containing a grpc_resolved_address to connect to. +#define GRPC_ARG_SUBCHANNEL_ADDRESS "grpc.subchannel_address" + /** A (sub-)channel that knows how to connect to exactly one target address. Provides a target for load balancing. */ typedef struct grpc_subchannel grpc_subchannel; typedef struct grpc_connected_subchannel grpc_connected_subchannel; typedef struct grpc_subchannel_call grpc_subchannel_call; typedef struct grpc_subchannel_args grpc_subchannel_args; +typedef struct grpc_subchannel_key grpc_subchannel_key; -#ifdef GRPC_STREAM_REFCOUNT_DEBUG +#ifndef NDEBUG #define GRPC_SUBCHANNEL_REF(p, r) \ grpc_subchannel_ref((p), __FILE__, __LINE__, (r)) #define GRPC_SUBCHANNEL_REF_FROM_WEAK_REF(p, r) \ @@ -109,10 +99,19 @@ void grpc_subchannel_call_unref(grpc_exec_ctx *exec_ctx, GRPC_SUBCHANNEL_REF_EXTRA_ARGS); /** construct a subchannel call */ +typedef struct { + grpc_polling_entity *pollent; + grpc_slice path; + gpr_timespec start_time; + gpr_timespec deadline; + gpr_arena *arena; + grpc_call_context_element *context; +} grpc_connected_subchannel_call_args; + grpc_error *grpc_connected_subchannel_create_call( grpc_exec_ctx *exec_ctx, grpc_connected_subchannel *connected_subchannel, - grpc_polling_entity *pollent, grpc_mdstr *path, gpr_timespec start_time, - gpr_timespec deadline, grpc_subchannel_call **subchannel_call); + const grpc_connected_subchannel_call_args *args, + grpc_subchannel_call **subchannel_call); /** process a transport level op */ void grpc_connected_subchannel_process_transport_op( @@ -142,15 +141,24 @@ void grpc_connected_subchannel_ping(grpc_exec_ctx *exec_ctx, grpc_connected_subchannel *grpc_subchannel_get_connected_subchannel( grpc_subchannel *subchannel); +/** return the subchannel index key for \a subchannel */ +const grpc_subchannel_key *grpc_subchannel_get_key( + const grpc_subchannel *subchannel); + /** continue processing a transport op */ void grpc_subchannel_call_process_op(grpc_exec_ctx *exec_ctx, grpc_subchannel_call *subchannel_call, - grpc_transport_stream_op *op); + grpc_transport_stream_op_batch *op); /** continue querying for peer */ char *grpc_subchannel_call_get_peer(grpc_exec_ctx *exec_ctx, grpc_subchannel_call *subchannel_call); +/** Must be called once per call. Sets the 'then_schedule_closure' argument for + call stack destruction. */ +void grpc_subchannel_call_set_cleanup_closure( + grpc_subchannel_call *subchannel_call, grpc_closure *closure); + grpc_call_stack *grpc_subchannel_call_get_call_stack( grpc_subchannel_call *subchannel_call); @@ -164,8 +172,6 @@ struct grpc_subchannel_args { size_t filter_count; /** Channel arguments to be supplied to the newly created channel */ const grpc_channel_args *args; - /** Address to connect to */ - grpc_resolved_address *addr; }; /** create a subchannel given a connector */ @@ -173,4 +179,16 @@ grpc_subchannel *grpc_subchannel_create(grpc_exec_ctx *exec_ctx, grpc_connector *connector, const grpc_subchannel_args *args); -#endif /* GRPC_CORE_EXT_CLIENT_CHANNEL_SUBCHANNEL_H */ +/// Sets \a addr from \a args. +void grpc_get_subchannel_address_arg(grpc_exec_ctx *exec_ctx, + const grpc_channel_args *args, + grpc_resolved_address *addr); + +/// Returns the URI string for the address to connect to. +const char *grpc_get_subchannel_address_uri_arg(const grpc_channel_args *args); + +/// Returns a new channel arg encoding the subchannel address as a string. +/// Caller is responsible for freeing the string. +grpc_arg grpc_create_subchannel_address_arg(const grpc_resolved_address *addr); + +#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_SUBCHANNEL_H */ diff --git a/Sources/CgRPC/src/core/ext/filters/client_channel/subchannel_index.c b/Sources/CgRPC/src/core/ext/filters/client_channel/subchannel_index.c new file mode 100644 index 000000000..ababd05d8 --- /dev/null +++ b/Sources/CgRPC/src/core/ext/filters/client_channel/subchannel_index.c @@ -0,0 +1,235 @@ +// +// +// Copyright 2016 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 "src/core/ext/filters/client_channel/subchannel_index.h" + +#include +#include + +#include +#include +#include +#include + +#include "src/core/lib/channel/channel_args.h" + +// a map of subchannel_key --> subchannel, used for detecting connections +// to the same destination in order to share them +static gpr_avl g_subchannel_index; + +static gpr_mu g_mu; + +struct grpc_subchannel_key { + grpc_subchannel_args args; +}; + +static bool g_force_creation = false; + +static grpc_subchannel_key *create_key( + const grpc_subchannel_args *args, + grpc_channel_args *(*copy_channel_args)(const grpc_channel_args *args)) { + grpc_subchannel_key *k = gpr_malloc(sizeof(*k)); + k->args.filter_count = args->filter_count; + if (k->args.filter_count > 0) { + k->args.filters = + gpr_malloc(sizeof(*k->args.filters) * k->args.filter_count); + memcpy((grpc_channel_filter *)k->args.filters, args->filters, + sizeof(*k->args.filters) * k->args.filter_count); + } else { + k->args.filters = NULL; + } + k->args.args = copy_channel_args(args->args); + return k; +} + +grpc_subchannel_key *grpc_subchannel_key_create( + const grpc_subchannel_args *args) { + return create_key(args, grpc_channel_args_normalize); +} + +static grpc_subchannel_key *subchannel_key_copy(grpc_subchannel_key *k) { + return create_key(&k->args, grpc_channel_args_copy); +} + +int grpc_subchannel_key_compare(const grpc_subchannel_key *a, + const grpc_subchannel_key *b) { + if (g_force_creation) return false; + int c = GPR_ICMP(a->args.filter_count, b->args.filter_count); + if (c != 0) return c; + if (a->args.filter_count > 0) { + c = memcmp(a->args.filters, b->args.filters, + a->args.filter_count * sizeof(*a->args.filters)); + if (c != 0) return c; + } + return grpc_channel_args_compare(a->args.args, b->args.args); +} + +void grpc_subchannel_key_destroy(grpc_exec_ctx *exec_ctx, + grpc_subchannel_key *k) { + gpr_free((grpc_channel_args *)k->args.filters); + grpc_channel_args_destroy(exec_ctx, (grpc_channel_args *)k->args.args); + gpr_free(k); +} + +static void sck_avl_destroy(void *p, void *user_data) { + grpc_exec_ctx *exec_ctx = (grpc_exec_ctx *)user_data; + grpc_subchannel_key_destroy(exec_ctx, p); +} + +static void *sck_avl_copy(void *p, void *unused) { + return subchannel_key_copy(p); +} + +static long sck_avl_compare(void *a, void *b, void *unused) { + return grpc_subchannel_key_compare(a, b); +} + +static void scv_avl_destroy(void *p, void *user_data) { + grpc_exec_ctx *exec_ctx = (grpc_exec_ctx *)user_data; + GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, p, "subchannel_index"); +} + +static void *scv_avl_copy(void *p, void *unused) { + GRPC_SUBCHANNEL_WEAK_REF(p, "subchannel_index"); + return p; +} + +static const gpr_avl_vtable subchannel_avl_vtable = { + .destroy_key = sck_avl_destroy, + .copy_key = sck_avl_copy, + .compare_keys = sck_avl_compare, + .destroy_value = scv_avl_destroy, + .copy_value = scv_avl_copy}; + +void grpc_subchannel_index_init(void) { + g_subchannel_index = gpr_avl_create(&subchannel_avl_vtable); + gpr_mu_init(&g_mu); +} + +void grpc_subchannel_index_shutdown(void) { + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + gpr_mu_destroy(&g_mu); + gpr_avl_unref(g_subchannel_index, &exec_ctx); + grpc_exec_ctx_finish(&exec_ctx); +} + +grpc_subchannel *grpc_subchannel_index_find(grpc_exec_ctx *exec_ctx, + grpc_subchannel_key *key) { + // Lock, and take a reference to the subchannel index. + // We don't need to do the search under a lock as avl's are immutable. + gpr_mu_lock(&g_mu); + gpr_avl index = gpr_avl_ref(g_subchannel_index, exec_ctx); + gpr_mu_unlock(&g_mu); + + grpc_subchannel *c = GRPC_SUBCHANNEL_REF_FROM_WEAK_REF( + gpr_avl_get(index, key, exec_ctx), "index_find"); + gpr_avl_unref(index, exec_ctx); + + return c; +} + +grpc_subchannel *grpc_subchannel_index_register(grpc_exec_ctx *exec_ctx, + grpc_subchannel_key *key, + grpc_subchannel *constructed) { + grpc_subchannel *c = NULL; + bool need_to_unref_constructed; + + while (c == NULL) { + need_to_unref_constructed = false; + + // Compare and swap loop: + // - take a reference to the current index + gpr_mu_lock(&g_mu); + gpr_avl index = gpr_avl_ref(g_subchannel_index, exec_ctx); + gpr_mu_unlock(&g_mu); + + // - Check to see if a subchannel already exists + c = gpr_avl_get(index, key, exec_ctx); + if (c != NULL) { + c = GRPC_SUBCHANNEL_REF_FROM_WEAK_REF(c, "index_register"); + } + if (c != NULL) { + // yes -> we're done + need_to_unref_constructed = true; + } else { + // no -> update the avl and compare/swap + gpr_avl updated = gpr_avl_add( + gpr_avl_ref(index, exec_ctx), subchannel_key_copy(key), + GRPC_SUBCHANNEL_WEAK_REF(constructed, "index_register"), exec_ctx); + + // it may happen (but it's expected to be unlikely) + // that some other thread has changed the index: + // compare/swap here to check that, and retry as necessary + gpr_mu_lock(&g_mu); + if (index.root == g_subchannel_index.root) { + GPR_SWAP(gpr_avl, updated, g_subchannel_index); + c = constructed; + } + gpr_mu_unlock(&g_mu); + + gpr_avl_unref(updated, exec_ctx); + } + gpr_avl_unref(index, exec_ctx); + } + + if (need_to_unref_constructed) { + GRPC_SUBCHANNEL_UNREF(exec_ctx, constructed, "index_register"); + } + + return c; +} + +void grpc_subchannel_index_unregister(grpc_exec_ctx *exec_ctx, + grpc_subchannel_key *key, + grpc_subchannel *constructed) { + bool done = false; + while (!done) { + // Compare and swap loop: + // - take a reference to the current index + gpr_mu_lock(&g_mu); + gpr_avl index = gpr_avl_ref(g_subchannel_index, exec_ctx); + gpr_mu_unlock(&g_mu); + + // Check to see if this key still refers to the previously + // registered subchannel + grpc_subchannel *c = gpr_avl_get(index, key, exec_ctx); + if (c != constructed) { + gpr_avl_unref(index, exec_ctx); + break; + } + + // compare and swap the update (some other thread may have + // mutated the index behind us) + gpr_avl updated = + gpr_avl_remove(gpr_avl_ref(index, exec_ctx), key, exec_ctx); + + gpr_mu_lock(&g_mu); + if (index.root == g_subchannel_index.root) { + GPR_SWAP(gpr_avl, updated, g_subchannel_index); + done = true; + } + gpr_mu_unlock(&g_mu); + + gpr_avl_unref(updated, exec_ctx); + gpr_avl_unref(index, exec_ctx); + } +} + +void grpc_subchannel_index_test_only_set_force_creation(bool force_creation) { + g_force_creation = force_creation; +} diff --git a/Sources/CgRPC/src/core/ext/filters/client_channel/subchannel_index.h b/Sources/CgRPC/src/core/ext/filters/client_channel/subchannel_index.h new file mode 100644 index 000000000..98d882a45 --- /dev/null +++ b/Sources/CgRPC/src/core/ext/filters/client_channel/subchannel_index.h @@ -0,0 +1,74 @@ +/* + * + * Copyright 2016 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 GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_SUBCHANNEL_INDEX_H +#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_SUBCHANNEL_INDEX_H + +#include "src/core/ext/filters/client_channel/subchannel.h" + +/** \file Provides an index of active subchannels so that they can be + shared amongst channels */ + +/** Create a key that can be used to uniquely identify a subchannel */ +grpc_subchannel_key *grpc_subchannel_key_create( + const grpc_subchannel_args *args); + +/** Destroy a subchannel key */ +void grpc_subchannel_key_destroy(grpc_exec_ctx *exec_ctx, + grpc_subchannel_key *key); + +/** Given a subchannel key, find the subchannel registered for it. + Returns NULL if no such channel exists. + Thread-safe. */ +grpc_subchannel *grpc_subchannel_index_find(grpc_exec_ctx *exec_ctx, + grpc_subchannel_key *key); + +/** Register a subchannel against a key. + Takes ownership of \a constructed. + Returns the registered subchannel. This may be different from + \a constructed in the case of a registration race. */ +grpc_subchannel *grpc_subchannel_index_register(grpc_exec_ctx *exec_ctx, + grpc_subchannel_key *key, + grpc_subchannel *constructed); + +/** Remove \a constructed as the registered subchannel for \a key. */ +void grpc_subchannel_index_unregister(grpc_exec_ctx *exec_ctx, + grpc_subchannel_key *key, + grpc_subchannel *constructed); + +int grpc_subchannel_key_compare(const grpc_subchannel_key *a, + const grpc_subchannel_key *b); + +/** Initialize the subchannel index (global) */ +void grpc_subchannel_index_init(void); +/** Shutdown the subchannel index (global) */ +void grpc_subchannel_index_shutdown(void); + +/** \em TEST ONLY. + * If \a force_creation is true, all key comparisons will be false, resulting in + * new subchannels always being created. Otherwise, the keys will be compared as + * usual. + * + * This function is *not* threadsafe on purpose: it should *only* be used in + * test code. + * + * Tests using this function \em MUST run tests with and without \a + * force_creation set. */ +void grpc_subchannel_index_test_only_set_force_creation(bool force_creation); + +#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_SUBCHANNEL_INDEX_H */ diff --git a/Sources/CgRPC/src/core/ext/client_channel/uri_parser.c b/Sources/CgRPC/src/core/ext/filters/client_channel/uri_parser.c similarity index 59% rename from Sources/CgRPC/src/core/ext/client_channel/uri_parser.c rename to Sources/CgRPC/src/core/ext/filters/client_channel/uri_parser.c index 0fbc542ef..e84192876 100644 --- a/Sources/CgRPC/src/core/ext/client_channel/uri_parser.c +++ b/Sources/CgRPC/src/core/ext/filters/client_channel/uri_parser.c @@ -1,47 +1,33 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 "src/core/ext/client_channel/uri_parser.h" +#include "src/core/ext/filters/client_channel/uri_parser.h" #include -#include #include #include #include #include #include +#include "src/core/lib/slice/percent_encoding.h" +#include "src/core/lib/slice/slice_internal.h" #include "src/core/lib/slice/slice_string_helpers.h" #include "src/core/lib/support/string.h" @@ -49,7 +35,7 @@ #define NOT_SET (~(size_t)0) static grpc_uri *bad_uri(const char *uri_text, size_t pos, const char *section, - int suppress_errors) { + bool suppress_errors) { char *line_prefix; size_t pfx_len; @@ -69,14 +55,24 @@ static grpc_uri *bad_uri(const char *uri_text, size_t pos, const char *section, return NULL; } -/** Returns a copy of \a src[begin, end) */ -static char *copy_component(const char *src, size_t begin, size_t end) { - char *out = gpr_malloc(end - begin + 1); - memcpy(out, src + begin, end - begin); - out[end - begin] = 0; +/** Returns a copy of percent decoded \a src[begin, end) */ +static char *decode_and_copy_component(grpc_exec_ctx *exec_ctx, const char *src, + size_t begin, size_t end) { + grpc_slice component = + grpc_slice_from_copied_buffer(src + begin, end - begin); + grpc_slice decoded_component = + grpc_permissive_percent_decode_slice(component); + char *out = grpc_dump_slice(decoded_component, GPR_DUMP_ASCII); + grpc_slice_unref_internal(exec_ctx, component); + grpc_slice_unref_internal(exec_ctx, decoded_component); return out; } +static bool valid_hex(char c) { + return ((c >= 'a') && (c <= 'f')) || ((c >= 'A') && (c <= 'F')) || + ((c >= '0') && (c <= '9')); +} + /** Returns how many chars to advance if \a uri_text[i] begins a valid \a pchar * production. If \a uri_text[i] introduces an invalid \a pchar (such as percent * sign not followed by two hex digits), NOT_SET is returned. */ @@ -87,27 +83,36 @@ static size_t parse_pchar(const char *uri_text, size_t i) { * sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "=" */ char c = uri_text[i]; - if (((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z')) || - ((c >= '0') && (c <= '9')) || - (c == '-' || c == '.' || c == '_' || c == '~') || /* unreserved */ - (c == '!' || c == '$' || c == '&' || c == '\'' || c == '$' || c == '&' || - c == '(' || c == ')' || c == '*' || c == '+' || c == ',' || c == ';' || - c == '=') /* sub-delims */) { - return 1; - } - if (c == '%') { /* pct-encoded */ - size_t j; - if (uri_text[i + 1] == 0 || uri_text[i + 2] == 0) { - return NOT_SET; - } - for (j = i + 1; j < 2; j++) { - c = uri_text[j]; - if (!(((c >= '0') && (c <= '9')) || ((c >= 'a') && (c <= 'f')) || - ((c >= 'A') && (c <= 'F')))) { - return NOT_SET; + switch (c) { + default: + if (((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')) || + ((c >= '0') && (c <= '9'))) { + return 1; } - } - return 2; + break; + case ':': + case '@': + case '-': + case '.': + case '_': + case '~': + case '!': + case '$': + case '&': + case '\'': + case '(': + case ')': + case '*': + case '+': + case ',': + case ';': + case '=': + return 1; + case '%': /* pct-encoded */ + if (valid_hex(uri_text[i + 1]) && valid_hex(uri_text[i + 2])) { + return 2; + } + return NOT_SET; } return 0; } @@ -138,7 +143,6 @@ static int parse_fragment_or_query(const char *uri_text, size_t *i) { return 1; } -static void do_nothing(void *ignored) {} static void parse_query_parts(grpc_uri *uri) { static const char *QUERY_PARTS_SEPARATOR = "&"; static const char *QUERY_PARTS_VALUE_SEPARATOR = "="; @@ -149,41 +153,36 @@ static void parse_query_parts(grpc_uri *uri) { uri->num_query_parts = 0; return; } - grpc_slice query_slice = - grpc_slice_new(uri->query, strlen(uri->query), do_nothing); - grpc_slice_buffer query_parts; /* the &-separated elements of the query */ - grpc_slice_buffer query_param_parts; /* the =-separated subelements */ - grpc_slice_buffer_init(&query_parts); - grpc_slice_buffer_init(&query_param_parts); - - grpc_slice_split(query_slice, QUERY_PARTS_SEPARATOR, &query_parts); - uri->query_parts = gpr_malloc(query_parts.count * sizeof(char *)); - uri->query_parts_values = gpr_malloc(query_parts.count * sizeof(char *)); - uri->num_query_parts = query_parts.count; - for (size_t i = 0; i < query_parts.count; i++) { - grpc_slice_split(query_parts.slices[i], QUERY_PARTS_VALUE_SEPARATOR, - &query_param_parts); - GPR_ASSERT(query_param_parts.count > 0); - uri->query_parts[i] = - grpc_dump_slice(query_param_parts.slices[0], GPR_DUMP_ASCII); - if (query_param_parts.count > 1) { + gpr_string_split(uri->query, QUERY_PARTS_SEPARATOR, &uri->query_parts, + &uri->num_query_parts); + uri->query_parts_values = gpr_malloc(uri->num_query_parts * sizeof(char **)); + for (size_t i = 0; i < uri->num_query_parts; i++) { + char **query_param_parts; + size_t num_query_param_parts; + char *full = uri->query_parts[i]; + gpr_string_split(full, QUERY_PARTS_VALUE_SEPARATOR, &query_param_parts, + &num_query_param_parts); + GPR_ASSERT(num_query_param_parts > 0); + uri->query_parts[i] = query_param_parts[0]; + if (num_query_param_parts > 1) { /* TODO(dgq): only the first value after the separator is considered. * Perhaps all chars after the first separator for the query part should * be included, even if they include the separator. */ - uri->query_parts_values[i] = - grpc_dump_slice(query_param_parts.slices[1], GPR_DUMP_ASCII); + uri->query_parts_values[i] = query_param_parts[1]; } else { uri->query_parts_values[i] = NULL; } - grpc_slice_buffer_reset_and_unref(&query_param_parts); + for (size_t j = 2; j < num_query_param_parts; j++) { + gpr_free(query_param_parts[j]); + } + gpr_free(query_param_parts); + gpr_free(full); } - grpc_slice_buffer_destroy(&query_parts); - grpc_slice_buffer_destroy(&query_param_parts); - grpc_slice_unref(query_slice); } -grpc_uri *grpc_uri_parse(const char *uri_text, int suppress_errors) { +grpc_uri *grpc_uri_parse(grpc_exec_ctx *exec_ctx, const char *uri_text, + bool suppress_errors) { grpc_uri *uri; size_t scheme_begin = 0; size_t scheme_end = NOT_SET; @@ -270,13 +269,17 @@ grpc_uri *grpc_uri_parse(const char *uri_text, int suppress_errors) { fragment_end = i; } - uri = gpr_malloc(sizeof(*uri)); - memset(uri, 0, sizeof(*uri)); - uri->scheme = copy_component(uri_text, scheme_begin, scheme_end); - uri->authority = copy_component(uri_text, authority_begin, authority_end); - uri->path = copy_component(uri_text, path_begin, path_end); - uri->query = copy_component(uri_text, query_begin, query_end); - uri->fragment = copy_component(uri_text, fragment_begin, fragment_end); + uri = gpr_zalloc(sizeof(*uri)); + uri->scheme = + decode_and_copy_component(exec_ctx, uri_text, scheme_begin, scheme_end); + uri->authority = decode_and_copy_component(exec_ctx, uri_text, + authority_begin, authority_end); + uri->path = + decode_and_copy_component(exec_ctx, uri_text, path_begin, path_end); + uri->query = + decode_and_copy_component(exec_ctx, uri_text, query_begin, query_end); + uri->fragment = decode_and_copy_component(exec_ctx, uri_text, fragment_begin, + fragment_end); parse_query_parts(uri); return uri; diff --git a/Sources/CgRPC/src/core/ext/filters/client_channel/uri_parser.h b/Sources/CgRPC/src/core/ext/filters/client_channel/uri_parser.h new file mode 100644 index 000000000..05ca2e00e --- /dev/null +++ b/Sources/CgRPC/src/core/ext/filters/client_channel/uri_parser.h @@ -0,0 +1,50 @@ +/* + * + * 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 GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_URI_PARSER_H +#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_URI_PARSER_H + +#include +#include "src/core/lib/iomgr/exec_ctx.h" + +typedef struct { + char *scheme; + char *authority; + char *path; + char *query; + /** Query substrings separated by '&' */ + char **query_parts; + /** Number of elements in \a query_parts and \a query_parts_values */ + size_t num_query_parts; + /** Split each query part by '='. NULL if not present. */ + char **query_parts_values; + char *fragment; +} grpc_uri; + +/** parse a uri, return NULL on failure */ +grpc_uri *grpc_uri_parse(grpc_exec_ctx *exec_ctx, const char *uri_text, + bool suppress_errors); + +/** return the part of a query string after the '=' in "?key=xxx&...", or NULL + * if key is not present */ +const char *grpc_uri_get_query_arg(const grpc_uri *uri, const char *key); + +/** destroy a uri */ +void grpc_uri_destroy(grpc_uri *uri); + +#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_URI_PARSER_H */ diff --git a/Sources/CgRPC/src/core/lib/channel/deadline_filter.c b/Sources/CgRPC/src/core/ext/filters/deadline/deadline_filter.c similarity index 51% rename from Sources/CgRPC/src/core/lib/channel/deadline_filter.c rename to Sources/CgRPC/src/core/ext/filters/deadline/deadline_filter.c index 470ccfea5..6789903c9 100644 --- a/Sources/CgRPC/src/core/lib/channel/deadline_filter.c +++ b/Sources/CgRPC/src/core/ext/filters/deadline/deadline_filter.c @@ -1,35 +1,20 @@ // -// Copyright 2016, Google Inc. -// All rights reserved. +// Copyright 2016 gRPC authors. // -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: +// 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 // -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. +// http://www.apache.org/licenses/LICENSE-2.0 // -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// 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 "src/core/lib/channel/deadline_filter.h" +#include "src/core/ext/filters/deadline/deadline_filter.h" #include #include @@ -39,8 +24,11 @@ #include #include +#include "src/core/lib/channel/channel_stack_builder.h" #include "src/core/lib/iomgr/exec_ctx.h" #include "src/core/lib/iomgr/timer.h" +#include "src/core/lib/slice/slice_internal.h" +#include "src/core/lib/surface/channel_init.h" // // grpc_deadline_state @@ -49,99 +37,97 @@ // Timer callback. static void timer_callback(grpc_exec_ctx* exec_ctx, void* arg, grpc_error* error) { - grpc_call_element* elem = arg; - grpc_deadline_state* deadline_state = elem->call_data; - gpr_mu_lock(&deadline_state->timer_mu); - deadline_state->timer_pending = false; - gpr_mu_unlock(&deadline_state->timer_mu); + grpc_call_element* elem = (grpc_call_element*)arg; + grpc_deadline_state* deadline_state = (grpc_deadline_state*)elem->call_data; if (error != GRPC_ERROR_CANCELLED) { - grpc_slice msg = grpc_slice_from_static_string("Deadline Exceeded"); - grpc_call_element_send_cancel_with_message( - exec_ctx, elem, GRPC_STATUS_DEADLINE_EXCEEDED, &msg); - grpc_slice_unref(msg); + grpc_call_element_signal_error( + exec_ctx, elem, + grpc_error_set_int( + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Deadline Exceeded"), + GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_DEADLINE_EXCEEDED)); } GRPC_CALL_STACK_UNREF(exec_ctx, deadline_state->call_stack, "deadline_timer"); } // Starts the deadline timer. -static void start_timer_if_needed_locked(grpc_exec_ctx* exec_ctx, - grpc_call_element* elem, - gpr_timespec deadline) { - grpc_deadline_state* deadline_state = elem->call_data; - deadline = gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC); - // Note: We do not start the timer if there is already a timer - // pending. This should be okay, because this is only called from two - // functions exported by this module: grpc_deadline_state_start(), which - // starts the initial timer, and grpc_deadline_state_reset(), which - // cancels any pre-existing timer before starting a new one. In - // particular, we want to ensure that if grpc_deadline_state_start() - // winds up trying to start the timer after grpc_deadline_state_reset() - // has already done so, we ignore the value from the former. - if (!deadline_state->timer_pending && - gpr_time_cmp(deadline, gpr_inf_future(GPR_CLOCK_MONOTONIC)) != 0) { - // Take a reference to the call stack, to be owned by the timer. - GRPC_CALL_STACK_REF(deadline_state->call_stack, "deadline_timer"); - deadline_state->timer_pending = true; - grpc_timer_init(exec_ctx, &deadline_state->timer, deadline, timer_callback, - elem, gpr_now(GPR_CLOCK_MONOTONIC)); - } -} static void start_timer_if_needed(grpc_exec_ctx* exec_ctx, grpc_call_element* elem, gpr_timespec deadline) { - grpc_deadline_state* deadline_state = elem->call_data; - gpr_mu_lock(&deadline_state->timer_mu); - start_timer_if_needed_locked(exec_ctx, elem, deadline); - gpr_mu_unlock(&deadline_state->timer_mu); + deadline = gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC); + if (gpr_time_cmp(deadline, gpr_inf_future(GPR_CLOCK_MONOTONIC)) == 0) { + return; + } + grpc_deadline_state* deadline_state = (grpc_deadline_state*)elem->call_data; + grpc_deadline_timer_state cur_state; + grpc_closure* closure = NULL; +retry: + cur_state = + (grpc_deadline_timer_state)gpr_atm_acq_load(&deadline_state->timer_state); + switch (cur_state) { + case GRPC_DEADLINE_STATE_PENDING: + // Note: We do not start the timer if there is already a timer + return; + case GRPC_DEADLINE_STATE_FINISHED: + if (gpr_atm_rel_cas(&deadline_state->timer_state, + GRPC_DEADLINE_STATE_FINISHED, + GRPC_DEADLINE_STATE_PENDING)) { + // If we've already created and destroyed a timer, we always create a + // new closure: we have no other guarantee that the inlined closure is + // not in use (it may hold a pending call to timer_callback) + closure = GRPC_CLOSURE_CREATE(timer_callback, elem, + grpc_schedule_on_exec_ctx); + } else { + goto retry; + } + break; + case GRPC_DEADLINE_STATE_INITIAL: + if (gpr_atm_rel_cas(&deadline_state->timer_state, + GRPC_DEADLINE_STATE_INITIAL, + GRPC_DEADLINE_STATE_PENDING)) { + closure = + GRPC_CLOSURE_INIT(&deadline_state->timer_callback, timer_callback, + elem, grpc_schedule_on_exec_ctx); + } else { + goto retry; + } + break; + } + GPR_ASSERT(closure); + GRPC_CALL_STACK_REF(deadline_state->call_stack, "deadline_timer"); + grpc_timer_init(exec_ctx, &deadline_state->timer, deadline, closure, + gpr_now(GPR_CLOCK_MONOTONIC)); } // Cancels the deadline timer. -static void cancel_timer_if_needed_locked(grpc_exec_ctx* exec_ctx, - grpc_deadline_state* deadline_state) { - if (deadline_state->timer_pending) { - grpc_timer_cancel(exec_ctx, &deadline_state->timer); - deadline_state->timer_pending = false; - } -} static void cancel_timer_if_needed(grpc_exec_ctx* exec_ctx, grpc_deadline_state* deadline_state) { - gpr_mu_lock(&deadline_state->timer_mu); - cancel_timer_if_needed_locked(exec_ctx, deadline_state); - gpr_mu_unlock(&deadline_state->timer_mu); + if (gpr_atm_rel_cas(&deadline_state->timer_state, GRPC_DEADLINE_STATE_PENDING, + GRPC_DEADLINE_STATE_FINISHED)) { + grpc_timer_cancel(exec_ctx, &deadline_state->timer); + } else { + // timer was either in STATE_INITAL (nothing to cancel) + // OR in STATE_FINISHED (again nothing to cancel) + } } // Callback run when the call is complete. static void on_complete(grpc_exec_ctx* exec_ctx, void* arg, grpc_error* error) { - grpc_deadline_state* deadline_state = arg; + grpc_deadline_state* deadline_state = (grpc_deadline_state*)arg; cancel_timer_if_needed(exec_ctx, deadline_state); // Invoke the next callback. - deadline_state->next_on_complete->cb( - exec_ctx, deadline_state->next_on_complete->cb_arg, error); + GRPC_CLOSURE_RUN(exec_ctx, deadline_state->next_on_complete, + GRPC_ERROR_REF(error)); } // Inject our own on_complete callback into op. static void inject_on_complete_cb(grpc_deadline_state* deadline_state, - grpc_transport_stream_op* op) { + grpc_transport_stream_op_batch* op) { deadline_state->next_on_complete = op->on_complete; - grpc_closure_init(&deadline_state->on_complete, on_complete, deadline_state); + GRPC_CLOSURE_INIT(&deadline_state->on_complete, on_complete, deadline_state, + grpc_schedule_on_exec_ctx); op->on_complete = &deadline_state->on_complete; } -void grpc_deadline_state_init(grpc_exec_ctx* exec_ctx, grpc_call_element* elem, - grpc_call_stack* call_stack) { - grpc_deadline_state* deadline_state = elem->call_data; - memset(deadline_state, 0, sizeof(*deadline_state)); - deadline_state->call_stack = call_stack; - gpr_mu_init(&deadline_state->timer_mu); -} - -void grpc_deadline_state_destroy(grpc_exec_ctx* exec_ctx, - grpc_call_element* elem) { - grpc_deadline_state* deadline_state = elem->call_data; - cancel_timer_if_needed(exec_ctx, deadline_state); - gpr_mu_destroy(&deadline_state->timer_mu); -} - // Callback and associated state for starting the timer after call stack // initialization has been completed. struct start_timer_after_init_state { @@ -156,8 +142,11 @@ static void start_timer_after_init(grpc_exec_ctx* exec_ctx, void* arg, gpr_free(state); } -void grpc_deadline_state_start(grpc_exec_ctx* exec_ctx, grpc_call_element* elem, - gpr_timespec deadline) { +void grpc_deadline_state_init(grpc_exec_ctx* exec_ctx, grpc_call_element* elem, + grpc_call_stack* call_stack, + gpr_timespec deadline) { + grpc_deadline_state* deadline_state = (grpc_deadline_state*)elem->call_data; + deadline_state->call_stack = call_stack; // Deadline will always be infinite on servers, so the timer will only be // set on clients with a finite deadline. deadline = gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC); @@ -172,31 +161,35 @@ void grpc_deadline_state_start(grpc_exec_ctx* exec_ctx, grpc_call_element* elem, struct start_timer_after_init_state* state = gpr_malloc(sizeof(*state)); state->elem = elem; state->deadline = deadline; - grpc_closure_init(&state->closure, start_timer_after_init, state); - grpc_exec_ctx_sched(exec_ctx, &state->closure, GRPC_ERROR_NONE, NULL); + GRPC_CLOSURE_INIT(&state->closure, start_timer_after_init, state, + grpc_schedule_on_exec_ctx); + GRPC_CLOSURE_SCHED(exec_ctx, &state->closure, GRPC_ERROR_NONE); } } +void grpc_deadline_state_destroy(grpc_exec_ctx* exec_ctx, + grpc_call_element* elem) { + grpc_deadline_state* deadline_state = (grpc_deadline_state*)elem->call_data; + cancel_timer_if_needed(exec_ctx, deadline_state); +} + void grpc_deadline_state_reset(grpc_exec_ctx* exec_ctx, grpc_call_element* elem, gpr_timespec new_deadline) { - grpc_deadline_state* deadline_state = elem->call_data; - gpr_mu_lock(&deadline_state->timer_mu); - cancel_timer_if_needed_locked(exec_ctx, deadline_state); - start_timer_if_needed_locked(exec_ctx, elem, new_deadline); - gpr_mu_unlock(&deadline_state->timer_mu); + grpc_deadline_state* deadline_state = (grpc_deadline_state*)elem->call_data; + cancel_timer_if_needed(exec_ctx, deadline_state); + start_timer_if_needed(exec_ctx, elem, new_deadline); } -void grpc_deadline_state_client_start_transport_stream_op( +void grpc_deadline_state_client_start_transport_stream_op_batch( grpc_exec_ctx* exec_ctx, grpc_call_element* elem, - grpc_transport_stream_op* op) { - grpc_deadline_state* deadline_state = elem->call_data; - if (op->cancel_error != GRPC_ERROR_NONE || - op->close_error != GRPC_ERROR_NONE) { + grpc_transport_stream_op_batch* op) { + grpc_deadline_state* deadline_state = (grpc_deadline_state*)elem->call_data; + if (op->cancel_stream) { cancel_timer_if_needed(exec_ctx, deadline_state); } else { // Make sure we know when the call is complete, so that we can cancel // the timer. - if (op->recv_trailing_metadata != NULL) { + if (op->recv_trailing_metadata) { inject_on_complete_cb(deadline_state, op); } } @@ -238,26 +231,24 @@ typedef struct server_call_data { // Constructor for call_data. Used for both client and server filters. static grpc_error* init_call_elem(grpc_exec_ctx* exec_ctx, grpc_call_element* elem, - grpc_call_element_args* args) { - // Note: size of call data is different between client and server. - memset(elem->call_data, 0, elem->filter->sizeof_call_data); - grpc_deadline_state_init(exec_ctx, elem, args->call_stack); - grpc_deadline_state_start(exec_ctx, elem, args->deadline); + const grpc_call_element_args* args) { + grpc_deadline_state_init(exec_ctx, elem, args->call_stack, args->deadline); return GRPC_ERROR_NONE; } // Destructor for call_data. Used for both client and server filters. static void destroy_call_elem(grpc_exec_ctx* exec_ctx, grpc_call_element* elem, const grpc_call_final_info* final_info, - void* and_free_memory) { + grpc_closure* ignored) { grpc_deadline_state_destroy(exec_ctx, elem); } // Method for starting a call op for client filter. -static void client_start_transport_stream_op(grpc_exec_ctx* exec_ctx, - grpc_call_element* elem, - grpc_transport_stream_op* op) { - grpc_deadline_state_client_start_transport_stream_op(exec_ctx, elem, op); +static void client_start_transport_stream_op_batch( + grpc_exec_ctx* exec_ctx, grpc_call_element* elem, + grpc_transport_stream_op_batch* op) { + grpc_deadline_state_client_start_transport_stream_op_batch(exec_ctx, elem, + op); // Chain to next filter. grpc_call_next_op(exec_ctx, elem, op); } @@ -265,8 +256,8 @@ static void client_start_transport_stream_op(grpc_exec_ctx* exec_ctx, // Callback for receiving initial metadata on the server. static void recv_initial_metadata_ready(grpc_exec_ctx* exec_ctx, void* arg, grpc_error* error) { - grpc_call_element* elem = arg; - server_call_data* calld = elem->call_data; + grpc_call_element* elem = (grpc_call_element*)arg; + server_call_data* calld = (server_call_data*)elem->call_data; // Get deadline from metadata and start the timer if needed. start_timer_if_needed(exec_ctx, elem, calld->recv_initial_metadata->deadline); // Invoke the next callback. @@ -275,30 +266,33 @@ static void recv_initial_metadata_ready(grpc_exec_ctx* exec_ctx, void* arg, } // Method for starting a call op for server filter. -static void server_start_transport_stream_op(grpc_exec_ctx* exec_ctx, - grpc_call_element* elem, - grpc_transport_stream_op* op) { - server_call_data* calld = elem->call_data; - if (op->cancel_error != GRPC_ERROR_NONE || - op->close_error != GRPC_ERROR_NONE) { +static void server_start_transport_stream_op_batch( + grpc_exec_ctx* exec_ctx, grpc_call_element* elem, + grpc_transport_stream_op_batch* op) { + server_call_data* calld = (server_call_data*)elem->call_data; + if (op->cancel_stream) { cancel_timer_if_needed(exec_ctx, &calld->base.deadline_state); } else { // If we're receiving initial metadata, we need to get the deadline // from the recv_initial_metadata_ready callback. So we inject our // own callback into that hook. - if (op->recv_initial_metadata_ready != NULL) { - calld->next_recv_initial_metadata_ready = op->recv_initial_metadata_ready; - calld->recv_initial_metadata = op->recv_initial_metadata; - grpc_closure_init(&calld->recv_initial_metadata_ready, - recv_initial_metadata_ready, elem); - op->recv_initial_metadata_ready = &calld->recv_initial_metadata_ready; + if (op->recv_initial_metadata) { + calld->next_recv_initial_metadata_ready = + op->payload->recv_initial_metadata.recv_initial_metadata_ready; + calld->recv_initial_metadata = + op->payload->recv_initial_metadata.recv_initial_metadata; + GRPC_CLOSURE_INIT(&calld->recv_initial_metadata_ready, + recv_initial_metadata_ready, elem, + grpc_schedule_on_exec_ctx); + op->payload->recv_initial_metadata.recv_initial_metadata_ready = + &calld->recv_initial_metadata_ready; } // Make sure we know when the call is complete, so that we can cancel // the timer. // Note that we trigger this on recv_trailing_metadata, even though // the client never sends trailing metadata, because this is the // hook that tells us when the call is complete on the server side. - if (op->recv_trailing_metadata != NULL) { + if (op->recv_trailing_metadata) { inject_on_complete_cb(&calld->base.deadline_state, op); } } @@ -307,7 +301,7 @@ static void server_start_transport_stream_op(grpc_exec_ctx* exec_ctx, } const grpc_channel_filter grpc_client_deadline_filter = { - client_start_transport_stream_op, + client_start_transport_stream_op_batch, grpc_channel_next_op, sizeof(base_call_data), init_call_elem, @@ -322,7 +316,7 @@ const grpc_channel_filter grpc_client_deadline_filter = { }; const grpc_channel_filter grpc_server_deadline_filter = { - server_start_transport_stream_op, + server_start_transport_stream_op_batch, grpc_channel_next_op, sizeof(server_call_data), init_call_elem, @@ -335,3 +329,30 @@ const grpc_channel_filter grpc_server_deadline_filter = { grpc_channel_next_get_info, "deadline", }; + +bool grpc_deadline_checking_enabled(const grpc_channel_args* channel_args) { + return grpc_channel_arg_get_bool( + grpc_channel_args_find(channel_args, GRPC_ARG_ENABLE_DEADLINE_CHECKS), + !grpc_channel_args_want_minimal_stack(channel_args)); +} + +static bool maybe_add_deadline_filter(grpc_exec_ctx* exec_ctx, + grpc_channel_stack_builder* builder, + void* arg) { + return grpc_deadline_checking_enabled( + grpc_channel_stack_builder_get_channel_arguments(builder)) + ? grpc_channel_stack_builder_prepend_filter( + builder, (const grpc_channel_filter*)arg, NULL, NULL) + : true; +} + +void grpc_deadline_filter_init(void) { + grpc_channel_init_register_stage( + GRPC_CLIENT_DIRECT_CHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, + maybe_add_deadline_filter, (void*)&grpc_client_deadline_filter); + grpc_channel_init_register_stage( + GRPC_SERVER_CHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, + maybe_add_deadline_filter, (void*)&grpc_server_deadline_filter); +} + +void grpc_deadline_filter_shutdown(void) {} diff --git a/Sources/CgRPC/src/core/ext/filters/deadline/deadline_filter.h b/Sources/CgRPC/src/core/ext/filters/deadline/deadline_filter.h new file mode 100644 index 000000000..420bf7065 --- /dev/null +++ b/Sources/CgRPC/src/core/ext/filters/deadline/deadline_filter.h @@ -0,0 +1,86 @@ +// +// Copyright 2016 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 GRPC_CORE_EXT_FILTERS_DEADLINE_DEADLINE_FILTER_H +#define GRPC_CORE_EXT_FILTERS_DEADLINE_DEADLINE_FILTER_H + +#include "src/core/lib/channel/channel_stack.h" +#include "src/core/lib/iomgr/timer.h" + +typedef enum grpc_deadline_timer_state { + GRPC_DEADLINE_STATE_INITIAL, + GRPC_DEADLINE_STATE_PENDING, + GRPC_DEADLINE_STATE_FINISHED +} grpc_deadline_timer_state; + +// State used for filters that enforce call deadlines. +// Must be the first field in the filter's call_data. +typedef struct grpc_deadline_state { + // We take a reference to the call stack for the timer callback. + grpc_call_stack* call_stack; + gpr_atm timer_state; + grpc_timer timer; + grpc_closure timer_callback; + // Closure to invoke when the call is complete. + // We use this to cancel the timer. + grpc_closure on_complete; + // The original on_complete closure, which we chain to after our own + // closure is invoked. + grpc_closure* next_on_complete; +} grpc_deadline_state; + +// +// NOTE: All of these functions require that the first field in +// elem->call_data is a grpc_deadline_state. +// + +// assumes elem->call_data is zero'd +void grpc_deadline_state_init(grpc_exec_ctx* exec_ctx, grpc_call_element* elem, + grpc_call_stack* call_stack, + gpr_timespec deadline); +void grpc_deadline_state_destroy(grpc_exec_ctx* exec_ctx, + grpc_call_element* elem); + +// Cancels the existing timer and starts a new one with new_deadline. +// +// Note: It is generally safe to call this with an earlier deadline +// value than the current one, but not the reverse. No checks are done +// to ensure that the timer callback is not invoked while it is in the +// process of being reset, which means that attempting to increase the +// deadline may result in the timer being called twice. +void grpc_deadline_state_reset(grpc_exec_ctx* exec_ctx, grpc_call_element* elem, + gpr_timespec new_deadline); + +// To be called from the client-side filter's start_transport_stream_op_batch() +// method. Ensures that the deadline timer is cancelled when the call +// is completed. +// +// Note: It is the caller's responsibility to chain to the next filter if +// necessary after this function returns. +void grpc_deadline_state_client_start_transport_stream_op_batch( + grpc_exec_ctx* exec_ctx, grpc_call_element* elem, + grpc_transport_stream_op_batch* op); + +// Should deadline checking be performed (according to channel args) +bool grpc_deadline_checking_enabled(const grpc_channel_args* args); + +// Deadline filters for direct client channels and server channels. +// Note: Deadlines for non-direct client channels are handled by the +// client_channel filter. +extern const grpc_channel_filter grpc_client_deadline_filter; +extern const grpc_channel_filter grpc_server_deadline_filter; + +#endif /* GRPC_CORE_EXT_FILTERS_DEADLINE_DEADLINE_FILTER_H */ diff --git a/Sources/CgRPC/src/core/ext/filters/http/client/http_client_filter.c b/Sources/CgRPC/src/core/ext/filters/http/client/http_client_filter.c new file mode 100644 index 000000000..3ca01a41b --- /dev/null +++ b/Sources/CgRPC/src/core/ext/filters/http/client/http_client_filter.c @@ -0,0 +1,570 @@ +/* + * 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 "src/core/ext/filters/http/client/http_client_filter.h" +#include +#include +#include +#include +#include "src/core/lib/profiling/timers.h" +#include "src/core/lib/slice/b64.h" +#include "src/core/lib/slice/percent_encoding.h" +#include "src/core/lib/slice/slice_internal.h" +#include "src/core/lib/slice/slice_string_helpers.h" +#include "src/core/lib/support/string.h" +#include "src/core/lib/transport/static_metadata.h" +#include "src/core/lib/transport/transport_impl.h" + +#define EXPECTED_CONTENT_TYPE "application/grpc" +#define EXPECTED_CONTENT_TYPE_LENGTH sizeof(EXPECTED_CONTENT_TYPE) - 1 + +/* default maximum size of payload eligable for GET request */ +static const size_t kMaxPayloadSizeForGet = 2048; + +typedef struct call_data { + // State for handling send_initial_metadata ops. + grpc_linked_mdelem method; + grpc_linked_mdelem scheme; + grpc_linked_mdelem authority; + grpc_linked_mdelem te_trailers; + grpc_linked_mdelem content_type; + grpc_linked_mdelem user_agent; + // State for handling recv_initial_metadata ops. + grpc_metadata_batch *recv_initial_metadata; + grpc_closure *original_recv_initial_metadata_ready; + grpc_closure recv_initial_metadata_ready; + // State for handling recv_trailing_metadata ops. + grpc_metadata_batch *recv_trailing_metadata; + grpc_closure *original_recv_trailing_metadata_on_complete; + grpc_closure recv_trailing_metadata_on_complete; + // State for handling send_message ops. + grpc_transport_stream_op_batch *send_message_batch; + size_t send_message_bytes_read; + grpc_byte_stream_cache send_message_cache; + grpc_caching_byte_stream send_message_caching_stream; + grpc_closure on_send_message_next_done; + grpc_closure *original_send_message_on_complete; + grpc_closure send_message_on_complete; +} call_data; + +typedef struct channel_data { + grpc_mdelem static_scheme; + grpc_mdelem user_agent; + size_t max_payload_size_for_get; +} channel_data; + +static grpc_error *client_filter_incoming_metadata(grpc_exec_ctx *exec_ctx, + grpc_call_element *elem, + grpc_metadata_batch *b) { + if (b->idx.named.status != NULL) { + if (grpc_mdelem_eq(b->idx.named.status->md, GRPC_MDELEM_STATUS_200)) { + grpc_metadata_batch_remove(exec_ctx, b, b->idx.named.status); + } else { + char *val = grpc_dump_slice(GRPC_MDVALUE(b->idx.named.status->md), + GPR_DUMP_ASCII); + char *msg; + gpr_asprintf(&msg, "Received http2 header with status: %s", val); + grpc_error *e = grpc_error_set_str( + grpc_error_set_int( + grpc_error_set_str( + GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "Received http2 :status header with non-200 OK status"), + GRPC_ERROR_STR_VALUE, grpc_slice_from_copied_string(val)), + GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_CANCELLED), + GRPC_ERROR_STR_GRPC_MESSAGE, grpc_slice_from_copied_string(msg)); + gpr_free(val); + gpr_free(msg); + return e; + } + } + + if (b->idx.named.grpc_message != NULL) { + grpc_slice pct_decoded_msg = grpc_permissive_percent_decode_slice( + GRPC_MDVALUE(b->idx.named.grpc_message->md)); + if (grpc_slice_is_equivalent(pct_decoded_msg, + GRPC_MDVALUE(b->idx.named.grpc_message->md))) { + grpc_slice_unref_internal(exec_ctx, pct_decoded_msg); + } else { + grpc_metadata_batch_set_value(exec_ctx, b->idx.named.grpc_message, + pct_decoded_msg); + } + } + + if (b->idx.named.content_type != NULL) { + if (!grpc_mdelem_eq(b->idx.named.content_type->md, + GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC)) { + if (grpc_slice_buf_start_eq(GRPC_MDVALUE(b->idx.named.content_type->md), + EXPECTED_CONTENT_TYPE, + EXPECTED_CONTENT_TYPE_LENGTH) && + (GRPC_SLICE_START_PTR(GRPC_MDVALUE( + b->idx.named.content_type->md))[EXPECTED_CONTENT_TYPE_LENGTH] == + '+' || + GRPC_SLICE_START_PTR(GRPC_MDVALUE( + b->idx.named.content_type->md))[EXPECTED_CONTENT_TYPE_LENGTH] == + ';')) { + /* Although the C implementation doesn't (currently) generate them, + any custom +-suffix is explicitly valid. */ + /* TODO(klempner): We should consider preallocating common values such + as +proto or +json, or at least stashing them if we see them. */ + /* TODO(klempner): Should we be surfacing this to application code? */ + } else { + /* TODO(klempner): We're currently allowing this, but we shouldn't + see it without a proxy so log for now. */ + char *val = grpc_dump_slice(GRPC_MDVALUE(b->idx.named.content_type->md), + GPR_DUMP_ASCII); + gpr_log(GPR_INFO, "Unexpected content-type '%s'", val); + gpr_free(val); + } + } + grpc_metadata_batch_remove(exec_ctx, b, b->idx.named.content_type); + } + + return GRPC_ERROR_NONE; +} + +static void recv_initial_metadata_ready(grpc_exec_ctx *exec_ctx, + void *user_data, grpc_error *error) { + grpc_call_element *elem = user_data; + call_data *calld = elem->call_data; + if (error == GRPC_ERROR_NONE) { + error = client_filter_incoming_metadata(exec_ctx, elem, + calld->recv_initial_metadata); + } else { + GRPC_ERROR_REF(error); + } + GRPC_CLOSURE_RUN(exec_ctx, calld->original_recv_initial_metadata_ready, + error); +} + +static void recv_trailing_metadata_on_complete(grpc_exec_ctx *exec_ctx, + void *user_data, + grpc_error *error) { + grpc_call_element *elem = user_data; + call_data *calld = elem->call_data; + if (error == GRPC_ERROR_NONE) { + error = client_filter_incoming_metadata(exec_ctx, elem, + calld->recv_trailing_metadata); + } else { + GRPC_ERROR_REF(error); + } + GRPC_CLOSURE_RUN(exec_ctx, calld->original_recv_trailing_metadata_on_complete, + error); +} + +static void send_message_on_complete(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error) { + grpc_call_element *elem = (grpc_call_element *)arg; + call_data *calld = (call_data *)elem->call_data; + grpc_byte_stream_cache_destroy(exec_ctx, &calld->send_message_cache); + GRPC_CLOSURE_RUN(exec_ctx, calld->original_send_message_on_complete, + GRPC_ERROR_REF(error)); +} + +// Pulls a slice from the send_message byte stream, updating +// calld->send_message_bytes_read. +static grpc_error *pull_slice_from_send_message(grpc_exec_ctx *exec_ctx, + call_data *calld) { + grpc_slice incoming_slice; + grpc_error *error = grpc_byte_stream_pull( + exec_ctx, &calld->send_message_caching_stream.base, &incoming_slice); + if (error == GRPC_ERROR_NONE) { + calld->send_message_bytes_read += GRPC_SLICE_LENGTH(incoming_slice); + grpc_slice_unref_internal(exec_ctx, incoming_slice); + } + return error; +} + +// Reads as many slices as possible from the send_message byte stream. +// Upon successful return, if calld->send_message_bytes_read == +// calld->send_message_caching_stream.base.length, then we have completed +// reading from the byte stream; otherwise, an async read has been dispatched +// and on_send_message_next_done() will be invoked when it is complete. +static grpc_error *read_all_available_send_message_data(grpc_exec_ctx *exec_ctx, + call_data *calld) { + while (grpc_byte_stream_next(exec_ctx, + &calld->send_message_caching_stream.base, + ~(size_t)0, &calld->on_send_message_next_done)) { + grpc_error *error = pull_slice_from_send_message(exec_ctx, calld); + if (error != GRPC_ERROR_NONE) return error; + if (calld->send_message_bytes_read == + calld->send_message_caching_stream.base.length) { + break; + } + } + return GRPC_ERROR_NONE; +} + +// Async callback for grpc_byte_stream_next(). +static void on_send_message_next_done(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error) { + grpc_call_element *elem = (grpc_call_element *)arg; + call_data *calld = (call_data *)elem->call_data; + if (error != GRPC_ERROR_NONE) { + grpc_transport_stream_op_batch_finish_with_failure( + exec_ctx, calld->send_message_batch, error); + return; + } + error = pull_slice_from_send_message(exec_ctx, calld); + if (error != GRPC_ERROR_NONE) { + grpc_transport_stream_op_batch_finish_with_failure( + exec_ctx, calld->send_message_batch, error); + return; + } + // There may or may not be more to read, but we don't care. If we got + // here, then we know that all of the data was not available + // synchronously, so we were not able to do a cached call. Instead, + // we just reset the byte stream and then send down the batch as-is. + grpc_caching_byte_stream_reset(&calld->send_message_caching_stream); + grpc_call_next_op(exec_ctx, elem, calld->send_message_batch); +} + +static char *slice_buffer_to_string(grpc_slice_buffer *slice_buffer) { + char *payload_bytes = gpr_malloc(slice_buffer->length + 1); + size_t offset = 0; + for (size_t i = 0; i < slice_buffer->count; ++i) { + memcpy(payload_bytes + offset, + GRPC_SLICE_START_PTR(slice_buffer->slices[i]), + GRPC_SLICE_LENGTH(slice_buffer->slices[i])); + offset += GRPC_SLICE_LENGTH(slice_buffer->slices[i]); + } + *(payload_bytes + offset) = '\0'; + return payload_bytes; +} + +// Modifies the path entry in the batch's send_initial_metadata to +// append the base64-encoded query for a GET request. +static grpc_error *update_path_for_get(grpc_exec_ctx *exec_ctx, + grpc_call_element *elem, + grpc_transport_stream_op_batch *batch) { + call_data *calld = (call_data *)elem->call_data; + grpc_slice path_slice = + GRPC_MDVALUE(batch->payload->send_initial_metadata.send_initial_metadata + ->idx.named.path->md); + /* sum up individual component's lengths and allocate enough memory to + * hold combined path+query */ + size_t estimated_len = GRPC_SLICE_LENGTH(path_slice); + estimated_len++; /* for the '?' */ + estimated_len += grpc_base64_estimate_encoded_size( + batch->payload->send_message.send_message->length, true /* url_safe */, + false /* multi_line */); + grpc_slice path_with_query_slice = GRPC_SLICE_MALLOC(estimated_len); + /* memcopy individual pieces into this slice */ + char *write_ptr = (char *)GRPC_SLICE_START_PTR(path_with_query_slice); + char *original_path = (char *)GRPC_SLICE_START_PTR(path_slice); + memcpy(write_ptr, original_path, GRPC_SLICE_LENGTH(path_slice)); + write_ptr += GRPC_SLICE_LENGTH(path_slice); + *write_ptr++ = '?'; + char *payload_bytes = + slice_buffer_to_string(&calld->send_message_cache.cache_buffer); + grpc_base64_encode_core((char *)write_ptr, payload_bytes, + batch->payload->send_message.send_message->length, + true /* url_safe */, false /* multi_line */); + gpr_free(payload_bytes); + /* remove trailing unused memory and add trailing 0 to terminate string */ + char *t = (char *)GRPC_SLICE_START_PTR(path_with_query_slice); + /* safe to use strlen since base64_encode will always add '\0' */ + path_with_query_slice = + grpc_slice_sub_no_ref(path_with_query_slice, 0, strlen(t)); + /* substitute previous path with the new path+query */ + grpc_mdelem mdelem_path_and_query = + grpc_mdelem_from_slices(exec_ctx, GRPC_MDSTR_PATH, path_with_query_slice); + grpc_metadata_batch *b = + batch->payload->send_initial_metadata.send_initial_metadata; + return grpc_metadata_batch_substitute(exec_ctx, b, b->idx.named.path, + mdelem_path_and_query); +} + +static void remove_if_present(grpc_exec_ctx *exec_ctx, + grpc_metadata_batch *batch, + grpc_metadata_batch_callouts_index idx) { + if (batch->idx.array[idx] != NULL) { + grpc_metadata_batch_remove(exec_ctx, batch, batch->idx.array[idx]); + } +} + +static void hc_start_transport_stream_op_batch( + grpc_exec_ctx *exec_ctx, grpc_call_element *elem, + grpc_transport_stream_op_batch *batch) { + call_data *calld = elem->call_data; + channel_data *channeld = elem->channel_data; + GPR_TIMER_BEGIN("hc_start_transport_stream_op_batch", 0); + GRPC_CALL_LOG_OP(GPR_INFO, elem, batch); + + if (batch->recv_initial_metadata) { + /* substitute our callback for the higher callback */ + calld->recv_initial_metadata = + batch->payload->recv_initial_metadata.recv_initial_metadata; + calld->original_recv_initial_metadata_ready = + batch->payload->recv_initial_metadata.recv_initial_metadata_ready; + batch->payload->recv_initial_metadata.recv_initial_metadata_ready = + &calld->recv_initial_metadata_ready; + } + + if (batch->recv_trailing_metadata) { + /* substitute our callback for the higher callback */ + calld->recv_trailing_metadata = + batch->payload->recv_trailing_metadata.recv_trailing_metadata; + calld->original_recv_trailing_metadata_on_complete = batch->on_complete; + batch->on_complete = &calld->recv_trailing_metadata_on_complete; + } + + grpc_error *error = GRPC_ERROR_NONE; + bool batch_will_be_handled_asynchronously = false; + if (batch->send_initial_metadata) { + // Decide which HTTP VERB to use. We use GET if the request is marked + // cacheable, and the operation contains both initial metadata and send + // message, and the payload is below the size threshold, and all the data + // for this request is immediately available. + grpc_mdelem method = GRPC_MDELEM_METHOD_POST; + if (batch->send_message && + (batch->payload->send_initial_metadata.send_initial_metadata_flags & + GRPC_INITIAL_METADATA_CACHEABLE_REQUEST) && + batch->payload->send_message.send_message->length < + channeld->max_payload_size_for_get) { + calld->send_message_bytes_read = 0; + grpc_byte_stream_cache_init(&calld->send_message_cache, + batch->payload->send_message.send_message); + grpc_caching_byte_stream_init(&calld->send_message_caching_stream, + &calld->send_message_cache); + batch->payload->send_message.send_message = + &calld->send_message_caching_stream.base; + calld->original_send_message_on_complete = batch->on_complete; + batch->on_complete = &calld->send_message_on_complete; + calld->send_message_batch = batch; + error = read_all_available_send_message_data(exec_ctx, calld); + if (error != GRPC_ERROR_NONE) goto done; + // If all the data has been read, then we can use GET. + if (calld->send_message_bytes_read == + calld->send_message_caching_stream.base.length) { + method = GRPC_MDELEM_METHOD_GET; + error = update_path_for_get(exec_ctx, elem, batch); + if (error != GRPC_ERROR_NONE) goto done; + batch->send_message = false; + grpc_byte_stream_destroy(exec_ctx, + &calld->send_message_caching_stream.base); + } else { + // Not all data is available. The batch will be sent down + // asynchronously in on_send_message_next_done(). + batch_will_be_handled_asynchronously = true; + // Fall back to POST. + gpr_log(GPR_DEBUG, + "Request is marked Cacheable but not all data is available. " + "Falling back to POST"); + } + } else if (batch->payload->send_initial_metadata + .send_initial_metadata_flags & + GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST) { + method = GRPC_MDELEM_METHOD_PUT; + } + + remove_if_present( + exec_ctx, batch->payload->send_initial_metadata.send_initial_metadata, + GRPC_BATCH_METHOD); + remove_if_present( + exec_ctx, batch->payload->send_initial_metadata.send_initial_metadata, + GRPC_BATCH_SCHEME); + remove_if_present( + exec_ctx, batch->payload->send_initial_metadata.send_initial_metadata, + GRPC_BATCH_TE); + remove_if_present( + exec_ctx, batch->payload->send_initial_metadata.send_initial_metadata, + GRPC_BATCH_CONTENT_TYPE); + remove_if_present( + exec_ctx, batch->payload->send_initial_metadata.send_initial_metadata, + GRPC_BATCH_USER_AGENT); + + /* Send : prefixed headers, which have to be before any application + layer headers. */ + error = grpc_metadata_batch_add_head( + exec_ctx, batch->payload->send_initial_metadata.send_initial_metadata, + &calld->method, method); + if (error != GRPC_ERROR_NONE) goto done; + error = grpc_metadata_batch_add_head( + exec_ctx, batch->payload->send_initial_metadata.send_initial_metadata, + &calld->scheme, channeld->static_scheme); + if (error != GRPC_ERROR_NONE) goto done; + error = grpc_metadata_batch_add_tail( + exec_ctx, batch->payload->send_initial_metadata.send_initial_metadata, + &calld->te_trailers, GRPC_MDELEM_TE_TRAILERS); + if (error != GRPC_ERROR_NONE) goto done; + error = grpc_metadata_batch_add_tail( + exec_ctx, batch->payload->send_initial_metadata.send_initial_metadata, + &calld->content_type, GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC); + if (error != GRPC_ERROR_NONE) goto done; + error = grpc_metadata_batch_add_tail( + exec_ctx, batch->payload->send_initial_metadata.send_initial_metadata, + &calld->user_agent, GRPC_MDELEM_REF(channeld->user_agent)); + if (error != GRPC_ERROR_NONE) goto done; + } + +done: + if (error != GRPC_ERROR_NONE) { + grpc_transport_stream_op_batch_finish_with_failure( + exec_ctx, calld->send_message_batch, error); + } else if (!batch_will_be_handled_asynchronously) { + grpc_call_next_op(exec_ctx, elem, batch); + } + GPR_TIMER_END("hc_start_transport_stream_op_batch", 0); +} + +/* Constructor for call_data */ +static grpc_error *init_call_elem(grpc_exec_ctx *exec_ctx, + grpc_call_element *elem, + const grpc_call_element_args *args) { + call_data *calld = (call_data *)elem->call_data; + GRPC_CLOSURE_INIT(&calld->recv_initial_metadata_ready, + recv_initial_metadata_ready, elem, + grpc_schedule_on_exec_ctx); + GRPC_CLOSURE_INIT(&calld->recv_trailing_metadata_on_complete, + recv_trailing_metadata_on_complete, elem, + grpc_schedule_on_exec_ctx); + GRPC_CLOSURE_INIT(&calld->send_message_on_complete, send_message_on_complete, + elem, grpc_schedule_on_exec_ctx); + GRPC_CLOSURE_INIT(&calld->on_send_message_next_done, + on_send_message_next_done, elem, grpc_schedule_on_exec_ctx); + return GRPC_ERROR_NONE; +} + +/* Destructor for call_data */ +static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, + const grpc_call_final_info *final_info, + grpc_closure *ignored) {} + +static grpc_mdelem scheme_from_args(const grpc_channel_args *args) { + unsigned i; + size_t j; + grpc_mdelem valid_schemes[] = {GRPC_MDELEM_SCHEME_HTTP, + GRPC_MDELEM_SCHEME_HTTPS}; + if (args != NULL) { + for (i = 0; i < args->num_args; ++i) { + if (args->args[i].type == GRPC_ARG_STRING && + strcmp(args->args[i].key, GRPC_ARG_HTTP2_SCHEME) == 0) { + for (j = 0; j < GPR_ARRAY_SIZE(valid_schemes); j++) { + if (0 == grpc_slice_str_cmp(GRPC_MDVALUE(valid_schemes[j]), + args->args[i].value.string)) { + return valid_schemes[j]; + } + } + } + } + } + return GRPC_MDELEM_SCHEME_HTTP; +} + +static size_t max_payload_size_from_args(const grpc_channel_args *args) { + if (args != NULL) { + for (size_t i = 0; i < args->num_args; ++i) { + if (0 == strcmp(args->args[i].key, GRPC_ARG_MAX_PAYLOAD_SIZE_FOR_GET)) { + if (args->args[i].type != GRPC_ARG_INTEGER) { + gpr_log(GPR_ERROR, "%s: must be an integer", + GRPC_ARG_MAX_PAYLOAD_SIZE_FOR_GET); + } else { + return (size_t)args->args[i].value.integer; + } + } + } + } + return kMaxPayloadSizeForGet; +} + +static grpc_slice user_agent_from_args(const grpc_channel_args *args, + const char *transport_name) { + gpr_strvec v; + size_t i; + int is_first = 1; + char *tmp; + grpc_slice result; + + gpr_strvec_init(&v); + + for (i = 0; args && i < args->num_args; i++) { + if (0 == strcmp(args->args[i].key, GRPC_ARG_PRIMARY_USER_AGENT_STRING)) { + if (args->args[i].type != GRPC_ARG_STRING) { + gpr_log(GPR_ERROR, "Channel argument '%s' should be a string", + GRPC_ARG_PRIMARY_USER_AGENT_STRING); + } else { + if (!is_first) gpr_strvec_add(&v, gpr_strdup(" ")); + is_first = 0; + gpr_strvec_add(&v, gpr_strdup(args->args[i].value.string)); + } + } + } + + gpr_asprintf(&tmp, "%sgrpc-c/%s (%s; %s; %s)", is_first ? "" : " ", + grpc_version_string(), GPR_PLATFORM_STRING, transport_name, + grpc_g_stands_for()); + is_first = 0; + gpr_strvec_add(&v, tmp); + + for (i = 0; args && i < args->num_args; i++) { + if (0 == strcmp(args->args[i].key, GRPC_ARG_SECONDARY_USER_AGENT_STRING)) { + if (args->args[i].type != GRPC_ARG_STRING) { + gpr_log(GPR_ERROR, "Channel argument '%s' should be a string", + GRPC_ARG_SECONDARY_USER_AGENT_STRING); + } else { + if (!is_first) gpr_strvec_add(&v, gpr_strdup(" ")); + is_first = 0; + gpr_strvec_add(&v, gpr_strdup(args->args[i].value.string)); + } + } + } + + tmp = gpr_strvec_flatten(&v, NULL); + gpr_strvec_destroy(&v); + result = grpc_slice_intern(grpc_slice_from_static_string(tmp)); + gpr_free(tmp); + + return result; +} + +/* Constructor for channel_data */ +static grpc_error *init_channel_elem(grpc_exec_ctx *exec_ctx, + grpc_channel_element *elem, + grpc_channel_element_args *args) { + channel_data *chand = elem->channel_data; + GPR_ASSERT(!args->is_last); + GPR_ASSERT(args->optional_transport != NULL); + chand->static_scheme = scheme_from_args(args->channel_args); + chand->max_payload_size_for_get = + max_payload_size_from_args(args->channel_args); + chand->user_agent = grpc_mdelem_from_slices( + exec_ctx, GRPC_MDSTR_USER_AGENT, + user_agent_from_args(args->channel_args, + args->optional_transport->vtable->name)); + return GRPC_ERROR_NONE; +} + +/* Destructor for channel data */ +static void destroy_channel_elem(grpc_exec_ctx *exec_ctx, + grpc_channel_element *elem) { + channel_data *chand = elem->channel_data; + GRPC_MDELEM_UNREF(exec_ctx, chand->user_agent); +} + +const grpc_channel_filter grpc_http_client_filter = { + hc_start_transport_stream_op_batch, + grpc_channel_next_op, + sizeof(call_data), + init_call_elem, + grpc_call_stack_ignore_set_pollset_or_pollset_set, + destroy_call_elem, + sizeof(channel_data), + init_channel_elem, + destroy_channel_elem, + grpc_call_next_get_peer, + grpc_channel_next_get_info, + "http-client"}; diff --git a/Sources/CgRPC/src/core/ext/filters/http/client/http_client_filter.h b/Sources/CgRPC/src/core/ext/filters/http/client/http_client_filter.h new file mode 100644 index 000000000..ec8177c43 --- /dev/null +++ b/Sources/CgRPC/src/core/ext/filters/http/client/http_client_filter.h @@ -0,0 +1,29 @@ +/* + * 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 GRPC_CORE_EXT_FILTERS_HTTP_CLIENT_HTTP_CLIENT_FILTER_H +#define GRPC_CORE_EXT_FILTERS_HTTP_CLIENT_HTTP_CLIENT_FILTER_H + +#include "src/core/lib/channel/channel_stack.h" + +/* Processes metadata on the client side for HTTP2 transports */ +extern const grpc_channel_filter grpc_http_client_filter; + +/* Channel arg to determine maximum size of payload eligable for GET request */ +#define GRPC_ARG_MAX_PAYLOAD_SIZE_FOR_GET "grpc.max_payload_size_for_get" + +#endif /* GRPC_CORE_EXT_FILTERS_HTTP_CLIENT_HTTP_CLIENT_FILTER_H */ diff --git a/Sources/CgRPC/src/core/ext/filters/http/http_filters_plugin.c b/Sources/CgRPC/src/core/ext/filters/http/http_filters_plugin.c new file mode 100644 index 000000000..a5c1b9205 --- /dev/null +++ b/Sources/CgRPC/src/core/ext/filters/http/http_filters_plugin.c @@ -0,0 +1,89 @@ +/* + * + * Copyright 2017 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 + +#include "src/core/ext/filters/http/client/http_client_filter.h" +#include "src/core/ext/filters/http/message_compress/message_compress_filter.h" +#include "src/core/ext/filters/http/server/http_server_filter.h" +#include "src/core/lib/channel/channel_stack_builder.h" +#include "src/core/lib/surface/call.h" +#include "src/core/lib/surface/channel_init.h" +#include "src/core/lib/transport/transport_impl.h" + +typedef struct { + const grpc_channel_filter *filter; + const char *control_channel_arg; +} optional_filter; + +static optional_filter compress_filter = { + &grpc_message_compress_filter, GRPC_ARG_ENABLE_PER_MESSAGE_COMPRESSION}; + +static bool is_building_http_like_transport( + grpc_channel_stack_builder *builder) { + grpc_transport *t = grpc_channel_stack_builder_get_transport(builder); + return t != NULL && strstr(t->vtable->name, "http"); +} + +static bool maybe_add_optional_filter(grpc_exec_ctx *exec_ctx, + grpc_channel_stack_builder *builder, + void *arg) { + if (!is_building_http_like_transport(builder)) return true; + optional_filter *filtarg = arg; + const grpc_channel_args *channel_args = + grpc_channel_stack_builder_get_channel_arguments(builder); + bool enable = grpc_channel_arg_get_bool( + grpc_channel_args_find(channel_args, filtarg->control_channel_arg), + !grpc_channel_args_want_minimal_stack(channel_args)); + return enable ? grpc_channel_stack_builder_prepend_filter( + builder, filtarg->filter, NULL, NULL) + : true; +} + +static bool maybe_add_required_filter(grpc_exec_ctx *exec_ctx, + grpc_channel_stack_builder *builder, + void *arg) { + return is_building_http_like_transport(builder) + ? grpc_channel_stack_builder_prepend_filter( + builder, (const grpc_channel_filter *)arg, NULL, NULL) + : true; +} + +void grpc_http_filters_init(void) { + grpc_register_tracer(&grpc_compression_trace); + grpc_channel_init_register_stage(GRPC_CLIENT_SUBCHANNEL, + GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, + maybe_add_optional_filter, &compress_filter); + grpc_channel_init_register_stage(GRPC_CLIENT_DIRECT_CHANNEL, + GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, + maybe_add_optional_filter, &compress_filter); + grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL, + GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, + maybe_add_optional_filter, &compress_filter); + grpc_channel_init_register_stage( + GRPC_CLIENT_SUBCHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, + maybe_add_required_filter, (void *)&grpc_http_client_filter); + grpc_channel_init_register_stage( + GRPC_CLIENT_DIRECT_CHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, + maybe_add_required_filter, (void *)&grpc_http_client_filter); + grpc_channel_init_register_stage( + GRPC_SERVER_CHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, + maybe_add_required_filter, (void *)&grpc_http_server_filter); +} + +void grpc_http_filters_shutdown(void) {} diff --git a/Sources/CgRPC/src/core/ext/filters/http/message_compress/message_compress_filter.c b/Sources/CgRPC/src/core/ext/filters/http/message_compress/message_compress_filter.c new file mode 100644 index 000000000..20a348811 --- /dev/null +++ b/Sources/CgRPC/src/core/ext/filters/http/message_compress/message_compress_filter.c @@ -0,0 +1,482 @@ +/* + * + * 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 +#include + +#include +#include +#include +#include + +#include "src/core/ext/filters/http/message_compress/message_compress_filter.h" +#include "src/core/lib/channel/channel_args.h" +#include "src/core/lib/compression/algorithm_metadata.h" +#include "src/core/lib/compression/message_compress.h" +#include "src/core/lib/profiling/timers.h" +#include "src/core/lib/slice/slice_internal.h" +#include "src/core/lib/slice/slice_string_helpers.h" +#include "src/core/lib/support/string.h" +#include "src/core/lib/surface/call.h" +#include "src/core/lib/transport/static_metadata.h" + +#define INITIAL_METADATA_UNSEEN 0 +#define HAS_COMPRESSION_ALGORITHM 2 +#define NO_COMPRESSION_ALGORITHM 4 + +#define CANCELLED_BIT ((gpr_atm)1) + +typedef struct call_data { + grpc_slice_buffer slices; /**< Buffers up input slices to be compressed */ + grpc_linked_mdelem compression_algorithm_storage; + grpc_linked_mdelem accept_encoding_storage; + uint32_t remaining_slice_bytes; + /** Compression algorithm we'll try to use. It may be given by incoming + * metadata, or by the channel's default compression settings. */ + grpc_compression_algorithm compression_algorithm; + + /* Atomic recording the state of initial metadata; allowed values: + INITIAL_METADATA_UNSEEN - initial metadata op not seen + HAS_COMPRESSION_ALGORITHM - initial metadata seen; compression algorithm + set + NO_COMPRESSION_ALGORITHM - initial metadata seen; no compression algorithm + set + pointer - a stalled op containing a send_message that's waiting on initial + metadata + pointer | CANCELLED_BIT - request was cancelled with error pointed to */ + gpr_atm send_initial_metadata_state; + + grpc_transport_stream_op_batch *send_message_batch; + grpc_slice_buffer_stream replacement_stream; + grpc_closure *original_send_message_on_complete; + grpc_closure send_message_on_complete; + grpc_closure on_send_message_next_done; +} call_data; + +typedef struct channel_data { + /** The default, channel-level, compression algorithm */ + grpc_compression_algorithm default_compression_algorithm; + /** Bitset of enabled algorithms */ + uint32_t enabled_algorithms_bitset; + /** Supported compression algorithms */ + uint32_t supported_compression_algorithms; +} channel_data; + +static bool skip_compression(grpc_call_element *elem, uint32_t flags, + bool has_compression_algorithm) { + call_data *calld = elem->call_data; + channel_data *channeld = elem->channel_data; + + if (flags & (GRPC_WRITE_NO_COMPRESS | GRPC_WRITE_INTERNAL_COMPRESS)) { + return 1; + } + if (has_compression_algorithm) { + if (calld->compression_algorithm == GRPC_COMPRESS_NONE) { + return 1; + } + return 0; /* we have an actual call-specific algorithm */ + } + /* no per-call compression override */ + return channeld->default_compression_algorithm == GRPC_COMPRESS_NONE; +} + +/** Filter initial metadata */ +static grpc_error *process_send_initial_metadata( + grpc_exec_ctx *exec_ctx, grpc_call_element *elem, + grpc_metadata_batch *initial_metadata, + bool *has_compression_algorithm) GRPC_MUST_USE_RESULT; +static grpc_error *process_send_initial_metadata( + grpc_exec_ctx *exec_ctx, grpc_call_element *elem, + grpc_metadata_batch *initial_metadata, bool *has_compression_algorithm) { + call_data *calld = elem->call_data; + channel_data *channeld = elem->channel_data; + *has_compression_algorithm = false; + /* Parse incoming request for compression. If any, it'll be available + * at calld->compression_algorithm */ + if (initial_metadata->idx.named.grpc_internal_encoding_request != NULL) { + grpc_mdelem md = + initial_metadata->idx.named.grpc_internal_encoding_request->md; + if (!grpc_compression_algorithm_parse(GRPC_MDVALUE(md), + &calld->compression_algorithm)) { + char *val = grpc_slice_to_c_string(GRPC_MDVALUE(md)); + gpr_log(GPR_ERROR, + "Invalid compression algorithm: '%s' (unknown). Ignoring.", val); + gpr_free(val); + calld->compression_algorithm = GRPC_COMPRESS_NONE; + } + if (!GPR_BITGET(channeld->enabled_algorithms_bitset, + calld->compression_algorithm)) { + char *val = grpc_slice_to_c_string(GRPC_MDVALUE(md)); + gpr_log(GPR_ERROR, + "Invalid compression algorithm: '%s' (previously disabled). " + "Ignoring.", + val); + gpr_free(val); + calld->compression_algorithm = GRPC_COMPRESS_NONE; + } + *has_compression_algorithm = true; + + grpc_metadata_batch_remove( + exec_ctx, initial_metadata, + initial_metadata->idx.named.grpc_internal_encoding_request); + } else { + /* If no algorithm was found in the metadata and we aren't + * exceptionally skipping compression, fall back to the channel + * default */ + calld->compression_algorithm = channeld->default_compression_algorithm; + *has_compression_algorithm = true; + } + + grpc_error *error = GRPC_ERROR_NONE; + /* hint compression algorithm */ + if (calld->compression_algorithm != GRPC_COMPRESS_NONE) { + error = grpc_metadata_batch_add_tail( + exec_ctx, initial_metadata, &calld->compression_algorithm_storage, + grpc_compression_encoding_mdelem(calld->compression_algorithm)); + } + + if (error != GRPC_ERROR_NONE) return error; + + /* convey supported compression algorithms */ + error = grpc_metadata_batch_add_tail( + exec_ctx, initial_metadata, &calld->accept_encoding_storage, + GRPC_MDELEM_ACCEPT_ENCODING_FOR_ALGORITHMS( + channeld->supported_compression_algorithms)); + + return error; +} + +static void send_message_on_complete(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error) { + grpc_call_element *elem = (grpc_call_element *)arg; + call_data *calld = (call_data *)elem->call_data; + grpc_slice_buffer_reset_and_unref_internal(exec_ctx, &calld->slices); + GRPC_CLOSURE_RUN(exec_ctx, calld->original_send_message_on_complete, + GRPC_ERROR_REF(error)); +} + +static void finish_send_message(grpc_exec_ctx *exec_ctx, + grpc_call_element *elem) { + call_data *calld = (call_data *)elem->call_data; + // Compress the data if appropriate. + grpc_slice_buffer tmp; + grpc_slice_buffer_init(&tmp); + uint32_t send_flags = + calld->send_message_batch->payload->send_message.send_message->flags; + const bool did_compress = grpc_msg_compress( + exec_ctx, calld->compression_algorithm, &calld->slices, &tmp); + if (did_compress) { + if (GRPC_TRACER_ON(grpc_compression_trace)) { + char *algo_name; + const size_t before_size = calld->slices.length; + const size_t after_size = tmp.length; + const float savings_ratio = 1.0f - (float)after_size / (float)before_size; + GPR_ASSERT(grpc_compression_algorithm_name(calld->compression_algorithm, + &algo_name)); + gpr_log(GPR_DEBUG, "Compressed[%s] %" PRIuPTR " bytes vs. %" PRIuPTR + " bytes (%.2f%% savings)", + algo_name, before_size, after_size, 100 * savings_ratio); + } + grpc_slice_buffer_swap(&calld->slices, &tmp); + send_flags |= GRPC_WRITE_INTERNAL_COMPRESS; + } else { + if (GRPC_TRACER_ON(grpc_compression_trace)) { + char *algo_name; + GPR_ASSERT(grpc_compression_algorithm_name(calld->compression_algorithm, + &algo_name)); + gpr_log(GPR_DEBUG, + "Algorithm '%s' enabled but decided not to compress. Input size: " + "%" PRIuPTR, + algo_name, calld->slices.length); + } + } + grpc_slice_buffer_destroy_internal(exec_ctx, &tmp); + // Swap out the original byte stream with our new one and send the + // batch down. + grpc_byte_stream_destroy( + exec_ctx, calld->send_message_batch->payload->send_message.send_message); + grpc_slice_buffer_stream_init(&calld->replacement_stream, &calld->slices, + send_flags); + calld->send_message_batch->payload->send_message.send_message = + &calld->replacement_stream.base; + calld->original_send_message_on_complete = + calld->send_message_batch->on_complete; + calld->send_message_batch->on_complete = &calld->send_message_on_complete; + grpc_call_next_op(exec_ctx, elem, calld->send_message_batch); +} + +// Pulls a slice from the send_message byte stream and adds it to calld->slices. +static grpc_error *pull_slice_from_send_message(grpc_exec_ctx *exec_ctx, + call_data *calld) { + grpc_slice incoming_slice; + grpc_error *error = grpc_byte_stream_pull( + exec_ctx, calld->send_message_batch->payload->send_message.send_message, + &incoming_slice); + if (error == GRPC_ERROR_NONE) { + grpc_slice_buffer_add(&calld->slices, incoming_slice); + } + return error; +} + +// Reads as many slices as possible from the send_message byte stream. +// If all data has been read, invokes finish_send_message(). Otherwise, +// an async call to grpc_byte_stream_next() has been started, which will +// eventually result in calling on_send_message_next_done(). +static grpc_error *continue_reading_send_message(grpc_exec_ctx *exec_ctx, + grpc_call_element *elem) { + call_data *calld = (call_data *)elem->call_data; + while (grpc_byte_stream_next( + exec_ctx, calld->send_message_batch->payload->send_message.send_message, + ~(size_t)0, &calld->on_send_message_next_done)) { + grpc_error *error = pull_slice_from_send_message(exec_ctx, calld); + if (error != GRPC_ERROR_NONE) return error; + if (calld->slices.length == + calld->send_message_batch->payload->send_message.send_message->length) { + finish_send_message(exec_ctx, elem); + break; + } + } + return GRPC_ERROR_NONE; +} + +// Async callback for grpc_byte_stream_next(). +static void on_send_message_next_done(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error) { + grpc_call_element *elem = (grpc_call_element *)arg; + call_data *calld = (call_data *)elem->call_data; + if (error != GRPC_ERROR_NONE) goto fail; + error = pull_slice_from_send_message(exec_ctx, calld); + if (error != GRPC_ERROR_NONE) goto fail; + if (calld->slices.length == + calld->send_message_batch->payload->send_message.send_message->length) { + finish_send_message(exec_ctx, elem); + } else { + // This will either finish reading all of the data and invoke + // finish_send_message(), or else it will make an async call to + // grpc_byte_stream_next(), which will eventually result in calling + // this function again. + error = continue_reading_send_message(exec_ctx, elem); + if (error != GRPC_ERROR_NONE) goto fail; + } + return; +fail: + grpc_transport_stream_op_batch_finish_with_failure( + exec_ctx, calld->send_message_batch, error); +} + +static void start_send_message_batch(grpc_exec_ctx *exec_ctx, + grpc_call_element *elem, + grpc_transport_stream_op_batch *batch, + bool has_compression_algorithm) { + call_data *calld = (call_data *)elem->call_data; + if (!skip_compression(elem, batch->payload->send_message.send_message->flags, + has_compression_algorithm)) { + calld->send_message_batch = batch; + // This will either finish reading all of the data and invoke + // finish_send_message(), or else it will make an async call to + // grpc_byte_stream_next(), which will eventually result in calling + // on_send_message_next_done(). + grpc_error *error = continue_reading_send_message(exec_ctx, elem); + if (error != GRPC_ERROR_NONE) { + grpc_transport_stream_op_batch_finish_with_failure( + exec_ctx, calld->send_message_batch, error); + } + } else { + /* pass control down the stack */ + grpc_call_next_op(exec_ctx, elem, batch); + } +} + +static void compress_start_transport_stream_op_batch( + grpc_exec_ctx *exec_ctx, grpc_call_element *elem, + grpc_transport_stream_op_batch *batch) { + call_data *calld = elem->call_data; + + GPR_TIMER_BEGIN("compress_start_transport_stream_op_batch", 0); + + if (batch->cancel_stream) { + // TODO(roth): As part of the upcoming call combiner work, change + // this to call grpc_byte_stream_shutdown() on the incoming byte + // stream, to cancel any in-flight calls to grpc_byte_stream_next(). + GRPC_ERROR_REF(batch->payload->cancel_stream.cancel_error); + gpr_atm cur = gpr_atm_full_xchg( + &calld->send_initial_metadata_state, + CANCELLED_BIT | (gpr_atm)batch->payload->cancel_stream.cancel_error); + switch (cur) { + case HAS_COMPRESSION_ALGORITHM: + case NO_COMPRESSION_ALGORITHM: + case INITIAL_METADATA_UNSEEN: + break; + default: + if ((cur & CANCELLED_BIT) == 0) { + grpc_transport_stream_op_batch_finish_with_failure( + exec_ctx, (grpc_transport_stream_op_batch *)cur, + GRPC_ERROR_REF(batch->payload->cancel_stream.cancel_error)); + } else { + GRPC_ERROR_UNREF((grpc_error *)(cur & ~CANCELLED_BIT)); + } + break; + } + } + + if (batch->send_initial_metadata) { + bool has_compression_algorithm; + grpc_error *error = process_send_initial_metadata( + exec_ctx, elem, + batch->payload->send_initial_metadata.send_initial_metadata, + &has_compression_algorithm); + if (error != GRPC_ERROR_NONE) { + grpc_transport_stream_op_batch_finish_with_failure(exec_ctx, batch, + error); + return; + } + gpr_atm cur; + retry_send_im: + cur = gpr_atm_acq_load(&calld->send_initial_metadata_state); + GPR_ASSERT(cur != HAS_COMPRESSION_ALGORITHM && + cur != NO_COMPRESSION_ALGORITHM); + if ((cur & CANCELLED_BIT) == 0) { + if (!gpr_atm_rel_cas(&calld->send_initial_metadata_state, cur, + has_compression_algorithm + ? HAS_COMPRESSION_ALGORITHM + : NO_COMPRESSION_ALGORITHM)) { + goto retry_send_im; + } + if (cur != INITIAL_METADATA_UNSEEN) { + start_send_message_batch(exec_ctx, elem, + (grpc_transport_stream_op_batch *)cur, + has_compression_algorithm); + } + } + } + if (batch->send_message) { + gpr_atm cur; + retry_send: + cur = gpr_atm_acq_load(&calld->send_initial_metadata_state); + switch (cur) { + case INITIAL_METADATA_UNSEEN: + if (!gpr_atm_rel_cas(&calld->send_initial_metadata_state, cur, + (gpr_atm)batch)) { + goto retry_send; + } + break; + case HAS_COMPRESSION_ALGORITHM: + case NO_COMPRESSION_ALGORITHM: + start_send_message_batch(exec_ctx, elem, batch, + cur == HAS_COMPRESSION_ALGORITHM); + break; + default: + if (cur & CANCELLED_BIT) { + grpc_transport_stream_op_batch_finish_with_failure( + exec_ctx, batch, + GRPC_ERROR_REF((grpc_error *)(cur & ~CANCELLED_BIT))); + } else { + /* >1 send_message concurrently */ + GPR_UNREACHABLE_CODE(break); + } + } + } else { + /* pass control down the stack */ + grpc_call_next_op(exec_ctx, elem, batch); + } + + GPR_TIMER_END("compress_start_transport_stream_op_batch", 0); +} + +/* Constructor for call_data */ +static grpc_error *init_call_elem(grpc_exec_ctx *exec_ctx, + grpc_call_element *elem, + const grpc_call_element_args *args) { + /* grab pointers to our data from the call element */ + call_data *calld = elem->call_data; + + /* initialize members */ + grpc_slice_buffer_init(&calld->slices); + GRPC_CLOSURE_INIT(&calld->on_send_message_next_done, + on_send_message_next_done, elem, grpc_schedule_on_exec_ctx); + GRPC_CLOSURE_INIT(&calld->send_message_on_complete, send_message_on_complete, + elem, grpc_schedule_on_exec_ctx); + + return GRPC_ERROR_NONE; +} + +/* Destructor for call_data */ +static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, + const grpc_call_final_info *final_info, + grpc_closure *ignored) { + /* grab pointers to our data from the call element */ + call_data *calld = elem->call_data; + grpc_slice_buffer_destroy_internal(exec_ctx, &calld->slices); + gpr_atm imstate = + gpr_atm_no_barrier_load(&calld->send_initial_metadata_state); + if (imstate & CANCELLED_BIT) { + GRPC_ERROR_UNREF((grpc_error *)(imstate & ~CANCELLED_BIT)); + } +} + +/* Constructor for channel_data */ +static grpc_error *init_channel_elem(grpc_exec_ctx *exec_ctx, + grpc_channel_element *elem, + grpc_channel_element_args *args) { + channel_data *channeld = elem->channel_data; + + channeld->enabled_algorithms_bitset = + grpc_channel_args_compression_algorithm_get_states(args->channel_args); + + channeld->default_compression_algorithm = + grpc_channel_args_get_compression_algorithm(args->channel_args); + /* Make sure the default isn't disabled. */ + if (!GPR_BITGET(channeld->enabled_algorithms_bitset, + channeld->default_compression_algorithm)) { + gpr_log(GPR_DEBUG, + "compression algorithm %d not enabled: switching to none", + channeld->default_compression_algorithm); + channeld->default_compression_algorithm = GRPC_COMPRESS_NONE; + } + + channeld->supported_compression_algorithms = 1; /* always support identity */ + for (grpc_compression_algorithm algo_idx = 1; + algo_idx < GRPC_COMPRESS_ALGORITHMS_COUNT; ++algo_idx) { + /* skip disabled algorithms */ + if (!GPR_BITGET(channeld->enabled_algorithms_bitset, algo_idx)) { + continue; + } + channeld->supported_compression_algorithms |= 1u << algo_idx; + } + + GPR_ASSERT(!args->is_last); + return GRPC_ERROR_NONE; +} + +/* Destructor for channel data */ +static void destroy_channel_elem(grpc_exec_ctx *exec_ctx, + grpc_channel_element *elem) {} + +const grpc_channel_filter grpc_message_compress_filter = { + compress_start_transport_stream_op_batch, + grpc_channel_next_op, + sizeof(call_data), + init_call_elem, + grpc_call_stack_ignore_set_pollset_or_pollset_set, + destroy_call_elem, + sizeof(channel_data), + init_channel_elem, + destroy_channel_elem, + grpc_call_next_get_peer, + grpc_channel_next_get_info, + "compress"}; diff --git a/Sources/CgRPC/src/core/ext/filters/http/message_compress/message_compress_filter.h b/Sources/CgRPC/src/core/ext/filters/http/message_compress/message_compress_filter.h new file mode 100644 index 000000000..c121a391e --- /dev/null +++ b/Sources/CgRPC/src/core/ext/filters/http/message_compress/message_compress_filter.h @@ -0,0 +1,51 @@ +/* + * + * 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 GRPC_CORE_EXT_FILTERS_HTTP_MESSAGE_COMPRESS_MESSAGE_COMPRESS_FILTER_H +#define GRPC_CORE_EXT_FILTERS_HTTP_MESSAGE_COMPRESS_MESSAGE_COMPRESS_FILTER_H + +#include + +#include "src/core/lib/channel/channel_stack.h" + +/** Compression filter for outgoing data. + * + * See for the available compression settings. + * + * Compression settings may come from: + * - Channel configuration, as established at channel creation time. + * - The metadata accompanying the outgoing data to be compressed. This is + * taken as a request only. We may choose not to honor it. The metadata key + * is given by \a GRPC_COMPRESSION_REQUEST_ALGORITHM_MD_KEY. + * + * Compression can be disabled for concrete messages (for instance in order to + * prevent CRIME/BEAST type attacks) by having the GRPC_WRITE_NO_COMPRESS set in + * the BEGIN_MESSAGE flags. + * + * The attempted compression mechanism is added to the resulting initial + * metadata under the'grpc-encoding' key. + * + * If compression is actually performed, BEGIN_MESSAGE's flag is modified to + * incorporate GRPC_WRITE_INTERNAL_COMPRESS. Otherwise, and regardless of the + * aforementioned 'grpc-encoding' metadata value, data will pass through + * uncompressed. */ + +extern const grpc_channel_filter grpc_message_compress_filter; + +#endif /* GRPC_CORE_EXT_FILTERS_HTTP_MESSAGE_COMPRESS_MESSAGE_COMPRESS_FILTER_H \ + */ diff --git a/Sources/CgRPC/src/core/ext/filters/http/server/http_server_filter.c b/Sources/CgRPC/src/core/ext/filters/http/server/http_server_filter.c new file mode 100644 index 000000000..b145f12af --- /dev/null +++ b/Sources/CgRPC/src/core/ext/filters/http/server/http_server_filter.c @@ -0,0 +1,428 @@ +/* + * + * 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 "src/core/ext/filters/http/server/http_server_filter.h" + +#include +#include +#include +#include "src/core/lib/profiling/timers.h" +#include "src/core/lib/slice/b64.h" +#include "src/core/lib/slice/percent_encoding.h" +#include "src/core/lib/slice/slice_internal.h" +#include "src/core/lib/slice/slice_string_helpers.h" +#include "src/core/lib/transport/static_metadata.h" + +#define EXPECTED_CONTENT_TYPE "application/grpc" +#define EXPECTED_CONTENT_TYPE_LENGTH sizeof(EXPECTED_CONTENT_TYPE) - 1 + +typedef struct call_data { + grpc_linked_mdelem status; + grpc_linked_mdelem content_type; + + /* did this request come with path query containing request payload */ + bool seen_path_with_query; + /* flag to ensure payload_bin is delivered only once */ + bool payload_bin_delivered; + + grpc_metadata_batch *recv_initial_metadata; + uint32_t *recv_initial_metadata_flags; + /** Closure to call when finished with the hs_on_recv hook */ + grpc_closure *on_done_recv; + /** Closure to call when we retrieve read message from the path URI + */ + grpc_closure *recv_message_ready; + grpc_closure *on_complete; + grpc_byte_stream **pp_recv_message; + grpc_slice_buffer read_slice_buffer; + grpc_slice_buffer_stream read_stream; + + /** Receive closures are chained: we inject this closure as the on_done_recv + up-call on transport_op, and remember to call our on_done_recv member + after handling it. */ + grpc_closure hs_on_recv; + grpc_closure hs_on_complete; + grpc_closure hs_recv_message_ready; +} call_data; + +typedef struct channel_data { uint8_t unused; } channel_data; + +static grpc_error *server_filter_outgoing_metadata(grpc_exec_ctx *exec_ctx, + grpc_call_element *elem, + grpc_metadata_batch *b) { + if (b->idx.named.grpc_message != NULL) { + grpc_slice pct_encoded_msg = grpc_percent_encode_slice( + GRPC_MDVALUE(b->idx.named.grpc_message->md), + grpc_compatible_percent_encoding_unreserved_bytes); + if (grpc_slice_is_equivalent(pct_encoded_msg, + GRPC_MDVALUE(b->idx.named.grpc_message->md))) { + grpc_slice_unref_internal(exec_ctx, pct_encoded_msg); + } else { + grpc_metadata_batch_set_value(exec_ctx, b->idx.named.grpc_message, + pct_encoded_msg); + } + } + return GRPC_ERROR_NONE; +} + +static void add_error(const char *error_name, grpc_error **cumulative, + grpc_error *new) { + if (new == GRPC_ERROR_NONE) return; + if (*cumulative == GRPC_ERROR_NONE) { + *cumulative = GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_name); + } + *cumulative = grpc_error_add_child(*cumulative, new); +} + +static grpc_error *server_filter_incoming_metadata(grpc_exec_ctx *exec_ctx, + grpc_call_element *elem, + grpc_metadata_batch *b) { + call_data *calld = elem->call_data; + grpc_error *error = GRPC_ERROR_NONE; + static const char *error_name = "Failed processing incoming headers"; + + if (b->idx.named.method != NULL) { + if (grpc_mdelem_eq(b->idx.named.method->md, GRPC_MDELEM_METHOD_POST)) { + *calld->recv_initial_metadata_flags &= + ~(GRPC_INITIAL_METADATA_CACHEABLE_REQUEST | + GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST); + } else if (grpc_mdelem_eq(b->idx.named.method->md, + GRPC_MDELEM_METHOD_PUT)) { + *calld->recv_initial_metadata_flags &= + ~GRPC_INITIAL_METADATA_CACHEABLE_REQUEST; + *calld->recv_initial_metadata_flags |= + GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST; + } else if (grpc_mdelem_eq(b->idx.named.method->md, + GRPC_MDELEM_METHOD_GET)) { + *calld->recv_initial_metadata_flags |= + GRPC_INITIAL_METADATA_CACHEABLE_REQUEST; + *calld->recv_initial_metadata_flags &= + ~GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST; + } else { + add_error(error_name, &error, + grpc_attach_md_to_error( + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Bad header"), + b->idx.named.method->md)); + } + grpc_metadata_batch_remove(exec_ctx, b, b->idx.named.method); + } else { + add_error( + error_name, &error, + grpc_error_set_str( + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Missing header"), + GRPC_ERROR_STR_KEY, grpc_slice_from_static_string(":method"))); + } + + if (b->idx.named.te != NULL) { + if (!grpc_mdelem_eq(b->idx.named.te->md, GRPC_MDELEM_TE_TRAILERS)) { + add_error(error_name, &error, + grpc_attach_md_to_error( + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Bad header"), + b->idx.named.te->md)); + } + grpc_metadata_batch_remove(exec_ctx, b, b->idx.named.te); + } else { + add_error(error_name, &error, + grpc_error_set_str( + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Missing header"), + GRPC_ERROR_STR_KEY, grpc_slice_from_static_string("te"))); + } + + if (b->idx.named.scheme != NULL) { + if (!grpc_mdelem_eq(b->idx.named.scheme->md, GRPC_MDELEM_SCHEME_HTTP) && + !grpc_mdelem_eq(b->idx.named.scheme->md, GRPC_MDELEM_SCHEME_HTTPS) && + !grpc_mdelem_eq(b->idx.named.scheme->md, GRPC_MDELEM_SCHEME_GRPC)) { + add_error(error_name, &error, + grpc_attach_md_to_error( + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Bad header"), + b->idx.named.scheme->md)); + } + grpc_metadata_batch_remove(exec_ctx, b, b->idx.named.scheme); + } else { + add_error( + error_name, &error, + grpc_error_set_str( + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Missing header"), + GRPC_ERROR_STR_KEY, grpc_slice_from_static_string(":scheme"))); + } + + if (b->idx.named.content_type != NULL) { + if (!grpc_mdelem_eq(b->idx.named.content_type->md, + GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC)) { + if (grpc_slice_buf_start_eq(GRPC_MDVALUE(b->idx.named.content_type->md), + EXPECTED_CONTENT_TYPE, + EXPECTED_CONTENT_TYPE_LENGTH) && + (GRPC_SLICE_START_PTR(GRPC_MDVALUE( + b->idx.named.content_type->md))[EXPECTED_CONTENT_TYPE_LENGTH] == + '+' || + GRPC_SLICE_START_PTR(GRPC_MDVALUE( + b->idx.named.content_type->md))[EXPECTED_CONTENT_TYPE_LENGTH] == + ';')) { + /* Although the C implementation doesn't (currently) generate them, + any custom +-suffix is explicitly valid. */ + /* TODO(klempner): We should consider preallocating common values such + as +proto or +json, or at least stashing them if we see them. */ + /* TODO(klempner): Should we be surfacing this to application code? */ + } else { + /* TODO(klempner): We're currently allowing this, but we shouldn't + see it without a proxy so log for now. */ + char *val = grpc_dump_slice(GRPC_MDVALUE(b->idx.named.content_type->md), + GPR_DUMP_ASCII); + gpr_log(GPR_INFO, "Unexpected content-type '%s'", val); + gpr_free(val); + } + } + grpc_metadata_batch_remove(exec_ctx, b, b->idx.named.content_type); + } + + if (b->idx.named.path == NULL) { + add_error(error_name, &error, + grpc_error_set_str( + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Missing header"), + GRPC_ERROR_STR_KEY, grpc_slice_from_static_string(":path"))); + } else if (*calld->recv_initial_metadata_flags & + GRPC_INITIAL_METADATA_CACHEABLE_REQUEST) { + /* We have a cacheable request made with GET verb. The path contains the + * query parameter which is base64 encoded request payload. */ + const char k_query_separator = '?'; + grpc_slice path_slice = GRPC_MDVALUE(b->idx.named.path->md); + uint8_t *path_ptr = (uint8_t *)GRPC_SLICE_START_PTR(path_slice); + size_t path_length = GRPC_SLICE_LENGTH(path_slice); + /* offset of the character '?' */ + size_t offset = 0; + for (offset = 0; offset < path_length && *path_ptr != k_query_separator; + path_ptr++, offset++) + ; + if (offset < path_length) { + grpc_slice query_slice = + grpc_slice_sub(path_slice, offset + 1, path_length); + + /* substitute path metadata with just the path (not query) */ + grpc_mdelem mdelem_path_without_query = grpc_mdelem_from_slices( + exec_ctx, GRPC_MDSTR_PATH, grpc_slice_sub(path_slice, 0, offset)); + + grpc_metadata_batch_substitute(exec_ctx, b, b->idx.named.path, + mdelem_path_without_query); + + /* decode payload from query and add to the slice buffer to be returned */ + const int k_url_safe = 1; + grpc_slice_buffer_add( + &calld->read_slice_buffer, + grpc_base64_decode_with_len( + exec_ctx, (const char *)GRPC_SLICE_START_PTR(query_slice), + GRPC_SLICE_LENGTH(query_slice), k_url_safe)); + grpc_slice_buffer_stream_init(&calld->read_stream, + &calld->read_slice_buffer, 0); + calld->seen_path_with_query = true; + grpc_slice_unref_internal(exec_ctx, query_slice); + } else { + gpr_log(GPR_ERROR, "GET request without QUERY"); + } + } + + if (b->idx.named.host != NULL && b->idx.named.authority == NULL) { + grpc_linked_mdelem *el = b->idx.named.host; + grpc_mdelem md = GRPC_MDELEM_REF(el->md); + grpc_metadata_batch_remove(exec_ctx, b, el); + add_error( + error_name, &error, + grpc_metadata_batch_add_head( + exec_ctx, b, el, grpc_mdelem_from_slices( + exec_ctx, GRPC_MDSTR_AUTHORITY, + grpc_slice_ref_internal(GRPC_MDVALUE(md))))); + GRPC_MDELEM_UNREF(exec_ctx, md); + } + + if (b->idx.named.authority == NULL) { + add_error( + error_name, &error, + grpc_error_set_str( + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Missing header"), + GRPC_ERROR_STR_KEY, grpc_slice_from_static_string(":authority"))); + } + + return error; +} + +static void hs_on_recv(grpc_exec_ctx *exec_ctx, void *user_data, + grpc_error *err) { + grpc_call_element *elem = user_data; + call_data *calld = elem->call_data; + if (err == GRPC_ERROR_NONE) { + err = server_filter_incoming_metadata(exec_ctx, elem, + calld->recv_initial_metadata); + } else { + GRPC_ERROR_REF(err); + } + GRPC_CLOSURE_RUN(exec_ctx, calld->on_done_recv, err); +} + +static void hs_on_complete(grpc_exec_ctx *exec_ctx, void *user_data, + grpc_error *err) { + grpc_call_element *elem = user_data; + call_data *calld = elem->call_data; + /* Call recv_message_ready if we got the payload via the path field */ + if (calld->seen_path_with_query && calld->recv_message_ready != NULL) { + *calld->pp_recv_message = calld->payload_bin_delivered + ? NULL + : (grpc_byte_stream *)&calld->read_stream; + GRPC_CLOSURE_RUN(exec_ctx, calld->recv_message_ready, GRPC_ERROR_REF(err)); + calld->recv_message_ready = NULL; + calld->payload_bin_delivered = true; + } + GRPC_CLOSURE_RUN(exec_ctx, calld->on_complete, GRPC_ERROR_REF(err)); +} + +static void hs_recv_message_ready(grpc_exec_ctx *exec_ctx, void *user_data, + grpc_error *err) { + grpc_call_element *elem = user_data; + call_data *calld = elem->call_data; + if (calld->seen_path_with_query) { + /* do nothing. This is probably a GET request, and payload will be returned + in hs_on_complete callback. */ + } else { + GRPC_CLOSURE_RUN(exec_ctx, calld->recv_message_ready, GRPC_ERROR_REF(err)); + } +} + +static void hs_mutate_op(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, + grpc_transport_stream_op_batch *op) { + /* grab pointers to our data from the call element */ + call_data *calld = elem->call_data; + + if (op->send_initial_metadata) { + grpc_error *error = GRPC_ERROR_NONE; + static const char *error_name = "Failed sending initial metadata"; + add_error( + error_name, &error, + grpc_metadata_batch_add_head( + exec_ctx, op->payload->send_initial_metadata.send_initial_metadata, + &calld->status, GRPC_MDELEM_STATUS_200)); + add_error( + error_name, &error, + grpc_metadata_batch_add_tail( + exec_ctx, op->payload->send_initial_metadata.send_initial_metadata, + &calld->content_type, + GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC)); + add_error(error_name, &error, + server_filter_outgoing_metadata( + exec_ctx, elem, + op->payload->send_initial_metadata.send_initial_metadata)); + if (error != GRPC_ERROR_NONE) { + grpc_transport_stream_op_batch_finish_with_failure(exec_ctx, op, error); + return; + } + } + + if (op->recv_initial_metadata) { + /* substitute our callback for the higher callback */ + GPR_ASSERT(op->payload->recv_initial_metadata.recv_flags != NULL); + calld->recv_initial_metadata = + op->payload->recv_initial_metadata.recv_initial_metadata; + calld->recv_initial_metadata_flags = + op->payload->recv_initial_metadata.recv_flags; + calld->on_done_recv = + op->payload->recv_initial_metadata.recv_initial_metadata_ready; + op->payload->recv_initial_metadata.recv_initial_metadata_ready = + &calld->hs_on_recv; + } + + if (op->recv_message) { + calld->recv_message_ready = op->payload->recv_message.recv_message_ready; + calld->pp_recv_message = op->payload->recv_message.recv_message; + if (op->payload->recv_message.recv_message_ready) { + op->payload->recv_message.recv_message_ready = + &calld->hs_recv_message_ready; + } + if (op->on_complete) { + calld->on_complete = op->on_complete; + op->on_complete = &calld->hs_on_complete; + } + } + + if (op->send_trailing_metadata) { + grpc_error *error = server_filter_outgoing_metadata( + exec_ctx, elem, + op->payload->send_trailing_metadata.send_trailing_metadata); + if (error != GRPC_ERROR_NONE) { + grpc_transport_stream_op_batch_finish_with_failure(exec_ctx, op, error); + return; + } + } +} + +static void hs_start_transport_op(grpc_exec_ctx *exec_ctx, + grpc_call_element *elem, + grpc_transport_stream_op_batch *op) { + GRPC_CALL_LOG_OP(GPR_INFO, elem, op); + GPR_TIMER_BEGIN("hs_start_transport_op", 0); + hs_mutate_op(exec_ctx, elem, op); + grpc_call_next_op(exec_ctx, elem, op); + GPR_TIMER_END("hs_start_transport_op", 0); +} + +/* Constructor for call_data */ +static grpc_error *init_call_elem(grpc_exec_ctx *exec_ctx, + grpc_call_element *elem, + const grpc_call_element_args *args) { + /* grab pointers to our data from the call element */ + call_data *calld = elem->call_data; + /* initialize members */ + GRPC_CLOSURE_INIT(&calld->hs_on_recv, hs_on_recv, elem, + grpc_schedule_on_exec_ctx); + GRPC_CLOSURE_INIT(&calld->hs_on_complete, hs_on_complete, elem, + grpc_schedule_on_exec_ctx); + GRPC_CLOSURE_INIT(&calld->hs_recv_message_ready, hs_recv_message_ready, elem, + grpc_schedule_on_exec_ctx); + grpc_slice_buffer_init(&calld->read_slice_buffer); + return GRPC_ERROR_NONE; +} + +/* Destructor for call_data */ +static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, + const grpc_call_final_info *final_info, + grpc_closure *ignored) { + call_data *calld = elem->call_data; + grpc_slice_buffer_destroy_internal(exec_ctx, &calld->read_slice_buffer); +} + +/* Constructor for channel_data */ +static grpc_error *init_channel_elem(grpc_exec_ctx *exec_ctx, + grpc_channel_element *elem, + grpc_channel_element_args *args) { + GPR_ASSERT(!args->is_last); + return GRPC_ERROR_NONE; +} + +/* Destructor for channel data */ +static void destroy_channel_elem(grpc_exec_ctx *exec_ctx, + grpc_channel_element *elem) {} + +const grpc_channel_filter grpc_http_server_filter = { + hs_start_transport_op, + grpc_channel_next_op, + sizeof(call_data), + init_call_elem, + grpc_call_stack_ignore_set_pollset_or_pollset_set, + destroy_call_elem, + sizeof(channel_data), + init_channel_elem, + destroy_channel_elem, + grpc_call_next_get_peer, + grpc_channel_next_get_info, + "http-server"}; diff --git a/Sources/CgRPC/src/core/ext/filters/http/server/http_server_filter.h b/Sources/CgRPC/src/core/ext/filters/http/server/http_server_filter.h new file mode 100644 index 000000000..c0f678a32 --- /dev/null +++ b/Sources/CgRPC/src/core/ext/filters/http/server/http_server_filter.h @@ -0,0 +1,27 @@ +/* + * + * 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 GRPC_CORE_EXT_FILTERS_HTTP_SERVER_HTTP_SERVER_FILTER_H +#define GRPC_CORE_EXT_FILTERS_HTTP_SERVER_HTTP_SERVER_FILTER_H + +#include "src/core/lib/channel/channel_stack.h" + +/* Processes metadata on the client side for HTTP2 transports */ +extern const grpc_channel_filter grpc_http_server_filter; + +#endif /* GRPC_CORE_EXT_FILTERS_HTTP_SERVER_HTTP_SERVER_FILTER_H */ diff --git a/Sources/CgRPC/src/core/ext/filters/load_reporting/load_reporting.c b/Sources/CgRPC/src/core/ext/filters/load_reporting/load_reporting.c new file mode 100644 index 000000000..9745763c9 --- /dev/null +++ b/Sources/CgRPC/src/core/ext/filters/load_reporting/load_reporting.c @@ -0,0 +1,64 @@ +/* + * + * Copyright 2016 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 + +#include +#include + +#include +#include +#include + +#include "src/core/ext/filters/load_reporting/load_reporting.h" +#include "src/core/ext/filters/load_reporting/load_reporting_filter.h" +#include "src/core/lib/channel/channel_stack_builder.h" +#include "src/core/lib/slice/slice_internal.h" +#include "src/core/lib/surface/call.h" +#include "src/core/lib/surface/channel_init.h" + +static bool is_load_reporting_enabled(const grpc_channel_args *a) { + return grpc_channel_arg_get_bool( + grpc_channel_args_find(a, GRPC_ARG_ENABLE_LOAD_REPORTING), false); +} + +static bool maybe_add_load_reporting_filter(grpc_exec_ctx *exec_ctx, + grpc_channel_stack_builder *builder, + void *arg) { + const grpc_channel_args *args = + grpc_channel_stack_builder_get_channel_arguments(builder); + if (is_load_reporting_enabled(args)) { + return grpc_channel_stack_builder_prepend_filter( + builder, (const grpc_channel_filter *)arg, NULL, NULL); + } + return true; +} + +grpc_arg grpc_load_reporting_enable_arg() { + return grpc_channel_arg_integer_create(GRPC_ARG_ENABLE_LOAD_REPORTING, 1); +} + +/* Plugin registration */ + +void grpc_load_reporting_plugin_init(void) { + grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL, INT_MAX, + maybe_add_load_reporting_filter, + (void *)&grpc_load_reporting_filter); +} + +void grpc_load_reporting_plugin_shutdown() {} diff --git a/Sources/CgRPC/src/core/ext/filters/load_reporting/load_reporting.h b/Sources/CgRPC/src/core/ext/filters/load_reporting/load_reporting.h new file mode 100644 index 000000000..fc04d2826 --- /dev/null +++ b/Sources/CgRPC/src/core/ext/filters/load_reporting/load_reporting.h @@ -0,0 +1,58 @@ +/* + * + * Copyright 2016 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 GRPC_CORE_EXT_FILTERS_LOAD_REPORTING_LOAD_REPORTING_H +#define GRPC_CORE_EXT_FILTERS_LOAD_REPORTING_LOAD_REPORTING_H + +#include + +#include "src/core/lib/channel/channel_stack.h" + +/** Identifiers for the invocation point of the users LR callback */ +typedef enum grpc_load_reporting_source { + GRPC_LR_POINT_UNKNOWN = 0, + GRPC_LR_POINT_CHANNEL_CREATION, + GRPC_LR_POINT_CHANNEL_DESTRUCTION, + GRPC_LR_POINT_CALL_CREATION, + GRPC_LR_POINT_CALL_DESTRUCTION +} grpc_load_reporting_source; + +/** Call information to be passed to the provided LR callback. */ +typedef struct grpc_load_reporting_call_data { + const grpc_load_reporting_source source; /**< point of last data update. */ + + /** Unique identifier for the channel associated with the data */ + intptr_t channel_id; + + /** Unique identifier for the call associated with the data. If the call + * hasn't been created yet, it'll have a value of zero. */ + intptr_t call_id; + + /** Only valid when \a source is \a GRPC_LR_POINT_CALL_DESTRUCTION, that is, + * once the call has completed */ + const grpc_call_final_info *final_info; + + const char *initial_md_string; /**< value string for LR's initial md key */ + const char *trailing_md_string; /**< value string for LR's trailing md key */ + const char *method_name; /**< Corresponds to :path header */ +} grpc_load_reporting_call_data; + +/** Return a \a grpc_arg enabling load reporting */ +grpc_arg grpc_load_reporting_enable_arg(); + +#endif /* GRPC_CORE_EXT_FILTERS_LOAD_REPORTING_LOAD_REPORTING_H */ diff --git a/Sources/CgRPC/src/core/ext/load_reporting/load_reporting_filter.c b/Sources/CgRPC/src/core/ext/filters/load_reporting/load_reporting_filter.c similarity index 55% rename from Sources/CgRPC/src/core/ext/load_reporting/load_reporting_filter.c rename to Sources/CgRPC/src/core/ext/filters/load_reporting/load_reporting_filter.c index 18bb82694..08474efb2 100644 --- a/Sources/CgRPC/src/core/ext/load_reporting/load_reporting_filter.c +++ b/Sources/CgRPC/src/core/ext/filters/load_reporting/load_reporting_filter.c @@ -1,53 +1,44 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 + +#include #include #include #include #include -#include -#include "src/core/ext/load_reporting/load_reporting.h" -#include "src/core/ext/load_reporting/load_reporting_filter.h" +#include "src/core/ext/filters/load_reporting/load_reporting.h" +#include "src/core/ext/filters/load_reporting/load_reporting_filter.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/profiling/timers.h" +#include "src/core/lib/slice/slice_internal.h" #include "src/core/lib/transport/static_metadata.h" typedef struct call_data { intptr_t id; /**< an id unique to the call */ - char *trailing_md_string; - char *initial_md_string; - const char *service_method; + bool have_trailing_md_string; + grpc_slice trailing_md_string; + bool have_initial_md_string; + grpc_slice initial_md_string; + bool have_service_method; + grpc_slice service_method; /* stores the recv_initial_metadata op's ready closure, which we wrap with our * own (on_initial_md_ready) in order to capture the incoming initial metadata @@ -63,40 +54,27 @@ typedef struct channel_data { intptr_t id; /**< an id unique to the channel */ } channel_data; -typedef struct { - grpc_call_element *elem; - grpc_exec_ctx *exec_ctx; -} recv_md_filter_args; - -static grpc_mdelem *recv_md_filter(void *user_data, grpc_mdelem *md) { - recv_md_filter_args *a = user_data; - grpc_call_element *elem = a->elem; - call_data *calld = elem->call_data; - - if (md->key == GRPC_MDSTR_PATH) { - calld->service_method = grpc_mdstr_as_c_string(md->value); - } else if (md->key == GRPC_MDSTR_LB_TOKEN) { - calld->initial_md_string = gpr_strdup(grpc_mdstr_as_c_string(md->value)); - return NULL; - } - - return md; -} - static void on_initial_md_ready(grpc_exec_ctx *exec_ctx, void *user_data, grpc_error *err) { grpc_call_element *elem = user_data; call_data *calld = elem->call_data; if (err == GRPC_ERROR_NONE) { - recv_md_filter_args a; - a.elem = elem; - a.exec_ctx = exec_ctx; - grpc_metadata_batch_filter(calld->recv_initial_metadata, recv_md_filter, - &a); - if (calld->service_method == NULL) { - err = - grpc_error_add_child(err, GRPC_ERROR_CREATE("Missing :path header")); + if (calld->recv_initial_metadata->idx.named.path != NULL) { + calld->service_method = grpc_slice_ref_internal( + GRPC_MDVALUE(calld->recv_initial_metadata->idx.named.path->md)); + calld->have_service_method = true; + } else { + err = grpc_error_add_child( + err, GRPC_ERROR_CREATE_FROM_STATIC_STRING("Missing :path header")); + } + if (calld->recv_initial_metadata->idx.named.lb_token != NULL) { + calld->initial_md_string = grpc_slice_ref_internal( + GRPC_MDVALUE(calld->recv_initial_metadata->idx.named.lb_token->md)); + calld->have_initial_md_string = true; + grpc_metadata_batch_remove( + exec_ctx, calld->recv_initial_metadata, + calld->recv_initial_metadata->idx.named.lb_token); } } else { GRPC_ERROR_REF(err); @@ -109,12 +87,11 @@ static void on_initial_md_ready(grpc_exec_ctx *exec_ctx, void *user_data, /* Constructor for call_data */ static grpc_error *init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, - grpc_call_element_args *args) { + const grpc_call_element_args *args) { call_data *calld = elem->call_data; - memset(calld, 0, sizeof(call_data)); - calld->id = (intptr_t)args->call_stack; - grpc_closure_init(&calld->on_initial_md_ready, on_initial_md_ready, elem); + GRPC_CLOSURE_INIT(&calld->on_initial_md_ready, on_initial_md_ready, elem, + grpc_schedule_on_exec_ctx); /* TODO(dgq): do something with the data channel_data *chand = elem->channel_data; @@ -133,7 +110,7 @@ static grpc_error *init_call_elem(grpc_exec_ctx *exec_ctx, /* Destructor for call_data */ static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, const grpc_call_final_info *final_info, - void *ignored) { + grpc_closure *ignored) { call_data *calld = elem->call_data; /* TODO(dgq): do something with the data @@ -147,8 +124,15 @@ static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, calld->service_method}; */ - gpr_free(calld->initial_md_string); - gpr_free(calld->trailing_md_string); + if (calld->have_initial_md_string) { + grpc_slice_unref_internal(exec_ctx, calld->initial_md_string); + } + if (calld->have_trailing_md_string) { + grpc_slice_unref_internal(exec_ctx, calld->trailing_md_string); + } + if (calld->have_service_method) { + grpc_slice_unref_internal(exec_ctx, calld->service_method); + } } /* Constructor for channel_data */ @@ -158,8 +142,6 @@ static grpc_error *init_channel_elem(grpc_exec_ctx *exec_ctx, GPR_ASSERT(!args->is_last); channel_data *chand = elem->channel_data; - memset(chand, 0, sizeof(channel_data)); - chand->id = (intptr_t)args->channel_stack; /* TODO(dgq): do something with the data @@ -191,40 +173,48 @@ static void destroy_channel_elem(grpc_exec_ctx *exec_ctx, */ } -static grpc_mdelem *lr_trailing_md_filter(void *user_data, grpc_mdelem *md) { +static grpc_filtered_mdelem lr_trailing_md_filter(grpc_exec_ctx *exec_ctx, + void *user_data, + grpc_mdelem md) { grpc_call_element *elem = user_data; call_data *calld = elem->call_data; - - if (md->key == GRPC_MDSTR_LB_COST_BIN) { - calld->trailing_md_string = gpr_strdup(grpc_mdstr_as_c_string(md->value)); - return NULL; + if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_LB_COST_BIN)) { + calld->trailing_md_string = GRPC_MDVALUE(md); + return GRPC_FILTERED_REMOVE(); } - - return md; + return GRPC_FILTERED_MDELEM(md); } -static void lr_start_transport_stream_op(grpc_exec_ctx *exec_ctx, - grpc_call_element *elem, - grpc_transport_stream_op *op) { - GPR_TIMER_BEGIN("lr_start_transport_stream_op", 0); +static void lr_start_transport_stream_op_batch( + grpc_exec_ctx *exec_ctx, grpc_call_element *elem, + grpc_transport_stream_op_batch *op) { + GPR_TIMER_BEGIN("lr_start_transport_stream_op_batch", 0); call_data *calld = elem->call_data; if (op->recv_initial_metadata) { - calld->recv_initial_metadata = op->recv_initial_metadata; /* substitute our callback for the higher callback */ - calld->ops_recv_initial_metadata_ready = op->recv_initial_metadata_ready; - op->recv_initial_metadata_ready = &calld->on_initial_md_ready; + calld->recv_initial_metadata = + op->payload->recv_initial_metadata.recv_initial_metadata; + calld->ops_recv_initial_metadata_ready = + op->payload->recv_initial_metadata.recv_initial_metadata_ready; + op->payload->recv_initial_metadata.recv_initial_metadata_ready = + &calld->on_initial_md_ready; } else if (op->send_trailing_metadata) { - grpc_metadata_batch_filter(op->send_trailing_metadata, - lr_trailing_md_filter, elem); + GRPC_LOG_IF_ERROR( + "grpc_metadata_batch_filter", + grpc_metadata_batch_filter( + exec_ctx, + op->payload->send_trailing_metadata.send_trailing_metadata, + lr_trailing_md_filter, elem, + "LR trailing metadata filtering error")); } grpc_call_next_op(exec_ctx, elem, op); - GPR_TIMER_END("lr_start_transport_stream_op", 0); + GPR_TIMER_END("lr_start_transport_stream_op_batch", 0); } const grpc_channel_filter grpc_load_reporting_filter = { - lr_start_transport_stream_op, + lr_start_transport_stream_op_batch, grpc_channel_next_op, sizeof(call_data), init_call_elem, diff --git a/Sources/CgRPC/src/core/ext/filters/load_reporting/load_reporting_filter.h b/Sources/CgRPC/src/core/ext/filters/load_reporting/load_reporting_filter.h new file mode 100644 index 000000000..1a5424e43 --- /dev/null +++ b/Sources/CgRPC/src/core/ext/filters/load_reporting/load_reporting_filter.h @@ -0,0 +1,27 @@ +/* + * + * Copyright 2016 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 GRPC_CORE_EXT_FILTERS_LOAD_REPORTING_LOAD_REPORTING_FILTER_H +#define GRPC_CORE_EXT_FILTERS_LOAD_REPORTING_LOAD_REPORTING_FILTER_H + +#include "src/core/ext/filters/load_reporting/load_reporting.h" +#include "src/core/lib/channel/channel_stack.h" + +extern const grpc_channel_filter grpc_load_reporting_filter; + +#endif /* GRPC_CORE_EXT_FILTERS_LOAD_REPORTING_LOAD_REPORTING_FILTER_H */ diff --git a/Sources/CgRPC/src/core/ext/filters/max_age/max_age_filter.c b/Sources/CgRPC/src/core/ext/filters/max_age/max_age_filter.c new file mode 100644 index 000000000..7d748b9c3 --- /dev/null +++ b/Sources/CgRPC/src/core/ext/filters/max_age/max_age_filter.c @@ -0,0 +1,424 @@ +/* + * + * Copyright 2017 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 "src/core/ext/filters/max_age/max_age_filter.h" + +#include +#include + +#include "src/core/lib/channel/channel_args.h" +#include "src/core/lib/channel/channel_stack_builder.h" +#include "src/core/lib/iomgr/timer.h" +#include "src/core/lib/surface/channel_init.h" +#include "src/core/lib/transport/http2_errors.h" + +#define DEFAULT_MAX_CONNECTION_AGE_MS INT_MAX +#define DEFAULT_MAX_CONNECTION_AGE_GRACE_MS INT_MAX +#define DEFAULT_MAX_CONNECTION_IDLE_MS INT_MAX +#define MAX_CONNECTION_AGE_JITTER 0.1 + +#define MAX_CONNECTION_AGE_INTEGER_OPTIONS \ + (grpc_integer_options) { DEFAULT_MAX_CONNECTION_AGE_MS, 1, INT_MAX } +#define MAX_CONNECTION_IDLE_INTEGER_OPTIONS \ + (grpc_integer_options) { DEFAULT_MAX_CONNECTION_IDLE_MS, 1, INT_MAX } + +typedef struct channel_data { + /* We take a reference to the channel stack for the timer callback */ + grpc_channel_stack* channel_stack; + /* Guards access to max_age_timer, max_age_timer_pending, max_age_grace_timer + and max_age_grace_timer_pending */ + gpr_mu max_age_timer_mu; + /* True if the max_age timer callback is currently pending */ + bool max_age_timer_pending; + /* True if the max_age_grace timer callback is currently pending */ + bool max_age_grace_timer_pending; + /* The timer for checking if the channel has reached its max age */ + grpc_timer max_age_timer; + /* The timer for checking if the max-aged channel has uesed up the grace + period */ + grpc_timer max_age_grace_timer; + /* The timer for checking if the channel's idle duration reaches + max_connection_idle */ + grpc_timer max_idle_timer; + /* Allowed max time a channel may have no outstanding rpcs */ + gpr_timespec max_connection_idle; + /* Allowed max time a channel may exist */ + gpr_timespec max_connection_age; + /* Allowed grace period after the channel reaches its max age */ + gpr_timespec max_connection_age_grace; + /* Closure to run when the channel's idle duration reaches max_connection_idle + and should be closed gracefully */ + grpc_closure close_max_idle_channel; + /* Closure to run when the channel reaches its max age and should be closed + gracefully */ + grpc_closure close_max_age_channel; + /* Closure to run the channel uses up its max age grace time and should be + closed forcibly */ + grpc_closure force_close_max_age_channel; + /* Closure to run when the init fo channel stack is done and the max_idle + timer should be started */ + grpc_closure start_max_idle_timer_after_init; + /* Closure to run when the init fo channel stack is done and the max_age timer + should be started */ + grpc_closure start_max_age_timer_after_init; + /* Closure to run when the goaway op is finished and the max_age_timer */ + grpc_closure start_max_age_grace_timer_after_goaway_op; + /* Closure to run when the channel connectivity state changes */ + grpc_closure channel_connectivity_changed; + /* Records the current connectivity state */ + grpc_connectivity_state connectivity_state; + /* Number of active calls */ + gpr_atm call_count; +} channel_data; + +/* Increase the nubmer of active calls. Before the increasement, if there are no + calls, the max_idle_timer should be cancelled. */ +static void increase_call_count(grpc_exec_ctx* exec_ctx, channel_data* chand) { + if (gpr_atm_full_fetch_add(&chand->call_count, 1) == 0) { + grpc_timer_cancel(exec_ctx, &chand->max_idle_timer); + } +} + +/* Decrease the nubmer of active calls. After the decrement, if there are no + calls, the max_idle_timer should be started. */ +static void decrease_call_count(grpc_exec_ctx* exec_ctx, channel_data* chand) { + if (gpr_atm_full_fetch_add(&chand->call_count, -1) == 1) { + GRPC_CHANNEL_STACK_REF(chand->channel_stack, "max_age max_idle_timer"); + grpc_timer_init( + exec_ctx, &chand->max_idle_timer, + gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), chand->max_connection_idle), + &chand->close_max_idle_channel, gpr_now(GPR_CLOCK_MONOTONIC)); + } +} + +static void start_max_idle_timer_after_init(grpc_exec_ctx* exec_ctx, void* arg, + grpc_error* error) { + channel_data* chand = (channel_data*)arg; + /* Decrease call_count. If there are no active calls at this time, + max_idle_timer will start here. If the number of active calls is not 0, + max_idle_timer will start after all the active calls end. */ + decrease_call_count(exec_ctx, chand); + GRPC_CHANNEL_STACK_UNREF(exec_ctx, chand->channel_stack, + "max_age start_max_idle_timer_after_init"); +} + +static void start_max_age_timer_after_init(grpc_exec_ctx* exec_ctx, void* arg, + grpc_error* error) { + channel_data* chand = (channel_data*)arg; + gpr_mu_lock(&chand->max_age_timer_mu); + chand->max_age_timer_pending = true; + GRPC_CHANNEL_STACK_REF(chand->channel_stack, "max_age max_age_timer"); + grpc_timer_init( + exec_ctx, &chand->max_age_timer, + gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), chand->max_connection_age), + &chand->close_max_age_channel, gpr_now(GPR_CLOCK_MONOTONIC)); + gpr_mu_unlock(&chand->max_age_timer_mu); + grpc_transport_op* op = grpc_make_transport_op(NULL); + op->on_connectivity_state_change = &chand->channel_connectivity_changed, + op->connectivity_state = &chand->connectivity_state; + grpc_channel_next_op(exec_ctx, + grpc_channel_stack_element(chand->channel_stack, 0), op); + GRPC_CHANNEL_STACK_UNREF(exec_ctx, chand->channel_stack, + "max_age start_max_age_timer_after_init"); +} + +static void start_max_age_grace_timer_after_goaway_op(grpc_exec_ctx* exec_ctx, + void* arg, + grpc_error* error) { + channel_data* chand = (channel_data*)arg; + gpr_mu_lock(&chand->max_age_timer_mu); + chand->max_age_grace_timer_pending = true; + GRPC_CHANNEL_STACK_REF(chand->channel_stack, "max_age max_age_grace_timer"); + grpc_timer_init(exec_ctx, &chand->max_age_grace_timer, + gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), + chand->max_connection_age_grace), + &chand->force_close_max_age_channel, + gpr_now(GPR_CLOCK_MONOTONIC)); + gpr_mu_unlock(&chand->max_age_timer_mu); + GRPC_CHANNEL_STACK_UNREF(exec_ctx, chand->channel_stack, + "max_age start_max_age_grace_timer_after_goaway_op"); +} + +static void close_max_idle_channel(grpc_exec_ctx* exec_ctx, void* arg, + grpc_error* error) { + channel_data* chand = (channel_data*)arg; + if (error == GRPC_ERROR_NONE) { + /* Prevent the max idle timer from being set again */ + gpr_atm_no_barrier_fetch_add(&chand->call_count, 1); + grpc_transport_op* op = grpc_make_transport_op(NULL); + op->goaway_error = + grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING("max_idle"), + GRPC_ERROR_INT_HTTP2_ERROR, GRPC_HTTP2_NO_ERROR); + grpc_channel_element* elem = + grpc_channel_stack_element(chand->channel_stack, 0); + elem->filter->start_transport_op(exec_ctx, elem, op); + } else if (error != GRPC_ERROR_CANCELLED) { + GRPC_LOG_IF_ERROR("close_max_idle_channel", error); + } + GRPC_CHANNEL_STACK_UNREF(exec_ctx, chand->channel_stack, + "max_age max_idle_timer"); +} + +static void close_max_age_channel(grpc_exec_ctx* exec_ctx, void* arg, + grpc_error* error) { + channel_data* chand = (channel_data*)arg; + gpr_mu_lock(&chand->max_age_timer_mu); + chand->max_age_timer_pending = false; + gpr_mu_unlock(&chand->max_age_timer_mu); + if (error == GRPC_ERROR_NONE) { + GRPC_CHANNEL_STACK_REF(chand->channel_stack, + "max_age start_max_age_grace_timer_after_goaway_op"); + grpc_transport_op* op = grpc_make_transport_op( + &chand->start_max_age_grace_timer_after_goaway_op); + op->goaway_error = + grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING("max_age"), + GRPC_ERROR_INT_HTTP2_ERROR, GRPC_HTTP2_NO_ERROR); + grpc_channel_element* elem = + grpc_channel_stack_element(chand->channel_stack, 0); + elem->filter->start_transport_op(exec_ctx, elem, op); + } else if (error != GRPC_ERROR_CANCELLED) { + GRPC_LOG_IF_ERROR("close_max_age_channel", error); + } + GRPC_CHANNEL_STACK_UNREF(exec_ctx, chand->channel_stack, + "max_age max_age_timer"); +} + +static void force_close_max_age_channel(grpc_exec_ctx* exec_ctx, void* arg, + grpc_error* error) { + channel_data* chand = (channel_data*)arg; + gpr_mu_lock(&chand->max_age_timer_mu); + chand->max_age_grace_timer_pending = false; + gpr_mu_unlock(&chand->max_age_timer_mu); + if (error == GRPC_ERROR_NONE) { + grpc_transport_op* op = grpc_make_transport_op(NULL); + op->disconnect_with_error = + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Channel reaches max age"); + grpc_channel_element* elem = + grpc_channel_stack_element(chand->channel_stack, 0); + elem->filter->start_transport_op(exec_ctx, elem, op); + } else if (error != GRPC_ERROR_CANCELLED) { + GRPC_LOG_IF_ERROR("force_close_max_age_channel", error); + } + GRPC_CHANNEL_STACK_UNREF(exec_ctx, chand->channel_stack, + "max_age max_age_grace_timer"); +} + +static void channel_connectivity_changed(grpc_exec_ctx* exec_ctx, void* arg, + grpc_error* error) { + channel_data* chand = (channel_data*)arg; + if (chand->connectivity_state != GRPC_CHANNEL_SHUTDOWN) { + grpc_transport_op* op = grpc_make_transport_op(NULL); + op->on_connectivity_state_change = &chand->channel_connectivity_changed, + op->connectivity_state = &chand->connectivity_state; + grpc_channel_next_op( + exec_ctx, grpc_channel_stack_element(chand->channel_stack, 0), op); + } else { + gpr_mu_lock(&chand->max_age_timer_mu); + if (chand->max_age_timer_pending) { + grpc_timer_cancel(exec_ctx, &chand->max_age_timer); + chand->max_age_timer_pending = false; + } + if (chand->max_age_grace_timer_pending) { + grpc_timer_cancel(exec_ctx, &chand->max_age_grace_timer); + chand->max_age_grace_timer_pending = false; + } + gpr_mu_unlock(&chand->max_age_timer_mu); + /* If there are no active calls, this increasement will cancel + max_idle_timer, and prevent max_idle_timer from being started in the + future. */ + increase_call_count(exec_ctx, chand); + } +} + +/* A random jitter of +/-10% will be added to MAX_CONNECTION_AGE to spread out + connection storms. Note that the MAX_CONNECTION_AGE option without jitter + would not create connection storms by itself, but if there happened to be a + connection storm it could cause it to repeat at a fixed period. */ +static int add_random_max_connection_age_jitter(int value) { + /* generate a random number between 1 - MAX_CONNECTION_AGE_JITTER and + 1 + MAX_CONNECTION_AGE_JITTER */ + double multiplier = rand() * MAX_CONNECTION_AGE_JITTER * 2.0 / RAND_MAX + + 1.0 - MAX_CONNECTION_AGE_JITTER; + double result = multiplier * value; + /* INT_MAX - 0.5 converts the value to float, so that result will not be + cast to int implicitly before the comparison. */ + return result > INT_MAX - 0.5 ? INT_MAX : (int)result; +} + +/* Constructor for call_data. */ +static grpc_error* init_call_elem(grpc_exec_ctx* exec_ctx, + grpc_call_element* elem, + const grpc_call_element_args* args) { + channel_data* chand = (channel_data*)elem->channel_data; + increase_call_count(exec_ctx, chand); + return GRPC_ERROR_NONE; +} + +/* Destructor for call_data. */ +static void destroy_call_elem(grpc_exec_ctx* exec_ctx, grpc_call_element* elem, + const grpc_call_final_info* final_info, + grpc_closure* ignored) { + channel_data* chand = elem->channel_data; + decrease_call_count(exec_ctx, chand); +} + +/* Constructor for channel_data. */ +static grpc_error* init_channel_elem(grpc_exec_ctx* exec_ctx, + grpc_channel_element* elem, + grpc_channel_element_args* args) { + channel_data* chand = (channel_data*)elem->channel_data; + gpr_mu_init(&chand->max_age_timer_mu); + chand->max_age_timer_pending = false; + chand->max_age_grace_timer_pending = false; + chand->channel_stack = args->channel_stack; + chand->max_connection_age = + DEFAULT_MAX_CONNECTION_AGE_MS == INT_MAX + ? gpr_inf_future(GPR_TIMESPAN) + : gpr_time_from_millis(add_random_max_connection_age_jitter( + DEFAULT_MAX_CONNECTION_AGE_MS), + GPR_TIMESPAN); + chand->max_connection_age_grace = + DEFAULT_MAX_CONNECTION_AGE_GRACE_MS == INT_MAX + ? gpr_inf_future(GPR_TIMESPAN) + : gpr_time_from_millis(DEFAULT_MAX_CONNECTION_AGE_GRACE_MS, + GPR_TIMESPAN); + chand->max_connection_idle = + DEFAULT_MAX_CONNECTION_IDLE_MS == INT_MAX + ? gpr_inf_future(GPR_TIMESPAN) + : gpr_time_from_millis(DEFAULT_MAX_CONNECTION_IDLE_MS, GPR_TIMESPAN); + for (size_t i = 0; i < args->channel_args->num_args; ++i) { + if (0 == strcmp(args->channel_args->args[i].key, + GRPC_ARG_MAX_CONNECTION_AGE_MS)) { + const int value = grpc_channel_arg_get_integer( + &args->channel_args->args[i], MAX_CONNECTION_AGE_INTEGER_OPTIONS); + chand->max_connection_age = + value == INT_MAX + ? gpr_inf_future(GPR_TIMESPAN) + : gpr_time_from_millis( + add_random_max_connection_age_jitter(value), GPR_TIMESPAN); + } else if (0 == strcmp(args->channel_args->args[i].key, + GRPC_ARG_MAX_CONNECTION_AGE_GRACE_MS)) { + const int value = grpc_channel_arg_get_integer( + &args->channel_args->args[i], + (grpc_integer_options){DEFAULT_MAX_CONNECTION_AGE_GRACE_MS, 0, + INT_MAX}); + chand->max_connection_age_grace = + value == INT_MAX ? gpr_inf_future(GPR_TIMESPAN) + : gpr_time_from_millis(value, GPR_TIMESPAN); + } else if (0 == strcmp(args->channel_args->args[i].key, + GRPC_ARG_MAX_CONNECTION_IDLE_MS)) { + const int value = grpc_channel_arg_get_integer( + &args->channel_args->args[i], MAX_CONNECTION_IDLE_INTEGER_OPTIONS); + chand->max_connection_idle = + value == INT_MAX ? gpr_inf_future(GPR_TIMESPAN) + : gpr_time_from_millis(value, GPR_TIMESPAN); + } + } + GRPC_CLOSURE_INIT(&chand->close_max_idle_channel, close_max_idle_channel, + chand, grpc_schedule_on_exec_ctx); + GRPC_CLOSURE_INIT(&chand->close_max_age_channel, close_max_age_channel, chand, + grpc_schedule_on_exec_ctx); + GRPC_CLOSURE_INIT(&chand->force_close_max_age_channel, + force_close_max_age_channel, chand, + grpc_schedule_on_exec_ctx); + GRPC_CLOSURE_INIT(&chand->start_max_idle_timer_after_init, + start_max_idle_timer_after_init, chand, + grpc_schedule_on_exec_ctx); + GRPC_CLOSURE_INIT(&chand->start_max_age_timer_after_init, + start_max_age_timer_after_init, chand, + grpc_schedule_on_exec_ctx); + GRPC_CLOSURE_INIT(&chand->start_max_age_grace_timer_after_goaway_op, + start_max_age_grace_timer_after_goaway_op, chand, + grpc_schedule_on_exec_ctx); + GRPC_CLOSURE_INIT(&chand->channel_connectivity_changed, + channel_connectivity_changed, chand, + grpc_schedule_on_exec_ctx); + + if (gpr_time_cmp(chand->max_connection_age, gpr_inf_future(GPR_TIMESPAN)) != + 0) { + /* When the channel reaches its max age, we send down an op with + goaway_error set. However, we can't send down any ops until after the + channel stack is fully initialized. If we start the timer here, we have + no guarantee that the timer won't pop before channel stack initialization + is finished. To avoid that problem, we create a closure to start the + timer, and we schedule that closure to be run after call stack + initialization is done. */ + GRPC_CHANNEL_STACK_REF(chand->channel_stack, + "max_age start_max_age_timer_after_init"); + GRPC_CLOSURE_SCHED(exec_ctx, &chand->start_max_age_timer_after_init, + GRPC_ERROR_NONE); + } + + /* Initialize the number of calls as 1, so that the max_idle_timer will not + start until start_max_idle_timer_after_init is invoked. */ + gpr_atm_rel_store(&chand->call_count, 1); + if (gpr_time_cmp(chand->max_connection_idle, gpr_inf_future(GPR_TIMESPAN)) != + 0) { + GRPC_CHANNEL_STACK_REF(chand->channel_stack, + "max_age start_max_idle_timer_after_init"); + GRPC_CLOSURE_SCHED(exec_ctx, &chand->start_max_idle_timer_after_init, + GRPC_ERROR_NONE); + } + return GRPC_ERROR_NONE; +} + +/* Destructor for channel_data. */ +static void destroy_channel_elem(grpc_exec_ctx* exec_ctx, + grpc_channel_element* elem) {} + +const grpc_channel_filter grpc_max_age_filter = { + grpc_call_next_op, + grpc_channel_next_op, + 0, /* sizeof_call_data */ + init_call_elem, + grpc_call_stack_ignore_set_pollset_or_pollset_set, + destroy_call_elem, + sizeof(channel_data), + init_channel_elem, + destroy_channel_elem, + grpc_call_next_get_peer, + grpc_channel_next_get_info, + "max_age"}; + +static bool maybe_add_max_age_filter(grpc_exec_ctx* exec_ctx, + grpc_channel_stack_builder* builder, + void* arg) { + const grpc_channel_args* channel_args = + grpc_channel_stack_builder_get_channel_arguments(builder); + bool enable = + grpc_channel_arg_get_integer( + grpc_channel_args_find(channel_args, GRPC_ARG_MAX_CONNECTION_AGE_MS), + MAX_CONNECTION_AGE_INTEGER_OPTIONS) != INT_MAX && + grpc_channel_arg_get_integer( + grpc_channel_args_find(channel_args, GRPC_ARG_MAX_CONNECTION_IDLE_MS), + MAX_CONNECTION_IDLE_INTEGER_OPTIONS) != INT_MAX; + if (enable) { + return grpc_channel_stack_builder_prepend_filter( + builder, &grpc_max_age_filter, NULL, NULL); + } else { + return true; + } +} + +void grpc_max_age_filter_init(void) { + grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL, + GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, + maybe_add_max_age_filter, NULL); +} + +void grpc_max_age_filter_shutdown(void) {} diff --git a/Sources/CgRPC/src/core/ext/filters/max_age/max_age_filter.h b/Sources/CgRPC/src/core/ext/filters/max_age/max_age_filter.h new file mode 100644 index 000000000..68fb4a4ca --- /dev/null +++ b/Sources/CgRPC/src/core/ext/filters/max_age/max_age_filter.h @@ -0,0 +1,24 @@ +// +// Copyright 2017 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 GRPC_CORE_EXT_FILTERS_MAX_AGE_MAX_AGE_FILTER_H +#define GRPC_CORE_EXT_FILTERS_MAX_AGE_MAX_AGE_FILTER_H + +#include "src/core/lib/channel/channel_stack.h" + +extern const grpc_channel_filter grpc_max_age_filter; + +#endif /* GRPC_CORE_EXT_FILTERS_MAX_AGE_MAX_AGE_FILTER_H */ diff --git a/Sources/CgRPC/src/core/ext/filters/message_size/message_size_filter.c b/Sources/CgRPC/src/core/ext/filters/message_size/message_size_filter.c new file mode 100644 index 000000000..846c7df69 --- /dev/null +++ b/Sources/CgRPC/src/core/ext/filters/message_size/message_size_filter.c @@ -0,0 +1,301 @@ +// +// Copyright 2016 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 "src/core/ext/filters/message_size/message_size_filter.h" + +#include +#include + +#include +#include +#include +#include + +#include "src/core/lib/channel/channel_args.h" +#include "src/core/lib/channel/channel_stack_builder.h" +#include "src/core/lib/support/string.h" +#include "src/core/lib/surface/channel_init.h" +#include "src/core/lib/transport/service_config.h" + +typedef struct message_size_limits { + int max_send_size; + int max_recv_size; +} message_size_limits; + +static void message_size_limits_free(grpc_exec_ctx* exec_ctx, void* value) { + gpr_free(value); +} + +static void* message_size_limits_create_from_json(const grpc_json* json) { + int max_request_message_bytes = -1; + int max_response_message_bytes = -1; + for (grpc_json* field = json->child; field != NULL; field = field->next) { + if (field->key == NULL) continue; + if (strcmp(field->key, "maxRequestMessageBytes") == 0) { + if (max_request_message_bytes >= 0) return NULL; // Duplicate. + if (field->type != GRPC_JSON_STRING && field->type != GRPC_JSON_NUMBER) { + return NULL; + } + max_request_message_bytes = gpr_parse_nonnegative_int(field->value); + if (max_request_message_bytes == -1) return NULL; + } else if (strcmp(field->key, "maxResponseMessageBytes") == 0) { + if (max_response_message_bytes >= 0) return NULL; // Duplicate. + if (field->type != GRPC_JSON_STRING && field->type != GRPC_JSON_NUMBER) { + return NULL; + } + max_response_message_bytes = gpr_parse_nonnegative_int(field->value); + if (max_response_message_bytes == -1) return NULL; + } + } + message_size_limits* value = + (message_size_limits*)gpr_malloc(sizeof(message_size_limits)); + value->max_send_size = max_request_message_bytes; + value->max_recv_size = max_response_message_bytes; + return value; +} + +typedef struct call_data { + message_size_limits limits; + // Receive closures are chained: we inject this closure as the + // recv_message_ready up-call on transport_stream_op, and remember to + // call our next_recv_message_ready member after handling it. + grpc_closure recv_message_ready; + // Used by recv_message_ready. + grpc_byte_stream** recv_message; + // Original recv_message_ready callback, invoked after our own. + grpc_closure* next_recv_message_ready; +} call_data; + +typedef struct channel_data { + message_size_limits limits; + // Maps path names to message_size_limits structs. + grpc_slice_hash_table* method_limit_table; +} channel_data; + +// Callback invoked when we receive a message. Here we check the max +// receive message size. +static void recv_message_ready(grpc_exec_ctx* exec_ctx, void* user_data, + grpc_error* error) { + grpc_call_element* elem = (grpc_call_element*)user_data; + call_data* calld = (call_data*)elem->call_data; + if (*calld->recv_message != NULL && calld->limits.max_recv_size >= 0 && + (*calld->recv_message)->length > (size_t)calld->limits.max_recv_size) { + char* message_string; + gpr_asprintf(&message_string, + "Received message larger than max (%u vs. %d)", + (*calld->recv_message)->length, calld->limits.max_recv_size); + grpc_error* new_error = grpc_error_set_int( + GRPC_ERROR_CREATE_FROM_COPIED_STRING(message_string), + GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_RESOURCE_EXHAUSTED); + if (error == GRPC_ERROR_NONE) { + error = new_error; + } else { + error = grpc_error_add_child(error, new_error); + GRPC_ERROR_UNREF(new_error); + } + gpr_free(message_string); + } else { + GRPC_ERROR_REF(error); + } + // Invoke the next callback. + GRPC_CLOSURE_RUN(exec_ctx, calld->next_recv_message_ready, error); +} + +// Start transport stream op. +static void start_transport_stream_op_batch( + grpc_exec_ctx* exec_ctx, grpc_call_element* elem, + grpc_transport_stream_op_batch* op) { + call_data* calld = (call_data*)elem->call_data; + // Check max send message size. + if (op->send_message && calld->limits.max_send_size >= 0 && + op->payload->send_message.send_message->length > + (size_t)calld->limits.max_send_size) { + char* message_string; + gpr_asprintf(&message_string, "Sent message larger than max (%u vs. %d)", + op->payload->send_message.send_message->length, + calld->limits.max_send_size); + grpc_transport_stream_op_batch_finish_with_failure( + exec_ctx, op, + grpc_error_set_int(GRPC_ERROR_CREATE_FROM_COPIED_STRING(message_string), + GRPC_ERROR_INT_GRPC_STATUS, + GRPC_STATUS_RESOURCE_EXHAUSTED)); + gpr_free(message_string); + return; + } + // Inject callback for receiving a message. + if (op->recv_message) { + calld->next_recv_message_ready = + op->payload->recv_message.recv_message_ready; + calld->recv_message = op->payload->recv_message.recv_message; + op->payload->recv_message.recv_message_ready = &calld->recv_message_ready; + } + // Chain to the next filter. + grpc_call_next_op(exec_ctx, elem, op); +} + +// Constructor for call_data. +static grpc_error* init_call_elem(grpc_exec_ctx* exec_ctx, + grpc_call_element* elem, + const grpc_call_element_args* args) { + channel_data* chand = (channel_data*)elem->channel_data; + call_data* calld = (call_data*)elem->call_data; + calld->next_recv_message_ready = NULL; + GRPC_CLOSURE_INIT(&calld->recv_message_ready, recv_message_ready, elem, + grpc_schedule_on_exec_ctx); + // Get max sizes from channel data, then merge in per-method config values. + // Note: Per-method config is only available on the client, so we + // apply the max request size to the send limit and the max response + // size to the receive limit. + calld->limits = chand->limits; + if (chand->method_limit_table != NULL) { + message_size_limits* limits = + (message_size_limits*)grpc_method_config_table_get( + exec_ctx, chand->method_limit_table, args->path); + if (limits != NULL) { + if (limits->max_send_size >= 0 && + (limits->max_send_size < calld->limits.max_send_size || + calld->limits.max_send_size < 0)) { + calld->limits.max_send_size = limits->max_send_size; + } + if (limits->max_recv_size >= 0 && + (limits->max_recv_size < calld->limits.max_recv_size || + calld->limits.max_recv_size < 0)) { + calld->limits.max_recv_size = limits->max_recv_size; + } + } + } + return GRPC_ERROR_NONE; +} + +// Destructor for call_data. +static void destroy_call_elem(grpc_exec_ctx* exec_ctx, grpc_call_element* elem, + const grpc_call_final_info* final_info, + grpc_closure* ignored) {} + +static int default_size(const grpc_channel_args* args, + int without_minimal_stack) { + if (grpc_channel_args_want_minimal_stack(args)) { + return -1; + } + return without_minimal_stack; +} + +message_size_limits get_message_size_limits( + const grpc_channel_args* channel_args) { + message_size_limits lim; + lim.max_send_size = + default_size(channel_args, GRPC_DEFAULT_MAX_SEND_MESSAGE_LENGTH); + lim.max_recv_size = + default_size(channel_args, GRPC_DEFAULT_MAX_RECV_MESSAGE_LENGTH); + for (size_t i = 0; i < channel_args->num_args; ++i) { + if (strcmp(channel_args->args[i].key, GRPC_ARG_MAX_SEND_MESSAGE_LENGTH) == + 0) { + const grpc_integer_options options = {lim.max_send_size, -1, INT_MAX}; + lim.max_send_size = + grpc_channel_arg_get_integer(&channel_args->args[i], options); + } + if (strcmp(channel_args->args[i].key, + GRPC_ARG_MAX_RECEIVE_MESSAGE_LENGTH) == 0) { + const grpc_integer_options options = {lim.max_recv_size, -1, INT_MAX}; + lim.max_recv_size = + grpc_channel_arg_get_integer(&channel_args->args[i], options); + } + } + return lim; +} + +// Constructor for channel_data. +static grpc_error* init_channel_elem(grpc_exec_ctx* exec_ctx, + grpc_channel_element* elem, + grpc_channel_element_args* args) { + GPR_ASSERT(!args->is_last); + channel_data* chand = (channel_data*)elem->channel_data; + chand->limits = get_message_size_limits(args->channel_args); + // Get method config table from channel args. + const grpc_arg* channel_arg = + grpc_channel_args_find(args->channel_args, GRPC_ARG_SERVICE_CONFIG); + if (channel_arg != NULL) { + GPR_ASSERT(channel_arg->type == GRPC_ARG_STRING); + grpc_service_config* service_config = + grpc_service_config_create(channel_arg->value.string); + if (service_config != NULL) { + chand->method_limit_table = + grpc_service_config_create_method_config_table( + exec_ctx, service_config, message_size_limits_create_from_json, + message_size_limits_free); + grpc_service_config_destroy(service_config); + } + } + return GRPC_ERROR_NONE; +} + +// Destructor for channel_data. +static void destroy_channel_elem(grpc_exec_ctx* exec_ctx, + grpc_channel_element* elem) { + channel_data* chand = (channel_data*)elem->channel_data; + grpc_slice_hash_table_unref(exec_ctx, chand->method_limit_table); +} + +const grpc_channel_filter grpc_message_size_filter = { + start_transport_stream_op_batch, + grpc_channel_next_op, + sizeof(call_data), + init_call_elem, + grpc_call_stack_ignore_set_pollset_or_pollset_set, + destroy_call_elem, + sizeof(channel_data), + init_channel_elem, + destroy_channel_elem, + grpc_call_next_get_peer, + grpc_channel_next_get_info, + "message_size"}; + +static bool maybe_add_message_size_filter(grpc_exec_ctx* exec_ctx, + grpc_channel_stack_builder* builder, + void* arg) { + const grpc_channel_args* channel_args = + grpc_channel_stack_builder_get_channel_arguments(builder); + bool enable = false; + message_size_limits lim = get_message_size_limits(channel_args); + if (lim.max_send_size != -1 || lim.max_recv_size != -1) { + enable = true; + } + const grpc_arg* a = + grpc_channel_args_find(channel_args, GRPC_ARG_SERVICE_CONFIG); + if (a != NULL) { + enable = true; + } + if (enable) { + return grpc_channel_stack_builder_prepend_filter( + builder, &grpc_message_size_filter, NULL, NULL); + } else { + return true; + } +} + +void grpc_message_size_filter_init(void) { + grpc_channel_init_register_stage(GRPC_CLIENT_SUBCHANNEL, + GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, + maybe_add_message_size_filter, NULL); + grpc_channel_init_register_stage(GRPC_CLIENT_DIRECT_CHANNEL, + GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, + maybe_add_message_size_filter, NULL); + grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL, + GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, + maybe_add_message_size_filter, NULL); +} + +void grpc_message_size_filter_shutdown(void) {} diff --git a/Sources/CgRPC/src/core/ext/filters/message_size/message_size_filter.h b/Sources/CgRPC/src/core/ext/filters/message_size/message_size_filter.h new file mode 100644 index 000000000..d3667f700 --- /dev/null +++ b/Sources/CgRPC/src/core/ext/filters/message_size/message_size_filter.h @@ -0,0 +1,24 @@ +// +// Copyright 2016 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 GRPC_CORE_EXT_FILTERS_MESSAGE_SIZE_MESSAGE_SIZE_FILTER_H +#define GRPC_CORE_EXT_FILTERS_MESSAGE_SIZE_MESSAGE_SIZE_FILTER_H + +#include "src/core/lib/channel/channel_stack.h" + +extern const grpc_channel_filter grpc_message_size_filter; + +#endif /* GRPC_CORE_EXT_FILTERS_MESSAGE_SIZE_MESSAGE_SIZE_FILTER_H */ diff --git a/Sources/CgRPC/src/core/ext/filters/workarounds/workaround_cronet_compression_filter.c b/Sources/CgRPC/src/core/ext/filters/workarounds/workaround_cronet_compression_filter.c new file mode 100644 index 000000000..b4d2cb4b8 --- /dev/null +++ b/Sources/CgRPC/src/core/ext/filters/workarounds/workaround_cronet_compression_filter.c @@ -0,0 +1,208 @@ +// +// Copyright 2017 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 "src/core/ext/filters/workarounds/workaround_cronet_compression_filter.h" + +#include + +#include + +#include "src/core/ext/filters/workarounds/workaround_utils.h" +#include "src/core/lib/channel/channel_stack_builder.h" +#include "src/core/lib/surface/channel_init.h" +#include "src/core/lib/transport/metadata.h" + +typedef struct call_data { + // Receive closures are chained: we inject this closure as the + // recv_initial_metadata_ready up-call on transport_stream_op, and remember to + // call our next_recv_initial_metadata_ready member after handling it. + grpc_closure recv_initial_metadata_ready; + // Used by recv_initial_metadata_ready. + grpc_metadata_batch* recv_initial_metadata; + // Original recv_initial_metadata_ready callback, invoked after our own. + grpc_closure* next_recv_initial_metadata_ready; + + // Marks whether the workaround is active + bool workaround_active; +} call_data; + +// Find the user agent metadata element in the batch +static bool get_user_agent_mdelem(const grpc_metadata_batch* batch, + grpc_mdelem* md) { + if (batch->idx.named.user_agent != NULL) { + *md = batch->idx.named.user_agent->md; + return true; + } + return false; +} + +// Callback invoked when we receive an initial metadata. +static void recv_initial_metadata_ready(grpc_exec_ctx* exec_ctx, + void* user_data, grpc_error* error) { + grpc_call_element* elem = (grpc_call_element*)user_data; + call_data* calld = (call_data*)elem->call_data; + + if (GRPC_ERROR_NONE == error) { + grpc_mdelem md; + if (get_user_agent_mdelem(calld->recv_initial_metadata, &md)) { + grpc_workaround_user_agent_md* user_agent_md = grpc_parse_user_agent(md); + if (user_agent_md + ->workaround_active[GRPC_WORKAROUND_ID_CRONET_COMPRESSION]) { + calld->workaround_active = true; + } + } + } + + // Invoke the next callback. + GRPC_CLOSURE_RUN(exec_ctx, calld->next_recv_initial_metadata_ready, + GRPC_ERROR_REF(error)); +} + +// Start transport stream op. +static void start_transport_stream_op_batch( + grpc_exec_ctx* exec_ctx, grpc_call_element* elem, + grpc_transport_stream_op_batch* op) { + call_data* calld = (call_data*)elem->call_data; + + // Inject callback for receiving initial metadata + if (op->recv_initial_metadata) { + calld->next_recv_initial_metadata_ready = + op->payload->recv_initial_metadata.recv_initial_metadata_ready; + op->payload->recv_initial_metadata.recv_initial_metadata_ready = + &calld->recv_initial_metadata_ready; + calld->recv_initial_metadata = + op->payload->recv_initial_metadata.recv_initial_metadata; + } + + if (op->send_message) { + /* Send message happens after client's user-agent (initial metadata) is + * received, so workaround_active must be set already */ + if (calld->workaround_active) { + op->payload->send_message.send_message->flags |= GRPC_WRITE_NO_COMPRESS; + } + } + + // Chain to the next filter. + grpc_call_next_op(exec_ctx, elem, op); +} + +// Constructor for call_data. +static grpc_error* init_call_elem(grpc_exec_ctx* exec_ctx, + grpc_call_element* elem, + const grpc_call_element_args* args) { + call_data* calld = (call_data*)elem->call_data; + calld->next_recv_initial_metadata_ready = NULL; + calld->workaround_active = false; + GRPC_CLOSURE_INIT(&calld->recv_initial_metadata_ready, + recv_initial_metadata_ready, elem, + grpc_schedule_on_exec_ctx); + return GRPC_ERROR_NONE; +} + +// Destructor for call_data. +static void destroy_call_elem(grpc_exec_ctx* exec_ctx, grpc_call_element* elem, + const grpc_call_final_info* final_info, + grpc_closure* ignored) {} + +// Constructor for channel_data. +static grpc_error* init_channel_elem(grpc_exec_ctx* exec_ctx, + grpc_channel_element* elem, + grpc_channel_element_args* args) { + return GRPC_ERROR_NONE; +} + +// Destructor for channel_data. +static void destroy_channel_elem(grpc_exec_ctx* exec_ctx, + grpc_channel_element* elem) {} + +// Parse the user agent +static bool parse_user_agent(grpc_mdelem md) { + const char grpc_objc_specifier[] = "grpc-objc/"; + const size_t grpc_objc_specifier_len = sizeof(grpc_objc_specifier) - 1; + const char cronet_specifier[] = "cronet_http"; + const size_t cronet_specifier_len = sizeof(cronet_specifier) - 1; + + char* user_agent_str = grpc_slice_to_c_string(GRPC_MDVALUE(md)); + bool grpc_objc_specifier_seen = false; + bool cronet_specifier_seen = false; + char *major_version_str = user_agent_str, *minor_version_str; + long major_version, minor_version; + + char* head = strtok(user_agent_str, " "); + while (head != NULL) { + if (!grpc_objc_specifier_seen && + 0 == strncmp(head, grpc_objc_specifier, grpc_objc_specifier_len)) { + major_version_str = head + grpc_objc_specifier_len; + grpc_objc_specifier_seen = true; + } else if (grpc_objc_specifier_seen && + 0 == strncmp(head, cronet_specifier, cronet_specifier_len)) { + cronet_specifier_seen = true; + break; + } + + head = strtok(NULL, " "); + } + if (grpc_objc_specifier_seen) { + major_version_str = strtok(major_version_str, "."); + minor_version_str = strtok(NULL, "."); + major_version = atol(major_version_str); + minor_version = atol(minor_version_str); + } + + gpr_free(user_agent_str); + return (grpc_objc_specifier_seen && cronet_specifier_seen && + (major_version < 1 || (major_version == 1 && minor_version <= 3))); +} + +const grpc_channel_filter grpc_workaround_cronet_compression_filter = { + start_transport_stream_op_batch, + grpc_channel_next_op, + sizeof(call_data), + init_call_elem, + grpc_call_stack_ignore_set_pollset_or_pollset_set, + destroy_call_elem, + 0, + init_channel_elem, + destroy_channel_elem, + grpc_call_next_get_peer, + grpc_channel_next_get_info, + "workaround_cronet_compression"}; + +static bool register_workaround_cronet_compression( + grpc_exec_ctx* exec_ctx, grpc_channel_stack_builder* builder, void* arg) { + const grpc_channel_args* channel_args = + grpc_channel_stack_builder_get_channel_arguments(builder); + const grpc_arg* a = grpc_channel_args_find( + channel_args, GRPC_ARG_WORKAROUND_CRONET_COMPRESSION); + if (a == NULL) { + return true; + } + if (grpc_channel_arg_get_bool(a, false) == false) { + return true; + } + return grpc_channel_stack_builder_prepend_filter( + builder, &grpc_workaround_cronet_compression_filter, NULL, NULL); +} + +void grpc_workaround_cronet_compression_filter_init(void) { + grpc_channel_init_register_stage( + GRPC_SERVER_CHANNEL, GRPC_WORKAROUND_PRIORITY_HIGH, + register_workaround_cronet_compression, NULL); + grpc_register_workaround(GRPC_WORKAROUND_ID_CRONET_COMPRESSION, + parse_user_agent); +} + +void grpc_workaround_cronet_compression_filter_shutdown(void) {} diff --git a/Sources/CgRPC/src/core/ext/filters/workarounds/workaround_cronet_compression_filter.h b/Sources/CgRPC/src/core/ext/filters/workarounds/workaround_cronet_compression_filter.h new file mode 100644 index 000000000..9dae4f073 --- /dev/null +++ b/Sources/CgRPC/src/core/ext/filters/workarounds/workaround_cronet_compression_filter.h @@ -0,0 +1,25 @@ +// +// Copyright 2017 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 GRPC_CORE_EXT_FILTERS_WORKAROUNDS_WORKAROUND_CRONET_COMPRESSION_FILTER_H +#define GRPC_CORE_EXT_FILTERS_WORKAROUNDS_WORKAROUND_CRONET_COMPRESSION_FILTER_H + +#include "src/core/lib/channel/channel_stack.h" + +extern const grpc_channel_filter grpc_workaround_cronet_compression_filter; + +#endif /* GRPC_CORE_EXT_FILTERS_WORKAROUNDS_WORKAROUND_CRONET_COMPRESSION_FILTER_H \ + */ diff --git a/Sources/CgRPC/src/core/ext/filters/workarounds/workaround_utils.c b/Sources/CgRPC/src/core/ext/filters/workarounds/workaround_utils.c new file mode 100644 index 000000000..e600fbee6 --- /dev/null +++ b/Sources/CgRPC/src/core/ext/filters/workarounds/workaround_utils.c @@ -0,0 +1,51 @@ +// +// Copyright 2017 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 "src/core/ext/filters/workarounds/workaround_utils.h" + +#include +#include + +user_agent_parser ua_parser[GRPC_MAX_WORKAROUND_ID]; + +static void destroy_user_agent_md(void *user_agent_md) { + gpr_free(user_agent_md); +} + +grpc_workaround_user_agent_md *grpc_parse_user_agent(grpc_mdelem md) { + grpc_workaround_user_agent_md *user_agent_md = + (grpc_workaround_user_agent_md *)grpc_mdelem_get_user_data( + md, destroy_user_agent_md); + + if (NULL != user_agent_md) { + return user_agent_md; + } + user_agent_md = (grpc_workaround_user_agent_md *)gpr_malloc( + sizeof(grpc_workaround_user_agent_md)); + for (int i = 0; i < GRPC_MAX_WORKAROUND_ID; i++) { + if (ua_parser[i]) { + user_agent_md->workaround_active[i] = ua_parser[i](md); + } + } + grpc_mdelem_set_user_data(md, destroy_user_agent_md, (void *)user_agent_md); + + return user_agent_md; +} + +void grpc_register_workaround(uint32_t id, user_agent_parser parser) { + GPR_ASSERT(id < GRPC_MAX_WORKAROUND_ID); + ua_parser[id] = parser; +} diff --git a/Sources/CgRPC/src/core/ext/filters/workarounds/workaround_utils.h b/Sources/CgRPC/src/core/ext/filters/workarounds/workaround_utils.h new file mode 100644 index 000000000..2ad7a876d --- /dev/null +++ b/Sources/CgRPC/src/core/ext/filters/workarounds/workaround_utils.h @@ -0,0 +1,37 @@ +// +// Copyright 2017 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 GRPC_CORE_EXT_FILTERS_WORKAROUNDS_WORKAROUND_UTILS_H +#define GRPC_CORE_EXT_FILTERS_WORKAROUNDS_WORKAROUND_UTILS_H + +#include + +#include "src/core/lib/transport/metadata.h" + +#define GRPC_WORKAROUND_PRIORITY_HIGH 10001 +#define GRPC_WORKAROUND_PROIRITY_LOW 9999 + +typedef struct grpc_workaround_user_agent_md { + bool workaround_active[GRPC_MAX_WORKAROUND_ID]; +} grpc_workaround_user_agent_md; + +grpc_workaround_user_agent_md *grpc_parse_user_agent(grpc_mdelem md); + +typedef bool (*user_agent_parser)(grpc_mdelem); + +void grpc_register_workaround(uint32_t id, user_agent_parser parser); + +#endif /* GRPC_CORE_EXT_FILTERS_WORKAROUNDS_WORKAROUND_UTILS_H */ diff --git a/Sources/CgRPC/src/core/ext/lb_policy/grpclb/grpclb.c b/Sources/CgRPC/src/core/ext/lb_policy/grpclb/grpclb.c deleted file mode 100644 index bed5e6c90..000000000 --- a/Sources/CgRPC/src/core/ext/lb_policy/grpclb/grpclb.c +++ /dev/null @@ -1,1394 +0,0 @@ -/* - * - * Copyright 2016, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -/** Implementation of the gRPC LB policy. - * - * This policy takes as input a set of resolved addresses {a1..an} for which the - * LB set was set (it's the resolver's responsibility to ensure this). That is - * to say, {a1..an} represent a collection of LB servers. - * - * An internal channel (\a glb_lb_policy.lb_channel) is created over {a1..an}. - * This channel behaves just like a regular channel. In particular, the - * constructed URI over the addresses a1..an will use the default pick first - * policy to select from this list of LB server backends. - * - * The first time the policy gets a request for a pick, a ping, or to exit the - * idle state, \a query_for_backends_locked() is called. This function sets up - * and initiates the internal communication with the LB server. In particular, - * it's responsible for instantiating the internal *streaming* call to the LB - * server (whichever address from {a1..an} pick-first chose). This call is - * serviced by two callbacks, \a lb_on_server_status_received and \a - * lb_on_response_received. The former will be called when the call to the LB - * server completes. This can happen if the LB server closes the connection or - * if this policy itself cancels the call (for example because it's shutting - * down). If the internal call times out, the usual behavior of pick-first - * applies, continuing to pick from the list {a1..an}. - * - * Upon sucesss, the incoming \a LoadBalancingResponse is processed by \a - * res_recv. An invalid one results in the termination of the streaming call. A - * new streaming call should be created if possible, failing the original call - * otherwise. For a valid \a LoadBalancingResponse, the server list of actual - * backends is extracted. A Round Robin policy will be created from this list. - * There are two possible scenarios: - * - * 1. This is the first server list received. There was no previous instance of - * the Round Robin policy. \a rr_handover_locked() will instantiate the RR - * policy and perform all the pending operations over it. - * 2. There's already a RR policy instance active. We need to introduce the new - * one build from the new serverlist, but taking care not to disrupt the - * operations in progress over the old RR instance. This is done by - * decreasing the reference count on the old policy. The moment no more - * references are held on the old RR policy, it'll be destroyed and \a - * glb_rr_connectivity_changed notified with a \a GRPC_CHANNEL_SHUTDOWN - * state. At this point we can transition to a new RR instance safely, which - * is done once again via \a rr_handover_locked(). - * - * - * Once a RR policy instance is in place (and getting updated as described), - * calls to for a pick, a ping or a cancellation will be serviced right away by - * forwarding them to the RR instance. Any time there's no RR policy available - * (ie, right after the creation of the gRPCLB policy, if an empty serverlist is - * received, etc), pick/ping requests are added to a list of pending picks/pings - * to be flushed and serviced as part of \a rr_handover_locked() the moment the - * RR policy instance becomes available. - * - * \see https://github.com/grpc/grpc/blob/master/doc/load-balancing.md for the - * high level design and details. */ - -/* TODO(dgq): - * - Implement LB service forwarding (point 2c. in the doc's diagram). - */ - -/* With the addition of a libuv endpoint, sockaddr.h now includes uv.h when - using that endpoint. Because of various transitive includes in uv.h, - including windows.h on Windows, uv.h must be included before other system - headers. Therefore, sockaddr.h must always be included first */ -#include "src/core/lib/iomgr/sockaddr.h" - -#include - -#include - -#include -#include -#include -#include -#include -#include - -#include "src/core/ext/client_channel/client_channel.h" -#include "src/core/ext/client_channel/client_channel_factory.h" -#include "src/core/ext/client_channel/lb_policy_factory.h" -#include "src/core/ext/client_channel/lb_policy_registry.h" -#include "src/core/ext/client_channel/parse_address.h" -#include "src/core/ext/lb_policy/grpclb/grpclb.h" -#include "src/core/ext/lb_policy/grpclb/load_balancer_api.h" -#include "src/core/lib/channel/channel_args.h" -#include "src/core/lib/iomgr/sockaddr.h" -#include "src/core/lib/iomgr/sockaddr_utils.h" -#include "src/core/lib/iomgr/timer.h" -#include "src/core/lib/slice/slice_string_helpers.h" -#include "src/core/lib/support/backoff.h" -#include "src/core/lib/support/string.h" -#include "src/core/lib/surface/call.h" -#include "src/core/lib/surface/channel.h" -#include "src/core/lib/transport/static_metadata.h" - -#define GRPC_GRPCLB_MIN_CONNECT_TIMEOUT_SECONDS 20 -#define GRPC_GRPCLB_INITIAL_CONNECT_BACKOFF_SECONDS 1 -#define GRPC_GRPCLB_RECONNECT_BACKOFF_MULTIPLIER 1.6 -#define GRPC_GRPCLB_RECONNECT_MAX_BACKOFF_SECONDS 120 -#define GRPC_GRPCLB_RECONNECT_JITTER 0.2 - -int grpc_lb_glb_trace = 0; - -/* add lb_token of selected subchannel (address) to the call's initial - * metadata */ -static void initial_metadata_add_lb_token( - grpc_metadata_batch *initial_metadata, - grpc_linked_mdelem *lb_token_mdelem_storage, grpc_mdelem *lb_token) { - GPR_ASSERT(lb_token_mdelem_storage != NULL); - GPR_ASSERT(lb_token != NULL); - grpc_metadata_batch_add_tail(initial_metadata, lb_token_mdelem_storage, - lb_token); -} - -typedef struct wrapped_rr_closure_arg { - /* the closure instance using this struct as argument */ - grpc_closure wrapper_closure; - - /* the original closure. Usually a on_complete/notify cb for pick() and ping() - * calls against the internal RR instance, respectively. */ - grpc_closure *wrapped_closure; - - /* the pick's initial metadata, kept in order to append the LB token for the - * pick */ - grpc_metadata_batch *initial_metadata; - - /* the picked target, used to determine which LB token to add to the pick's - * initial metadata */ - grpc_connected_subchannel **target; - - /* the LB token associated with the pick */ - grpc_mdelem *lb_token; - - /* storage for the lb token initial metadata mdelem */ - grpc_linked_mdelem *lb_token_mdelem_storage; - - /* The RR instance related to the closure */ - grpc_lb_policy *rr_policy; - - /* heap memory to be freed upon closure execution. */ - void *free_when_done; -} wrapped_rr_closure_arg; - -/* The \a on_complete closure passed as part of the pick requires keeping a - * reference to its associated round robin instance. We wrap this closure in - * order to unref the round robin instance upon its invocation */ -static void wrapped_rr_closure(grpc_exec_ctx *exec_ctx, void *arg, - grpc_error *error) { - wrapped_rr_closure_arg *wc_arg = arg; - - GPR_ASSERT(wc_arg->wrapped_closure != NULL); - grpc_exec_ctx_sched(exec_ctx, wc_arg->wrapped_closure, GRPC_ERROR_REF(error), - NULL); - - if (wc_arg->rr_policy != NULL) { - /* if *target is NULL, no pick has been made by the RR policy (eg, all - * addresses failed to connect). There won't be any user_data/token - * available */ - if (*wc_arg->target != NULL) { - if (wc_arg->lb_token != NULL) { - initial_metadata_add_lb_token(wc_arg->initial_metadata, - wc_arg->lb_token_mdelem_storage, - GRPC_MDELEM_REF(wc_arg->lb_token)); - } else { - gpr_log(GPR_ERROR, - "No LB token for connected subchannel pick %p (from RR " - "instance %p).", - (void *)*wc_arg->target, (void *)wc_arg->rr_policy); - abort(); - } - } - if (grpc_lb_glb_trace) { - gpr_log(GPR_INFO, "Unreffing RR %p", (void *)wc_arg->rr_policy); - } - GRPC_LB_POLICY_UNREF(exec_ctx, wc_arg->rr_policy, "wrapped_rr_closure"); - } - GPR_ASSERT(wc_arg->free_when_done != NULL); - gpr_free(wc_arg->free_when_done); -} - -/* Linked list of pending pick requests. It stores all information needed to - * eventually call (Round Robin's) pick() on them. They mainly stay pending - * waiting for the RR policy to be created/updated. - * - * One particularity is the wrapping of the user-provided \a on_complete closure - * (in \a wrapped_on_complete and \a wrapped_on_complete_arg). This is needed in - * order to correctly unref the RR policy instance upon completion of the pick. - * See \a wrapped_rr_closure for details. */ -typedef struct pending_pick { - struct pending_pick *next; - - /* original pick()'s arguments */ - grpc_lb_policy_pick_args pick_args; - - /* output argument where to store the pick()ed connected subchannel, or NULL - * upon error. */ - grpc_connected_subchannel **target; - - /* args for wrapped_on_complete */ - wrapped_rr_closure_arg wrapped_on_complete_arg; -} pending_pick; - -static void add_pending_pick(pending_pick **root, - const grpc_lb_policy_pick_args *pick_args, - grpc_connected_subchannel **target, - grpc_closure *on_complete) { - pending_pick *pp = gpr_malloc(sizeof(*pp)); - memset(pp, 0, sizeof(pending_pick)); - memset(&pp->wrapped_on_complete_arg, 0, sizeof(wrapped_rr_closure_arg)); - pp->next = *root; - pp->pick_args = *pick_args; - pp->target = target; - pp->wrapped_on_complete_arg.wrapped_closure = on_complete; - pp->wrapped_on_complete_arg.target = target; - pp->wrapped_on_complete_arg.initial_metadata = pick_args->initial_metadata; - pp->wrapped_on_complete_arg.lb_token_mdelem_storage = - pick_args->lb_token_mdelem_storage; - pp->wrapped_on_complete_arg.free_when_done = pp; - grpc_closure_init(&pp->wrapped_on_complete_arg.wrapper_closure, - wrapped_rr_closure, &pp->wrapped_on_complete_arg); - *root = pp; -} - -/* Same as the \a pending_pick struct but for ping operations */ -typedef struct pending_ping { - struct pending_ping *next; - - /* args for wrapped_notify */ - wrapped_rr_closure_arg wrapped_notify_arg; -} pending_ping; - -static void add_pending_ping(pending_ping **root, grpc_closure *notify) { - pending_ping *pping = gpr_malloc(sizeof(*pping)); - memset(pping, 0, sizeof(pending_ping)); - memset(&pping->wrapped_notify_arg, 0, sizeof(wrapped_rr_closure_arg)); - pping->wrapped_notify_arg.wrapped_closure = notify; - pping->wrapped_notify_arg.free_when_done = pping; - pping->next = *root; - grpc_closure_init(&pping->wrapped_notify_arg.wrapper_closure, - wrapped_rr_closure, &pping->wrapped_notify_arg); - *root = pping; -} - -/* - * glb_lb_policy - */ -typedef struct rr_connectivity_data rr_connectivity_data; -static const grpc_lb_policy_vtable glb_lb_policy_vtable; -typedef struct glb_lb_policy { - /** base policy: must be first */ - grpc_lb_policy base; - - /** mutex protecting remaining members */ - gpr_mu mu; - - /** who the client is trying to communicate with */ - const char *server_name; - grpc_client_channel_factory *cc_factory; - grpc_channel_args *args; - - /** deadline for the LB's call */ - gpr_timespec deadline; - - /** for communicating with the LB server */ - grpc_channel *lb_channel; - - /** the RR policy to use of the backend servers returned by the LB server */ - grpc_lb_policy *rr_policy; - - bool started_picking; - - /** our connectivity state tracker */ - grpc_connectivity_state_tracker state_tracker; - - /** stores the deserialized response from the LB. May be NULL until one such - * response has arrived. */ - grpc_grpclb_serverlist *serverlist; - - /** list of picks that are waiting on RR's policy connectivity */ - pending_pick *pending_picks; - - /** list of pings that are waiting on RR's policy connectivity */ - pending_ping *pending_pings; - - bool shutting_down; - - /************************************************************/ - /* client data associated with the LB server communication */ - /************************************************************/ - /* Status from the LB server has been received. This signals the end of the LB - * call. */ - grpc_closure lb_on_server_status_received; - - /* A response from the LB server has been received. Process it */ - grpc_closure lb_on_response_received; - - grpc_call *lb_call; /* streaming call to the LB server, */ - - grpc_metadata_array lb_initial_metadata_recv; /* initial MD from LB server */ - grpc_metadata_array - lb_trailing_metadata_recv; /* trailing MD from LB server */ - - /* what's being sent to the LB server. Note that its value may vary if the LB - * server indicates a redirect. */ - grpc_byte_buffer *lb_request_payload; - - /* response the LB server, if any. Processed in lb_on_response_received() */ - grpc_byte_buffer *lb_response_payload; - - /* call status code and details, set in lb_on_server_status_received() */ - grpc_status_code lb_call_status; - char *lb_call_status_details; - size_t lb_call_status_details_capacity; - - /** LB call retry backoff state */ - gpr_backoff lb_call_backoff_state; - - /** LB call retry timer */ - grpc_timer lb_call_retry_timer; -} glb_lb_policy; - -/* Keeps track and reacts to changes in connectivity of the RR instance */ -struct rr_connectivity_data { - grpc_closure on_change; - grpc_connectivity_state state; - glb_lb_policy *glb_policy; -}; - -static bool is_server_valid(const grpc_grpclb_server *server, size_t idx, - bool log) { - const grpc_grpclb_ip_address *ip = &server->ip_address; - if (server->port >> 16 != 0) { - if (log) { - gpr_log(GPR_ERROR, - "Invalid port '%d' at index %lu of serverlist. Ignoring.", - server->port, (unsigned long)idx); - } - return false; - } - - if (ip->size != 4 && ip->size != 16) { - if (log) { - gpr_log(GPR_ERROR, - "Expected IP to be 4 or 16 bytes, got %d at index %lu of " - "serverlist. Ignoring", - ip->size, (unsigned long)idx); - } - return false; - } - return true; -} - -/* vtable for LB tokens in grpc_lb_addresses. */ -static void *lb_token_copy(void *token) { - return token == NULL ? NULL : GRPC_MDELEM_REF(token); -} -static void lb_token_destroy(void *token) { - if (token != NULL) GRPC_MDELEM_UNREF(token); -} -static int lb_token_cmp(void *token1, void *token2) { - if (token1 > token2) return 1; - if (token1 < token2) return -1; - return 0; -} -static const grpc_lb_user_data_vtable lb_token_vtable = { - lb_token_copy, lb_token_destroy, lb_token_cmp}; - -static void parse_server(const grpc_grpclb_server *server, - grpc_resolved_address *addr) { - const uint16_t netorder_port = htons((uint16_t)server->port); - /* the addresses are given in binary format (a in(6)_addr struct) in - * server->ip_address.bytes. */ - const grpc_grpclb_ip_address *ip = &server->ip_address; - memset(addr, 0, sizeof(*addr)); - if (ip->size == 4) { - addr->len = sizeof(struct sockaddr_in); - struct sockaddr_in *addr4 = (struct sockaddr_in *)&addr->addr; - addr4->sin_family = AF_INET; - memcpy(&addr4->sin_addr, ip->bytes, ip->size); - addr4->sin_port = netorder_port; - } else if (ip->size == 16) { - addr->len = sizeof(struct sockaddr_in6); - struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&addr->addr; - addr6->sin6_family = AF_INET6; - memcpy(&addr6->sin6_addr, ip->bytes, ip->size); - addr6->sin6_port = netorder_port; - } -} - -/* Returns addresses extracted from \a serverlist. */ -static grpc_lb_addresses *process_serverlist_locked( - const grpc_grpclb_serverlist *serverlist) { - size_t num_valid = 0; - /* first pass: count how many are valid in order to allocate the necessary - * memory in a single block */ - for (size_t i = 0; i < serverlist->num_servers; ++i) { - if (is_server_valid(serverlist->servers[i], i, true)) ++num_valid; - } - if (num_valid == 0) return NULL; - - grpc_lb_addresses *lb_addresses = - grpc_lb_addresses_create(num_valid, &lb_token_vtable); - - /* second pass: actually populate the addresses and LB tokens (aka user data - * to the outside world) to be read by the RR policy during its creation. - * Given that the validity tests are very cheap, they are performed again - * instead of marking the valid ones during the first pass, as this would - * incurr in an allocation due to the arbitrary number of server */ - size_t addr_idx = 0; - for (size_t sl_idx = 0; sl_idx < serverlist->num_servers; ++sl_idx) { - GPR_ASSERT(addr_idx < num_valid); - const grpc_grpclb_server *server = serverlist->servers[sl_idx]; - if (!is_server_valid(serverlist->servers[sl_idx], sl_idx, false)) continue; - - /* address processing */ - grpc_resolved_address addr; - parse_server(server, &addr); - - /* lb token processing */ - void *user_data; - if (server->has_load_balance_token) { - const size_t lb_token_max_length = - GPR_ARRAY_SIZE(server->load_balance_token); - const size_t lb_token_length = - strnlen(server->load_balance_token, lb_token_max_length); - grpc_mdstr *lb_token_mdstr = grpc_mdstr_from_buffer( - (uint8_t *)server->load_balance_token, lb_token_length); - user_data = grpc_mdelem_from_metadata_strings(GRPC_MDSTR_LB_TOKEN, - lb_token_mdstr); - } else { - char *uri = grpc_sockaddr_to_uri(&addr); - gpr_log(GPR_INFO, - "Missing LB token for backend address '%s'. The empty token will " - "be used instead", - uri); - gpr_free(uri); - user_data = GRPC_MDELEM_LB_TOKEN_EMPTY; - } - - grpc_lb_addresses_set_address(lb_addresses, addr_idx, &addr.addr, addr.len, - false /* is_balancer */, - NULL /* balancer_name */, user_data); - ++addr_idx; - } - GPR_ASSERT(addr_idx == num_valid); - return lb_addresses; -} - -/* returns true if the new RR policy should replace the current one, if any */ -static bool update_lb_connectivity_status_locked( - grpc_exec_ctx *exec_ctx, glb_lb_policy *glb_policy, - grpc_connectivity_state new_rr_state, grpc_error *new_rr_state_error) { - grpc_error *curr_state_error; - const grpc_connectivity_state curr_glb_state = grpc_connectivity_state_check( - &glb_policy->state_tracker, &curr_state_error); - - /* The new connectivity status is a function of the previous one and the new - * input coming from the status of the RR policy. - * - * current state (grpclb's) - * | - * v || I | C | R | TF | SD | <- new state (RR's) - * ===++====+=====+=====+======+======+ - * I || I | C | R | [I] | [I] | - * ---++----+-----+-----+------+------+ - * C || I | C | R | [C] | [C] | - * ---++----+-----+-----+------+------+ - * R || I | C | R | [R] | [R] | - * ---++----+-----+-----+------+------+ - * TF || I | C | R | [TF] | [TF] | - * ---++----+-----+-----+------+------+ - * SD || NA | NA | NA | NA | NA | (*) - * ---++----+-----+-----+------+------+ - * - * A [STATE] indicates that the old RR policy is kept. In those cases, STATE - * is the current state of grpclb, which is left untouched. - * - * In summary, if the new state is TRANSIENT_FAILURE or SHUTDOWN, stick to - * the previous RR instance. - * - * Note that the status is never updated to SHUTDOWN as a result of calling - * this function. Only glb_shutdown() has the power to set that state. - * - * (*) This function mustn't be called during shutting down. */ - GPR_ASSERT(curr_glb_state != GRPC_CHANNEL_SHUTDOWN); - - switch (new_rr_state) { - case GRPC_CHANNEL_TRANSIENT_FAILURE: - case GRPC_CHANNEL_SHUTDOWN: - GPR_ASSERT(new_rr_state_error != GRPC_ERROR_NONE); - return false; /* don't replace the RR policy */ - case GRPC_CHANNEL_INIT: - case GRPC_CHANNEL_IDLE: - case GRPC_CHANNEL_CONNECTING: - case GRPC_CHANNEL_READY: - GPR_ASSERT(new_rr_state_error == GRPC_ERROR_NONE); - } - - if (grpc_lb_glb_trace) { - gpr_log(GPR_INFO, - "Setting grpclb's state to %s from new RR policy %p state.", - grpc_connectivity_state_name(new_rr_state), - (void *)glb_policy->rr_policy); - } - grpc_connectivity_state_set(exec_ctx, &glb_policy->state_tracker, - new_rr_state, GRPC_ERROR_REF(new_rr_state_error), - "update_lb_connectivity_status_locked"); - return true; -} - -/* perform a pick over \a rr_policy. Given that a pick can return immediately - * (ignoring its completion callback) we need to perform the cleanups this - * callback would be otherwise resposible for */ -static bool pick_from_internal_rr_locked( - grpc_exec_ctx *exec_ctx, grpc_lb_policy *rr_policy, - const grpc_lb_policy_pick_args *pick_args, - grpc_connected_subchannel **target, wrapped_rr_closure_arg *wc_arg) { - GPR_ASSERT(rr_policy != NULL); - const bool pick_done = - grpc_lb_policy_pick(exec_ctx, rr_policy, pick_args, target, - (void **)&wc_arg->lb_token, &wc_arg->wrapper_closure); - if (pick_done) { - /* synchronous grpc_lb_policy_pick call. Unref the RR policy. */ - if (grpc_lb_glb_trace) { - gpr_log(GPR_INFO, "Unreffing RR (0x%" PRIxPTR ")", - (intptr_t)wc_arg->rr_policy); - } - GRPC_LB_POLICY_UNREF(exec_ctx, wc_arg->rr_policy, "glb_pick_sync"); - - /* add the load reporting initial metadata */ - initial_metadata_add_lb_token(pick_args->initial_metadata, - pick_args->lb_token_mdelem_storage, - GRPC_MDELEM_REF(wc_arg->lb_token)); - - gpr_free(wc_arg); - } - /* else, the pending pick will be registered and taken care of by the - * pending pick list inside the RR policy (glb_policy->rr_policy). - * Eventually, wrapped_on_complete will be called, which will -among other - * things- add the LB token to the call's initial metadata */ - return pick_done; -} - -static grpc_lb_policy *create_rr_locked( - grpc_exec_ctx *exec_ctx, const grpc_grpclb_serverlist *serverlist, - glb_lb_policy *glb_policy) { - GPR_ASSERT(serverlist != NULL && serverlist->num_servers > 0); - - grpc_lb_policy_args args; - memset(&args, 0, sizeof(args)); - args.client_channel_factory = glb_policy->cc_factory; - grpc_lb_addresses *addresses = process_serverlist_locked(serverlist); - - // Replace the LB addresses in the channel args that we pass down to - // the subchannel. - static const char *keys_to_remove[] = {GRPC_ARG_LB_ADDRESSES}; - const grpc_arg arg = grpc_lb_addresses_create_channel_arg(addresses); - args.args = grpc_channel_args_copy_and_add_and_remove( - glb_policy->args, keys_to_remove, GPR_ARRAY_SIZE(keys_to_remove), &arg, - 1); - - grpc_lb_policy *rr = grpc_lb_policy_create(exec_ctx, "round_robin", &args); - GPR_ASSERT(rr != NULL); - grpc_lb_addresses_destroy(addresses); - grpc_channel_args_destroy(args.args); - return rr; -} - -static void glb_rr_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg, - grpc_error *error); -/* glb_policy->rr_policy may be NULL (initial handover) */ -static void rr_handover_locked(grpc_exec_ctx *exec_ctx, - glb_lb_policy *glb_policy) { - GPR_ASSERT(glb_policy->serverlist != NULL && - glb_policy->serverlist->num_servers > 0); - - if (glb_policy->shutting_down) return; - - grpc_lb_policy *new_rr_policy = - create_rr_locked(exec_ctx, glb_policy->serverlist, glb_policy); - if (new_rr_policy == NULL) { - gpr_log(GPR_ERROR, - "Failure creating a RoundRobin policy for serverlist update with " - "%lu entries. The previous RR instance (%p), if any, will continue " - "to be used. Future updates from the LB will attempt to create new " - "instances.", - (unsigned long)glb_policy->serverlist->num_servers, - (void *)glb_policy->rr_policy); - return; - } - - grpc_error *new_rr_state_error = NULL; - const grpc_connectivity_state new_rr_state = - grpc_lb_policy_check_connectivity(exec_ctx, new_rr_policy, - &new_rr_state_error); - /* Connectivity state is a function of the new RR policy just created */ - const bool replace_old_rr = update_lb_connectivity_status_locked( - exec_ctx, glb_policy, new_rr_state, new_rr_state_error); - - if (!replace_old_rr) { - /* dispose of the new RR policy that won't be used after all */ - GRPC_LB_POLICY_UNREF(exec_ctx, new_rr_policy, "rr_handover_no_replace"); - if (grpc_lb_glb_trace) { - gpr_log(GPR_INFO, - "Keeping old RR policy (%p) despite new serverlist: new RR " - "policy was in %s connectivity state.", - (void *)glb_policy->rr_policy, - grpc_connectivity_state_name(new_rr_state)); - } - return; - } - - if (grpc_lb_glb_trace) { - gpr_log(GPR_INFO, "Created RR policy (%p) to replace old RR (%p)", - (void *)new_rr_policy, (void *)glb_policy->rr_policy); - } - - if (glb_policy->rr_policy != NULL) { - /* if we are phasing out an existing RR instance, unref it. */ - GRPC_LB_POLICY_UNREF(exec_ctx, glb_policy->rr_policy, "rr_handover"); - } - - /* Finally update the RR policy to the newly created one */ - glb_policy->rr_policy = new_rr_policy; - - /* Add the gRPC LB's interested_parties pollset_set to that of the newly - * created RR policy. This will make the RR policy progress upon activity on - * gRPC LB, which in turn is tied to the application's call */ - grpc_pollset_set_add_pollset_set(exec_ctx, - glb_policy->rr_policy->interested_parties, - glb_policy->base.interested_parties); - - /* Allocate the data for the tracking of the new RR policy's connectivity. - * It'll be deallocated in glb_rr_connectivity_changed() */ - rr_connectivity_data *rr_connectivity = - gpr_malloc(sizeof(rr_connectivity_data)); - memset(rr_connectivity, 0, sizeof(rr_connectivity_data)); - grpc_closure_init(&rr_connectivity->on_change, glb_rr_connectivity_changed, - rr_connectivity); - rr_connectivity->glb_policy = glb_policy; - rr_connectivity->state = new_rr_state; - - /* Subscribe to changes to the connectivity of the new RR */ - GRPC_LB_POLICY_WEAK_REF(&glb_policy->base, "rr_connectivity_cb"); - grpc_lb_policy_notify_on_state_change(exec_ctx, glb_policy->rr_policy, - &rr_connectivity->state, - &rr_connectivity->on_change); - grpc_lb_policy_exit_idle(exec_ctx, glb_policy->rr_policy); - - /* Update picks and pings in wait */ - pending_pick *pp; - while ((pp = glb_policy->pending_picks)) { - glb_policy->pending_picks = pp->next; - GRPC_LB_POLICY_REF(glb_policy->rr_policy, "rr_handover_pending_pick"); - pp->wrapped_on_complete_arg.rr_policy = glb_policy->rr_policy; - if (grpc_lb_glb_trace) { - gpr_log(GPR_INFO, "Pending pick about to PICK from 0x%" PRIxPTR "", - (intptr_t)glb_policy->rr_policy); - } - pick_from_internal_rr_locked(exec_ctx, glb_policy->rr_policy, - &pp->pick_args, pp->target, - &pp->wrapped_on_complete_arg); - } - - pending_ping *pping; - while ((pping = glb_policy->pending_pings)) { - glb_policy->pending_pings = pping->next; - GRPC_LB_POLICY_REF(glb_policy->rr_policy, "rr_handover_pending_ping"); - pping->wrapped_notify_arg.rr_policy = glb_policy->rr_policy; - if (grpc_lb_glb_trace) { - gpr_log(GPR_INFO, "Pending ping about to PING from 0x%" PRIxPTR "", - (intptr_t)glb_policy->rr_policy); - } - grpc_lb_policy_ping_one(exec_ctx, glb_policy->rr_policy, - &pping->wrapped_notify_arg.wrapper_closure); - } -} - -static void glb_rr_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg, - grpc_error *error) { - rr_connectivity_data *rr_connectivity = arg; - glb_lb_policy *glb_policy = rr_connectivity->glb_policy; - - gpr_mu_lock(&glb_policy->mu); - const bool shutting_down = glb_policy->shutting_down; - bool unref_needed = false; - GRPC_ERROR_REF(error); - - if (rr_connectivity->state == GRPC_CHANNEL_SHUTDOWN || shutting_down) { - /* RR policy shutting down. Don't renew subscription and free the arg of - * this callback. In addition we need to stash away the current policy to - * be UNREF'd after releasing the lock. Otherwise, if the UNREF is the last - * one, the policy would be destroyed, alongside the lock, which would - * result in a use-after-free */ - unref_needed = true; - gpr_free(rr_connectivity); - } else { /* rr state != SHUTDOWN && !shutting down: biz as usual */ - update_lb_connectivity_status_locked(exec_ctx, glb_policy, - rr_connectivity->state, error); - /* Resubscribe. Reuse the "rr_connectivity_cb" weak ref. */ - grpc_lb_policy_notify_on_state_change(exec_ctx, glb_policy->rr_policy, - &rr_connectivity->state, - &rr_connectivity->on_change); - } - gpr_mu_unlock(&glb_policy->mu); - if (unref_needed) { - GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &glb_policy->base, - "rr_connectivity_cb"); - } - GRPC_ERROR_UNREF(error); -} - -static grpc_lb_policy *glb_create(grpc_exec_ctx *exec_ctx, - grpc_lb_policy_factory *factory, - grpc_lb_policy_args *args) { - /* Count the number of gRPC-LB addresses. There must be at least one. - * TODO(roth): For now, we ignore non-balancer addresses, but in the - * future, we may change the behavior such that we fall back to using - * the non-balancer addresses if we cannot reach any balancers. At that - * time, this should be changed to allow a list with no balancer addresses, - * since the resolver might fail to return a balancer address even when - * this is the right LB policy to use. */ - const grpc_arg *arg = - grpc_channel_args_find(args->args, GRPC_ARG_LB_ADDRESSES); - GPR_ASSERT(arg != NULL && arg->type == GRPC_ARG_POINTER); - grpc_lb_addresses *addresses = arg->value.pointer.p; - size_t num_grpclb_addrs = 0; - for (size_t i = 0; i < addresses->num_addresses; ++i) { - if (addresses->addresses[i].is_balancer) ++num_grpclb_addrs; - } - if (num_grpclb_addrs == 0) return NULL; - - glb_lb_policy *glb_policy = gpr_malloc(sizeof(*glb_policy)); - memset(glb_policy, 0, sizeof(*glb_policy)); - - /* Get server name. */ - arg = grpc_channel_args_find(args->args, GRPC_ARG_SERVER_URI); - GPR_ASSERT(arg != NULL); - GPR_ASSERT(arg->type == GRPC_ARG_STRING); - grpc_uri *uri = grpc_uri_parse(arg->value.string, true); - GPR_ASSERT(uri->path[0] != '\0'); - glb_policy->server_name = - gpr_strdup(uri->path[0] == '/' ? uri->path + 1 : uri->path); - if (grpc_lb_glb_trace) { - gpr_log(GPR_INFO, "Will use '%s' as the server name for LB request.", - glb_policy->server_name); - } - grpc_uri_destroy(uri); - - /* All input addresses in addresses come from a resolver that claims - * they are LB services. It's the resolver's responsibility to make sure - * this policy is only instantiated and used in that case. - * - * Create a client channel over them to communicate with a LB service */ - glb_policy->cc_factory = args->client_channel_factory; - glb_policy->args = grpc_channel_args_copy(args->args); - GPR_ASSERT(glb_policy->cc_factory != NULL); - - /* construct a target from the addresses in args, given in the form - * ipvX://ip1:port1,ip2:port2,... - * TODO(dgq): support mixed ip version */ - char **addr_strs = gpr_malloc(sizeof(char *) * num_grpclb_addrs); - size_t addr_index = 0; - for (size_t i = 0; i < addresses->num_addresses; i++) { - if (addresses->addresses[i].user_data != NULL) { - gpr_log(GPR_ERROR, - "This LB policy doesn't support user data. It will be ignored"); - } - if (addresses->addresses[i].is_balancer) { - if (addr_index == 0) { - addr_strs[addr_index++] = - grpc_sockaddr_to_uri(&addresses->addresses[i].address); - } else { - GPR_ASSERT(grpc_sockaddr_to_string(&addr_strs[addr_index++], - &addresses->addresses[i].address, - true) > 0); - } - } - } - size_t uri_path_len; - char *target_uri_str = gpr_strjoin_sep((const char **)addr_strs, - num_grpclb_addrs, ",", &uri_path_len); - - /* Create a channel to talk to the LBs. - * - * We strip out the channel arg for the LB policy name, since we want - * to use the default (pick_first) in this case. - * - * We also strip out the channel arg for the resolved addresses, since - * that will be generated by the name resolver used in the LB channel. - * Note that the LB channel will use the sockaddr resolver, so this - * won't actually generate a query to DNS (or some other name service). - * However, the addresses returned by the sockaddr resolver will have - * is_balancer=false, whereas our own addresses have is_balancer=true. - * We need the LB channel to return addresses with is_balancer=false - * so that it does not wind up recursively using the grpclb LB policy, - * as per the special case logic in client_channel.c. - * - * Finally, we also strip out the channel arg for the server URI, - * since that will be different for the LB channel than for the parent - * channel. (The client channel factory will re-add this arg with - * the right value.) - */ - static const char *keys_to_remove[] = { - GRPC_ARG_LB_POLICY_NAME, GRPC_ARG_LB_ADDRESSES, GRPC_ARG_SERVER_URI}; - grpc_channel_args *new_args = grpc_channel_args_copy_and_remove( - args->args, keys_to_remove, GPR_ARRAY_SIZE(keys_to_remove)); - glb_policy->lb_channel = grpc_client_channel_factory_create_channel( - exec_ctx, glb_policy->cc_factory, target_uri_str, - GRPC_CLIENT_CHANNEL_TYPE_LOAD_BALANCING, new_args); - grpc_channel_args_destroy(new_args); - - gpr_free(target_uri_str); - for (size_t i = 0; i < num_grpclb_addrs; i++) { - gpr_free(addr_strs[i]); - } - gpr_free(addr_strs); - - if (glb_policy->lb_channel == NULL) { - gpr_free(glb_policy); - return NULL; - } - - grpc_lb_policy_init(&glb_policy->base, &glb_lb_policy_vtable); - gpr_mu_init(&glb_policy->mu); - grpc_connectivity_state_init(&glb_policy->state_tracker, GRPC_CHANNEL_IDLE, - "grpclb"); - - return &glb_policy->base; -} - -static void glb_destroy(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) { - glb_lb_policy *glb_policy = (glb_lb_policy *)pol; - GPR_ASSERT(glb_policy->pending_picks == NULL); - GPR_ASSERT(glb_policy->pending_pings == NULL); - gpr_free((void *)glb_policy->server_name); - grpc_channel_args_destroy(glb_policy->args); - grpc_channel_destroy(glb_policy->lb_channel); - glb_policy->lb_channel = NULL; - grpc_connectivity_state_destroy(exec_ctx, &glb_policy->state_tracker); - if (glb_policy->serverlist != NULL) { - grpc_grpclb_destroy_serverlist(glb_policy->serverlist); - } - gpr_mu_destroy(&glb_policy->mu); - gpr_free(glb_policy); -} - -static void glb_shutdown(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) { - glb_lb_policy *glb_policy = (glb_lb_policy *)pol; - gpr_mu_lock(&glb_policy->mu); - glb_policy->shutting_down = true; - - pending_pick *pp = glb_policy->pending_picks; - glb_policy->pending_picks = NULL; - pending_ping *pping = glb_policy->pending_pings; - glb_policy->pending_pings = NULL; - if (glb_policy->rr_policy) { - GRPC_LB_POLICY_UNREF(exec_ctx, glb_policy->rr_policy, "glb_shutdown"); - } - grpc_connectivity_state_set( - exec_ctx, &glb_policy->state_tracker, GRPC_CHANNEL_SHUTDOWN, - GRPC_ERROR_CREATE("Channel Shutdown"), "glb_shutdown"); - /* We need a copy of the lb_call pointer because we can't cancell the call - * while holding glb_policy->mu: lb_on_server_status_received, invoked due to - * the cancel, needs to acquire that same lock */ - grpc_call *lb_call = glb_policy->lb_call; - gpr_mu_unlock(&glb_policy->mu); - - /* glb_policy->lb_call and this local lb_call must be consistent at this point - * because glb_policy->lb_call is only assigned in lb_call_init_locked as part - * of query_for_backends_locked, which can only be invoked while - * glb_policy->shutting_down is false. */ - if (lb_call != NULL) { - grpc_call_cancel(lb_call, NULL); - /* lb_on_server_status_received will pick up the cancel and clean up */ - } - while (pp != NULL) { - pending_pick *next = pp->next; - *pp->target = NULL; - grpc_exec_ctx_sched(exec_ctx, &pp->wrapped_on_complete_arg.wrapper_closure, - GRPC_ERROR_NONE, NULL); - pp = next; - } - - while (pping != NULL) { - pending_ping *next = pping->next; - grpc_exec_ctx_sched(exec_ctx, &pping->wrapped_notify_arg.wrapper_closure, - GRPC_ERROR_NONE, NULL); - pping = next; - } -} - -static void glb_cancel_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, - grpc_connected_subchannel **target, - grpc_error *error) { - glb_lb_policy *glb_policy = (glb_lb_policy *)pol; - gpr_mu_lock(&glb_policy->mu); - pending_pick *pp = glb_policy->pending_picks; - glb_policy->pending_picks = NULL; - while (pp != NULL) { - pending_pick *next = pp->next; - if (pp->target == target) { - *target = NULL; - grpc_exec_ctx_sched( - exec_ctx, &pp->wrapped_on_complete_arg.wrapper_closure, - GRPC_ERROR_CREATE_REFERENCING("Pick Cancelled", &error, 1), NULL); - } else { - pp->next = glb_policy->pending_picks; - glb_policy->pending_picks = pp; - } - pp = next; - } - gpr_mu_unlock(&glb_policy->mu); - GRPC_ERROR_UNREF(error); -} - -static void glb_cancel_picks(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, - uint32_t initial_metadata_flags_mask, - uint32_t initial_metadata_flags_eq, - grpc_error *error) { - glb_lb_policy *glb_policy = (glb_lb_policy *)pol; - gpr_mu_lock(&glb_policy->mu); - pending_pick *pp = glb_policy->pending_picks; - glb_policy->pending_picks = NULL; - while (pp != NULL) { - pending_pick *next = pp->next; - if ((pp->pick_args.initial_metadata_flags & initial_metadata_flags_mask) == - initial_metadata_flags_eq) { - grpc_exec_ctx_sched( - exec_ctx, &pp->wrapped_on_complete_arg.wrapper_closure, - GRPC_ERROR_CREATE_REFERENCING("Pick Cancelled", &error, 1), NULL); - } else { - pp->next = glb_policy->pending_picks; - glb_policy->pending_picks = pp; - } - pp = next; - } - gpr_mu_unlock(&glb_policy->mu); - GRPC_ERROR_UNREF(error); -} - -static void query_for_backends_locked(grpc_exec_ctx *exec_ctx, - glb_lb_policy *glb_policy); -static void start_picking_locked(grpc_exec_ctx *exec_ctx, - glb_lb_policy *glb_policy) { - glb_policy->started_picking = true; - gpr_backoff_reset(&glb_policy->lb_call_backoff_state); - query_for_backends_locked(exec_ctx, glb_policy); -} - -static void glb_exit_idle(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) { - glb_lb_policy *glb_policy = (glb_lb_policy *)pol; - gpr_mu_lock(&glb_policy->mu); - if (!glb_policy->started_picking) { - start_picking_locked(exec_ctx, glb_policy); - } - gpr_mu_unlock(&glb_policy->mu); -} - -static int glb_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, - const grpc_lb_policy_pick_args *pick_args, - grpc_connected_subchannel **target, void **user_data, - grpc_closure *on_complete) { - if (pick_args->lb_token_mdelem_storage == NULL) { - *target = NULL; - grpc_exec_ctx_sched( - exec_ctx, on_complete, - GRPC_ERROR_CREATE("No mdelem storage for the LB token. Load reporting " - "won't work without it. Failing"), - NULL); - return 0; - } - - glb_lb_policy *glb_policy = (glb_lb_policy *)pol; - gpr_mu_lock(&glb_policy->mu); - glb_policy->deadline = pick_args->deadline; - bool pick_done; - - if (glb_policy->rr_policy != NULL) { - if (grpc_lb_glb_trace) { - gpr_log(GPR_INFO, "grpclb %p about to PICK from RR %p", - (void *)glb_policy, (void *)glb_policy->rr_policy); - } - GRPC_LB_POLICY_REF(glb_policy->rr_policy, "glb_pick"); - - wrapped_rr_closure_arg *wc_arg = gpr_malloc(sizeof(wrapped_rr_closure_arg)); - memset(wc_arg, 0, sizeof(wrapped_rr_closure_arg)); - - grpc_closure_init(&wc_arg->wrapper_closure, wrapped_rr_closure, wc_arg); - wc_arg->rr_policy = glb_policy->rr_policy; - wc_arg->target = target; - wc_arg->wrapped_closure = on_complete; - wc_arg->lb_token_mdelem_storage = pick_args->lb_token_mdelem_storage; - wc_arg->initial_metadata = pick_args->initial_metadata; - wc_arg->free_when_done = wc_arg; - pick_done = pick_from_internal_rr_locked(exec_ctx, glb_policy->rr_policy, - pick_args, target, wc_arg); - } else { - if (grpc_lb_glb_trace) { - gpr_log(GPR_DEBUG, - "No RR policy in grpclb instance %p. Adding to grpclb's pending " - "picks", - (void *)(glb_policy)); - } - add_pending_pick(&glb_policy->pending_picks, pick_args, target, - on_complete); - - if (!glb_policy->started_picking) { - start_picking_locked(exec_ctx, glb_policy); - } - pick_done = false; - } - gpr_mu_unlock(&glb_policy->mu); - return pick_done; -} - -static grpc_connectivity_state glb_check_connectivity( - grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, - grpc_error **connectivity_error) { - glb_lb_policy *glb_policy = (glb_lb_policy *)pol; - grpc_connectivity_state st; - gpr_mu_lock(&glb_policy->mu); - st = grpc_connectivity_state_check(&glb_policy->state_tracker, - connectivity_error); - gpr_mu_unlock(&glb_policy->mu); - return st; -} - -static void glb_ping_one(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, - grpc_closure *closure) { - glb_lb_policy *glb_policy = (glb_lb_policy *)pol; - gpr_mu_lock(&glb_policy->mu); - if (glb_policy->rr_policy) { - grpc_lb_policy_ping_one(exec_ctx, glb_policy->rr_policy, closure); - } else { - add_pending_ping(&glb_policy->pending_pings, closure); - if (!glb_policy->started_picking) { - start_picking_locked(exec_ctx, glb_policy); - } - } - gpr_mu_unlock(&glb_policy->mu); -} - -static void glb_notify_on_state_change(grpc_exec_ctx *exec_ctx, - grpc_lb_policy *pol, - grpc_connectivity_state *current, - grpc_closure *notify) { - glb_lb_policy *glb_policy = (glb_lb_policy *)pol; - gpr_mu_lock(&glb_policy->mu); - grpc_connectivity_state_notify_on_state_change( - exec_ctx, &glb_policy->state_tracker, current, notify); - - gpr_mu_unlock(&glb_policy->mu); -} - -static void lb_on_server_status_received(grpc_exec_ctx *exec_ctx, void *arg, - grpc_error *error); -static void lb_on_response_received(grpc_exec_ctx *exec_ctx, void *arg, - grpc_error *error); -static void lb_call_init_locked(glb_lb_policy *glb_policy) { - GPR_ASSERT(glb_policy->server_name != NULL); - GPR_ASSERT(glb_policy->server_name[0] != '\0'); - GPR_ASSERT(!glb_policy->shutting_down); - - /* Note the following LB call progresses every time there's activity in \a - * glb_policy->base.interested_parties, which is comprised of the polling - * entities from \a client_channel. */ - glb_policy->lb_call = grpc_channel_create_pollset_set_call( - glb_policy->lb_channel, NULL, GRPC_PROPAGATE_DEFAULTS, - glb_policy->base.interested_parties, - "/grpc.lb.v1.LoadBalancer/BalanceLoad", glb_policy->server_name, - glb_policy->deadline, NULL); - - grpc_metadata_array_init(&glb_policy->lb_initial_metadata_recv); - grpc_metadata_array_init(&glb_policy->lb_trailing_metadata_recv); - - grpc_grpclb_request *request = - grpc_grpclb_request_create(glb_policy->server_name); - grpc_slice request_payload_slice = grpc_grpclb_request_encode(request); - glb_policy->lb_request_payload = - grpc_raw_byte_buffer_create(&request_payload_slice, 1); - grpc_slice_unref(request_payload_slice); - grpc_grpclb_request_destroy(request); - - glb_policy->lb_call_status_details = NULL; - glb_policy->lb_call_status_details_capacity = 0; - - grpc_closure_init(&glb_policy->lb_on_server_status_received, - lb_on_server_status_received, glb_policy); - grpc_closure_init(&glb_policy->lb_on_response_received, - lb_on_response_received, glb_policy); - - gpr_backoff_init(&glb_policy->lb_call_backoff_state, - GRPC_GRPCLB_INITIAL_CONNECT_BACKOFF_SECONDS, - GRPC_GRPCLB_RECONNECT_BACKOFF_MULTIPLIER, - GRPC_GRPCLB_RECONNECT_JITTER, - GRPC_GRPCLB_MIN_CONNECT_TIMEOUT_SECONDS * 1000, - GRPC_GRPCLB_RECONNECT_MAX_BACKOFF_SECONDS * 1000); -} - -static void lb_call_destroy_locked(glb_lb_policy *glb_policy) { - GPR_ASSERT(glb_policy->lb_call != NULL); - grpc_call_destroy(glb_policy->lb_call); - glb_policy->lb_call = NULL; - - grpc_metadata_array_destroy(&glb_policy->lb_initial_metadata_recv); - grpc_metadata_array_destroy(&glb_policy->lb_trailing_metadata_recv); - - grpc_byte_buffer_destroy(glb_policy->lb_request_payload); - gpr_free(glb_policy->lb_call_status_details); -} - -/* - * Auxiliary functions and LB client callbacks. - */ -static void query_for_backends_locked(grpc_exec_ctx *exec_ctx, - glb_lb_policy *glb_policy) { - GPR_ASSERT(glb_policy->lb_channel != NULL); - if (glb_policy->shutting_down) return; - - lb_call_init_locked(glb_policy); - - if (grpc_lb_glb_trace) { - gpr_log(GPR_INFO, "Query for backends (grpclb: %p, lb_call: %p)", - (void *)glb_policy, (void *)glb_policy->lb_call); - } - GPR_ASSERT(glb_policy->lb_call != NULL); - - grpc_call_error call_error; - grpc_op ops[4]; - memset(ops, 0, sizeof(ops)); - - grpc_op *op = ops; - op->op = GRPC_OP_SEND_INITIAL_METADATA; - op->data.send_initial_metadata.count = 0; - op->flags = 0; - op->reserved = NULL; - op++; - - op->op = GRPC_OP_RECV_INITIAL_METADATA; - op->data.recv_initial_metadata = &glb_policy->lb_initial_metadata_recv; - op->flags = 0; - op->reserved = NULL; - op++; - - GPR_ASSERT(glb_policy->lb_request_payload != NULL); - op->op = GRPC_OP_SEND_MESSAGE; - op->data.send_message = glb_policy->lb_request_payload; - op->flags = 0; - op->reserved = NULL; - op++; - - op->op = GRPC_OP_RECV_STATUS_ON_CLIENT; - op->data.recv_status_on_client.trailing_metadata = - &glb_policy->lb_trailing_metadata_recv; - op->data.recv_status_on_client.status = &glb_policy->lb_call_status; - op->data.recv_status_on_client.status_details = - &glb_policy->lb_call_status_details; - op->data.recv_status_on_client.status_details_capacity = - &glb_policy->lb_call_status_details_capacity; - op->flags = 0; - op->reserved = NULL; - op++; - /* take a weak ref (won't prevent calling of \a glb_shutdown if the strong ref - * count goes to zero) to be unref'd in lb_on_server_status_received */ - GRPC_LB_POLICY_WEAK_REF(&glb_policy->base, "lb_on_server_status_received"); - call_error = grpc_call_start_batch_and_execute( - exec_ctx, glb_policy->lb_call, ops, (size_t)(op - ops), - &glb_policy->lb_on_server_status_received); - GPR_ASSERT(GRPC_CALL_OK == call_error); - - op = ops; - op->op = GRPC_OP_RECV_MESSAGE; - op->data.recv_message = &glb_policy->lb_response_payload; - op->flags = 0; - op->reserved = NULL; - op++; - /* take another weak ref to be unref'd in lb_on_response_received */ - GRPC_LB_POLICY_WEAK_REF(&glb_policy->base, "lb_on_response_received"); - call_error = grpc_call_start_batch_and_execute( - exec_ctx, glb_policy->lb_call, ops, (size_t)(op - ops), - &glb_policy->lb_on_response_received); - GPR_ASSERT(GRPC_CALL_OK == call_error); -} - -static void lb_on_response_received(grpc_exec_ctx *exec_ctx, void *arg, - grpc_error *error) { - glb_lb_policy *glb_policy = arg; - - grpc_op ops[2]; - memset(ops, 0, sizeof(ops)); - grpc_op *op = ops; - gpr_mu_lock(&glb_policy->mu); - if (glb_policy->lb_response_payload != NULL) { - gpr_backoff_reset(&glb_policy->lb_call_backoff_state); - /* Received data from the LB server. Look inside - * glb_policy->lb_response_payload, for a serverlist. */ - grpc_byte_buffer_reader bbr; - grpc_byte_buffer_reader_init(&bbr, glb_policy->lb_response_payload); - grpc_slice response_slice = grpc_byte_buffer_reader_readall(&bbr); - grpc_byte_buffer_destroy(glb_policy->lb_response_payload); - grpc_grpclb_serverlist *serverlist = - grpc_grpclb_response_parse_serverlist(response_slice); - if (serverlist != NULL) { - GPR_ASSERT(glb_policy->lb_call != NULL); - grpc_slice_unref(response_slice); - if (grpc_lb_glb_trace) { - gpr_log(GPR_INFO, "Serverlist with %lu servers received", - (unsigned long)serverlist->num_servers); - for (size_t i = 0; i < serverlist->num_servers; ++i) { - grpc_resolved_address addr; - parse_server(serverlist->servers[i], &addr); - char *ipport; - grpc_sockaddr_to_string(&ipport, &addr, false); - gpr_log(GPR_INFO, "Serverlist[%lu]: %s", (unsigned long)i, ipport); - gpr_free(ipport); - } - } - - /* update serverlist */ - if (serverlist->num_servers > 0) { - if (grpc_grpclb_serverlist_equals(glb_policy->serverlist, serverlist)) { - if (grpc_lb_glb_trace) { - gpr_log(GPR_INFO, - "Incoming server list identical to current, ignoring."); - } - grpc_grpclb_destroy_serverlist(serverlist); - } else { /* new serverlist */ - if (glb_policy->serverlist != NULL) { - /* dispose of the old serverlist */ - grpc_grpclb_destroy_serverlist(glb_policy->serverlist); - } - /* and update the copy in the glb_lb_policy instance. This serverlist - * instance will be destroyed either upon the next update or in - * glb_destroy() */ - glb_policy->serverlist = serverlist; - - rr_handover_locked(exec_ctx, glb_policy); - } - } else { - if (grpc_lb_glb_trace) { - gpr_log(GPR_INFO, - "Received empty server list. Picks will stay pending until a " - "response with > 0 servers is received"); - } - } - } else { /* serverlist == NULL */ - gpr_log(GPR_ERROR, "Invalid LB response received: '%s'. Ignoring.", - grpc_dump_slice(response_slice, GPR_DUMP_ASCII | GPR_DUMP_HEX)); - grpc_slice_unref(response_slice); - } - - if (!glb_policy->shutting_down) { - /* keep listening for serverlist updates */ - op->op = GRPC_OP_RECV_MESSAGE; - op->data.recv_message = &glb_policy->lb_response_payload; - op->flags = 0; - op->reserved = NULL; - op++; - /* reuse the "lb_on_response_received" weak ref taken in - * query_for_backends_locked() */ - const grpc_call_error call_error = grpc_call_start_batch_and_execute( - exec_ctx, glb_policy->lb_call, ops, (size_t)(op - ops), - &glb_policy->lb_on_response_received); /* loop */ - GPR_ASSERT(GRPC_CALL_OK == call_error); - } - gpr_mu_unlock(&glb_policy->mu); - } else { /* empty payload: call cancelled. */ - /* dispose of the "lb_on_response_received" weak ref taken in - * query_for_backends_locked() and reused in every reception loop */ - gpr_mu_unlock(&glb_policy->mu); - GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &glb_policy->base, - "lb_on_response_received_empty_payload"); - } -} - -static void lb_call_on_retry_timer(grpc_exec_ctx *exec_ctx, void *arg, - grpc_error *error) { - glb_lb_policy *glb_policy = arg; - gpr_mu_lock(&glb_policy->mu); - - if (!glb_policy->shutting_down) { - if (grpc_lb_glb_trace) { - gpr_log(GPR_INFO, "Restaring call to LB server (grpclb %p)", - (void *)glb_policy); - } - GPR_ASSERT(glb_policy->lb_call == NULL); - query_for_backends_locked(exec_ctx, glb_policy); - } - gpr_mu_unlock(&glb_policy->mu); - GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &glb_policy->base, - "grpclb_on_retry_timer"); -} - -static void lb_on_server_status_received(grpc_exec_ctx *exec_ctx, void *arg, - grpc_error *error) { - glb_lb_policy *glb_policy = arg; - gpr_mu_lock(&glb_policy->mu); - - GPR_ASSERT(glb_policy->lb_call != NULL); - - if (grpc_lb_glb_trace) { - gpr_log(GPR_DEBUG, - "Status from LB server received. Status = %d, Details = '%s', " - "(call: %p)", - glb_policy->lb_call_status, glb_policy->lb_call_status_details, - (void *)glb_policy->lb_call); - } - - /* We need to performe cleanups no matter what. */ - lb_call_destroy_locked(glb_policy); - - if (!glb_policy->shutting_down) { - /* if we aren't shutting down, restart the LB client call after some time */ - gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC); - gpr_timespec next_try = - gpr_backoff_step(&glb_policy->lb_call_backoff_state, now); - if (grpc_lb_glb_trace) { - gpr_log(GPR_DEBUG, "Connection to LB server lost (grpclb: %p)...", - (void *)glb_policy); - gpr_timespec timeout = gpr_time_sub(next_try, now); - if (gpr_time_cmp(timeout, gpr_time_0(timeout.clock_type)) > 0) { - gpr_log(GPR_DEBUG, "... retrying in %" PRId64 ".%09d seconds.", - timeout.tv_sec, timeout.tv_nsec); - } else { - gpr_log(GPR_DEBUG, "... retrying immediately."); - } - } - GRPC_LB_POLICY_WEAK_REF(&glb_policy->base, "grpclb_retry_timer"); - grpc_timer_init(exec_ctx, &glb_policy->lb_call_retry_timer, next_try, - lb_call_on_retry_timer, glb_policy, now); - } - gpr_mu_unlock(&glb_policy->mu); - GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &glb_policy->base, - "lb_on_server_status_received"); -} - -/* Code wiring the policy with the rest of the core */ -static const grpc_lb_policy_vtable glb_lb_policy_vtable = { - glb_destroy, glb_shutdown, glb_pick, - glb_cancel_pick, glb_cancel_picks, glb_ping_one, - glb_exit_idle, glb_check_connectivity, glb_notify_on_state_change}; - -static void glb_factory_ref(grpc_lb_policy_factory *factory) {} - -static void glb_factory_unref(grpc_lb_policy_factory *factory) {} - -static const grpc_lb_policy_factory_vtable glb_factory_vtable = { - glb_factory_ref, glb_factory_unref, glb_create, "grpclb"}; - -static grpc_lb_policy_factory glb_lb_policy_factory = {&glb_factory_vtable}; - -grpc_lb_policy_factory *grpc_glb_lb_factory_create() { - return &glb_lb_policy_factory; -} - -/* Plugin registration */ -void grpc_lb_policy_grpclb_init() { - grpc_register_lb_policy(grpc_glb_lb_factory_create()); - grpc_register_tracer("glb", &grpc_lb_glb_trace); -} - -void grpc_lb_policy_grpclb_shutdown() {} diff --git a/Sources/CgRPC/src/core/ext/lb_policy/grpclb/grpclb.h b/Sources/CgRPC/src/core/ext/lb_policy/grpclb/grpclb.h deleted file mode 100644 index ff23f3a54..000000000 --- a/Sources/CgRPC/src/core/ext/lb_policy/grpclb/grpclb.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * - * Copyright 2016, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#ifndef GRPC_CORE_EXT_LB_POLICY_GRPCLB_GRPCLB_H -#define GRPC_CORE_EXT_LB_POLICY_GRPCLB_GRPCLB_H - -#include "src/core/ext/client_channel/lb_policy_factory.h" - -/** Returns a load balancing factory for the glb policy, which tries to connect - * to a load balancing server to decide the next successfully connected - * subchannel to pick. */ -grpc_lb_policy_factory *grpc_glb_lb_factory_create(); - -#endif /* GRPC_CORE_EXT_LB_POLICY_GRPCLB_GRPCLB_H */ diff --git a/Sources/CgRPC/src/core/ext/lb_policy/grpclb/load_balancer_api.c b/Sources/CgRPC/src/core/ext/lb_policy/grpclb/load_balancer_api.c deleted file mode 100644 index 837e9c111..000000000 --- a/Sources/CgRPC/src/core/ext/lb_policy/grpclb/load_balancer_api.c +++ /dev/null @@ -1,252 +0,0 @@ -/* - * - * Copyright 2016, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include "src/core/ext/lb_policy/grpclb/load_balancer_api.h" -#include "third_party/nanopb/pb_decode.h" -#include "third_party/nanopb/pb_encode.h" - -#include - -typedef struct decode_serverlist_arg { - /* The first pass counts the number of servers in the server list. The second - * one allocates and decodes. */ - bool first_pass; - /* The decoding callback is invoked once per server in serverlist. Remember - * which index of the serverlist are we currently decoding */ - size_t decoding_idx; - /* Populated after the first pass. Number of server in the input serverlist */ - size_t num_servers; - /* The decoded serverlist */ - grpc_grpclb_server **servers; -} decode_serverlist_arg; - -/* invoked once for every Server in ServerList */ -static bool decode_serverlist(pb_istream_t *stream, const pb_field_t *field, - void **arg) { - decode_serverlist_arg *dec_arg = *arg; - if (dec_arg->first_pass) { /* count how many server do we have */ - grpc_grpclb_server server; - if (!pb_decode(stream, grpc_lb_v1_Server_fields, &server)) { - gpr_log(GPR_ERROR, "nanopb error: %s", PB_GET_ERROR(stream)); - return false; - } - dec_arg->num_servers++; - } else { /* second pass. Actually decode. */ - grpc_grpclb_server *server = gpr_malloc(sizeof(grpc_grpclb_server)); - memset(server, 0, sizeof(grpc_grpclb_server)); - GPR_ASSERT(dec_arg->num_servers > 0); - if (dec_arg->decoding_idx == 0) { /* first iteration of second pass */ - dec_arg->servers = - gpr_malloc(sizeof(grpc_grpclb_server *) * dec_arg->num_servers); - } - if (!pb_decode(stream, grpc_lb_v1_Server_fields, server)) { - gpr_log(GPR_ERROR, "nanopb error: %s", PB_GET_ERROR(stream)); - return false; - } - dec_arg->servers[dec_arg->decoding_idx++] = server; - } - - return true; -} - -grpc_grpclb_request *grpc_grpclb_request_create(const char *lb_service_name) { - grpc_grpclb_request *req = gpr_malloc(sizeof(grpc_grpclb_request)); - - req->has_client_stats = 0; /* TODO(dgq): add support for stats once defined */ - req->has_initial_request = 1; - req->initial_request.has_name = 1; - strncpy(req->initial_request.name, lb_service_name, - GRPC_GRPCLB_SERVICE_NAME_MAX_LENGTH); - return req; -} - -grpc_slice grpc_grpclb_request_encode(const grpc_grpclb_request *request) { - size_t encoded_length; - pb_ostream_t sizestream; - pb_ostream_t outputstream; - grpc_slice slice; - memset(&sizestream, 0, sizeof(pb_ostream_t)); - pb_encode(&sizestream, grpc_lb_v1_LoadBalanceRequest_fields, request); - encoded_length = sizestream.bytes_written; - - slice = grpc_slice_malloc(encoded_length); - outputstream = - pb_ostream_from_buffer(GRPC_SLICE_START_PTR(slice), encoded_length); - GPR_ASSERT(pb_encode(&outputstream, grpc_lb_v1_LoadBalanceRequest_fields, - request) != 0); - return slice; -} - -void grpc_grpclb_request_destroy(grpc_grpclb_request *request) { - gpr_free(request); -} - -typedef grpc_lb_v1_LoadBalanceResponse grpc_grpclb_response; -grpc_grpclb_initial_response *grpc_grpclb_initial_response_parse( - grpc_slice encoded_grpc_grpclb_response) { - pb_istream_t stream = - pb_istream_from_buffer(GRPC_SLICE_START_PTR(encoded_grpc_grpclb_response), - GRPC_SLICE_LENGTH(encoded_grpc_grpclb_response)); - grpc_grpclb_response res; - memset(&res, 0, sizeof(grpc_grpclb_response)); - if (!pb_decode(&stream, grpc_lb_v1_LoadBalanceResponse_fields, &res)) { - gpr_log(GPR_ERROR, "nanopb error: %s", PB_GET_ERROR(&stream)); - return NULL; - } - grpc_grpclb_initial_response *initial_res = - gpr_malloc(sizeof(grpc_grpclb_initial_response)); - memcpy(initial_res, &res.initial_response, - sizeof(grpc_grpclb_initial_response)); - - return initial_res; -} - -grpc_grpclb_serverlist *grpc_grpclb_response_parse_serverlist( - grpc_slice encoded_grpc_grpclb_response) { - bool status; - decode_serverlist_arg arg; - pb_istream_t stream = - pb_istream_from_buffer(GRPC_SLICE_START_PTR(encoded_grpc_grpclb_response), - GRPC_SLICE_LENGTH(encoded_grpc_grpclb_response)); - pb_istream_t stream_at_start = stream; - grpc_grpclb_response res; - memset(&res, 0, sizeof(grpc_grpclb_response)); - memset(&arg, 0, sizeof(decode_serverlist_arg)); - - res.server_list.servers.funcs.decode = decode_serverlist; - res.server_list.servers.arg = &arg; - arg.first_pass = true; - status = pb_decode(&stream, grpc_lb_v1_LoadBalanceResponse_fields, &res); - if (!status) { - gpr_log(GPR_ERROR, "nanopb error: %s", PB_GET_ERROR(&stream)); - return NULL; - } - - arg.first_pass = false; - status = - pb_decode(&stream_at_start, grpc_lb_v1_LoadBalanceResponse_fields, &res); - if (!status) { - gpr_log(GPR_ERROR, "nanopb error: %s", PB_GET_ERROR(&stream)); - return NULL; - } - - grpc_grpclb_serverlist *sl = gpr_malloc(sizeof(grpc_grpclb_serverlist)); - memset(sl, 0, sizeof(*sl)); - sl->num_servers = arg.num_servers; - sl->servers = arg.servers; - if (res.server_list.has_expiration_interval) { - sl->expiration_interval = res.server_list.expiration_interval; - } - return sl; -} - -void grpc_grpclb_destroy_serverlist(grpc_grpclb_serverlist *serverlist) { - if (serverlist == NULL) { - return; - } - for (size_t i = 0; i < serverlist->num_servers; i++) { - gpr_free(serverlist->servers[i]); - } - gpr_free(serverlist->servers); - gpr_free(serverlist); -} - -grpc_grpclb_serverlist *grpc_grpclb_serverlist_copy( - const grpc_grpclb_serverlist *sl) { - grpc_grpclb_serverlist *copy = gpr_malloc(sizeof(grpc_grpclb_serverlist)); - memset(copy, 0, sizeof(grpc_grpclb_serverlist)); - copy->num_servers = sl->num_servers; - memcpy(©->expiration_interval, &sl->expiration_interval, - sizeof(grpc_grpclb_duration)); - copy->servers = gpr_malloc(sizeof(grpc_grpclb_server *) * sl->num_servers); - for (size_t i = 0; i < sl->num_servers; i++) { - copy->servers[i] = gpr_malloc(sizeof(grpc_grpclb_server)); - memcpy(copy->servers[i], sl->servers[i], sizeof(grpc_grpclb_server)); - } - return copy; -} - -bool grpc_grpclb_serverlist_equals(const grpc_grpclb_serverlist *lhs, - const grpc_grpclb_serverlist *rhs) { - if ((lhs == NULL) || (rhs == NULL)) { - return false; - } - if (lhs->num_servers != rhs->num_servers) { - return false; - } - if (grpc_grpclb_duration_compare(&lhs->expiration_interval, - &rhs->expiration_interval) != 0) { - return false; - } - for (size_t i = 0; i < lhs->num_servers; i++) { - if (!grpc_grpclb_server_equals(lhs->servers[i], rhs->servers[i])) { - return false; - } - } - return true; -} - -bool grpc_grpclb_server_equals(const grpc_grpclb_server *lhs, - const grpc_grpclb_server *rhs) { - return memcmp(lhs, rhs, sizeof(grpc_grpclb_server)) == 0; -} - -int grpc_grpclb_duration_compare(const grpc_grpclb_duration *lhs, - const grpc_grpclb_duration *rhs) { - GPR_ASSERT(lhs && rhs); - if (lhs->has_seconds && rhs->has_seconds) { - if (lhs->seconds < rhs->seconds) return -1; - if (lhs->seconds > rhs->seconds) return 1; - } else if (lhs->has_seconds) { - return 1; - } else if (rhs->has_seconds) { - return -1; - } - - GPR_ASSERT(lhs->seconds == rhs->seconds); - if (lhs->has_nanos && rhs->has_nanos) { - if (lhs->nanos < rhs->nanos) return -1; - if (lhs->nanos > rhs->nanos) return 1; - } else if (lhs->has_nanos) { - return 1; - } else if (rhs->has_nanos) { - return -1; - } - - return 0; -} - -void grpc_grpclb_initial_response_destroy( - grpc_grpclb_initial_response *response) { - gpr_free(response); -} diff --git a/Sources/CgRPC/src/core/ext/lb_policy/pick_first/pick_first.c b/Sources/CgRPC/src/core/ext/lb_policy/pick_first/pick_first.c deleted file mode 100644 index b9cfe6b5c..000000000 --- a/Sources/CgRPC/src/core/ext/lb_policy/pick_first/pick_first.c +++ /dev/null @@ -1,510 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include - -#include - -#include "src/core/ext/client_channel/lb_policy_registry.h" -#include "src/core/lib/channel/channel_args.h" -#include "src/core/lib/transport/connectivity_state.h" - -typedef struct pending_pick { - struct pending_pick *next; - uint32_t initial_metadata_flags; - grpc_connected_subchannel **target; - grpc_closure *on_complete; -} pending_pick; - -typedef struct { - /** base policy: must be first */ - grpc_lb_policy base; - /** all our subchannels */ - grpc_subchannel **subchannels; - size_t num_subchannels; - - grpc_closure connectivity_changed; - - /** the selected channel (a grpc_connected_subchannel) */ - gpr_atm selected; - - /** mutex protecting remaining members */ - gpr_mu mu; - /** have we started picking? */ - int started_picking; - /** are we shut down? */ - int shutdown; - /** which subchannel are we watching? */ - size_t checking_subchannel; - /** what is the connectivity of that channel? */ - grpc_connectivity_state checking_connectivity; - /** list of picks that are waiting on connectivity */ - pending_pick *pending_picks; - - /** our connectivity state tracker */ - grpc_connectivity_state_tracker state_tracker; -} pick_first_lb_policy; - -#define GET_SELECTED(p) \ - ((grpc_connected_subchannel *)gpr_atm_acq_load(&(p)->selected)) - -static void pf_destroy(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) { - pick_first_lb_policy *p = (pick_first_lb_policy *)pol; - grpc_connected_subchannel *selected = GET_SELECTED(p); - size_t i; - GPR_ASSERT(p->pending_picks == NULL); - for (i = 0; i < p->num_subchannels; i++) { - GRPC_SUBCHANNEL_UNREF(exec_ctx, p->subchannels[i], "pick_first"); - } - if (selected != NULL) { - GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, selected, "picked_first"); - } - grpc_connectivity_state_destroy(exec_ctx, &p->state_tracker); - gpr_free(p->subchannels); - gpr_mu_destroy(&p->mu); - gpr_free(p); -} - -static void pf_shutdown(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) { - pick_first_lb_policy *p = (pick_first_lb_policy *)pol; - pending_pick *pp; - grpc_connected_subchannel *selected; - gpr_mu_lock(&p->mu); - selected = GET_SELECTED(p); - p->shutdown = 1; - pp = p->pending_picks; - p->pending_picks = NULL; - grpc_connectivity_state_set( - exec_ctx, &p->state_tracker, GRPC_CHANNEL_SHUTDOWN, - GRPC_ERROR_CREATE("Channel shutdown"), "shutdown"); - /* cancel subscription */ - if (selected != NULL) { - grpc_connected_subchannel_notify_on_state_change( - exec_ctx, selected, NULL, NULL, &p->connectivity_changed); - } else if (p->num_subchannels > 0) { - grpc_subchannel_notify_on_state_change( - exec_ctx, p->subchannels[p->checking_subchannel], NULL, NULL, - &p->connectivity_changed); - } - gpr_mu_unlock(&p->mu); - while (pp != NULL) { - pending_pick *next = pp->next; - *pp->target = NULL; - grpc_exec_ctx_sched(exec_ctx, pp->on_complete, GRPC_ERROR_NONE, NULL); - gpr_free(pp); - pp = next; - } -} - -static void pf_cancel_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, - grpc_connected_subchannel **target, - grpc_error *error) { - pick_first_lb_policy *p = (pick_first_lb_policy *)pol; - pending_pick *pp; - gpr_mu_lock(&p->mu); - pp = p->pending_picks; - p->pending_picks = NULL; - while (pp != NULL) { - pending_pick *next = pp->next; - if (pp->target == target) { - *target = NULL; - grpc_exec_ctx_sched( - exec_ctx, pp->on_complete, - GRPC_ERROR_CREATE_REFERENCING("Pick Cancelled", &error, 1), NULL); - gpr_free(pp); - } else { - pp->next = p->pending_picks; - p->pending_picks = pp; - } - pp = next; - } - gpr_mu_unlock(&p->mu); - GRPC_ERROR_UNREF(error); -} - -static void pf_cancel_picks(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, - uint32_t initial_metadata_flags_mask, - uint32_t initial_metadata_flags_eq, - grpc_error *error) { - pick_first_lb_policy *p = (pick_first_lb_policy *)pol; - pending_pick *pp; - gpr_mu_lock(&p->mu); - pp = p->pending_picks; - p->pending_picks = NULL; - while (pp != NULL) { - pending_pick *next = pp->next; - if ((pp->initial_metadata_flags & initial_metadata_flags_mask) == - initial_metadata_flags_eq) { - grpc_exec_ctx_sched( - exec_ctx, pp->on_complete, - GRPC_ERROR_CREATE_REFERENCING("Pick Cancelled", &error, 1), NULL); - gpr_free(pp); - } else { - pp->next = p->pending_picks; - p->pending_picks = pp; - } - pp = next; - } - gpr_mu_unlock(&p->mu); - GRPC_ERROR_UNREF(error); -} - -static void start_picking(grpc_exec_ctx *exec_ctx, pick_first_lb_policy *p) { - p->started_picking = 1; - p->checking_subchannel = 0; - p->checking_connectivity = GRPC_CHANNEL_IDLE; - GRPC_LB_POLICY_WEAK_REF(&p->base, "pick_first_connectivity"); - grpc_subchannel_notify_on_state_change( - exec_ctx, p->subchannels[p->checking_subchannel], - p->base.interested_parties, &p->checking_connectivity, - &p->connectivity_changed); -} - -static void pf_exit_idle(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) { - pick_first_lb_policy *p = (pick_first_lb_policy *)pol; - gpr_mu_lock(&p->mu); - if (!p->started_picking) { - start_picking(exec_ctx, p); - } - gpr_mu_unlock(&p->mu); -} - -static int pf_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, - const grpc_lb_policy_pick_args *pick_args, - grpc_connected_subchannel **target, void **user_data, - grpc_closure *on_complete) { - pick_first_lb_policy *p = (pick_first_lb_policy *)pol; - pending_pick *pp; - - /* Check atomically for a selected channel */ - grpc_connected_subchannel *selected = GET_SELECTED(p); - if (selected != NULL) { - *target = GRPC_CONNECTED_SUBCHANNEL_REF(selected, "picked"); - return 1; - } - - /* No subchannel selected yet, so acquire lock and then attempt again */ - gpr_mu_lock(&p->mu); - selected = GET_SELECTED(p); - if (selected) { - gpr_mu_unlock(&p->mu); - *target = GRPC_CONNECTED_SUBCHANNEL_REF(selected, "picked"); - return 1; - } else { - if (!p->started_picking) { - start_picking(exec_ctx, p); - } - pp = gpr_malloc(sizeof(*pp)); - pp->next = p->pending_picks; - pp->target = target; - pp->initial_metadata_flags = pick_args->initial_metadata_flags; - pp->on_complete = on_complete; - p->pending_picks = pp; - gpr_mu_unlock(&p->mu); - return 0; - } -} - -static void destroy_subchannels(grpc_exec_ctx *exec_ctx, void *arg, - grpc_error *error) { - pick_first_lb_policy *p = arg; - size_t i; - size_t num_subchannels = p->num_subchannels; - grpc_subchannel **subchannels; - - gpr_mu_lock(&p->mu); - subchannels = p->subchannels; - p->num_subchannels = 0; - p->subchannels = NULL; - gpr_mu_unlock(&p->mu); - GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "destroy_subchannels"); - - for (i = 0; i < num_subchannels; i++) { - GRPC_SUBCHANNEL_UNREF(exec_ctx, subchannels[i], "pick_first"); - } - - gpr_free(subchannels); -} - -static void pf_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg, - grpc_error *error) { - pick_first_lb_policy *p = arg; - grpc_subchannel *selected_subchannel; - pending_pick *pp; - grpc_connected_subchannel *selected; - - GRPC_ERROR_REF(error); - - gpr_mu_lock(&p->mu); - - selected = GET_SELECTED(p); - - if (p->shutdown) { - gpr_mu_unlock(&p->mu); - GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "pick_first_connectivity"); - GRPC_ERROR_UNREF(error); - return; - } else if (selected != NULL) { - if (p->checking_connectivity == GRPC_CHANNEL_TRANSIENT_FAILURE) { - /* if the selected channel goes bad, we're done */ - p->checking_connectivity = GRPC_CHANNEL_SHUTDOWN; - } - grpc_connectivity_state_set(exec_ctx, &p->state_tracker, - p->checking_connectivity, GRPC_ERROR_REF(error), - "selected_changed"); - if (p->checking_connectivity != GRPC_CHANNEL_SHUTDOWN) { - grpc_connected_subchannel_notify_on_state_change( - exec_ctx, selected, p->base.interested_parties, - &p->checking_connectivity, &p->connectivity_changed); - } else { - GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "pick_first_connectivity"); - } - } else { - loop: - switch (p->checking_connectivity) { - case GRPC_CHANNEL_INIT: - GPR_UNREACHABLE_CODE(return ); - case GRPC_CHANNEL_READY: - grpc_connectivity_state_set(exec_ctx, &p->state_tracker, - GRPC_CHANNEL_READY, GRPC_ERROR_NONE, - "connecting_ready"); - selected_subchannel = p->subchannels[p->checking_subchannel]; - selected = - grpc_subchannel_get_connected_subchannel(selected_subchannel); - GPR_ASSERT(selected != NULL); - GRPC_CONNECTED_SUBCHANNEL_REF(selected, "picked_first"); - /* drop the pick list: we are connected now */ - GRPC_LB_POLICY_WEAK_REF(&p->base, "destroy_subchannels"); - gpr_atm_rel_store(&p->selected, (gpr_atm)selected); - grpc_exec_ctx_sched(exec_ctx, - grpc_closure_create(destroy_subchannels, p), - GRPC_ERROR_NONE, NULL); - /* update any calls that were waiting for a pick */ - while ((pp = p->pending_picks)) { - p->pending_picks = pp->next; - *pp->target = GRPC_CONNECTED_SUBCHANNEL_REF(selected, "picked"); - grpc_exec_ctx_sched(exec_ctx, pp->on_complete, GRPC_ERROR_NONE, NULL); - gpr_free(pp); - } - grpc_connected_subchannel_notify_on_state_change( - exec_ctx, selected, p->base.interested_parties, - &p->checking_connectivity, &p->connectivity_changed); - break; - case GRPC_CHANNEL_TRANSIENT_FAILURE: - p->checking_subchannel = - (p->checking_subchannel + 1) % p->num_subchannels; - if (p->checking_subchannel == 0) { - /* only trigger transient failure when we've tried all alternatives */ - grpc_connectivity_state_set( - exec_ctx, &p->state_tracker, GRPC_CHANNEL_TRANSIENT_FAILURE, - GRPC_ERROR_REF(error), "connecting_transient_failure"); - } - GRPC_ERROR_UNREF(error); - p->checking_connectivity = grpc_subchannel_check_connectivity( - p->subchannels[p->checking_subchannel], &error); - if (p->checking_connectivity == GRPC_CHANNEL_TRANSIENT_FAILURE) { - grpc_subchannel_notify_on_state_change( - exec_ctx, p->subchannels[p->checking_subchannel], - p->base.interested_parties, &p->checking_connectivity, - &p->connectivity_changed); - } else { - goto loop; - } - break; - case GRPC_CHANNEL_CONNECTING: - case GRPC_CHANNEL_IDLE: - grpc_connectivity_state_set( - exec_ctx, &p->state_tracker, GRPC_CHANNEL_CONNECTING, - GRPC_ERROR_REF(error), "connecting_changed"); - grpc_subchannel_notify_on_state_change( - exec_ctx, p->subchannels[p->checking_subchannel], - p->base.interested_parties, &p->checking_connectivity, - &p->connectivity_changed); - break; - case GRPC_CHANNEL_SHUTDOWN: - p->num_subchannels--; - GPR_SWAP(grpc_subchannel *, p->subchannels[p->checking_subchannel], - p->subchannels[p->num_subchannels]); - GRPC_SUBCHANNEL_UNREF(exec_ctx, p->subchannels[p->num_subchannels], - "pick_first"); - if (p->num_subchannels == 0) { - grpc_connectivity_state_set( - exec_ctx, &p->state_tracker, GRPC_CHANNEL_SHUTDOWN, - GRPC_ERROR_CREATE_REFERENCING("Pick first exhausted channels", - &error, 1), - "no_more_channels"); - while ((pp = p->pending_picks)) { - p->pending_picks = pp->next; - *pp->target = NULL; - grpc_exec_ctx_sched(exec_ctx, pp->on_complete, GRPC_ERROR_NONE, - NULL); - gpr_free(pp); - } - GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, - "pick_first_connectivity"); - } else { - grpc_connectivity_state_set( - exec_ctx, &p->state_tracker, GRPC_CHANNEL_TRANSIENT_FAILURE, - GRPC_ERROR_REF(error), "subchannel_failed"); - p->checking_subchannel %= p->num_subchannels; - GRPC_ERROR_UNREF(error); - p->checking_connectivity = grpc_subchannel_check_connectivity( - p->subchannels[p->checking_subchannel], &error); - goto loop; - } - } - } - - gpr_mu_unlock(&p->mu); - - GRPC_ERROR_UNREF(error); -} - -static grpc_connectivity_state pf_check_connectivity(grpc_exec_ctx *exec_ctx, - grpc_lb_policy *pol, - grpc_error **error) { - pick_first_lb_policy *p = (pick_first_lb_policy *)pol; - grpc_connectivity_state st; - gpr_mu_lock(&p->mu); - st = grpc_connectivity_state_check(&p->state_tracker, error); - gpr_mu_unlock(&p->mu); - return st; -} - -static void pf_notify_on_state_change(grpc_exec_ctx *exec_ctx, - grpc_lb_policy *pol, - grpc_connectivity_state *current, - grpc_closure *notify) { - pick_first_lb_policy *p = (pick_first_lb_policy *)pol; - gpr_mu_lock(&p->mu); - grpc_connectivity_state_notify_on_state_change(exec_ctx, &p->state_tracker, - current, notify); - gpr_mu_unlock(&p->mu); -} - -static void pf_ping_one(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, - grpc_closure *closure) { - pick_first_lb_policy *p = (pick_first_lb_policy *)pol; - grpc_connected_subchannel *selected = GET_SELECTED(p); - if (selected) { - grpc_connected_subchannel_ping(exec_ctx, selected, closure); - } else { - grpc_exec_ctx_sched(exec_ctx, closure, GRPC_ERROR_CREATE("Not connected"), - NULL); - } -} - -static const grpc_lb_policy_vtable pick_first_lb_policy_vtable = { - pf_destroy, pf_shutdown, pf_pick, - pf_cancel_pick, pf_cancel_picks, pf_ping_one, - pf_exit_idle, pf_check_connectivity, pf_notify_on_state_change}; - -static void pick_first_factory_ref(grpc_lb_policy_factory *factory) {} - -static void pick_first_factory_unref(grpc_lb_policy_factory *factory) {} - -static grpc_lb_policy *create_pick_first(grpc_exec_ctx *exec_ctx, - grpc_lb_policy_factory *factory, - grpc_lb_policy_args *args) { - GPR_ASSERT(args->client_channel_factory != NULL); - - /* Find the number of backend addresses. We ignore balancer - * addresses, since we don't know how to handle them. */ - const grpc_arg *arg = - grpc_channel_args_find(args->args, GRPC_ARG_LB_ADDRESSES); - GPR_ASSERT(arg != NULL && arg->type == GRPC_ARG_POINTER); - grpc_lb_addresses *addresses = arg->value.pointer.p; - size_t num_addrs = 0; - for (size_t i = 0; i < addresses->num_addresses; i++) { - if (!addresses->addresses[i].is_balancer) ++num_addrs; - } - if (num_addrs == 0) return NULL; - - pick_first_lb_policy *p = gpr_malloc(sizeof(*p)); - memset(p, 0, sizeof(*p)); - - p->subchannels = gpr_malloc(sizeof(grpc_subchannel *) * num_addrs); - memset(p->subchannels, 0, sizeof(*p->subchannels) * num_addrs); - grpc_subchannel_args sc_args; - size_t subchannel_idx = 0; - for (size_t i = 0; i < addresses->num_addresses; i++) { - /* Skip balancer addresses, since we only know how to handle backends. */ - if (addresses->addresses[i].is_balancer) continue; - - if (addresses->addresses[i].user_data != NULL) { - gpr_log(GPR_ERROR, - "This LB policy doesn't support user data. It will be ignored"); - } - - memset(&sc_args, 0, sizeof(grpc_subchannel_args)); - sc_args.addr = &addresses->addresses[i].address; - sc_args.args = args->args; - - grpc_subchannel *subchannel = grpc_client_channel_factory_create_subchannel( - exec_ctx, args->client_channel_factory, &sc_args); - - if (subchannel != NULL) { - p->subchannels[subchannel_idx++] = subchannel; - } - } - if (subchannel_idx == 0) { - gpr_free(p->subchannels); - gpr_free(p); - return NULL; - } - p->num_subchannels = subchannel_idx; - - grpc_lb_policy_init(&p->base, &pick_first_lb_policy_vtable); - grpc_closure_init(&p->connectivity_changed, pf_connectivity_changed, p); - gpr_mu_init(&p->mu); - return &p->base; -} - -static const grpc_lb_policy_factory_vtable pick_first_factory_vtable = { - pick_first_factory_ref, pick_first_factory_unref, create_pick_first, - "pick_first"}; - -static grpc_lb_policy_factory pick_first_lb_policy_factory = { - &pick_first_factory_vtable}; - -static grpc_lb_policy_factory *pick_first_lb_factory_create() { - return &pick_first_lb_policy_factory; -} - -/* Plugin registration */ - -void grpc_lb_policy_pick_first_init() { - grpc_register_lb_policy(pick_first_lb_factory_create()); -} - -void grpc_lb_policy_pick_first_shutdown() {} diff --git a/Sources/CgRPC/src/core/ext/lb_policy/round_robin/round_robin.c b/Sources/CgRPC/src/core/ext/lb_policy/round_robin/round_robin.c deleted file mode 100644 index f0305473d..000000000 --- a/Sources/CgRPC/src/core/ext/lb_policy/round_robin/round_robin.c +++ /dev/null @@ -1,799 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -/** Round Robin Policy. - * - * This policy keeps: - * - A circular list of ready (connected) subchannels, the *readylist*. An empty - * readylist consists solely of its root (dummy) node. - * - A pointer to the last element picked from the readylist, the *lastpick*. - * Initially set to point to the readylist's root. - * - * Behavior: - * - When a subchannel connects, it's *prepended* to the readylist's root node. - * Ie, if readylist = A <-> B <-> ROOT <-> C - * ^ ^ - * |____________________| - * and subchannel D becomes connected, the addition of D to the readylist - * results in readylist = A <-> B <-> D <-> ROOT <-> C - * ^ ^ - * |__________________________| - * - When a subchannel disconnects, it's removed from the readylist. If the - * subchannel being removed was the most recently picked, the *lastpick* - * pointer moves to the removed node's previous element. Note that if the - * readylist only had one element, this is still legal, as the lastpick would - * point to the dummy root node, for an empty readylist. - * - Upon picking, *lastpick* is updated to point to the returned (connected) - * subchannel. Note that it's possible that the selected subchannel becomes - * disconnected in the interim between the selection and the actual usage of - * the subchannel by the caller. - */ - -#include - -#include - -#include "src/core/ext/client_channel/lb_policy_registry.h" -#include "src/core/lib/channel/channel_args.h" -#include "src/core/lib/debug/trace.h" -#include "src/core/lib/transport/connectivity_state.h" -#include "src/core/lib/transport/static_metadata.h" - -typedef struct round_robin_lb_policy round_robin_lb_policy; - -int grpc_lb_round_robin_trace = 0; - -/** List of entities waiting for a pick. - * - * Once a pick is available, \a target is updated and \a on_complete called. */ -typedef struct pending_pick { - struct pending_pick *next; - - /* output argument where to store the pick()ed user_data. It'll be NULL if no - * such data is present or there's an error (the definite test for errors is - * \a target being NULL). */ - void **user_data; - - /* bitmask passed to pick() and used for selective cancelling. See - * grpc_lb_policy_cancel_picks() */ - uint32_t initial_metadata_flags; - - /* output argument where to store the pick()ed connected subchannel, or NULL - * upon error. */ - grpc_connected_subchannel **target; - - /* to be invoked once the pick() has completed (regardless of success) */ - grpc_closure *on_complete; -} pending_pick; - -/** List of subchannels in a connectivity READY state */ -typedef struct ready_list { - grpc_subchannel *subchannel; - /* references namesake entry in subchannel_data */ - void *user_data; - struct ready_list *next; - struct ready_list *prev; -} ready_list; - -typedef struct { - /** index within policy->subchannels */ - size_t index; - /** backpointer to owning policy */ - round_robin_lb_policy *policy; - /** subchannel itself */ - grpc_subchannel *subchannel; - /** notification that connectivity has changed on subchannel */ - grpc_closure connectivity_changed_closure; - /** this subchannels current position in subchannel->ready_list */ - ready_list *ready_list_node; - /** last observed connectivity. Not updated by - * \a grpc_subchannel_notify_on_state_change. Used to determine the previous - * state while processing the new state in \a rr_connectivity_changed */ - grpc_connectivity_state prev_connectivity_state; - /** current connectivity state. Updated by \a - * grpc_subchannel_notify_on_state_change */ - grpc_connectivity_state curr_connectivity_state; - /** the subchannel's target user data */ - void *user_data; - /** vtable to operate over \a user_data */ - const grpc_lb_user_data_vtable *user_data_vtable; -} subchannel_data; - -struct round_robin_lb_policy { - /** base policy: must be first */ - grpc_lb_policy base; - gpr_mu mu; - - /** total number of addresses received at creation time */ - size_t num_addresses; - - /** all our subchannels */ - size_t num_subchannels; - subchannel_data **subchannels; - - /** how many subchannels are in TRANSIENT_FAILURE */ - size_t num_transient_failures; - /** how many subchannels are IDLE */ - size_t num_idle; - - /** have we started picking? */ - int started_picking; - /** are we shutting down? */ - int shutdown; - /** List of picks that are waiting on connectivity */ - pending_pick *pending_picks; - - /** our connectivity state tracker */ - grpc_connectivity_state_tracker state_tracker; - - /** (Dummy) root of the doubly linked list containing READY subchannels */ - ready_list ready_list; - /** Last pick from the ready list. */ - ready_list *ready_list_last_pick; -}; - -/** Returns the next subchannel from the connected list or NULL if the list is - * empty. - * - * Note that this function does *not* advance p->ready_list_last_pick. Use \a - * advance_last_picked_locked() for that. */ -static ready_list *peek_next_connected_locked(const round_robin_lb_policy *p) { - ready_list *selected; - selected = p->ready_list_last_pick->next; - - while (selected != NULL) { - if (selected == &p->ready_list) { - GPR_ASSERT(selected->subchannel == NULL); - /* skip dummy root */ - selected = selected->next; - } else { - GPR_ASSERT(selected->subchannel != NULL); - return selected; - } - } - return NULL; -} - -/** Advance the \a ready_list picking head. */ -static void advance_last_picked_locked(round_robin_lb_policy *p) { - if (p->ready_list_last_pick->next != NULL) { /* non-empty list */ - p->ready_list_last_pick = p->ready_list_last_pick->next; - if (p->ready_list_last_pick == &p->ready_list) { - /* skip dummy root */ - p->ready_list_last_pick = p->ready_list_last_pick->next; - } - } else { /* should be an empty list */ - GPR_ASSERT(p->ready_list_last_pick == &p->ready_list); - } - - if (grpc_lb_round_robin_trace) { - gpr_log(GPR_DEBUG, - "[READYLIST, RR: %p] ADVANCED LAST PICK. NOW AT NODE %p (SC %p, " - "CSC %p)", - (void *)p, (void *)p->ready_list_last_pick, - (void *)p->ready_list_last_pick->subchannel, - (void *)grpc_subchannel_get_connected_subchannel( - p->ready_list_last_pick->subchannel)); - } -} - -/** Prepends (relative to the root at p->ready_list) the connected subchannel \a - * csc to the list of ready subchannels. */ -static ready_list *add_connected_sc_locked(round_robin_lb_policy *p, - subchannel_data *sd) { - ready_list *new_elem = gpr_malloc(sizeof(ready_list)); - memset(new_elem, 0, sizeof(ready_list)); - new_elem->subchannel = sd->subchannel; - new_elem->user_data = sd->user_data; - if (p->ready_list.prev == NULL) { - /* first element */ - new_elem->next = &p->ready_list; - new_elem->prev = &p->ready_list; - p->ready_list.next = new_elem; - p->ready_list.prev = new_elem; - } else { - new_elem->next = &p->ready_list; - new_elem->prev = p->ready_list.prev; - p->ready_list.prev->next = new_elem; - p->ready_list.prev = new_elem; - } - if (grpc_lb_round_robin_trace) { - gpr_log(GPR_DEBUG, "[READYLIST] ADDING NODE %p (Conn. SC %p)", - (void *)new_elem, (void *)sd->subchannel); - } - return new_elem; -} - -/** Removes \a node from the list of connected subchannels */ -static void remove_disconnected_sc_locked(round_robin_lb_policy *p, - ready_list *node) { - if (node == NULL) { - return; - } - if (node == p->ready_list_last_pick) { - p->ready_list_last_pick = p->ready_list_last_pick->prev; - } - - /* removing last item */ - if (node->next == &p->ready_list && node->prev == &p->ready_list) { - GPR_ASSERT(p->ready_list.next == node); - GPR_ASSERT(p->ready_list.prev == node); - p->ready_list.next = NULL; - p->ready_list.prev = NULL; - } else { - node->prev->next = node->next; - node->next->prev = node->prev; - } - - if (grpc_lb_round_robin_trace) { - gpr_log(GPR_DEBUG, "[READYLIST] REMOVED NODE %p (SC %p)", (void *)node, - (void *)node->subchannel); - } - - node->next = NULL; - node->prev = NULL; - node->subchannel = NULL; - - gpr_free(node); -} - -static bool is_ready_list_empty(round_robin_lb_policy *p) { - return p->ready_list.prev == NULL; -} - -static void rr_destroy(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) { - round_robin_lb_policy *p = (round_robin_lb_policy *)pol; - ready_list *elem; - - if (grpc_lb_round_robin_trace) { - gpr_log(GPR_DEBUG, "Destroying Round Robin policy at %p", (void *)pol); - } - - for (size_t i = 0; i < p->num_subchannels; i++) { - subchannel_data *sd = p->subchannels[i]; - GRPC_SUBCHANNEL_UNREF(exec_ctx, sd->subchannel, "rr_destroy"); - if (sd->user_data != NULL) { - GPR_ASSERT(sd->user_data_vtable != NULL); - sd->user_data_vtable->destroy(sd->user_data); - } - gpr_free(sd); - } - - grpc_connectivity_state_destroy(exec_ctx, &p->state_tracker); - gpr_free(p->subchannels); - gpr_mu_destroy(&p->mu); - - elem = p->ready_list.next; - while (elem != NULL && elem != &p->ready_list) { - ready_list *tmp; - tmp = elem->next; - elem->next = NULL; - elem->prev = NULL; - elem->subchannel = NULL; - gpr_free(elem); - elem = tmp; - } - - gpr_free(p); -} - -static void rr_shutdown(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) { - round_robin_lb_policy *p = (round_robin_lb_policy *)pol; - pending_pick *pp; - size_t i; - - gpr_mu_lock(&p->mu); - if (grpc_lb_round_robin_trace) { - gpr_log(GPR_DEBUG, "Shutting down Round Robin policy at %p", (void *)pol); - } - - p->shutdown = 1; - while ((pp = p->pending_picks)) { - p->pending_picks = pp->next; - *pp->target = NULL; - grpc_exec_ctx_sched(exec_ctx, pp->on_complete, - GRPC_ERROR_CREATE("Channel Shutdown"), NULL); - gpr_free(pp); - } - grpc_connectivity_state_set( - exec_ctx, &p->state_tracker, GRPC_CHANNEL_SHUTDOWN, - GRPC_ERROR_CREATE("Channel Shutdown"), "rr_shutdown"); - for (i = 0; i < p->num_subchannels; i++) { - subchannel_data *sd = p->subchannels[i]; - grpc_subchannel_notify_on_state_change(exec_ctx, sd->subchannel, NULL, NULL, - &sd->connectivity_changed_closure); - } - gpr_mu_unlock(&p->mu); -} - -static void rr_cancel_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, - grpc_connected_subchannel **target, - grpc_error *error) { - round_robin_lb_policy *p = (round_robin_lb_policy *)pol; - pending_pick *pp; - gpr_mu_lock(&p->mu); - pp = p->pending_picks; - p->pending_picks = NULL; - while (pp != NULL) { - pending_pick *next = pp->next; - if (pp->target == target) { - *target = NULL; - grpc_exec_ctx_sched( - exec_ctx, pp->on_complete, - GRPC_ERROR_CREATE_REFERENCING("Pick cancelled", &error, 1), NULL); - gpr_free(pp); - } else { - pp->next = p->pending_picks; - p->pending_picks = pp; - } - pp = next; - } - gpr_mu_unlock(&p->mu); - GRPC_ERROR_UNREF(error); -} - -static void rr_cancel_picks(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, - uint32_t initial_metadata_flags_mask, - uint32_t initial_metadata_flags_eq, - grpc_error *error) { - round_robin_lb_policy *p = (round_robin_lb_policy *)pol; - pending_pick *pp; - gpr_mu_lock(&p->mu); - pp = p->pending_picks; - p->pending_picks = NULL; - while (pp != NULL) { - pending_pick *next = pp->next; - if ((pp->initial_metadata_flags & initial_metadata_flags_mask) == - initial_metadata_flags_eq) { - *pp->target = NULL; - grpc_exec_ctx_sched( - exec_ctx, pp->on_complete, - GRPC_ERROR_CREATE_REFERENCING("Pick cancelled", &error, 1), NULL); - gpr_free(pp); - } else { - pp->next = p->pending_picks; - p->pending_picks = pp; - } - pp = next; - } - gpr_mu_unlock(&p->mu); - GRPC_ERROR_UNREF(error); -} - -static void start_picking(grpc_exec_ctx *exec_ctx, round_robin_lb_policy *p) { - size_t i; - p->started_picking = 1; - - for (i = 0; i < p->num_subchannels; i++) { - subchannel_data *sd = p->subchannels[i]; - /* use some sentinel value outside of the range of grpc_connectivity_state - * to signal an undefined previous state. We won't be referring to this - * value again and it'll be overwritten after the first call to - * rr_connectivity_changed */ - sd->prev_connectivity_state = GRPC_CHANNEL_INIT; - sd->curr_connectivity_state = GRPC_CHANNEL_IDLE; - GRPC_LB_POLICY_WEAK_REF(&p->base, "rr_connectivity"); - grpc_subchannel_notify_on_state_change( - exec_ctx, sd->subchannel, p->base.interested_parties, - &sd->curr_connectivity_state, &sd->connectivity_changed_closure); - } -} - -static void rr_exit_idle(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) { - round_robin_lb_policy *p = (round_robin_lb_policy *)pol; - gpr_mu_lock(&p->mu); - if (!p->started_picking) { - start_picking(exec_ctx, p); - } - gpr_mu_unlock(&p->mu); -} - -static int rr_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, - const grpc_lb_policy_pick_args *pick_args, - grpc_connected_subchannel **target, void **user_data, - grpc_closure *on_complete) { - round_robin_lb_policy *p = (round_robin_lb_policy *)pol; - pending_pick *pp; - ready_list *selected; - gpr_mu_lock(&p->mu); - - if (grpc_lb_round_robin_trace) { - gpr_log(GPR_INFO, "Round Robin %p trying to pick", (void *)pol); - } - - if ((selected = peek_next_connected_locked(p))) { - /* readily available, report right away */ - *target = GRPC_CONNECTED_SUBCHANNEL_REF( - grpc_subchannel_get_connected_subchannel(selected->subchannel), - "rr_picked"); - - if (user_data != NULL) { - *user_data = selected->user_data; - } - if (grpc_lb_round_robin_trace) { - gpr_log(GPR_DEBUG, - "[RR PICK] TARGET <-- CONNECTED SUBCHANNEL %p (NODE %p)", - (void *)*target, (void *)selected); - } - /* only advance the last picked pointer if the selection was used */ - advance_last_picked_locked(p); - gpr_mu_unlock(&p->mu); - return 1; - } else { - /* no pick currently available. Save for later in list of pending picks */ - if (!p->started_picking) { - start_picking(exec_ctx, p); - } - pp = gpr_malloc(sizeof(*pp)); - pp->next = p->pending_picks; - pp->target = target; - pp->on_complete = on_complete; - pp->initial_metadata_flags = pick_args->initial_metadata_flags; - pp->user_data = user_data; - p->pending_picks = pp; - gpr_mu_unlock(&p->mu); - return 0; - } -} - -static void update_state_counters(subchannel_data *sd) { - round_robin_lb_policy *p = sd->policy; - - /* update p->num_transient_failures (resp. p->num_idle): if the previous - * state was TRANSIENT_FAILURE (resp. IDLE), decrement - * p->num_transient_failures (resp. p->num_idle). */ - if (sd->prev_connectivity_state == GRPC_CHANNEL_TRANSIENT_FAILURE) { - GPR_ASSERT(p->num_transient_failures > 0); - --p->num_transient_failures; - } else if (sd->prev_connectivity_state == GRPC_CHANNEL_IDLE) { - GPR_ASSERT(p->num_idle > 0); - --p->num_idle; - } -} - -/* sd is the subchannel_data associted with the updated subchannel. - * shutdown_error will only be used upon policy transition to TRANSIENT_FAILURE - * or SHUTDOWN */ -static grpc_connectivity_state update_lb_connectivity_status( - grpc_exec_ctx *exec_ctx, subchannel_data *sd, grpc_error *error) { - /* In priority order. The first rule to match terminates the search (ie, if we - * are on rule n, all previous rules were unfulfilled). - * - * 1) RULE: ANY subchannel is READY => policy is READY. - * CHECK: At least one subchannel is ready iff p->ready_list is NOT empty. - * - * 2) RULE: ANY subchannel is CONNECTING => policy is CONNECTING. - * CHECK: sd->curr_connectivity_state == CONNECTING. - * - * 3) RULE: ALL subchannels are SHUTDOWN => policy is SHUTDOWN. - * CHECK: p->num_subchannels = 0. - * - * 4) RULE: ALL subchannels are TRANSIENT_FAILURE => policy is - * TRANSIENT_FAILURE. - * CHECK: p->num_transient_failures == p->num_subchannels. - * - * 5) RULE: ALL subchannels are IDLE => policy is IDLE. - * CHECK: p->num_idle == p->num_subchannels. - */ - round_robin_lb_policy *p = sd->policy; - if (!is_ready_list_empty(p)) { /* 1) READY */ - grpc_connectivity_state_set(exec_ctx, &p->state_tracker, GRPC_CHANNEL_READY, - GRPC_ERROR_NONE, "rr_ready"); - return GRPC_CHANNEL_READY; - } else if (sd->curr_connectivity_state == - GRPC_CHANNEL_CONNECTING) { /* 2) CONNECTING */ - grpc_connectivity_state_set(exec_ctx, &p->state_tracker, - GRPC_CHANNEL_CONNECTING, GRPC_ERROR_NONE, - "rr_connecting"); - return GRPC_CHANNEL_CONNECTING; - } else if (p->num_subchannels == 0) { /* 3) SHUTDOWN */ - grpc_connectivity_state_set(exec_ctx, &p->state_tracker, - GRPC_CHANNEL_SHUTDOWN, GRPC_ERROR_REF(error), - "rr_shutdown"); - return GRPC_CHANNEL_SHUTDOWN; - } else if (p->num_transient_failures == - p->num_subchannels) { /* 4) TRANSIENT_FAILURE */ - grpc_connectivity_state_set(exec_ctx, &p->state_tracker, - GRPC_CHANNEL_TRANSIENT_FAILURE, - GRPC_ERROR_REF(error), "rr_transient_failure"); - return GRPC_CHANNEL_TRANSIENT_FAILURE; - } else if (p->num_idle == p->num_subchannels) { /* 5) IDLE */ - grpc_connectivity_state_set(exec_ctx, &p->state_tracker, GRPC_CHANNEL_IDLE, - GRPC_ERROR_NONE, "rr_idle"); - return GRPC_CHANNEL_IDLE; - } - /* no change */ - return sd->curr_connectivity_state; -} - -static void rr_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg, - grpc_error *error) { - subchannel_data *sd = arg; - round_robin_lb_policy *p = sd->policy; - pending_pick *pp; - - GRPC_ERROR_REF(error); - gpr_mu_lock(&p->mu); - - if (p->shutdown) { - gpr_mu_unlock(&p->mu); - GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "rr_connectivity"); - GRPC_ERROR_UNREF(error); - return; - } - switch (sd->curr_connectivity_state) { - case GRPC_CHANNEL_INIT: - GPR_UNREACHABLE_CODE(return ); - case GRPC_CHANNEL_READY: - /* add the newly connected subchannel to the list of connected ones. - * Note that it goes to the "end of the line". */ - sd->ready_list_node = add_connected_sc_locked(p, sd); - /* at this point we know there's at least one suitable subchannel. Go - * ahead and pick one and notify the pending suitors in - * p->pending_picks. This preemtively replicates rr_pick()'s actions. */ - ready_list *selected = peek_next_connected_locked(p); - GPR_ASSERT(selected != NULL); - if (p->pending_picks != NULL) { - /* if the selected subchannel is going to be used for the pending - * picks, update the last picked pointer */ - advance_last_picked_locked(p); - } - while ((pp = p->pending_picks)) { - p->pending_picks = pp->next; - *pp->target = GRPC_CONNECTED_SUBCHANNEL_REF( - grpc_subchannel_get_connected_subchannel(selected->subchannel), - "rr_picked"); - if (pp->user_data != NULL) { - *pp->user_data = selected->user_data; - } - if (grpc_lb_round_robin_trace) { - gpr_log(GPR_DEBUG, - "[RR CONN CHANGED] TARGET <-- SUBCHANNEL %p (NODE %p)", - (void *)selected->subchannel, (void *)selected); - } - grpc_exec_ctx_sched(exec_ctx, pp->on_complete, GRPC_ERROR_NONE, NULL); - gpr_free(pp); - } - update_lb_connectivity_status(exec_ctx, sd, error); - sd->prev_connectivity_state = sd->curr_connectivity_state; - /* renew notification: reuses the "rr_connectivity" weak ref */ - grpc_subchannel_notify_on_state_change( - exec_ctx, sd->subchannel, p->base.interested_parties, - &sd->curr_connectivity_state, &sd->connectivity_changed_closure); - break; - case GRPC_CHANNEL_IDLE: - ++p->num_idle; - /* fallthrough */ - case GRPC_CHANNEL_CONNECTING: - update_state_counters(sd); - update_lb_connectivity_status(exec_ctx, sd, error); - sd->prev_connectivity_state = sd->curr_connectivity_state; - /* renew notification: reuses the "rr_connectivity" weak ref */ - grpc_subchannel_notify_on_state_change( - exec_ctx, sd->subchannel, p->base.interested_parties, - &sd->curr_connectivity_state, &sd->connectivity_changed_closure); - break; - case GRPC_CHANNEL_TRANSIENT_FAILURE: - ++p->num_transient_failures; - /* remove from ready list if still present */ - if (sd->ready_list_node != NULL) { - remove_disconnected_sc_locked(p, sd->ready_list_node); - sd->ready_list_node = NULL; - } - update_lb_connectivity_status(exec_ctx, sd, error); - sd->prev_connectivity_state = sd->curr_connectivity_state; - /* renew notification: reuses the "rr_connectivity" weak ref */ - grpc_subchannel_notify_on_state_change( - exec_ctx, sd->subchannel, p->base.interested_parties, - &sd->curr_connectivity_state, &sd->connectivity_changed_closure); - break; - case GRPC_CHANNEL_SHUTDOWN: - update_state_counters(sd); - if (sd->ready_list_node != NULL) { - remove_disconnected_sc_locked(p, sd->ready_list_node); - sd->ready_list_node = NULL; - } - --p->num_subchannels; - GPR_SWAP(subchannel_data *, p->subchannels[sd->index], - p->subchannels[p->num_subchannels]); - GRPC_SUBCHANNEL_UNREF(exec_ctx, sd->subchannel, "rr_subchannel_shutdown"); - p->subchannels[sd->index]->index = sd->index; - if (update_lb_connectivity_status(exec_ctx, sd, error) == - GRPC_CHANNEL_SHUTDOWN) { - /* the policy is shutting down. Flush all the pending picks... */ - while ((pp = p->pending_picks)) { - p->pending_picks = pp->next; - *pp->target = NULL; - grpc_exec_ctx_sched(exec_ctx, pp->on_complete, GRPC_ERROR_NONE, NULL); - gpr_free(pp); - } - } - gpr_free(sd); - /* unref the "rr_connectivity" weak ref from start_picking */ - GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "rr_connectivity"); - break; - } - gpr_mu_unlock(&p->mu); - GRPC_ERROR_UNREF(error); -} - -static grpc_connectivity_state rr_check_connectivity(grpc_exec_ctx *exec_ctx, - grpc_lb_policy *pol, - grpc_error **error) { - round_robin_lb_policy *p = (round_robin_lb_policy *)pol; - grpc_connectivity_state st; - gpr_mu_lock(&p->mu); - st = grpc_connectivity_state_check(&p->state_tracker, error); - gpr_mu_unlock(&p->mu); - return st; -} - -static void rr_notify_on_state_change(grpc_exec_ctx *exec_ctx, - grpc_lb_policy *pol, - grpc_connectivity_state *current, - grpc_closure *notify) { - round_robin_lb_policy *p = (round_robin_lb_policy *)pol; - gpr_mu_lock(&p->mu); - grpc_connectivity_state_notify_on_state_change(exec_ctx, &p->state_tracker, - current, notify); - gpr_mu_unlock(&p->mu); -} - -static void rr_ping_one(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, - grpc_closure *closure) { - round_robin_lb_policy *p = (round_robin_lb_policy *)pol; - ready_list *selected; - grpc_connected_subchannel *target; - gpr_mu_lock(&p->mu); - if ((selected = peek_next_connected_locked(p))) { - gpr_mu_unlock(&p->mu); - target = GRPC_CONNECTED_SUBCHANNEL_REF( - grpc_subchannel_get_connected_subchannel(selected->subchannel), - "rr_picked"); - grpc_connected_subchannel_ping(exec_ctx, target, closure); - GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, target, "rr_picked"); - } else { - gpr_mu_unlock(&p->mu); - grpc_exec_ctx_sched(exec_ctx, closure, - GRPC_ERROR_CREATE("Round Robin not connected"), NULL); - } -} - -static const grpc_lb_policy_vtable round_robin_lb_policy_vtable = { - rr_destroy, rr_shutdown, rr_pick, - rr_cancel_pick, rr_cancel_picks, rr_ping_one, - rr_exit_idle, rr_check_connectivity, rr_notify_on_state_change}; - -static void round_robin_factory_ref(grpc_lb_policy_factory *factory) {} - -static void round_robin_factory_unref(grpc_lb_policy_factory *factory) {} - -static grpc_lb_policy *round_robin_create(grpc_exec_ctx *exec_ctx, - grpc_lb_policy_factory *factory, - grpc_lb_policy_args *args) { - GPR_ASSERT(args->client_channel_factory != NULL); - - /* Find the number of backend addresses. We ignore balancer - * addresses, since we don't know how to handle them. */ - const grpc_arg *arg = - grpc_channel_args_find(args->args, GRPC_ARG_LB_ADDRESSES); - GPR_ASSERT(arg != NULL && arg->type == GRPC_ARG_POINTER); - grpc_lb_addresses *addresses = arg->value.pointer.p; - size_t num_addrs = 0; - for (size_t i = 0; i < addresses->num_addresses; i++) { - if (!addresses->addresses[i].is_balancer) ++num_addrs; - } - if (num_addrs == 0) return NULL; - - round_robin_lb_policy *p = gpr_malloc(sizeof(*p)); - memset(p, 0, sizeof(*p)); - - p->num_addresses = num_addrs; - p->subchannels = gpr_malloc(sizeof(*p->subchannels) * num_addrs); - memset(p->subchannels, 0, sizeof(*p->subchannels) * num_addrs); - - grpc_subchannel_args sc_args; - size_t subchannel_idx = 0; - for (size_t i = 0; i < addresses->num_addresses; i++) { - /* Skip balancer addresses, since we only know how to handle backends. */ - if (addresses->addresses[i].is_balancer) continue; - - memset(&sc_args, 0, sizeof(grpc_subchannel_args)); - sc_args.addr = &addresses->addresses[i].address; - sc_args.args = args->args; - - grpc_subchannel *subchannel = grpc_client_channel_factory_create_subchannel( - exec_ctx, args->client_channel_factory, &sc_args); - - if (subchannel != NULL) { - subchannel_data *sd = gpr_malloc(sizeof(*sd)); - memset(sd, 0, sizeof(*sd)); - p->subchannels[subchannel_idx] = sd; - sd->policy = p; - sd->index = subchannel_idx; - sd->subchannel = subchannel; - sd->user_data_vtable = addresses->user_data_vtable; - if (sd->user_data_vtable != NULL) { - sd->user_data = - sd->user_data_vtable->copy(addresses->addresses[i].user_data); - } - ++subchannel_idx; - grpc_closure_init(&sd->connectivity_changed_closure, - rr_connectivity_changed, sd); - } - } - if (subchannel_idx == 0) { - /* couldn't create any subchannel. Bail out */ - gpr_free(p->subchannels); - gpr_free(p); - return NULL; - } - p->num_subchannels = subchannel_idx; - - /* The (dummy node) root of the ready list */ - p->ready_list.subchannel = NULL; - p->ready_list.prev = NULL; - p->ready_list.next = NULL; - p->ready_list_last_pick = &p->ready_list; - - grpc_lb_policy_init(&p->base, &round_robin_lb_policy_vtable); - grpc_connectivity_state_init(&p->state_tracker, GRPC_CHANNEL_IDLE, - "round_robin"); - - if (grpc_lb_round_robin_trace) { - gpr_log(GPR_DEBUG, "Created RR policy at %p with %lu subchannels", - (void *)p, (unsigned long)p->num_subchannels); - } - gpr_mu_init(&p->mu); - return &p->base; -} - -static const grpc_lb_policy_factory_vtable round_robin_factory_vtable = { - round_robin_factory_ref, round_robin_factory_unref, round_robin_create, - "round_robin"}; - -static grpc_lb_policy_factory round_robin_lb_policy_factory = { - &round_robin_factory_vtable}; - -static grpc_lb_policy_factory *round_robin_lb_factory_create() { - return &round_robin_lb_policy_factory; -} - -/* Plugin registration */ - -void grpc_lb_policy_round_robin_init() { - grpc_register_lb_policy(round_robin_lb_factory_create()); - grpc_register_tracer("round_robin", &grpc_lb_round_robin_trace); -} - -void grpc_lb_policy_round_robin_shutdown() {} diff --git a/Sources/CgRPC/src/core/ext/load_reporting/load_reporting.c b/Sources/CgRPC/src/core/ext/load_reporting/load_reporting.c deleted file mode 100644 index df1ea0ec9..000000000 --- a/Sources/CgRPC/src/core/ext/load_reporting/load_reporting.c +++ /dev/null @@ -1,83 +0,0 @@ -/* - * - * Copyright 2016, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include -#include - -#include -#include - -#include "src/core/ext/load_reporting/load_reporting.h" -#include "src/core/ext/load_reporting/load_reporting_filter.h" -#include "src/core/lib/channel/channel_stack_builder.h" -#include "src/core/lib/surface/channel_init.h" - -static bool is_load_reporting_enabled(const grpc_channel_args *a) { - if (a == NULL) return false; - for (size_t i = 0; i < a->num_args; i++) { - if (0 == strcmp(a->args[i].key, GRPC_ARG_ENABLE_LOAD_REPORTING)) { - return a->args[i].type == GRPC_ARG_INTEGER && - a->args[i].value.integer != 0; - } - } - return false; -} - -static bool maybe_add_load_reporting_filter(grpc_channel_stack_builder *builder, - void *arg) { - const grpc_channel_args *args = - grpc_channel_stack_builder_get_channel_arguments(builder); - if (is_load_reporting_enabled(args)) { - return grpc_channel_stack_builder_prepend_filter( - builder, (const grpc_channel_filter *)arg, NULL, NULL); - } - return true; -} - -grpc_arg grpc_load_reporting_enable_arg() { - grpc_arg arg; - arg.type = GRPC_ARG_INTEGER; - arg.key = GRPC_ARG_ENABLE_LOAD_REPORTING; - arg.value.integer = 1; - return arg; -} - -/* Plugin registration */ - -void grpc_load_reporting_plugin_init(void) { - grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL, INT_MAX, - maybe_add_load_reporting_filter, - (void *)&grpc_load_reporting_filter); -} - -void grpc_load_reporting_plugin_shutdown() {} diff --git a/Sources/CgRPC/src/core/ext/load_reporting/load_reporting.h b/Sources/CgRPC/src/core/ext/load_reporting/load_reporting.h deleted file mode 100644 index a15784473..000000000 --- a/Sources/CgRPC/src/core/ext/load_reporting/load_reporting.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * - * Copyright 2016, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#ifndef GRPC_CORE_EXT_LOAD_REPORTING_LOAD_REPORTING_H -#define GRPC_CORE_EXT_LOAD_REPORTING_LOAD_REPORTING_H - -#include -#include "src/core/lib/channel/channel_stack.h" - -/** Metadata key for the gRPC LB load balancer token. - * - * The value corresponding to this key is an opaque token that is given to the - * frontend as part of each pick; the frontend sends this token to the backend - * in each request it sends when using that pick. The token is used by the - * backend to verify the request and to allow the backend to report load to the - * gRPC LB system. */ -#define GRPC_LB_TOKEN_MD_KEY "lb-token" - -/** Metadata key for gRPC LB cost reporting. - * - * The value corresponding to this key is an opaque binary blob reported by the - * backend as part of its trailing metadata containing cost information for the - * call. */ -#define GRPC_LB_COST_MD_KEY "lb-cost-bin" - -/** Identifiers for the invocation point of the users LR callback */ -typedef enum grpc_load_reporting_source { - GRPC_LR_POINT_UNKNOWN = 0, - GRPC_LR_POINT_CHANNEL_CREATION, - GRPC_LR_POINT_CHANNEL_DESTRUCTION, - GRPC_LR_POINT_CALL_CREATION, - GRPC_LR_POINT_CALL_DESTRUCTION -} grpc_load_reporting_source; - -/** Call information to be passed to the provided LR callback. */ -typedef struct grpc_load_reporting_call_data { - const grpc_load_reporting_source source; /**< point of last data update. */ - - /** Unique identifier for the channel associated with the data */ - intptr_t channel_id; - - /** Unique identifier for the call associated with the data. If the call - * hasn't been created yet, it'll have a value of zero. */ - intptr_t call_id; - - /** Only valid when \a source is \a GRPC_LR_POINT_CALL_DESTRUCTION, that is, - * once the call has completed */ - const grpc_call_final_info *final_info; - - const char *initial_md_string; /**< value string for LR's initial md key */ - const char *trailing_md_string; /**< value string for LR's trailing md key */ - const char *method_name; /**< Corresponds to :path header */ -} grpc_load_reporting_call_data; - -/** Return a \a grpc_arg enabling load reporting */ -grpc_arg grpc_load_reporting_enable_arg(); - -#endif /* GRPC_CORE_EXT_LOAD_REPORTING_LOAD_REPORTING_H */ diff --git a/Sources/CgRPC/src/core/ext/load_reporting/load_reporting_filter.h b/Sources/CgRPC/src/core/ext/load_reporting/load_reporting_filter.h deleted file mode 100644 index 160ed32af..000000000 --- a/Sources/CgRPC/src/core/ext/load_reporting/load_reporting_filter.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * - * Copyright 2016, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#ifndef GRPC_CORE_EXT_LOAD_REPORTING_LOAD_REPORTING_FILTER_H -#define GRPC_CORE_EXT_LOAD_REPORTING_LOAD_REPORTING_FILTER_H - -#include "src/core/ext/load_reporting/load_reporting.h" -#include "src/core/lib/channel/channel_stack.h" - -extern const grpc_channel_filter grpc_load_reporting_filter; - -#endif /* GRPC_CORE_EXT_LOAD_REPORTING_LOAD_REPORTING_FILTER_H */ diff --git a/Sources/CgRPC/src/core/ext/transport/chttp2/alpn/alpn.c b/Sources/CgRPC/src/core/ext/transport/chttp2/alpn/alpn.c index 55710dc5a..ca2e801ec 100644 --- a/Sources/CgRPC/src/core/ext/transport/chttp2/alpn/alpn.c +++ b/Sources/CgRPC/src/core/ext/transport/chttp2/alpn/alpn.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/ext/transport/chttp2/alpn/alpn.h b/Sources/CgRPC/src/core/ext/transport/chttp2/alpn/alpn.h index 1316770f1..379af4b24 100644 --- a/Sources/CgRPC/src/core/ext/transport/chttp2/alpn/alpn.h +++ b/Sources/CgRPC/src/core/ext/transport/chttp2/alpn/alpn.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/ext/transport/chttp2/client/chttp2_connector.c b/Sources/CgRPC/src/core/ext/transport/chttp2/client/chttp2_connector.c index 114bb0722..983691bba 100644 --- a/Sources/CgRPC/src/core/ext/transport/chttp2/client/chttp2_connector.c +++ b/Sources/CgRPC/src/core/ext/transport/chttp2/client/chttp2_connector.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -41,13 +26,15 @@ #include #include -#include "src/core/ext/client_channel/connector.h" -#include "src/core/ext/client_channel/http_connect_handshaker.h" +#include "src/core/ext/filters/client_channel/connector.h" +#include "src/core/ext/filters/client_channel/http_connect_handshaker.h" +#include "src/core/ext/filters/client_channel/subchannel.h" #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/channel/handshaker_registry.h" #include "src/core/lib/iomgr/tcp_client.h" -#include "src/core/lib/security/transport/security_connector.h" +#include "src/core/lib/slice/slice_internal.h" typedef struct { grpc_connector base; @@ -58,14 +45,9 @@ typedef struct { bool shutdown; bool connecting; - grpc_chttp2_add_handshakers_func add_handshakers; - void *add_handshakers_user_data; - grpc_closure *notify; grpc_connect_in_args args; grpc_connect_out_args *result; - grpc_closure initial_string_sent; - grpc_slice_buffer initial_string_buffer; grpc_endpoint *endpoint; // Non-NULL until handshaking starts. @@ -83,7 +65,6 @@ static void chttp2_connector_unref(grpc_exec_ctx *exec_ctx, grpc_connector *con) { chttp2_connector *c = (chttp2_connector *)con; if (gpr_unref(&c->refs)) { - /* c->initial_string_buffer does not need to be destroyed */ gpr_mu_destroy(&c->mu); // If handshaking is not yet in progress, destroy the endpoint. // Otherwise, the handshaker will do this for us. @@ -93,19 +74,21 @@ static void chttp2_connector_unref(grpc_exec_ctx *exec_ctx, } static void chttp2_connector_shutdown(grpc_exec_ctx *exec_ctx, - grpc_connector *con) { + grpc_connector *con, grpc_error *why) { chttp2_connector *c = (chttp2_connector *)con; gpr_mu_lock(&c->mu); c->shutdown = true; if (c->handshake_mgr != NULL) { - grpc_handshake_manager_shutdown(exec_ctx, c->handshake_mgr); + grpc_handshake_manager_shutdown(exec_ctx, c->handshake_mgr, + GRPC_ERROR_REF(why)); } // If handshaking is not yet in progress, shutdown the endpoint. // Otherwise, the handshaker will do this for us. if (!c->connecting && c->endpoint != NULL) { - grpc_endpoint_shutdown(exec_ctx, c->endpoint); + grpc_endpoint_shutdown(exec_ctx, c->endpoint, GRPC_ERROR_REF(why)); } gpr_mu_unlock(&c->mu); + GRPC_ERROR_UNREF(why); } static void on_handshake_done(grpc_exec_ctx *exec_ctx, void *arg, @@ -115,17 +98,17 @@ static void on_handshake_done(grpc_exec_ctx *exec_ctx, void *arg, gpr_mu_lock(&c->mu); if (error != GRPC_ERROR_NONE || c->shutdown) { if (error == GRPC_ERROR_NONE) { - error = GRPC_ERROR_CREATE("connector shutdown"); + error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("connector shutdown"); // We were shut down after handshaking completed successfully, so // destroy the endpoint here. // TODO(ctiller): It is currently necessary to shutdown endpoints // before destroying them, even if we know that there are no // pending read/write callbacks. This should be fixed, at which // point this can be removed. - grpc_endpoint_shutdown(exec_ctx, args->endpoint); + grpc_endpoint_shutdown(exec_ctx, args->endpoint, GRPC_ERROR_REF(error)); grpc_endpoint_destroy(exec_ctx, args->endpoint); - grpc_channel_args_destroy(args->args); - grpc_slice_buffer_destroy(args->read_buffer); + grpc_channel_args_destroy(exec_ctx, args->args); + grpc_slice_buffer_destroy_internal(exec_ctx, args->read_buffer); gpr_free(args->read_buffer); } else { error = GRPC_ERROR_REF(error); @@ -141,7 +124,7 @@ static void on_handshake_done(grpc_exec_ctx *exec_ctx, void *arg, } grpc_closure *notify = c->notify; c->notify = NULL; - grpc_exec_ctx_sched(exec_ctx, notify, error, NULL); + GRPC_CLOSURE_SCHED(exec_ctx, notify, error); grpc_handshake_manager_destroy(exec_ctx, c->handshake_mgr); c->handshake_mgr = NULL; gpr_mu_unlock(&c->mu); @@ -151,44 +134,14 @@ static void on_handshake_done(grpc_exec_ctx *exec_ctx, void *arg, static void start_handshake_locked(grpc_exec_ctx *exec_ctx, chttp2_connector *c) { c->handshake_mgr = grpc_handshake_manager_create(); - char *proxy_name = grpc_get_http_proxy_server(); - if (proxy_name != NULL) { - grpc_handshake_manager_add(c->handshake_mgr, - grpc_http_connect_handshaker_create(proxy_name)); - gpr_free(proxy_name); - } - if (c->add_handshakers != NULL) { - c->add_handshakers(exec_ctx, c->add_handshakers_user_data, + grpc_handshakers_add(exec_ctx, HANDSHAKER_CLIENT, c->args.channel_args, c->handshake_mgr); - } grpc_handshake_manager_do_handshake( exec_ctx, c->handshake_mgr, c->endpoint, c->args.channel_args, c->args.deadline, NULL /* acceptor */, on_handshake_done, c); c->endpoint = NULL; // Endpoint handed off to handshake manager. } -static void on_initial_connect_string_sent(grpc_exec_ctx *exec_ctx, void *arg, - grpc_error *error) { - chttp2_connector *c = arg; - gpr_mu_lock(&c->mu); - if (error != GRPC_ERROR_NONE || c->shutdown) { - if (error == GRPC_ERROR_NONE) { - error = GRPC_ERROR_CREATE("connector shutdown"); - } else { - error = GRPC_ERROR_REF(error); - } - memset(c->result, 0, sizeof(*c->result)); - grpc_closure *notify = c->notify; - c->notify = NULL; - grpc_exec_ctx_sched(exec_ctx, notify, error, NULL); - gpr_mu_unlock(&c->mu); - chttp2_connector_unref(exec_ctx, arg); - } else { - start_handshake_locked(exec_ctx, c); - gpr_mu_unlock(&c->mu); - } -} - static void connected(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { chttp2_connector *c = arg; gpr_mu_lock(&c->mu); @@ -196,30 +149,22 @@ static void connected(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { c->connecting = false; if (error != GRPC_ERROR_NONE || c->shutdown) { if (error == GRPC_ERROR_NONE) { - error = GRPC_ERROR_CREATE("connector shutdown"); + error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("connector shutdown"); } else { error = GRPC_ERROR_REF(error); } memset(c->result, 0, sizeof(*c->result)); grpc_closure *notify = c->notify; c->notify = NULL; - grpc_exec_ctx_sched(exec_ctx, notify, error, NULL); - if (c->endpoint != NULL) grpc_endpoint_shutdown(exec_ctx, c->endpoint); + GRPC_CLOSURE_SCHED(exec_ctx, notify, error); + if (c->endpoint != NULL) { + grpc_endpoint_shutdown(exec_ctx, c->endpoint, GRPC_ERROR_REF(error)); + } gpr_mu_unlock(&c->mu); chttp2_connector_unref(exec_ctx, arg); } else { GPR_ASSERT(c->endpoint != NULL); - if (!GRPC_SLICE_IS_EMPTY(c->args.initial_connect_string)) { - grpc_closure_init(&c->initial_string_sent, on_initial_connect_string_sent, - c); - grpc_slice_buffer_init(&c->initial_string_buffer); - grpc_slice_buffer_add(&c->initial_string_buffer, - c->args.initial_connect_string); - grpc_endpoint_write(exec_ctx, c->endpoint, &c->initial_string_buffer, - &c->initial_string_sent); - } else { - start_handshake_locked(exec_ctx, c); - } + start_handshake_locked(exec_ctx, c); gpr_mu_unlock(&c->mu); } } @@ -230,6 +175,8 @@ static void chttp2_connector_connect(grpc_exec_ctx *exec_ctx, grpc_connect_out_args *result, grpc_closure *notify) { chttp2_connector *c = (chttp2_connector *)con; + grpc_resolved_address addr; + grpc_get_subchannel_address_arg(exec_ctx, args->channel_args, &addr); gpr_mu_lock(&c->mu); GPR_ASSERT(c->notify == NULL); c->notify = notify; @@ -237,12 +184,12 @@ static void chttp2_connector_connect(grpc_exec_ctx *exec_ctx, c->result = result; GPR_ASSERT(c->endpoint == NULL); chttp2_connector_ref(con); // Ref taken for callback. - grpc_closure_init(&c->connected, connected, c); + GRPC_CLOSURE_INIT(&c->connected, connected, c, grpc_schedule_on_exec_ctx); GPR_ASSERT(!c->connecting); c->connecting = true; grpc_tcp_client_connect(exec_ctx, &c->connected, &c->endpoint, - args->interested_parties, args->channel_args, - args->addr, args->deadline); + args->interested_parties, args->channel_args, &addr, + args->deadline); gpr_mu_unlock(&c->mu); } @@ -250,15 +197,10 @@ static const grpc_connector_vtable chttp2_connector_vtable = { chttp2_connector_ref, chttp2_connector_unref, chttp2_connector_shutdown, chttp2_connector_connect}; -grpc_connector *grpc_chttp2_connector_create( - grpc_exec_ctx *exec_ctx, grpc_chttp2_add_handshakers_func add_handshakers, - void *add_handshakers_user_data) { - chttp2_connector *c = gpr_malloc(sizeof(*c)); - memset(c, 0, sizeof(*c)); +grpc_connector *grpc_chttp2_connector_create() { + chttp2_connector *c = gpr_zalloc(sizeof(*c)); c->base.vtable = &chttp2_connector_vtable; gpr_mu_init(&c->mu); gpr_ref_init(&c->refs, 1); - c->add_handshakers = add_handshakers; - c->add_handshakers_user_data = add_handshakers_user_data; return &c->base; } diff --git a/Sources/CgRPC/src/core/ext/transport/chttp2/client/chttp2_connector.h b/Sources/CgRPC/src/core/ext/transport/chttp2/client/chttp2_connector.h index 58eba2241..e258892cf 100644 --- a/Sources/CgRPC/src/core/ext/transport/chttp2/client/chttp2_connector.h +++ b/Sources/CgRPC/src/core/ext/transport/chttp2/client/chttp2_connector.h @@ -1,51 +1,26 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 GRPC_CORE_EXT_TRANSPORT_CHTTP2_CLIENT_CHTTP2_CONNECTOR_H #define GRPC_CORE_EXT_TRANSPORT_CHTTP2_CLIENT_CHTTP2_CONNECTOR_H -#include "src/core/ext/client_channel/connector.h" -#include "src/core/lib/channel/handshaker.h" -#include "src/core/lib/iomgr/exec_ctx.h" +#include "src/core/ext/filters/client_channel/connector.h" -typedef void (*grpc_chttp2_add_handshakers_func)( - grpc_exec_ctx* exec_ctx, void* user_data, - grpc_handshake_manager* handshake_mgr); - -/// If \a add_handshakers is non-NULL, it will be called with -/// \a add_handshakers_user_data to add handshakers. -grpc_connector* grpc_chttp2_connector_create( - grpc_exec_ctx* exec_ctx, grpc_chttp2_add_handshakers_func add_handshakers, - void* add_handshakers_user_data); +grpc_connector* grpc_chttp2_connector_create(); #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_CLIENT_CHTTP2_CONNECTOR_H */ diff --git a/Sources/CgRPC/src/core/ext/transport/chttp2/client/insecure/channel_create.c b/Sources/CgRPC/src/core/ext/transport/chttp2/client/insecure/channel_create.c index a0d0652ce..cccb347bf 100644 --- a/Sources/CgRPC/src/core/ext/transport/chttp2/client/insecure/channel_create.c +++ b/Sources/CgRPC/src/core/ext/transport/chttp2/client/insecure/channel_create.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -38,7 +23,8 @@ #include #include -#include "src/core/ext/client_channel/client_channel.h" +#include "src/core/ext/filters/client_channel/client_channel.h" +#include "src/core/ext/filters/client_channel/resolver_registry.h" #include "src/core/ext/transport/chttp2/client/chttp2_connector.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/surface/api_trace.h" @@ -53,8 +39,7 @@ static void client_channel_factory_unref( static grpc_subchannel *client_channel_factory_create_subchannel( grpc_exec_ctx *exec_ctx, grpc_client_channel_factory *cc_factory, const grpc_subchannel_args *args) { - grpc_connector *connector = grpc_chttp2_connector_create( - exec_ctx, NULL /* add_handshakers */, NULL /* user_data */); + grpc_connector *connector = grpc_chttp2_connector_create(); grpc_subchannel *s = grpc_subchannel_create(exec_ctx, connector, args); grpc_connector_unref(exec_ctx, connector); return s; @@ -64,15 +49,21 @@ static grpc_channel *client_channel_factory_create_channel( grpc_exec_ctx *exec_ctx, grpc_client_channel_factory *cc_factory, const char *target, grpc_client_channel_type type, const grpc_channel_args *args) { + if (target == NULL) { + gpr_log(GPR_ERROR, "cannot create channel with NULL target name"); + return NULL; + } // Add channel arg containing the server URI. - grpc_arg arg; - arg.type = GRPC_ARG_STRING; - arg.key = GRPC_ARG_SERVER_URI; - arg.value.string = (char *)target; - grpc_channel_args *new_args = grpc_channel_args_copy_and_add(args, &arg, 1); + grpc_arg arg = grpc_channel_arg_string_create( + GRPC_ARG_SERVER_URI, + grpc_resolver_factory_add_default_prefix_if_needed(exec_ctx, target)); + const char *to_remove[] = {GRPC_ARG_SERVER_URI}; + grpc_channel_args *new_args = + grpc_channel_args_copy_and_add_and_remove(args, to_remove, 1, &arg, 1); + gpr_free(arg.value.string); grpc_channel *channel = grpc_channel_create(exec_ctx, target, new_args, GRPC_CLIENT_CHANNEL, NULL); - grpc_channel_args_destroy(new_args); + grpc_channel_args_destroy(exec_ctx, new_args); return channel; } @@ -93,20 +84,19 @@ grpc_channel *grpc_insecure_channel_create(const char *target, void *reserved) { grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; GRPC_API_TRACE( - "grpc_insecure_channel_create(target=%p, args=%p, reserved=%p)", 3, + "grpc_insecure_channel_create(target=%s, args=%p, reserved=%p)", 3, (target, args, reserved)); GPR_ASSERT(reserved == NULL); - grpc_client_channel_factory *factory = - (grpc_client_channel_factory *)&client_channel_factory; // Add channel arg containing the client channel factory. - grpc_arg arg = grpc_client_channel_factory_create_channel_arg(factory); + grpc_arg arg = + grpc_client_channel_factory_create_channel_arg(&client_channel_factory); grpc_channel_args *new_args = grpc_channel_args_copy_and_add(args, &arg, 1); // Create channel. grpc_channel *channel = client_channel_factory_create_channel( - &exec_ctx, factory, target, GRPC_CLIENT_CHANNEL_TYPE_REGULAR, new_args); + &exec_ctx, &client_channel_factory, target, + GRPC_CLIENT_CHANNEL_TYPE_REGULAR, new_args); // Clean up. - grpc_channel_args_destroy(new_args); - grpc_client_channel_factory_unref(&exec_ctx, factory); + grpc_channel_args_destroy(&exec_ctx, new_args); grpc_exec_ctx_finish(&exec_ctx); return channel != NULL ? channel : grpc_lame_client_channel_create( target, GRPC_STATUS_INTERNAL, diff --git a/Sources/CgRPC/src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c b/Sources/CgRPC/src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c index 1e5b1c22e..0346d50b6 100644 --- a/Sources/CgRPC/src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c +++ b/Sources/CgRPC/src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -56,10 +41,8 @@ grpc_channel *grpc_insecure_channel_create_from_fd( GRPC_API_TRACE("grpc_insecure_channel_create(target=%p, fd=%d, args=%p)", 3, (target, fd, args)); - grpc_arg default_authority_arg; - default_authority_arg.type = GRPC_ARG_STRING; - default_authority_arg.key = GRPC_ARG_DEFAULT_AUTHORITY; - default_authority_arg.value.string = "test.authority"; + grpc_arg default_authority_arg = grpc_channel_arg_string_create( + GRPC_ARG_DEFAULT_AUTHORITY, "test.authority"); grpc_channel_args *final_args = grpc_channel_args_copy_and_add(args, &default_authority_arg, 1); @@ -74,7 +57,7 @@ grpc_channel *grpc_insecure_channel_create_from_fd( GPR_ASSERT(transport); grpc_channel *channel = grpc_channel_create( &exec_ctx, target, final_args, GRPC_CLIENT_DIRECT_CHANNEL, transport); - grpc_channel_args_destroy(final_args); + grpc_channel_args_destroy(&exec_ctx, final_args); grpc_chttp2_transport_start_reading(&exec_ctx, transport, NULL); grpc_exec_ctx_finish(&exec_ctx); diff --git a/Sources/CgRPC/src/core/ext/transport/chttp2/client/secure/secure_channel_create.c b/Sources/CgRPC/src/core/ext/transport/chttp2/client/secure/secure_channel_create.c index f35439cd4..d4580f15f 100644 --- a/Sources/CgRPC/src/core/ext/transport/chttp2/client/secure/secure_channel_create.c +++ b/Sources/CgRPC/src/core/ext/transport/chttp2/client/secure/secure_channel_create.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -38,50 +23,134 @@ #include #include -#include "src/core/ext/client_channel/client_channel.h" +#include "src/core/ext/filters/client_channel/client_channel.h" +#include "src/core/ext/filters/client_channel/resolver_registry.h" +#include "src/core/ext/filters/client_channel/uri_parser.h" #include "src/core/ext/transport/chttp2/client/chttp2_connector.h" #include "src/core/lib/channel/channel_args.h" +#include "src/core/lib/iomgr/sockaddr_utils.h" #include "src/core/lib/security/credentials/credentials.h" +#include "src/core/lib/security/transport/lb_targets_info.h" #include "src/core/lib/security/transport/security_connector.h" +#include "src/core/lib/slice/slice_hash_table.h" +#include "src/core/lib/slice/slice_internal.h" #include "src/core/lib/surface/api_trace.h" #include "src/core/lib/surface/channel.h" -typedef struct { - grpc_client_channel_factory base; - gpr_refcount refs; - grpc_channel_security_connector *security_connector; -} client_channel_factory; - static void client_channel_factory_ref( - grpc_client_channel_factory *cc_factory) { - client_channel_factory *f = (client_channel_factory *)cc_factory; - gpr_ref(&f->refs); -} + grpc_client_channel_factory *cc_factory) {} static void client_channel_factory_unref( - grpc_exec_ctx *exec_ctx, grpc_client_channel_factory *cc_factory) { - client_channel_factory *f = (client_channel_factory *)cc_factory; - if (gpr_unref(&f->refs)) { - GRPC_SECURITY_CONNECTOR_UNREF(&f->security_connector->base, - "client_channel_factory"); - gpr_free(f); + grpc_exec_ctx *exec_ctx, grpc_client_channel_factory *cc_factory) {} + +static grpc_subchannel_args *get_secure_naming_subchannel_args( + grpc_exec_ctx *exec_ctx, const grpc_subchannel_args *args) { + grpc_channel_credentials *channel_credentials = + grpc_channel_credentials_find_in_args(args->args); + if (channel_credentials == NULL) { + gpr_log(GPR_ERROR, + "Can't create subchannel: channel credentials missing for secure " + "channel."); + return NULL; } -} + // Make sure security connector does not already exist in args. + if (grpc_security_connector_find_in_args(args->args) != NULL) { + gpr_log(GPR_ERROR, + "Can't create subchannel: security connector already present in " + "channel args."); + return NULL; + } + // To which address are we connecting? By default, use the server URI. + const grpc_arg *server_uri_arg = + grpc_channel_args_find(args->args, GRPC_ARG_SERVER_URI); + GPR_ASSERT(server_uri_arg != NULL); + GPR_ASSERT(server_uri_arg->type == GRPC_ARG_STRING); + const char *server_uri_str = server_uri_arg->value.string; + GPR_ASSERT(server_uri_str != NULL); + grpc_uri *server_uri = + grpc_uri_parse(exec_ctx, server_uri_str, true /* supress errors */); + GPR_ASSERT(server_uri != NULL); + const char *server_uri_path; + server_uri_path = + server_uri->path[0] == '/' ? server_uri->path + 1 : server_uri->path; + const grpc_slice_hash_table *targets_info = + grpc_lb_targets_info_find_in_args(args->args); + char *target_name_to_check = NULL; + if (targets_info != NULL) { // LB channel + // Find the balancer name for the target. + const char *target_uri_str = + grpc_get_subchannel_address_uri_arg(args->args); + grpc_uri *target_uri = + grpc_uri_parse(exec_ctx, target_uri_str, false /* suppress errors */); + GPR_ASSERT(target_uri != NULL); + if (target_uri->path[0] != '\0') { // "path" may be empty + const grpc_slice key = grpc_slice_from_static_string( + target_uri->path[0] == '/' ? target_uri->path + 1 : target_uri->path); + const char *value = grpc_slice_hash_table_get(targets_info, key); + if (value != NULL) target_name_to_check = gpr_strdup(value); + grpc_slice_unref_internal(exec_ctx, key); + } + if (target_name_to_check == NULL) { + // If the target name to check hasn't already been set, fall back to using + // SERVER_URI + target_name_to_check = gpr_strdup(server_uri_path); + } + grpc_uri_destroy(target_uri); + } else { // regular channel: the secure name is the original server URI. + target_name_to_check = gpr_strdup(server_uri_path); + } + grpc_uri_destroy(server_uri); + GPR_ASSERT(target_name_to_check != NULL); + grpc_channel_security_connector *subchannel_security_connector = NULL; + // Create the security connector using the credentials and target name. + grpc_channel_args *new_args_from_connector = NULL; + const grpc_security_status security_status = + grpc_channel_credentials_create_security_connector( + exec_ctx, channel_credentials, target_name_to_check, args->args, + &subchannel_security_connector, &new_args_from_connector); + if (security_status != GRPC_SECURITY_OK) { + gpr_log(GPR_ERROR, + "Failed to create secure subchannel for secure name '%s'", + target_name_to_check); + gpr_free(target_name_to_check); + return NULL; + } + gpr_free(target_name_to_check); + grpc_arg new_security_connector_arg = + grpc_security_connector_to_arg(&subchannel_security_connector->base); -static void add_handshakers(grpc_exec_ctx *exec_ctx, void *security_connector, - grpc_handshake_manager *handshake_mgr) { - grpc_channel_security_connector_add_handshakers(exec_ctx, security_connector, - handshake_mgr); + grpc_channel_args *new_args = grpc_channel_args_copy_and_add( + new_args_from_connector != NULL ? new_args_from_connector : args->args, + &new_security_connector_arg, 1); + GRPC_SECURITY_CONNECTOR_UNREF(exec_ctx, &subchannel_security_connector->base, + "lb_channel_create"); + if (new_args_from_connector != NULL) { + grpc_channel_args_destroy(exec_ctx, new_args_from_connector); + } + grpc_subchannel_args *final_sc_args = gpr_malloc(sizeof(*final_sc_args)); + memcpy(final_sc_args, args, sizeof(*args)); + final_sc_args->args = new_args; + return final_sc_args; } static grpc_subchannel *client_channel_factory_create_subchannel( grpc_exec_ctx *exec_ctx, grpc_client_channel_factory *cc_factory, const grpc_subchannel_args *args) { - client_channel_factory *f = (client_channel_factory *)cc_factory; - grpc_connector *connector = grpc_chttp2_connector_create( - exec_ctx, add_handshakers, f->security_connector); - grpc_subchannel *s = grpc_subchannel_create(exec_ctx, connector, args); + grpc_subchannel_args *subchannel_args = + get_secure_naming_subchannel_args(exec_ctx, args); + if (subchannel_args == NULL) { + gpr_log( + GPR_ERROR, + "Failed to create subchannel arguments during subchannel creation."); + return NULL; + } + grpc_connector *connector = grpc_chttp2_connector_create(); + grpc_subchannel *s = + grpc_subchannel_create(exec_ctx, connector, subchannel_args); grpc_connector_unref(exec_ctx, connector); + grpc_channel_args_destroy(exec_ctx, + (grpc_channel_args *)subchannel_args->args); + gpr_free(subchannel_args); return s; } @@ -89,15 +158,21 @@ static grpc_channel *client_channel_factory_create_channel( grpc_exec_ctx *exec_ctx, grpc_client_channel_factory *cc_factory, const char *target, grpc_client_channel_type type, const grpc_channel_args *args) { + if (target == NULL) { + gpr_log(GPR_ERROR, "cannot create channel with NULL target name"); + return NULL; + } // Add channel arg containing the server URI. - grpc_arg arg; - arg.type = GRPC_ARG_STRING; - arg.key = GRPC_ARG_SERVER_URI; - arg.value.string = (char *)target; - grpc_channel_args *new_args = grpc_channel_args_copy_and_add(args, &arg, 1); + grpc_arg arg = grpc_channel_arg_string_create( + GRPC_ARG_SERVER_URI, + grpc_resolver_factory_add_default_prefix_if_needed(exec_ctx, target)); + const char *to_remove[] = {GRPC_ARG_SERVER_URI}; + grpc_channel_args *new_args = + grpc_channel_args_copy_and_add_and_remove(args, to_remove, 1, &arg, 1); + gpr_free(arg.value.string); grpc_channel *channel = grpc_channel_create(exec_ctx, target, new_args, GRPC_CLIENT_CHANNEL, NULL); - grpc_channel_args_destroy(new_args); + grpc_channel_args_destroy(exec_ctx, new_args); return channel; } @@ -106,10 +181,13 @@ static const grpc_client_channel_factory_vtable client_channel_factory_vtable = client_channel_factory_create_subchannel, client_channel_factory_create_channel}; -/* Create a secure client channel: - Asynchronously: - resolve target - - connect to it (trying alternatives as presented) - - perform handshakes */ +static grpc_client_channel_factory client_channel_factory = { + &client_channel_factory_vtable}; + +// Create a secure client channel: +// Asynchronously: - resolve target +// - connect to it (trying alternatives as presented) +// - perform handshakes grpc_channel *grpc_secure_channel_create(grpc_channel_credentials *creds, const char *target, const grpc_channel_args *args, @@ -118,53 +196,27 @@ grpc_channel *grpc_secure_channel_create(grpc_channel_credentials *creds, GRPC_API_TRACE( "grpc_secure_channel_create(creds=%p, target=%s, args=%p, " "reserved=%p)", - 4, (creds, target, args, reserved)); + 4, ((void *)creds, target, (void *)args, (void *)reserved)); GPR_ASSERT(reserved == NULL); - // Make sure security connector does not already exist in args. - if (grpc_find_security_connector_in_args(args) != NULL) { - gpr_log(GPR_ERROR, "Cannot set security context in channel args."); + grpc_channel *channel = NULL; + if (creds != NULL) { + // Add channel args containing the client channel factory and channel + // credentials. + grpc_arg args_to_add[] = { + grpc_client_channel_factory_create_channel_arg(&client_channel_factory), + grpc_channel_credentials_to_arg(creds)}; + grpc_channel_args *new_args = grpc_channel_args_copy_and_add( + args, args_to_add, GPR_ARRAY_SIZE(args_to_add)); + // Create channel. + channel = client_channel_factory_create_channel( + &exec_ctx, &client_channel_factory, target, + GRPC_CLIENT_CHANNEL_TYPE_REGULAR, new_args); + // Clean up. + grpc_channel_args_destroy(&exec_ctx, new_args); grpc_exec_ctx_finish(&exec_ctx); - return grpc_lame_client_channel_create( - target, GRPC_STATUS_INTERNAL, - "Security connector exists in channel args."); - } - // Create security connector and construct new channel args. - grpc_channel_security_connector *security_connector; - grpc_channel_args *new_args_from_connector; - if (grpc_channel_credentials_create_security_connector( - creds, target, args, &security_connector, &new_args_from_connector) != - GRPC_SECURITY_OK) { - grpc_exec_ctx_finish(&exec_ctx); - return grpc_lame_client_channel_create( - target, GRPC_STATUS_INTERNAL, "Failed to create security connector."); - } - // Create client channel factory. - client_channel_factory *f = gpr_malloc(sizeof(*f)); - memset(f, 0, sizeof(*f)); - f->base.vtable = &client_channel_factory_vtable; - gpr_ref_init(&f->refs, 1); - GRPC_SECURITY_CONNECTOR_REF(&security_connector->base, - "grpc_secure_channel_create"); - f->security_connector = security_connector; - // Add channel args containing the client channel factory and security - // connector. - grpc_arg new_args[2]; - new_args[0] = grpc_client_channel_factory_create_channel_arg(&f->base); - new_args[1] = grpc_security_connector_to_arg(&security_connector->base); - grpc_channel_args *args_copy = grpc_channel_args_copy_and_add( - new_args_from_connector != NULL ? new_args_from_connector : args, - new_args, GPR_ARRAY_SIZE(new_args)); - if (new_args_from_connector != NULL) { - grpc_channel_args_destroy(new_args_from_connector); } - // Create channel. - grpc_channel *channel = client_channel_factory_create_channel( - &exec_ctx, &f->base, target, GRPC_CLIENT_CHANNEL_TYPE_REGULAR, args_copy); - // Clean up. - GRPC_SECURITY_CONNECTOR_UNREF(&f->security_connector->base, - "secure_client_channel_factory_create_channel"); - grpc_channel_args_destroy(args_copy); - grpc_client_channel_factory_unref(&exec_ctx, &f->base); - grpc_exec_ctx_finish(&exec_ctx); - return channel; /* may be NULL */ + return channel != NULL ? channel + : grpc_lame_client_channel_create( + target, GRPC_STATUS_INTERNAL, + "Failed to create secure client channel"); } diff --git a/Sources/CgRPC/src/core/ext/transport/chttp2/server/chttp2_server.c b/Sources/CgRPC/src/core/ext/transport/chttp2/server/chttp2_server.c index f0857714f..f20715590 100644 --- a/Sources/CgRPC/src/core/ext/transport/chttp2/server/chttp2_server.c +++ b/Sources/CgRPC/src/core/ext/transport/chttp2/server/chttp2_server.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -43,49 +28,27 @@ #include #include +#include "src/core/ext/filters/http/server/http_server_filter.h" #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/channel/http_server_filter.h" +#include "src/core/lib/channel/handshaker_registry.h" #include "src/core/lib/iomgr/endpoint.h" #include "src/core/lib/iomgr/resolve_address.h" #include "src/core/lib/iomgr/tcp_server.h" +#include "src/core/lib/slice/slice_internal.h" #include "src/core/lib/surface/api_trace.h" #include "src/core/lib/surface/server.h" -void grpc_chttp2_server_handshaker_factory_add_handshakers( - grpc_exec_ctx *exec_ctx, - grpc_chttp2_server_handshaker_factory *handshaker_factory, - grpc_handshake_manager *handshake_mgr) { - if (handshaker_factory != NULL) { - handshaker_factory->vtable->add_handshakers(exec_ctx, handshaker_factory, - handshake_mgr); - } -} - -void grpc_chttp2_server_handshaker_factory_destroy( - grpc_exec_ctx *exec_ctx, - grpc_chttp2_server_handshaker_factory *handshaker_factory) { - if (handshaker_factory != NULL) { - handshaker_factory->vtable->destroy(exec_ctx, handshaker_factory); - } -} - -typedef struct pending_handshake_manager_node { - grpc_handshake_manager *handshake_mgr; - struct pending_handshake_manager_node *next; -} pending_handshake_manager_node; - typedef struct { grpc_server *server; grpc_tcp_server *tcp_server; grpc_channel_args *args; - grpc_chttp2_server_handshaker_factory *handshaker_factory; gpr_mu mu; bool shutdown; grpc_closure tcp_server_shutdown_complete; grpc_closure *server_destroy_listener_done; - pending_handshake_manager_node *pending_handshake_mgrs; + grpc_handshake_manager *pending_handshake_mgrs; } server_state; typedef struct { @@ -95,41 +58,6 @@ typedef struct { grpc_handshake_manager *handshake_mgr; } server_connection_state; -static void pending_handshake_manager_add_locked( - server_state *state, grpc_handshake_manager *handshake_mgr) { - pending_handshake_manager_node *node = gpr_malloc(sizeof(*node)); - node->handshake_mgr = handshake_mgr; - node->next = state->pending_handshake_mgrs; - state->pending_handshake_mgrs = node; -} - -static void pending_handshake_manager_remove_locked( - server_state *state, grpc_handshake_manager *handshake_mgr) { - pending_handshake_manager_node **prev_node = &state->pending_handshake_mgrs; - for (pending_handshake_manager_node *node = state->pending_handshake_mgrs; - node != NULL; node = node->next) { - if (node->handshake_mgr == handshake_mgr) { - *prev_node = node->next; - gpr_free(node); - break; - } - prev_node = &node->next; - } -} - -static void pending_handshake_manager_shutdown_locked(grpc_exec_ctx *exec_ctx, - server_state *state) { - pending_handshake_manager_node *prev_node = NULL; - for (pending_handshake_manager_node *node = state->pending_handshake_mgrs; - node != NULL; node = node->next) { - grpc_handshake_manager_shutdown(exec_ctx, node->handshake_mgr); - gpr_free(prev_node); - prev_node = node; - } - gpr_free(prev_node); - state->pending_handshake_mgrs = NULL; -} - static void on_handshake_done(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { grpc_handshaker_args *args = arg; @@ -137,8 +65,8 @@ static void on_handshake_done(grpc_exec_ctx *exec_ctx, void *arg, gpr_mu_lock(&connection_state->server_state->mu); if (error != GRPC_ERROR_NONE || connection_state->server_state->shutdown) { const char *error_str = grpc_error_string(error); - gpr_log(GPR_ERROR, "Handshaking failed: %s", error_str); - grpc_error_free_string(error_str); + gpr_log(GPR_DEBUG, "Handshaking failed: %s", error_str); + if (error == GRPC_ERROR_NONE && args->endpoint != NULL) { // We were shut down after handshaking completed successfully, so // destroy the endpoint here. @@ -146,10 +74,10 @@ static void on_handshake_done(grpc_exec_ctx *exec_ctx, void *arg, // before destroying them, even if we know that there are no // pending read/write callbacks. This should be fixed, at which // point this can be removed. - grpc_endpoint_shutdown(exec_ctx, args->endpoint); + grpc_endpoint_shutdown(exec_ctx, args->endpoint, GRPC_ERROR_NONE); grpc_endpoint_destroy(exec_ctx, args->endpoint); - grpc_channel_args_destroy(args->args); - grpc_slice_buffer_destroy(args->read_buffer); + grpc_channel_args_destroy(exec_ctx, args->args); + grpc_slice_buffer_destroy_internal(exec_ctx, args->read_buffer); gpr_free(args->read_buffer); } } else { @@ -164,11 +92,12 @@ static void on_handshake_done(grpc_exec_ctx *exec_ctx, void *arg, connection_state->accepting_pollset, args->args); grpc_chttp2_transport_start_reading(exec_ctx, transport, args->read_buffer); - grpc_channel_args_destroy(args->args); + grpc_channel_args_destroy(exec_ctx, args->args); } } - pending_handshake_manager_remove_locked(connection_state->server_state, - connection_state->handshake_mgr); + grpc_handshake_manager_pending_list_remove( + &connection_state->server_state->pending_handshake_mgrs, + connection_state->handshake_mgr); gpr_mu_unlock(&connection_state->server_state->mu); grpc_handshake_manager_destroy(exec_ctx, connection_state->handshake_mgr); grpc_tcp_server_unref(exec_ctx, connection_state->server_state->tcp_server); @@ -183,12 +112,14 @@ static void on_accept(grpc_exec_ctx *exec_ctx, void *arg, grpc_endpoint *tcp, gpr_mu_lock(&state->mu); if (state->shutdown) { gpr_mu_unlock(&state->mu); + grpc_endpoint_shutdown(exec_ctx, tcp, GRPC_ERROR_NONE); grpc_endpoint_destroy(exec_ctx, tcp); gpr_free(acceptor); return; } grpc_handshake_manager *handshake_mgr = grpc_handshake_manager_create(); - pending_handshake_manager_add_locked(state, handshake_mgr); + grpc_handshake_manager_pending_list_add(&state->pending_handshake_mgrs, + handshake_mgr); gpr_mu_unlock(&state->mu); grpc_tcp_server_ref(state->tcp_server); server_connection_state *connection_state = @@ -197,8 +128,8 @@ static void on_accept(grpc_exec_ctx *exec_ctx, void *arg, grpc_endpoint *tcp, connection_state->accepting_pollset = accepting_pollset; connection_state->acceptor = acceptor; connection_state->handshake_mgr = handshake_mgr; - grpc_chttp2_server_handshaker_factory_add_handshakers( - exec_ctx, state->handshaker_factory, connection_state->handshake_mgr); + grpc_handshakers_add(exec_ctx, HANDSHAKER_SERVER, state->args, + connection_state->handshake_mgr); // TODO(roth): We should really get this timeout value from channel // args instead of hard-coding it. const gpr_timespec deadline = gpr_time_add( @@ -227,18 +158,17 @@ static void tcp_server_shutdown_complete(grpc_exec_ctx *exec_ctx, void *arg, gpr_mu_lock(&state->mu); grpc_closure *destroy_done = state->server_destroy_listener_done; GPR_ASSERT(state->shutdown); - pending_handshake_manager_shutdown_locked(exec_ctx, state); + grpc_handshake_manager_pending_list_shutdown_all( + exec_ctx, state->pending_handshake_mgrs, GRPC_ERROR_REF(error)); gpr_mu_unlock(&state->mu); // Flush queued work before destroying handshaker factory, since that // may do a synchronous unref. grpc_exec_ctx_flush(exec_ctx); - grpc_chttp2_server_handshaker_factory_destroy(exec_ctx, - state->handshaker_factory); if (destroy_done != NULL) { destroy_done->cb(exec_ctx, destroy_done->cb_arg, GRPC_ERROR_REF(error)); grpc_exec_ctx_flush(exec_ctx); } - grpc_channel_args_destroy(state->args); + grpc_channel_args_destroy(exec_ctx, state->args); gpr_mu_destroy(&state->mu); gpr_free(state); } @@ -258,10 +188,10 @@ static void server_destroy_listener(grpc_exec_ctx *exec_ctx, grpc_tcp_server_unref(exec_ctx, tcp_server); } -grpc_error *grpc_chttp2_server_add_port( - grpc_exec_ctx *exec_ctx, grpc_server *server, const char *addr, - grpc_channel_args *args, - grpc_chttp2_server_handshaker_factory *handshaker_factory, int *port_num) { +grpc_error *grpc_chttp2_server_add_port(grpc_exec_ctx *exec_ctx, + grpc_server *server, const char *addr, + grpc_channel_args *args, + int *port_num) { grpc_resolved_addresses *resolved = NULL; grpc_tcp_server *tcp_server = NULL; size_t i; @@ -278,10 +208,10 @@ grpc_error *grpc_chttp2_server_add_port( if (err != GRPC_ERROR_NONE) { goto error; } - state = gpr_malloc(sizeof(*state)); - memset(state, 0, sizeof(*state)); - grpc_closure_init(&state->tcp_server_shutdown_complete, - tcp_server_shutdown_complete, state); + state = gpr_zalloc(sizeof(*state)); + GRPC_CLOSURE_INIT(&state->tcp_server_shutdown_complete, + tcp_server_shutdown_complete, state, + grpc_schedule_on_exec_ctx); err = grpc_tcp_server_create(exec_ctx, &state->tcp_server_shutdown_complete, args, &tcp_server); if (err != GRPC_ERROR_NONE) { @@ -291,7 +221,6 @@ grpc_error *grpc_chttp2_server_add_port( state->server = server; state->tcp_server = tcp_server; state->args = args; - state->handshaker_factory = handshaker_factory; state->shutdown = true; gpr_mu_init(&state->mu); @@ -313,7 +242,7 @@ grpc_error *grpc_chttp2_server_add_port( char *msg; gpr_asprintf(&msg, "No address added out of total %" PRIuPTR " resolved", naddrs); - err = GRPC_ERROR_CREATE_REFERENCING(msg, errors, naddrs); + err = GRPC_ERROR_CREATE_REFERENCING_FROM_COPIED_STRING(msg, errors, naddrs); gpr_free(msg); goto error; } else if (count != naddrs) { @@ -321,12 +250,12 @@ grpc_error *grpc_chttp2_server_add_port( gpr_asprintf(&msg, "Only %" PRIuPTR " addresses added out of total %" PRIuPTR " resolved", count, naddrs); - err = GRPC_ERROR_CREATE_REFERENCING(msg, errors, naddrs); + err = GRPC_ERROR_CREATE_REFERENCING_FROM_COPIED_STRING(msg, errors, naddrs); gpr_free(msg); const char *warning_message = grpc_error_string(err); gpr_log(GPR_INFO, "WARNING: %s", warning_message); - grpc_error_free_string(warning_message); + /* we managed to bind some addresses: continue */ } grpc_resolved_addresses_destroy(resolved); @@ -345,8 +274,7 @@ grpc_error *grpc_chttp2_server_add_port( if (tcp_server) { grpc_tcp_server_unref(exec_ctx, tcp_server); } else { - grpc_channel_args_destroy(args); - grpc_chttp2_server_handshaker_factory_destroy(exec_ctx, handshaker_factory); + grpc_channel_args_destroy(exec_ctx, args); gpr_free(state); } *port_num = 0; diff --git a/Sources/CgRPC/src/core/ext/transport/chttp2/server/chttp2_server.h b/Sources/CgRPC/src/core/ext/transport/chttp2/server/chttp2_server.h index aa364b565..ed968496f 100644 --- a/Sources/CgRPC/src/core/ext/transport/chttp2/server/chttp2_server.h +++ b/Sources/CgRPC/src/core/ext/transport/chttp2/server/chttp2_server.h @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -36,43 +21,12 @@ #include -#include "src/core/lib/channel/handshaker.h" #include "src/core/lib/iomgr/exec_ctx.h" -/// A server handshaker factory is used to create handshakers for server -/// connections. -typedef struct grpc_chttp2_server_handshaker_factory - grpc_chttp2_server_handshaker_factory; - -typedef struct { - void (*add_handshakers)( - grpc_exec_ctx *exec_ctx, - grpc_chttp2_server_handshaker_factory *handshaker_factory, - grpc_handshake_manager *handshake_mgr); - void (*destroy)(grpc_exec_ctx *exec_ctx, - grpc_chttp2_server_handshaker_factory *handshaker_factory); -} grpc_chttp2_server_handshaker_factory_vtable; - -struct grpc_chttp2_server_handshaker_factory { - const grpc_chttp2_server_handshaker_factory_vtable *vtable; -}; - -void grpc_chttp2_server_handshaker_factory_add_handshakers( - grpc_exec_ctx *exec_ctx, - grpc_chttp2_server_handshaker_factory *handshaker_factory, - grpc_handshake_manager *handshake_mgr); - -void grpc_chttp2_server_handshaker_factory_destroy( - grpc_exec_ctx *exec_ctx, - grpc_chttp2_server_handshaker_factory *handshaker_factory); - /// Adds a port to \a server. Sets \a port_num to the port number. -/// If \a handshaker_factory is not NULL, it will be used to create -/// handshakers for the port. -/// Takes ownership of \a args and \a handshaker_factory. -grpc_error *grpc_chttp2_server_add_port( - grpc_exec_ctx *exec_ctx, grpc_server *server, const char *addr, - grpc_channel_args *args, - grpc_chttp2_server_handshaker_factory *handshaker_factory, int *port_num); +/// Takes ownership of \a args. +grpc_error *grpc_chttp2_server_add_port(grpc_exec_ctx *exec_ctx, + grpc_server *server, const char *addr, + grpc_channel_args *args, int *port_num); #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_SERVER_CHTTP2_SERVER_H */ diff --git a/Sources/CgRPC/src/core/ext/transport/chttp2/server/insecure/server_chttp2.c b/Sources/CgRPC/src/core/ext/transport/chttp2/server/insecure/server_chttp2.c index 7e286d4e4..d42b2d123 100644 --- a/Sources/CgRPC/src/core/ext/transport/chttp2/server/insecure/server_chttp2.c +++ b/Sources/CgRPC/src/core/ext/transport/chttp2/server/insecure/server_chttp2.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -47,12 +32,11 @@ int grpc_server_add_insecure_http2_port(grpc_server *server, const char *addr) { (server, addr)); grpc_error *err = grpc_chttp2_server_add_port( &exec_ctx, server, addr, - grpc_channel_args_copy(grpc_server_get_channel_args(server)), - NULL /* handshaker_factory */, &port_num); + grpc_channel_args_copy(grpc_server_get_channel_args(server)), &port_num); if (err != GRPC_ERROR_NONE) { const char *msg = grpc_error_string(err); gpr_log(GPR_ERROR, "%s", msg); - grpc_error_free_string(msg); + GRPC_ERROR_UNREF(err); } grpc_exec_ctx_finish(&exec_ctx); diff --git a/Sources/CgRPC/src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c b/Sources/CgRPC/src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c index aa2ecf574..e647067f7 100644 --- a/Sources/CgRPC/src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c +++ b/Sources/CgRPC/src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -57,12 +42,9 @@ void grpc_server_add_insecure_channel_from_fd(grpc_server *server, char *name; gpr_asprintf(&name, "fd:%d", fd); - grpc_resource_quota *resource_quota = grpc_resource_quota_from_channel_args( - grpc_server_get_channel_args(server)); grpc_endpoint *server_endpoint = - grpc_tcp_create(grpc_fd_create(fd, name), resource_quota, - GRPC_TCP_DEFAULT_READ_SLICE_SIZE, name); - grpc_resource_quota_internal_unref(&exec_ctx, resource_quota); + grpc_tcp_create(&exec_ctx, grpc_fd_create(fd, name), + grpc_server_get_channel_args(server), name); gpr_free(name); diff --git a/Sources/CgRPC/src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c b/Sources/CgRPC/src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c index a33a7a3f7..5ad63aaf1 100644 --- a/Sources/CgRPC/src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c +++ b/Sources/CgRPC/src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -49,34 +34,6 @@ #include "src/core/lib/surface/api_trace.h" #include "src/core/lib/surface/server.h" -typedef struct { - grpc_chttp2_server_handshaker_factory base; - grpc_server_security_connector *security_connector; -} server_security_handshaker_factory; - -static void server_security_handshaker_factory_add_handshakers( - grpc_exec_ctx *exec_ctx, grpc_chttp2_server_handshaker_factory *hf, - grpc_handshake_manager *handshake_mgr) { - server_security_handshaker_factory *handshaker_factory = - (server_security_handshaker_factory *)hf; - grpc_server_security_connector_add_handshakers( - exec_ctx, handshaker_factory->security_connector, handshake_mgr); -} - -static void server_security_handshaker_factory_destroy( - grpc_exec_ctx *exec_ctx, grpc_chttp2_server_handshaker_factory *hf) { - server_security_handshaker_factory *handshaker_factory = - (server_security_handshaker_factory *)hf; - GRPC_SECURITY_CONNECTOR_UNREF(&handshaker_factory->security_connector->base, - "server"); - gpr_free(hf); -} - -static const grpc_chttp2_server_handshaker_factory_vtable - server_security_handshaker_factory_vtable = { - server_security_handshaker_factory_add_handshakers, - server_security_handshaker_factory_destroy}; - int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr, grpc_server_credentials *creds) { grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; @@ -89,41 +46,40 @@ int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr, 3, (server, addr, creds)); // Create security context. if (creds == NULL) { - err = GRPC_ERROR_CREATE( + err = GRPC_ERROR_CREATE_FROM_STATIC_STRING( "No credentials specified for secure server port (creds==NULL)"); goto done; } grpc_security_status status = - grpc_server_credentials_create_security_connector(creds, &sc); + grpc_server_credentials_create_security_connector(&exec_ctx, creds, &sc); if (status != GRPC_SECURITY_OK) { 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(msg), + err = grpc_error_set_int(GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg), GRPC_ERROR_INT_SECURITY_STATUS, status); gpr_free(msg); goto done; } - // Create handshaker factory. - server_security_handshaker_factory *handshaker_factory = - gpr_malloc(sizeof(*handshaker_factory)); - memset(handshaker_factory, 0, sizeof(*handshaker_factory)); - handshaker_factory->base.vtable = &server_security_handshaker_factory_vtable; - handshaker_factory->security_connector = sc; // Create channel args. - grpc_arg channel_arg = grpc_server_credentials_to_arg(creds); - grpc_channel_args *args = grpc_channel_args_copy_and_add( - grpc_server_get_channel_args(server), &channel_arg, 1); + 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); + grpc_channel_args *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(&exec_ctx, server, addr, args, - &handshaker_factory->base, &port_num); + err = grpc_chttp2_server_add_port(&exec_ctx, server, addr, args, &port_num); done: + if (sc != NULL) { + GRPC_SECURITY_CONNECTOR_UNREF(&exec_ctx, &sc->base, "server"); + } grpc_exec_ctx_finish(&exec_ctx); if (err != GRPC_ERROR_NONE) { const char *msg = grpc_error_string(err); gpr_log(GPR_ERROR, "%s", msg); - grpc_error_free_string(msg); + GRPC_ERROR_UNREF(err); } return port_num; diff --git a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/bin_decoder.c b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/bin_decoder.c index 3eef80b55..5a99cbeff 100644 --- a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/bin_decoder.c +++ b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/bin_decoder.c @@ -1,39 +1,25 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 "src/core/ext/transport/chttp2/transport/bin_decoder.h" #include #include +#include "src/core/lib/slice/slice_internal.h" #include "src/core/lib/slice/slice_string_helpers.h" #include "src/core/lib/support/string.h" @@ -132,6 +118,7 @@ bool grpc_base64_decode_partial(struct grpc_base64_decode_context *ctx) { switch (input_tail) { case 3: ctx->output_cur[1] = COMPOSE_OUTPUT_BYTE_1(ctx->input_cur); + /* fallthrough */ case 2: ctx->output_cur[0] = COMPOSE_OUTPUT_BYTE_0(ctx->input_cur); } @@ -143,7 +130,8 @@ bool grpc_base64_decode_partial(struct grpc_base64_decode_context *ctx) { return true; } -grpc_slice grpc_chttp2_base64_decode(grpc_slice input) { +grpc_slice grpc_chttp2_base64_decode(grpc_exec_ctx *exec_ctx, + grpc_slice input) { size_t input_length = GRPC_SLICE_LENGTH(input); size_t output_length = input_length / 4 * 3; struct grpc_base64_decode_context ctx; @@ -155,7 +143,7 @@ grpc_slice grpc_chttp2_base64_decode(grpc_slice input) { "grpc_chttp2_base64_decode has a length of %d, which is not a " "multiple of 4.\n", (int)input_length); - return gpr_empty_slice(); + return grpc_empty_slice(); } if (input_length > 0) { @@ -167,7 +155,7 @@ grpc_slice grpc_chttp2_base64_decode(grpc_slice input) { } } } - output = grpc_slice_malloc(output_length); + output = GRPC_SLICE_MALLOC(output_length); ctx.input_cur = GRPC_SLICE_START_PTR(input); ctx.input_end = GRPC_SLICE_END_PTR(input); @@ -176,21 +164,22 @@ grpc_slice grpc_chttp2_base64_decode(grpc_slice input) { ctx.contains_tail = false; if (!grpc_base64_decode_partial(&ctx)) { - char *s = grpc_dump_slice(input, GPR_DUMP_ASCII); + char *s = grpc_slice_to_c_string(input); gpr_log(GPR_ERROR, "Base64 decoding failed, input string:\n%s\n", s); gpr_free(s); - grpc_slice_unref(output); - return gpr_empty_slice(); + grpc_slice_unref_internal(exec_ctx, output); + return grpc_empty_slice(); } GPR_ASSERT(ctx.output_cur == GRPC_SLICE_END_PTR(output)); GPR_ASSERT(ctx.input_cur == GRPC_SLICE_END_PTR(input)); return output; } -grpc_slice grpc_chttp2_base64_decode_with_length(grpc_slice input, +grpc_slice grpc_chttp2_base64_decode_with_length(grpc_exec_ctx *exec_ctx, + grpc_slice input, size_t output_length) { size_t input_length = GRPC_SLICE_LENGTH(input); - grpc_slice output = grpc_slice_malloc(output_length); + grpc_slice output = GRPC_SLICE_MALLOC(output_length); struct grpc_base64_decode_context ctx; // The length of a base64 string cannot be 4 * n + 1 @@ -200,8 +189,8 @@ grpc_slice grpc_chttp2_base64_decode_with_length(grpc_slice input, "grpc_chttp2_base64_decode_with_length has a length of %d, which " "has a tail of 1 byte.\n", (int)input_length); - grpc_slice_unref(output); - return gpr_empty_slice(); + grpc_slice_unref_internal(exec_ctx, output); + return grpc_empty_slice(); } if (output_length > input_length / 4 * 3 + tail_xtra[input_length % 4]) { @@ -210,8 +199,8 @@ grpc_slice grpc_chttp2_base64_decode_with_length(grpc_slice input, "than the max possible output length %d.\n", (int)output_length, (int)(input_length / 4 * 3 + tail_xtra[input_length % 4])); - grpc_slice_unref(output); - return gpr_empty_slice(); + grpc_slice_unref_internal(exec_ctx, output); + return grpc_empty_slice(); } ctx.input_cur = GRPC_SLICE_START_PTR(input); @@ -221,11 +210,11 @@ grpc_slice grpc_chttp2_base64_decode_with_length(grpc_slice input, ctx.contains_tail = true; if (!grpc_base64_decode_partial(&ctx)) { - char *s = grpc_dump_slice(input, GPR_DUMP_ASCII); + char *s = grpc_slice_to_c_string(input); gpr_log(GPR_ERROR, "Base64 decoding failed, input string:\n%s\n", s); gpr_free(s); - grpc_slice_unref(output); - return gpr_empty_slice(); + grpc_slice_unref_internal(exec_ctx, output); + return grpc_empty_slice(); } GPR_ASSERT(ctx.output_cur == GRPC_SLICE_END_PTR(output)); GPR_ASSERT(ctx.input_cur <= GRPC_SLICE_END_PTR(input)); diff --git a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/bin_decoder.h b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/bin_decoder.h index 83a90be51..047b33d58 100644 --- a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/bin_decoder.h +++ b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/bin_decoder.h @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -55,12 +40,13 @@ bool grpc_base64_decode_partial(struct grpc_base64_decode_context *ctx); /* base64 decode a slice with pad chars. Returns a new slice, does not take ownership of the input. Returns an empty slice if decoding is failed. */ -grpc_slice grpc_chttp2_base64_decode(grpc_slice input); +grpc_slice grpc_chttp2_base64_decode(grpc_exec_ctx *exec_ctx, grpc_slice input); /* base64 decode a slice without pad chars, data length is needed. Returns a new slice, does not take ownership of the input. Returns an empty slice if decoding is failed. */ -grpc_slice grpc_chttp2_base64_decode_with_length(grpc_slice input, +grpc_slice grpc_chttp2_base64_decode_with_length(grpc_exec_ctx *exec_ctx, + grpc_slice input, size_t output_length); #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_BIN_DECODER_H */ diff --git a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/bin_encoder.c b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/bin_encoder.c index af25a4352..42d481b3c 100644 --- a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/bin_encoder.c +++ b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/bin_encoder.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -66,7 +51,7 @@ grpc_slice grpc_chttp2_base64_encode(grpc_slice input) { size_t input_triplets = input_length / 3; size_t tail_case = input_length % 3; size_t output_length = input_triplets * 4 + tail_xtra[tail_case]; - grpc_slice output = grpc_slice_malloc(output_length); + grpc_slice output = GRPC_SLICE_MALLOC(output_length); uint8_t *in = GRPC_SLICE_START_PTR(input); char *out = (char *)GRPC_SLICE_START_PTR(output); size_t i; @@ -119,7 +104,7 @@ grpc_slice grpc_chttp2_huffman_compress(grpc_slice input) { nbits += grpc_chttp2_huffsyms[*in].length; } - output = grpc_slice_malloc(nbits / 8 + (nbits % 8 != 0)); + output = GRPC_SLICE_MALLOC(nbits / 8 + (nbits % 8 != 0)); out = GRPC_SLICE_START_PTR(output); for (in = GRPC_SLICE_START_PTR(input); in != GRPC_SLICE_END_PTR(input); ++in) { @@ -177,15 +162,14 @@ static void enc_add1(huff_out *out, uint8_t a) { enc_flush_some(out); } -grpc_slice grpc_chttp2_base64_encode_and_huffman_compress_impl( - grpc_slice input) { +grpc_slice grpc_chttp2_base64_encode_and_huffman_compress(grpc_slice input) { size_t input_length = GRPC_SLICE_LENGTH(input); size_t input_triplets = input_length / 3; size_t tail_case = input_length % 3; size_t output_syms = input_triplets * 4 + tail_xtra[tail_case]; size_t max_output_bits = 11 * output_syms; size_t max_output_length = max_output_bits / 8 + (max_output_bits % 8 != 0); - grpc_slice output = grpc_slice_malloc(max_output_length); + grpc_slice output = GRPC_SLICE_MALLOC(max_output_length); uint8_t *in = GRPC_SLICE_START_PTR(input); uint8_t *start_out = GRPC_SLICE_START_PTR(output); huff_out out; diff --git a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/bin_encoder.h b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/bin_encoder.h index 9e143b46e..a8f36a345 100644 --- a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/bin_encoder.h +++ b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/bin_encoder.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -47,9 +32,8 @@ grpc_slice grpc_chttp2_huffman_compress(grpc_slice input); /* equivalent to: grpc_slice x = grpc_chttp2_base64_encode(input); grpc_slice y = grpc_chttp2_huffman_compress(x); - grpc_slice_unref(x); + grpc_slice_unref_internal(exec_ctx, x); return y; */ -grpc_slice grpc_chttp2_base64_encode_and_huffman_compress_impl( - grpc_slice input); +grpc_slice grpc_chttp2_base64_encode_and_huffman_compress(grpc_slice input); #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_BIN_ENCODER_H */ diff --git a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/chttp2_plugin.c b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/chttp2_plugin.c index bd87253ed..78551df9c 100644 --- a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/chttp2_plugin.c +++ b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/chttp2_plugin.c @@ -1,46 +1,31 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 "src/core/ext/transport/chttp2/transport/bin_encoder.h" #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h" #include "src/core/lib/debug/trace.h" #include "src/core/lib/transport/metadata.h" void grpc_chttp2_plugin_init(void) { - grpc_chttp2_base64_encode_and_huffman_compress = - grpc_chttp2_base64_encode_and_huffman_compress_impl; - grpc_register_tracer("http", &grpc_http_trace); - grpc_register_tracer("flowctl", &grpc_flowctl_trace); + grpc_register_tracer(&grpc_http_trace); + grpc_register_tracer(&grpc_flowctl_trace); +#ifndef NDEBUG + grpc_register_tracer(&grpc_trace_chttp2_refcount); +#endif } void grpc_chttp2_plugin_shutdown(void) {} diff --git a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/chttp2_transport.c b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/chttp2_transport.c index 6bc054866..7bad188f4 100644 --- a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/chttp2_transport.c +++ b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/chttp2_transport.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -44,28 +29,59 @@ #include #include -#include "src/core/ext/transport/chttp2/transport/http2_errors.h" +#include "src/core/ext/transport/chttp2/transport/frame_data.h" #include "src/core/ext/transport/chttp2/transport/internal.h" -#include "src/core/ext/transport/chttp2/transport/status_conversion.h" +#include "src/core/ext/transport/chttp2/transport/varint.h" #include "src/core/lib/channel/channel_args.h" +#include "src/core/lib/compression/stream_compression.h" #include "src/core/lib/http/parser.h" -#include "src/core/lib/iomgr/workqueue.h" +#include "src/core/lib/iomgr/executor.h" +#include "src/core/lib/iomgr/timer.h" #include "src/core/lib/profiling/timers.h" +#include "src/core/lib/slice/slice_internal.h" #include "src/core/lib/slice/slice_string_helpers.h" +#include "src/core/lib/support/env.h" #include "src/core/lib/support/string.h" +#include "src/core/lib/transport/error_utils.h" +#include "src/core/lib/transport/http2_errors.h" #include "src/core/lib/transport/static_metadata.h" +#include "src/core/lib/transport/status_conversion.h" #include "src/core/lib/transport/timeout_encoding.h" +#include "src/core/lib/transport/transport.h" #include "src/core/lib/transport/transport_impl.h" #define DEFAULT_WINDOW 65535 #define DEFAULT_CONNECTION_WINDOW_TARGET (1024 * 1024) #define MAX_WINDOW 0x7fffffffu - -#define DEFAULT_MAX_HEADER_LIST_SIZE (16 * 1024) +#define MAX_WRITE_BUFFER_SIZE (64 * 1024 * 1024) +#define DEFAULT_MAX_HEADER_LIST_SIZE (8 * 1024) + +#define DEFAULT_CLIENT_KEEPALIVE_TIME_MS INT_MAX +#define DEFAULT_CLIENT_KEEPALIVE_TIMEOUT_MS 20000 /* 20 seconds */ +#define DEFAULT_SERVER_KEEPALIVE_TIME_MS 7200000 /* 2 hours */ +#define DEFAULT_SERVER_KEEPALIVE_TIMEOUT_MS 20000 /* 20 seconds */ +#define DEFAULT_KEEPALIVE_PERMIT_WITHOUT_CALLS false +#define KEEPALIVE_TIME_BACKOFF_MULTIPLIER 2 + +static int g_default_client_keepalive_time_ms = + DEFAULT_CLIENT_KEEPALIVE_TIME_MS; +static int g_default_client_keepalive_timeout_ms = + DEFAULT_CLIENT_KEEPALIVE_TIMEOUT_MS; +static int g_default_server_keepalive_time_ms = + DEFAULT_SERVER_KEEPALIVE_TIME_MS; +static int g_default_server_keepalive_timeout_ms = + DEFAULT_SERVER_KEEPALIVE_TIMEOUT_MS; +static bool g_default_keepalive_permit_without_calls = + DEFAULT_KEEPALIVE_PERMIT_WITHOUT_CALLS; #define MAX_CLIENT_STREAM_ID 0x7fffffffu -int grpc_http_trace = 0; -int grpc_flowctl_trace = 0; +grpc_tracer_flag grpc_http_trace = GRPC_TRACER_INITIALIZER(false, "http"); +grpc_tracer_flag grpc_flowctl_trace = GRPC_TRACER_INITIALIZER(false, "flowctl"); + +#ifndef NDEBUG +grpc_tracer_flag grpc_trace_chttp2_refcount = + GRPC_TRACER_INITIALIZER(false, "chttp2_refcount"); +#endif static const grpc_transport_vtable vtable; @@ -73,23 +89,18 @@ static const grpc_transport_vtable vtable; static void write_action_begin_locked(grpc_exec_ctx *exec_ctx, void *t, grpc_error *error); static void write_action(grpc_exec_ctx *exec_ctx, void *t, grpc_error *error); -static void write_action_end(grpc_exec_ctx *exec_ctx, void *t, - grpc_error *error); static void write_action_end_locked(grpc_exec_ctx *exec_ctx, void *t, grpc_error *error); -static void read_action_begin(grpc_exec_ctx *exec_ctx, void *t, - grpc_error *error); static void read_action_locked(grpc_exec_ctx *exec_ctx, void *t, grpc_error *error); static void complete_fetch_locked(grpc_exec_ctx *exec_ctx, void *gs, grpc_error *error); -static void complete_fetch(grpc_exec_ctx *exec_ctx, void *gs, - grpc_error *error); /** Set a transport level setting, and push it to our peer */ -static void push_setting(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, - grpc_chttp2_setting_id id, uint32_t value); +static void queue_setting_update(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t, + grpc_chttp2_setting_id id, uint32_t value); static void close_from_api(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, grpc_chttp2_stream *s, grpc_error *error); @@ -103,21 +114,17 @@ static void connectivity_state_set(grpc_exec_ctx *exec_ctx, grpc_connectivity_state state, grpc_error *error, const char *reason); -static void incoming_byte_stream_update_flow_control(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport *t, - grpc_chttp2_stream *s, - size_t max_size_hint, - size_t have_already); static void incoming_byte_stream_destroy_locked(grpc_exec_ctx *exec_ctx, void *byte_stream, grpc_error *error_ignored); +static void incoming_byte_stream_publish_error( + grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_byte_stream *bs, + grpc_error *error); +static void incoming_byte_stream_unref(grpc_exec_ctx *exec_ctx, + grpc_chttp2_incoming_byte_stream *bs); -static void benign_reclaimer(grpc_exec_ctx *exec_ctx, void *t, - grpc_error *error); static void benign_reclaimer_locked(grpc_exec_ctx *exec_ctx, void *t, grpc_error *error); -static void destructive_reclaimer(grpc_exec_ctx *exec_ctx, void *t, - grpc_error *error); static void destructive_reclaimer_locked(grpc_exec_ctx *exec_ctx, void *t, grpc_error *error); @@ -131,6 +138,38 @@ static void close_transport_locked(grpc_exec_ctx *exec_ctx, static void end_all_the_calls(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, grpc_error *error); +static void start_bdp_ping_locked(grpc_exec_ctx *exec_ctx, void *tp, + grpc_error *error); +static void finish_bdp_ping_locked(grpc_exec_ctx *exec_ctx, void *tp, + grpc_error *error); + +static void cancel_pings(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, + grpc_error *error); +static void send_ping_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, + grpc_chttp2_ping_type ping_type, + grpc_closure *on_initiate, + grpc_closure *on_complete); +static void retry_initiate_ping_locked(grpc_exec_ctx *exec_ctx, void *tp, + grpc_error *error); + +#define DEFAULT_MIN_TIME_BETWEEN_PINGS_MS 0 +#define DEFAULT_MAX_PINGS_BETWEEN_DATA 3 +#define DEFAULT_MAX_PING_STRIKES 2 +#define DEFAULT_MIN_PING_INTERVAL_WITHOUT_DATA_MS 300000 /* 5 minutes */ + +/** keepalive-relevant functions */ +static void init_keepalive_ping_locked(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error); +static void start_keepalive_ping_locked(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error); +static void finish_keepalive_ping_locked(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error); +static void keepalive_watchdog_fired_locked(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error); + +static void reset_byte_stream(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error); + /******************************************************************************* * CONSTRUCTION/DESTRUCTION/REFCOUNTING */ @@ -141,13 +180,13 @@ static void destruct_transport(grpc_exec_ctx *exec_ctx, grpc_endpoint_destroy(exec_ctx, t->ep); - grpc_slice_buffer_destroy(&t->qbuf); + grpc_slice_buffer_destroy_internal(exec_ctx, &t->qbuf); - grpc_slice_buffer_destroy(&t->outbuf); - grpc_chttp2_hpack_compressor_destroy(&t->hpack_compressor); + grpc_slice_buffer_destroy_internal(exec_ctx, &t->outbuf); + grpc_chttp2_hpack_compressor_destroy(exec_ctx, &t->hpack_compressor); - grpc_slice_buffer_destroy(&t->read_buffer); - grpc_chttp2_hpack_parser_destroy(&t->hpack_parser); + grpc_slice_buffer_destroy_internal(exec_ctx, &t->read_buffer); + grpc_chttp2_hpack_parser_destroy(exec_ctx, &t->hpack_parser); grpc_chttp2_goaway_parser_destroy(&t->goaway_parser); for (i = 0; i < STREAM_LIST_COUNT; i++) { @@ -160,18 +199,10 @@ static void destruct_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_stream_map_destroy(&t->stream_map); grpc_connectivity_state_destroy(exec_ctx, &t->channel_callback.state_tracker); - grpc_combiner_destroy(exec_ctx, t->combiner); + GRPC_COMBINER_UNREF(exec_ctx, t->combiner, "chttp2_transport"); - /* callback remaining pings: they're not allowed to call into the transpot, - and maybe they hold resources that need to be freed */ - while (t->pings.next != &t->pings) { - grpc_chttp2_outstanding_ping *ping = t->pings.next; - grpc_exec_ctx_sched(exec_ctx, ping->on_recv, - GRPC_ERROR_CREATE("Transport closed"), NULL); - ping->next->prev = ping->prev; - ping->prev->next = ping->next; - gpr_free(ping); - } + cancel_pings(exec_ctx, t, + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Transport destroyed")); while (t->write_cb_pool) { grpc_chttp2_write_cb *next = t->write_cb_pool->next; @@ -179,24 +210,31 @@ static void destruct_transport(grpc_exec_ctx *exec_ctx, t->write_cb_pool = next; } + gpr_free(t->ping_acks); gpr_free(t->peer_string); gpr_free(t); } -#ifdef GRPC_CHTTP2_REFCOUNTING_DEBUG +#ifndef NDEBUG void grpc_chttp2_unref_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, const char *reason, const char *file, int line) { - gpr_log(GPR_DEBUG, "chttp2:unref:%p %" PRIdPTR "->%" PRIdPTR " %s [%s:%d]", t, - t->refs.count, t->refs.count - 1, reason, file, line); + if (GRPC_TRACER_ON(grpc_trace_chttp2_refcount)) { + gpr_atm val = gpr_atm_no_barrier_load(&t->refs.count); + gpr_log(GPR_DEBUG, "chttp2:unref:%p %" PRIdPTR "->%" PRIdPTR " %s [%s:%d]", + t, val, val - 1, reason, file, line); + } if (!gpr_unref(&t->refs)) return; destruct_transport(exec_ctx, t); } void grpc_chttp2_ref_transport(grpc_chttp2_transport *t, const char *reason, const char *file, int line) { - gpr_log(GPR_DEBUG, "chttp2: ref:%p %" PRIdPTR "->%" PRIdPTR " %s [%s:%d]", t, - t->refs.count, t->refs.count + 1, reason, file, line); + if (GRPC_TRACER_ON(grpc_trace_chttp2_refcount)) { + gpr_atm val = gpr_atm_no_barrier_load(&t->refs.count); + gpr_log(GPR_DEBUG, "chttp2: ref:%p %" PRIdPTR "->%" PRIdPTR " %s [%s:%d]", + t, val, val + 1, reason, file, line); + } gpr_ref(&t->refs); } #else @@ -218,23 +256,18 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, GPR_ASSERT(strlen(GRPC_CHTTP2_CLIENT_CONNECT_STRING) == GRPC_CHTTP2_CLIENT_CONNECT_STRLEN); - memset(t, 0, sizeof(*t)); - t->base.vtable = &vtable; t->ep = ep; /* one ref is for destroy */ gpr_ref_init(&t->refs, 1); - t->combiner = grpc_combiner_create(grpc_endpoint_get_workqueue(ep)); + t->combiner = grpc_combiner_create(); t->peer_string = grpc_endpoint_get_peer(ep); t->endpoint_reading = 1; t->next_stream_id = is_client ? 1 : 2; t->is_client = is_client; - t->outgoing_window = DEFAULT_WINDOW; - t->incoming_window = DEFAULT_WINDOW; - t->stream_lookahead = DEFAULT_WINDOW; - t->connection_window_target = DEFAULT_CONNECTION_WINDOW_TARGET; - t->ping_counter = 1; - t->pings.next = t->pings.prev = &t->pings; + t->flow_control.remote_window = DEFAULT_WINDOW; + t->flow_control.announced_window = DEFAULT_WINDOW; + t->flow_control.t = t; t->deframe_state = is_client ? GRPC_DTS_FH_0 : GRPC_DTS_CLIENT_PREFIX_0; t->is_first_frame = true; grpc_connectivity_state_init( @@ -246,21 +279,45 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, grpc_slice_buffer_init(&t->outbuf); grpc_chttp2_hpack_compressor_init(&t->hpack_compressor); - grpc_closure_init(&t->write_action_begin_locked, write_action_begin_locked, - t); - grpc_closure_init(&t->write_action, write_action, t); - grpc_closure_init(&t->write_action_end, write_action_end, t); - grpc_closure_init(&t->write_action_end_locked, write_action_end_locked, t); - grpc_closure_init(&t->read_action_begin, read_action_begin, t); - grpc_closure_init(&t->read_action_locked, read_action_locked, t); - grpc_closure_init(&t->benign_reclaimer, benign_reclaimer, t); - grpc_closure_init(&t->destructive_reclaimer, destructive_reclaimer, t); - grpc_closure_init(&t->benign_reclaimer_locked, benign_reclaimer_locked, t); - grpc_closure_init(&t->destructive_reclaimer_locked, - destructive_reclaimer_locked, t); + GRPC_CLOSURE_INIT(&t->read_action_locked, read_action_locked, t, + grpc_combiner_scheduler(t->combiner)); + GRPC_CLOSURE_INIT(&t->benign_reclaimer_locked, benign_reclaimer_locked, t, + grpc_combiner_scheduler(t->combiner)); + GRPC_CLOSURE_INIT(&t->destructive_reclaimer_locked, + destructive_reclaimer_locked, t, + grpc_combiner_scheduler(t->combiner)); + GRPC_CLOSURE_INIT(&t->retry_initiate_ping_locked, retry_initiate_ping_locked, + t, grpc_combiner_scheduler(t->combiner)); + GRPC_CLOSURE_INIT(&t->start_bdp_ping_locked, start_bdp_ping_locked, t, + grpc_combiner_scheduler(t->combiner)); + GRPC_CLOSURE_INIT(&t->finish_bdp_ping_locked, finish_bdp_ping_locked, t, + grpc_combiner_scheduler(t->combiner)); + GRPC_CLOSURE_INIT(&t->init_keepalive_ping_locked, init_keepalive_ping_locked, + t, grpc_combiner_scheduler(t->combiner)); + GRPC_CLOSURE_INIT(&t->start_keepalive_ping_locked, + start_keepalive_ping_locked, t, + grpc_combiner_scheduler(t->combiner)); + GRPC_CLOSURE_INIT(&t->finish_keepalive_ping_locked, + finish_keepalive_ping_locked, t, + grpc_combiner_scheduler(t->combiner)); + GRPC_CLOSURE_INIT(&t->keepalive_watchdog_fired_locked, + keepalive_watchdog_fired_locked, t, + grpc_combiner_scheduler(t->combiner)); + + grpc_bdp_estimator_init(&t->flow_control.bdp_estimator, t->peer_string); + t->flow_control.last_pid_update = gpr_now(GPR_CLOCK_MONOTONIC); + grpc_pid_controller_init( + &t->flow_control.pid_controller, + (grpc_pid_controller_args){.gain_p = 4, + .gain_i = 8, + .gain_d = 0, + .initial_control_value = log2(DEFAULT_WINDOW), + .min_control_value = -1, + .max_control_value = 25, + .integral_range = 10}); grpc_chttp2_goaway_parser_init(&t->goaway_parser); - grpc_chttp2_hpack_parser_init(&t->hpack_parser); + grpc_chttp2_hpack_parser_init(exec_ctx, &t->hpack_parser); grpc_slice_buffer_init(&t->read_buffer); @@ -282,22 +339,64 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, window -- this should by rights be 0 */ t->force_send_settings = 1 << GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE; t->sent_local_settings = 0; + t->write_buffer_size = DEFAULT_WINDOW; + t->flow_control.enable_bdp_probe = true; if (is_client) { grpc_slice_buffer_add(&t->outbuf, grpc_slice_from_copied_string( GRPC_CHTTP2_CLIENT_CONNECT_STRING)); - grpc_chttp2_initiate_write(exec_ctx, t, false, "initial_write"); + grpc_chttp2_initiate_write(exec_ctx, t, "initial_write"); } /* configure http2 the way we like it */ if (is_client) { - push_setting(exec_ctx, t, GRPC_CHTTP2_SETTINGS_ENABLE_PUSH, 0); - push_setting(exec_ctx, t, GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 0); + queue_setting_update(exec_ctx, t, GRPC_CHTTP2_SETTINGS_ENABLE_PUSH, 0); + queue_setting_update(exec_ctx, t, + GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 0); + } + queue_setting_update(exec_ctx, t, GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE, + DEFAULT_WINDOW); + queue_setting_update(exec_ctx, t, GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE, + DEFAULT_MAX_HEADER_LIST_SIZE); + queue_setting_update(exec_ctx, t, + GRPC_CHTTP2_SETTINGS_GRPC_ALLOW_TRUE_BINARY_METADATA, 1); + + t->ping_policy = (grpc_chttp2_repeated_ping_policy){ + .max_pings_without_data = DEFAULT_MAX_PINGS_BETWEEN_DATA, + .min_time_between_pings = + gpr_time_from_millis(DEFAULT_MIN_TIME_BETWEEN_PINGS_MS, GPR_TIMESPAN), + .max_ping_strikes = DEFAULT_MAX_PING_STRIKES, + .min_ping_interval_without_data = gpr_time_from_millis( + DEFAULT_MIN_PING_INTERVAL_WITHOUT_DATA_MS, GPR_TIMESPAN), + }; + + /* Keepalive setting */ + if (t->is_client) { + t->keepalive_time = + g_default_client_keepalive_time_ms == INT_MAX + ? gpr_inf_future(GPR_TIMESPAN) + : gpr_time_from_millis(g_default_client_keepalive_time_ms, + GPR_TIMESPAN); + t->keepalive_timeout = + g_default_client_keepalive_timeout_ms == INT_MAX + ? gpr_inf_future(GPR_TIMESPAN) + : gpr_time_from_millis(g_default_client_keepalive_timeout_ms, + GPR_TIMESPAN); + } else { + t->keepalive_time = + g_default_server_keepalive_time_ms == INT_MAX + ? gpr_inf_future(GPR_TIMESPAN) + : gpr_time_from_millis(g_default_server_keepalive_time_ms, + GPR_TIMESPAN); + t->keepalive_timeout = + g_default_server_keepalive_timeout_ms == INT_MAX + ? gpr_inf_future(GPR_TIMESPAN) + : gpr_time_from_millis(g_default_server_keepalive_timeout_ms, + GPR_TIMESPAN); } - push_setting(exec_ctx, t, GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE, - DEFAULT_WINDOW); - push_setting(exec_ctx, t, GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE, - DEFAULT_MAX_HEADER_LIST_SIZE); + t->keepalive_permit_without_calls = g_default_keepalive_permit_without_calls; + + t->opt_target = GRPC_CHTTP2_OPTIMIZE_FOR_LATENCY; if (channel_args) { for (i = 0; i < channel_args->num_args; i++) { @@ -315,14 +414,6 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, t->next_stream_id = (uint32_t)value; } } - } else if (0 == strcmp(channel_args->args[i].key, - GRPC_ARG_HTTP2_STREAM_LOOKAHEAD_BYTES)) { - const grpc_integer_options options = {-1, 5, INT_MAX}; - const int value = - grpc_channel_arg_get_integer(&channel_args->args[i], options); - if (value >= 0) { - t->stream_lookahead = (uint32_t)value; - } } else if (0 == strcmp(channel_args->args[i].key, GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_ENCODER)) { const grpc_integer_options options = {-1, 0, INT_MAX}; @@ -332,6 +423,86 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, grpc_chttp2_hpack_compressor_set_max_usable_size(&t->hpack_compressor, (uint32_t)value); } + } else if (0 == strcmp(channel_args->args[i].key, + GRPC_ARG_HTTP2_MAX_PINGS_WITHOUT_DATA)) { + t->ping_policy.max_pings_without_data = grpc_channel_arg_get_integer( + &channel_args->args[i], + (grpc_integer_options){DEFAULT_MAX_PINGS_BETWEEN_DATA, 0, INT_MAX}); + } else if (0 == strcmp(channel_args->args[i].key, + GRPC_ARG_HTTP2_MAX_PING_STRIKES)) { + t->ping_policy.max_ping_strikes = grpc_channel_arg_get_integer( + &channel_args->args[i], + (grpc_integer_options){DEFAULT_MAX_PING_STRIKES, 0, INT_MAX}); + } else if (0 == strcmp(channel_args->args[i].key, + GRPC_ARG_HTTP2_MIN_TIME_BETWEEN_PINGS_MS)) { + t->ping_policy.min_time_between_pings = gpr_time_from_millis( + grpc_channel_arg_get_integer( + &channel_args->args[i], + (grpc_integer_options){DEFAULT_MIN_TIME_BETWEEN_PINGS_MS, 0, + INT_MAX}), + GPR_TIMESPAN); + } else if (0 == + strcmp(channel_args->args[i].key, + GRPC_ARG_HTTP2_MIN_PING_INTERVAL_WITHOUT_DATA_MS)) { + t->ping_policy.min_ping_interval_without_data = gpr_time_from_millis( + grpc_channel_arg_get_integer( + &channel_args->args[i], + (grpc_integer_options){ + DEFAULT_MIN_PING_INTERVAL_WITHOUT_DATA_MS, 0, INT_MAX}), + GPR_TIMESPAN); + } else if (0 == strcmp(channel_args->args[i].key, + GRPC_ARG_HTTP2_WRITE_BUFFER_SIZE)) { + t->write_buffer_size = (uint32_t)grpc_channel_arg_get_integer( + &channel_args->args[i], + (grpc_integer_options){0, 0, MAX_WRITE_BUFFER_SIZE}); + } else if (0 == + strcmp(channel_args->args[i].key, GRPC_ARG_HTTP2_BDP_PROBE)) { + t->flow_control.enable_bdp_probe = grpc_channel_arg_get_integer( + &channel_args->args[i], (grpc_integer_options){1, 0, 1}); + } else if (0 == strcmp(channel_args->args[i].key, + GRPC_ARG_KEEPALIVE_TIME_MS)) { + const int value = grpc_channel_arg_get_integer( + &channel_args->args[i], + (grpc_integer_options){t->is_client + ? g_default_client_keepalive_time_ms + : g_default_server_keepalive_time_ms, + 1, INT_MAX}); + t->keepalive_time = value == INT_MAX + ? gpr_inf_future(GPR_TIMESPAN) + : gpr_time_from_millis(value, GPR_TIMESPAN); + } else if (0 == strcmp(channel_args->args[i].key, + GRPC_ARG_KEEPALIVE_TIMEOUT_MS)) { + const int value = grpc_channel_arg_get_integer( + &channel_args->args[i], + (grpc_integer_options){t->is_client + ? g_default_client_keepalive_timeout_ms + : g_default_server_keepalive_timeout_ms, + 0, INT_MAX}); + t->keepalive_timeout = value == INT_MAX + ? gpr_inf_future(GPR_TIMESPAN) + : gpr_time_from_millis(value, GPR_TIMESPAN); + } else if (0 == strcmp(channel_args->args[i].key, + GRPC_ARG_KEEPALIVE_PERMIT_WITHOUT_CALLS)) { + t->keepalive_permit_without_calls = + (uint32_t)grpc_channel_arg_get_integer( + &channel_args->args[i], (grpc_integer_options){0, 0, 1}); + } else if (0 == strcmp(channel_args->args[i].key, + GRPC_ARG_OPTIMIZATION_TARGET)) { + if (channel_args->args[i].type != GRPC_ARG_STRING) { + gpr_log(GPR_ERROR, "%s should be a string", + GRPC_ARG_OPTIMIZATION_TARGET); + } else if (0 == strcmp(channel_args->args[i].value.string, "blend")) { + t->opt_target = GRPC_CHTTP2_OPTIMIZE_FOR_LATENCY; + } else if (0 == strcmp(channel_args->args[i].value.string, "latency")) { + t->opt_target = GRPC_CHTTP2_OPTIMIZE_FOR_LATENCY; + } else if (0 == + strcmp(channel_args->args[i].value.string, "throughput")) { + t->opt_target = GRPC_CHTTP2_OPTIMIZE_FOR_THROUGHPUT; + } else { + gpr_log(GPR_ERROR, "%s value '%s' unknown, assuming 'blend'", + GRPC_ARG_OPTIMIZATION_TARGET, + channel_args->args[i].value.string); + } } else { static const struct { const char *channel_arg_name; @@ -341,21 +512,28 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, } settings_map[] = { {GRPC_ARG_MAX_CONCURRENT_STREAMS, GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, - {-1, 0, INT_MAX}, + {-1, 0, INT32_MAX}, {true, false}}, {GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_DECODER, GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE, - {-1, 0, INT_MAX}, + {-1, 0, INT32_MAX}, {true, true}}, {GRPC_ARG_MAX_METADATA_SIZE, GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE, - {-1, 0, INT_MAX}, + {-1, 0, INT32_MAX}, {true, true}}, {GRPC_ARG_HTTP2_MAX_FRAME_SIZE, GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE, {-1, 16384, 16777215}, {true, true}}, - }; + {GRPC_ARG_HTTP2_ENABLE_TRUE_BINARY, + GRPC_CHTTP2_SETTINGS_GRPC_ALLOW_TRUE_BINARY_METADATA, + {1, 0, 1}, + {true, true}}, + {GRPC_ARG_HTTP2_STREAM_LOOKAHEAD_BYTES, + GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE, + {-1, 5, INT32_MAX}, + {true, true}}}; for (j = 0; j < (int)GPR_ARRAY_SIZE(settings_map); j++) { if (0 == strcmp(channel_args->args[i].key, settings_map[j].channel_arg_name)) { @@ -367,8 +545,8 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, int value = grpc_channel_arg_get_integer( &channel_args->args[i], settings_map[j].integer_options); if (value >= 0) { - push_setting(exec_ctx, t, settings_map[j].setting_id, - (uint32_t)value); + queue_setting_update(exec_ctx, t, settings_map[j].setting_id, + (uint32_t)value); } } break; @@ -378,7 +556,33 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, } } - grpc_chttp2_initiate_write(exec_ctx, t, false, "init"); + GRPC_CLOSURE_INIT(&t->write_action, write_action, t, + t->opt_target == GRPC_CHTTP2_OPTIMIZE_FOR_THROUGHPUT + ? grpc_executor_scheduler + : grpc_schedule_on_exec_ctx); + + t->ping_state.pings_before_data_required = + t->ping_policy.max_pings_without_data; + t->ping_state.is_delayed_ping_timer_set = false; + + t->ping_recv_state.last_ping_recv_time = gpr_inf_past(GPR_CLOCK_MONOTONIC); + t->ping_recv_state.ping_strikes = 0; + + /* Start keepalive pings */ + if (gpr_time_cmp(t->keepalive_time, gpr_inf_future(GPR_TIMESPAN)) != 0) { + t->keepalive_state = GRPC_CHTTP2_KEEPALIVE_STATE_WAITING; + GRPC_CHTTP2_REF_TRANSPORT(t, "init keepalive ping"); + grpc_timer_init( + exec_ctx, &t->keepalive_ping_timer, + gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), t->keepalive_time), + &t->init_keepalive_ping_locked, gpr_now(GPR_CLOCK_MONOTONIC)); + } else { + /* Use GRPC_CHTTP2_KEEPALIVE_STATE_DISABLED to indicate there are no + inflight keeaplive timers */ + t->keepalive_state = GRPC_CHTTP2_KEEPALIVE_STATE_DISABLED; + } + + grpc_chttp2_initiate_write(exec_ctx, t, "init"); post_benign_reclaimer(exec_ctx, t); } @@ -388,39 +592,55 @@ static void destroy_transport_locked(grpc_exec_ctx *exec_ctx, void *tp, t->destroying = 1; close_transport_locked( exec_ctx, t, - grpc_error_set_int(GRPC_ERROR_CREATE("Transport destroyed"), - GRPC_ERROR_INT_OCCURRED_DURING_WRITE, t->write_state)); + grpc_error_set_int( + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Transport destroyed"), + GRPC_ERROR_INT_OCCURRED_DURING_WRITE, t->write_state)); GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "destroy"); } static void destroy_transport(grpc_exec_ctx *exec_ctx, grpc_transport *gt) { grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt; - grpc_combiner_execute(exec_ctx, t->combiner, - grpc_closure_create(destroy_transport_locked, t), - GRPC_ERROR_NONE, false); + GRPC_CLOSURE_SCHED(exec_ctx, + GRPC_CLOSURE_CREATE(destroy_transport_locked, t, + grpc_combiner_scheduler(t->combiner)), + GRPC_ERROR_NONE); } static void close_transport_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, grpc_error *error) { if (!t->closed) { + if (!grpc_error_has_clear_grpc_status(error)) { + error = grpc_error_set_int(error, GRPC_ERROR_INT_GRPC_STATUS, + GRPC_STATUS_UNAVAILABLE); + } if (t->write_state != GRPC_CHTTP2_WRITE_STATE_IDLE) { if (t->close_transport_on_writes_finished == NULL) { t->close_transport_on_writes_finished = - GRPC_ERROR_CREATE("Delayed close due to in-progress write"); + GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "Delayed close due to in-progress write"); } t->close_transport_on_writes_finished = grpc_error_add_child(t->close_transport_on_writes_finished, error); return; } - if (!grpc_error_get_int(error, GRPC_ERROR_INT_GRPC_STATUS, NULL)) { - error = grpc_error_set_int(error, GRPC_ERROR_INT_GRPC_STATUS, - GRPC_STATUS_UNAVAILABLE); - } t->closed = 1; connectivity_state_set(exec_ctx, t, GRPC_CHANNEL_SHUTDOWN, GRPC_ERROR_REF(error), "close_transport"); - grpc_endpoint_shutdown(exec_ctx, t->ep); + grpc_endpoint_shutdown(exec_ctx, t->ep, GRPC_ERROR_REF(error)); + switch (t->keepalive_state) { + case GRPC_CHTTP2_KEEPALIVE_STATE_WAITING: + grpc_timer_cancel(exec_ctx, &t->keepalive_ping_timer); + break; + case GRPC_CHTTP2_KEEPALIVE_STATE_PINGING: + grpc_timer_cancel(exec_ctx, &t->keepalive_ping_timer); + grpc_timer_cancel(exec_ctx, &t->keepalive_watchdog_timer); + break; + case GRPC_CHTTP2_KEEPALIVE_STATE_DYING: + case GRPC_CHTTP2_KEEPALIVE_STATE_DISABLED: + /* keepalive timers are not set in these two states */ + break; + } /* flush writable stream list to avoid dangling references */ grpc_chttp2_stream *s; @@ -428,11 +648,12 @@ static void close_transport_locked(grpc_exec_ctx *exec_ctx, GRPC_CHTTP2_STREAM_UNREF(exec_ctx, s, "chttp2_writing:close"); } end_all_the_calls(exec_ctx, t, GRPC_ERROR_REF(error)); + cancel_pings(exec_ctx, t, GRPC_ERROR_REF(error)); } GRPC_ERROR_UNREF(error); } -#ifdef GRPC_STREAM_REFCOUNT_DEBUG +#ifndef NDEBUG void grpc_chttp2_stream_ref(grpc_chttp2_stream *s, const char *reason) { grpc_stream_ref(s->refcount, reason); } @@ -451,43 +672,41 @@ void grpc_chttp2_stream_unref(grpc_exec_ctx *exec_ctx, grpc_chttp2_stream *s) { static int init_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt, grpc_stream *gs, grpc_stream_refcount *refcount, - const void *server_data) { + const void *server_data, gpr_arena *arena) { GPR_TIMER_BEGIN("init_stream", 0); grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt; grpc_chttp2_stream *s = (grpc_chttp2_stream *)gs; - memset(s, 0, sizeof(*s)); - s->t = t; s->refcount = refcount; /* We reserve one 'active stream' that's dropped when the stream is read-closed. The others are for incoming_byte_streams that are actively reading */ - gpr_ref_init(&s->active_streams, 1); GRPC_CHTTP2_STREAM_REF(s, "chttp2"); - grpc_chttp2_incoming_metadata_buffer_init(&s->metadata_buffer[0]); - grpc_chttp2_incoming_metadata_buffer_init(&s->metadata_buffer[1]); + grpc_chttp2_incoming_metadata_buffer_init(&s->metadata_buffer[0], arena); + grpc_chttp2_incoming_metadata_buffer_init(&s->metadata_buffer[1], arena); grpc_chttp2_data_parser_init(&s->data_parser); grpc_slice_buffer_init(&s->flow_controlled_buffer); s->deadline = gpr_inf_future(GPR_CLOCK_MONOTONIC); - grpc_closure_init(&s->complete_fetch, complete_fetch, s); - grpc_closure_init(&s->complete_fetch_locked, complete_fetch_locked, s); + GRPC_CLOSURE_INIT(&s->complete_fetch_locked, complete_fetch_locked, s, + grpc_schedule_on_exec_ctx); + grpc_slice_buffer_init(&s->unprocessed_incoming_frames_buffer); + grpc_slice_buffer_init(&s->frame_storage); + s->pending_byte_stream = false; + GRPC_CLOSURE_INIT(&s->reset_byte_stream, reset_byte_stream, s, + grpc_combiner_scheduler(t->combiner)); GRPC_CHTTP2_REF_TRANSPORT(t, "stream"); if (server_data) { s->id = (uint32_t)(uintptr_t)server_data; - s->outgoing_window = t->settings[GRPC_PEER_SETTINGS] - [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]; - s->incoming_window = s->max_recv_bytes = - t->settings[GRPC_SENT_SETTINGS] - [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]; *t->accepting_stream = s; grpc_chttp2_stream_map_add(&t->stream_map, s->id, s); post_destructive_reclaimer(exec_ctx, t); } + s->flow_control.s = s; GPR_TIMER_END("init_stream", 0); return 0; @@ -495,7 +714,6 @@ static int init_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt, static void destroy_stream_locked(grpc_exec_ctx *exec_ctx, void *sp, grpc_error *error) { - grpc_byte_stream *bs; grpc_chttp2_stream *s = sp; grpc_chttp2_transport *t = s->t; @@ -506,11 +724,20 @@ static void destroy_stream_locked(grpc_exec_ctx *exec_ctx, void *sp, GPR_ASSERT(grpc_chttp2_stream_map_find(&t->stream_map, s->id) == NULL); } - while ((bs = grpc_chttp2_incoming_frame_queue_pop(&s->incoming_frames))) { - incoming_byte_stream_destroy_locked(exec_ctx, bs, GRPC_ERROR_NONE); + grpc_slice_buffer_destroy_internal(exec_ctx, + &s->unprocessed_incoming_frames_buffer); + grpc_slice_buffer_destroy_internal(exec_ctx, &s->frame_storage); + if (s->compressed_data_buffer) { + grpc_slice_buffer_destroy_internal(exec_ctx, s->compressed_data_buffer); + gpr_free(s->compressed_data_buffer); + } + if (s->decompressed_data_buffer) { + grpc_slice_buffer_destroy_internal(exec_ctx, s->decompressed_data_buffer); + gpr_free(s->decompressed_data_buffer); } grpc_chttp2_list_remove_stalled_by_transport(t, s); + grpc_chttp2_list_remove_stalled_by_stream(t, s); for (int i = 0; i < STREAM_LIST_COUNT; i++) { if (s->included[i]) { @@ -527,29 +754,45 @@ static void destroy_stream_locked(grpc_exec_ctx *exec_ctx, void *sp, GPR_ASSERT(s->recv_message_ready == NULL); GPR_ASSERT(s->recv_trailing_metadata_finished == NULL); grpc_chttp2_data_parser_destroy(exec_ctx, &s->data_parser); - grpc_chttp2_incoming_metadata_buffer_destroy(&s->metadata_buffer[0]); - grpc_chttp2_incoming_metadata_buffer_destroy(&s->metadata_buffer[1]); - grpc_slice_buffer_destroy(&s->flow_controlled_buffer); + grpc_chttp2_incoming_metadata_buffer_destroy(exec_ctx, + &s->metadata_buffer[0]); + grpc_chttp2_incoming_metadata_buffer_destroy(exec_ctx, + &s->metadata_buffer[1]); + grpc_slice_buffer_destroy_internal(exec_ctx, &s->flow_controlled_buffer); GRPC_ERROR_UNREF(s->read_closed_error); GRPC_ERROR_UNREF(s->write_closed_error); + GRPC_ERROR_UNREF(s->byte_stream_error); + + grpc_chttp2_flowctl_destroy_stream(&t->flow_control, &s->flow_control); GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "stream"); GPR_TIMER_END("destroy_stream", 0); - gpr_free(s->destroy_stream_arg); + GRPC_CLOSURE_SCHED(exec_ctx, s->destroy_stream_arg, GRPC_ERROR_NONE); } static void destroy_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt, - grpc_stream *gs, void *and_free_memory) { + grpc_stream *gs, + grpc_closure *then_schedule_closure) { GPR_TIMER_BEGIN("destroy_stream", 0); grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt; grpc_chttp2_stream *s = (grpc_chttp2_stream *)gs; - s->destroy_stream_arg = and_free_memory; - grpc_closure_init(&s->destroy_stream, destroy_stream_locked, s); - grpc_combiner_execute(exec_ctx, t->combiner, &s->destroy_stream, - GRPC_ERROR_NONE, false); + if (s->stream_compression_ctx != NULL) { + grpc_stream_compression_context_destroy(s->stream_compression_ctx); + s->stream_compression_ctx = NULL; + } + if (s->stream_decompression_ctx != NULL) { + grpc_stream_compression_context_destroy(s->stream_decompression_ctx); + s->stream_decompression_ctx = NULL; + } + + s->destroy_stream_arg = then_schedule_closure; + GRPC_CLOSURE_SCHED( + exec_ctx, GRPC_CLOSURE_INIT(&s->destroy_stream, destroy_stream_locked, s, + grpc_combiner_scheduler(t->combiner)), + GRPC_ERROR_NONE); GPR_TIMER_END("destroy_stream", 0); } @@ -586,8 +829,6 @@ static const char *write_state_name(grpc_chttp2_write_state st) { return "WRITING"; case GRPC_CHTTP2_WRITE_STATE_WRITING_WITH_MORE: return "WRITING+MORE"; - case GRPC_CHTTP2_WRITE_STATE_WRITING_WITH_MORE_AND_COVERED_BY_POLLER: - return "WRITING+MORE+COVERED"; } GPR_UNREACHABLE_CODE(return "UNKNOWN"); } @@ -600,7 +841,7 @@ static void set_write_state(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, write_state_name(st), reason)); t->write_state = st; if (st == GRPC_CHTTP2_WRITE_STATE_IDLE) { - grpc_exec_ctx_enqueue_list(exec_ctx, &t->run_after_write, NULL); + GRPC_CLOSURE_LIST_SCHED(exec_ctx, &t->run_after_write); if (t->close_transport_on_writes_finished != NULL) { grpc_error *err = t->close_transport_on_writes_finished; t->close_transport_on_writes_finished = NULL; @@ -610,47 +851,45 @@ static void set_write_state(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, } void grpc_chttp2_initiate_write(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport *t, - bool covered_by_poller, const char *reason) { + grpc_chttp2_transport *t, const char *reason) { GPR_TIMER_BEGIN("grpc_chttp2_initiate_write", 0); switch (t->write_state) { case GRPC_CHTTP2_WRITE_STATE_IDLE: set_write_state(exec_ctx, t, GRPC_CHTTP2_WRITE_STATE_WRITING, reason); GRPC_CHTTP2_REF_TRANSPORT(t, "writing"); - grpc_combiner_execute_finally(exec_ctx, t->combiner, - &t->write_action_begin_locked, - GRPC_ERROR_NONE, covered_by_poller); + GRPC_CLOSURE_SCHED( + exec_ctx, + GRPC_CLOSURE_INIT(&t->write_action_begin_locked, + write_action_begin_locked, t, + grpc_combiner_finally_scheduler(t->combiner)), + GRPC_ERROR_NONE); break; case GRPC_CHTTP2_WRITE_STATE_WRITING: - set_write_state( - exec_ctx, t, - covered_by_poller - ? GRPC_CHTTP2_WRITE_STATE_WRITING_WITH_MORE_AND_COVERED_BY_POLLER - : GRPC_CHTTP2_WRITE_STATE_WRITING_WITH_MORE, - reason); + set_write_state(exec_ctx, t, GRPC_CHTTP2_WRITE_STATE_WRITING_WITH_MORE, + reason); break; case GRPC_CHTTP2_WRITE_STATE_WRITING_WITH_MORE: - if (covered_by_poller) { - set_write_state( - exec_ctx, t, - GRPC_CHTTP2_WRITE_STATE_WRITING_WITH_MORE_AND_COVERED_BY_POLLER, - reason); - } - break; - case GRPC_CHTTP2_WRITE_STATE_WRITING_WITH_MORE_AND_COVERED_BY_POLLER: break; } GPR_TIMER_END("grpc_chttp2_initiate_write", 0); } -void grpc_chttp2_become_writable(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport *t, - grpc_chttp2_stream *s, bool covered_by_poller, - const char *reason) { +void grpc_chttp2_become_writable( + grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, grpc_chttp2_stream *s, + grpc_chttp2_stream_write_type stream_write_type, const char *reason) { if (!t->closed && grpc_chttp2_list_add_writable_stream(t, s)) { GRPC_CHTTP2_STREAM_REF(s, "chttp2_writing:become"); - grpc_chttp2_initiate_write(exec_ctx, t, covered_by_poller, reason); + } + switch (stream_write_type) { + case GRPC_CHTTP2_STREAM_WRITE_PIGGYBACK: + break; + case GRPC_CHTTP2_STREAM_WRITE_INITIATE_COVERED: + grpc_chttp2_initiate_write(exec_ctx, t, reason); + break; + case GRPC_CHTTP2_STREAM_WRITE_INITIATE_UNCOVERED: + grpc_chttp2_initiate_write(exec_ctx, t, reason); + break; } } @@ -659,14 +898,23 @@ static void write_action_begin_locked(grpc_exec_ctx *exec_ctx, void *gt, GPR_TIMER_BEGIN("write_action_begin_locked", 0); grpc_chttp2_transport *t = gt; GPR_ASSERT(t->write_state != GRPC_CHTTP2_WRITE_STATE_IDLE); - if (!t->closed && grpc_chttp2_begin_write(exec_ctx, t)) { - set_write_state(exec_ctx, t, GRPC_CHTTP2_WRITE_STATE_WRITING, - "begin writing"); - grpc_exec_ctx_sched(exec_ctx, &t->write_action, GRPC_ERROR_NONE, NULL); - } else { - set_write_state(exec_ctx, t, GRPC_CHTTP2_WRITE_STATE_IDLE, - "begin writing nothing"); - GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "writing"); + switch (t->closed ? GRPC_CHTTP2_NOTHING_TO_WRITE + : grpc_chttp2_begin_write(exec_ctx, t)) { + case GRPC_CHTTP2_NOTHING_TO_WRITE: + set_write_state(exec_ctx, t, GRPC_CHTTP2_WRITE_STATE_IDLE, + "begin writing nothing"); + GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "writing"); + break; + case GRPC_CHTTP2_PARTIAL_WRITE: + set_write_state(exec_ctx, t, GRPC_CHTTP2_WRITE_STATE_WRITING_WITH_MORE, + "begin writing partial"); + GRPC_CLOSURE_SCHED(exec_ctx, &t->write_action, GRPC_ERROR_NONE); + break; + case GRPC_CHTTP2_FULL_WRITE: + set_write_state(exec_ctx, t, GRPC_CHTTP2_WRITE_STATE_WRITING, + "begin writing"); + GRPC_CLOSURE_SCHED(exec_ctx, &t->write_action, GRPC_ERROR_NONE); + break; } GPR_TIMER_END("write_action_begin_locked", 0); } @@ -674,19 +922,13 @@ static void write_action_begin_locked(grpc_exec_ctx *exec_ctx, void *gt, static void write_action(grpc_exec_ctx *exec_ctx, void *gt, grpc_error *error) { grpc_chttp2_transport *t = gt; GPR_TIMER_BEGIN("write_action", 0); - grpc_endpoint_write(exec_ctx, t->ep, &t->outbuf, &t->write_action_end); + grpc_endpoint_write( + exec_ctx, t->ep, &t->outbuf, + GRPC_CLOSURE_INIT(&t->write_action_end_locked, write_action_end_locked, t, + grpc_combiner_scheduler(t->combiner))); GPR_TIMER_END("write_action", 0); } -static void write_action_end(grpc_exec_ctx *exec_ctx, void *gt, - grpc_error *error) { - grpc_chttp2_transport *t = gt; - GPR_TIMER_BEGIN("write_action_end", 0); - grpc_combiner_execute(exec_ctx, t->combiner, &t->write_action_end_locked, - GRPC_ERROR_REF(error), false); - GPR_TIMER_END("write_action_end", 0); -} - static void write_action_end_locked(grpc_exec_ctx *exec_ctx, void *tp, grpc_error *error) { GPR_TIMER_BEGIN("terminate_writing_with_lock", 0); @@ -699,7 +941,8 @@ static void write_action_end_locked(grpc_exec_ctx *exec_ctx, void *tp, if (t->sent_goaway_state == GRPC_CHTTP2_GOAWAY_SEND_SCHEDULED) { t->sent_goaway_state = GRPC_CHTTP2_GOAWAY_SENT; if (grpc_chttp2_stream_map_size(&t->stream_map) == 0) { - close_transport_locked(exec_ctx, t, GRPC_ERROR_CREATE("goaway sent")); + close_transport_locked( + exec_ctx, t, GRPC_ERROR_CREATE_FROM_STATIC_STRING("goaway sent")); } } @@ -716,18 +959,12 @@ static void write_action_end_locked(grpc_exec_ctx *exec_ctx, void *tp, set_write_state(exec_ctx, t, GRPC_CHTTP2_WRITE_STATE_WRITING, "continue writing [!covered]"); GRPC_CHTTP2_REF_TRANSPORT(t, "writing"); - grpc_combiner_execute_finally(exec_ctx, t->combiner, - &t->write_action_begin_locked, - GRPC_ERROR_NONE, false); - break; - case GRPC_CHTTP2_WRITE_STATE_WRITING_WITH_MORE_AND_COVERED_BY_POLLER: - GPR_TIMER_MARK("state=writing_stale_with_poller", 0); - set_write_state(exec_ctx, t, GRPC_CHTTP2_WRITE_STATE_WRITING, - "continue writing [covered]"); - GRPC_CHTTP2_REF_TRANSPORT(t, "writing"); - grpc_combiner_execute_finally(exec_ctx, t->combiner, - &t->write_action_begin_locked, - GRPC_ERROR_NONE, true); + GRPC_CLOSURE_RUN( + exec_ctx, + GRPC_CLOSURE_INIT(&t->write_action_begin_locked, + write_action_begin_locked, t, + grpc_combiner_finally_scheduler(t->combiner)), + GRPC_ERROR_NONE); break; } @@ -737,8 +974,11 @@ static void write_action_end_locked(grpc_exec_ctx *exec_ctx, void *tp, GPR_TIMER_END("terminate_writing_with_lock", 0); } -static void push_setting(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, - grpc_chttp2_setting_id id, uint32_t value) { +// Dirties an HTTP2 setting to be sent out next time a writing path occurs. +// If the change needs to occur immediately, manually initiate a write. +static void queue_setting_update(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t, + grpc_chttp2_setting_id id, uint32_t value) { const grpc_chttp2_setting_parameters *sp = &grpc_chttp2_settings_parameters[id]; uint32_t use_value = GPR_CLAMP(value, sp->min_value, sp->max_value); @@ -749,7 +989,6 @@ static void push_setting(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, if (use_value != t->settings[GRPC_LOCAL_SETTINGS][id]) { t->settings[GRPC_LOCAL_SETTINGS][id] = use_value; t->dirtied_local_settings = 1; - grpc_chttp2_initiate_write(exec_ctx, t, false, "push_setting"); } } @@ -757,28 +996,44 @@ void grpc_chttp2_add_incoming_goaway(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, uint32_t goaway_error, grpc_slice goaway_text) { - char *msg = grpc_dump_slice(goaway_text, GPR_DUMP_HEX | GPR_DUMP_ASCII); - GRPC_CHTTP2_IF_TRACING( - gpr_log(GPR_DEBUG, "got goaway [%d]: %s", goaway_error, msg)); - grpc_slice_unref(goaway_text); + // GRPC_CHTTP2_IF_TRACING( + // gpr_log(GPR_DEBUG, "got goaway [%d]: %s", goaway_error, msg)); t->seen_goaway = 1; + + /* When a client receives a GOAWAY with error code ENHANCE_YOUR_CALM and debug + * data equal to "too_many_pings", it should log the occurrence at a log level + * that is enabled by default and double the configured KEEPALIVE_TIME used + * for new connections on that channel. */ + if (t->is_client && goaway_error == GRPC_HTTP2_ENHANCE_YOUR_CALM && + grpc_slice_str_cmp(goaway_text, "too_many_pings") == 0) { + gpr_log(GPR_ERROR, + "Received a GOAWAY with error code ENHANCE_YOUR_CALM and debug " + "data equal to \"too_many_pings\""); + double current_keepalive_time_ms = + gpr_timespec_to_micros(t->keepalive_time) / 1000; + t->keepalive_time = + current_keepalive_time_ms > INT_MAX / KEEPALIVE_TIME_BACKOFF_MULTIPLIER + ? gpr_inf_future(GPR_TIMESPAN) + : gpr_time_from_millis((int64_t)(current_keepalive_time_ms * + KEEPALIVE_TIME_BACKOFF_MULTIPLIER), + GPR_TIMESPAN); + } + /* lie: use transient failure from the transport to indicate goaway has been * received */ connectivity_state_set( exec_ctx, t, GRPC_CHANNEL_TRANSIENT_FAILURE, grpc_error_set_str( - grpc_error_set_int(GRPC_ERROR_CREATE("GOAWAY received"), - GRPC_ERROR_INT_HTTP2_ERROR, - (intptr_t)goaway_error), - GRPC_ERROR_STR_RAW_BYTES, msg), + grpc_error_set_int( + GRPC_ERROR_CREATE_FROM_STATIC_STRING("GOAWAY received"), + GRPC_ERROR_INT_HTTP2_ERROR, (intptr_t)goaway_error), + GRPC_ERROR_STR_RAW_BYTES, goaway_text), "got_goaway"); - gpr_free(msg); } static void maybe_start_some_streams(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t) { grpc_chttp2_stream *s; - uint32_t stream_incoming_window; /* start streams where we have free grpc_chttp2_stream ids and free * concurrency */ while (t->next_stream_id <= MAX_CLIENT_STREAM_ID && @@ -796,29 +1051,26 @@ static void maybe_start_some_streams(grpc_exec_ctx *exec_ctx, t->next_stream_id += 2; if (t->next_stream_id >= MAX_CLIENT_STREAM_ID) { - connectivity_state_set(exec_ctx, t, GRPC_CHANNEL_TRANSIENT_FAILURE, - GRPC_ERROR_CREATE("Stream IDs exhausted"), - "no_more_stream_ids"); + connectivity_state_set( + exec_ctx, t, GRPC_CHANNEL_TRANSIENT_FAILURE, + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Stream IDs exhausted"), + "no_more_stream_ids"); } - s->outgoing_window = t->settings[GRPC_PEER_SETTINGS] - [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]; - s->incoming_window = stream_incoming_window = - t->settings[GRPC_SENT_SETTINGS] - [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]; - s->max_recv_bytes = GPR_MAX(stream_incoming_window, s->max_recv_bytes); grpc_chttp2_stream_map_add(&t->stream_map, s->id, s); post_destructive_reclaimer(exec_ctx, t); - grpc_chttp2_become_writable(exec_ctx, t, s, true, "new_stream"); + grpc_chttp2_become_writable(exec_ctx, t, s, + GRPC_CHTTP2_STREAM_WRITE_INITIATE_COVERED, + "new_stream"); } /* cancel out streams that will never be started */ while (t->next_stream_id >= MAX_CLIENT_STREAM_ID && grpc_chttp2_list_pop_waiting_for_concurrency(t, &s)) { grpc_chttp2_cancel_stream( exec_ctx, t, s, - grpc_error_set_int(GRPC_ERROR_CREATE("Stream IDs exhausted"), - GRPC_ERROR_INT_GRPC_STATUS, - GRPC_STATUS_UNAVAILABLE)); + grpc_error_set_int( + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Stream IDs exhausted"), + GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE)); } } @@ -841,7 +1093,7 @@ static void null_then_run_closure(grpc_exec_ctx *exec_ctx, grpc_closure **closure, grpc_error *error) { grpc_closure *c = *closure; *closure = NULL; - grpc_closure_run(exec_ctx, c, error); + GRPC_CLOSURE_RUN(exec_ctx, c, error); } void grpc_chttp2_complete_closure_step(grpc_exec_ctx *exec_ctx, @@ -856,7 +1108,7 @@ void grpc_chttp2_complete_closure_step(grpc_exec_ctx *exec_ctx, return; } closure->next_data.scratch -= CLOSURE_BARRIER_FIRST_REF_BIT; - if (grpc_http_trace) { + if (GRPC_TRACER_ON(grpc_http_trace)) { const char *errstr = grpc_error_string(error); gpr_log(GPR_DEBUG, "complete_closure_step: %p refs=%d flags=0x%04x desc=%s err=%s", @@ -864,15 +1116,14 @@ void grpc_chttp2_complete_closure_step(grpc_exec_ctx *exec_ctx, (int)(closure->next_data.scratch / CLOSURE_BARRIER_FIRST_REF_BIT), (int)(closure->next_data.scratch % CLOSURE_BARRIER_FIRST_REF_BIT), desc, errstr); - grpc_error_free_string(errstr); } if (error != GRPC_ERROR_NONE) { if (closure->error_data.error == GRPC_ERROR_NONE) { - closure->error_data.error = - GRPC_ERROR_CREATE("Error in HTTP transport completing operation"); - closure->error_data.error = - grpc_error_set_str(closure->error_data.error, - GRPC_ERROR_STR_TARGET_ADDRESS, t->peer_string); + closure->error_data.error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "Error in HTTP transport completing operation"); + closure->error_data.error = grpc_error_set_str( + closure->error_data.error, GRPC_ERROR_STR_TARGET_ADDRESS, + grpc_slice_from_copied_string(t->peer_string)); } closure->error_data.error = grpc_error_add_child(closure->error_data.error, error); @@ -884,7 +1135,7 @@ void grpc_chttp2_complete_closure_step(grpc_exec_ctx *exec_ctx, } if ((t->write_state == GRPC_CHTTP2_WRITE_STATE_IDLE) || !(closure->next_data.scratch & CLOSURE_BARRIER_MAY_COVER_WRITE)) { - grpc_closure_run(exec_ctx, closure, closure->error_data.error); + GRPC_CLOSURE_RUN(exec_ctx, closure, closure->error_data.error); } else { grpc_closure_list_append(&t->run_after_write, closure, closure->error_data.error); @@ -893,25 +1144,31 @@ void grpc_chttp2_complete_closure_step(grpc_exec_ctx *exec_ctx, } static bool contains_non_ok_status(grpc_metadata_batch *batch) { - grpc_linked_mdelem *l; - for (l = batch->list.head; l; l = l->next) { - if (l->md->key == GRPC_MDSTR_GRPC_STATUS && - l->md != GRPC_MDELEM_GRPC_STATUS_0) { - return true; - } + if (batch->idx.named.grpc_status != NULL) { + return !grpc_mdelem_eq(batch->idx.named.grpc_status->md, + GRPC_MDELEM_GRPC_STATUS_0); } return false; } +static void maybe_become_writable_due_to_send_msg(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t, + grpc_chttp2_stream *s) { + if (s->id != 0 && (!s->write_buffering || + s->flow_controlled_buffer.length > t->write_buffer_size)) { + grpc_chttp2_become_writable(exec_ctx, t, s, + GRPC_CHTTP2_STREAM_WRITE_INITIATE_COVERED, + "op.send_message"); + } +} + static void add_fetched_slice_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, grpc_chttp2_stream *s) { s->fetched_send_message_length += (uint32_t)GRPC_SLICE_LENGTH(s->fetching_slice); grpc_slice_buffer_add(&s->flow_controlled_buffer, s->fetching_slice); - if (s->id != 0) { - grpc_chttp2_become_writable(exec_ctx, t, s, true, "op.send_message"); - } + maybe_become_writable_due_to_send_msg(exec_ctx, t, s); } static void continue_fetching_send_locked(grpc_exec_ctx *exec_ctx, @@ -924,6 +1181,7 @@ static void continue_fetching_send_locked(grpc_exec_ctx *exec_ctx, return; /* early out */ } if (s->fetched_send_message_length == s->fetching_send_message->length) { + grpc_byte_stream_destroy(exec_ctx, s->fetching_send_message); int64_t notify_offset = s->next_message_end_offset; if (notify_offset <= s->flow_controlled_bytes_written) { grpc_chttp2_complete_closure_step( @@ -945,9 +1203,15 @@ static void continue_fetching_send_locked(grpc_exec_ctx *exec_ctx, s->fetching_send_message = NULL; return; /* early out */ } else if (grpc_byte_stream_next(exec_ctx, s->fetching_send_message, - &s->fetching_slice, UINT32_MAX, - &s->complete_fetch)) { - add_fetched_slice_locked(exec_ctx, t, s); + UINT32_MAX, &s->complete_fetch_locked)) { + grpc_error *error = grpc_byte_stream_pull( + exec_ctx, s->fetching_send_message, &s->fetching_slice); + if (error != GRPC_ERROR_NONE) { + grpc_byte_stream_destroy(exec_ctx, s->fetching_send_message); + grpc_chttp2_cancel_stream(exec_ctx, t, s, error); + } else { + add_fetched_slice_locked(exec_ctx, t, s); + } } } } @@ -957,32 +1221,31 @@ static void complete_fetch_locked(grpc_exec_ctx *exec_ctx, void *gs, grpc_chttp2_stream *s = gs; grpc_chttp2_transport *t = s->t; if (error == GRPC_ERROR_NONE) { - add_fetched_slice_locked(exec_ctx, t, s); - continue_fetching_send_locked(exec_ctx, t, s); - } else { - /* TODO(ctiller): what to do here */ - abort(); + error = grpc_byte_stream_pull(exec_ctx, s->fetching_send_message, + &s->fetching_slice); + if (error == GRPC_ERROR_NONE) { + add_fetched_slice_locked(exec_ctx, t, s); + continue_fetching_send_locked(exec_ctx, t, s); + } + } + if (error != GRPC_ERROR_NONE) { + grpc_byte_stream_destroy(exec_ctx, s->fetching_send_message); + grpc_chttp2_cancel_stream(exec_ctx, t, s, error); } -} - -static void complete_fetch(grpc_exec_ctx *exec_ctx, void *gs, - grpc_error *error) { - grpc_chttp2_stream *s = gs; - grpc_chttp2_transport *t = s->t; - grpc_combiner_execute(exec_ctx, t->combiner, &s->complete_fetch_locked, - GRPC_ERROR_REF(error), - s->complete_fetch_covered_by_poller); } static void do_nothing(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {} static void log_metadata(const grpc_metadata_batch *md_batch, uint32_t id, bool is_client, bool is_initial) { - for (grpc_linked_mdelem *md = md_batch->list.head; md != md_batch->list.tail; + for (grpc_linked_mdelem *md = md_batch->list.head; md != NULL; md = md->next) { + char *key = grpc_slice_to_c_string(GRPC_MDKEY(md->md)); + char *value = grpc_slice_to_c_string(GRPC_MDVALUE(md->md)); gpr_log(GPR_INFO, "HTTP:%d:%s:%s: %s: %s", id, is_initial ? "HDR" : "TRL", - is_client ? "CLI" : "SVR", grpc_mdstr_as_c_string(md->md->key), - grpc_mdstr_as_c_string(md->md->value)); + is_client ? "CLI" : "SVR", key, value); + gpr_free(key); + gpr_free(value); } } @@ -990,26 +1253,30 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op, grpc_error *error_ignored) { GPR_TIMER_BEGIN("perform_stream_op_locked", 0); - grpc_transport_stream_op *op = stream_op; - grpc_chttp2_transport *t = op->transport_private.args[0]; - grpc_chttp2_stream *s = op->transport_private.args[1]; + grpc_transport_stream_op_batch *op = stream_op; + grpc_chttp2_stream *s = op->handler_private.extra_arg; + grpc_transport_stream_op_batch_payload *op_payload = op->payload; + grpc_chttp2_transport *t = s->t; - if (grpc_http_trace) { - char *str = grpc_transport_stream_op_string(op); + if (GRPC_TRACER_ON(grpc_http_trace)) { + char *str = grpc_transport_stream_op_batch_string(op); gpr_log(GPR_DEBUG, "perform_stream_op_locked: %s; on_complete = %p", str, op->on_complete); gpr_free(str); if (op->send_initial_metadata) { - log_metadata(op->send_initial_metadata, s->id, t->is_client, true); + log_metadata(op_payload->send_initial_metadata.send_initial_metadata, + s->id, t->is_client, true); } if (op->send_trailing_metadata) { - log_metadata(op->send_trailing_metadata, s->id, t->is_client, false); + log_metadata(op_payload->send_trailing_metadata.send_trailing_metadata, + s->id, t->is_client, false); } } grpc_closure *on_complete = op->on_complete; if (on_complete == NULL) { - on_complete = grpc_closure_create(do_nothing, NULL); + on_complete = + GRPC_CLOSURE_CREATE(do_nothing, NULL, grpc_schedule_on_exec_ctx); } /* use final_data as a barrier until enqueue time; the inital counter is @@ -1017,27 +1284,25 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op, on_complete->next_data.scratch = CLOSURE_BARRIER_FIRST_REF_BIT; on_complete->error_data.error = GRPC_ERROR_NONE; - if (op->collect_stats != NULL) { + if (op->collect_stats) { GPR_ASSERT(s->collecting_stats == NULL); - s->collecting_stats = op->collect_stats; + s->collecting_stats = op_payload->collect_stats.collect_stats; on_complete->next_data.scratch |= CLOSURE_BARRIER_STATS_BIT; } - if (op->cancel_error != GRPC_ERROR_NONE) { - grpc_chttp2_cancel_stream(exec_ctx, t, s, GRPC_ERROR_REF(op->cancel_error)); + if (op->cancel_stream) { + grpc_chttp2_cancel_stream(exec_ctx, t, s, + op_payload->cancel_stream.cancel_error); } - if (op->close_error != GRPC_ERROR_NONE) { - close_from_api(exec_ctx, t, s, GRPC_ERROR_REF(op->close_error)); - } - - if (op->send_initial_metadata != NULL) { + if (op->send_initial_metadata) { GPR_ASSERT(s->send_initial_metadata_finished == NULL); on_complete->next_data.scratch |= CLOSURE_BARRIER_MAY_COVER_WRITE; s->send_initial_metadata_finished = add_closure_barrier(on_complete); - s->send_initial_metadata = op->send_initial_metadata; + s->send_initial_metadata = + op_payload->send_initial_metadata.send_initial_metadata; const size_t metadata_size = - grpc_metadata_batch_size(op->send_initial_metadata); + grpc_metadata_batch_size(s->send_initial_metadata); const size_t metadata_peer_limit = t->settings[GRPC_PEER_SETTINGS] [GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE]; @@ -1050,14 +1315,15 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op, exec_ctx, t, s, grpc_error_set_int( grpc_error_set_int( - grpc_error_set_int( - GRPC_ERROR_CREATE("to-be-sent initial metadata size " - "exceeds peer limit"), - GRPC_ERROR_INT_SIZE, (intptr_t)metadata_size), + grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "to-be-sent initial metadata size " + "exceeds peer limit"), + GRPC_ERROR_INT_SIZE, + (intptr_t)metadata_size), GRPC_ERROR_INT_LIMIT, (intptr_t)metadata_peer_limit), GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_RESOURCE_EXHAUSTED)); } else { - if (contains_non_ok_status(op->send_initial_metadata)) { + if (contains_non_ok_status(s->send_initial_metadata)) { s->seen_error = true; } if (!s->write_closed) { @@ -1067,69 +1333,82 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op, grpc_chttp2_list_add_waiting_for_concurrency(t, s); maybe_start_some_streams(exec_ctx, t); } else { - grpc_chttp2_cancel_stream(exec_ctx, t, s, - GRPC_ERROR_CREATE("Transport closed")); + grpc_chttp2_cancel_stream( + exec_ctx, t, s, + grpc_error_set_int( + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Transport closed"), + GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE)); } } else { GPR_ASSERT(s->id != 0); - grpc_chttp2_become_writable(exec_ctx, t, s, true, + grpc_chttp2_stream_write_type write_type = + GRPC_CHTTP2_STREAM_WRITE_INITIATE_COVERED; + if (op->send_message && + (op->payload->send_message.send_message->flags & + GRPC_WRITE_BUFFER_HINT)) { + write_type = GRPC_CHTTP2_STREAM_WRITE_PIGGYBACK; + } + grpc_chttp2_become_writable(exec_ctx, t, s, write_type, "op.send_initial_metadata"); } } else { s->send_initial_metadata = NULL; grpc_chttp2_complete_closure_step( exec_ctx, t, s, &s->send_initial_metadata_finished, - GRPC_ERROR_CREATE( - "Attempt to send initial metadata after stream was closed"), + GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( + "Attempt to send initial metadata after stream was closed", + &s->write_closed_error, 1), "send_initial_metadata_finished"); } } } - if (op->send_message != NULL) { + if (op->send_message) { on_complete->next_data.scratch |= CLOSURE_BARRIER_MAY_COVER_WRITE; s->fetching_send_message_finished = add_closure_barrier(op->on_complete); if (s->write_closed) { grpc_chttp2_complete_closure_step( exec_ctx, t, s, &s->fetching_send_message_finished, - GRPC_ERROR_CREATE("Attempt to send message after stream was closed"), + GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( + "Attempt to send message after stream was closed", + &s->write_closed_error, 1), "fetching_send_message_finished"); } else { GPR_ASSERT(s->fetching_send_message == NULL); - uint8_t *frame_hdr = - grpc_slice_buffer_tiny_add(&s->flow_controlled_buffer, 5); - uint32_t flags = op->send_message->flags; + uint8_t *frame_hdr = grpc_slice_buffer_tiny_add( + &s->flow_controlled_buffer, GRPC_HEADER_SIZE_IN_BYTES); + uint32_t flags = op_payload->send_message.send_message->flags; frame_hdr[0] = (flags & GRPC_WRITE_INTERNAL_COMPRESS) != 0; - size_t len = op->send_message->length; + size_t len = op_payload->send_message.send_message->length; frame_hdr[1] = (uint8_t)(len >> 24); frame_hdr[2] = (uint8_t)(len >> 16); frame_hdr[3] = (uint8_t)(len >> 8); frame_hdr[4] = (uint8_t)(len); - s->fetching_send_message = op->send_message; + s->fetching_send_message = op_payload->send_message.send_message; s->fetched_send_message_length = 0; s->next_message_end_offset = s->flow_controlled_bytes_written + (int64_t)s->flow_controlled_buffer.length + (int64_t)len; - s->complete_fetch_covered_by_poller = op->covered_by_poller; if (flags & GRPC_WRITE_BUFFER_HINT) { - /* allow up to 64kb to be buffered */ - /* TODO(ctiller): make this configurable */ - s->next_message_end_offset -= 65536; + s->next_message_end_offset -= t->write_buffer_size; + s->write_buffering = true; + } else { + s->write_buffering = false; } continue_fetching_send_locked(exec_ctx, t, s); - if (s->id != 0) { - grpc_chttp2_become_writable(exec_ctx, t, s, true, "op.send_message"); - } + maybe_become_writable_due_to_send_msg(exec_ctx, t, s); } } - if (op->send_trailing_metadata != NULL) { + if (op->send_trailing_metadata) { GPR_ASSERT(s->send_trailing_metadata_finished == NULL); on_complete->next_data.scratch |= CLOSURE_BARRIER_MAY_COVER_WRITE; s->send_trailing_metadata_finished = add_closure_barrier(on_complete); - s->send_trailing_metadata = op->send_trailing_metadata; + s->send_trailing_metadata = + op_payload->send_trailing_metadata.send_trailing_metadata; + s->write_buffering = false; const size_t metadata_size = - grpc_metadata_batch_size(op->send_trailing_metadata); + grpc_metadata_batch_size(s->send_trailing_metadata); const size_t metadata_peer_limit = t->settings[GRPC_PEER_SETTINGS] [GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE]; @@ -1138,57 +1417,75 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op, exec_ctx, t, s, grpc_error_set_int( grpc_error_set_int( - grpc_error_set_int( - GRPC_ERROR_CREATE("to-be-sent trailing metadata size " - "exceeds peer limit"), - GRPC_ERROR_INT_SIZE, (intptr_t)metadata_size), + grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "to-be-sent trailing metadata size " + "exceeds peer limit"), + GRPC_ERROR_INT_SIZE, + (intptr_t)metadata_size), GRPC_ERROR_INT_LIMIT, (intptr_t)metadata_peer_limit), GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_RESOURCE_EXHAUSTED)); } else { - if (contains_non_ok_status(op->send_trailing_metadata)) { + if (contains_non_ok_status(s->send_trailing_metadata)) { s->seen_error = true; } if (s->write_closed) { s->send_trailing_metadata = NULL; grpc_chttp2_complete_closure_step( exec_ctx, t, s, &s->send_trailing_metadata_finished, - grpc_metadata_batch_is_empty(op->send_trailing_metadata) + grpc_metadata_batch_is_empty( + op->payload->send_trailing_metadata.send_trailing_metadata) ? GRPC_ERROR_NONE - : GRPC_ERROR_CREATE("Attempt to send trailing metadata after " - "stream was closed"), + : GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "Attempt to send trailing metadata after " + "stream was closed"), "send_trailing_metadata_finished"); } else if (s->id != 0) { /* TODO(ctiller): check if there's flow control for any outstanding bytes before going writable */ - grpc_chttp2_become_writable(exec_ctx, t, s, true, + grpc_chttp2_become_writable(exec_ctx, t, s, + GRPC_CHTTP2_STREAM_WRITE_INITIATE_COVERED, "op.send_trailing_metadata"); } } } - if (op->recv_initial_metadata != NULL) { + if (op->recv_initial_metadata) { GPR_ASSERT(s->recv_initial_metadata_ready == NULL); - s->recv_initial_metadata_ready = op->recv_initial_metadata_ready; - s->recv_initial_metadata = op->recv_initial_metadata; + s->recv_initial_metadata_ready = + op_payload->recv_initial_metadata.recv_initial_metadata_ready; + s->recv_initial_metadata = + op_payload->recv_initial_metadata.recv_initial_metadata; + s->trailing_metadata_available = + op_payload->recv_initial_metadata.trailing_metadata_available; grpc_chttp2_maybe_complete_recv_initial_metadata(exec_ctx, t, s); } - if (op->recv_message != NULL) { + if (op->recv_message) { + size_t already_received; GPR_ASSERT(s->recv_message_ready == NULL); - s->recv_message_ready = op->recv_message_ready; - s->recv_message = op->recv_message; - if (s->id != 0 && - (s->incoming_frames.head == NULL || s->incoming_frames.head->is_tail)) { - incoming_byte_stream_update_flow_control(exec_ctx, t, s, - t->stream_lookahead, 0); + GPR_ASSERT(!s->pending_byte_stream); + s->recv_message_ready = op_payload->recv_message.recv_message_ready; + s->recv_message = op_payload->recv_message.recv_message; + if (s->id != 0) { + if (!s->read_closed) { + already_received = s->frame_storage.length; + grpc_chttp2_flowctl_incoming_bs_update( + &t->flow_control, &s->flow_control, GRPC_HEADER_SIZE_IN_BYTES, + already_received); + grpc_chttp2_act_on_flowctl_action( + exec_ctx, + grpc_chttp2_flowctl_get_action(&t->flow_control, &s->flow_control), + t, s); + } } grpc_chttp2_maybe_complete_recv_message(exec_ctx, t, s); } - if (op->recv_trailing_metadata != NULL) { + if (op->recv_trailing_metadata) { GPR_ASSERT(s->recv_trailing_metadata_finished == NULL); s->recv_trailing_metadata_finished = add_closure_barrier(on_complete); - s->recv_trailing_metadata = op->recv_trailing_metadata; + s->recv_trailing_metadata = + op_payload->recv_trailing_metadata.recv_trailing_metadata; s->final_metadata_requested = true; grpc_chttp2_maybe_complete_recv_trailing_metadata(exec_ctx, t, s); } @@ -1201,91 +1498,129 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op, } static void perform_stream_op(grpc_exec_ctx *exec_ctx, grpc_transport *gt, - grpc_stream *gs, grpc_transport_stream_op *op) { + grpc_stream *gs, + grpc_transport_stream_op_batch *op) { GPR_TIMER_BEGIN("perform_stream_op", 0); grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt; grpc_chttp2_stream *s = (grpc_chttp2_stream *)gs; - if (grpc_http_trace) { - char *str = grpc_transport_stream_op_string(op); - gpr_log(GPR_DEBUG, "perform_stream_op[s=%p/%d]: %s", s, s->id, str); + if (!t->is_client) { + if (op->send_initial_metadata) { + gpr_timespec deadline = + op->payload->send_initial_metadata.send_initial_metadata->deadline; + GPR_ASSERT(0 == + gpr_time_cmp(gpr_inf_future(deadline.clock_type), deadline)); + } + if (op->send_trailing_metadata) { + gpr_timespec deadline = + op->payload->send_trailing_metadata.send_trailing_metadata->deadline; + GPR_ASSERT(0 == + gpr_time_cmp(gpr_inf_future(deadline.clock_type), deadline)); + } + } + + if (GRPC_TRACER_ON(grpc_http_trace)) { + char *str = grpc_transport_stream_op_batch_string(op); + gpr_log(GPR_DEBUG, "perform_stream_op[s=%p]: %s", s, str); gpr_free(str); } - grpc_closure_init(&op->transport_private.closure, perform_stream_op_locked, - op); - op->transport_private.args[0] = gt; - op->transport_private.args[1] = gs; + op->handler_private.extra_arg = gs; GRPC_CHTTP2_STREAM_REF(s, "perform_stream_op"); - grpc_combiner_execute(exec_ctx, t->combiner, &op->transport_private.closure, - GRPC_ERROR_NONE, op->covered_by_poller); + GRPC_CLOSURE_SCHED( + exec_ctx, + GRPC_CLOSURE_INIT(&op->handler_private.closure, perform_stream_op_locked, + op, grpc_combiner_scheduler(t->combiner)), + GRPC_ERROR_NONE); GPR_TIMER_END("perform_stream_op", 0); } +static void cancel_pings(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, + grpc_error *error) { + /* callback remaining pings: they're not allowed to call into the transpot, + and maybe they hold resources that need to be freed */ + for (size_t i = 0; i < GRPC_CHTTP2_PING_TYPE_COUNT; i++) { + grpc_chttp2_ping_queue *pq = &t->ping_queues[i]; + for (size_t j = 0; j < GRPC_CHTTP2_PCL_COUNT; j++) { + grpc_closure_list_fail_all(&pq->lists[j], GRPC_ERROR_REF(error)); + GRPC_CLOSURE_LIST_SCHED(exec_ctx, &pq->lists[j]); + } + } + GRPC_ERROR_UNREF(error); +} + static void send_ping_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, - grpc_closure *on_recv) { - grpc_chttp2_outstanding_ping *p = gpr_malloc(sizeof(*p)); - p->next = &t->pings; - p->prev = p->next->prev; - p->prev->next = p->next->prev = p; - p->id[0] = (uint8_t)((t->ping_counter >> 56) & 0xff); - p->id[1] = (uint8_t)((t->ping_counter >> 48) & 0xff); - p->id[2] = (uint8_t)((t->ping_counter >> 40) & 0xff); - p->id[3] = (uint8_t)((t->ping_counter >> 32) & 0xff); - p->id[4] = (uint8_t)((t->ping_counter >> 24) & 0xff); - p->id[5] = (uint8_t)((t->ping_counter >> 16) & 0xff); - p->id[6] = (uint8_t)((t->ping_counter >> 8) & 0xff); - p->id[7] = (uint8_t)(t->ping_counter & 0xff); - t->ping_counter++; - p->on_recv = on_recv; - grpc_slice_buffer_add(&t->qbuf, grpc_chttp2_ping_create(0, p->id)); - grpc_chttp2_initiate_write(exec_ctx, t, true, "send_ping"); + grpc_chttp2_ping_type ping_type, + grpc_closure *on_initiate, grpc_closure *on_ack) { + grpc_chttp2_ping_queue *pq = &t->ping_queues[ping_type]; + grpc_closure_list_append(&pq->lists[GRPC_CHTTP2_PCL_INITIATE], on_initiate, + GRPC_ERROR_NONE); + if (grpc_closure_list_append(&pq->lists[GRPC_CHTTP2_PCL_NEXT], on_ack, + GRPC_ERROR_NONE)) { + grpc_chttp2_initiate_write(exec_ctx, t, "send_ping"); + } +} + +static void retry_initiate_ping_locked(grpc_exec_ctx *exec_ctx, void *tp, + grpc_error *error) { + grpc_chttp2_transport *t = tp; + t->ping_state.is_delayed_ping_timer_set = false; + grpc_chttp2_initiate_write(exec_ctx, t, "retry_send_ping"); } void grpc_chttp2_ack_ping(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, - const uint8_t *opaque_8bytes) { - grpc_chttp2_outstanding_ping *ping; - for (ping = t->pings.next; ping != &t->pings; ping = ping->next) { - if (0 == memcmp(opaque_8bytes, ping->id, 8)) { - grpc_exec_ctx_sched(exec_ctx, ping->on_recv, GRPC_ERROR_NONE, NULL); - ping->next->prev = ping->prev; - ping->prev->next = ping->next; - gpr_free(ping); - return; - } + uint64_t id) { + grpc_chttp2_ping_queue *pq = + &t->ping_queues[id % GRPC_CHTTP2_PING_TYPE_COUNT]; + if (pq->inflight_id != id) { + char *from = grpc_endpoint_get_peer(t->ep); + gpr_log(GPR_DEBUG, "Unknown ping response from %s: %" PRIx64, from, id); + gpr_free(from); + return; + } + GRPC_CLOSURE_LIST_SCHED(exec_ctx, &pq->lists[GRPC_CHTTP2_PCL_INFLIGHT]); + if (!grpc_closure_list_empty(pq->lists[GRPC_CHTTP2_PCL_NEXT])) { + grpc_chttp2_initiate_write(exec_ctx, t, "continue_pings"); } - char *msg = gpr_dump((const char *)opaque_8bytes, 8, GPR_DUMP_HEX); - char *from = grpc_endpoint_get_peer(t->ep); - gpr_log(GPR_DEBUG, "Unknown ping response from %s: %s", from, msg); - gpr_free(from); - gpr_free(msg); } static void send_goaway(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, - grpc_chttp2_error_code error, grpc_slice data) { + grpc_error *error) { t->sent_goaway_state = GRPC_CHTTP2_GOAWAY_SEND_SCHEDULED; - grpc_chttp2_goaway_append(t->last_new_stream_id, (uint32_t)error, data, - &t->qbuf); - grpc_chttp2_initiate_write(exec_ctx, t, false, "goaway_sent"); + grpc_http2_error_code http_error; + grpc_slice slice; + grpc_error_get_status(error, gpr_inf_future(GPR_CLOCK_MONOTONIC), NULL, + &slice, &http_error); + grpc_chttp2_goaway_append(t->last_new_stream_id, (uint32_t)http_error, + grpc_slice_ref_internal(slice), &t->qbuf); + grpc_chttp2_initiate_write(exec_ctx, t, "goaway_sent"); + GRPC_ERROR_UNREF(error); +} + +void grpc_chttp2_add_ping_strike(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t) { + gpr_log(GPR_DEBUG, "PING strike"); + if (++t->ping_recv_state.ping_strikes > t->ping_policy.max_ping_strikes && + t->ping_policy.max_ping_strikes != 0) { + send_goaway(exec_ctx, t, + grpc_error_set_int( + GRPC_ERROR_CREATE_FROM_STATIC_STRING("too_many_pings"), + GRPC_ERROR_INT_HTTP2_ERROR, GRPC_HTTP2_ENHANCE_YOUR_CALM)); + /*The transport will be closed after the write is done */ + close_transport_locked( + exec_ctx, t, GRPC_ERROR_CREATE_FROM_STATIC_STRING("Too many pings")); + } } static void perform_transport_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op, grpc_error *error_ignored) { grpc_transport_op *op = stream_op; - grpc_chttp2_transport *t = op->transport_private.args[0]; + grpc_chttp2_transport *t = op->handler_private.extra_arg; grpc_error *close_transport = op->disconnect_with_error; - if (op->on_connectivity_state_change != NULL) { - grpc_connectivity_state_notify_on_state_change( - exec_ctx, &t->channel_callback.state_tracker, op->connectivity_state, - op->on_connectivity_state_change); - } - - if (op->send_goaway) { - send_goaway(exec_ctx, t, - grpc_chttp2_grpc_status_to_http2_error(op->goaway_status), - grpc_slice_ref(*op->goaway_message)); + if (op->goaway_error) { + send_goaway(exec_ctx, t, op->goaway_error); } if (op->set_accept_stream) { @@ -1303,14 +1638,21 @@ static void perform_transport_op_locked(grpc_exec_ctx *exec_ctx, } if (op->send_ping) { - send_ping_locked(exec_ctx, t, op->send_ping); + send_ping_locked(exec_ctx, t, GRPC_CHTTP2_PING_ON_NEXT_WRITE, NULL, + op->send_ping); + } + + if (op->on_connectivity_state_change != NULL) { + grpc_connectivity_state_notify_on_state_change( + exec_ctx, &t->channel_callback.state_tracker, op->connectivity_state, + op->on_connectivity_state_change); } if (close_transport != GRPC_ERROR_NONE) { close_transport_locked(exec_ctx, t, close_transport); } - grpc_closure_run(exec_ctx, op->on_consumed, GRPC_ERROR_NONE); + GRPC_CLOSURE_RUN(exec_ctx, op->on_consumed, GRPC_ERROR_NONE); GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "transport_op"); } @@ -1320,12 +1662,13 @@ static void perform_transport_op(grpc_exec_ctx *exec_ctx, grpc_transport *gt, grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt; char *msg = grpc_transport_op_string(op); gpr_free(msg); - op->transport_private.args[0] = gt; - grpc_closure_init(&op->transport_private.closure, perform_transport_op_locked, - op); + op->handler_private.extra_arg = gt; GRPC_CHTTP2_REF_TRANSPORT(t, "transport_op"); - grpc_combiner_execute(exec_ctx, t->combiner, &op->transport_private.closure, - GRPC_ERROR_NONE, false); + GRPC_CLOSURE_SCHED(exec_ctx, + GRPC_CLOSURE_INIT(&op->handler_private.closure, + perform_transport_op_locked, op, + grpc_combiner_scheduler(t->combiner)), + GRPC_ERROR_NONE); } /******************************************************************************* @@ -1335,17 +1678,17 @@ static void perform_transport_op(grpc_exec_ctx *exec_ctx, grpc_transport *gt, void grpc_chttp2_maybe_complete_recv_initial_metadata(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, grpc_chttp2_stream *s) { - grpc_byte_stream *bs; if (s->recv_initial_metadata_ready != NULL && s->published_metadata[0] != GRPC_METADATA_NOT_PUBLISHED) { if (s->seen_error) { - while ((bs = grpc_chttp2_incoming_frame_queue_pop(&s->incoming_frames)) != - NULL) { - incoming_byte_stream_destroy_locked(exec_ctx, bs, GRPC_ERROR_NONE); + grpc_slice_buffer_reset_and_unref_internal(exec_ctx, &s->frame_storage); + if (!s->pending_byte_stream) { + grpc_slice_buffer_reset_and_unref_internal( + exec_ctx, &s->unprocessed_incoming_frames_buffer); } } - grpc_chttp2_incoming_metadata_buffer_publish(&s->metadata_buffer[0], - s->recv_initial_metadata); + grpc_chttp2_incoming_metadata_buffer_publish( + exec_ctx, &s->metadata_buffer[0], s->recv_initial_metadata); null_then_run_closure(exec_ctx, &s->recv_initial_metadata_ready, GRPC_ERROR_NONE); } @@ -1354,42 +1697,129 @@ void grpc_chttp2_maybe_complete_recv_initial_metadata(grpc_exec_ctx *exec_ctx, void grpc_chttp2_maybe_complete_recv_message(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, grpc_chttp2_stream *s) { - grpc_byte_stream *bs; + grpc_error *error = GRPC_ERROR_NONE; if (s->recv_message_ready != NULL) { - while (s->final_metadata_requested && s->seen_error && - (bs = grpc_chttp2_incoming_frame_queue_pop(&s->incoming_frames)) != - NULL) { - incoming_byte_stream_destroy_locked(exec_ctx, bs, GRPC_ERROR_NONE); + *s->recv_message = NULL; + if (s->final_metadata_requested && s->seen_error) { + grpc_slice_buffer_reset_and_unref_internal(exec_ctx, &s->frame_storage); + if (!s->pending_byte_stream) { + grpc_slice_buffer_reset_and_unref_internal( + exec_ctx, &s->unprocessed_incoming_frames_buffer); + } } - if (s->incoming_frames.head != NULL) { - *s->recv_message = - grpc_chttp2_incoming_frame_queue_pop(&s->incoming_frames); - GPR_ASSERT(*s->recv_message != NULL); + if (!s->pending_byte_stream) { + while (s->unprocessed_incoming_frames_buffer.length > 0 || + s->frame_storage.length > 0) { + if (s->unprocessed_incoming_frames_buffer.length == 0) { + grpc_slice_buffer_swap(&s->unprocessed_incoming_frames_buffer, + &s->frame_storage); + s->unprocessed_incoming_frames_decompressed = false; + } + if (s->stream_compression_recv_enabled && + !s->unprocessed_incoming_frames_decompressed) { + GPR_ASSERT(s->decompressed_data_buffer->length == 0); + bool end_of_context; + if (!s->stream_decompression_ctx) { + s->stream_decompression_ctx = + grpc_stream_compression_context_create( + GRPC_STREAM_COMPRESSION_DECOMPRESS); + } + if (!grpc_stream_decompress(s->stream_decompression_ctx, + &s->unprocessed_incoming_frames_buffer, + s->decompressed_data_buffer, NULL, + GRPC_HEADER_SIZE_IN_BYTES, + &end_of_context)) { + grpc_slice_buffer_reset_and_unref_internal(exec_ctx, + &s->frame_storage); + grpc_slice_buffer_reset_and_unref_internal( + exec_ctx, &s->unprocessed_incoming_frames_buffer); + error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "Stream decompression error."); + } else { + error = grpc_deframe_unprocessed_incoming_frames( + exec_ctx, &s->data_parser, s, s->decompressed_data_buffer, NULL, + s->recv_message); + if (end_of_context) { + grpc_stream_compression_context_destroy( + s->stream_decompression_ctx); + s->stream_decompression_ctx = NULL; + } + } + } else { + error = grpc_deframe_unprocessed_incoming_frames( + exec_ctx, &s->data_parser, s, + &s->unprocessed_incoming_frames_buffer, NULL, s->recv_message); + } + if (error != GRPC_ERROR_NONE) { + s->seen_error = true; + grpc_slice_buffer_reset_and_unref_internal(exec_ctx, + &s->frame_storage); + grpc_slice_buffer_reset_and_unref_internal( + exec_ctx, &s->unprocessed_incoming_frames_buffer); + break; + } else if (*s->recv_message != NULL) { + break; + } + } + } + if (error == GRPC_ERROR_NONE && *s->recv_message != NULL) { null_then_run_closure(exec_ctx, &s->recv_message_ready, GRPC_ERROR_NONE); } else if (s->published_metadata[1] != GRPC_METADATA_NOT_PUBLISHED) { *s->recv_message = NULL; null_then_run_closure(exec_ctx, &s->recv_message_ready, GRPC_ERROR_NONE); } + GRPC_ERROR_UNREF(error); } } void grpc_chttp2_maybe_complete_recv_trailing_metadata(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, grpc_chttp2_stream *s) { - grpc_byte_stream *bs; grpc_chttp2_maybe_complete_recv_message(exec_ctx, t, s); if (s->recv_trailing_metadata_finished != NULL && s->read_closed && s->write_closed) { if (s->seen_error) { - while ((bs = grpc_chttp2_incoming_frame_queue_pop(&s->incoming_frames)) != - NULL) { - incoming_byte_stream_destroy_locked(exec_ctx, bs, GRPC_ERROR_NONE); + grpc_slice_buffer_reset_and_unref_internal(exec_ctx, &s->frame_storage); + if (!s->pending_byte_stream) { + grpc_slice_buffer_reset_and_unref_internal( + exec_ctx, &s->unprocessed_incoming_frames_buffer); } } - if (s->all_incoming_byte_streams_finished && + bool pending_data = s->pending_byte_stream || + s->unprocessed_incoming_frames_buffer.length > 0; + if (s->stream_compression_recv_enabled && s->read_closed && + s->frame_storage.length > 0 && !pending_data && !s->seen_error && s->recv_trailing_metadata_finished != NULL) { - grpc_chttp2_incoming_metadata_buffer_publish(&s->metadata_buffer[1], - s->recv_trailing_metadata); + /* Maybe some SYNC_FLUSH data is left in frame_storage. Consume them and + * maybe decompress the next 5 bytes in the stream. */ + bool end_of_context; + if (!s->stream_decompression_ctx) { + s->stream_decompression_ctx = grpc_stream_compression_context_create( + GRPC_STREAM_COMPRESSION_DECOMPRESS); + } + if (!grpc_stream_decompress(s->stream_decompression_ctx, + &s->frame_storage, + &s->unprocessed_incoming_frames_buffer, NULL, + GRPC_HEADER_SIZE_IN_BYTES, &end_of_context)) { + grpc_slice_buffer_reset_and_unref_internal(exec_ctx, &s->frame_storage); + grpc_slice_buffer_reset_and_unref_internal( + exec_ctx, &s->unprocessed_incoming_frames_buffer); + s->seen_error = true; + } else { + if (s->unprocessed_incoming_frames_buffer.length > 0) { + s->unprocessed_incoming_frames_decompressed = true; + } + if (end_of_context) { + grpc_stream_compression_context_destroy(s->stream_decompression_ctx); + s->stream_decompression_ctx = NULL; + } + } + } + if (s->read_closed && s->frame_storage.length == 0 && + (!pending_data || s->seen_error) && + s->recv_trailing_metadata_finished != NULL) { + grpc_chttp2_incoming_metadata_buffer_publish( + exec_ctx, &s->metadata_buffer[1], s->recv_trailing_metadata); grpc_chttp2_complete_closure_step( exec_ctx, t, s, &s->recv_trailing_metadata_finished, GRPC_ERROR_NONE, "recv_trailing_metadata_finished"); @@ -1397,14 +1827,6 @@ void grpc_chttp2_maybe_complete_recv_trailing_metadata(grpc_exec_ctx *exec_ctx, } } -static void decrement_active_streams_locked(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport *t, - grpc_chttp2_stream *s) { - if ((s->all_incoming_byte_streams_finished = gpr_unref(&s->active_streams))) { - grpc_chttp2_maybe_complete_recv_trailing_metadata(exec_ctx, t, s); - } -} - static void remove_stream(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, uint32_t id, grpc_error *error) { grpc_chttp2_stream *s = grpc_chttp2_stream_map_delete(&t->stream_map, id); @@ -1413,10 +1835,19 @@ static void remove_stream(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, t->incoming_stream = NULL; grpc_chttp2_parsing_become_skip_parser(exec_ctx, t); } - if (s->data_parser.parsing_frame != NULL) { - grpc_chttp2_incoming_byte_stream_finished( - exec_ctx, s->data_parser.parsing_frame, GRPC_ERROR_REF(error)); - s->data_parser.parsing_frame = NULL; + if (s->pending_byte_stream) { + if (s->on_next != NULL) { + grpc_chttp2_incoming_byte_stream *bs = s->data_parser.parsing_frame; + if (error == GRPC_ERROR_NONE) { + error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Truncated message"); + } + incoming_byte_stream_publish_error(exec_ctx, bs, error); + incoming_byte_stream_unref(exec_ctx, bs); + s->data_parser.parsing_frame = NULL; + } else { + GRPC_ERROR_UNREF(s->byte_stream_error); + s->byte_stream_error = GRPC_ERROR_REF(error); + } } if (grpc_chttp2_stream_map_size(&t->stream_map) == 0) { @@ -1424,7 +1855,7 @@ static void remove_stream(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, if (t->sent_goaway_state == GRPC_CHTTP2_GOAWAY_SENT) { close_transport_locked( exec_ctx, t, - GRPC_ERROR_CREATE_REFERENCING( + GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( "Last stream closed after sending GOAWAY", &error, 1)); } } @@ -1437,70 +1868,37 @@ static void remove_stream(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, maybe_start_some_streams(exec_ctx, t); } -static void status_codes_from_error(grpc_error *error, gpr_timespec deadline, - grpc_chttp2_error_code *http2_error, - grpc_status_code *grpc_status) { - intptr_t ip_http; - intptr_t ip_grpc; - bool have_http = - grpc_error_get_int(error, GRPC_ERROR_INT_HTTP2_ERROR, &ip_http); - bool have_grpc = - grpc_error_get_int(error, GRPC_ERROR_INT_GRPC_STATUS, &ip_grpc); - if (have_http) { - *http2_error = (grpc_chttp2_error_code)ip_http; - } else if (have_grpc) { - *http2_error = - grpc_chttp2_grpc_status_to_http2_error((grpc_status_code)ip_grpc); - } else { - *http2_error = GRPC_CHTTP2_INTERNAL_ERROR; - } - if (have_grpc) { - *grpc_status = (grpc_status_code)ip_grpc; - } else if (have_http) { - *grpc_status = grpc_chttp2_http2_error_to_grpc_status( - (grpc_chttp2_error_code)ip_http, deadline); - } else { - *grpc_status = GRPC_STATUS_INTERNAL; - } -} - void grpc_chttp2_cancel_stream(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, grpc_chttp2_stream *s, grpc_error *due_to_error) { - if (!s->read_closed || !s->write_closed) { - grpc_status_code grpc_status; - grpc_chttp2_error_code http_error; - status_codes_from_error(due_to_error, s->deadline, &http_error, - &grpc_status); + if (!t->is_client && !s->sent_trailing_metadata && + grpc_error_has_clear_grpc_status(due_to_error)) { + close_from_api(exec_ctx, t, s, due_to_error); + return; + } + if (!s->read_closed || !s->write_closed) { if (s->id != 0) { + grpc_http2_error_code http_error; + grpc_error_get_status(due_to_error, s->deadline, NULL, NULL, &http_error); grpc_slice_buffer_add( &t->qbuf, grpc_chttp2_rst_stream_create(s->id, (uint32_t)http_error, &s->stats.outgoing)); - grpc_chttp2_initiate_write(exec_ctx, t, false, "rst_stream"); - } - - const char *msg = - grpc_error_get_str(due_to_error, GRPC_ERROR_STR_GRPC_MESSAGE); - bool free_msg = false; - if (msg == NULL) { - free_msg = true; - msg = grpc_error_string(due_to_error); + grpc_chttp2_initiate_write(exec_ctx, t, "rst_stream"); } - grpc_slice msg_slice = grpc_slice_from_copied_string(msg); - grpc_chttp2_fake_status(exec_ctx, t, s, grpc_status, &msg_slice); - if (free_msg) grpc_error_free_string(msg); } if (due_to_error != GRPC_ERROR_NONE && !s->seen_error) { s->seen_error = true; - grpc_chttp2_maybe_complete_recv_trailing_metadata(exec_ctx, t, s); } grpc_chttp2_mark_stream_closed(exec_ctx, t, s, 1, 1, due_to_error); } void grpc_chttp2_fake_status(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, - grpc_chttp2_stream *s, grpc_status_code status, - grpc_slice *slice) { + grpc_chttp2_stream *s, grpc_error *error) { + grpc_status_code status; + grpc_slice slice; + grpc_error_get_status(error, s->deadline, &status, &slice, NULL); + if (status != GRPC_STATUS_OK) { s->seen_error = true; } @@ -1514,23 +1912,25 @@ void grpc_chttp2_fake_status(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, s->recv_trailing_metadata_finished != NULL) { char status_string[GPR_LTOA_MIN_BUFSIZE]; gpr_ltoa(status, status_string); - grpc_chttp2_incoming_metadata_buffer_add( - &s->metadata_buffer[1], - grpc_mdelem_from_metadata_strings( - GRPC_MDSTR_GRPC_STATUS, grpc_mdstr_from_string(status_string))); - if (slice) { - grpc_chttp2_incoming_metadata_buffer_add( - &s->metadata_buffer[1], - grpc_mdelem_from_metadata_strings( - GRPC_MDSTR_GRPC_MESSAGE, - grpc_mdstr_from_slice(grpc_slice_ref(*slice)))); + GRPC_LOG_IF_ERROR("add_status", + grpc_chttp2_incoming_metadata_buffer_replace_or_add( + exec_ctx, &s->metadata_buffer[1], + grpc_mdelem_from_slices( + exec_ctx, GRPC_MDSTR_GRPC_STATUS, + grpc_slice_from_copied_string(status_string)))); + if (!GRPC_SLICE_IS_EMPTY(slice)) { + GRPC_LOG_IF_ERROR( + "add_status_message", + grpc_chttp2_incoming_metadata_buffer_replace_or_add( + exec_ctx, &s->metadata_buffer[1], + grpc_mdelem_from_slices(exec_ctx, GRPC_MDSTR_GRPC_MESSAGE, + grpc_slice_ref_internal(slice)))); } s->published_metadata[1] = GRPC_METADATA_SYNTHESIZED_FROM_FAKE; grpc_chttp2_maybe_complete_recv_trailing_metadata(exec_ctx, t, s); } - if (slice) { - grpc_slice_unref(*slice); - } + + GRPC_ERROR_UNREF(error); } static void add_error(grpc_error *error, grpc_error **refs, size_t *nrefs) { @@ -1553,7 +1953,8 @@ static grpc_error *removal_error(grpc_error *extra_error, grpc_chttp2_stream *s, add_error(extra_error, refs, &nrefs); grpc_error *error = GRPC_ERROR_NONE; if (nrefs > 0) { - error = GRPC_ERROR_CREATE_REFERENCING(master_error_msg, refs, nrefs); + error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(master_error_msg, + refs, nrefs); } GRPC_ERROR_UNREF(extra_error); return error; @@ -1596,36 +1997,47 @@ void grpc_chttp2_mark_stream_closed(grpc_exec_ctx *exec_ctx, int close_writes, grpc_error *error) { if (s->read_closed && s->write_closed) { /* already closed */ + grpc_chttp2_maybe_complete_recv_trailing_metadata(exec_ctx, t, s); GRPC_ERROR_UNREF(error); return; } + bool closed_read = false; + bool became_closed = false; if (close_reads && !s->read_closed) { s->read_closed_error = GRPC_ERROR_REF(error); s->read_closed = true; - for (int i = 0; i < 2; i++) { - if (s->published_metadata[i] == GRPC_METADATA_NOT_PUBLISHED) { - s->published_metadata[i] = GPRC_METADATA_PUBLISHED_AT_CLOSE; - } - } - decrement_active_streams_locked(exec_ctx, t, s); - grpc_chttp2_maybe_complete_recv_initial_metadata(exec_ctx, t, s); - grpc_chttp2_maybe_complete_recv_message(exec_ctx, t, s); - grpc_chttp2_maybe_complete_recv_trailing_metadata(exec_ctx, t, s); + closed_read = true; } if (close_writes && !s->write_closed) { s->write_closed_error = GRPC_ERROR_REF(error); s->write_closed = true; grpc_chttp2_fail_pending_writes(exec_ctx, t, s, GRPC_ERROR_REF(error)); - grpc_chttp2_maybe_complete_recv_trailing_metadata(exec_ctx, t, s); } if (s->read_closed && s->write_closed) { + became_closed = true; + grpc_error *overall_error = + removal_error(GRPC_ERROR_REF(error), s, "Stream removed"); if (s->id != 0) { - remove_stream(exec_ctx, t, s->id, - removal_error(GRPC_ERROR_REF(error), s, "Stream removed")); + remove_stream(exec_ctx, t, s->id, GRPC_ERROR_REF(overall_error)); } else { /* Purge streams waiting on concurrency still waiting for id assignment */ grpc_chttp2_list_remove_waiting_for_concurrency(t, s); } + if (overall_error != GRPC_ERROR_NONE) { + grpc_chttp2_fake_status(exec_ctx, t, s, overall_error); + } + } + if (closed_read) { + for (int i = 0; i < 2; i++) { + if (s->published_metadata[i] == GRPC_METADATA_NOT_PUBLISHED) { + s->published_metadata[i] = GPRC_METADATA_PUBLISHED_AT_CLOSE; + } + } + grpc_chttp2_maybe_complete_recv_initial_metadata(exec_ctx, t, s); + grpc_chttp2_maybe_complete_recv_message(exec_ctx, t, s); + } + if (became_closed) { + grpc_chttp2_maybe_complete_recv_trailing_metadata(exec_ctx, t, s); GRPC_CHTTP2_STREAM_UNREF(exec_ctx, s, "chttp2"); } GRPC_ERROR_UNREF(error); @@ -1635,116 +2047,157 @@ static void close_from_api(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, grpc_chttp2_stream *s, grpc_error *error) { grpc_slice hdr; grpc_slice status_hdr; + grpc_slice http_status_hdr; + grpc_slice content_type_hdr; grpc_slice message_pfx; uint8_t *p; uint32_t len = 0; grpc_status_code grpc_status; - grpc_chttp2_error_code http_error; - status_codes_from_error(error, s->deadline, &http_error, &grpc_status); + grpc_slice slice; + grpc_error_get_status(error, s->deadline, &grpc_status, &slice, NULL); GPR_ASSERT(grpc_status >= 0 && (int)grpc_status < 100); - if (s->id != 0 && !t->is_client) { - /* Hand roll a header block. - This is unnecessarily ugly - at some point we should find a more - elegant - solution. - It's complicated by the fact that our send machinery would be dead by - the - time we got around to sending this, so instead we ignore HPACK - compression - and just write the uncompressed bytes onto the wire. */ - status_hdr = grpc_slice_malloc(15 + (grpc_status >= 10)); - p = GRPC_SLICE_START_PTR(status_hdr); - *p++ = 0x40; /* literal header */ - *p++ = 11; /* len(grpc-status) */ - *p++ = 'g'; - *p++ = 'r'; - *p++ = 'p'; - *p++ = 'c'; - *p++ = '-'; + /* Hand roll a header block. + This is unnecessarily ugly - at some point we should find a more + elegant solution. + It's complicated by the fact that our send machinery would be dead by + the time we got around to sending this, so instead we ignore HPACK + compression and just write the uncompressed bytes onto the wire. */ + if (!s->sent_initial_metadata) { + http_status_hdr = GRPC_SLICE_MALLOC(13); + p = GRPC_SLICE_START_PTR(http_status_hdr); + *p++ = 0x00; + *p++ = 7; + *p++ = ':'; *p++ = 's'; *p++ = 't'; *p++ = 'a'; *p++ = 't'; *p++ = 'u'; *p++ = 's'; - if (grpc_status < 10) { - *p++ = 1; - *p++ = (uint8_t)('0' + grpc_status); - } else { - *p++ = 2; - *p++ = (uint8_t)('0' + (grpc_status / 10)); - *p++ = (uint8_t)('0' + (grpc_status % 10)); - } - GPR_ASSERT(p == GRPC_SLICE_END_PTR(status_hdr)); - len += (uint32_t)GRPC_SLICE_LENGTH(status_hdr); - - const char *optional_message = - grpc_error_get_str(error, GRPC_ERROR_STR_GRPC_MESSAGE); - - if (optional_message != NULL) { - size_t msg_len = strlen(optional_message); - GPR_ASSERT(msg_len < 127); - message_pfx = grpc_slice_malloc(15); - p = GRPC_SLICE_START_PTR(message_pfx); - *p++ = 0x40; - *p++ = 12; /* len(grpc-message) */ - *p++ = 'g'; - *p++ = 'r'; - *p++ = 'p'; - *p++ = 'c'; - *p++ = '-'; - *p++ = 'm'; - *p++ = 'e'; - *p++ = 's'; - *p++ = 's'; - *p++ = 'a'; - *p++ = 'g'; - *p++ = 'e'; - *p++ = (uint8_t)msg_len; - GPR_ASSERT(p == GRPC_SLICE_END_PTR(message_pfx)); - len += (uint32_t)GRPC_SLICE_LENGTH(message_pfx); - len += (uint32_t)msg_len; - } - - hdr = grpc_slice_malloc(9); - p = GRPC_SLICE_START_PTR(hdr); - *p++ = (uint8_t)(len >> 16); - *p++ = (uint8_t)(len >> 8); - *p++ = (uint8_t)(len); - *p++ = GRPC_CHTTP2_FRAME_HEADER; - *p++ = GRPC_CHTTP2_DATA_FLAG_END_STREAM | GRPC_CHTTP2_DATA_FLAG_END_HEADERS; - *p++ = (uint8_t)(s->id >> 24); - *p++ = (uint8_t)(s->id >> 16); - *p++ = (uint8_t)(s->id >> 8); - *p++ = (uint8_t)(s->id); - GPR_ASSERT(p == GRPC_SLICE_END_PTR(hdr)); - - grpc_slice_buffer_add(&t->qbuf, hdr); - grpc_slice_buffer_add(&t->qbuf, status_hdr); - if (optional_message) { - grpc_slice_buffer_add(&t->qbuf, message_pfx); - grpc_slice_buffer_add(&t->qbuf, - grpc_slice_from_copied_string(optional_message)); - } - grpc_slice_buffer_add( - &t->qbuf, grpc_chttp2_rst_stream_create(s->id, GRPC_CHTTP2_NO_ERROR, - &s->stats.outgoing)); - } - - const char *msg = grpc_error_get_str(error, GRPC_ERROR_STR_GRPC_MESSAGE); - bool free_msg = false; - if (msg == NULL) { - free_msg = true; - msg = grpc_error_string(error); - } - grpc_slice msg_slice = grpc_slice_from_copied_string(msg); - grpc_chttp2_fake_status(exec_ctx, t, s, grpc_status, &msg_slice); - if (free_msg) grpc_error_free_string(msg); + *p++ = 3; + *p++ = '2'; + *p++ = '0'; + *p++ = '0'; + GPR_ASSERT(p == GRPC_SLICE_END_PTR(http_status_hdr)); + len += (uint32_t)GRPC_SLICE_LENGTH(http_status_hdr); + + content_type_hdr = GRPC_SLICE_MALLOC(31); + p = GRPC_SLICE_START_PTR(content_type_hdr); + *p++ = 0x00; + *p++ = 12; + *p++ = 'c'; + *p++ = 'o'; + *p++ = 'n'; + *p++ = 't'; + *p++ = 'e'; + *p++ = 'n'; + *p++ = 't'; + *p++ = '-'; + *p++ = 't'; + *p++ = 'y'; + *p++ = 'p'; + *p++ = 'e'; + *p++ = 16; + *p++ = 'a'; + *p++ = 'p'; + *p++ = 'p'; + *p++ = 'l'; + *p++ = 'i'; + *p++ = 'c'; + *p++ = 'a'; + *p++ = 't'; + *p++ = 'i'; + *p++ = 'o'; + *p++ = 'n'; + *p++ = '/'; + *p++ = 'g'; + *p++ = 'r'; + *p++ = 'p'; + *p++ = 'c'; + GPR_ASSERT(p == GRPC_SLICE_END_PTR(content_type_hdr)); + len += (uint32_t)GRPC_SLICE_LENGTH(content_type_hdr); + } + + status_hdr = GRPC_SLICE_MALLOC(15 + (grpc_status >= 10)); + p = GRPC_SLICE_START_PTR(status_hdr); + *p++ = 0x00; /* literal header, not indexed */ + *p++ = 11; /* len(grpc-status) */ + *p++ = 'g'; + *p++ = 'r'; + *p++ = 'p'; + *p++ = 'c'; + *p++ = '-'; + *p++ = 's'; + *p++ = 't'; + *p++ = 'a'; + *p++ = 't'; + *p++ = 'u'; + *p++ = 's'; + if (grpc_status < 10) { + *p++ = 1; + *p++ = (uint8_t)('0' + grpc_status); + } else { + *p++ = 2; + *p++ = (uint8_t)('0' + (grpc_status / 10)); + *p++ = (uint8_t)('0' + (grpc_status % 10)); + } + GPR_ASSERT(p == GRPC_SLICE_END_PTR(status_hdr)); + len += (uint32_t)GRPC_SLICE_LENGTH(status_hdr); + + size_t msg_len = GRPC_SLICE_LENGTH(slice); + GPR_ASSERT(msg_len <= UINT32_MAX); + uint32_t msg_len_len = GRPC_CHTTP2_VARINT_LENGTH((uint32_t)msg_len, 1); + message_pfx = GRPC_SLICE_MALLOC(14 + msg_len_len); + p = GRPC_SLICE_START_PTR(message_pfx); + *p++ = 0x00; /* literal header, not indexed */ + *p++ = 12; /* len(grpc-message) */ + *p++ = 'g'; + *p++ = 'r'; + *p++ = 'p'; + *p++ = 'c'; + *p++ = '-'; + *p++ = 'm'; + *p++ = 'e'; + *p++ = 's'; + *p++ = 's'; + *p++ = 'a'; + *p++ = 'g'; + *p++ = 'e'; + GRPC_CHTTP2_WRITE_VARINT((uint32_t)msg_len, 1, 0, p, (uint32_t)msg_len_len); + p += msg_len_len; + GPR_ASSERT(p == GRPC_SLICE_END_PTR(message_pfx)); + len += (uint32_t)GRPC_SLICE_LENGTH(message_pfx); + len += (uint32_t)msg_len; + + hdr = GRPC_SLICE_MALLOC(9); + p = GRPC_SLICE_START_PTR(hdr); + *p++ = (uint8_t)(len >> 16); + *p++ = (uint8_t)(len >> 8); + *p++ = (uint8_t)(len); + *p++ = GRPC_CHTTP2_FRAME_HEADER; + *p++ = GRPC_CHTTP2_DATA_FLAG_END_STREAM | GRPC_CHTTP2_DATA_FLAG_END_HEADERS; + *p++ = (uint8_t)(s->id >> 24); + *p++ = (uint8_t)(s->id >> 16); + *p++ = (uint8_t)(s->id >> 8); + *p++ = (uint8_t)(s->id); + GPR_ASSERT(p == GRPC_SLICE_END_PTR(hdr)); + + grpc_slice_buffer_add(&t->qbuf, hdr); + if (!s->sent_initial_metadata) { + grpc_slice_buffer_add(&t->qbuf, http_status_hdr); + grpc_slice_buffer_add(&t->qbuf, content_type_hdr); + } + grpc_slice_buffer_add(&t->qbuf, status_hdr); + grpc_slice_buffer_add(&t->qbuf, message_pfx); + grpc_slice_buffer_add(&t->qbuf, grpc_slice_ref_internal(slice)); + grpc_slice_buffer_add( + &t->qbuf, grpc_chttp2_rst_stream_create(s->id, GRPC_HTTP2_NO_ERROR, + &s->stats.outgoing)); grpc_chttp2_mark_stream_closed(exec_ctx, t, s, 1, 1, error); - grpc_chttp2_initiate_write(exec_ctx, t, false, "close_from_api"); + grpc_chttp2_initiate_write(exec_ctx, t, "close_from_api"); } typedef struct { @@ -1767,51 +2220,60 @@ static void end_all_the_calls(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, GRPC_ERROR_UNREF(error); } -/** update window from a settings change */ -typedef struct { - grpc_chttp2_transport *t; - grpc_exec_ctx *exec_ctx; -} update_global_window_args; - -static void update_global_window(void *args, uint32_t id, void *stream) { - update_global_window_args *a = args; - grpc_chttp2_transport *t = a->t; - grpc_chttp2_stream *s = stream; - int was_zero; - int is_zero; - int64_t initial_window_update = t->initial_window_update; - - if (initial_window_update > 0) { - was_zero = s->outgoing_window <= 0; - GRPC_CHTTP2_FLOW_CREDIT_STREAM("settings", t, s, outgoing_window, - initial_window_update); - is_zero = s->outgoing_window <= 0; - - if (was_zero && !is_zero) { - grpc_chttp2_become_writable(a->exec_ctx, t, s, true, - "update_global_window"); - } - } else { - GRPC_CHTTP2_FLOW_DEBIT_STREAM("settings", t, s, outgoing_window, - -initial_window_update); - } -} - /******************************************************************************* * INPUT PROCESSING - PARSING */ -static void read_action_begin(grpc_exec_ctx *exec_ctx, void *tp, - grpc_error *error) { - /* Control flow: - reading_action_locked -> - (parse_unlocked -> post_parse_locked)? -> - post_reading_action_locked */ - GPR_TIMER_BEGIN("reading_action", 0); - grpc_chttp2_transport *t = tp; - grpc_combiner_execute(exec_ctx, t->combiner, &t->read_action_locked, - GRPC_ERROR_REF(error), false); - GPR_TIMER_END("reading_action", 0); +void grpc_chttp2_act_on_flowctl_action(grpc_exec_ctx *exec_ctx, + grpc_chttp2_flowctl_action action, + grpc_chttp2_transport *t, + grpc_chttp2_stream *s) { + switch (action.send_stream_update) { + case GRPC_CHTTP2_FLOWCTL_NO_ACTION_NEEDED: + break; + case GRPC_CHTTP2_FLOWCTL_UPDATE_IMMEDIATELY: + grpc_chttp2_become_writable(exec_ctx, t, s, + GRPC_CHTTP2_STREAM_WRITE_INITIATE_COVERED, + "immediate stream flowctl"); + break; + case GRPC_CHTTP2_FLOWCTL_QUEUE_UPDATE: + grpc_chttp2_become_writable(exec_ctx, t, s, + GRPC_CHTTP2_STREAM_WRITE_PIGGYBACK, + "queue stream flowctl"); + break; + } + switch (action.send_transport_update) { + case GRPC_CHTTP2_FLOWCTL_NO_ACTION_NEEDED: + break; + case GRPC_CHTTP2_FLOWCTL_UPDATE_IMMEDIATELY: + grpc_chttp2_initiate_write(exec_ctx, t, "immediate transport flowctl"); + break; + // this is the same as no action b/c every time the transport enters the + // writing path it will maybe do an update + case GRPC_CHTTP2_FLOWCTL_QUEUE_UPDATE: + break; + } + if (action.send_setting_update != GRPC_CHTTP2_FLOWCTL_NO_ACTION_NEEDED) { + if (action.initial_window_size > 0) { + queue_setting_update(exec_ctx, t, + GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE, + (uint32_t)action.initial_window_size); + } + if (action.max_frame_size > 0) { + queue_setting_update(exec_ctx, t, GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE, + (uint32_t)action.max_frame_size); + } + if (action.send_setting_update == GRPC_CHTTP2_FLOWCTL_UPDATE_IMMEDIATELY) { + grpc_chttp2_initiate_write(exec_ctx, t, "immediate setting update"); + } + } + if (action.need_ping) { + GRPC_CHTTP2_REF_TRANSPORT(t, "bdp_ping"); + grpc_bdp_estimator_schedule_ping(&t->flow_control.bdp_estimator); + send_ping_locked(exec_ctx, t, + GRPC_CHTTP2_PING_BEFORE_TRANSPORT_WINDOW_UPDATE, + &t->start_bdp_ping_locked, &t->finish_bdp_ping_locked); + } } static grpc_error *try_http_parsing(grpc_exec_ctx *exec_ctx, @@ -1832,8 +2294,10 @@ static grpc_error *try_http_parsing(grpc_exec_ctx *exec_ctx, if (parse_error == GRPC_ERROR_NONE && (parse_error = grpc_http_parser_eof(&parser)) == GRPC_ERROR_NONE) { error = grpc_error_set_int( - GRPC_ERROR_CREATE("Trying to connect an http1.x server"), - GRPC_ERROR_INT_HTTP_STATUS, response.status); + grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "Trying to connect an http1.x server"), + GRPC_ERROR_INT_HTTP_STATUS, response.status), + GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE); } GRPC_ERROR_UNREF(parse_error); @@ -1852,9 +2316,10 @@ static void read_action_locked(grpc_exec_ctx *exec_ctx, void *tp, grpc_error *err = error; if (err != GRPC_ERROR_NONE) { - err = grpc_error_set_int( - GRPC_ERROR_CREATE_REFERENCING("Endpoint read failed", &err, 1), - GRPC_ERROR_INT_OCCURRED_DURING_WRITE, t->write_state); + err = grpc_error_set_int(GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( + "Endpoint read failed", &err, 1), + GRPC_ERROR_INT_OCCURRED_DURING_WRITE, + t->write_state); } GPR_SWAP(grpc_error *, err, error); GRPC_ERROR_UNREF(err); @@ -1864,14 +2329,17 @@ static void read_action_locked(grpc_exec_ctx *exec_ctx, void *tp, grpc_error *errors[3] = {GRPC_ERROR_REF(error), GRPC_ERROR_NONE, GRPC_ERROR_NONE}; for (; i < t->read_buffer.count && errors[1] == GRPC_ERROR_NONE; i++) { + grpc_bdp_estimator_add_incoming_bytes( + &t->flow_control.bdp_estimator, + (int64_t)GRPC_SLICE_LENGTH(t->read_buffer.slices[i])); errors[1] = grpc_chttp2_perform_read(exec_ctx, t, t->read_buffer.slices[i]); - }; + } if (errors[1] != GRPC_ERROR_NONE) { errors[2] = try_http_parsing(exec_ctx, t); GRPC_ERROR_UNREF(error); - error = GRPC_ERROR_CREATE_REFERENCING("Failed parsing HTTP/2", errors, - GPR_ARRAY_SIZE(errors)); + error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( + "Failed parsing HTTP/2", errors, GPR_ARRAY_SIZE(errors)); } for (i = 0; i < GPR_ARRAY_SIZE(errors); i++) { GRPC_ERROR_UNREF(errors[i]); @@ -1879,29 +2347,24 @@ static void read_action_locked(grpc_exec_ctx *exec_ctx, void *tp, GPR_TIMER_END("reading_action.parse", 0); GPR_TIMER_BEGIN("post_parse_locked", 0); - if (t->initial_window_update != 0) { - update_global_window_args args = {t, exec_ctx}; - grpc_chttp2_stream_map_for_each(&t->stream_map, update_global_window, - &args); - t->initial_window_update = 0; - } - /* handle higher level things */ - if (t->incoming_window < t->connection_window_target * 3 / 4) { - int64_t announce_bytes = t->connection_window_target - t->incoming_window; - GRPC_CHTTP2_FLOW_CREDIT_TRANSPORT("parsed", t, announce_incoming_window, - announce_bytes); - GRPC_CHTTP2_FLOW_CREDIT_TRANSPORT("parsed", t, incoming_window, - announce_bytes); - grpc_chttp2_initiate_write(exec_ctx, t, false, "global incoming window"); + if (t->flow_control.initial_window_update != 0) { + if (t->flow_control.initial_window_update > 0) { + grpc_chttp2_stream *s; + while (grpc_chttp2_list_pop_stalled_by_stream(t, &s)) { + grpc_chttp2_become_writable( + exec_ctx, t, s, GRPC_CHTTP2_STREAM_WRITE_INITIATE_UNCOVERED, + "unstalled"); + } + } + t->flow_control.initial_window_update = 0; } - GPR_TIMER_END("post_parse_locked", 0); } GPR_TIMER_BEGIN("post_reading_action_locked", 0); bool keep_reading = false; if (error == GRPC_ERROR_NONE && t->closed) { - error = GRPC_ERROR_CREATE("Transport closed"); + error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Transport closed"); } if (error != GRPC_ERROR_NONE) { close_transport_locked(exec_ctx, t, GRPC_ERROR_REF(error)); @@ -1910,10 +2373,14 @@ static void read_action_locked(grpc_exec_ctx *exec_ctx, void *tp, keep_reading = true; GRPC_CHTTP2_REF_TRANSPORT(t, "keep_reading"); } - grpc_slice_buffer_reset_and_unref(&t->read_buffer); + grpc_slice_buffer_reset_and_unref_internal(exec_ctx, &t->read_buffer); if (keep_reading) { - grpc_endpoint_read(exec_ctx, t->ep, &t->read_buffer, &t->read_action_begin); + grpc_endpoint_read(exec_ctx, t->ep, &t->read_buffer, + &t->read_action_locked); + grpc_chttp2_act_on_flowctl_action( + exec_ctx, grpc_chttp2_flowctl_get_bdp_action(&t->flow_control), t, + NULL); GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "keep_reading"); } else { GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "reading_action"); @@ -1926,6 +2393,147 @@ static void read_action_locked(grpc_exec_ctx *exec_ctx, void *tp, GPR_TIMER_END("reading_action_locked", 0); } +static void start_bdp_ping_locked(grpc_exec_ctx *exec_ctx, void *tp, + grpc_error *error) { + grpc_chttp2_transport *t = tp; + if (GRPC_TRACER_ON(grpc_http_trace)) { + gpr_log(GPR_DEBUG, "%s: Start BDP ping", t->peer_string); + } + /* Reset the keepalive ping timer */ + if (t->keepalive_state == GRPC_CHTTP2_KEEPALIVE_STATE_WAITING) { + grpc_timer_cancel(exec_ctx, &t->keepalive_ping_timer); + } + grpc_bdp_estimator_start_ping(&t->flow_control.bdp_estimator); +} + +static void finish_bdp_ping_locked(grpc_exec_ctx *exec_ctx, void *tp, + grpc_error *error) { + grpc_chttp2_transport *t = tp; + if (GRPC_TRACER_ON(grpc_http_trace)) { + gpr_log(GPR_DEBUG, "%s: Complete BDP ping", t->peer_string); + } + grpc_bdp_estimator_complete_ping(&t->flow_control.bdp_estimator); + + GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "bdp_ping"); +} + +void grpc_chttp2_config_default_keepalive_args(grpc_channel_args *args, + bool is_client) { + size_t i; + if (args) { + for (i = 0; i < args->num_args; i++) { + if (0 == strcmp(args->args[i].key, GRPC_ARG_KEEPALIVE_TIME_MS)) { + const int value = grpc_channel_arg_get_integer( + &args->args[i], + (grpc_integer_options){g_default_client_keepalive_time_ms, 1, + INT_MAX}); + if (is_client) { + g_default_client_keepalive_time_ms = value; + } else { + g_default_server_keepalive_time_ms = value; + } + } else if (0 == + strcmp(args->args[i].key, GRPC_ARG_KEEPALIVE_TIMEOUT_MS)) { + const int value = grpc_channel_arg_get_integer( + &args->args[i], + (grpc_integer_options){g_default_client_keepalive_timeout_ms, 0, + INT_MAX}); + if (is_client) { + g_default_client_keepalive_timeout_ms = value; + } else { + g_default_server_keepalive_timeout_ms = value; + } + } else if (0 == strcmp(args->args[i].key, + GRPC_ARG_KEEPALIVE_PERMIT_WITHOUT_CALLS)) { + g_default_keepalive_permit_without_calls = + (uint32_t)grpc_channel_arg_get_integer( + &args->args[i], + (grpc_integer_options){g_default_keepalive_permit_without_calls, + 0, 1}); + } + } + } +} + +static void init_keepalive_ping_locked(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error) { + grpc_chttp2_transport *t = arg; + GPR_ASSERT(t->keepalive_state == GRPC_CHTTP2_KEEPALIVE_STATE_WAITING); + if (t->destroying || t->closed) { + t->keepalive_state = GRPC_CHTTP2_KEEPALIVE_STATE_DYING; + } else if (error == GRPC_ERROR_NONE) { + if (t->keepalive_permit_without_calls || + grpc_chttp2_stream_map_size(&t->stream_map) > 0) { + t->keepalive_state = GRPC_CHTTP2_KEEPALIVE_STATE_PINGING; + GRPC_CHTTP2_REF_TRANSPORT(t, "keepalive ping end"); + send_ping_locked(exec_ctx, t, GRPC_CHTTP2_PING_ON_NEXT_WRITE, + &t->start_keepalive_ping_locked, + &t->finish_keepalive_ping_locked); + } else { + GRPC_CHTTP2_REF_TRANSPORT(t, "init keepalive ping"); + grpc_timer_init( + exec_ctx, &t->keepalive_ping_timer, + gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), t->keepalive_time), + &t->init_keepalive_ping_locked, gpr_now(GPR_CLOCK_MONOTONIC)); + } + } else if (error == GRPC_ERROR_CANCELLED) { + /* The keepalive ping timer may be cancelled by bdp */ + GRPC_CHTTP2_REF_TRANSPORT(t, "init keepalive ping"); + grpc_timer_init( + exec_ctx, &t->keepalive_ping_timer, + gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), t->keepalive_time), + &t->init_keepalive_ping_locked, gpr_now(GPR_CLOCK_MONOTONIC)); + } + GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "init keepalive ping"); +} + +static void start_keepalive_ping_locked(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error) { + grpc_chttp2_transport *t = arg; + GRPC_CHTTP2_REF_TRANSPORT(t, "keepalive watchdog"); + grpc_timer_init( + exec_ctx, &t->keepalive_watchdog_timer, + gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), t->keepalive_timeout), + &t->keepalive_watchdog_fired_locked, gpr_now(GPR_CLOCK_MONOTONIC)); +} + +static void finish_keepalive_ping_locked(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error) { + grpc_chttp2_transport *t = arg; + if (t->keepalive_state == GRPC_CHTTP2_KEEPALIVE_STATE_PINGING) { + if (error == GRPC_ERROR_NONE) { + t->keepalive_state = GRPC_CHTTP2_KEEPALIVE_STATE_WAITING; + grpc_timer_cancel(exec_ctx, &t->keepalive_watchdog_timer); + GRPC_CHTTP2_REF_TRANSPORT(t, "init keepalive ping"); + grpc_timer_init( + exec_ctx, &t->keepalive_ping_timer, + gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), t->keepalive_time), + &t->init_keepalive_ping_locked, gpr_now(GPR_CLOCK_MONOTONIC)); + } + } + GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "keepalive ping end"); +} + +static void keepalive_watchdog_fired_locked(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error) { + grpc_chttp2_transport *t = arg; + if (t->keepalive_state == GRPC_CHTTP2_KEEPALIVE_STATE_PINGING) { + if (error == GRPC_ERROR_NONE) { + t->keepalive_state = GRPC_CHTTP2_KEEPALIVE_STATE_DYING; + close_transport_locked(exec_ctx, t, GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "keepalive watchdog timeout")); + } + } else { + /* The watchdog timer should have been cancelled by + * finish_keepalive_ping_locked. */ + if (error != GRPC_ERROR_CANCELLED) { + gpr_log(GPR_ERROR, "keepalive_ping_end state error: %d (expect: %d)", + t->keepalive_state, GRPC_CHTTP2_KEEPALIVE_STATE_PINGING); + } + } + GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "keepalive watchdog"); +} + /******************************************************************************* * CALLBACK LOOP */ @@ -1960,53 +2568,29 @@ static void set_pollset_set(grpc_exec_ctx *exec_ctx, grpc_transport *gt, * BYTE STREAM */ -static void incoming_byte_stream_unref(grpc_exec_ctx *exec_ctx, - grpc_chttp2_incoming_byte_stream *bs) { - if (gpr_unref(&bs->refs)) { - GRPC_ERROR_UNREF(bs->error); - grpc_slice_buffer_destroy(&bs->slices); - gpr_mu_destroy(&bs->slice_mu); - gpr_free(bs); - } -} - -static void incoming_byte_stream_update_flow_control(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport *t, - grpc_chttp2_stream *s, - size_t max_size_hint, - size_t have_already) { - uint32_t max_recv_bytes; +static void reset_byte_stream(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error) { + grpc_chttp2_stream *s = (grpc_chttp2_stream *)arg; - /* clamp max recv hint to an allowable size */ - if (max_size_hint >= UINT32_MAX - t->stream_lookahead) { - max_recv_bytes = UINT32_MAX - t->stream_lookahead; + s->pending_byte_stream = false; + if (error == GRPC_ERROR_NONE) { + grpc_chttp2_maybe_complete_recv_message(exec_ctx, s->t, s); + grpc_chttp2_maybe_complete_recv_trailing_metadata(exec_ctx, s->t, s); } else { - max_recv_bytes = (uint32_t)max_size_hint; + GPR_ASSERT(error != GRPC_ERROR_NONE); + GRPC_CLOSURE_SCHED(exec_ctx, s->on_next, GRPC_ERROR_REF(error)); + s->on_next = NULL; + GRPC_ERROR_UNREF(s->byte_stream_error); + s->byte_stream_error = GRPC_ERROR_NONE; + grpc_chttp2_cancel_stream(exec_ctx, s->t, s, GRPC_ERROR_REF(error)); + s->byte_stream_error = error; } +} - /* account for bytes already received but unknown to higher layers */ - if (max_recv_bytes >= have_already) { - max_recv_bytes -= (uint32_t)have_already; - } else { - max_recv_bytes = 0; - } - - /* add some small lookahead to keep pipelines flowing */ - GPR_ASSERT(max_recv_bytes <= UINT32_MAX - t->stream_lookahead); - max_recv_bytes += t->stream_lookahead; - if (s->max_recv_bytes < max_recv_bytes) { - uint32_t add_max_recv_bytes = max_recv_bytes - s->max_recv_bytes; - bool new_window_write_is_covered_by_poller = - s->max_recv_bytes < have_already; - GRPC_CHTTP2_FLOW_CREDIT_STREAM("op", t, s, max_recv_bytes, - add_max_recv_bytes); - GRPC_CHTTP2_FLOW_CREDIT_STREAM("op", t, s, incoming_window, - add_max_recv_bytes); - GRPC_CHTTP2_FLOW_CREDIT_STREAM("op", t, s, announce_window, - add_max_recv_bytes); - grpc_chttp2_become_writable(exec_ctx, t, s, - new_window_write_is_covered_by_poller, - "read_incoming_stream"); +static void incoming_byte_stream_unref(grpc_exec_ctx *exec_ctx, + grpc_chttp2_incoming_byte_stream *bs) { + if (gpr_unref(&bs->refs)) { + gpr_free(bs); } } @@ -2017,115 +2601,218 @@ static void incoming_byte_stream_next_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t = bs->transport; grpc_chttp2_stream *s = bs->stream; - if (bs->is_tail) { - gpr_mu_lock(&bs->slice_mu); - size_t cur_length = bs->slices.length; - gpr_mu_unlock(&bs->slice_mu); - incoming_byte_stream_update_flow_control( - exec_ctx, t, s, bs->next_action.max_size_hint, cur_length); - } - gpr_mu_lock(&bs->slice_mu); - if (bs->slices.count > 0) { - *bs->next_action.slice = grpc_slice_buffer_take_first(&bs->slices); - grpc_closure_run(exec_ctx, bs->next_action.on_complete, GRPC_ERROR_NONE); - } else if (bs->error != GRPC_ERROR_NONE) { - grpc_closure_run(exec_ctx, bs->next_action.on_complete, - GRPC_ERROR_REF(bs->error)); + size_t cur_length = s->frame_storage.length; + if (!s->read_closed) { + grpc_chttp2_flowctl_incoming_bs_update(&t->flow_control, &s->flow_control, + bs->next_action.max_size_hint, + cur_length); + grpc_chttp2_act_on_flowctl_action( + exec_ctx, + grpc_chttp2_flowctl_get_action(&t->flow_control, &s->flow_control), t, + s); + } + GPR_ASSERT(s->unprocessed_incoming_frames_buffer.length == 0); + if (s->frame_storage.length > 0) { + grpc_slice_buffer_swap(&s->frame_storage, + &s->unprocessed_incoming_frames_buffer); + s->unprocessed_incoming_frames_decompressed = false; + GRPC_CLOSURE_SCHED(exec_ctx, bs->next_action.on_complete, GRPC_ERROR_NONE); + } else if (s->byte_stream_error != GRPC_ERROR_NONE) { + GRPC_CLOSURE_SCHED(exec_ctx, bs->next_action.on_complete, + GRPC_ERROR_REF(s->byte_stream_error)); + if (s->data_parser.parsing_frame != NULL) { + incoming_byte_stream_unref(exec_ctx, s->data_parser.parsing_frame); + s->data_parser.parsing_frame = NULL; + } + } else if (s->read_closed) { + if (bs->remaining_bytes != 0) { + s->byte_stream_error = + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Truncated message"); + GRPC_CLOSURE_SCHED(exec_ctx, bs->next_action.on_complete, + GRPC_ERROR_REF(s->byte_stream_error)); + if (s->data_parser.parsing_frame != NULL) { + incoming_byte_stream_unref(exec_ctx, s->data_parser.parsing_frame); + s->data_parser.parsing_frame = NULL; + } + } else { + /* Should never reach here. */ + GPR_ASSERT(false); + } } else { - bs->on_next = bs->next_action.on_complete; - bs->next = bs->next_action.slice; + s->on_next = bs->next_action.on_complete; } - gpr_mu_unlock(&bs->slice_mu); incoming_byte_stream_unref(exec_ctx, bs); } -static int incoming_byte_stream_next(grpc_exec_ctx *exec_ctx, - grpc_byte_stream *byte_stream, - grpc_slice *slice, size_t max_size_hint, - grpc_closure *on_complete) { +static bool incoming_byte_stream_next(grpc_exec_ctx *exec_ctx, + grpc_byte_stream *byte_stream, + size_t max_size_hint, + grpc_closure *on_complete) { GPR_TIMER_BEGIN("incoming_byte_stream_next", 0); grpc_chttp2_incoming_byte_stream *bs = (grpc_chttp2_incoming_byte_stream *)byte_stream; - gpr_ref(&bs->refs); - bs->next_action.slice = slice; - bs->next_action.max_size_hint = max_size_hint; - bs->next_action.on_complete = on_complete; - grpc_closure_init(&bs->next_action.closure, incoming_byte_stream_next_locked, - bs); - grpc_combiner_execute(exec_ctx, bs->transport->combiner, - &bs->next_action.closure, GRPC_ERROR_NONE, false); - GPR_TIMER_END("incoming_byte_stream_next", 0); - return 0; -} + grpc_chttp2_stream *s = bs->stream; + if (s->unprocessed_incoming_frames_buffer.length > 0) { + GPR_TIMER_END("incoming_byte_stream_next", 0); + return true; + } else { + gpr_ref(&bs->refs); + bs->next_action.max_size_hint = max_size_hint; + bs->next_action.on_complete = on_complete; + GRPC_CLOSURE_SCHED( + exec_ctx, + GRPC_CLOSURE_INIT(&bs->next_action.closure, + incoming_byte_stream_next_locked, bs, + grpc_combiner_scheduler(bs->transport->combiner)), + GRPC_ERROR_NONE); + GPR_TIMER_END("incoming_byte_stream_next", 0); + return false; + } +} + +static grpc_error *incoming_byte_stream_pull(grpc_exec_ctx *exec_ctx, + grpc_byte_stream *byte_stream, + grpc_slice *slice) { + GPR_TIMER_BEGIN("incoming_byte_stream_pull", 0); + grpc_chttp2_incoming_byte_stream *bs = + (grpc_chttp2_incoming_byte_stream *)byte_stream; + grpc_chttp2_stream *s = bs->stream; + grpc_error *error; -static void incoming_byte_stream_destroy(grpc_exec_ctx *exec_ctx, - grpc_byte_stream *byte_stream); + if (s->unprocessed_incoming_frames_buffer.length > 0) { + if (s->stream_compression_recv_enabled && + !s->unprocessed_incoming_frames_decompressed) { + bool end_of_context; + if (!s->stream_decompression_ctx) { + s->stream_decompression_ctx = grpc_stream_compression_context_create( + GRPC_STREAM_COMPRESSION_DECOMPRESS); + } + if (!grpc_stream_decompress(s->stream_decompression_ctx, + &s->unprocessed_incoming_frames_buffer, + s->decompressed_data_buffer, NULL, MAX_SIZE_T, + &end_of_context)) { + error = + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Stream decompression error."); + return error; + } + GPR_ASSERT(s->unprocessed_incoming_frames_buffer.length == 0); + grpc_slice_buffer_swap(&s->unprocessed_incoming_frames_buffer, + s->decompressed_data_buffer); + s->unprocessed_incoming_frames_decompressed = true; + if (end_of_context) { + grpc_stream_compression_context_destroy(s->stream_decompression_ctx); + s->stream_decompression_ctx = NULL; + } + } + error = grpc_deframe_unprocessed_incoming_frames( + exec_ctx, &s->data_parser, s, &s->unprocessed_incoming_frames_buffer, + slice, NULL); + if (error != GRPC_ERROR_NONE) { + return error; + } + } else { + error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Truncated message"); + GRPC_CLOSURE_SCHED(exec_ctx, &s->reset_byte_stream, GRPC_ERROR_REF(error)); + return error; + } + GPR_TIMER_END("incoming_byte_stream_pull", 0); + return GRPC_ERROR_NONE; +} static void incoming_byte_stream_destroy_locked(grpc_exec_ctx *exec_ctx, void *byte_stream, - grpc_error *error_ignored) { - grpc_chttp2_incoming_byte_stream *bs = byte_stream; - GPR_ASSERT(bs->base.destroy == incoming_byte_stream_destroy); - decrement_active_streams_locked(exec_ctx, bs->transport, bs->stream); - incoming_byte_stream_unref(exec_ctx, bs); -} + grpc_error *error_ignored); static void incoming_byte_stream_destroy(grpc_exec_ctx *exec_ctx, grpc_byte_stream *byte_stream) { GPR_TIMER_BEGIN("incoming_byte_stream_destroy", 0); grpc_chttp2_incoming_byte_stream *bs = (grpc_chttp2_incoming_byte_stream *)byte_stream; - grpc_closure_init(&bs->destroy_action, incoming_byte_stream_destroy_locked, - bs); - grpc_combiner_execute(exec_ctx, bs->transport->combiner, &bs->destroy_action, - GRPC_ERROR_NONE, false); + GRPC_CLOSURE_SCHED( + exec_ctx, GRPC_CLOSURE_INIT( + &bs->destroy_action, incoming_byte_stream_destroy_locked, + bs, grpc_combiner_scheduler(bs->transport->combiner)), + GRPC_ERROR_NONE); GPR_TIMER_END("incoming_byte_stream_destroy", 0); } static void incoming_byte_stream_publish_error( grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_byte_stream *bs, grpc_error *error) { + grpc_chttp2_stream *s = bs->stream; + GPR_ASSERT(error != GRPC_ERROR_NONE); - grpc_exec_ctx_sched(exec_ctx, bs->on_next, GRPC_ERROR_REF(error), NULL); - bs->on_next = NULL; - GRPC_ERROR_UNREF(bs->error); - bs->error = error; + GRPC_CLOSURE_SCHED(exec_ctx, s->on_next, GRPC_ERROR_REF(error)); + s->on_next = NULL; + GRPC_ERROR_UNREF(s->byte_stream_error); + s->byte_stream_error = GRPC_ERROR_REF(error); + grpc_chttp2_cancel_stream(exec_ctx, bs->transport, bs->stream, + GRPC_ERROR_REF(error)); } -void grpc_chttp2_incoming_byte_stream_push(grpc_exec_ctx *exec_ctx, - grpc_chttp2_incoming_byte_stream *bs, - grpc_slice slice) { - gpr_mu_lock(&bs->slice_mu); +grpc_error *grpc_chttp2_incoming_byte_stream_push( + grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_byte_stream *bs, + grpc_slice slice, grpc_slice *slice_out) { + grpc_chttp2_stream *s = bs->stream; + if (bs->remaining_bytes < GRPC_SLICE_LENGTH(slice)) { - incoming_byte_stream_publish_error( - exec_ctx, bs, GRPC_ERROR_CREATE("Too many bytes in stream")); + grpc_error *error = + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Too many bytes in stream"); + + GRPC_CLOSURE_SCHED(exec_ctx, &s->reset_byte_stream, GRPC_ERROR_REF(error)); + grpc_slice_unref_internal(exec_ctx, slice); + return error; } else { bs->remaining_bytes -= (uint32_t)GRPC_SLICE_LENGTH(slice); - if (bs->on_next != NULL) { - *bs->next = slice; - grpc_exec_ctx_sched(exec_ctx, bs->on_next, GRPC_ERROR_NONE, NULL); - bs->on_next = NULL; - } else { - grpc_slice_buffer_add(&bs->slices, slice); + if (slice_out != NULL) { + *slice_out = slice; } + return GRPC_ERROR_NONE; } - gpr_mu_unlock(&bs->slice_mu); } -void grpc_chttp2_incoming_byte_stream_finished( +grpc_error *grpc_chttp2_incoming_byte_stream_finished( grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_byte_stream *bs, - grpc_error *error) { + grpc_error *error, bool reset_on_error) { + grpc_chttp2_stream *s = bs->stream; + if (error == GRPC_ERROR_NONE) { - gpr_mu_lock(&bs->slice_mu); if (bs->remaining_bytes != 0) { - error = GRPC_ERROR_CREATE("Truncated message"); + error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Truncated message"); } - gpr_mu_unlock(&bs->slice_mu); } - if (error != GRPC_ERROR_NONE) { - incoming_byte_stream_publish_error(exec_ctx, bs, error); + if (error != GRPC_ERROR_NONE && reset_on_error) { + GRPC_CLOSURE_SCHED(exec_ctx, &s->reset_byte_stream, GRPC_ERROR_REF(error)); } incoming_byte_stream_unref(exec_ctx, bs); + return error; +} + +static void incoming_byte_stream_shutdown(grpc_exec_ctx *exec_ctx, + grpc_byte_stream *byte_stream, + grpc_error *error) { + grpc_chttp2_incoming_byte_stream *bs = + (grpc_chttp2_incoming_byte_stream *)byte_stream; + GRPC_ERROR_UNREF(grpc_chttp2_incoming_byte_stream_finished( + exec_ctx, bs, error, true /* reset_on_error */)); +} + +static const grpc_byte_stream_vtable grpc_chttp2_incoming_byte_stream_vtable = { + incoming_byte_stream_next, incoming_byte_stream_pull, + incoming_byte_stream_shutdown, incoming_byte_stream_destroy}; + +static void incoming_byte_stream_destroy_locked(grpc_exec_ctx *exec_ctx, + void *byte_stream, + grpc_error *error_ignored) { + grpc_chttp2_incoming_byte_stream *bs = byte_stream; + grpc_chttp2_stream *s = bs->stream; + grpc_chttp2_transport *t = s->t; + + GPR_ASSERT(bs->base.vtable == &grpc_chttp2_incoming_byte_stream_vtable); + incoming_byte_stream_unref(exec_ctx, bs); + s->pending_byte_stream = false; + grpc_chttp2_maybe_complete_recv_message(exec_ctx, t, s); + grpc_chttp2_maybe_complete_recv_trailing_metadata(exec_ctx, t, s); } grpc_chttp2_incoming_byte_stream *grpc_chttp2_incoming_byte_stream_create( @@ -2136,27 +2823,12 @@ grpc_chttp2_incoming_byte_stream *grpc_chttp2_incoming_byte_stream_create( incoming_byte_stream->base.length = frame_size; incoming_byte_stream->remaining_bytes = frame_size; incoming_byte_stream->base.flags = flags; - incoming_byte_stream->base.next = incoming_byte_stream_next; - incoming_byte_stream->base.destroy = incoming_byte_stream_destroy; - gpr_mu_init(&incoming_byte_stream->slice_mu); + incoming_byte_stream->base.vtable = &grpc_chttp2_incoming_byte_stream_vtable; gpr_ref_init(&incoming_byte_stream->refs, 2); - incoming_byte_stream->next_message = NULL; incoming_byte_stream->transport = t; incoming_byte_stream->stream = s; - gpr_ref(&incoming_byte_stream->stream->active_streams); - grpc_slice_buffer_init(&incoming_byte_stream->slices); - incoming_byte_stream->on_next = NULL; - incoming_byte_stream->is_tail = 1; - incoming_byte_stream->error = GRPC_ERROR_NONE; - grpc_chttp2_incoming_frame_queue *q = &s->incoming_frames; - if (q->head == NULL) { - q->head = incoming_byte_stream; - } else { - q->tail->is_tail = 0; - q->tail->next_message = incoming_byte_stream; - } - q->tail = incoming_byte_stream; - grpc_chttp2_maybe_complete_recv_message(exec_ctx, t, s); + GRPC_ERROR_UNREF(s->byte_stream_error); + s->byte_stream_error = GRPC_ERROR_NONE; return incoming_byte_stream; } @@ -2171,7 +2843,7 @@ static void post_benign_reclaimer(grpc_exec_ctx *exec_ctx, GRPC_CHTTP2_REF_TRANSPORT(t, "benign_reclaimer"); grpc_resource_user_post_reclaimer(exec_ctx, grpc_endpoint_get_resource_user(t->ep), - false, &t->benign_reclaimer); + false, &t->benign_reclaimer_locked); } } @@ -2182,24 +2854,10 @@ static void post_destructive_reclaimer(grpc_exec_ctx *exec_ctx, GRPC_CHTTP2_REF_TRANSPORT(t, "destructive_reclaimer"); grpc_resource_user_post_reclaimer(exec_ctx, grpc_endpoint_get_resource_user(t->ep), - true, &t->destructive_reclaimer); + true, &t->destructive_reclaimer_locked); } } -static void benign_reclaimer(grpc_exec_ctx *exec_ctx, void *arg, - grpc_error *error) { - grpc_chttp2_transport *t = arg; - grpc_combiner_execute(exec_ctx, t->combiner, &t->benign_reclaimer_locked, - GRPC_ERROR_REF(error), false); -} - -static void destructive_reclaimer(grpc_exec_ctx *exec_ctx, void *arg, - grpc_error *error) { - grpc_chttp2_transport *t = arg; - grpc_combiner_execute(exec_ctx, t->combiner, &t->destructive_reclaimer_locked, - GRPC_ERROR_REF(error), false); -} - static void benign_reclaimer_locked(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { grpc_chttp2_transport *t = arg; @@ -2207,13 +2865,16 @@ static void benign_reclaimer_locked(grpc_exec_ctx *exec_ctx, void *arg, grpc_chttp2_stream_map_size(&t->stream_map) == 0) { /* Channel with no active streams: send a goaway to try and make it * disconnect cleanly */ - if (grpc_resource_quota_trace) { + if (GRPC_TRACER_ON(grpc_resource_quota_trace)) { gpr_log(GPR_DEBUG, "HTTP2: %s - send goaway to free memory", t->peer_string); } - send_goaway(exec_ctx, t, GRPC_CHTTP2_ENHANCE_YOUR_CALM, - grpc_slice_from_static_string("Buffers full")); - } else if (error == GRPC_ERROR_NONE && grpc_resource_quota_trace) { + send_goaway(exec_ctx, t, + grpc_error_set_int( + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Buffers full"), + GRPC_ERROR_INT_HTTP2_ERROR, GRPC_HTTP2_ENHANCE_YOUR_CALM)); + } else if (error == GRPC_ERROR_NONE && + GRPC_TRACER_ON(grpc_resource_quota_trace)) { gpr_log(GPR_DEBUG, "HTTP2: %s - skip benign reclamation, there are still %" PRIdPTR " streams", @@ -2234,14 +2895,15 @@ static void destructive_reclaimer_locked(grpc_exec_ctx *exec_ctx, void *arg, t->destructive_reclaimer_registered = false; if (error == GRPC_ERROR_NONE && n > 0) { grpc_chttp2_stream *s = grpc_chttp2_stream_map_rand(&t->stream_map); - if (grpc_resource_quota_trace) { + if (GRPC_TRACER_ON(grpc_resource_quota_trace)) { gpr_log(GPR_DEBUG, "HTTP2: %s - abandon stream id %d", t->peer_string, s->id); } grpc_chttp2_cancel_stream( - exec_ctx, t, s, grpc_error_set_int(GRPC_ERROR_CREATE("Buffers full"), - GRPC_ERROR_INT_HTTP2_ERROR, - GRPC_CHTTP2_ENHANCE_YOUR_CALM)); + exec_ctx, t, s, + grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING("Buffers full"), + GRPC_ERROR_INT_HTTP2_ERROR, + GRPC_HTTP2_ENHANCE_YOUR_CALM)); if (n > 1) { /* Since we cancel one stream per destructive reclamation, if there are more streams left, we can immediately post a new @@ -2257,83 +2919,6 @@ static void destructive_reclaimer_locked(grpc_exec_ctx *exec_ctx, void *arg, GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "destructive_reclaimer"); } -/******************************************************************************* - * TRACING - */ - -static char *format_flowctl_context_var(const char *context, const char *var, - int64_t val, uint32_t id) { - char *name; - if (context == NULL) { - name = gpr_strdup(var); - } else if (0 == strcmp(context, "t")) { - GPR_ASSERT(id == 0); - gpr_asprintf(&name, "TRANSPORT:%s", var); - } else if (0 == strcmp(context, "s")) { - GPR_ASSERT(id != 0); - gpr_asprintf(&name, "STREAM[%d]:%s", id, var); - } else { - gpr_asprintf(&name, "BAD_CONTEXT[%s][%d]:%s", context, id, var); - } - char *name_fld = gpr_leftpad(name, ' ', 64); - char *value; - gpr_asprintf(&value, "%" PRId64, val); - char *value_fld = gpr_leftpad(value, ' ', 8); - char *result; - gpr_asprintf(&result, "%s %s", name_fld, value_fld); - gpr_free(name); - gpr_free(name_fld); - gpr_free(value); - gpr_free(value_fld); - return result; -} - -void grpc_chttp2_flowctl_trace(const char *file, int line, const char *phase, - grpc_chttp2_flowctl_op op, const char *context1, - const char *var1, const char *context2, - const char *var2, int is_client, - uint32_t stream_id, int64_t val1, int64_t val2) { - char *tmp_phase; - char *label1 = format_flowctl_context_var(context1, var1, val1, stream_id); - char *label2 = format_flowctl_context_var(context2, var2, val2, stream_id); - char *clisvr = is_client ? "client" : "server"; - char *prefix; - - tmp_phase = gpr_leftpad(phase, ' ', 8); - gpr_asprintf(&prefix, "FLOW %s: %s ", tmp_phase, clisvr); - gpr_free(tmp_phase); - - switch (op) { - case GRPC_CHTTP2_FLOWCTL_MOVE: - if (val2 != 0) { - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, - "%sMOVE %s <- %s giving %" PRId64, prefix, label1, label2, - val1 + val2); - } - break; - case GRPC_CHTTP2_FLOWCTL_CREDIT: - GPR_ASSERT(val2 >= 0); - if (val2 != 0) { - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, - "%sCREDIT %s by %s giving %" PRId64, prefix, label1, label2, - val1 + val2); - } - break; - case GRPC_CHTTP2_FLOWCTL_DEBIT: - GPR_ASSERT(val2 >= 0); - if (val2 != 0) { - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, - "%sDEBIT %s by %s giving %" PRId64, prefix, label1, label2, - val1 - val2); - } - break; - } - - gpr_free(label1); - gpr_free(label2); - gpr_free(prefix); -} - /******************************************************************************* * INTEGRATION GLUE */ @@ -2365,7 +2950,7 @@ static const grpc_transport_vtable vtable = {sizeof(grpc_chttp2_stream), grpc_transport *grpc_create_chttp2_transport( grpc_exec_ctx *exec_ctx, const grpc_channel_args *channel_args, grpc_endpoint *ep, int is_client) { - grpc_chttp2_transport *t = gpr_malloc(sizeof(grpc_chttp2_transport)); + grpc_chttp2_transport *t = gpr_zalloc(sizeof(grpc_chttp2_transport)); init_transport(exec_ctx, t, channel_args, ep, is_client != 0); return &t->base; } @@ -2380,5 +2965,5 @@ void grpc_chttp2_transport_start_reading(grpc_exec_ctx *exec_ctx, grpc_slice_buffer_move_into(read_buffer, &t->read_buffer); gpr_free(read_buffer); } - read_action_begin(exec_ctx, t, GRPC_ERROR_NONE); + GRPC_CLOSURE_SCHED(exec_ctx, &t->read_action_locked, GRPC_ERROR_NONE); } diff --git a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/chttp2_transport.h b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/chttp2_transport.h index c372174f2..0c4e2a91c 100644 --- a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/chttp2_transport.h +++ b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/chttp2_transport.h @@ -1,44 +1,34 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_CHTTP2_TRANSPORT_H #define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_CHTTP2_TRANSPORT_H +#include "src/core/lib/debug/trace.h" #include "src/core/lib/iomgr/endpoint.h" #include "src/core/lib/transport/transport.h" -extern int grpc_http_trace; -extern int grpc_flowctl_trace; +extern grpc_tracer_flag grpc_http_trace; +extern grpc_tracer_flag grpc_flowctl_trace; + +#ifndef NDEBUG +extern grpc_tracer_flag grpc_trace_chttp2_refcount; +#endif grpc_transport *grpc_create_chttp2_transport( grpc_exec_ctx *exec_ctx, const grpc_channel_args *channel_args, diff --git a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/flow_control.c b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/flow_control.c new file mode 100644 index 000000000..8dbdd1290 --- /dev/null +++ b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/flow_control.c @@ -0,0 +1,500 @@ +/* + * + * Copyright 2017 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 "src/core/ext/transport/chttp2/transport/internal.h" + +#include +#include + +#include +#include +#include +#include + +#include "src/core/lib/support/string.h" + +static uint32_t grpc_chttp2_target_announced_window( + const grpc_chttp2_transport_flowctl* tfc); + +#ifndef NDEBUG + +typedef struct { + int64_t remote_window; + int64_t target_window; + int64_t announced_window; + int64_t remote_window_delta; + int64_t local_window_delta; + int64_t announced_window_delta; + uint32_t local_init_window; + uint32_t local_max_frame; +} shadow_flow_control; + +static void pretrace(shadow_flow_control* shadow_fc, + grpc_chttp2_transport_flowctl* tfc, + grpc_chttp2_stream_flowctl* sfc) { + shadow_fc->remote_window = tfc->remote_window; + shadow_fc->target_window = grpc_chttp2_target_announced_window(tfc); + shadow_fc->announced_window = tfc->announced_window; + if (sfc != NULL) { + shadow_fc->remote_window_delta = sfc->remote_window_delta; + shadow_fc->local_window_delta = sfc->local_window_delta; + shadow_fc->announced_window_delta = sfc->announced_window_delta; + } +} + +#define TRACE_PADDING 30 + +static char* fmt_int64_diff_str(int64_t old, int64_t new) { + char* str; + if (old != new) { + gpr_asprintf(&str, "%" PRId64 " -> %" PRId64 "", old, new); + } else { + gpr_asprintf(&str, "%" PRId64 "", old); + } + char* str_lp = gpr_leftpad(str, ' ', TRACE_PADDING); + gpr_free(str); + return str_lp; +} + +static char* fmt_uint32_diff_str(uint32_t old, uint32_t new) { + char* str; + if (new > 0 && old != new) { + gpr_asprintf(&str, "%" PRIu32 " -> %" PRIu32 "", old, new); + } else { + gpr_asprintf(&str, "%" PRIu32 "", old); + } + char* str_lp = gpr_leftpad(str, ' ', TRACE_PADDING); + gpr_free(str); + return str_lp; +} + +static void posttrace(shadow_flow_control* shadow_fc, + grpc_chttp2_transport_flowctl* tfc, + grpc_chttp2_stream_flowctl* sfc, char* reason) { + uint32_t acked_local_window = + tfc->t->settings[GRPC_SENT_SETTINGS] + [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]; + uint32_t remote_window = + tfc->t->settings[GRPC_PEER_SETTINGS] + [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]; + char* trw_str = + fmt_int64_diff_str(shadow_fc->remote_window, tfc->remote_window); + char* tlw_str = fmt_int64_diff_str(shadow_fc->target_window, + grpc_chttp2_target_announced_window(tfc)); + char* taw_str = + fmt_int64_diff_str(shadow_fc->announced_window, tfc->announced_window); + char* srw_str; + char* slw_str; + char* saw_str; + if (sfc != NULL) { + srw_str = fmt_int64_diff_str(shadow_fc->remote_window_delta + remote_window, + sfc->remote_window_delta + remote_window); + slw_str = + fmt_int64_diff_str(shadow_fc->local_window_delta + acked_local_window, + sfc->local_window_delta + acked_local_window); + saw_str = fmt_int64_diff_str( + shadow_fc->announced_window_delta + acked_local_window, + sfc->announced_window_delta + acked_local_window); + } else { + srw_str = gpr_leftpad("", ' ', TRACE_PADDING); + slw_str = gpr_leftpad("", ' ', TRACE_PADDING); + saw_str = gpr_leftpad("", ' ', TRACE_PADDING); + } + gpr_log(GPR_DEBUG, + "%p[%u][%s] | %s | trw:%s, ttw:%s, taw:%s, srw:%s, slw:%s, saw:%s", + tfc, sfc != NULL ? sfc->s->id : 0, tfc->t->is_client ? "cli" : "svr", + reason, trw_str, tlw_str, taw_str, srw_str, slw_str, saw_str); + gpr_free(trw_str); + gpr_free(tlw_str); + gpr_free(taw_str); + gpr_free(srw_str); + gpr_free(slw_str); + gpr_free(saw_str); +} + +static char* urgency_to_string(grpc_chttp2_flowctl_urgency urgency) { + switch (urgency) { + case GRPC_CHTTP2_FLOWCTL_NO_ACTION_NEEDED: + return "no action"; + case GRPC_CHTTP2_FLOWCTL_UPDATE_IMMEDIATELY: + return "update immediately"; + case GRPC_CHTTP2_FLOWCTL_QUEUE_UPDATE: + return "queue update"; + default: + GPR_UNREACHABLE_CODE(return "unknown"); + } + GPR_UNREACHABLE_CODE(return "unknown"); +} + +static void trace_action(grpc_chttp2_transport_flowctl* tfc, + grpc_chttp2_flowctl_action action) { + char* iw_str = fmt_uint32_diff_str( + tfc->t->settings[GRPC_SENT_SETTINGS] + [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE], + action.initial_window_size); + char* mf_str = fmt_uint32_diff_str( + tfc->t->settings[GRPC_SENT_SETTINGS][GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE], + action.max_frame_size); + gpr_log(GPR_DEBUG, "t[%s], s[%s], settings[%s] iw:%s mf:%s", + urgency_to_string(action.send_transport_update), + urgency_to_string(action.send_stream_update), + urgency_to_string(action.send_setting_update), iw_str, mf_str); + gpr_free(iw_str); + gpr_free(mf_str); +} + +#define PRETRACE(tfc, sfc) \ + shadow_flow_control shadow_fc; \ + GRPC_FLOW_CONTROL_IF_TRACING(pretrace(&shadow_fc, tfc, sfc)) +#define POSTTRACE(tfc, sfc, reason) \ + GRPC_FLOW_CONTROL_IF_TRACING(posttrace(&shadow_fc, tfc, sfc, reason)) +#define TRACEACTION(tfc, action) \ + GRPC_FLOW_CONTROL_IF_TRACING(trace_action(tfc, action)) +#else +#define PRETRACE(tfc, sfc) +#define POSTTRACE(tfc, sfc, reason) +#define TRACEACTION(tfc, action) +#endif + +/* How many bytes of incoming flow control would we like to advertise */ +static uint32_t grpc_chttp2_target_announced_window( + const grpc_chttp2_transport_flowctl* tfc) { + return (uint32_t)GPR_MIN( + (int64_t)((1u << 31) - 1), + tfc->announced_stream_total_over_incoming_window + + tfc->t->settings[GRPC_SENT_SETTINGS] + [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]); +} + +// we have sent data on the wire, we must track this in our bookkeeping for the +// remote peer's flow control. +void grpc_chttp2_flowctl_sent_data(grpc_chttp2_transport_flowctl* tfc, + grpc_chttp2_stream_flowctl* sfc, + int64_t size) { + PRETRACE(tfc, sfc); + tfc->remote_window -= size; + sfc->remote_window_delta -= size; + POSTTRACE(tfc, sfc, " data sent"); +} + +static void announced_window_delta_preupdate(grpc_chttp2_transport_flowctl* tfc, + grpc_chttp2_stream_flowctl* sfc) { + if (sfc->announced_window_delta > 0) { + tfc->announced_stream_total_over_incoming_window -= + sfc->announced_window_delta; + } else { + tfc->announced_stream_total_under_incoming_window += + -sfc->announced_window_delta; + } +} + +static void announced_window_delta_postupdate( + grpc_chttp2_transport_flowctl* tfc, grpc_chttp2_stream_flowctl* sfc) { + if (sfc->announced_window_delta > 0) { + tfc->announced_stream_total_over_incoming_window += + sfc->announced_window_delta; + } else { + tfc->announced_stream_total_under_incoming_window -= + -sfc->announced_window_delta; + } +} + +// We have received data from the wire. We must track this in our own flow +// control bookkeeping. +// Returns an error if the incoming frame violates our flow control. +grpc_error* grpc_chttp2_flowctl_recv_data(grpc_chttp2_transport_flowctl* tfc, + grpc_chttp2_stream_flowctl* sfc, + int64_t incoming_frame_size) { + uint32_t sent_init_window = + tfc->t->settings[GRPC_SENT_SETTINGS] + [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]; + uint32_t acked_init_window = + tfc->t->settings[GRPC_ACKED_SETTINGS] + [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]; + PRETRACE(tfc, sfc); + if (incoming_frame_size > tfc->announced_window) { + char* msg; + gpr_asprintf(&msg, + "frame of size %" PRId64 " overflows local window of %" PRId64, + incoming_frame_size, tfc->announced_window); + grpc_error* err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg); + gpr_free(msg); + return err; + } + + if (sfc != NULL) { + int64_t acked_stream_window = + sfc->announced_window_delta + acked_init_window; + int64_t sent_stream_window = sfc->announced_window_delta + sent_init_window; + if (incoming_frame_size > acked_stream_window) { + if (incoming_frame_size <= sent_stream_window) { + gpr_log( + GPR_ERROR, + "Incoming frame of size %" PRId64 + " exceeds local window size of %" PRId64 + ".\n" + "The (un-acked, future) window size would be %" PRId64 + " which is not exceeded.\n" + "This would usually cause a disconnection, but allowing it due to" + "broken HTTP2 implementations in the wild.\n" + "See (for example) https://github.com/netty/netty/issues/6520.", + incoming_frame_size, acked_stream_window, sent_stream_window); + } else { + char* msg; + gpr_asprintf(&msg, "frame of size %" PRId64 + " overflows local window of %" PRId64, + incoming_frame_size, acked_stream_window); + grpc_error* err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg); + gpr_free(msg); + return err; + } + } + + announced_window_delta_preupdate(tfc, sfc); + sfc->announced_window_delta -= incoming_frame_size; + announced_window_delta_postupdate(tfc, sfc); + sfc->local_window_delta -= incoming_frame_size; + } + + tfc->announced_window -= incoming_frame_size; + + POSTTRACE(tfc, sfc, " data recv"); + return GRPC_ERROR_NONE; +} + +// Returns a non zero announce integer if we should send a transport window +// update +uint32_t grpc_chttp2_flowctl_maybe_send_transport_update( + grpc_chttp2_transport_flowctl* tfc) { + PRETRACE(tfc, NULL); + uint32_t target_announced_window = grpc_chttp2_target_announced_window(tfc); + uint32_t threshold_to_send_transport_window_update = + tfc->t->outbuf.count > 0 ? 3 * target_announced_window / 4 + : target_announced_window / 2; + if (tfc->announced_window <= threshold_to_send_transport_window_update && + tfc->announced_window != target_announced_window) { + uint32_t announce = (uint32_t)GPR_CLAMP( + target_announced_window - tfc->announced_window, 0, UINT32_MAX); + tfc->announced_window += announce; + POSTTRACE(tfc, NULL, "t updt sent"); + return announce; + } + GRPC_FLOW_CONTROL_IF_TRACING( + gpr_log(GPR_DEBUG, "%p[0][%s] will not send transport update", tfc, + tfc->t->is_client ? "cli" : "svr")); + return 0; +} + +// Returns a non zero announce integer if we should send a stream window update +uint32_t grpc_chttp2_flowctl_maybe_send_stream_update( + grpc_chttp2_transport_flowctl* tfc, grpc_chttp2_stream_flowctl* sfc) { + PRETRACE(tfc, sfc); + if (sfc->local_window_delta > sfc->announced_window_delta) { + uint32_t announce = (uint32_t)GPR_CLAMP( + sfc->local_window_delta - sfc->announced_window_delta, 0, UINT32_MAX); + announced_window_delta_preupdate(tfc, sfc); + sfc->announced_window_delta += announce; + announced_window_delta_postupdate(tfc, sfc); + POSTTRACE(tfc, sfc, "s updt sent"); + return announce; + } + GRPC_FLOW_CONTROL_IF_TRACING( + gpr_log(GPR_DEBUG, "%p[%u][%s] will not send stream update", tfc, + sfc->s->id, tfc->t->is_client ? "cli" : "svr")); + return 0; +} + +// we have received a WINDOW_UPDATE frame for a transport +void grpc_chttp2_flowctl_recv_transport_update( + grpc_chttp2_transport_flowctl* tfc, uint32_t size) { + PRETRACE(tfc, NULL); + tfc->remote_window += size; + POSTTRACE(tfc, NULL, "t updt recv"); +} + +// we have received a WINDOW_UPDATE frame for a stream +void grpc_chttp2_flowctl_recv_stream_update(grpc_chttp2_transport_flowctl* tfc, + grpc_chttp2_stream_flowctl* sfc, + uint32_t size) { + PRETRACE(tfc, sfc); + sfc->remote_window_delta += size; + POSTTRACE(tfc, sfc, "s updt recv"); +} + +void grpc_chttp2_flowctl_incoming_bs_update(grpc_chttp2_transport_flowctl* tfc, + grpc_chttp2_stream_flowctl* sfc, + size_t max_size_hint, + size_t have_already) { + PRETRACE(tfc, sfc); + uint32_t max_recv_bytes; + uint32_t sent_init_window = + tfc->t->settings[GRPC_SENT_SETTINGS] + [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]; + + /* clamp max recv hint to an allowable size */ + if (max_size_hint >= UINT32_MAX - sent_init_window) { + max_recv_bytes = UINT32_MAX - sent_init_window; + } else { + max_recv_bytes = (uint32_t)max_size_hint; + } + + /* account for bytes already received but unknown to higher layers */ + if (max_recv_bytes >= have_already) { + max_recv_bytes -= (uint32_t)have_already; + } else { + max_recv_bytes = 0; + } + + /* add some small lookahead to keep pipelines flowing */ + GPR_ASSERT(max_recv_bytes <= UINT32_MAX - sent_init_window); + if (sfc->local_window_delta < max_recv_bytes) { + uint32_t add_max_recv_bytes = + (uint32_t)(max_recv_bytes - sfc->local_window_delta); + sfc->local_window_delta += add_max_recv_bytes; + } + POSTTRACE(tfc, sfc, "app st recv"); +} + +void grpc_chttp2_flowctl_destroy_stream(grpc_chttp2_transport_flowctl* tfc, + grpc_chttp2_stream_flowctl* sfc) { + announced_window_delta_preupdate(tfc, sfc); +} + +// Returns an urgency with which to make an update +static grpc_chttp2_flowctl_urgency delta_is_significant( + const grpc_chttp2_transport_flowctl* tfc, int32_t value, + grpc_chttp2_setting_id setting_id) { + int64_t delta = (int64_t)value - + (int64_t)tfc->t->settings[GRPC_LOCAL_SETTINGS][setting_id]; + // TODO(ncteisen): tune this + if (delta != 0 && (delta <= -value / 5 || delta >= value / 5)) { + return GRPC_CHTTP2_FLOWCTL_QUEUE_UPDATE; + } else { + return GRPC_CHTTP2_FLOWCTL_NO_ACTION_NEEDED; + } +} + +// Takes in a target and uses the pid controller to return a stabilized +// guess at the new bdp. +static double get_pid_controller_guess(grpc_chttp2_transport_flowctl* tfc, + double target) { + double bdp_error = target - grpc_pid_controller_last(&tfc->pid_controller); + gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC); + gpr_timespec dt_timespec = gpr_time_sub(now, tfc->last_pid_update); + double dt = (double)dt_timespec.tv_sec + dt_timespec.tv_nsec * 1e-9; + if (dt > 0.1) { + dt = 0.1; + } + double log2_bdp_guess = + grpc_pid_controller_update(&tfc->pid_controller, bdp_error, dt); + tfc->last_pid_update = now; + return pow(2, log2_bdp_guess); +} + +// Take in a target and modifies it based on the memory pressure of the system +static double get_target_under_memory_pressure( + grpc_chttp2_transport_flowctl* tfc, double target) { + // do not increase window under heavy memory pressure. + double memory_pressure = grpc_resource_quota_get_memory_pressure( + grpc_resource_user_quota(grpc_endpoint_get_resource_user(tfc->t->ep))); + if (memory_pressure > 0.8) { + target *= 1 - GPR_MIN(1, (memory_pressure - 0.8) / 0.1); + } + return target; +} + +grpc_chttp2_flowctl_action grpc_chttp2_flowctl_get_action( + grpc_chttp2_transport_flowctl* tfc, grpc_chttp2_stream_flowctl* sfc) { + grpc_chttp2_flowctl_action action; + memset(&action, 0, sizeof(action)); + uint32_t target_announced_window = grpc_chttp2_target_announced_window(tfc); + if (tfc->announced_window < target_announced_window / 2) { + action.send_transport_update = GRPC_CHTTP2_FLOWCTL_UPDATE_IMMEDIATELY; + } + // TODO(ncteisen): tune this + if (sfc != NULL && !sfc->s->read_closed) { + uint32_t sent_init_window = + tfc->t->settings[GRPC_SENT_SETTINGS] + [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]; + if ((int64_t)sfc->local_window_delta > + (int64_t)sfc->announced_window_delta && + (int64_t)sfc->announced_window_delta + sent_init_window <= + sent_init_window / 2) { + action.send_stream_update = GRPC_CHTTP2_FLOWCTL_UPDATE_IMMEDIATELY; + } else if (sfc->local_window_delta > sfc->announced_window_delta) { + action.send_stream_update = GRPC_CHTTP2_FLOWCTL_QUEUE_UPDATE; + } + } + TRACEACTION(tfc, action); + return action; +} + +grpc_chttp2_flowctl_action grpc_chttp2_flowctl_get_bdp_action( + grpc_chttp2_transport_flowctl* tfc) { + grpc_chttp2_flowctl_action action; + memset(&action, 0, sizeof(action)); + if (tfc->enable_bdp_probe) { + action.need_ping = grpc_bdp_estimator_need_ping(&tfc->bdp_estimator); + + // get bdp estimate and update initial_window accordingly. + int64_t estimate = -1; + int32_t bdp = -1; + if (grpc_bdp_estimator_get_estimate(&tfc->bdp_estimator, &estimate)) { + double target = 1 + log2((double)estimate); + + // target might change based on how much memory pressure we are under + // TODO(ncteisen): experiment with setting target to be huge under low + // memory pressure. + target = get_target_under_memory_pressure(tfc, target); + + // run our target through the pid controller to stabilize change. + // TODO(ncteisen): experiment with other controllers here. + double bdp_guess = get_pid_controller_guess(tfc, target); + + // Though initial window 'could' drop to 0, we keep the floor at 128 + bdp = GPR_MAX((int32_t)bdp_guess, 128); + + grpc_chttp2_flowctl_urgency init_window_update_urgency = + delta_is_significant(tfc, bdp, + GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE); + if (init_window_update_urgency != GRPC_CHTTP2_FLOWCTL_NO_ACTION_NEEDED) { + action.send_setting_update = init_window_update_urgency; + action.initial_window_size = (uint32_t)bdp; + } + } + + // get bandwidth estimate and update max_frame accordingly. + double bw_dbl = -1; + if (grpc_bdp_estimator_get_bw(&tfc->bdp_estimator, &bw_dbl)) { + // we target the max of BDP or bandwidth in microseconds. + int32_t frame_size = + GPR_CLAMP(GPR_MAX((int32_t)bw_dbl / 1000, bdp), 16384, 16777215); + grpc_chttp2_flowctl_urgency frame_size_urgency = delta_is_significant( + tfc, frame_size, GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE); + if (frame_size_urgency != GRPC_CHTTP2_FLOWCTL_NO_ACTION_NEEDED) { + if (frame_size_urgency > action.send_setting_update) { + action.send_setting_update = frame_size_urgency; + } + action.max_frame_size = (uint32_t)frame_size; + } + } + } + + TRACEACTION(tfc, action); + return action; +} diff --git a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/frame.h b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/frame.h index ffd4d9669..dba4c004e 100644 --- a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/frame.h +++ b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/frame.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/frame_data.c b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/frame_data.c index f9b9e1b30..222d2177b 100644 --- a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/frame_data.c +++ b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/frame_data.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -40,6 +25,7 @@ #include #include #include "src/core/ext/transport/chttp2/transport/internal.h" +#include "src/core/lib/slice/slice_internal.h" #include "src/core/lib/slice/slice_string_helpers.h" #include "src/core/lib/support/string.h" #include "src/core/lib/transport/transport.h" @@ -53,66 +39,36 @@ grpc_error *grpc_chttp2_data_parser_init(grpc_chttp2_data_parser *parser) { void grpc_chttp2_data_parser_destroy(grpc_exec_ctx *exec_ctx, grpc_chttp2_data_parser *parser) { if (parser->parsing_frame != NULL) { - grpc_chttp2_incoming_byte_stream_finished( - exec_ctx, parser->parsing_frame, GRPC_ERROR_CREATE("Parser destroyed")); + GRPC_ERROR_UNREF(grpc_chttp2_incoming_byte_stream_finished( + exec_ctx, parser->parsing_frame, + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Parser destroyed"), false)); } GRPC_ERROR_UNREF(parser->error); } grpc_error *grpc_chttp2_data_parser_begin_frame(grpc_chttp2_data_parser *parser, uint8_t flags, - uint32_t stream_id) { + uint32_t stream_id, + grpc_chttp2_stream *s) { if (flags & ~GRPC_CHTTP2_DATA_FLAG_END_STREAM) { char *msg; gpr_asprintf(&msg, "unsupported data flags: 0x%02x", flags); - grpc_error *err = grpc_error_set_int( - GRPC_ERROR_CREATE(msg), GRPC_ERROR_INT_STREAM_ID, (intptr_t)stream_id); + grpc_error *err = + grpc_error_set_int(GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg), + GRPC_ERROR_INT_STREAM_ID, (intptr_t)stream_id); gpr_free(msg); return err; } if (flags & GRPC_CHTTP2_DATA_FLAG_END_STREAM) { - parser->is_last_frame = 1; + s->received_last_frame = true; } else { - parser->is_last_frame = 0; + s->received_last_frame = false; } return GRPC_ERROR_NONE; } -void grpc_chttp2_incoming_frame_queue_merge( - grpc_chttp2_incoming_frame_queue *head_dst, - grpc_chttp2_incoming_frame_queue *tail_src) { - if (tail_src->head == NULL) { - return; - } - - if (head_dst->head == NULL) { - *head_dst = *tail_src; - memset(tail_src, 0, sizeof(*tail_src)); - return; - } - - head_dst->tail->next_message = tail_src->head; - head_dst->tail = tail_src->tail; - memset(tail_src, 0, sizeof(*tail_src)); -} - -grpc_byte_stream *grpc_chttp2_incoming_frame_queue_pop( - grpc_chttp2_incoming_frame_queue *q) { - grpc_byte_stream *out; - if (q->head == NULL) { - return NULL; - } - out = &q->head->base; - if (q->head == q->tail) { - memset(q, 0, sizeof(*q)); - } else { - q->head = q->head->next_message; - } - return out; -} - void grpc_chttp2_encode_data(uint32_t id, grpc_slice_buffer *inbuf, uint32_t write_bytes, int is_eof, grpc_transport_one_way_stats *stats, @@ -121,7 +77,7 @@ void grpc_chttp2_encode_data(uint32_t id, grpc_slice_buffer *inbuf, uint8_t *p; static const size_t header_size = 9; - hdr = grpc_slice_malloc(header_size); + hdr = GRPC_SLICE_MALLOC(header_size); p = GRPC_SLICE_START_PTR(hdr); GPR_ASSERT(write_bytes < (1 << 24)); *p++ = (uint8_t)(write_bytes >> 16); @@ -135,150 +91,228 @@ void grpc_chttp2_encode_data(uint32_t id, grpc_slice_buffer *inbuf, *p++ = (uint8_t)(id); grpc_slice_buffer_add(outbuf, hdr); - grpc_slice_buffer_move_first(inbuf, write_bytes, outbuf); + grpc_slice_buffer_move_first_no_ref(inbuf, write_bytes, outbuf); stats->framing_bytes += header_size; stats->data_bytes += write_bytes; } -static grpc_error *parse_inner(grpc_exec_ctx *exec_ctx, - grpc_chttp2_data_parser *p, - grpc_chttp2_transport *t, grpc_chttp2_stream *s, - grpc_slice slice) { - uint8_t *const beg = GRPC_SLICE_START_PTR(slice); - uint8_t *const end = GRPC_SLICE_END_PTR(slice); - uint8_t *cur = beg; - uint32_t message_flags; - grpc_chttp2_incoming_byte_stream *incoming_byte_stream; - char *msg; +grpc_error *grpc_deframe_unprocessed_incoming_frames( + grpc_exec_ctx *exec_ctx, grpc_chttp2_data_parser *p, grpc_chttp2_stream *s, + grpc_slice_buffer *slices, grpc_slice *slice_out, + grpc_byte_stream **stream_out) { + grpc_error *error = GRPC_ERROR_NONE; + grpc_chttp2_transport *t = s->t; - if (cur == end) { - return GRPC_ERROR_NONE; - } + while (slices->count > 0) { + uint8_t *beg = NULL; + uint8_t *end = NULL; + uint8_t *cur = NULL; - switch (p->state) { - case GRPC_CHTTP2_DATA_ERROR: - p->state = GRPC_CHTTP2_DATA_ERROR; - return GRPC_ERROR_REF(p->error); - fh_0: - case GRPC_CHTTP2_DATA_FH_0: - s->stats.incoming.framing_bytes++; - p->frame_type = *cur; - switch (p->frame_type) { - case 0: - p->is_frame_compressed = 0; /* GPR_FALSE */ - break; - case 1: - p->is_frame_compressed = 1; /* GPR_TRUE */ - break; - default: - gpr_asprintf(&msg, "Bad GRPC frame type 0x%02x", p->frame_type); - p->error = GRPC_ERROR_CREATE(msg); - p->error = grpc_error_set_int(p->error, GRPC_ERROR_INT_STREAM_ID, - (intptr_t)s->id); - gpr_free(msg); - msg = grpc_dump_slice(slice, GPR_DUMP_HEX | GPR_DUMP_ASCII); - p->error = - grpc_error_set_str(p->error, GRPC_ERROR_STR_RAW_BYTES, msg); - gpr_free(msg); - p->error = - grpc_error_set_int(p->error, GRPC_ERROR_INT_OFFSET, cur - beg); - p->state = GRPC_CHTTP2_DATA_ERROR; - return GRPC_ERROR_REF(p->error); - } - if (++cur == end) { - p->state = GRPC_CHTTP2_DATA_FH_1; - return GRPC_ERROR_NONE; - } - /* fallthrough */ - case GRPC_CHTTP2_DATA_FH_1: - s->stats.incoming.framing_bytes++; - p->frame_size = ((uint32_t)*cur) << 24; - if (++cur == end) { - p->state = GRPC_CHTTP2_DATA_FH_2; - return GRPC_ERROR_NONE; - } - /* fallthrough */ - case GRPC_CHTTP2_DATA_FH_2: - s->stats.incoming.framing_bytes++; - p->frame_size |= ((uint32_t)*cur) << 16; - if (++cur == end) { - p->state = GRPC_CHTTP2_DATA_FH_3; - return GRPC_ERROR_NONE; - } - /* fallthrough */ - case GRPC_CHTTP2_DATA_FH_3: - s->stats.incoming.framing_bytes++; - p->frame_size |= ((uint32_t)*cur) << 8; - if (++cur == end) { - p->state = GRPC_CHTTP2_DATA_FH_4; - return GRPC_ERROR_NONE; - } - /* fallthrough */ - case GRPC_CHTTP2_DATA_FH_4: - s->stats.incoming.framing_bytes++; - p->frame_size |= ((uint32_t)*cur); - p->state = GRPC_CHTTP2_DATA_FRAME; - ++cur; - message_flags = 0; - if (p->is_frame_compressed) { - message_flags |= GRPC_WRITE_INTERNAL_COMPRESS; - } - p->parsing_frame = incoming_byte_stream = - grpc_chttp2_incoming_byte_stream_create(exec_ctx, t, s, p->frame_size, - message_flags); - /* fallthrough */ - case GRPC_CHTTP2_DATA_FRAME: - if (cur == end) { - return GRPC_ERROR_NONE; - } - uint32_t remaining = (uint32_t)(end - cur); - if (remaining == p->frame_size) { - s->stats.incoming.data_bytes += p->frame_size; - grpc_chttp2_incoming_byte_stream_push( - exec_ctx, p->parsing_frame, - grpc_slice_sub(slice, (size_t)(cur - beg), (size_t)(end - beg))); - grpc_chttp2_incoming_byte_stream_finished(exec_ctx, p->parsing_frame, - GRPC_ERROR_NONE); - p->parsing_frame = NULL; - p->state = GRPC_CHTTP2_DATA_FH_0; - return GRPC_ERROR_NONE; - } else if (remaining > p->frame_size) { - s->stats.incoming.data_bytes += p->frame_size; - grpc_chttp2_incoming_byte_stream_push( - exec_ctx, p->parsing_frame, - grpc_slice_sub(slice, (size_t)(cur - beg), - (size_t)(cur + p->frame_size - beg))); - grpc_chttp2_incoming_byte_stream_finished(exec_ctx, p->parsing_frame, - GRPC_ERROR_NONE); - p->parsing_frame = NULL; - cur += p->frame_size; - goto fh_0; /* loop */ - } else { - GPR_ASSERT(remaining <= p->frame_size); - grpc_chttp2_incoming_byte_stream_push( - exec_ctx, p->parsing_frame, - grpc_slice_sub(slice, (size_t)(cur - beg), (size_t)(end - beg))); - p->frame_size -= remaining; - s->stats.incoming.data_bytes += remaining; + grpc_slice slice = grpc_slice_buffer_take_first(slices); + + beg = GRPC_SLICE_START_PTR(slice); + end = GRPC_SLICE_END_PTR(slice); + cur = beg; + uint32_t message_flags; + char *msg; + + if (cur == end) { + grpc_slice_unref_internal(exec_ctx, slice); + continue; + } + + switch (p->state) { + case GRPC_CHTTP2_DATA_ERROR: + p->state = GRPC_CHTTP2_DATA_ERROR; + grpc_slice_unref_internal(exec_ctx, slice); + return GRPC_ERROR_REF(p->error); + case GRPC_CHTTP2_DATA_FH_0: + s->stats.incoming.framing_bytes++; + p->frame_type = *cur; + switch (p->frame_type) { + case 0: + p->is_frame_compressed = false; /* GPR_FALSE */ + break; + case 1: + p->is_frame_compressed = true; /* GPR_TRUE */ + break; + default: + gpr_asprintf(&msg, "Bad GRPC frame type 0x%02x", p->frame_type); + p->error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg); + p->error = grpc_error_set_int(p->error, GRPC_ERROR_INT_STREAM_ID, + (intptr_t)s->id); + gpr_free(msg); + msg = grpc_dump_slice(slice, GPR_DUMP_HEX | GPR_DUMP_ASCII); + p->error = grpc_error_set_str(p->error, GRPC_ERROR_STR_RAW_BYTES, + grpc_slice_from_copied_string(msg)); + gpr_free(msg); + p->error = + grpc_error_set_int(p->error, GRPC_ERROR_INT_OFFSET, cur - beg); + p->state = GRPC_CHTTP2_DATA_ERROR; + grpc_slice_unref_internal(exec_ctx, slice); + return GRPC_ERROR_REF(p->error); + } + if (++cur == end) { + p->state = GRPC_CHTTP2_DATA_FH_1; + grpc_slice_unref_internal(exec_ctx, slice); + continue; + } + /* fallthrough */ + case GRPC_CHTTP2_DATA_FH_1: + s->stats.incoming.framing_bytes++; + p->frame_size = ((uint32_t)*cur) << 24; + if (++cur == end) { + p->state = GRPC_CHTTP2_DATA_FH_2; + grpc_slice_unref_internal(exec_ctx, slice); + continue; + } + /* fallthrough */ + case GRPC_CHTTP2_DATA_FH_2: + s->stats.incoming.framing_bytes++; + p->frame_size |= ((uint32_t)*cur) << 16; + if (++cur == end) { + p->state = GRPC_CHTTP2_DATA_FH_3; + grpc_slice_unref_internal(exec_ctx, slice); + continue; + } + /* fallthrough */ + case GRPC_CHTTP2_DATA_FH_3: + s->stats.incoming.framing_bytes++; + p->frame_size |= ((uint32_t)*cur) << 8; + if (++cur == end) { + p->state = GRPC_CHTTP2_DATA_FH_4; + grpc_slice_unref_internal(exec_ctx, slice); + continue; + } + /* fallthrough */ + case GRPC_CHTTP2_DATA_FH_4: + s->stats.incoming.framing_bytes++; + GPR_ASSERT(stream_out != NULL); + GPR_ASSERT(p->parsing_frame == NULL); + p->frame_size |= ((uint32_t)*cur); + p->state = GRPC_CHTTP2_DATA_FRAME; + ++cur; + message_flags = 0; + if (p->is_frame_compressed) { + message_flags |= GRPC_WRITE_INTERNAL_COMPRESS; + } + p->parsing_frame = grpc_chttp2_incoming_byte_stream_create( + exec_ctx, t, s, p->frame_size, message_flags); + *stream_out = &p->parsing_frame->base; + if (p->parsing_frame->remaining_bytes == 0) { + GRPC_ERROR_UNREF(grpc_chttp2_incoming_byte_stream_finished( + exec_ctx, p->parsing_frame, GRPC_ERROR_NONE, true)); + p->parsing_frame = NULL; + p->state = GRPC_CHTTP2_DATA_FH_0; + } + s->pending_byte_stream = true; + + if (cur != end) { + grpc_slice_buffer_undo_take_first( + &s->unprocessed_incoming_frames_buffer, + grpc_slice_sub(slice, (size_t)(cur - beg), (size_t)(end - beg))); + } + grpc_slice_unref_internal(exec_ctx, slice); return GRPC_ERROR_NONE; + case GRPC_CHTTP2_DATA_FRAME: { + GPR_ASSERT(p->parsing_frame != NULL); + GPR_ASSERT(slice_out != NULL); + if (cur == end) { + grpc_slice_unref_internal(exec_ctx, slice); + continue; + } + uint32_t remaining = (uint32_t)(end - cur); + if (remaining == p->frame_size) { + s->stats.incoming.data_bytes += remaining; + if (GRPC_ERROR_NONE != (error = grpc_chttp2_incoming_byte_stream_push( + exec_ctx, p->parsing_frame, + grpc_slice_sub(slice, (size_t)(cur - beg), + (size_t)(end - beg)), + slice_out))) { + grpc_slice_unref_internal(exec_ctx, slice); + return error; + } + if (GRPC_ERROR_NONE != + (error = grpc_chttp2_incoming_byte_stream_finished( + exec_ctx, p->parsing_frame, GRPC_ERROR_NONE, true))) { + grpc_slice_unref_internal(exec_ctx, slice); + return error; + } + p->parsing_frame = NULL; + p->state = GRPC_CHTTP2_DATA_FH_0; + grpc_slice_unref_internal(exec_ctx, slice); + return GRPC_ERROR_NONE; + } else if (remaining < p->frame_size) { + s->stats.incoming.data_bytes += remaining; + if (GRPC_ERROR_NONE != (error = grpc_chttp2_incoming_byte_stream_push( + exec_ctx, p->parsing_frame, + grpc_slice_sub(slice, (size_t)(cur - beg), + (size_t)(end - beg)), + slice_out))) { + return error; + } + p->frame_size -= remaining; + grpc_slice_unref_internal(exec_ctx, slice); + return GRPC_ERROR_NONE; + } else { + GPR_ASSERT(remaining > p->frame_size); + s->stats.incoming.data_bytes += p->frame_size; + if (GRPC_ERROR_NONE != + (grpc_chttp2_incoming_byte_stream_push( + exec_ctx, p->parsing_frame, + grpc_slice_sub(slice, (size_t)(cur - beg), + (size_t)(cur + p->frame_size - beg)), + slice_out))) { + grpc_slice_unref_internal(exec_ctx, slice); + return error; + } + if (GRPC_ERROR_NONE != + (error = grpc_chttp2_incoming_byte_stream_finished( + exec_ctx, p->parsing_frame, GRPC_ERROR_NONE, true))) { + grpc_slice_unref_internal(exec_ctx, slice); + return error; + } + p->parsing_frame = NULL; + p->state = GRPC_CHTTP2_DATA_FH_0; + cur += p->frame_size; + grpc_slice_buffer_undo_take_first( + &s->unprocessed_incoming_frames_buffer, + grpc_slice_sub(slice, (size_t)(cur - beg), (size_t)(end - beg))); + grpc_slice_unref_internal(exec_ctx, slice); + return GRPC_ERROR_NONE; + } } + } } - GPR_UNREACHABLE_CODE(return GRPC_ERROR_CREATE("Should never reach here")); + return GRPC_ERROR_NONE; } grpc_error *grpc_chttp2_data_parser_parse(grpc_exec_ctx *exec_ctx, void *parser, grpc_chttp2_transport *t, grpc_chttp2_stream *s, grpc_slice slice, int is_last) { - grpc_chttp2_data_parser *p = parser; - grpc_error *error = parse_inner(exec_ctx, p, t, s, slice); + if (!s->pending_byte_stream) { + grpc_slice_ref_internal(slice); + grpc_slice_buffer_add(&s->frame_storage, slice); + grpc_chttp2_maybe_complete_recv_message(exec_ctx, t, s); + } else if (s->on_next) { + GPR_ASSERT(s->frame_storage.length == 0); + grpc_slice_ref_internal(slice); + grpc_slice_buffer_add(&s->unprocessed_incoming_frames_buffer, slice); + GRPC_CLOSURE_SCHED(exec_ctx, s->on_next, GRPC_ERROR_NONE); + s->on_next = NULL; + s->unprocessed_incoming_frames_decompressed = false; + } else { + grpc_slice_ref_internal(slice); + grpc_slice_buffer_add(&s->frame_storage, slice); + } - if (is_last && p->is_last_frame) { + if (is_last && s->received_last_frame) { grpc_chttp2_mark_stream_closed(exec_ctx, t, s, true, false, GRPC_ERROR_NONE); } - return error; + return GRPC_ERROR_NONE; } diff --git a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/frame_data.h b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/frame_data.h index 264ad1460..3f1c78784 100644 --- a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/frame_data.h +++ b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/frame_data.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -56,28 +41,16 @@ typedef enum { typedef struct grpc_chttp2_incoming_byte_stream grpc_chttp2_incoming_byte_stream; -typedef struct grpc_chttp2_incoming_frame_queue { - grpc_chttp2_incoming_byte_stream *head; - grpc_chttp2_incoming_byte_stream *tail; -} grpc_chttp2_incoming_frame_queue; - typedef struct { grpc_chttp2_stream_state state; - uint8_t is_last_frame; uint8_t frame_type; uint32_t frame_size; grpc_error *error; - int is_frame_compressed; + bool is_frame_compressed; grpc_chttp2_incoming_byte_stream *parsing_frame; } grpc_chttp2_data_parser; -void grpc_chttp2_incoming_frame_queue_merge( - grpc_chttp2_incoming_frame_queue *head_dst, - grpc_chttp2_incoming_frame_queue *tail_src); -grpc_byte_stream *grpc_chttp2_incoming_frame_queue_pop( - grpc_chttp2_incoming_frame_queue *q); - /* initialize per-stream state for data frame parsing */ grpc_error *grpc_chttp2_data_parser_init(grpc_chttp2_data_parser *parser); @@ -87,7 +60,8 @@ void grpc_chttp2_data_parser_destroy(grpc_exec_ctx *exec_ctx, /* start processing a new data frame */ grpc_error *grpc_chttp2_data_parser_begin_frame(grpc_chttp2_data_parser *parser, uint8_t flags, - uint32_t stream_id); + uint32_t stream_id, + grpc_chttp2_stream *s); /* handle a slice of a data frame - is_last indicates the last slice of a frame */ @@ -101,4 +75,9 @@ void grpc_chttp2_encode_data(uint32_t id, grpc_slice_buffer *inbuf, grpc_transport_one_way_stats *stats, grpc_slice_buffer *outbuf); +grpc_error *grpc_deframe_unprocessed_incoming_frames( + grpc_exec_ctx *exec_ctx, grpc_chttp2_data_parser *p, grpc_chttp2_stream *s, + grpc_slice_buffer *slices, grpc_slice *slice_out, + grpc_byte_stream **stream_out); + #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_DATA_H */ diff --git a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/frame_goaway.c b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/frame_goaway.c index d99d486c1..4bce84f21 100644 --- a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/frame_goaway.c +++ b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/frame_goaway.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -54,7 +39,7 @@ grpc_error *grpc_chttp2_goaway_parser_begin_frame(grpc_chttp2_goaway_parser *p, if (length < 8) { char *msg; gpr_asprintf(&msg, "goaway frame too short (%d bytes)", length); - grpc_error *err = GRPC_ERROR_CREATE(msg); + grpc_error *err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg); gpr_free(msg); return err; } @@ -156,13 +141,14 @@ grpc_error *grpc_chttp2_goaway_parser_parse(grpc_exec_ctx *exec_ctx, } return GRPC_ERROR_NONE; } - GPR_UNREACHABLE_CODE(return GRPC_ERROR_CREATE("Should never reach here")); + GPR_UNREACHABLE_CODE( + return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Should never reach here")); } void grpc_chttp2_goaway_append(uint32_t last_stream_id, uint32_t error_code, grpc_slice debug_data, grpc_slice_buffer *slice_buffer) { - grpc_slice header = grpc_slice_malloc(9 + 4 + 4); + grpc_slice header = GRPC_SLICE_MALLOC(9 + 4 + 4); uint8_t *p = GRPC_SLICE_START_PTR(header); uint32_t frame_length; GPR_ASSERT(GRPC_SLICE_LENGTH(debug_data) < UINT32_MAX - 4 - 4); diff --git a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/frame_goaway.h b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/frame_goaway.h index 21fe81948..abc48f30c 100644 --- a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/frame_goaway.h +++ b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/frame_goaway.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/frame_ping.c b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/frame_ping.c index 7de5f6362..3d7c6fbfa 100644 --- a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/frame_ping.c +++ b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/frame_ping.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -40,8 +25,10 @@ #include #include -grpc_slice grpc_chttp2_ping_create(uint8_t ack, uint8_t *opaque_8bytes) { - grpc_slice slice = grpc_slice_malloc(9 + 8); +static bool g_disable_ping_ack = false; + +grpc_slice grpc_chttp2_ping_create(uint8_t ack, uint64_t opaque_8bytes) { + grpc_slice slice = GRPC_SLICE_MALLOC(9 + 8); uint8_t *p = GRPC_SLICE_START_PTR(slice); *p++ = 0; @@ -53,7 +40,14 @@ grpc_slice grpc_chttp2_ping_create(uint8_t ack, uint8_t *opaque_8bytes) { *p++ = 0; *p++ = 0; *p++ = 0; - memcpy(p, opaque_8bytes, 8); + *p++ = (uint8_t)(opaque_8bytes >> 56); + *p++ = (uint8_t)(opaque_8bytes >> 48); + *p++ = (uint8_t)(opaque_8bytes >> 40); + *p++ = (uint8_t)(opaque_8bytes >> 32); + *p++ = (uint8_t)(opaque_8bytes >> 24); + *p++ = (uint8_t)(opaque_8bytes >> 16); + *p++ = (uint8_t)(opaque_8bytes >> 8); + *p++ = (uint8_t)(opaque_8bytes); return slice; } @@ -64,12 +58,13 @@ grpc_error *grpc_chttp2_ping_parser_begin_frame(grpc_chttp2_ping_parser *parser, if (flags & 0xfe || length != 8) { char *msg; gpr_asprintf(&msg, "invalid ping: length=%d, flags=%02x", length, flags); - grpc_error *error = GRPC_ERROR_CREATE(msg); + grpc_error *error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg); gpr_free(msg); return error; } parser->byte = 0; parser->is_ack = flags; + parser->opaque_8bytes = 0; return GRPC_ERROR_NONE; } @@ -83,7 +78,7 @@ grpc_error *grpc_chttp2_ping_parser_parse(grpc_exec_ctx *exec_ctx, void *parser, grpc_chttp2_ping_parser *p = parser; while (p->byte != 8 && cur != end) { - p->opaque_8bytes[p->byte] = *cur; + p->opaque_8bytes |= (((uint64_t)*cur) << (56 - 8 * p->byte)); cur++; p->byte++; } @@ -93,11 +88,43 @@ grpc_error *grpc_chttp2_ping_parser_parse(grpc_exec_ctx *exec_ctx, void *parser, if (p->is_ack) { grpc_chttp2_ack_ping(exec_ctx, t, p->opaque_8bytes); } else { - grpc_slice_buffer_add(&t->qbuf, - grpc_chttp2_ping_create(1, p->opaque_8bytes)); - grpc_chttp2_initiate_write(exec_ctx, t, false, "ping response"); + if (!t->is_client) { + gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC); + gpr_timespec next_allowed_ping = + gpr_time_add(t->ping_recv_state.last_ping_recv_time, + t->ping_policy.min_ping_interval_without_data); + + if (t->keepalive_permit_without_calls == 0 && + grpc_chttp2_stream_map_size(&t->stream_map) == 0) { + /* According to RFC1122, the interval of TCP Keep-Alive is default to + no less than two hours. When there is no outstanding streams, we + restrict the number of PINGS equivalent to TCP Keep-Alive. */ + next_allowed_ping = + gpr_time_add(t->ping_recv_state.last_ping_recv_time, + gpr_time_from_seconds(7200, GPR_TIMESPAN)); + } + + if (gpr_time_cmp(next_allowed_ping, now) > 0) { + grpc_chttp2_add_ping_strike(exec_ctx, t); + } + + t->ping_recv_state.last_ping_recv_time = now; + } + if (!g_disable_ping_ack) { + if (t->ping_ack_count == t->ping_ack_capacity) { + t->ping_ack_capacity = GPR_MAX(t->ping_ack_capacity * 3 / 2, 3); + t->ping_acks = gpr_realloc( + t->ping_acks, t->ping_ack_capacity * sizeof(*t->ping_acks)); + } + t->ping_acks[t->ping_ack_count++] = p->opaque_8bytes; + grpc_chttp2_initiate_write(exec_ctx, t, "ping response"); + } } } return GRPC_ERROR_NONE; } + +void grpc_set_disable_ping_ack(bool disable_ping_ack) { + g_disable_ping_ack = disable_ping_ack; +} diff --git a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/frame_ping.h b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/frame_ping.h index b9889e2d1..5969ace9b 100644 --- a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/frame_ping.h +++ b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/frame_ping.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -41,10 +26,10 @@ typedef struct { uint8_t byte; uint8_t is_ack; - uint8_t opaque_8bytes[8]; + uint64_t opaque_8bytes; } grpc_chttp2_ping_parser; -grpc_slice grpc_chttp2_ping_create(uint8_t ack, uint8_t *opaque_8bytes); +grpc_slice grpc_chttp2_ping_create(uint8_t ack, uint64_t opaque_8bytes); grpc_error *grpc_chttp2_ping_parser_begin_frame(grpc_chttp2_ping_parser *parser, uint32_t length, uint8_t flags); @@ -53,4 +38,7 @@ grpc_error *grpc_chttp2_ping_parser_parse(grpc_exec_ctx *exec_ctx, void *parser, grpc_chttp2_stream *s, grpc_slice slice, int is_last); +/* Test-only function for disabling ping ack */ +void grpc_set_disable_ping_ack(bool disable_ping_ack); + #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_PING_H */ diff --git a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/frame_rst_stream.c b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/frame_rst_stream.c index b4c5ed769..689dc8935 100644 --- a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/frame_rst_stream.c +++ b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/frame_rst_stream.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -39,13 +24,12 @@ #include #include "src/core/ext/transport/chttp2/transport/frame.h" -#include "src/core/ext/transport/chttp2/transport/http2_errors.h" -#include "src/core/ext/transport/chttp2/transport/status_conversion.h" +#include "src/core/lib/transport/http2_errors.h" grpc_slice grpc_chttp2_rst_stream_create(uint32_t id, uint32_t code, grpc_transport_one_way_stats *stats) { static const size_t frame_size = 13; - grpc_slice slice = grpc_slice_malloc(frame_size); + grpc_slice slice = GRPC_SLICE_MALLOC(frame_size); stats->framing_bytes += frame_size; uint8_t *p = GRPC_SLICE_START_PTR(slice); @@ -77,7 +61,7 @@ grpc_error *grpc_chttp2_rst_stream_parser_begin_frame( char *msg; gpr_asprintf(&msg, "invalid rst_stream: length=%d, flags=%02x", length, flags); - grpc_error *err = GRPC_ERROR_CREATE(msg); + grpc_error *err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg); gpr_free(msg); return err; } @@ -109,17 +93,15 @@ grpc_error *grpc_chttp2_rst_stream_parser_parse(grpc_exec_ctx *exec_ctx, (((uint32_t)p->reason_bytes[2]) << 8) | (((uint32_t)p->reason_bytes[3])); grpc_error *error = GRPC_ERROR_NONE; - if (reason != GRPC_CHTTP2_NO_ERROR) { - error = grpc_error_set_int(GRPC_ERROR_CREATE("RST_STREAM"), - GRPC_ERROR_INT_HTTP2_ERROR, (intptr_t)reason); - grpc_status_code status_code = grpc_chttp2_http2_error_to_grpc_status( - (grpc_chttp2_error_code)reason, s->deadline); - char *status_details; - gpr_asprintf(&status_details, "Received RST_STREAM with error code %d", - reason); - grpc_slice slice_details = grpc_slice_from_copied_string(status_details); - gpr_free(status_details); - grpc_chttp2_fake_status(exec_ctx, t, s, status_code, &slice_details); + if (reason != GRPC_HTTP2_NO_ERROR || s->metadata_buffer[1].size == 0) { + char *message; + gpr_asprintf(&message, "Received RST_STREAM with error code %d", reason); + error = grpc_error_set_int( + grpc_error_set_str(GRPC_ERROR_CREATE_FROM_STATIC_STRING("RST_STREAM"), + GRPC_ERROR_STR_GRPC_MESSAGE, + grpc_slice_from_copied_string(message)), + GRPC_ERROR_INT_HTTP2_ERROR, (intptr_t)reason); + gpr_free(message); } grpc_chttp2_mark_stream_closed(exec_ctx, t, s, true, true, error); } diff --git a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/frame_rst_stream.h b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/frame_rst_stream.h index 779507a61..d088221b5 100644 --- a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/frame_rst_stream.h +++ b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/frame_rst_stream.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/frame_settings.c b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/frame_settings.c index 98facae87..057d3d9ed 100644 --- a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/frame_settings.c +++ b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/frame_settings.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -43,31 +28,8 @@ #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h" #include "src/core/ext/transport/chttp2/transport/frame.h" -#include "src/core/ext/transport/chttp2/transport/http2_errors.h" #include "src/core/lib/debug/trace.h" - -#define MAX_MAX_HEADER_LIST_SIZE (1024 * 1024 * 1024) - -/* HTTP/2 mandated initial connection settings */ -const grpc_chttp2_setting_parameters - grpc_chttp2_settings_parameters[GRPC_CHTTP2_NUM_SETTINGS] = { - {NULL, 0, 0, 0, GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE, - GRPC_CHTTP2_PROTOCOL_ERROR}, - {"HEADER_TABLE_SIZE", 4096, 0, 0xffffffff, - GRPC_CHTTP2_CLAMP_INVALID_VALUE, GRPC_CHTTP2_PROTOCOL_ERROR}, - {"ENABLE_PUSH", 1, 0, 1, GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE, - GRPC_CHTTP2_PROTOCOL_ERROR}, - {"MAX_CONCURRENT_STREAMS", 0xffffffffu, 0, 0xffffffffu, - GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE, GRPC_CHTTP2_PROTOCOL_ERROR}, - {"INITIAL_WINDOW_SIZE", 65535, 0, 0x7fffffffu, - GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE, - GRPC_CHTTP2_FLOW_CONTROL_ERROR}, - {"MAX_FRAME_SIZE", 16384, 16384, 16777215, - GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE, GRPC_CHTTP2_PROTOCOL_ERROR}, - {"MAX_HEADER_LIST_SIZE", MAX_MAX_HEADER_LIST_SIZE, 0, - MAX_MAX_HEADER_LIST_SIZE, GRPC_CHTTP2_CLAMP_INVALID_VALUE, - GRPC_CHTTP2_PROTOCOL_ERROR}, -}; +#include "src/core/lib/transport/http2_errors.h" static uint8_t *fill_header(uint8_t *out, uint32_t length, uint8_t flags) { *out++ = (uint8_t)(length >> 16); @@ -93,14 +55,13 @@ grpc_slice grpc_chttp2_settings_create(uint32_t *old, const uint32_t *new, n += (new[i] != old[i] || (force_mask & (1u << i)) != 0); } - output = grpc_slice_malloc(9 + 6 * n); + output = GRPC_SLICE_MALLOC(9 + 6 * n); p = fill_header(GRPC_SLICE_START_PTR(output), 6 * n, 0); for (i = 0; i < count; i++) { if (new[i] != old[i] || (force_mask & (1u << i)) != 0) { - GPR_ASSERT(i); - *p++ = (uint8_t)(i >> 8); - *p++ = (uint8_t)(i); + *p++ = (uint8_t)(grpc_setting_id_to_wire_id[i] >> 8); + *p++ = (uint8_t)(grpc_setting_id_to_wire_id[i]); *p++ = (uint8_t)(new[i] >> 24); *p++ = (uint8_t)(new[i] >> 16); *p++ = (uint8_t)(new[i] >> 8); @@ -115,7 +76,7 @@ grpc_slice grpc_chttp2_settings_create(uint32_t *old, const uint32_t *new, } grpc_slice grpc_chttp2_settings_ack_create(void) { - grpc_slice output = grpc_slice_malloc(9); + grpc_slice output = GRPC_SLICE_MALLOC(9); fill_header(GRPC_SLICE_START_PTR(output), 0, GRPC_CHTTP2_FLAG_ACK); return output; } @@ -131,13 +92,16 @@ grpc_error *grpc_chttp2_settings_parser_begin_frame( if (flags == GRPC_CHTTP2_FLAG_ACK) { parser->is_ack = 1; if (length != 0) { - return GRPC_ERROR_CREATE("non-empty settings ack frame received"); + return GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "non-empty settings ack frame received"); } return GRPC_ERROR_NONE; } else if (flags != 0) { - return GRPC_ERROR_CREATE("invalid flags on settings frame"); + return GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "invalid flags on settings frame"); } else if (length % 6 != 0) { - return GRPC_ERROR_CREATE("settings frames must be a multiple of six bytes"); + return GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "settings frames must be a multiple of six bytes"); } else { return GRPC_ERROR_NONE; } @@ -151,6 +115,7 @@ grpc_error *grpc_chttp2_settings_parser_parse(grpc_exec_ctx *exec_ctx, void *p, const uint8_t *cur = GRPC_SLICE_START_PTR(slice); const uint8_t *end = GRPC_SLICE_END_PTR(slice); char *msg; + grpc_chttp2_setting_id id; if (parser->is_ack) { return GRPC_ERROR_NONE; @@ -213,9 +178,9 @@ grpc_error *grpc_chttp2_settings_parser_parse(grpc_exec_ctx *exec_ctx, void *p, parser->value |= *cur; cur++; - if (parser->id > 0 && parser->id < GRPC_CHTTP2_NUM_SETTINGS) { + if (grpc_wire_id_to_setting_id(parser->id, &id)) { const grpc_chttp2_setting_parameters *sp = - &grpc_chttp2_settings_parameters[parser->id]; + &grpc_chttp2_settings_parameters[id]; if (parser->value < sp->min_value || parser->value > sp->max_value) { switch (sp->invalid_value_behavior) { case GRPC_CHTTP2_CLAMP_INVALID_VALUE: @@ -229,26 +194,29 @@ grpc_error *grpc_chttp2_settings_parser_parse(grpc_exec_ctx *exec_ctx, void *p, &t->qbuf); gpr_asprintf(&msg, "invalid value %u passed for %s", parser->value, sp->name); - grpc_error *err = GRPC_ERROR_CREATE(msg); + grpc_error *err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg); gpr_free(msg); return err; } } - if (parser->id == GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE && - parser->incoming_settings[parser->id] != parser->value) { - t->initial_window_update = - (int64_t)parser->value - parser->incoming_settings[parser->id]; - if (grpc_http_trace) { - gpr_log(GPR_DEBUG, "adding %d for initial_window change", - (int)t->initial_window_update); + if (id == GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE && + parser->incoming_settings[id] != parser->value) { + t->flow_control.initial_window_update += + (int64_t)parser->value - parser->incoming_settings[id]; + if (GRPC_TRACER_ON(grpc_http_trace) || + GRPC_TRACER_ON(grpc_flowctl_trace)) { + gpr_log(GPR_DEBUG, "%p[%s] adding %d for initial_window change", + t, t->is_client ? "cli" : "svr", + (int)t->flow_control.initial_window_update); } } - parser->incoming_settings[parser->id] = parser->value; - if (grpc_http_trace) { - gpr_log(GPR_DEBUG, "CHTTP2:%s: got setting %d = %d", - t->is_client ? "CLI" : "SVR", parser->id, parser->value); + parser->incoming_settings[id] = parser->value; + if (GRPC_TRACER_ON(grpc_http_trace)) { + gpr_log(GPR_DEBUG, "CHTTP2:%s:%s: got setting %s = %d", + t->is_client ? "CLI" : "SVR", t->peer_string, sp->name, + parser->value); } - } else if (grpc_http_trace) { + } else if (GRPC_TRACER_ON(grpc_http_trace)) { gpr_log(GPR_ERROR, "CHTTP2: Ignoring unknown setting %d (value %d)", parser->id, parser->value); } diff --git a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/frame_settings.h b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/frame_settings.h index a29dc8210..47479d675 100644 --- a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/frame_settings.h +++ b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/frame_settings.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -37,6 +22,7 @@ #include #include #include "src/core/ext/transport/chttp2/transport/frame.h" +#include "src/core/ext/transport/chttp2/transport/http2_settings.h" #include "src/core/lib/iomgr/exec_ctx.h" typedef enum { @@ -48,17 +34,6 @@ typedef enum { GRPC_CHTTP2_SPS_VAL3 } grpc_chttp2_settings_parse_state; -/* The things HTTP/2 defines as connection level settings */ -typedef enum { - GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE = 1, - GRPC_CHTTP2_SETTINGS_ENABLE_PUSH = 2, - GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS = 3, - GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE = 4, - GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE = 5, - GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE = 6, - GRPC_CHTTP2_NUM_SETTINGS -} grpc_chttp2_setting_id; - typedef struct { grpc_chttp2_settings_parse_state state; uint32_t *target_settings; @@ -68,26 +43,8 @@ typedef struct { uint32_t incoming_settings[GRPC_CHTTP2_NUM_SETTINGS]; } grpc_chttp2_settings_parser; -typedef enum { - GRPC_CHTTP2_CLAMP_INVALID_VALUE, - GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE -} grpc_chttp2_invalid_value_behavior; - -typedef struct { - const char *name; - uint32_t default_value; - uint32_t min_value; - uint32_t max_value; - grpc_chttp2_invalid_value_behavior invalid_value_behavior; - uint32_t error_value; -} grpc_chttp2_setting_parameters; - -/* HTTP/2 mandated connection setting parameters */ -extern const grpc_chttp2_setting_parameters - grpc_chttp2_settings_parameters[GRPC_CHTTP2_NUM_SETTINGS]; - /* Create a settings frame by diffing old & new, and updating old to be new */ -grpc_slice grpc_chttp2_settings_create(uint32_t *old, const uint32_t *new, +grpc_slice grpc_chttp2_settings_create(uint32_t *old, const uint32_t *newval, uint32_t force_mask, size_t count); /* Create an ack settings frame */ grpc_slice grpc_chttp2_settings_ack_create(void); diff --git a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/frame_window_update.c b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/frame_window_update.c index 31a31c287..65f3b01d7 100644 --- a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/frame_window_update.c +++ b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/frame_window_update.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -41,7 +26,7 @@ grpc_slice grpc_chttp2_window_update_create( uint32_t id, uint32_t window_update, grpc_transport_one_way_stats *stats) { static const size_t frame_size = 13; - grpc_slice slice = grpc_slice_malloc(frame_size); + grpc_slice slice = GRPC_SLICE_MALLOC(frame_size); stats->header_bytes += frame_size; uint8_t *p = GRPC_SLICE_START_PTR(slice); @@ -70,7 +55,7 @@ grpc_error *grpc_chttp2_window_update_parser_begin_frame( char *msg; gpr_asprintf(&msg, "invalid window update: length=%d, flags=%02x", length, flags); - grpc_error *err = GRPC_ERROR_CREATE(msg); + grpc_error *err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg); gpr_free(msg); return err; } @@ -102,7 +87,7 @@ grpc_error *grpc_chttp2_window_update_parser_parse( if (received_update == 0 || (received_update & 0x80000000u)) { char *msg; gpr_asprintf(&msg, "invalid window update bytes: %d", p->amount); - grpc_error *err = GRPC_ERROR_CREATE(msg); + grpc_error *err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg); gpr_free(msg); return err; } @@ -110,23 +95,21 @@ grpc_error *grpc_chttp2_window_update_parser_parse( if (t->incoming_stream_id != 0) { if (s != NULL) { - bool was_zero = s->outgoing_window <= 0; - GRPC_CHTTP2_FLOW_CREDIT_STREAM("parse", t, s, outgoing_window, - received_update); - bool is_zero = s->outgoing_window <= 0; - if (was_zero && !is_zero) { - grpc_chttp2_become_writable(exec_ctx, t, s, false, - "stream.read_flow_control"); + grpc_chttp2_flowctl_recv_stream_update( + &t->flow_control, &s->flow_control, received_update); + if (grpc_chttp2_list_remove_stalled_by_stream(t, s)) { + grpc_chttp2_become_writable( + exec_ctx, t, s, GRPC_CHTTP2_STREAM_WRITE_INITIATE_UNCOVERED, + "stream.read_flow_control"); } } } else { - bool was_zero = t->outgoing_window <= 0; - GRPC_CHTTP2_FLOW_CREDIT_TRANSPORT("parse", t, outgoing_window, - received_update); - bool is_zero = t->outgoing_window <= 0; + bool was_zero = t->flow_control.remote_window <= 0; + grpc_chttp2_flowctl_recv_transport_update(&t->flow_control, + received_update); + bool is_zero = t->flow_control.remote_window <= 0; if (was_zero && !is_zero) { - grpc_chttp2_initiate_write(exec_ctx, t, false, - "new_global_flow_control"); + grpc_chttp2_initiate_write(exec_ctx, t, "new_global_flow_control"); } } } diff --git a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/frame_window_update.h b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/frame_window_update.h index f75dfb3d8..698da4e35 100644 --- a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/frame_window_update.h +++ b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/frame_window_update.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/hpack_encoder.c b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/hpack_encoder.c index eb68fe313..a0e748e7b 100644 --- a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/hpack_encoder.c +++ b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/hpack_encoder.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -48,6 +33,8 @@ #include "src/core/ext/transport/chttp2/transport/bin_encoder.h" #include "src/core/ext/transport/chttp2/transport/hpack_table.h" #include "src/core/ext/transport/chttp2/transport/varint.h" +#include "src/core/lib/slice/slice_internal.h" +#include "src/core/lib/slice/slice_string_helpers.h" #include "src/core/lib/transport/metadata.h" #include "src/core/lib/transport/static_metadata.h" #include "src/core/lib/transport/timeout_encoding.h" @@ -63,7 +50,11 @@ /* don't consider adding anything bigger than this to the hpack table */ #define MAX_DECODER_SPACE_USAGE 512 -extern int grpc_http_trace; +static grpc_slice_refcount terminal_slice_refcount = {NULL, NULL}; +static const grpc_slice terminal_slice = {&terminal_slice_refcount, + .data.refcounted = {0, 0}}; + +extern grpc_tracer_flag grpc_http_trace; typedef struct { int is_first_frame; @@ -80,6 +71,7 @@ typedef struct { grpc_transport_one_way_stats *stats; /* maximum size of a frame */ size_t max_frame_size; + bool use_true_binary_metadata; } framer_state; /* fills p (which is expected to be 9 bytes long) with a data frame header */ @@ -116,7 +108,7 @@ static void finish_frame(framer_state *st, int is_header_boundary, output before beginning */ static void begin_frame(framer_state *st) { st->header_idx = - grpc_slice_buffer_add_indexed(st->output, grpc_slice_malloc(9)); + grpc_slice_buffer_add_indexed(st->output, GRPC_SLICE_MALLOC(9)); st->output_length_at_start_of_frame = st->output->length; } @@ -167,6 +159,7 @@ static void add_header_data(framer_state *st, grpc_slice slice) { static uint8_t *add_tiny_header_data(framer_state *st, size_t len) { ensure_space(st, len); + st->stats->header_bytes += len; return grpc_slice_buffer_tiny_add(st->output, len); } @@ -183,9 +176,13 @@ static void evict_entry(grpc_chttp2_hpack_compressor *c) { } /* add an element to the decoder table */ -static void add_elem(grpc_chttp2_hpack_compressor *c, grpc_mdelem *elem) { - uint32_t key_hash = elem->key->hash; - uint32_t elem_hash = GRPC_MDSTR_KV_HASH(key_hash, elem->value->hash); +static void add_elem(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_compressor *c, + grpc_mdelem elem) { + GPR_ASSERT(GRPC_MDELEM_IS_INTERNED(elem)); + + uint32_t key_hash = grpc_slice_hash(GRPC_MDKEY(elem)); + uint32_t value_hash = grpc_slice_hash(GRPC_MDVALUE(elem)); + uint32_t elem_hash = GRPC_MDSTR_KV_HASH(key_hash, value_hash); uint32_t new_index = c->tail_remote_index + c->table_elems + 1; size_t elem_size = grpc_mdelem_get_size_in_hpack_table(elem); @@ -210,53 +207,64 @@ static void add_elem(grpc_chttp2_hpack_compressor *c, grpc_mdelem *elem) { c->table_elems++; /* Store this element into {entries,indices}_elem */ - if (c->entries_elems[HASH_FRAGMENT_2(elem_hash)] == elem) { + if (grpc_mdelem_eq(c->entries_elems[HASH_FRAGMENT_2(elem_hash)], elem)) { /* already there: update with new index */ c->indices_elems[HASH_FRAGMENT_2(elem_hash)] = new_index; - } else if (c->entries_elems[HASH_FRAGMENT_3(elem_hash)] == elem) { + } else if (grpc_mdelem_eq(c->entries_elems[HASH_FRAGMENT_3(elem_hash)], + elem)) { /* already there (cuckoo): update with new index */ c->indices_elems[HASH_FRAGMENT_3(elem_hash)] = new_index; - } else if (c->entries_elems[HASH_FRAGMENT_2(elem_hash)] == NULL) { + } else if (GRPC_MDISNULL(c->entries_elems[HASH_FRAGMENT_2(elem_hash)])) { /* not there, but a free element: add */ c->entries_elems[HASH_FRAGMENT_2(elem_hash)] = GRPC_MDELEM_REF(elem); c->indices_elems[HASH_FRAGMENT_2(elem_hash)] = new_index; - } else if (c->entries_elems[HASH_FRAGMENT_3(elem_hash)] == NULL) { + } else if (GRPC_MDISNULL(c->entries_elems[HASH_FRAGMENT_3(elem_hash)])) { /* not there (cuckoo), but a free element: add */ c->entries_elems[HASH_FRAGMENT_3(elem_hash)] = GRPC_MDELEM_REF(elem); c->indices_elems[HASH_FRAGMENT_3(elem_hash)] = new_index; } else if (c->indices_elems[HASH_FRAGMENT_2(elem_hash)] < c->indices_elems[HASH_FRAGMENT_3(elem_hash)]) { /* not there: replace oldest */ - GRPC_MDELEM_UNREF(c->entries_elems[HASH_FRAGMENT_2(elem_hash)]); + GRPC_MDELEM_UNREF(exec_ctx, c->entries_elems[HASH_FRAGMENT_2(elem_hash)]); c->entries_elems[HASH_FRAGMENT_2(elem_hash)] = GRPC_MDELEM_REF(elem); c->indices_elems[HASH_FRAGMENT_2(elem_hash)] = new_index; } else { /* not there: replace oldest */ - GRPC_MDELEM_UNREF(c->entries_elems[HASH_FRAGMENT_3(elem_hash)]); + GRPC_MDELEM_UNREF(exec_ctx, c->entries_elems[HASH_FRAGMENT_3(elem_hash)]); c->entries_elems[HASH_FRAGMENT_3(elem_hash)] = GRPC_MDELEM_REF(elem); c->indices_elems[HASH_FRAGMENT_3(elem_hash)] = new_index; } /* do exactly the same for the key (so we can find by that again too) */ - if (c->entries_keys[HASH_FRAGMENT_2(key_hash)] == elem->key) { + if (grpc_slice_eq(c->entries_keys[HASH_FRAGMENT_2(key_hash)], + GRPC_MDKEY(elem))) { c->indices_keys[HASH_FRAGMENT_2(key_hash)] = new_index; - } else if (c->entries_keys[HASH_FRAGMENT_3(key_hash)] == elem->key) { + } else if (grpc_slice_eq(c->entries_keys[HASH_FRAGMENT_3(key_hash)], + GRPC_MDKEY(elem))) { c->indices_keys[HASH_FRAGMENT_3(key_hash)] = new_index; - } else if (c->entries_keys[HASH_FRAGMENT_2(key_hash)] == NULL) { - c->entries_keys[HASH_FRAGMENT_2(key_hash)] = GRPC_MDSTR_REF(elem->key); + } else if (c->entries_keys[HASH_FRAGMENT_2(key_hash)].refcount == + &terminal_slice_refcount) { + c->entries_keys[HASH_FRAGMENT_2(key_hash)] = + grpc_slice_ref_internal(GRPC_MDKEY(elem)); c->indices_keys[HASH_FRAGMENT_2(key_hash)] = new_index; - } else if (c->entries_keys[HASH_FRAGMENT_3(key_hash)] == NULL) { - c->entries_keys[HASH_FRAGMENT_3(key_hash)] = GRPC_MDSTR_REF(elem->key); + } else if (c->entries_keys[HASH_FRAGMENT_3(key_hash)].refcount == + &terminal_slice_refcount) { + c->entries_keys[HASH_FRAGMENT_3(key_hash)] = + grpc_slice_ref_internal(GRPC_MDKEY(elem)); c->indices_keys[HASH_FRAGMENT_3(key_hash)] = new_index; } else if (c->indices_keys[HASH_FRAGMENT_2(key_hash)] < c->indices_keys[HASH_FRAGMENT_3(key_hash)]) { - GRPC_MDSTR_UNREF(c->entries_keys[HASH_FRAGMENT_2(key_hash)]); - c->entries_keys[HASH_FRAGMENT_2(key_hash)] = GRPC_MDSTR_REF(elem->key); + grpc_slice_unref_internal(exec_ctx, + c->entries_keys[HASH_FRAGMENT_2(key_hash)]); + c->entries_keys[HASH_FRAGMENT_2(key_hash)] = + grpc_slice_ref_internal(GRPC_MDKEY(elem)); c->indices_keys[HASH_FRAGMENT_2(key_hash)] = new_index; } else { - GRPC_MDSTR_UNREF(c->entries_keys[HASH_FRAGMENT_3(key_hash)]); - c->entries_keys[HASH_FRAGMENT_3(key_hash)] = GRPC_MDSTR_REF(elem->key); + grpc_slice_unref_internal(exec_ctx, + c->entries_keys[HASH_FRAGMENT_3(key_hash)]); + c->entries_keys[HASH_FRAGMENT_3(key_hash)] = + grpc_slice_ref_internal(GRPC_MDKEY(elem)); c->indices_keys[HASH_FRAGMENT_3(key_hash)] = new_index; } } @@ -268,88 +276,113 @@ static void emit_indexed(grpc_chttp2_hpack_compressor *c, uint32_t elem_index, len); } -static grpc_slice get_wire_value(grpc_mdelem *elem, uint8_t *huffman_prefix) { - if (grpc_is_binary_header( - (const char *)GRPC_SLICE_START_PTR(elem->key->slice), - GRPC_SLICE_LENGTH(elem->key->slice))) { - *huffman_prefix = 0x80; - return grpc_mdstr_as_base64_encoded_and_huffman_compressed(elem->value); +typedef struct { + grpc_slice data; + uint8_t huffman_prefix; + bool insert_null_before_wire_value; +} wire_value; + +static wire_value get_wire_value(grpc_mdelem elem, bool true_binary_enabled) { + if (grpc_is_binary_header(GRPC_MDKEY(elem))) { + if (true_binary_enabled) { + return (wire_value){ + .huffman_prefix = 0x00, + .insert_null_before_wire_value = true, + .data = grpc_slice_ref_internal(GRPC_MDVALUE(elem)), + }; + } else { + return (wire_value){ + .huffman_prefix = 0x80, + .insert_null_before_wire_value = false, + .data = grpc_chttp2_base64_encode_and_huffman_compress( + GRPC_MDVALUE(elem)), + }; + } + } else { + /* TODO(ctiller): opportunistically compress non-binary headers */ + return (wire_value){ + .huffman_prefix = 0x00, + .insert_null_before_wire_value = false, + .data = grpc_slice_ref_internal(GRPC_MDVALUE(elem)), + }; } - /* TODO(ctiller): opportunistically compress non-binary headers */ - *huffman_prefix = 0x00; - return elem->value->slice; +} + +static size_t wire_value_length(wire_value v) { + return GPR_SLICE_LENGTH(v.data) + v.insert_null_before_wire_value; +} + +static void add_wire_value(framer_state *st, wire_value v) { + if (v.insert_null_before_wire_value) *add_tiny_header_data(st, 1) = 0; + add_header_data(st, v.data); } static void emit_lithdr_incidx(grpc_chttp2_hpack_compressor *c, - uint32_t key_index, grpc_mdelem *elem, + uint32_t key_index, grpc_mdelem elem, framer_state *st) { uint32_t len_pfx = GRPC_CHTTP2_VARINT_LENGTH(key_index, 2); - uint8_t huffman_prefix; - grpc_slice value_slice = get_wire_value(elem, &huffman_prefix); - size_t len_val = GRPC_SLICE_LENGTH(value_slice); + wire_value value = get_wire_value(elem, st->use_true_binary_metadata); + size_t len_val = wire_value_length(value); uint32_t len_val_len; GPR_ASSERT(len_val <= UINT32_MAX); len_val_len = GRPC_CHTTP2_VARINT_LENGTH((uint32_t)len_val, 1); GRPC_CHTTP2_WRITE_VARINT(key_index, 2, 0x40, add_tiny_header_data(st, len_pfx), len_pfx); - GRPC_CHTTP2_WRITE_VARINT((uint32_t)len_val, 1, huffman_prefix, + GRPC_CHTTP2_WRITE_VARINT((uint32_t)len_val, 1, value.huffman_prefix, add_tiny_header_data(st, len_val_len), len_val_len); - add_header_data(st, grpc_slice_ref(value_slice)); + add_wire_value(st, value); } static void emit_lithdr_noidx(grpc_chttp2_hpack_compressor *c, - uint32_t key_index, grpc_mdelem *elem, + uint32_t key_index, grpc_mdelem elem, framer_state *st) { uint32_t len_pfx = GRPC_CHTTP2_VARINT_LENGTH(key_index, 4); - uint8_t huffman_prefix; - grpc_slice value_slice = get_wire_value(elem, &huffman_prefix); - size_t len_val = GRPC_SLICE_LENGTH(value_slice); + wire_value value = get_wire_value(elem, st->use_true_binary_metadata); + size_t len_val = wire_value_length(value); uint32_t len_val_len; GPR_ASSERT(len_val <= UINT32_MAX); len_val_len = GRPC_CHTTP2_VARINT_LENGTH((uint32_t)len_val, 1); GRPC_CHTTP2_WRITE_VARINT(key_index, 4, 0x00, add_tiny_header_data(st, len_pfx), len_pfx); - GRPC_CHTTP2_WRITE_VARINT((uint32_t)len_val, 1, huffman_prefix, + GRPC_CHTTP2_WRITE_VARINT((uint32_t)len_val, 1, value.huffman_prefix, add_tiny_header_data(st, len_val_len), len_val_len); - add_header_data(st, grpc_slice_ref(value_slice)); + add_wire_value(st, value); } static void emit_lithdr_incidx_v(grpc_chttp2_hpack_compressor *c, - grpc_mdelem *elem, framer_state *st) { - uint32_t len_key = (uint32_t)GRPC_SLICE_LENGTH(elem->key->slice); - uint8_t huffman_prefix; - grpc_slice value_slice = get_wire_value(elem, &huffman_prefix); - uint32_t len_val = (uint32_t)GRPC_SLICE_LENGTH(value_slice); + grpc_mdelem elem, framer_state *st) { + uint32_t len_key = (uint32_t)GRPC_SLICE_LENGTH(GRPC_MDKEY(elem)); + wire_value value = get_wire_value(elem, st->use_true_binary_metadata); + uint32_t len_val = (uint32_t)wire_value_length(value); uint32_t len_key_len = GRPC_CHTTP2_VARINT_LENGTH(len_key, 1); uint32_t len_val_len = GRPC_CHTTP2_VARINT_LENGTH(len_val, 1); GPR_ASSERT(len_key <= UINT32_MAX); - GPR_ASSERT(GRPC_SLICE_LENGTH(value_slice) <= UINT32_MAX); + GPR_ASSERT(wire_value_length(value) <= UINT32_MAX); *add_tiny_header_data(st, 1) = 0x40; GRPC_CHTTP2_WRITE_VARINT(len_key, 1, 0x00, add_tiny_header_data(st, len_key_len), len_key_len); - add_header_data(st, grpc_slice_ref(elem->key->slice)); - GRPC_CHTTP2_WRITE_VARINT(len_val, 1, huffman_prefix, + add_header_data(st, grpc_slice_ref_internal(GRPC_MDKEY(elem))); + GRPC_CHTTP2_WRITE_VARINT(len_val, 1, value.huffman_prefix, add_tiny_header_data(st, len_val_len), len_val_len); - add_header_data(st, grpc_slice_ref(value_slice)); + add_wire_value(st, value); } static void emit_lithdr_noidx_v(grpc_chttp2_hpack_compressor *c, - grpc_mdelem *elem, framer_state *st) { - uint32_t len_key = (uint32_t)GRPC_SLICE_LENGTH(elem->key->slice); - uint8_t huffman_prefix; - grpc_slice value_slice = get_wire_value(elem, &huffman_prefix); - uint32_t len_val = (uint32_t)GRPC_SLICE_LENGTH(value_slice); + grpc_mdelem elem, framer_state *st) { + uint32_t len_key = (uint32_t)GRPC_SLICE_LENGTH(GRPC_MDKEY(elem)); + wire_value value = get_wire_value(elem, st->use_true_binary_metadata); + uint32_t len_val = (uint32_t)wire_value_length(value); uint32_t len_key_len = GRPC_CHTTP2_VARINT_LENGTH(len_key, 1); uint32_t len_val_len = GRPC_CHTTP2_VARINT_LENGTH(len_val, 1); GPR_ASSERT(len_key <= UINT32_MAX); - GPR_ASSERT(GRPC_SLICE_LENGTH(value_slice) <= UINT32_MAX); + GPR_ASSERT(wire_value_length(value) <= UINT32_MAX); *add_tiny_header_data(st, 1) = 0x00; GRPC_CHTTP2_WRITE_VARINT(len_key, 1, 0x00, add_tiny_header_data(st, len_key_len), len_key_len); - add_header_data(st, grpc_slice_ref(elem->key->slice)); - GRPC_CHTTP2_WRITE_VARINT(len_val, 1, huffman_prefix, + add_header_data(st, grpc_slice_ref_internal(GRPC_MDKEY(elem))); + GRPC_CHTTP2_WRITE_VARINT(len_val, 1, value.huffman_prefix, add_tiny_header_data(st, len_val_len), len_val_len); - add_header_data(st, grpc_slice_ref(value_slice)); + add_wire_value(st, value); } static void emit_advertise_table_size_change(grpc_chttp2_hpack_compressor *c, @@ -366,16 +399,10 @@ static uint32_t dynidx(grpc_chttp2_hpack_compressor *c, uint32_t elem_index) { } /* encode an mdelem */ -static void hpack_enc(grpc_chttp2_hpack_compressor *c, grpc_mdelem *elem, - framer_state *st) { - uint32_t key_hash = elem->key->hash; - uint32_t elem_hash = GRPC_MDSTR_KV_HASH(key_hash, elem->value->hash); - size_t decoder_space_usage; - uint32_t indices_key; - int should_add_elem; - - GPR_ASSERT(GRPC_SLICE_LENGTH(elem->key->slice) > 0); - if (GRPC_SLICE_START_PTR(elem->key->slice)[0] != ':') { /* regular header */ +static void hpack_enc(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_compressor *c, + grpc_mdelem elem, framer_state *st) { + GPR_ASSERT(GRPC_SLICE_LENGTH(GRPC_MDKEY(elem)) > 0); + if (GRPC_SLICE_START_PTR(GRPC_MDKEY(elem))[0] != ':') { /* regular header */ st->seen_regular_header = 1; } else { GPR_ASSERT( @@ -383,11 +410,39 @@ static void hpack_enc(grpc_chttp2_hpack_compressor *c, grpc_mdelem *elem, "Reserved header (colon-prefixed) happening after regular ones."); } + if (GRPC_TRACER_ON(grpc_http_trace) && !GRPC_MDELEM_IS_INTERNED(elem)) { + char *k = grpc_slice_to_c_string(GRPC_MDKEY(elem)); + char *v = grpc_slice_to_c_string(GRPC_MDVALUE(elem)); + gpr_log( + GPR_DEBUG, + "Encode: '%s: %s', elem_interned=%d [%d], k_interned=%d, v_interned=%d", + k, v, GRPC_MDELEM_IS_INTERNED(elem), GRPC_MDELEM_STORAGE(elem), + grpc_slice_is_interned(GRPC_MDKEY(elem)), + grpc_slice_is_interned(GRPC_MDVALUE(elem))); + gpr_free(k); + gpr_free(v); + } + if (!GRPC_MDELEM_IS_INTERNED(elem)) { + emit_lithdr_noidx_v(c, elem, st); + return; + } + + uint32_t key_hash; + uint32_t value_hash; + uint32_t elem_hash; + size_t decoder_space_usage; + uint32_t indices_key; + int should_add_elem; + + key_hash = grpc_slice_hash(GRPC_MDKEY(elem)); + value_hash = grpc_slice_hash(GRPC_MDVALUE(elem)); + elem_hash = GRPC_MDSTR_KV_HASH(key_hash, value_hash); + inc_filter(HASH_FRAGMENT_1(elem_hash), &c->filter_elems_sum, c->filter_elems); /* is this elem currently in the decoders table? */ - if (c->entries_elems[HASH_FRAGMENT_2(elem_hash)] == elem && + if (grpc_mdelem_eq(c->entries_elems[HASH_FRAGMENT_2(elem_hash)], elem) && c->indices_elems[HASH_FRAGMENT_2(elem_hash)] > c->tail_remote_index) { /* HIT: complete element (first cuckoo hash) */ emit_indexed(c, dynidx(c, c->indices_elems[HASH_FRAGMENT_2(elem_hash)]), @@ -395,7 +450,7 @@ static void hpack_enc(grpc_chttp2_hpack_compressor *c, grpc_mdelem *elem, return; } - if (c->entries_elems[HASH_FRAGMENT_3(elem_hash)] == elem && + if (grpc_mdelem_eq(c->entries_elems[HASH_FRAGMENT_3(elem_hash)], elem) && c->indices_elems[HASH_FRAGMENT_3(elem_hash)] > c->tail_remote_index) { /* HIT: complete element (second cuckoo hash) */ emit_indexed(c, dynidx(c, c->indices_elems[HASH_FRAGMENT_3(elem_hash)]), @@ -412,12 +467,13 @@ static void hpack_enc(grpc_chttp2_hpack_compressor *c, grpc_mdelem *elem, /* no hits for the elem... maybe there's a key? */ indices_key = c->indices_keys[HASH_FRAGMENT_2(key_hash)]; - if (c->entries_keys[HASH_FRAGMENT_2(key_hash)] == elem->key && + if (grpc_slice_eq(c->entries_keys[HASH_FRAGMENT_2(key_hash)], + GRPC_MDKEY(elem)) && indices_key > c->tail_remote_index) { /* HIT: key (first cuckoo hash) */ if (should_add_elem) { emit_lithdr_incidx(c, dynidx(c, indices_key), elem, st); - add_elem(c, elem); + add_elem(exec_ctx, c, elem); return; } else { emit_lithdr_noidx(c, dynidx(c, indices_key), elem, st); @@ -427,12 +483,13 @@ static void hpack_enc(grpc_chttp2_hpack_compressor *c, grpc_mdelem *elem, } indices_key = c->indices_keys[HASH_FRAGMENT_3(key_hash)]; - if (c->entries_keys[HASH_FRAGMENT_3(key_hash)] == elem->key && + if (grpc_slice_eq(c->entries_keys[HASH_FRAGMENT_3(key_hash)], + GRPC_MDKEY(elem)) && indices_key > c->tail_remote_index) { /* HIT: key (first cuckoo hash) */ if (should_add_elem) { emit_lithdr_incidx(c, dynidx(c, indices_key), elem, st); - add_elem(c, elem); + add_elem(exec_ctx, c, elem); return; } else { emit_lithdr_noidx(c, dynidx(c, indices_key), elem, st); @@ -445,7 +502,7 @@ static void hpack_enc(grpc_chttp2_hpack_compressor *c, grpc_mdelem *elem, if (should_add_elem) { emit_lithdr_incidx_v(c, elem, st); - add_elem(c, elem); + add_elem(exec_ctx, c, elem); return; } else { emit_lithdr_noidx_v(c, elem, st); @@ -457,16 +514,17 @@ static void hpack_enc(grpc_chttp2_hpack_compressor *c, grpc_mdelem *elem, #define STRLEN_LIT(x) (sizeof(x) - 1) #define TIMEOUT_KEY "grpc-timeout" -static void deadline_enc(grpc_chttp2_hpack_compressor *c, gpr_timespec deadline, +static void deadline_enc(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_compressor *c, gpr_timespec deadline, framer_state *st) { char timeout_str[GRPC_HTTP2_TIMEOUT_ENCODE_MIN_BUFSIZE]; - grpc_mdelem *mdelem; + grpc_mdelem mdelem; grpc_http2_encode_timeout( gpr_time_sub(deadline, gpr_now(deadline.clock_type)), timeout_str); - mdelem = grpc_mdelem_from_metadata_strings( - GRPC_MDSTR_GRPC_TIMEOUT, grpc_mdstr_from_string(timeout_str)); - hpack_enc(c, mdelem, st); - GRPC_MDELEM_UNREF(mdelem); + mdelem = grpc_mdelem_from_slices(exec_ctx, GRPC_MDSTR_GRPC_TIMEOUT, + grpc_slice_from_copied_string(timeout_str)); + hpack_enc(exec_ctx, c, mdelem, st); + GRPC_MDELEM_UNREF(exec_ctx, mdelem); } static uint32_t elems_for_bytes(uint32_t bytes) { return (bytes + 31) / 32; } @@ -481,13 +539,19 @@ void grpc_chttp2_hpack_compressor_init(grpc_chttp2_hpack_compressor *c) { gpr_malloc(sizeof(*c->table_elem_size) * c->cap_table_elems); memset(c->table_elem_size, 0, sizeof(*c->table_elem_size) * c->cap_table_elems); + for (size_t i = 0; i < GPR_ARRAY_SIZE(c->entries_keys); i++) { + c->entries_keys[i] = terminal_slice; + } } -void grpc_chttp2_hpack_compressor_destroy(grpc_chttp2_hpack_compressor *c) { +void grpc_chttp2_hpack_compressor_destroy(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_compressor *c) { int i; for (i = 0; i < GRPC_CHTTP2_HPACKC_NUM_VALUES; i++) { - if (c->entries_keys[i]) GRPC_MDSTR_UNREF(c->entries_keys[i]); - if (c->entries_elems[i]) GRPC_MDELEM_UNREF(c->entries_elems[i]); + if (c->entries_keys[i].refcount != &terminal_slice_refcount) { + grpc_slice_unref_internal(exec_ctx, c->entries_keys[i]); + } + GRPC_MDELEM_UNREF(exec_ctx, c->entries_elems[i]); } gpr_free(c->table_elem_size); } @@ -537,29 +601,28 @@ void grpc_chttp2_hpack_compressor_set_max_table_size( } } c->advertise_table_size_change = 1; - if (grpc_http_trace) { + if (GRPC_TRACER_ON(grpc_http_trace)) { gpr_log(GPR_DEBUG, "set max table size from encoder to %d", max_table_size); } } -void grpc_chttp2_encode_header(grpc_chttp2_hpack_compressor *c, - uint32_t stream_id, - grpc_metadata_batch *metadata, int is_eof, - size_t max_frame_size, - grpc_transport_one_way_stats *stats, +void grpc_chttp2_encode_header(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_compressor *c, + grpc_mdelem **extra_headers, + size_t extra_headers_size, + grpc_metadata_batch *metadata, + const grpc_encode_header_options *options, grpc_slice_buffer *outbuf) { - framer_state st; - grpc_linked_mdelem *l; - gpr_timespec deadline; - - GPR_ASSERT(stream_id != 0); + GPR_ASSERT(options->stream_id != 0); + framer_state st; st.seen_regular_header = 0; - st.stream_id = stream_id; + st.stream_id = options->stream_id; st.output = outbuf; st.is_first_frame = 1; - st.stats = stats; - st.max_frame_size = max_frame_size; + st.stats = options->stats; + st.max_frame_size = options->max_frame_size; + st.use_true_binary_metadata = options->use_true_binary_metadata; /* Encode a metadata batch; store the returned values, representing a metadata element that needs to be unreffed back into the metadata @@ -569,14 +632,17 @@ void grpc_chttp2_encode_header(grpc_chttp2_hpack_compressor *c, if (c->advertise_table_size_change != 0) { emit_advertise_table_size_change(c, &st); } + for (size_t i = 0; i < extra_headers_size; ++i) { + hpack_enc(exec_ctx, c, *extra_headers[i], &st); + } grpc_metadata_batch_assert_ok(metadata); - for (l = metadata->list.head; l; l = l->next) { - hpack_enc(c, l->md, &st); + for (grpc_linked_mdelem *l = metadata->list.head; l; l = l->next) { + hpack_enc(exec_ctx, c, l->md, &st); } - deadline = metadata->deadline; + gpr_timespec deadline = metadata->deadline; if (gpr_time_cmp(deadline, gpr_inf_future(deadline.clock_type)) != 0) { - deadline_enc(c, deadline, &st); + deadline_enc(exec_ctx, c, deadline, &st); } - finish_frame(&st, 1, is_eof); + finish_frame(&st, 1, options->is_eof); } diff --git a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/hpack_encoder.h b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/hpack_encoder.h index bcbd675ca..271192f89 100644 --- a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/hpack_encoder.h +++ b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/hpack_encoder.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -74,8 +59,8 @@ typedef struct { /* entry tables for keys & elems: these tables track values that have been seen and *may* be in the decompressor table */ - grpc_mdstr *entries_keys[GRPC_CHTTP2_HPACKC_NUM_VALUES]; - grpc_mdelem *entries_elems[GRPC_CHTTP2_HPACKC_NUM_VALUES]; + grpc_slice entries_keys[GRPC_CHTTP2_HPACKC_NUM_VALUES]; + grpc_mdelem entries_elems[GRPC_CHTTP2_HPACKC_NUM_VALUES]; uint32_t indices_keys[GRPC_CHTTP2_HPACKC_NUM_VALUES]; uint32_t indices_elems[GRPC_CHTTP2_HPACKC_NUM_VALUES]; @@ -83,16 +68,27 @@ typedef struct { } grpc_chttp2_hpack_compressor; void grpc_chttp2_hpack_compressor_init(grpc_chttp2_hpack_compressor *c); -void grpc_chttp2_hpack_compressor_destroy(grpc_chttp2_hpack_compressor *c); +void grpc_chttp2_hpack_compressor_destroy(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_compressor *c); void grpc_chttp2_hpack_compressor_set_max_table_size( grpc_chttp2_hpack_compressor *c, uint32_t max_table_size); void grpc_chttp2_hpack_compressor_set_max_usable_size( grpc_chttp2_hpack_compressor *c, uint32_t max_table_size); -void grpc_chttp2_encode_header(grpc_chttp2_hpack_compressor *c, uint32_t id, - grpc_metadata_batch *metadata, int is_eof, - size_t max_frame_size, - grpc_transport_one_way_stats *stats, +typedef struct { + uint32_t stream_id; + bool is_eof; + bool use_true_binary_metadata; + size_t max_frame_size; + grpc_transport_one_way_stats *stats; +} grpc_encode_header_options; + +void grpc_chttp2_encode_header(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_compressor *c, + grpc_mdelem **extra_headers, + size_t extra_headers_size, + grpc_metadata_batch *metadata, + const grpc_encode_header_options *options, grpc_slice_buffer *outbuf); #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HPACK_ENCODER_H */ diff --git a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/hpack_parser.c b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/hpack_parser.c index 6a9200b8d..7f3736555 100644 --- a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/hpack_parser.c +++ b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/hpack_parser.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -38,11 +23,6 @@ #include #include -/* This is here for grpc_is_binary_header - * TODO(murgatroid99): Remove this - */ -#include - #include #include #include @@ -50,14 +30,14 @@ #include #include "src/core/ext/transport/chttp2/transport/bin_encoder.h" -#include "src/core/ext/transport/chttp2/transport/http2_errors.h" #include "src/core/lib/profiling/timers.h" +#include "src/core/lib/slice/slice_internal.h" #include "src/core/lib/support/string.h" - -extern int grpc_http_trace; +#include "src/core/lib/transport/http2_errors.h" typedef enum { NOT_BINARY, + BINARY_BEGIN, B64_BYTE0, B64_BYTE1, B64_BYTE2, @@ -668,23 +648,55 @@ static const uint8_t inverse_base64[256] = { /* emission helpers */ static grpc_error *on_hdr(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_parser *p, - grpc_mdelem *md, int add_to_table) { + grpc_mdelem md, int add_to_table) { + if (GRPC_TRACER_ON(grpc_http_trace) && !GRPC_MDELEM_IS_INTERNED(md)) { + char *k = grpc_slice_to_c_string(GRPC_MDKEY(md)); + char *v = grpc_slice_to_c_string(GRPC_MDVALUE(md)); + gpr_log( + GPR_DEBUG, + "Decode: '%s: %s', elem_interned=%d [%d], k_interned=%d, v_interned=%d", + k, v, GRPC_MDELEM_IS_INTERNED(md), GRPC_MDELEM_STORAGE(md), + grpc_slice_is_interned(GRPC_MDKEY(md)), + grpc_slice_is_interned(GRPC_MDVALUE(md))); + gpr_free(k); + gpr_free(v); + } if (add_to_table) { - grpc_error *err = grpc_chttp2_hptbl_add(&p->table, md); + GPR_ASSERT(GRPC_MDELEM_STORAGE(md) == GRPC_MDELEM_STORAGE_INTERNED || + GRPC_MDELEM_STORAGE(md) == GRPC_MDELEM_STORAGE_STATIC); + grpc_error *err = grpc_chttp2_hptbl_add(exec_ctx, &p->table, md); if (err != GRPC_ERROR_NONE) return err; } if (p->on_header == NULL) { - GRPC_MDELEM_UNREF(md); - return GRPC_ERROR_CREATE("on_header callback not set"); + GRPC_MDELEM_UNREF(exec_ctx, md); + return GRPC_ERROR_CREATE_FROM_STATIC_STRING("on_header callback not set"); } p->on_header(exec_ctx, p->on_header_user_data, md); return GRPC_ERROR_NONE; } -static grpc_mdstr *take_string(grpc_chttp2_hpack_parser *p, - grpc_chttp2_hpack_parser_string *str) { - grpc_mdstr *s = grpc_mdstr_from_buffer((uint8_t *)str->str, str->length); - str->length = 0; +static grpc_slice take_string(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, + grpc_chttp2_hpack_parser_string *str, + bool intern) { + grpc_slice s; + if (!str->copied) { + if (intern) { + s = grpc_slice_intern(str->data.referenced); + grpc_slice_unref_internal(exec_ctx, str->data.referenced); + } else { + s = str->data.referenced; + } + str->copied = true; + str->data.referenced = grpc_empty_slice(); + } else if (intern) { + s = grpc_slice_intern(grpc_slice_from_static_buffer( + str->data.copied.str, str->data.copied.length)); + } else { + s = grpc_slice_from_copied_buffer(str->data.copied.str, + str->data.copied.length); + } + str->data.copied.length = 0; return s; } @@ -771,10 +783,11 @@ static grpc_error *finish_indexed_field(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end) { - grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index); - if (md == NULL) { + grpc_mdelem md = grpc_chttp2_hptbl_lookup(&p->table, p->index); + if (GRPC_MDISNULL(md)) { return grpc_error_set_int( - grpc_error_set_int(GRPC_ERROR_CREATE("Invalid HPACK index received"), + grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "Invalid HPACK index received"), GRPC_ERROR_INT_INDEX, (intptr_t)p->index), GRPC_ERROR_INT_SIZE, (intptr_t)p->table.num_ents); } @@ -813,11 +826,12 @@ static grpc_error *finish_lithdr_incidx(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end) { - grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index); - GPR_ASSERT(md != NULL); /* handled in string parsing */ + grpc_mdelem md = grpc_chttp2_hptbl_lookup(&p->table, p->index); + GPR_ASSERT(!GRPC_MDISNULL(md)); /* handled in string parsing */ grpc_error *err = on_hdr( - exec_ctx, p, grpc_mdelem_from_metadata_strings(GRPC_MDSTR_REF(md->key), - take_string(p, &p->value)), + exec_ctx, p, + grpc_mdelem_from_slices(exec_ctx, grpc_slice_ref_internal(GRPC_MDKEY(md)), + take_string(exec_ctx, p, &p->value, true)), 1); if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err); return parse_begin(exec_ctx, p, cur, end); @@ -829,8 +843,9 @@ static grpc_error *finish_lithdr_incidx_v(grpc_exec_ctx *exec_ctx, const uint8_t *cur, const uint8_t *end) { grpc_error *err = on_hdr( - exec_ctx, p, grpc_mdelem_from_metadata_strings(take_string(p, &p->key), - take_string(p, &p->value)), + exec_ctx, p, + grpc_mdelem_from_slices(exec_ctx, take_string(exec_ctx, p, &p->key, true), + take_string(exec_ctx, p, &p->value, true)), 1); if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err); return parse_begin(exec_ctx, p, cur, end); @@ -881,11 +896,12 @@ static grpc_error *finish_lithdr_notidx(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end) { - grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index); - GPR_ASSERT(md != NULL); /* handled in string parsing */ + grpc_mdelem md = grpc_chttp2_hptbl_lookup(&p->table, p->index); + GPR_ASSERT(!GRPC_MDISNULL(md)); /* handled in string parsing */ grpc_error *err = on_hdr( - exec_ctx, p, grpc_mdelem_from_metadata_strings(GRPC_MDSTR_REF(md->key), - take_string(p, &p->value)), + exec_ctx, p, + grpc_mdelem_from_slices(exec_ctx, grpc_slice_ref_internal(GRPC_MDKEY(md)), + take_string(exec_ctx, p, &p->value, false)), 0); if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err); return parse_begin(exec_ctx, p, cur, end); @@ -897,8 +913,9 @@ static grpc_error *finish_lithdr_notidx_v(grpc_exec_ctx *exec_ctx, const uint8_t *cur, const uint8_t *end) { grpc_error *err = on_hdr( - exec_ctx, p, grpc_mdelem_from_metadata_strings(take_string(p, &p->key), - take_string(p, &p->value)), + exec_ctx, p, + grpc_mdelem_from_slices(exec_ctx, take_string(exec_ctx, p, &p->key, true), + take_string(exec_ctx, p, &p->value, false)), 0); if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err); return parse_begin(exec_ctx, p, cur, end); @@ -949,11 +966,12 @@ static grpc_error *finish_lithdr_nvridx(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end) { - grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index); - GPR_ASSERT(md != NULL); /* handled in string parsing */ + grpc_mdelem md = grpc_chttp2_hptbl_lookup(&p->table, p->index); + GPR_ASSERT(!GRPC_MDISNULL(md)); /* handled in string parsing */ grpc_error *err = on_hdr( - exec_ctx, p, grpc_mdelem_from_metadata_strings(GRPC_MDSTR_REF(md->key), - take_string(p, &p->value)), + exec_ctx, p, + grpc_mdelem_from_slices(exec_ctx, grpc_slice_ref_internal(GRPC_MDKEY(md)), + take_string(exec_ctx, p, &p->value, false)), 0); if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err); return parse_begin(exec_ctx, p, cur, end); @@ -965,8 +983,9 @@ static grpc_error *finish_lithdr_nvridx_v(grpc_exec_ctx *exec_ctx, const uint8_t *cur, const uint8_t *end) { grpc_error *err = on_hdr( - exec_ctx, p, grpc_mdelem_from_metadata_strings(take_string(p, &p->key), - take_string(p, &p->value)), + exec_ctx, p, + grpc_mdelem_from_slices(exec_ctx, take_string(exec_ctx, p, &p->key, true), + take_string(exec_ctx, p, &p->value, false)), 0); if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err); return parse_begin(exec_ctx, p, cur, end); @@ -1016,11 +1035,11 @@ static grpc_error *parse_lithdr_nvridx_v(grpc_exec_ctx *exec_ctx, static grpc_error *finish_max_tbl_size(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end) { - if (grpc_http_trace) { + if (GRPC_TRACER_ON(grpc_http_trace)) { gpr_log(GPR_INFO, "MAX TABLE SIZE: %d", p->index); } grpc_error *err = - grpc_chttp2_hptbl_set_current_table_size(&p->table, p->index); + grpc_chttp2_hptbl_set_current_table_size(exec_ctx, &p->table, p->index); if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err); return parse_begin(exec_ctx, p, cur, end); } @@ -1032,7 +1051,7 @@ static grpc_error *parse_max_tbl_size(grpc_exec_ctx *exec_ctx, if (p->dynamic_table_update_allowed == 0) { return parse_error( exec_ctx, p, cur, end, - GRPC_ERROR_CREATE( + GRPC_ERROR_CREATE_FROM_STATIC_STRING( "More than two max table size changes in a single frame")); } p->dynamic_table_update_allowed--; @@ -1050,7 +1069,7 @@ static grpc_error *parse_max_tbl_size_x(grpc_exec_ctx *exec_ctx, if (p->dynamic_table_update_allowed == 0) { return parse_error( exec_ctx, p, cur, end, - GRPC_ERROR_CREATE( + GRPC_ERROR_CREATE_FROM_STATIC_STRING( "More than two max table size changes in a single frame")); } p->dynamic_table_update_allowed--; @@ -1084,7 +1103,7 @@ static grpc_error *parse_illegal_op(grpc_exec_ctx *exec_ctx, GPR_ASSERT(cur != end); char *msg; gpr_asprintf(&msg, "Illegal hpack op code %d", *cur); - grpc_error *err = GRPC_ERROR_CREATE(msg); + grpc_error *err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg); gpr_free(msg); return parse_error(exec_ctx, p, cur, end, err); } @@ -1204,7 +1223,7 @@ static grpc_error *parse_value4(grpc_exec_ctx *exec_ctx, "integer overflow in hpack integer decoding: have 0x%08x, " "got byte 0x%02x on byte 5", *p->parsing.value, *cur); - grpc_error *err = GRPC_ERROR_CREATE(msg); + grpc_error *err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg); gpr_free(msg); return parse_error(exec_ctx, p, cur, end, err); } @@ -1233,7 +1252,7 @@ static grpc_error *parse_value5up(grpc_exec_ctx *exec_ctx, "integer overflow in hpack integer decoding: have 0x%08x, " "got byte 0x%02x sometime after byte 5", *p->parsing.value, *cur); - grpc_error *err = GRPC_ERROR_CREATE(msg); + grpc_error *err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg); gpr_free(msg); return parse_error(exec_ctx, p, cur, end, err); } @@ -1261,14 +1280,15 @@ static grpc_error *parse_string_prefix(grpc_exec_ctx *exec_ctx, static void append_bytes(grpc_chttp2_hpack_parser_string *str, const uint8_t *data, size_t length) { if (length == 0) return; - if (length + str->length > str->capacity) { - GPR_ASSERT(str->length + length <= UINT32_MAX); - str->capacity = (uint32_t)(str->length + length); - str->str = gpr_realloc(str->str, str->capacity); + if (length + str->data.copied.length > str->data.copied.capacity) { + GPR_ASSERT(str->data.copied.length + length <= UINT32_MAX); + str->data.copied.capacity = (uint32_t)(str->data.copied.length + length); + str->data.copied.str = + gpr_realloc(str->data.copied.str, str->data.copied.capacity); } - memcpy(str->str + str->length, data, length); - GPR_ASSERT(length <= UINT32_MAX - str->length); - str->length += (uint32_t)length; + memcpy(str->data.copied.str + str->data.copied.length, data, length); + GPR_ASSERT(length <= UINT32_MAX - str->data.copied.length); + str->data.copied.length += (uint32_t)length; } static grpc_error *append_string(grpc_exec_ctx *exec_ctx, @@ -1281,6 +1301,19 @@ static grpc_error *append_string(grpc_exec_ctx *exec_ctx, case NOT_BINARY: append_bytes(str, cur, (size_t)(end - cur)); return GRPC_ERROR_NONE; + case BINARY_BEGIN: + if (cur == end) { + p->binary = BINARY_BEGIN; + return GRPC_ERROR_NONE; + } + if (*cur == 0) { + /* 'true-binary' case */ + ++cur; + p->binary = NOT_BINARY; + append_bytes(str, cur, (size_t)(end - cur)); + return GRPC_ERROR_NONE; + } + /* fallthrough */ b64_byte0: case B64_BYTE0: if (cur == end) { @@ -1290,8 +1323,9 @@ static grpc_error *append_string(grpc_exec_ctx *exec_ctx, bits = inverse_base64[*cur]; ++cur; if (bits == 255) - return parse_error(exec_ctx, p, cur, end, - GRPC_ERROR_CREATE("Illegal base64 character")); + return parse_error( + exec_ctx, p, cur, end, + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Illegal base64 character")); else if (bits == 64) goto b64_byte0; p->base64_buffer = bits << 18; @@ -1305,8 +1339,9 @@ static grpc_error *append_string(grpc_exec_ctx *exec_ctx, bits = inverse_base64[*cur]; ++cur; if (bits == 255) - return parse_error(exec_ctx, p, cur, end, - GRPC_ERROR_CREATE("Illegal base64 character")); + return parse_error( + exec_ctx, p, cur, end, + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Illegal base64 character")); else if (bits == 64) goto b64_byte1; p->base64_buffer |= bits << 12; @@ -1320,8 +1355,9 @@ static grpc_error *append_string(grpc_exec_ctx *exec_ctx, bits = inverse_base64[*cur]; ++cur; if (bits == 255) - return parse_error(exec_ctx, p, cur, end, - GRPC_ERROR_CREATE("Illegal base64 character")); + return parse_error( + exec_ctx, p, cur, end, + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Illegal base64 character")); else if (bits == 64) goto b64_byte2; p->base64_buffer |= bits << 6; @@ -1335,8 +1371,9 @@ static grpc_error *append_string(grpc_exec_ctx *exec_ctx, bits = inverse_base64[*cur]; ++cur; if (bits == 255) - return parse_error(exec_ctx, p, cur, end, - GRPC_ERROR_CREATE("Illegal base64 character")); + return parse_error( + exec_ctx, p, cur, end, + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Illegal base64 character")); else if (bits == 64) goto b64_byte3; p->base64_buffer |= bits; @@ -1348,33 +1385,34 @@ static grpc_error *append_string(grpc_exec_ctx *exec_ctx, goto b64_byte0; } GPR_UNREACHABLE_CODE(return parse_error( - exec_ctx, p, cur, end, GRPC_ERROR_CREATE("Should never reach here"))); + exec_ctx, p, cur, end, + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Should never reach here"))); } -/* append a null terminator to a string */ static grpc_error *finish_str(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end) { - uint8_t terminator = 0; uint8_t decoded[2]; uint32_t bits; grpc_chttp2_hpack_parser_string *str = p->parsing.str; switch ((binary_state)p->binary) { case NOT_BINARY: break; + case BINARY_BEGIN: + break; case B64_BYTE0: break; case B64_BYTE1: - return parse_error( - exec_ctx, p, cur, end, - GRPC_ERROR_CREATE("illegal base64 encoding")); /* illegal encoding */ + return parse_error(exec_ctx, p, cur, end, + GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "illegal base64 encoding")); /* illegal encoding */ case B64_BYTE2: bits = p->base64_buffer; if (bits & 0xffff) { char *msg; gpr_asprintf(&msg, "trailing bits in base64 encoding: 0x%04x", bits & 0xffff); - grpc_error *err = GRPC_ERROR_CREATE(msg); + grpc_error *err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg); gpr_free(msg); return parse_error(exec_ctx, p, cur, end, err); } @@ -1387,7 +1425,7 @@ static grpc_error *finish_str(grpc_exec_ctx *exec_ctx, char *msg; gpr_asprintf(&msg, "trailing bits in base64 encoding: 0x%02x", bits & 0xff); - grpc_error *err = GRPC_ERROR_CREATE(msg); + grpc_error *err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg); gpr_free(msg); return parse_error(exec_ctx, p, cur, end, err); } @@ -1396,8 +1434,6 @@ static grpc_error *finish_str(grpc_exec_ctx *exec_ctx, append_bytes(str, decoded, 2); break; } - append_bytes(str, &terminator, 1); - p->parsing.str->length--; /* don't actually count the null terminator */ return GRPC_ERROR_NONE; } @@ -1472,8 +1508,18 @@ static grpc_error *begin_parse_string(grpc_exec_ctx *exec_ctx, const uint8_t *cur, const uint8_t *end, uint8_t binary, grpc_chttp2_hpack_parser_string *str) { + if (!p->huff && binary == NOT_BINARY && (end - cur) >= (intptr_t)p->strlen && + p->current_slice_refcount != NULL) { + str->copied = false; + str->data.referenced.refcount = p->current_slice_refcount; + str->data.referenced.data.refcounted.bytes = (uint8_t *)cur; + str->data.referenced.data.refcounted.length = p->strlen; + grpc_slice_ref_internal(str->data.referenced); + return parse_next(exec_ctx, p, cur + p->strlen, end); + } p->strgot = 0; - str->length = 0; + str->copied = true; + str->data.copied.length = 0; p->parsing.str = str; p->huff_state = 0; p->binary = binary; @@ -1490,21 +1536,23 @@ static grpc_error *parse_key_string(grpc_exec_ctx *exec_ctx, /* check if a key represents a binary header or not */ static bool is_binary_literal_header(grpc_chttp2_hpack_parser *p) { - return grpc_is_binary_header(p->key.str, p->key.length); + return grpc_is_binary_header( + p->key.copied ? grpc_slice_from_static_buffer(p->key.data.copied.str, + p->key.data.copied.length) + : p->key.data.referenced); } static grpc_error *is_binary_indexed_header(grpc_chttp2_hpack_parser *p, bool *is) { - grpc_mdelem *elem = grpc_chttp2_hptbl_lookup(&p->table, p->index); - if (!elem) { + grpc_mdelem elem = grpc_chttp2_hptbl_lookup(&p->table, p->index); + if (GRPC_MDISNULL(elem)) { return grpc_error_set_int( - grpc_error_set_int(GRPC_ERROR_CREATE("Invalid HPACK index received"), + grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "Invalid HPACK index received"), GRPC_ERROR_INT_INDEX, (intptr_t)p->index), GRPC_ERROR_INT_SIZE, (intptr_t)p->table.num_ents); } - *is = grpc_is_binary_header( - (const char *)GRPC_SLICE_START_PTR(elem->key->slice), - GRPC_SLICE_LENGTH(elem->key->slice)); + *is = grpc_is_binary_header(GRPC_MDKEY(elem)); return GRPC_ERROR_NONE; } @@ -1514,7 +1562,7 @@ static grpc_error *parse_value_string(grpc_exec_ctx *exec_ctx, const uint8_t *cur, const uint8_t *end, bool is_binary) { return begin_parse_string(exec_ctx, p, cur, end, - is_binary ? B64_BYTE0 : NOT_BINARY, &p->value); + is_binary ? BINARY_BEGIN : NOT_BINARY, &p->value); } static grpc_error *parse_value_string_with_indexed_key( @@ -1534,19 +1582,22 @@ static grpc_error *parse_value_string_with_literal_key( /* PUBLIC INTERFACE */ -void grpc_chttp2_hpack_parser_init(grpc_chttp2_hpack_parser *p) { +void grpc_chttp2_hpack_parser_init(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p) { p->on_header = NULL; p->on_header_user_data = NULL; p->state = parse_begin; - p->key.str = NULL; - p->key.capacity = 0; - p->key.length = 0; - p->value.str = NULL; - p->value.capacity = 0; - p->value.length = 0; + p->key.data.referenced = grpc_empty_slice(); + p->key.data.copied.str = NULL; + p->key.data.copied.capacity = 0; + p->key.data.copied.length = 0; + p->value.data.referenced = grpc_empty_slice(); + p->value.data.copied.str = NULL; + p->value.data.copied.capacity = 0; + p->value.data.copied.length = 0; p->dynamic_table_update_allowed = 2; p->last_error = GRPC_ERROR_NONE; - grpc_chttp2_hptbl_init(&p->table); + grpc_chttp2_hptbl_init(exec_ctx, &p->table); } void grpc_chttp2_hpack_parser_set_has_priority(grpc_chttp2_hpack_parser *p) { @@ -1554,22 +1605,33 @@ void grpc_chttp2_hpack_parser_set_has_priority(grpc_chttp2_hpack_parser *p) { p->state = parse_stream_dep0; } -void grpc_chttp2_hpack_parser_destroy(grpc_chttp2_hpack_parser *p) { - grpc_chttp2_hptbl_destroy(&p->table); +void grpc_chttp2_hpack_parser_destroy(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p) { + grpc_chttp2_hptbl_destroy(exec_ctx, &p->table); GRPC_ERROR_UNREF(p->last_error); - gpr_free(p->key.str); - gpr_free(p->value.str); + grpc_slice_unref_internal(exec_ctx, p->key.data.referenced); + grpc_slice_unref_internal(exec_ctx, p->value.data.referenced); + gpr_free(p->key.data.copied.str); + gpr_free(p->value.data.copied.str); } grpc_error *grpc_chttp2_hpack_parser_parse(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_parser *p, - const uint8_t *beg, - const uint8_t *end) { - /* TODO(ctiller): limit the distance of end from beg, and perform multiple - steps in the event of a large chunk of data to limit - stack space usage when no tail call optimization is - available */ - return p->state(exec_ctx, p, beg, end); + grpc_slice slice) { +/* max number of bytes to parse at a time... limits call stack depth on + * compilers without TCO */ +#define MAX_PARSE_LENGTH 1024 + p->current_slice_refcount = slice.refcount; + uint8_t *start = GRPC_SLICE_START_PTR(slice); + uint8_t *end = GRPC_SLICE_END_PTR(slice); + grpc_error *error = GRPC_ERROR_NONE; + while (start != end && error == GRPC_ERROR_NONE) { + uint8_t *target = start + GPR_MIN(MAX_PARSE_LENGTH, end - start); + error = p->state(exec_ctx, p, start, target); + start = target; + } + p->current_slice_refcount = NULL; + return error; } typedef void (*maybe_complete_func_type)(grpc_exec_ctx *exec_ctx, @@ -1585,9 +1647,9 @@ static void force_client_rst_stream(grpc_exec_ctx *exec_ctx, void *sp, grpc_chttp2_transport *t = s->t; if (!s->write_closed) { grpc_slice_buffer_add( - &t->qbuf, grpc_chttp2_rst_stream_create(s->id, GRPC_CHTTP2_NO_ERROR, + &t->qbuf, grpc_chttp2_rst_stream_create(s->id, GRPC_HTTP2_NO_ERROR, &s->stats.outgoing)); - grpc_chttp2_initiate_write(exec_ctx, t, false, "force_rst_stream"); + grpc_chttp2_initiate_write(exec_ctx, t, "force_rst_stream"); grpc_chttp2_mark_stream_closed(exec_ctx, t, s, true, true, GRPC_ERROR_NONE); } GRPC_CHTTP2_STREAM_UNREF(exec_ctx, s, "final_rst"); @@ -1603,8 +1665,7 @@ grpc_error *grpc_chttp2_header_parser_parse(grpc_exec_ctx *exec_ctx, if (s != NULL) { s->stats.incoming.header_bytes += GRPC_SLICE_LENGTH(slice); } - grpc_error *error = grpc_chttp2_hpack_parser_parse( - exec_ctx, parser, GRPC_SLICE_START_PTR(slice), GRPC_SLICE_END_PTR(slice)); + grpc_error *error = grpc_chttp2_hpack_parser_parse(exec_ctx, parser, slice); if (error != GRPC_ERROR_NONE) { GPR_TIMER_END("grpc_chttp2_hpack_parser_parse", 0); return error; @@ -1612,7 +1673,7 @@ grpc_error *grpc_chttp2_header_parser_parse(grpc_exec_ctx *exec_ctx, if (is_last) { if (parser->is_boundary && parser->state != parse_begin) { GPR_TIMER_END("grpc_chttp2_hpack_parser_parse", 0); - return GRPC_ERROR_CREATE( + return GRPC_ERROR_CREATE_FROM_STATIC_STRING( "end of header frame not aligned with a hpack record boundary"); } /* need to check for null stream: this can occur if we receive an invalid @@ -1620,7 +1681,8 @@ grpc_error *grpc_chttp2_header_parser_parse(grpc_exec_ctx *exec_ctx, if (s != NULL) { if (parser->is_boundary) { if (s->header_frames_received == GPR_ARRAY_SIZE(s->metadata_buffer)) { - return GRPC_ERROR_CREATE("Too many trailer frames"); + return GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "Too many trailer frames"); } s->published_metadata[s->header_frames_received] = GRPC_METADATA_PUBLISHED_FROM_WIRE; @@ -1634,10 +1696,11 @@ grpc_error *grpc_chttp2_header_parser_parse(grpc_exec_ctx *exec_ctx, however -- it might be that we receive a RST_STREAM following this and can avoid the extra write */ GRPC_CHTTP2_STREAM_REF(s, "final_rst"); - grpc_combiner_execute_finally( - exec_ctx, t->combiner, - grpc_closure_create(force_client_rst_stream, s), GRPC_ERROR_NONE, - false); + GRPC_CLOSURE_SCHED( + exec_ctx, + GRPC_CLOSURE_CREATE(force_client_rst_stream, s, + grpc_combiner_finally_scheduler(t->combiner)), + GRPC_ERROR_NONE); } grpc_chttp2_mark_stream_closed(exec_ctx, t, s, true, false, GRPC_ERROR_NONE); diff --git a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/hpack_parser.h b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/hpack_parser.h index a39bf466c..8fbc6a602 100644 --- a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/hpack_parser.h +++ b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/hpack_parser.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -49,14 +34,20 @@ typedef grpc_error *(*grpc_chttp2_hpack_parser_state)( const uint8_t *end); typedef struct { - char *str; - uint32_t length; - uint32_t capacity; + bool copied; + struct { + grpc_slice referenced; + struct { + char *str; + uint32_t length; + uint32_t capacity; + } copied; + } data; } grpc_chttp2_hpack_parser_string; struct grpc_chttp2_hpack_parser { /* user specified callback for each header output */ - void (*on_header)(grpc_exec_ctx *exec_ctx, void *user_data, grpc_mdelem *md); + void (*on_header)(grpc_exec_ctx *exec_ctx, void *user_data, grpc_mdelem md); void *on_header_user_data; grpc_error *last_error; @@ -67,6 +58,8 @@ struct grpc_chttp2_hpack_parser { const grpc_chttp2_hpack_parser_state *next_state; /* what to do after skipping prioritization data */ grpc_chttp2_hpack_parser_state after_prioritization; + /* the refcount of the slice that we're currently parsing */ + grpc_slice_refcount *current_slice_refcount; /* the value we're currently parsing */ union { uint32_t *value; @@ -99,16 +92,16 @@ struct grpc_chttp2_hpack_parser { grpc_chttp2_hptbl table; }; -void grpc_chttp2_hpack_parser_init(grpc_chttp2_hpack_parser *p); -void grpc_chttp2_hpack_parser_destroy(grpc_chttp2_hpack_parser *p); +void grpc_chttp2_hpack_parser_init(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p); +void grpc_chttp2_hpack_parser_destroy(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p); void grpc_chttp2_hpack_parser_set_has_priority(grpc_chttp2_hpack_parser *p); -/* returns 1 on success, 0 on error */ grpc_error *grpc_chttp2_hpack_parser_parse(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_parser *p, - const uint8_t *beg, - const uint8_t *end); + grpc_slice slice); /* wraps grpc_chttp2_hpack_parser_parse to provide a frame level parser for the transport */ diff --git a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/hpack_table.c b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/hpack_table.c index 2dc793d30..944d77801 100644 --- a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/hpack_table.c +++ b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/hpack_table.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -40,9 +25,10 @@ #include #include +#include "src/core/lib/debug/trace.h" #include "src/core/lib/support/murmur_hash.h" -extern int grpc_http_trace; +extern grpc_tracer_flag grpc_http_trace; static struct { const char *key; @@ -179,7 +165,7 @@ static uint32_t entries_for_bytes(uint32_t bytes) { GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD; } -void grpc_chttp2_hptbl_init(grpc_chttp2_hptbl *tbl) { +void grpc_chttp2_hptbl_init(grpc_exec_ctx *exec_ctx, grpc_chttp2_hptbl *tbl) { size_t i; memset(tbl, 0, sizeof(*tbl)); @@ -190,24 +176,29 @@ void grpc_chttp2_hptbl_init(grpc_chttp2_hptbl *tbl) { tbl->ents = gpr_malloc(sizeof(*tbl->ents) * tbl->cap_entries); memset(tbl->ents, 0, sizeof(*tbl->ents) * tbl->cap_entries); for (i = 1; i <= GRPC_CHTTP2_LAST_STATIC_ENTRY; i++) { - tbl->static_ents[i - 1] = - grpc_mdelem_from_strings(static_table[i].key, static_table[i].value); + tbl->static_ents[i - 1] = grpc_mdelem_from_slices( + exec_ctx, + grpc_slice_intern(grpc_slice_from_static_string(static_table[i].key)), + grpc_slice_intern( + grpc_slice_from_static_string(static_table[i].value))); } } -void grpc_chttp2_hptbl_destroy(grpc_chttp2_hptbl *tbl) { +void grpc_chttp2_hptbl_destroy(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hptbl *tbl) { size_t i; for (i = 0; i < GRPC_CHTTP2_LAST_STATIC_ENTRY; i++) { - GRPC_MDELEM_UNREF(tbl->static_ents[i]); + GRPC_MDELEM_UNREF(exec_ctx, tbl->static_ents[i]); } for (i = 0; i < tbl->num_ents; i++) { - GRPC_MDELEM_UNREF(tbl->ents[(tbl->first_ent + i) % tbl->cap_entries]); + GRPC_MDELEM_UNREF(exec_ctx, + tbl->ents[(tbl->first_ent + i) % tbl->cap_entries]); } gpr_free(tbl->ents); } -grpc_mdelem *grpc_chttp2_hptbl_lookup(const grpc_chttp2_hptbl *tbl, - uint32_t tbl_index) { +grpc_mdelem grpc_chttp2_hptbl_lookup(const grpc_chttp2_hptbl *tbl, + uint32_t tbl_index) { /* Static table comes first, just return an entry from it */ if (tbl_index <= GRPC_CHTTP2_LAST_STATIC_ENTRY) { return tbl->static_ents[tbl_index - 1]; @@ -220,24 +211,24 @@ grpc_mdelem *grpc_chttp2_hptbl_lookup(const grpc_chttp2_hptbl *tbl, return tbl->ents[offset]; } /* Invalid entry: return error */ - return NULL; + return GRPC_MDNULL; } /* Evict one element from the table */ -static void evict1(grpc_chttp2_hptbl *tbl) { - grpc_mdelem *first_ent = tbl->ents[tbl->first_ent]; - size_t elem_bytes = GRPC_SLICE_LENGTH(first_ent->key->slice) + - GRPC_SLICE_LENGTH(first_ent->value->slice) + +static void evict1(grpc_exec_ctx *exec_ctx, grpc_chttp2_hptbl *tbl) { + grpc_mdelem first_ent = tbl->ents[tbl->first_ent]; + size_t elem_bytes = GRPC_SLICE_LENGTH(GRPC_MDKEY(first_ent)) + + GRPC_SLICE_LENGTH(GRPC_MDVALUE(first_ent)) + GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD; GPR_ASSERT(elem_bytes <= tbl->mem_used); tbl->mem_used -= (uint32_t)elem_bytes; tbl->first_ent = ((tbl->first_ent + 1) % tbl->cap_entries); tbl->num_ents--; - GRPC_MDELEM_UNREF(first_ent); + GRPC_MDELEM_UNREF(exec_ctx, first_ent); } static void rebuild_ents(grpc_chttp2_hptbl *tbl, uint32_t new_cap) { - grpc_mdelem **ents = gpr_malloc(sizeof(*ents) * new_cap); + grpc_mdelem *ents = gpr_malloc(sizeof(*ents) * new_cap); uint32_t i; for (i = 0; i < tbl->num_ents; i++) { @@ -249,21 +240,23 @@ static void rebuild_ents(grpc_chttp2_hptbl *tbl, uint32_t new_cap) { tbl->first_ent = 0; } -void grpc_chttp2_hptbl_set_max_bytes(grpc_chttp2_hptbl *tbl, +void grpc_chttp2_hptbl_set_max_bytes(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hptbl *tbl, uint32_t max_bytes) { if (tbl->max_bytes == max_bytes) { return; } - if (grpc_http_trace) { + if (GRPC_TRACER_ON(grpc_http_trace)) { gpr_log(GPR_DEBUG, "Update hpack parser max size to %d", max_bytes); } while (tbl->mem_used > max_bytes) { - evict1(tbl); + evict1(exec_ctx, tbl); } tbl->max_bytes = max_bytes; } -grpc_error *grpc_chttp2_hptbl_set_current_table_size(grpc_chttp2_hptbl *tbl, +grpc_error *grpc_chttp2_hptbl_set_current_table_size(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hptbl *tbl, uint32_t bytes) { if (tbl->current_table_bytes == bytes) { return GRPC_ERROR_NONE; @@ -273,15 +266,15 @@ grpc_error *grpc_chttp2_hptbl_set_current_table_size(grpc_chttp2_hptbl *tbl, gpr_asprintf(&msg, "Attempt to make hpack table %d bytes when max is %d bytes", bytes, tbl->max_bytes); - grpc_error *err = GRPC_ERROR_CREATE(msg); + grpc_error *err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg); gpr_free(msg); return err; } - if (grpc_http_trace) { + if (GRPC_TRACER_ON(grpc_http_trace)) { gpr_log(GPR_DEBUG, "Update hpack parser table size to %d", bytes); } while (tbl->mem_used > bytes) { - evict1(tbl); + evict1(exec_ctx, tbl); } tbl->current_table_bytes = bytes; tbl->max_entries = entries_for_bytes(bytes); @@ -296,10 +289,11 @@ grpc_error *grpc_chttp2_hptbl_set_current_table_size(grpc_chttp2_hptbl *tbl, return GRPC_ERROR_NONE; } -grpc_error *grpc_chttp2_hptbl_add(grpc_chttp2_hptbl *tbl, grpc_mdelem *md) { +grpc_error *grpc_chttp2_hptbl_add(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hptbl *tbl, grpc_mdelem md) { /* determine how many bytes of buffer this entry represents */ - size_t elem_bytes = GRPC_SLICE_LENGTH(md->key->slice) + - GRPC_SLICE_LENGTH(md->value->slice) + + size_t elem_bytes = GRPC_SLICE_LENGTH(GRPC_MDKEY(md)) + + GRPC_SLICE_LENGTH(GRPC_MDVALUE(md)) + GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD; if (tbl->current_table_bytes > tbl->max_bytes) { @@ -309,7 +303,7 @@ grpc_error *grpc_chttp2_hptbl_add(grpc_chttp2_hptbl *tbl, grpc_mdelem *md) { "HPACK max table size reduced to %d but not reflected by hpack " "stream (still at %d)", tbl->max_bytes, tbl->current_table_bytes); - grpc_error *err = GRPC_ERROR_CREATE(msg); + grpc_error *err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg); gpr_free(msg); return err; } @@ -326,14 +320,14 @@ grpc_error *grpc_chttp2_hptbl_add(grpc_chttp2_hptbl *tbl, grpc_mdelem *md) { * empty table. */ while (tbl->num_ents) { - evict1(tbl); + evict1(exec_ctx, tbl); } return GRPC_ERROR_NONE; } /* evict entries to ensure no overflow */ while (elem_bytes > (size_t)tbl->current_table_bytes - tbl->mem_used) { - evict1(tbl); + evict1(exec_ctx, tbl); } /* copy the finalized entry in */ @@ -347,16 +341,16 @@ grpc_error *grpc_chttp2_hptbl_add(grpc_chttp2_hptbl *tbl, grpc_mdelem *md) { } grpc_chttp2_hptbl_find_result grpc_chttp2_hptbl_find( - const grpc_chttp2_hptbl *tbl, grpc_mdelem *md) { + const grpc_chttp2_hptbl *tbl, grpc_mdelem md) { grpc_chttp2_hptbl_find_result r = {0, 0}; uint32_t i; /* See if the string is in the static table */ for (i = 0; i < GRPC_CHTTP2_LAST_STATIC_ENTRY; i++) { - grpc_mdelem *ent = tbl->static_ents[i]; - if (md->key != ent->key) continue; + grpc_mdelem ent = tbl->static_ents[i]; + if (!grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDKEY(ent))) continue; r.index = i + 1u; - r.has_value = md->value == ent->value; + r.has_value = grpc_slice_eq(GRPC_MDVALUE(md), GRPC_MDVALUE(ent)); if (r.has_value) return r; } @@ -364,10 +358,10 @@ grpc_chttp2_hptbl_find_result grpc_chttp2_hptbl_find( for (i = 0; i < tbl->num_ents; i++) { uint32_t idx = (uint32_t)(tbl->num_ents - i + GRPC_CHTTP2_LAST_STATIC_ENTRY); - grpc_mdelem *ent = tbl->ents[(tbl->first_ent + i) % tbl->cap_entries]; - if (md->key != ent->key) continue; + grpc_mdelem ent = tbl->ents[(tbl->first_ent + i) % tbl->cap_entries]; + if (!grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDKEY(ent))) continue; r.index = idx; - r.has_value = md->value == ent->value; + r.has_value = grpc_slice_eq(GRPC_MDVALUE(md), GRPC_MDVALUE(ent)); if (r.has_value) return r; } diff --git a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/hpack_table.h b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/hpack_table.h index 2ca130e64..2cf8f6850 100644 --- a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/hpack_table.h +++ b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/hpack_table.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -79,24 +64,27 @@ typedef struct { /* a circular buffer of headers - this is stored in the opposite order to what hpack specifies, in order to simplify table management a little... meaning lookups need to SUBTRACT from the end position */ - grpc_mdelem **ents; - grpc_mdelem *static_ents[GRPC_CHTTP2_LAST_STATIC_ENTRY]; + grpc_mdelem *ents; + grpc_mdelem static_ents[GRPC_CHTTP2_LAST_STATIC_ENTRY]; } grpc_chttp2_hptbl; /* initialize a hpack table */ -void grpc_chttp2_hptbl_init(grpc_chttp2_hptbl *tbl); -void grpc_chttp2_hptbl_destroy(grpc_chttp2_hptbl *tbl); -void grpc_chttp2_hptbl_set_max_bytes(grpc_chttp2_hptbl *tbl, +void grpc_chttp2_hptbl_init(grpc_exec_ctx *exec_ctx, grpc_chttp2_hptbl *tbl); +void grpc_chttp2_hptbl_destroy(grpc_exec_ctx *exec_ctx, grpc_chttp2_hptbl *tbl); +void grpc_chttp2_hptbl_set_max_bytes(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hptbl *tbl, uint32_t max_bytes); -grpc_error *grpc_chttp2_hptbl_set_current_table_size(grpc_chttp2_hptbl *tbl, +grpc_error *grpc_chttp2_hptbl_set_current_table_size(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hptbl *tbl, uint32_t bytes); /* lookup a table entry based on its hpack index */ -grpc_mdelem *grpc_chttp2_hptbl_lookup(const grpc_chttp2_hptbl *tbl, - uint32_t index); +grpc_mdelem grpc_chttp2_hptbl_lookup(const grpc_chttp2_hptbl *tbl, + uint32_t index); /* add a table entry to the index */ -grpc_error *grpc_chttp2_hptbl_add(grpc_chttp2_hptbl *tbl, - grpc_mdelem *md) GRPC_MUST_USE_RESULT; +grpc_error *grpc_chttp2_hptbl_add(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hptbl *tbl, + grpc_mdelem md) GRPC_MUST_USE_RESULT; /* Find a key/value pair in the table... returns the index in the table of the most similar entry, or 0 if the value was not found */ typedef struct { @@ -104,6 +92,6 @@ typedef struct { int has_value; } grpc_chttp2_hptbl_find_result; grpc_chttp2_hptbl_find_result grpc_chttp2_hptbl_find( - const grpc_chttp2_hptbl *tbl, grpc_mdelem *md); + const grpc_chttp2_hptbl *tbl, grpc_mdelem md); #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HPACK_TABLE_H */ diff --git a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/http2_errors.h b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/http2_errors.h deleted file mode 100644 index deab2b7e3..000000000 --- a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/http2_errors.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HTTP2_ERRORS_H -#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HTTP2_ERRORS_H - -/* error codes for RST_STREAM from http2 draft 14 section 7 */ -typedef enum { - GRPC_CHTTP2_NO_ERROR = 0x0, - GRPC_CHTTP2_PROTOCOL_ERROR = 0x1, - GRPC_CHTTP2_INTERNAL_ERROR = 0x2, - GRPC_CHTTP2_FLOW_CONTROL_ERROR = 0x3, - GRPC_CHTTP2_SETTINGS_TIMEOUT = 0x4, - GRPC_CHTTP2_STREAM_CLOSED = 0x5, - GRPC_CHTTP2_FRAME_SIZE_ERROR = 0x6, - GRPC_CHTTP2_REFUSED_STREAM = 0x7, - GRPC_CHTTP2_CANCEL = 0x8, - GRPC_CHTTP2_COMPRESSION_ERROR = 0x9, - GRPC_CHTTP2_CONNECT_ERROR = 0xa, - GRPC_CHTTP2_ENHANCE_YOUR_CALM = 0xb, - GRPC_CHTTP2_INADEQUATE_SECURITY = 0xc, - /* force use of a default clause */ - GRPC_CHTTP2__ERROR_DO_NOT_USE = -1 -} grpc_chttp2_error_code; - -#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HTTP2_ERRORS_H */ diff --git a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/http2_settings.c b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/http2_settings.c new file mode 100644 index 000000000..46b7c0c49 --- /dev/null +++ b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/http2_settings.c @@ -0,0 +1,60 @@ +/* + * Copyright 2017 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. + */ + +/* + * Automatically generated by tools/codegen/core/gen_settings_ids.py + */ + +#include "src/core/ext/transport/chttp2/transport/http2_settings.h" + +#include +#include "src/core/lib/transport/http2_errors.h" + +const uint16_t grpc_setting_id_to_wire_id[] = {1, 2, 3, 4, 5, 6, 65027}; + +bool grpc_wire_id_to_setting_id(uint32_t wire_id, grpc_chttp2_setting_id *out) { + uint32_t i = wire_id - 1; + uint32_t x = i % 256; + uint32_t y = i / 256; + uint32_t h = x; + switch (y) { + case 254: + h += 4; + break; + } + *out = (grpc_chttp2_setting_id)h; + return h < GPR_ARRAY_SIZE(grpc_setting_id_to_wire_id) && + grpc_setting_id_to_wire_id[h] == wire_id; +} + +const grpc_chttp2_setting_parameters + grpc_chttp2_settings_parameters[GRPC_CHTTP2_NUM_SETTINGS] = { + {"HEADER_TABLE_SIZE", 4096u, 0u, 4294967295u, + GRPC_CHTTP2_CLAMP_INVALID_VALUE, GRPC_HTTP2_PROTOCOL_ERROR}, + {"ENABLE_PUSH", 1u, 0u, 1u, GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE, + GRPC_HTTP2_PROTOCOL_ERROR}, + {"MAX_CONCURRENT_STREAMS", 4294967295u, 0u, 4294967295u, + GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE, GRPC_HTTP2_PROTOCOL_ERROR}, + {"INITIAL_WINDOW_SIZE", 65535u, 0u, 2147483647u, + GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE, + GRPC_HTTP2_FLOW_CONTROL_ERROR}, + {"MAX_FRAME_SIZE", 16384u, 16384u, 16777215u, + GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE, GRPC_HTTP2_PROTOCOL_ERROR}, + {"MAX_HEADER_LIST_SIZE", 16777216u, 0u, 16777216u, + GRPC_CHTTP2_CLAMP_INVALID_VALUE, GRPC_HTTP2_PROTOCOL_ERROR}, + {"GRPC_ALLOW_TRUE_BINARY_METADATA", 0u, 0u, 1u, + GRPC_CHTTP2_CLAMP_INVALID_VALUE, GRPC_HTTP2_PROTOCOL_ERROR}, +}; diff --git a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/http2_settings.h b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/http2_settings.h new file mode 100644 index 000000000..706dfc313 --- /dev/null +++ b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/http2_settings.h @@ -0,0 +1,59 @@ +/* + * Copyright 2017 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. + */ + +/* + * Automatically generated by tools/codegen/core/gen_settings_ids.py + */ + +#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HTTP2_SETTINGS_H +#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HTTP2_SETTINGS_H + +#include +#include + +typedef enum { + GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE = 0, /* wire id 1 */ + GRPC_CHTTP2_SETTINGS_ENABLE_PUSH = 1, /* wire id 2 */ + GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS = 2, /* wire id 3 */ + GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE = 3, /* wire id 4 */ + GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE = 4, /* wire id 5 */ + GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE = 5, /* wire id 6 */ + GRPC_CHTTP2_SETTINGS_GRPC_ALLOW_TRUE_BINARY_METADATA = 6, /* wire id 65027 */ +} grpc_chttp2_setting_id; + +#define GRPC_CHTTP2_NUM_SETTINGS 7 +extern const uint16_t grpc_setting_id_to_wire_id[]; + +bool grpc_wire_id_to_setting_id(uint32_t wire_id, grpc_chttp2_setting_id *out); + +typedef enum { + GRPC_CHTTP2_CLAMP_INVALID_VALUE, + GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE +} grpc_chttp2_invalid_value_behavior; + +typedef struct { + const char *name; + uint32_t default_value; + uint32_t min_value; + uint32_t max_value; + grpc_chttp2_invalid_value_behavior invalid_value_behavior; + uint32_t error_value; +} grpc_chttp2_setting_parameters; + +extern const grpc_chttp2_setting_parameters + grpc_chttp2_settings_parameters[GRPC_CHTTP2_NUM_SETTINGS]; + +#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HTTP2_SETTINGS_H */ diff --git a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/huffsyms.c b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/huffsyms.c index 68b34e4e2..f28d8cc30 100644 --- a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/huffsyms.c +++ b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/huffsyms.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/huffsyms.h b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/huffsyms.h index fee00954a..2e2a5daca 100644 --- a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/huffsyms.h +++ b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/huffsyms.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/incoming_metadata.c b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/incoming_metadata.c index 3e463a799..cf0a9ca92 100644 --- a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/incoming_metadata.c +++ b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/incoming_metadata.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -41,57 +26,48 @@ #include void grpc_chttp2_incoming_metadata_buffer_init( - grpc_chttp2_incoming_metadata_buffer *buffer) { - buffer->deadline = gpr_inf_future(GPR_CLOCK_REALTIME); + grpc_chttp2_incoming_metadata_buffer *buffer, gpr_arena *arena) { + buffer->arena = arena; + grpc_metadata_batch_init(&buffer->batch); + buffer->batch.deadline = gpr_inf_future(GPR_CLOCK_REALTIME); } void grpc_chttp2_incoming_metadata_buffer_destroy( - grpc_chttp2_incoming_metadata_buffer *buffer) { - size_t i; - if (!buffer->published) { - for (i = 0; i < buffer->count; i++) { - GRPC_MDELEM_UNREF(buffer->elems[i].md); - } - } - gpr_free(buffer->elems); + grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_metadata_buffer *buffer) { + grpc_metadata_batch_destroy(exec_ctx, &buffer->batch); } -void grpc_chttp2_incoming_metadata_buffer_add( - grpc_chttp2_incoming_metadata_buffer *buffer, grpc_mdelem *elem) { - GPR_ASSERT(!buffer->published); - if (buffer->capacity == buffer->count) { - buffer->capacity = GPR_MAX(8, 2 * buffer->capacity); - buffer->elems = - gpr_realloc(buffer->elems, sizeof(*buffer->elems) * buffer->capacity); - } - buffer->elems[buffer->count++].md = elem; +grpc_error *grpc_chttp2_incoming_metadata_buffer_add( + grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_metadata_buffer *buffer, + grpc_mdelem elem) { buffer->size += GRPC_MDELEM_LENGTH(elem); + return grpc_metadata_batch_add_tail( + exec_ctx, &buffer->batch, + gpr_arena_alloc(buffer->arena, sizeof(grpc_linked_mdelem)), elem); +} + +grpc_error *grpc_chttp2_incoming_metadata_buffer_replace_or_add( + grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_metadata_buffer *buffer, + grpc_mdelem elem) { + for (grpc_linked_mdelem *l = buffer->batch.list.head; l != NULL; + l = l->next) { + if (grpc_slice_eq(GRPC_MDKEY(l->md), GRPC_MDKEY(elem))) { + GRPC_MDELEM_UNREF(exec_ctx, l->md); + l->md = elem; + return GRPC_ERROR_NONE; + } + } + return grpc_chttp2_incoming_metadata_buffer_add(exec_ctx, buffer, elem); } void grpc_chttp2_incoming_metadata_buffer_set_deadline( grpc_chttp2_incoming_metadata_buffer *buffer, gpr_timespec deadline) { - GPR_ASSERT(!buffer->published); - buffer->deadline = deadline; + buffer->batch.deadline = deadline; } void grpc_chttp2_incoming_metadata_buffer_publish( - grpc_chttp2_incoming_metadata_buffer *buffer, grpc_metadata_batch *batch) { - GPR_ASSERT(!buffer->published); - buffer->published = 1; - if (buffer->count > 0) { - size_t i; - for (i = 1; i < buffer->count; i++) { - buffer->elems[i].prev = &buffer->elems[i - 1]; - } - for (i = 0; i < buffer->count - 1; i++) { - buffer->elems[i].next = &buffer->elems[i + 1]; - } - buffer->elems[0].prev = NULL; - buffer->elems[buffer->count - 1].next = NULL; - batch->list.head = &buffer->elems[0]; - batch->list.tail = &buffer->elems[buffer->count - 1]; - } else { - batch->list.head = batch->list.tail = NULL; - } - batch->deadline = buffer->deadline; + grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_metadata_buffer *buffer, + grpc_metadata_batch *batch) { + *batch = buffer->batch; + grpc_metadata_batch_init(&buffer->batch); } diff --git a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/incoming_metadata.h b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/incoming_metadata.h index df4343b93..a951d8764 100644 --- a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/incoming_metadata.h +++ b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/incoming_metadata.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -37,24 +22,26 @@ #include "src/core/lib/transport/transport.h" typedef struct { - grpc_linked_mdelem *elems; - size_t count; - size_t capacity; - gpr_timespec deadline; - int published; + gpr_arena *arena; + grpc_metadata_batch batch; size_t size; // total size of metadata } grpc_chttp2_incoming_metadata_buffer; /** assumes everything initially zeroed */ void grpc_chttp2_incoming_metadata_buffer_init( - grpc_chttp2_incoming_metadata_buffer *buffer); + grpc_chttp2_incoming_metadata_buffer *buffer, gpr_arena *arena); void grpc_chttp2_incoming_metadata_buffer_destroy( - grpc_chttp2_incoming_metadata_buffer *buffer); + grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_metadata_buffer *buffer); void grpc_chttp2_incoming_metadata_buffer_publish( - grpc_chttp2_incoming_metadata_buffer *buffer, grpc_metadata_batch *batch); + grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_metadata_buffer *buffer, + grpc_metadata_batch *batch); -void grpc_chttp2_incoming_metadata_buffer_add( - grpc_chttp2_incoming_metadata_buffer *buffer, grpc_mdelem *elem); +grpc_error *grpc_chttp2_incoming_metadata_buffer_add( + grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_metadata_buffer *buffer, + grpc_mdelem elem) GRPC_MUST_USE_RESULT; +grpc_error *grpc_chttp2_incoming_metadata_buffer_replace_or_add( + grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_metadata_buffer *buffer, + grpc_mdelem elem) GRPC_MUST_USE_RESULT; void grpc_chttp2_incoming_metadata_buffer_set_deadline( grpc_chttp2_incoming_metadata_buffer *buffer, gpr_timespec deadline); diff --git a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/internal.h b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/internal.h index b727965d4..3c41a8958 100644 --- a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/internal.h +++ b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/internal.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -48,9 +33,13 @@ #include "src/core/ext/transport/chttp2/transport/hpack_parser.h" #include "src/core/ext/transport/chttp2/transport/incoming_metadata.h" #include "src/core/ext/transport/chttp2/transport/stream_map.h" +#include "src/core/lib/compression/stream_compression.h" #include "src/core/lib/iomgr/combiner.h" #include "src/core/lib/iomgr/endpoint.h" +#include "src/core/lib/iomgr/timer.h" +#include "src/core/lib/transport/bdp_estimator.h" #include "src/core/lib/transport/connectivity_state.h" +#include "src/core/lib/transport/pid_controller.h" #include "src/core/lib/transport/transport_impl.h" /* streams are kept in various linked lists depending on what things need to @@ -59,6 +48,7 @@ typedef enum { GRPC_CHTTP2_LIST_WRITABLE, GRPC_CHTTP2_LIST_WRITING, GRPC_CHTTP2_LIST_STALLED_BY_TRANSPORT, + GRPC_CHTTP2_LIST_STALLED_BY_STREAM, /** streams that are waiting to start because there are too many concurrent streams on the connection */ GRPC_CHTTP2_LIST_WAITING_FOR_CONCURRENCY, @@ -69,9 +59,50 @@ typedef enum { GRPC_CHTTP2_WRITE_STATE_IDLE, GRPC_CHTTP2_WRITE_STATE_WRITING, GRPC_CHTTP2_WRITE_STATE_WRITING_WITH_MORE, - GRPC_CHTTP2_WRITE_STATE_WRITING_WITH_MORE_AND_COVERED_BY_POLLER, } grpc_chttp2_write_state; +typedef enum { + GRPC_CHTTP2_PING_ON_NEXT_WRITE = 0, + GRPC_CHTTP2_PING_BEFORE_TRANSPORT_WINDOW_UPDATE, + GRPC_CHTTP2_PING_TYPE_COUNT /* must be last */ +} grpc_chttp2_ping_type; + +typedef enum { + GRPC_CHTTP2_OPTIMIZE_FOR_LATENCY, + GRPC_CHTTP2_OPTIMIZE_FOR_THROUGHPUT, +} grpc_chttp2_optimization_target; + +typedef enum { + GRPC_CHTTP2_PCL_INITIATE = 0, + GRPC_CHTTP2_PCL_NEXT, + GRPC_CHTTP2_PCL_INFLIGHT, + GRPC_CHTTP2_PCL_COUNT /* must be last */ +} grpc_chttp2_ping_closure_list; + +typedef struct { + grpc_closure_list lists[GRPC_CHTTP2_PCL_COUNT]; + uint64_t inflight_id; +} grpc_chttp2_ping_queue; + +typedef struct { + gpr_timespec min_time_between_pings; + int max_pings_without_data; + int max_ping_strikes; + gpr_timespec min_ping_interval_without_data; +} grpc_chttp2_repeated_ping_policy; + +typedef struct { + gpr_timespec last_ping_sent_time; + int pings_before_data_required; + grpc_timer delayed_ping_timer; + bool is_delayed_ping_timer_set; +} grpc_chttp2_repeated_ping_state; + +typedef struct { + gpr_timespec last_ping_recv_time; + int ping_strikes; +} grpc_chttp2_server_ping_recv_state; + /* deframer state for the overall http2 stream of bytes */ typedef enum { /* prefix: one entry per http2 connection prefix byte */ @@ -144,14 +175,6 @@ typedef enum { GRPC_CHTTP2_GOAWAY_SENT, } grpc_chttp2_sent_goaway_state; -/* Outstanding ping request data */ -typedef struct grpc_chttp2_outstanding_ping { - uint8_t id[8]; - grpc_closure *on_recv; - struct grpc_chttp2_outstanding_ping *next; - struct grpc_chttp2_outstanding_ping *prev; -} grpc_chttp2_outstanding_ping; - typedef struct grpc_chttp2_write_cb { int64_t call_at_byte; grpc_closure *closure; @@ -162,22 +185,20 @@ typedef struct grpc_chttp2_write_cb { struct grpc_chttp2_incoming_byte_stream { grpc_byte_stream base; gpr_refcount refs; - struct grpc_chttp2_incoming_byte_stream *next_message; - grpc_error *error; - grpc_chttp2_transport *transport; - grpc_chttp2_stream *stream; - bool is_tail; + grpc_chttp2_transport *transport; /* immutable */ + grpc_chttp2_stream *stream; /* immutable */ - gpr_mu slice_mu; // protects slices, on_next - grpc_slice_buffer slices; - grpc_closure *on_next; - grpc_slice *next; + /* Accessed only by transport thread when stream->pending_byte_stream == false + * Accessed only by application thread when stream->pending_byte_stream == + * true */ uint32_t remaining_bytes; + /* Accessed only by transport thread when stream->pending_byte_stream == false + * Accessed only by application thread when stream->pending_byte_stream == + * true */ struct { grpc_closure closure; - grpc_slice *slice; size_t max_size_hint; grpc_closure *on_complete; } next_action; @@ -185,6 +206,52 @@ struct grpc_chttp2_incoming_byte_stream { grpc_closure finished_action; }; +typedef enum { + GRPC_CHTTP2_KEEPALIVE_STATE_WAITING, + GRPC_CHTTP2_KEEPALIVE_STATE_PINGING, + GRPC_CHTTP2_KEEPALIVE_STATE_DYING, + GRPC_CHTTP2_KEEPALIVE_STATE_DISABLED, +} grpc_chttp2_keepalive_state; + +typedef struct { + /** initial window change. This is tracked as we parse settings frames from + * the remote peer. If there is a positive delta, then we will make all + * streams readable since they may have become unstalled */ + int64_t initial_window_update; + + /** Our bookkeeping for the remote peer's available window */ + int64_t remote_window; + + /** calculating what we should give for local window: + we track the total amount of flow control over initial window size + across all streams: this is data that we want to receive right now (it + has an outstanding read) + and the total amount of flow control under initial window size across all + streams: this is data we've read early + we want to adjust incoming_window such that: + incoming_window = total_over - max(bdp - total_under, 0) */ + int64_t announced_stream_total_over_incoming_window; + int64_t announced_stream_total_under_incoming_window; + + /** This is out window according to what we have sent to our remote peer. The + * difference between this and target window is what we use to decide when + * to send WINDOW_UPDATE frames. */ + int64_t announced_window; + + /** should we probe bdp? */ + bool enable_bdp_probe; + + /* bdp estimation */ + grpc_bdp_estimator bdp_estimator; + + /* pid controller */ + grpc_pid_controller pid_controller; + gpr_timespec last_pid_update; + + // pointer back to transport for tracing + const grpc_chttp2_transport *t; +} grpc_chttp2_transport_flowctl; + struct grpc_chttp2_transport { grpc_transport base; /* must be first */ gpr_refcount refs; @@ -204,6 +271,8 @@ struct grpc_chttp2_transport { /** is there a read request to the endpoint outstanding? */ uint8_t endpoint_reading; + grpc_chttp2_optimization_target opt_target; + /** various lists of streams */ grpc_chttp2_stream_list lists[STREAM_LIST_COUNT]; @@ -212,10 +281,8 @@ struct grpc_chttp2_transport { grpc_closure write_action_begin_locked; grpc_closure write_action; - grpc_closure write_action_end; grpc_closure write_action_end_locked; - grpc_closure read_action_begin; grpc_closure read_action_locked; /** incoming read bytes */ @@ -240,17 +307,15 @@ struct grpc_chttp2_transport { grpc_slice_buffer outbuf; /** hpack encoding */ grpc_chttp2_hpack_compressor hpack_compressor; - int64_t outgoing_window; /** is this a client? */ uint8_t is_client; /** data to write next write */ grpc_slice_buffer qbuf; - /** window available to announce to peer */ - int64_t announce_incoming_window; - /** how much window would we like to have for incoming_window */ - uint32_t connection_window_target; + /** how much data are we willing to buffer when the WRITE_BUFFER_HINT is set? + */ + uint32_t write_buffer_size; /** have we seen a goaway */ uint8_t seen_goaway; @@ -270,16 +335,21 @@ struct grpc_chttp2_transport { copied to next_stream_id in parsing when parsing commences */ uint32_t next_stream_id; - /** how far to lookahead in a stream? */ - uint32_t stream_lookahead; - /** last new stream id */ uint32_t last_new_stream_id; - /** pings awaiting responses */ - grpc_chttp2_outstanding_ping pings; - /** next payload for an outgoing ping */ - uint64_t ping_counter; + /** ping queues for various ping insertion points */ + grpc_chttp2_ping_queue ping_queues[GRPC_CHTTP2_PING_TYPE_COUNT]; + grpc_chttp2_repeated_ping_policy ping_policy; + grpc_chttp2_repeated_ping_state ping_state; + uint64_t ping_ctr; /* unique id for pings */ + grpc_closure retry_initiate_ping_locked; + + /** ping acks */ + size_t ping_ack_count; + size_t ping_ack_capacity; + uint64_t *ping_acks; + grpc_chttp2_server_ping_recv_state ping_recv_state; /** parser for headers */ grpc_chttp2_hpack_parser hpack_parser; @@ -293,11 +363,7 @@ struct grpc_chttp2_transport { /** parser for goaway frames */ grpc_chttp2_goaway_parser goaway_parser; - /** initial window change */ - int64_t initial_window_update; - - /** window available for peer to send to us */ - int64_t incoming_window; + grpc_chttp2_transport_flowctl flow_control; /* deframing */ grpc_chttp2_deframe_transport_state deframe_state; @@ -323,6 +389,10 @@ struct grpc_chttp2_transport { grpc_chttp2_write_cb *write_cb_pool; + /* bdp estimator */ + grpc_closure start_bdp_ping_locked; + grpc_closure finish_bdp_ping_locked; + /* if non-NULL, close the transport with this error when writes are finished */ grpc_error *close_transport_on_writes_finished; @@ -336,11 +406,31 @@ struct grpc_chttp2_transport { /** have we scheduled a destructive cleanup? */ bool destructive_reclaimer_registered; /** benign cleanup closure */ - grpc_closure benign_reclaimer; grpc_closure benign_reclaimer_locked; /** destructive cleanup closure */ - grpc_closure destructive_reclaimer; grpc_closure destructive_reclaimer_locked; + + /* keep-alive ping support */ + /** Closure to initialize a keepalive ping */ + grpc_closure init_keepalive_ping_locked; + /** Closure to run when the keepalive ping is sent */ + grpc_closure start_keepalive_ping_locked; + /** Cousure to run when the keepalive ping ack is received */ + grpc_closure finish_keepalive_ping_locked; + /** Closrue to run when the keepalive ping timeouts */ + grpc_closure keepalive_watchdog_fired_locked; + /** timer to initiate ping events */ + grpc_timer keepalive_ping_timer; + /** watchdog to kill the transport when waiting for the keepalive ping */ + grpc_timer keepalive_watchdog_timer; + /** time duration in between pings */ + gpr_timespec keepalive_time; + /** grace period for a ping to complete before watchdog kicks in */ + gpr_timespec keepalive_timeout; + /** if keepalive pings are allowed when there's no outstanding streams */ + bool keepalive_permit_without_calls; + /** keep-alive state machine state */ + grpc_chttp2_keepalive_state keepalive_state; }; typedef enum { @@ -350,12 +440,31 @@ typedef enum { GPRC_METADATA_PUBLISHED_AT_CLOSE } grpc_published_metadata_method; +typedef struct { + /** window available for us to send to peer, over or under the initial window + * size of the transport... ie: + * remote_window = remote_window_delta + transport.initial_window_size */ + int64_t remote_window_delta; + + /** window available for peer to send to us (as a delta on + * transport.initial_window_size) + * local_window = local_window_delta + transport.initial_window_size */ + int64_t local_window_delta; + + /** window available for peer to send to us over this stream that we have + * announced to the peer */ + int64_t announced_window_delta; + + // read only pointer back to stream for data + const grpc_chttp2_stream *s; +} grpc_chttp2_stream_flowctl; + struct grpc_chttp2_stream { grpc_chttp2_transport *t; grpc_stream_refcount *refcount; grpc_closure destroy_stream; - void *destroy_stream_arg; + grpc_closure *destroy_stream_arg; grpc_chttp2_stream_link links[STREAM_LIST_COUNT]; uint8_t included[STREAM_LIST_COUNT]; @@ -363,12 +472,6 @@ struct grpc_chttp2_stream { /** HTTP2 stream id for this stream, or zero if one has not been assigned */ uint32_t id; - /** window available for us to send to peer */ - int64_t outgoing_window; - /** The number of bytes the upper layers have offered to receive. - As the upper layer offers more bytes, this value increases. - As bytes are read, this value decreases. */ - uint32_t max_recv_bytes; /** things the upper layers would like to send */ grpc_metadata_batch *send_initial_metadata; grpc_closure *send_initial_metadata_finished; @@ -380,13 +483,12 @@ struct grpc_chttp2_stream { grpc_slice fetching_slice; int64_t next_message_end_offset; int64_t flow_controlled_bytes_written; - bool complete_fetch_covered_by_poller; - grpc_closure complete_fetch; grpc_closure complete_fetch_locked; grpc_closure *fetching_send_message_finished; grpc_metadata_batch *recv_initial_metadata; grpc_closure *recv_initial_metadata_ready; + bool *trailing_metadata_available; grpc_byte_stream **recv_message; grpc_closure *recv_message_ready; grpc_metadata_batch *recv_trailing_metadata; @@ -395,9 +497,6 @@ struct grpc_chttp2_stream { grpc_transport_stream_stats *collecting_stats; grpc_transport_stream_stats stats; - /** number of streams that are currently being read */ - gpr_refcount active_streams; - /** Is this stream closed for writing. */ bool write_closed; /** Is this stream reading half-closed. */ @@ -407,6 +506,9 @@ struct grpc_chttp2_stream { /** Has this stream seen an error. If true, then pending incoming frames can be thrown away. */ bool seen_error; + /** Are we buffering writes on this stream? If yes, we won't become writable + until there's enough queued up in the flow_controlled_buffer */ + bool write_buffering; /** the error that resulted in this stream being read-closed */ grpc_error *read_closed_error; @@ -418,7 +520,17 @@ struct grpc_chttp2_stream { grpc_chttp2_incoming_metadata_buffer metadata_buffer[2]; - grpc_chttp2_incoming_frame_queue incoming_frames; + grpc_slice_buffer frame_storage; /* protected by t combiner */ + + /* Accessed only by transport thread when stream->pending_byte_stream == false + * Accessed only by application thread when stream->pending_byte_stream == + * true */ + grpc_slice_buffer unprocessed_incoming_frames_buffer; + grpc_closure *on_next; /* protected by t combiner */ + bool pending_byte_stream; /* protected by t combiner */ + grpc_closure reset_byte_stream; + grpc_error *byte_stream_error; /* protected by t combiner */ + bool received_last_frame; /* protected by t combiner */ gpr_timespec deadline; @@ -426,22 +538,44 @@ struct grpc_chttp2_stream { grpc_error *forced_close_error; /** how many header frames have we received? */ uint8_t header_frames_received; - /** window available for peer to send to us */ - int64_t incoming_window; /** parsing state for data frames */ + /* Accessed only by transport thread when stream->pending_byte_stream == false + * Accessed only by application thread when stream->pending_byte_stream == + * true */ grpc_chttp2_data_parser data_parser; /** number of bytes received - reset at end of parse thread execution */ int64_t received_bytes; bool sent_initial_metadata; bool sent_trailing_metadata; - /** how much window should we announce? */ - uint32_t announce_window; + + grpc_chttp2_stream_flowctl flow_control; + grpc_slice_buffer flow_controlled_buffer; grpc_chttp2_write_cb *on_write_finished_cbs; grpc_chttp2_write_cb *finish_after_write; size_t sending_bytes; + + /** Whether stream compression send is enabled */ + bool stream_compression_recv_enabled; + /** Whether stream compression recv is enabled */ + bool stream_compression_send_enabled; + /** Whether bytes stored in unprocessed_incoming_byte_stream is decompressed + */ + bool unprocessed_incoming_frames_decompressed; + /** Stream compression decompress context */ + grpc_stream_compression_context *stream_decompression_ctx; + /** Stream compression compress context */ + grpc_stream_compression_context *stream_compression_ctx; + + /** Buffer storing data that is compressed but not sent */ + grpc_slice_buffer *compressed_data_buffer; + /** Amount of uncompressed bytes sent out when compressed_data_buffer is + * emptied */ + size_t uncompressed_data_size; + /** Temporary buffer storing decompressed data */ + grpc_slice_buffer *decompressed_data_buffer; }; /** Transport writing call flow: @@ -457,12 +591,16 @@ struct grpc_chttp2_stream { The actual call chain is documented in the implementation of this function. */ void grpc_chttp2_initiate_write(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport *t, - bool covered_by_poller, const char *reason); + grpc_chttp2_transport *t, const char *reason); + +typedef enum { + GRPC_CHTTP2_NOTHING_TO_WRITE, + GRPC_CHTTP2_PARTIAL_WRITE, + GRPC_CHTTP2_FULL_WRITE, +} grpc_chttp2_begin_write_result; -/** Someone is unlocking the transport mutex: check to see if writes - are required, and frame them if so */ -bool grpc_chttp2_begin_write(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t); +grpc_chttp2_begin_write_result grpc_chttp2_begin_write( + grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t); void grpc_chttp2_end_write(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, grpc_error *error); @@ -476,36 +614,118 @@ bool grpc_chttp2_list_add_writable_stream(grpc_chttp2_transport *t, grpc_chttp2_stream *s); /** Get a writable stream returns non-zero if there was a stream available */ -int grpc_chttp2_list_pop_writable_stream(grpc_chttp2_transport *t, - grpc_chttp2_stream **s); +bool grpc_chttp2_list_pop_writable_stream(grpc_chttp2_transport *t, + grpc_chttp2_stream **s); bool grpc_chttp2_list_remove_writable_stream( grpc_chttp2_transport *t, grpc_chttp2_stream *s) GRPC_MUST_USE_RESULT; bool grpc_chttp2_list_add_writing_stream(grpc_chttp2_transport *t, grpc_chttp2_stream *s); -int grpc_chttp2_list_have_writing_streams(grpc_chttp2_transport *t); -int grpc_chttp2_list_pop_writing_stream(grpc_chttp2_transport *t, - grpc_chttp2_stream **s); +bool grpc_chttp2_list_have_writing_streams(grpc_chttp2_transport *t); +bool grpc_chttp2_list_pop_writing_stream(grpc_chttp2_transport *t, + grpc_chttp2_stream **s); void grpc_chttp2_list_add_written_stream(grpc_chttp2_transport *t, grpc_chttp2_stream *s); -int grpc_chttp2_list_pop_written_stream(grpc_chttp2_transport *t, - grpc_chttp2_stream **s); +bool grpc_chttp2_list_pop_written_stream(grpc_chttp2_transport *t, + grpc_chttp2_stream **s); void grpc_chttp2_list_add_waiting_for_concurrency(grpc_chttp2_transport *t, grpc_chttp2_stream *s); -int grpc_chttp2_list_pop_waiting_for_concurrency(grpc_chttp2_transport *t, - grpc_chttp2_stream **s); +bool grpc_chttp2_list_pop_waiting_for_concurrency(grpc_chttp2_transport *t, + grpc_chttp2_stream **s); void grpc_chttp2_list_remove_waiting_for_concurrency(grpc_chttp2_transport *t, grpc_chttp2_stream *s); void grpc_chttp2_list_add_stalled_by_transport(grpc_chttp2_transport *t, grpc_chttp2_stream *s); -int grpc_chttp2_list_pop_stalled_by_transport(grpc_chttp2_transport *t, - grpc_chttp2_stream **s); +bool grpc_chttp2_list_pop_stalled_by_transport(grpc_chttp2_transport *t, + grpc_chttp2_stream **s); void grpc_chttp2_list_remove_stalled_by_transport(grpc_chttp2_transport *t, grpc_chttp2_stream *s); +void grpc_chttp2_list_add_stalled_by_stream(grpc_chttp2_transport *t, + grpc_chttp2_stream *s); +bool grpc_chttp2_list_pop_stalled_by_stream(grpc_chttp2_transport *t, + grpc_chttp2_stream **s); +bool grpc_chttp2_list_remove_stalled_by_stream(grpc_chttp2_transport *t, + grpc_chttp2_stream *s); + +/********* Flow Control ***************/ + +// we have sent data on the wire +void grpc_chttp2_flowctl_sent_data(grpc_chttp2_transport_flowctl *tfc, + grpc_chttp2_stream_flowctl *sfc, + int64_t size); + +// we have received data from the wire +grpc_error *grpc_chttp2_flowctl_recv_data(grpc_chttp2_transport_flowctl *tfc, + grpc_chttp2_stream_flowctl *sfc, + int64_t incoming_frame_size); + +// returns an announce if we should send a transport update to our peer, +// else returns zero +uint32_t grpc_chttp2_flowctl_maybe_send_transport_update( + grpc_chttp2_transport_flowctl *tfc); + +// returns an announce if we should send a stream update to our peer, else +// returns zero +uint32_t grpc_chttp2_flowctl_maybe_send_stream_update( + grpc_chttp2_transport_flowctl *tfc, grpc_chttp2_stream_flowctl *sfc); + +// we have received a WINDOW_UPDATE frame for a transport +void grpc_chttp2_flowctl_recv_transport_update( + grpc_chttp2_transport_flowctl *tfc, uint32_t size); + +// we have received a WINDOW_UPDATE frame for a stream +void grpc_chttp2_flowctl_recv_stream_update(grpc_chttp2_transport_flowctl *tfc, + grpc_chttp2_stream_flowctl *sfc, + uint32_t size); + +// the application is asking for a certain amount of bytes +void grpc_chttp2_flowctl_incoming_bs_update(grpc_chttp2_transport_flowctl *tfc, + grpc_chttp2_stream_flowctl *sfc, + size_t max_size_hint, + size_t have_already); + +void grpc_chttp2_flowctl_destroy_stream(grpc_chttp2_transport_flowctl *tfc, + grpc_chttp2_stream_flowctl *sfc); + +typedef enum { + // Nothing to be done. + GRPC_CHTTP2_FLOWCTL_NO_ACTION_NEEDED = 0, + // Initiate a write to update the initial window immediately. + GRPC_CHTTP2_FLOWCTL_UPDATE_IMMEDIATELY, + // Push the flow control update into a send buffer, to be sent + // out the next time a write is initiated. + GRPC_CHTTP2_FLOWCTL_QUEUE_UPDATE, +} grpc_chttp2_flowctl_urgency; + +typedef struct { + grpc_chttp2_flowctl_urgency send_stream_update; + grpc_chttp2_flowctl_urgency send_transport_update; + grpc_chttp2_flowctl_urgency send_setting_update; + uint32_t initial_window_size; + uint32_t max_frame_size; + bool need_ping; +} grpc_chttp2_flowctl_action; + +// Reads the flow control data and returns and actionable struct that will tell +// chttp2 exactly what it needs to do +grpc_chttp2_flowctl_action grpc_chttp2_flowctl_get_action( + grpc_chttp2_transport_flowctl *tfc, grpc_chttp2_stream_flowctl *sfc); + +grpc_chttp2_flowctl_action grpc_chttp2_flowctl_get_bdp_action( + grpc_chttp2_transport_flowctl *tfc); + +// Takes in a flow control action and performs all the needed operations. +void grpc_chttp2_act_on_flowctl_action(grpc_exec_ctx *exec_ctx, + grpc_chttp2_flowctl_action action, + grpc_chttp2_transport *t, + grpc_chttp2_stream *s); + +/********* End of Flow Control ***************/ + grpc_chttp2_stream *grpc_chttp2_parsing_lookup_stream(grpc_chttp2_transport *t, uint32_t id); grpc_chttp2_stream *grpc_chttp2_parsing_accept_stream(grpc_exec_ctx *exec_ctx, @@ -526,98 +746,34 @@ void grpc_chttp2_complete_closure_step(grpc_exec_ctx *exec_ctx, grpc_closure **pclosure, grpc_error *error, const char *desc); +#define GRPC_HEADER_SIZE_IN_BYTES 5 +#define MAX_SIZE_T (~(size_t)0) + #define GRPC_CHTTP2_CLIENT_CONNECT_STRING "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" #define GRPC_CHTTP2_CLIENT_CONNECT_STRLEN \ (sizeof(GRPC_CHTTP2_CLIENT_CONNECT_STRING) - 1) -extern int grpc_http_trace; -extern int grpc_flowctl_trace; +extern grpc_tracer_flag grpc_http_trace; +extern grpc_tracer_flag grpc_flowctl_trace; -#define GRPC_CHTTP2_IF_TRACING(stmt) \ - if (!(grpc_http_trace)) \ - ; \ - else \ +#ifndef NDEBUG +#define GRPC_FLOW_CONTROL_IF_TRACING(stmt) \ + if (!(GRPC_TRACER_ON(grpc_flowctl_trace))) \ + ; \ + else \ stmt +#else +#define GRPC_FLOW_CONTROL_IF_TRACING(stmt) +#endif -typedef enum { - GRPC_CHTTP2_FLOWCTL_MOVE, - GRPC_CHTTP2_FLOWCTL_CREDIT, - GRPC_CHTTP2_FLOWCTL_DEBIT -} grpc_chttp2_flowctl_op; - -#define GRPC_CHTTP2_FLOW_MOVE_COMMON(phase, transport, id1, id2, dst_context, \ - dst_var, src_context, src_var) \ - do { \ - assert(id1 == id2); \ - if (grpc_flowctl_trace) { \ - grpc_chttp2_flowctl_trace( \ - __FILE__, __LINE__, phase, GRPC_CHTTP2_FLOWCTL_MOVE, #dst_context, \ - #dst_var, #src_context, #src_var, transport->is_client, id1, \ - dst_context->dst_var, src_context->src_var); \ - } \ - dst_context->dst_var += src_context->src_var; \ - src_context->src_var = 0; \ - } while (0) - -#define GRPC_CHTTP2_FLOW_MOVE_STREAM(phase, transport, dst_context, dst_var, \ - src_context, src_var) \ - GRPC_CHTTP2_FLOW_MOVE_COMMON(phase, transport, dst_context->id, \ - src_context->id, dst_context, dst_var, \ - src_context, src_var) -#define GRPC_CHTTP2_FLOW_MOVE_TRANSPORT(phase, dst_context, dst_var, \ - src_context, src_var) \ - GRPC_CHTTP2_FLOW_MOVE_COMMON(phase, dst_context, 0, 0, dst_context, dst_var, \ - src_context, src_var) - -#define GRPC_CHTTP2_FLOW_CREDIT_COMMON(phase, transport, id, dst_context, \ - dst_var, amount) \ - do { \ - if (grpc_flowctl_trace) { \ - grpc_chttp2_flowctl_trace(__FILE__, __LINE__, phase, \ - GRPC_CHTTP2_FLOWCTL_CREDIT, #dst_context, \ - #dst_var, NULL, #amount, transport->is_client, \ - id, dst_context->dst_var, amount); \ - } \ - dst_context->dst_var += amount; \ - } while (0) - -#define GRPC_CHTTP2_FLOW_CREDIT_STREAM(phase, transport, dst_context, dst_var, \ - amount) \ - GRPC_CHTTP2_FLOW_CREDIT_COMMON(phase, transport, dst_context->id, \ - dst_context, dst_var, amount) -#define GRPC_CHTTP2_FLOW_CREDIT_TRANSPORT(phase, dst_context, dst_var, amount) \ - GRPC_CHTTP2_FLOW_CREDIT_COMMON(phase, dst_context, 0, dst_context, dst_var, \ - amount) - -#define GRPC_CHTTP2_FLOW_DEBIT_COMMON(phase, transport, id, dst_context, \ - dst_var, amount) \ - do { \ - if (grpc_flowctl_trace) { \ - grpc_chttp2_flowctl_trace(__FILE__, __LINE__, phase, \ - GRPC_CHTTP2_FLOWCTL_DEBIT, #dst_context, \ - #dst_var, NULL, #amount, transport->is_client, \ - id, dst_context->dst_var, amount); \ - } \ - dst_context->dst_var -= amount; \ - } while (0) - -#define GRPC_CHTTP2_FLOW_DEBIT_STREAM(phase, transport, dst_context, dst_var, \ - amount) \ - GRPC_CHTTP2_FLOW_DEBIT_COMMON(phase, transport, dst_context->id, \ - dst_context, dst_var, amount) -#define GRPC_CHTTP2_FLOW_DEBIT_TRANSPORT(phase, dst_context, dst_var, amount) \ - GRPC_CHTTP2_FLOW_DEBIT_COMMON(phase, dst_context, 0, dst_context, dst_var, \ - amount) - -void grpc_chttp2_flowctl_trace(const char *file, int line, const char *phase, - grpc_chttp2_flowctl_op op, const char *context1, - const char *var1, const char *context2, - const char *var2, int is_client, - uint32_t stream_id, int64_t val1, int64_t val2); +#define GRPC_CHTTP2_IF_TRACING(stmt) \ + if (!(GRPC_TRACER_ON(grpc_http_trace))) \ + ; \ + else \ + stmt void grpc_chttp2_fake_status(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, - grpc_chttp2_stream *stream, - grpc_status_code status, grpc_slice *details); + grpc_chttp2_stream *stream, grpc_error *error); void grpc_chttp2_mark_stream_closed(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, grpc_chttp2_stream *s, int close_reads, @@ -625,7 +781,7 @@ void grpc_chttp2_mark_stream_closed(grpc_exec_ctx *exec_ctx, void grpc_chttp2_start_writing(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t); -#ifdef GRPC_STREAM_REFCOUNT_DEBUG +#ifndef NDEBUG #define GRPC_CHTTP2_STREAM_REF(stream, reason) \ grpc_chttp2_stream_ref(stream, reason) #define GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream, reason) \ @@ -641,8 +797,7 @@ void grpc_chttp2_stream_ref(grpc_chttp2_stream *s); void grpc_chttp2_stream_unref(grpc_exec_ctx *exec_ctx, grpc_chttp2_stream *s); #endif -//#define GRPC_CHTTP2_REFCOUNTING_DEBUG 1 -#ifdef GRPC_CHTTP2_REFCOUNTING_DEBUG +#ifndef NDEBUG #define GRPC_CHTTP2_REF_TRANSPORT(t, r) \ grpc_chttp2_ref_transport(t, r, __FILE__, __LINE__) #define GRPC_CHTTP2_UNREF_TRANSPORT(cl, t, r) \ @@ -663,21 +818,41 @@ void grpc_chttp2_ref_transport(grpc_chttp2_transport *t); grpc_chttp2_incoming_byte_stream *grpc_chttp2_incoming_byte_stream_create( grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, grpc_chttp2_stream *s, uint32_t frame_size, uint32_t flags); -void grpc_chttp2_incoming_byte_stream_push(grpc_exec_ctx *exec_ctx, - grpc_chttp2_incoming_byte_stream *bs, - grpc_slice slice); -void grpc_chttp2_incoming_byte_stream_finished( +grpc_error *grpc_chttp2_incoming_byte_stream_push( + grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_byte_stream *bs, + grpc_slice slice, grpc_slice *slice_out); +grpc_error *grpc_chttp2_incoming_byte_stream_finished( + grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_byte_stream *bs, + grpc_error *error, bool reset_on_error); +void grpc_chttp2_incoming_byte_stream_notify( grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_byte_stream *bs, grpc_error *error); void grpc_chttp2_ack_ping(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, - const uint8_t *opaque_8bytes); + uint64_t id); + +/** Add a new ping strike to ping_recv_state.ping_strikes. If + ping_recv_state.ping_strikes > ping_policy.max_ping_strikes, it sends GOAWAY + with error code ENHANCE_YOUR_CALM and additional debug data resembling + "too_many_pings" followed by immediately closing the connection. */ +void grpc_chttp2_add_ping_strike(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t); + +typedef enum { + /* don't initiate a transport write, but piggyback on the next one */ + GRPC_CHTTP2_STREAM_WRITE_PIGGYBACK, + /* initiate a covered write */ + GRPC_CHTTP2_STREAM_WRITE_INITIATE_COVERED, + /* initiate an uncovered write */ + GRPC_CHTTP2_STREAM_WRITE_INITIATE_UNCOVERED +} grpc_chttp2_stream_write_type; /** add a ref to the stream and add it to the writable list; ref will be dropped in writing.c */ void grpc_chttp2_become_writable(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, - grpc_chttp2_stream *s, bool covered_by_poller, + grpc_chttp2_stream *s, + grpc_chttp2_stream_write_type type, const char *reason); void grpc_chttp2_cancel_stream(grpc_exec_ctx *exec_ctx, @@ -698,4 +873,9 @@ void grpc_chttp2_fail_pending_writes(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, grpc_chttp2_stream *s, grpc_error *error); +/** Set the default keepalive configurations, must only be called at + initialization */ +void grpc_chttp2_config_default_keepalive_args(grpc_channel_args *args, + bool is_client); + #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_INTERNAL_H */ diff --git a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/parsing.c b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/parsing.c index 5efb49751..18d163ee9 100644 --- a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/parsing.c +++ b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/parsing.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -39,10 +24,11 @@ #include #include -#include "src/core/ext/transport/chttp2/transport/http2_errors.h" -#include "src/core/ext/transport/chttp2/transport/status_conversion.h" #include "src/core/lib/profiling/timers.h" +#include "src/core/lib/slice/slice_string_helpers.h" +#include "src/core/lib/transport/http2_errors.h" #include "src/core/lib/transport/static_metadata.h" +#include "src/core/lib/transport/status_conversion.h" #include "src/core/lib/transport/timeout_encoding.h" static grpc_error *init_frame_parser(grpc_exec_ctx *exec_ctx, @@ -115,7 +101,7 @@ grpc_error *grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx, GRPC_CHTTP2_CLIENT_CONNECT_STRING[t->deframe_state], (int)(uint8_t)GRPC_CHTTP2_CLIENT_CONNECT_STRING[t->deframe_state], *cur, (int)*cur, t->deframe_state); - err = GRPC_ERROR_CREATE(msg); + err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg); gpr_free(msg); return err; } @@ -200,7 +186,7 @@ grpc_error *grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx, return err; } if (t->incoming_frame_size == 0) { - err = parse_frame_slice(exec_ctx, t, gpr_empty_slice(), 1); + err = parse_frame_slice(exec_ctx, t, grpc_empty_slice(), 1); if (err != GRPC_ERROR_NONE) { return err; } @@ -218,7 +204,7 @@ grpc_error *grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx, t->incoming_frame_size, t->settings[GRPC_ACKED_SETTINGS] [GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE]); - err = GRPC_ERROR_CREATE(msg); + err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg); gpr_free(msg); return err; } @@ -277,7 +263,7 @@ static grpc_error *init_frame_parser(grpc_exec_ctx *exec_ctx, gpr_asprintf( &msg, "Expected SETTINGS frame as the first frame, got frame type %d", t->incoming_frame_type); - grpc_error *err = GRPC_ERROR_CREATE(msg); + grpc_error *err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg); gpr_free(msg); return err; } @@ -287,7 +273,7 @@ static grpc_error *init_frame_parser(grpc_exec_ctx *exec_ctx, char *msg; gpr_asprintf(&msg, "Expected CONTINUATION frame, got frame type %02x", t->incoming_frame_type); - grpc_error *err = GRPC_ERROR_CREATE(msg); + grpc_error *err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg); gpr_free(msg); return err; } @@ -298,7 +284,7 @@ static grpc_error *init_frame_parser(grpc_exec_ctx *exec_ctx, "Expected CONTINUATION frame for grpc_chttp2_stream %08x, got " "grpc_chttp2_stream %08x", t->expect_continuation_stream_id, t->incoming_stream_id); - grpc_error *err = GRPC_ERROR_CREATE(msg); + grpc_error *err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg); gpr_free(msg); return err; } @@ -310,7 +296,8 @@ static grpc_error *init_frame_parser(grpc_exec_ctx *exec_ctx, case GRPC_CHTTP2_FRAME_HEADER: return init_header_frame_parser(exec_ctx, t, 0); case GRPC_CHTTP2_FRAME_CONTINUATION: - return GRPC_ERROR_CREATE("Unexpected CONTINUATION frame"); + return GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "Unexpected CONTINUATION frame"); case GRPC_CHTTP2_FRAME_RST_STREAM: return init_rst_stream_parser(exec_ctx, t); case GRPC_CHTTP2_FRAME_SETTINGS: @@ -322,7 +309,7 @@ static grpc_error *init_frame_parser(grpc_exec_ctx *exec_ctx, case GRPC_CHTTP2_FRAME_GOAWAY: return init_goaway_parser(exec_ctx, t); default: - if (grpc_http_trace) { + if (GRPC_TRACER_ON(grpc_http_trace)) { gpr_log(GPR_ERROR, "Unknown frame type %02x", t->incoming_frame_type); } return init_skip_frame_parser(exec_ctx, t, 0); @@ -335,8 +322,8 @@ static grpc_error *skip_parser(grpc_exec_ctx *exec_ctx, void *parser, return GRPC_ERROR_NONE; } -static void skip_header(grpc_exec_ctx *exec_ctx, void *tp, grpc_mdelem *md) { - GRPC_MDELEM_UNREF(md); +static void skip_header(grpc_exec_ctx *exec_ctx, void *tp, grpc_mdelem md) { + GRPC_MDELEM_UNREF(exec_ctx, md); } static grpc_error *init_skip_frame_parser(grpc_exec_ctx *exec_ctx, @@ -362,66 +349,37 @@ void grpc_chttp2_parsing_become_skip_parser(grpc_exec_ctx *exec_ctx, t->parser == grpc_chttp2_header_parser_parse); } -static grpc_error *update_incoming_window(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport *t, - grpc_chttp2_stream *s) { - uint32_t incoming_frame_size = t->incoming_frame_size; - if (incoming_frame_size > t->incoming_window) { - char *msg; - gpr_asprintf(&msg, "frame of size %d overflows incoming window of %" PRId64, - t->incoming_frame_size, t->incoming_window); - grpc_error *err = GRPC_ERROR_CREATE(msg); - gpr_free(msg); - return err; - } - - GRPC_CHTTP2_FLOW_DEBIT_TRANSPORT("parse", t, incoming_window, - incoming_frame_size); - - if (s != NULL) { - if (incoming_frame_size > s->incoming_window) { - char *msg; - gpr_asprintf(&msg, - "frame of size %d overflows incoming window of %" PRId64, - t->incoming_frame_size, s->incoming_window); - grpc_error *err = GRPC_ERROR_CREATE(msg); - gpr_free(msg); - return err; - } - - GRPC_CHTTP2_FLOW_DEBIT_STREAM("parse", t, s, incoming_window, - incoming_frame_size); - s->received_bytes += incoming_frame_size; - s->max_recv_bytes -= - (uint32_t)GPR_MIN(s->max_recv_bytes, incoming_frame_size); - } - - return GRPC_ERROR_NONE; -} - static grpc_error *init_data_frame_parser(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t) { grpc_chttp2_stream *s = grpc_chttp2_parsing_lookup_stream(t, t->incoming_stream_id); grpc_error *err = GRPC_ERROR_NONE; - err = update_incoming_window(exec_ctx, t, s); + err = grpc_chttp2_flowctl_recv_data(&t->flow_control, + s == NULL ? NULL : &s->flow_control, + t->incoming_frame_size); + grpc_chttp2_act_on_flowctl_action( + exec_ctx, grpc_chttp2_flowctl_get_action( + &t->flow_control, s == NULL ? NULL : &s->flow_control), + t, s); if (err != GRPC_ERROR_NONE) { goto error_handler; } if (s == NULL) { return init_skip_frame_parser(exec_ctx, t, 0); } + s->received_bytes += t->incoming_frame_size; s->stats.incoming.framing_bytes += 9; if (err == GRPC_ERROR_NONE && s->read_closed) { return init_skip_frame_parser(exec_ctx, t, 0); } if (err == GRPC_ERROR_NONE) { - err = grpc_chttp2_data_parser_begin_frame(&s->data_parser, - t->incoming_frame_flags, s->id); + err = grpc_chttp2_data_parser_begin_frame( + &s->data_parser, t->incoming_frame_flags, s->id, s); } error_handler: if (err == GRPC_ERROR_NONE) { t->incoming_stream = s; + /* t->parser = grpc_chttp2_data_parser_parse;*/ t->parser = grpc_chttp2_data_parser_parse; t->parser_data = &s->data_parser; return GRPC_ERROR_NONE; @@ -432,7 +390,7 @@ static grpc_error *init_data_frame_parser(grpc_exec_ctx *exec_ctx, } grpc_slice_buffer_add( &t->qbuf, grpc_chttp2_rst_stream_create(t->incoming_stream_id, - GRPC_CHTTP2_PROTOCOL_ERROR, + GRPC_HTTP2_PROTOCOL_ERROR, &s->stats.outgoing)); return init_skip_frame_parser(exec_ctx, t, 0); } else { @@ -443,7 +401,7 @@ static grpc_error *init_data_frame_parser(grpc_exec_ctx *exec_ctx, static void free_timeout(void *p) { gpr_free(p); } static void on_initial_header(grpc_exec_ctx *exec_ctx, void *tp, - grpc_mdelem *md) { + grpc_mdelem md) { grpc_chttp2_transport *t = tp; grpc_chttp2_stream *s = t->incoming_stream; @@ -451,33 +409,43 @@ static void on_initial_header(grpc_exec_ctx *exec_ctx, void *tp, GPR_ASSERT(s != NULL); - GRPC_CHTTP2_IF_TRACING(gpr_log( - GPR_INFO, "HTTP:%d:HDR:%s: %s: %s", s->id, t->is_client ? "CLI" : "SVR", - grpc_mdstr_as_c_string(md->key), grpc_mdstr_as_c_string(md->value))); + if (GRPC_TRACER_ON(grpc_http_trace)) { + char *key = grpc_slice_to_c_string(GRPC_MDKEY(md)); + char *value = + grpc_dump_slice(GRPC_MDVALUE(md), GPR_DUMP_HEX | GPR_DUMP_ASCII); + gpr_log(GPR_INFO, "HTTP:%d:HDR:%s: %s: %s", s->id, + t->is_client ? "CLI" : "SVR", key, value); + gpr_free(key); + gpr_free(value); + } - if (md->key == GRPC_MDSTR_GRPC_STATUS && md != GRPC_MDELEM_GRPC_STATUS_0) { + if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_STATUS) && + !grpc_mdelem_eq(md, GRPC_MDELEM_GRPC_STATUS_0)) { /* TODO(ctiller): check for a status like " 0" */ s->seen_error = true; } - if (md->key == GRPC_MDSTR_GRPC_TIMEOUT) { + if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_TIMEOUT)) { gpr_timespec *cached_timeout = grpc_mdelem_get_user_data(md, free_timeout); - if (!cached_timeout) { + gpr_timespec timeout; + if (cached_timeout == NULL) { /* not already parsed: parse it now, and store the result away */ cached_timeout = gpr_malloc(sizeof(gpr_timespec)); - if (!grpc_http2_decode_timeout(grpc_mdstr_as_c_string(md->value), - cached_timeout)) { - gpr_log(GPR_ERROR, "Ignoring bad timeout value '%s'", - grpc_mdstr_as_c_string(md->value)); + if (!grpc_http2_decode_timeout(GRPC_MDVALUE(md), cached_timeout)) { + char *val = grpc_slice_to_c_string(GRPC_MDVALUE(md)); + gpr_log(GPR_ERROR, "Ignoring bad timeout value '%s'", val); + gpr_free(val); *cached_timeout = gpr_inf_future(GPR_TIMESPAN); } - cached_timeout = - grpc_mdelem_set_user_data(md, free_timeout, cached_timeout); + timeout = *cached_timeout; + grpc_mdelem_set_user_data(md, free_timeout, cached_timeout); + } else { + timeout = *cached_timeout; } grpc_chttp2_incoming_metadata_buffer_set_deadline( &s->metadata_buffer[0], - gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), *cached_timeout)); - GRPC_MDELEM_UNREF(md); + gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), timeout)); + GRPC_MDELEM_UNREF(exec_ctx, md); } else { const size_t new_size = s->metadata_buffer[0].size + GRPC_MDELEM_LENGTH(md); const size_t metadata_size_limit = @@ -491,13 +459,21 @@ static void on_initial_header(grpc_exec_ctx *exec_ctx, void *tp, grpc_chttp2_cancel_stream( exec_ctx, t, s, grpc_error_set_int( - GRPC_ERROR_CREATE("received initial metadata size exceeds limit"), + GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "received initial metadata size exceeds limit"), GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_RESOURCE_EXHAUSTED)); grpc_chttp2_parsing_become_skip_parser(exec_ctx, t); s->seen_error = true; - GRPC_MDELEM_UNREF(md); + GRPC_MDELEM_UNREF(exec_ctx, md); } else { - grpc_chttp2_incoming_metadata_buffer_add(&s->metadata_buffer[0], md); + grpc_error *error = grpc_chttp2_incoming_metadata_buffer_add( + exec_ctx, &s->metadata_buffer[0], md); + if (error != GRPC_ERROR_NONE) { + grpc_chttp2_cancel_stream(exec_ctx, t, s, error); + grpc_chttp2_parsing_become_skip_parser(exec_ctx, t); + s->seen_error = true; + GRPC_MDELEM_UNREF(exec_ctx, md); + } } } @@ -505,7 +481,7 @@ static void on_initial_header(grpc_exec_ctx *exec_ctx, void *tp, } static void on_trailing_header(grpc_exec_ctx *exec_ctx, void *tp, - grpc_mdelem *md) { + grpc_mdelem md) { grpc_chttp2_transport *t = tp; grpc_chttp2_stream *s = t->incoming_stream; @@ -513,11 +489,18 @@ static void on_trailing_header(grpc_exec_ctx *exec_ctx, void *tp, GPR_ASSERT(s != NULL); - GRPC_CHTTP2_IF_TRACING(gpr_log( - GPR_INFO, "HTTP:%d:TRL:%s: %s: %s", s->id, t->is_client ? "CLI" : "SVR", - grpc_mdstr_as_c_string(md->key), grpc_mdstr_as_c_string(md->value))); + if (GRPC_TRACER_ON(grpc_http_trace)) { + char *key = grpc_slice_to_c_string(GRPC_MDKEY(md)); + char *value = + grpc_dump_slice(GRPC_MDVALUE(md), GPR_DUMP_HEX | GPR_DUMP_ASCII); + gpr_log(GPR_INFO, "HTTP:%d:TRL:%s: %s: %s", s->id, + t->is_client ? "CLI" : "SVR", key, value); + gpr_free(key); + gpr_free(value); + } - if (md->key == GRPC_MDSTR_GRPC_STATUS && md != GRPC_MDELEM_GRPC_STATUS_0) { + if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_STATUS) && + !grpc_mdelem_eq(md, GRPC_MDELEM_GRPC_STATUS_0)) { /* TODO(ctiller): check for a status like " 0" */ s->seen_error = true; } @@ -533,14 +516,22 @@ static void on_trailing_header(grpc_exec_ctx *exec_ctx, void *tp, new_size, metadata_size_limit); grpc_chttp2_cancel_stream( exec_ctx, t, s, - grpc_error_set_int( - GRPC_ERROR_CREATE("received trailing metadata size exceeds limit"), - GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_RESOURCE_EXHAUSTED)); + grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "received trailing metadata size exceeds limit"), + GRPC_ERROR_INT_GRPC_STATUS, + GRPC_STATUS_RESOURCE_EXHAUSTED)); grpc_chttp2_parsing_become_skip_parser(exec_ctx, t); s->seen_error = true; - GRPC_MDELEM_UNREF(md); + GRPC_MDELEM_UNREF(exec_ctx, md); } else { - grpc_chttp2_incoming_metadata_buffer_add(&s->metadata_buffer[1], md); + grpc_error *error = grpc_chttp2_incoming_metadata_buffer_add( + exec_ctx, &s->metadata_buffer[1], md); + if (error != GRPC_ERROR_NONE) { + grpc_chttp2_cancel_stream(exec_ctx, t, s, error); + grpc_chttp2_parsing_become_skip_parser(exec_ctx, t); + s->seen_error = true; + GRPC_MDELEM_UNREF(exec_ctx, md); + } } GPR_TIMER_END("on_trailing_header", 0); @@ -598,6 +589,10 @@ static grpc_error *init_header_frame_parser(grpc_exec_ctx *exec_ctx, "ignoring grpc_chttp2_stream with non-client generated index %d", t->incoming_stream_id)); return init_skip_frame_parser(exec_ctx, t, 1); + } else if (grpc_chttp2_stream_map_size(&t->stream_map) >= + t->settings[GRPC_ACKED_SETTINGS] + [GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS]) { + return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Max stream count exceeded"); } t->last_new_stream_id = t->incoming_stream_id; s = t->incoming_stream = @@ -622,9 +617,19 @@ static grpc_error *init_header_frame_parser(grpc_exec_ctx *exec_ctx, t->parser_data = &t->hpack_parser; switch (s->header_frames_received) { case 0: - t->hpack_parser.on_header = on_initial_header; + if (t->is_client && t->header_eof) { + GRPC_CHTTP2_IF_TRACING(gpr_log(GPR_INFO, "parsing Trailers-Only")); + if (s->trailing_metadata_available != NULL) { + *s->trailing_metadata_available = true; + } + t->hpack_parser.on_header = on_trailing_header; + } else { + GRPC_CHTTP2_IF_TRACING(gpr_log(GPR_INFO, "parsing initial_metadata")); + t->hpack_parser.on_header = on_initial_header; + } break; case 1: + GRPC_CHTTP2_IF_TRACING(gpr_log(GPR_INFO, "parsing trailing_metadata")); t->hpack_parser.on_header = on_trailing_header; break; case 2: @@ -699,7 +704,8 @@ static grpc_error *init_goaway_parser(grpc_exec_ctx *exec_ctx, static grpc_error *init_settings_frame_parser(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t) { if (t->incoming_stream_id != 0) { - return GRPC_ERROR_CREATE("Settings frame received for grpc_chttp2_stream"); + return GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "Settings frame received for grpc_chttp2_stream"); } grpc_error *err = grpc_chttp2_settings_parser_begin_frame( @@ -712,7 +718,7 @@ static grpc_error *init_settings_frame_parser(grpc_exec_ctx *exec_ctx, memcpy(t->settings[GRPC_ACKED_SETTINGS], t->settings[GRPC_SENT_SETTINGS], GRPC_CHTTP2_NUM_SETTINGS * sizeof(uint32_t)); grpc_chttp2_hptbl_set_max_bytes( - &t->hpack_parser.table, + exec_ctx, &t->hpack_parser.table, t->settings[GRPC_ACKED_SETTINGS] [GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE]); t->sent_local_settings = 0; @@ -730,17 +736,16 @@ static grpc_error *parse_frame_slice(grpc_exec_ctx *exec_ctx, if (err == GRPC_ERROR_NONE) { return err; } else if (grpc_error_get_int(err, GRPC_ERROR_INT_STREAM_ID, NULL)) { - if (grpc_http_trace) { + if (GRPC_TRACER_ON(grpc_http_trace)) { const char *msg = grpc_error_string(err); gpr_log(GPR_ERROR, "%s", msg); - grpc_error_free_string(msg); } grpc_chttp2_parsing_become_skip_parser(exec_ctx, t); if (s) { s->forced_close_error = err; grpc_slice_buffer_add( &t->qbuf, grpc_chttp2_rst_stream_create(t->incoming_stream_id, - GRPC_CHTTP2_PROTOCOL_ERROR, + GRPC_HTTP2_PROTOCOL_ERROR, &s->stats.outgoing)); } else { GRPC_ERROR_UNREF(err); diff --git a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/status_conversion.c b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/status_conversion.c deleted file mode 100644 index 5dce2f2d0..000000000 --- a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/status_conversion.c +++ /dev/null @@ -1,115 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include "src/core/ext/transport/chttp2/transport/status_conversion.h" - -int grpc_chttp2_grpc_status_to_http2_error(grpc_status_code status) { - switch (status) { - case GRPC_STATUS_OK: - return GRPC_CHTTP2_NO_ERROR; - case GRPC_STATUS_CANCELLED: - return GRPC_CHTTP2_CANCEL; - case GRPC_STATUS_DEADLINE_EXCEEDED: - return GRPC_CHTTP2_CANCEL; - case GRPC_STATUS_RESOURCE_EXHAUSTED: - return GRPC_CHTTP2_ENHANCE_YOUR_CALM; - case GRPC_STATUS_PERMISSION_DENIED: - return GRPC_CHTTP2_INADEQUATE_SECURITY; - case GRPC_STATUS_UNAVAILABLE: - return GRPC_CHTTP2_REFUSED_STREAM; - default: - return GRPC_CHTTP2_INTERNAL_ERROR; - } -} - -grpc_status_code grpc_chttp2_http2_error_to_grpc_status( - grpc_chttp2_error_code error, gpr_timespec deadline) { - switch (error) { - case GRPC_CHTTP2_NO_ERROR: - /* should never be received */ - return GRPC_STATUS_INTERNAL; - case GRPC_CHTTP2_CANCEL: - /* http2 cancel translates to STATUS_CANCELLED iff deadline hasn't been - * exceeded */ - return gpr_time_cmp(gpr_now(deadline.clock_type), deadline) >= 0 - ? GRPC_STATUS_DEADLINE_EXCEEDED - : GRPC_STATUS_CANCELLED; - case GRPC_CHTTP2_ENHANCE_YOUR_CALM: - return GRPC_STATUS_RESOURCE_EXHAUSTED; - case GRPC_CHTTP2_INADEQUATE_SECURITY: - return GRPC_STATUS_PERMISSION_DENIED; - case GRPC_CHTTP2_REFUSED_STREAM: - return GRPC_STATUS_UNAVAILABLE; - default: - return GRPC_STATUS_INTERNAL; - } -} - -grpc_status_code grpc_chttp2_http2_status_to_grpc_status(int status) { - switch (status) { - /* these HTTP2 status codes are called out explicitly in status.proto */ - case 200: - return GRPC_STATUS_OK; - case 400: - return GRPC_STATUS_INVALID_ARGUMENT; - case 401: - return GRPC_STATUS_UNAUTHENTICATED; - case 403: - return GRPC_STATUS_PERMISSION_DENIED; - case 404: - return GRPC_STATUS_NOT_FOUND; - case 409: - return GRPC_STATUS_ABORTED; - case 412: - return GRPC_STATUS_FAILED_PRECONDITION; - case 429: - return GRPC_STATUS_RESOURCE_EXHAUSTED; - case 499: - return GRPC_STATUS_CANCELLED; - case 500: - return GRPC_STATUS_UNKNOWN; - case 501: - return GRPC_STATUS_UNIMPLEMENTED; - case 503: - return GRPC_STATUS_UNAVAILABLE; - case 504: - return GRPC_STATUS_DEADLINE_EXCEEDED; - /* everything else is unknown */ - default: - return GRPC_STATUS_UNKNOWN; - } -} - -int grpc_chttp2_grpc_status_to_http2_status(grpc_status_code status) { - return 200; -} diff --git a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/status_conversion.h b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/status_conversion.h deleted file mode 100644 index 953bc9f1e..000000000 --- a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/status_conversion.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_STATUS_CONVERSION_H -#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_STATUS_CONVERSION_H - -#include -#include "src/core/ext/transport/chttp2/transport/http2_errors.h" - -/* Conversion of grpc status codes to http2 error codes (for RST_STREAM) */ -grpc_chttp2_error_code grpc_chttp2_grpc_status_to_http2_error( - grpc_status_code status); -grpc_status_code grpc_chttp2_http2_error_to_grpc_status( - grpc_chttp2_error_code error, gpr_timespec deadline); - -/* Conversion of HTTP status codes (:status) to grpc status codes */ -grpc_status_code grpc_chttp2_http2_status_to_grpc_status(int status); -int grpc_chttp2_grpc_status_to_http2_status(grpc_status_code status); - -#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_STATUS_CONVERSION_H */ diff --git a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/stream_lists.c b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/stream_lists.c index a60264cc5..7cc85dea9 100644 --- a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/stream_lists.c +++ b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/stream_lists.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -37,14 +22,14 @@ /* core list management */ -static int stream_list_empty(grpc_chttp2_transport *t, - grpc_chttp2_stream_list_id id) { +static bool stream_list_empty(grpc_chttp2_transport *t, + grpc_chttp2_stream_list_id id) { return t->lists[id].head == NULL; } -static int stream_list_pop(grpc_chttp2_transport *t, - grpc_chttp2_stream **stream, - grpc_chttp2_stream_list_id id) { +static bool stream_list_pop(grpc_chttp2_transport *t, + grpc_chttp2_stream **stream, + grpc_chttp2_stream_list_id id) { grpc_chttp2_stream *s = t->lists[id].head; if (s) { grpc_chttp2_stream *new_head = s->links[id].next; @@ -124,8 +109,8 @@ bool grpc_chttp2_list_add_writable_stream(grpc_chttp2_transport *t, return stream_list_add(t, s, GRPC_CHTTP2_LIST_WRITABLE); } -int grpc_chttp2_list_pop_writable_stream(grpc_chttp2_transport *t, - grpc_chttp2_stream **s) { +bool grpc_chttp2_list_pop_writable_stream(grpc_chttp2_transport *t, + grpc_chttp2_stream **s) { return stream_list_pop(t, s, GRPC_CHTTP2_LIST_WRITABLE); } @@ -139,12 +124,12 @@ bool grpc_chttp2_list_add_writing_stream(grpc_chttp2_transport *t, return stream_list_add(t, s, GRPC_CHTTP2_LIST_WRITING); } -int grpc_chttp2_list_have_writing_streams(grpc_chttp2_transport *t) { +bool grpc_chttp2_list_have_writing_streams(grpc_chttp2_transport *t) { return !stream_list_empty(t, GRPC_CHTTP2_LIST_WRITING); } -int grpc_chttp2_list_pop_writing_stream(grpc_chttp2_transport *t, - grpc_chttp2_stream **s) { +bool grpc_chttp2_list_pop_writing_stream(grpc_chttp2_transport *t, + grpc_chttp2_stream **s) { return stream_list_pop(t, s, GRPC_CHTTP2_LIST_WRITING); } @@ -153,8 +138,8 @@ void grpc_chttp2_list_add_waiting_for_concurrency(grpc_chttp2_transport *t, stream_list_add(t, s, GRPC_CHTTP2_LIST_WAITING_FOR_CONCURRENCY); } -int grpc_chttp2_list_pop_waiting_for_concurrency(grpc_chttp2_transport *t, - grpc_chttp2_stream **s) { +bool grpc_chttp2_list_pop_waiting_for_concurrency(grpc_chttp2_transport *t, + grpc_chttp2_stream **s) { return stream_list_pop(t, s, GRPC_CHTTP2_LIST_WAITING_FOR_CONCURRENCY); } @@ -165,15 +150,43 @@ void grpc_chttp2_list_remove_waiting_for_concurrency(grpc_chttp2_transport *t, void grpc_chttp2_list_add_stalled_by_transport(grpc_chttp2_transport *t, grpc_chttp2_stream *s) { + GRPC_FLOW_CONTROL_IF_TRACING( + gpr_log(GPR_DEBUG, "stream %u stalled by transport", s->id)); stream_list_add(t, s, GRPC_CHTTP2_LIST_STALLED_BY_TRANSPORT); } -int grpc_chttp2_list_pop_stalled_by_transport(grpc_chttp2_transport *t, - grpc_chttp2_stream **s) { - return stream_list_pop(t, s, GRPC_CHTTP2_LIST_STALLED_BY_TRANSPORT); +bool grpc_chttp2_list_pop_stalled_by_transport(grpc_chttp2_transport *t, + grpc_chttp2_stream **s) { + bool ret = stream_list_pop(t, s, GRPC_CHTTP2_LIST_STALLED_BY_TRANSPORT); + GRPC_FLOW_CONTROL_IF_TRACING(if (ret) gpr_log( + GPR_DEBUG, "stream %u un-stalled by transport", (*s)->id)); + return ret; } void grpc_chttp2_list_remove_stalled_by_transport(grpc_chttp2_transport *t, grpc_chttp2_stream *s) { stream_list_maybe_remove(t, s, GRPC_CHTTP2_LIST_STALLED_BY_TRANSPORT); } + +void grpc_chttp2_list_add_stalled_by_stream(grpc_chttp2_transport *t, + grpc_chttp2_stream *s) { + GRPC_FLOW_CONTROL_IF_TRACING( + gpr_log(GPR_DEBUG, "stream %u stalled by stream", s->id)); + stream_list_add(t, s, GRPC_CHTTP2_LIST_STALLED_BY_STREAM); +} + +bool grpc_chttp2_list_pop_stalled_by_stream(grpc_chttp2_transport *t, + grpc_chttp2_stream **s) { + bool ret = stream_list_pop(t, s, GRPC_CHTTP2_LIST_STALLED_BY_STREAM); + GRPC_FLOW_CONTROL_IF_TRACING( + if (ret) gpr_log(GPR_DEBUG, "stream %u un-stalled by stream", (*s)->id)); + return ret; +} + +bool grpc_chttp2_list_remove_stalled_by_stream(grpc_chttp2_transport *t, + grpc_chttp2_stream *s) { + bool ret = stream_list_maybe_remove(t, s, GRPC_CHTTP2_LIST_STALLED_BY_STREAM); + GRPC_FLOW_CONTROL_IF_TRACING( + if (ret) gpr_log(GPR_DEBUG, "stream %u un-stalled by stream", s->id)); + return ret; +} diff --git a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/stream_map.c b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/stream_map.c index 5f5a28446..e2f10bc20 100644 --- a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/stream_map.c +++ b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/stream_map.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/stream_map.h b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/stream_map.h index 203f64068..30c50ba32 100644 --- a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/stream_map.h +++ b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/stream_map.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/varint.c b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/varint.c index e434ad3c0..0d94ddcbc 100644 --- a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/varint.c +++ b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/varint.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -52,12 +37,16 @@ void grpc_chttp2_hpack_write_varint_tail(uint32_t tail_value, uint8_t* target, switch (tail_length) { case 5: target[4] = (uint8_t)((tail_value >> 28) | 0x80); + /* fallthrough */ case 4: target[3] = (uint8_t)((tail_value >> 21) | 0x80); + /* fallthrough */ case 3: target[2] = (uint8_t)((tail_value >> 14) | 0x80); + /* fallthrough */ case 2: target[1] = (uint8_t)((tail_value >> 7) | 0x80); + /* fallthrough */ case 1: target[0] = (uint8_t)((tail_value) | 0x80); } diff --git a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/varint.h b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/varint.h index 450e5fd11..5a2b670f0 100644 --- a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/varint.h +++ b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/varint.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/writing.c b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/writing.c index 139e7387c..80eb51ff0 100644 --- a/Sources/CgRPC/src/core/ext/transport/chttp2/transport/writing.c +++ b/Sources/CgRPC/src/core/ext/transport/chttp2/transport/writing.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -37,8 +22,9 @@ #include -#include "src/core/ext/transport/chttp2/transport/http2_errors.h" #include "src/core/lib/profiling/timers.h" +#include "src/core/lib/slice/slice_internal.h" +#include "src/core/lib/transport/http2_errors.h" static void add_to_write_list(grpc_chttp2_write_cb **list, grpc_chttp2_write_cb *cb) { @@ -55,6 +41,86 @@ static void finish_write_cb(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, t->write_cb_pool = cb; } +static void collapse_pings_from_into(grpc_chttp2_transport *t, + grpc_chttp2_ping_type ping_type, + grpc_chttp2_ping_queue *pq) { + for (size_t i = 0; i < GRPC_CHTTP2_PCL_COUNT; i++) { + grpc_closure_list_move(&t->ping_queues[ping_type].lists[i], &pq->lists[i]); + } +} + +static void maybe_initiate_ping(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t, + grpc_chttp2_ping_type ping_type) { + grpc_chttp2_ping_queue *pq = &t->ping_queues[ping_type]; + if (grpc_closure_list_empty(pq->lists[GRPC_CHTTP2_PCL_NEXT])) { + /* no ping needed: wait */ + return; + } + if (!grpc_closure_list_empty(pq->lists[GRPC_CHTTP2_PCL_INFLIGHT])) { + /* ping already in-flight: wait */ + if (GRPC_TRACER_ON(grpc_http_trace) || + GRPC_TRACER_ON(grpc_bdp_estimator_trace)) { + gpr_log(GPR_DEBUG, "Ping delayed [%p]: already pinging", t->peer_string); + } + return; + } + if (t->ping_state.pings_before_data_required == 0 && + t->ping_policy.max_pings_without_data != 0) { + /* need to send something of substance before sending a ping again */ + if (GRPC_TRACER_ON(grpc_http_trace) || + GRPC_TRACER_ON(grpc_bdp_estimator_trace)) { + gpr_log(GPR_DEBUG, "Ping delayed [%p]: too many recent pings: %d/%d", + t->peer_string, t->ping_state.pings_before_data_required, + t->ping_policy.max_pings_without_data); + } + return; + } + gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC); + gpr_timespec elapsed = gpr_time_sub(now, t->ping_state.last_ping_sent_time); + /*gpr_log(GPR_DEBUG, "elapsed:%d.%09d min:%d.%09d", (int)elapsed.tv_sec, + elapsed.tv_nsec, (int)t->ping_policy.min_time_between_pings.tv_sec, + (int)t->ping_policy.min_time_between_pings.tv_nsec);*/ + if (gpr_time_cmp(elapsed, t->ping_policy.min_time_between_pings) < 0) { + /* not enough elapsed time between successive pings */ + if (GRPC_TRACER_ON(grpc_http_trace) || + GRPC_TRACER_ON(grpc_bdp_estimator_trace)) { + gpr_log(GPR_DEBUG, + "Ping delayed [%p]: not enough time elapsed since last ping", + t->peer_string); + } + if (!t->ping_state.is_delayed_ping_timer_set) { + t->ping_state.is_delayed_ping_timer_set = true; + grpc_timer_init(exec_ctx, &t->ping_state.delayed_ping_timer, + gpr_time_add(t->ping_state.last_ping_sent_time, + t->ping_policy.min_time_between_pings), + &t->retry_initiate_ping_locked, + gpr_now(GPR_CLOCK_MONOTONIC)); + } + return; + } + /* coalesce equivalent pings into this one */ + switch (ping_type) { + case GRPC_CHTTP2_PING_BEFORE_TRANSPORT_WINDOW_UPDATE: + collapse_pings_from_into(t, GRPC_CHTTP2_PING_ON_NEXT_WRITE, pq); + break; + case GRPC_CHTTP2_PING_ON_NEXT_WRITE: + break; + case GRPC_CHTTP2_PING_TYPE_COUNT: + GPR_UNREACHABLE_CODE(break); + } + pq->inflight_id = t->ping_ctr * GRPC_CHTTP2_PING_TYPE_COUNT + ping_type; + t->ping_ctr++; + GRPC_CLOSURE_LIST_SCHED(exec_ctx, &pq->lists[GRPC_CHTTP2_PCL_INITIATE]); + grpc_closure_list_move(&pq->lists[GRPC_CHTTP2_PCL_NEXT], + &pq->lists[GRPC_CHTTP2_PCL_INFLIGHT]); + grpc_slice_buffer_add(&t->outbuf, + grpc_chttp2_ping_create(false, pq->inflight_id)); + t->ping_state.last_ping_sent_time = now; + t->ping_state.pings_before_data_required -= + (t->ping_state.pings_before_data_required != 0); +} + static void update_list(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, grpc_chttp2_stream *s, int64_t send_bytes, grpc_chttp2_write_cb **list, grpc_error *error) { @@ -73,8 +139,36 @@ static void update_list(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, GRPC_ERROR_UNREF(error); } -bool grpc_chttp2_begin_write(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport *t) { +static bool stream_ref_if_not_destroyed(gpr_refcount *r) { + gpr_atm count; + do { + count = gpr_atm_acq_load(&r->count); + if (count == 0) return false; + } while (!gpr_atm_rel_cas(&r->count, count, count + 1)); + return true; +} + +/* How many bytes would we like to put on the wire during a single syscall */ +static uint32_t target_write_size(grpc_chttp2_transport *t) { + return 1024 * 1024; +} + +// Returns true if initial_metadata contains only default headers. +// +// TODO(roth): The fact that we hard-code these particular headers here +// is fairly ugly. Need some better way to know which headers are +// default, maybe via a bit in the static metadata table? +static bool is_default_initial_metadata(grpc_metadata_batch *initial_metadata) { + int num_default_fields = + (initial_metadata->idx.named.status != NULL) + + (initial_metadata->idx.named.content_type != NULL) + + (initial_metadata->idx.named.grpc_encoding != NULL) + + (initial_metadata->idx.named.grpc_accept_encoding != NULL); + return (size_t)num_default_fields == initial_metadata->list.count; +} + +grpc_chttp2_begin_write_result grpc_chttp2_begin_write( + grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t) { grpc_chttp2_stream *s; GPR_TIMER_BEGIN("grpc_chttp2_begin_write", 0); @@ -98,105 +192,241 @@ bool grpc_chttp2_begin_write(grpc_exec_ctx *exec_ctx, &t->hpack_compressor, t->settings[GRPC_PEER_SETTINGS][GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE]); - if (t->outgoing_window > 0) { + if (t->flow_control.remote_window > 0) { while (grpc_chttp2_list_pop_stalled_by_transport(t, &s)) { - grpc_chttp2_become_writable(exec_ctx, t, s, false, - "transport.read_flow_control"); + if (!t->closed && grpc_chttp2_list_add_writable_stream(t, s) && + stream_ref_if_not_destroyed(&s->refcount->refs)) { + grpc_chttp2_initiate_write(exec_ctx, t, "transport.read_flow_control"); + } } } + bool partial_write = false; + /* for each grpc_chttp2_stream that's become writable, frame it's data (according to available window sizes) and add to the output buffer */ - while (grpc_chttp2_list_pop_writable_stream(t, &s)) { + while (true) { + if (t->outbuf.length > target_write_size(t)) { + partial_write = true; + break; + } + + if (!grpc_chttp2_list_pop_writable_stream(t, &s)) { + break; + } + bool sent_initial_metadata = s->sent_initial_metadata; bool now_writing = false; - GRPC_CHTTP2_IF_TRACING(gpr_log( - GPR_DEBUG, "W:%p %s[%d] im-(sent,send)=(%d,%d) announce=%d", t, - t->is_client ? "CLIENT" : "SERVER", s->id, sent_initial_metadata, - s->send_initial_metadata != NULL, s->announce_window)); + GRPC_CHTTP2_IF_TRACING( + gpr_log(GPR_DEBUG, "W:%p %s[%d] im-(sent,send)=(%d,%d) announce=%d", t, + t->is_client ? "CLIENT" : "SERVER", s->id, + sent_initial_metadata, s->send_initial_metadata != NULL, + (int)(s->flow_control.local_window_delta - + s->flow_control.announced_window_delta))); + + grpc_mdelem *extra_headers_for_trailing_metadata[2]; + size_t num_extra_headers_for_trailing_metadata = 0; /* send initial metadata if it's available */ - if (!sent_initial_metadata && s->send_initial_metadata) { - grpc_chttp2_encode_header( - &t->hpack_compressor, s->id, s->send_initial_metadata, 0, - t->settings[GRPC_ACKED_SETTINGS][GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE], - &s->stats.outgoing, &t->outbuf); + if (!sent_initial_metadata && s->send_initial_metadata != NULL) { + // We skip this on the server side if there is no custom initial + // metadata, there are no messages to send, and we are also sending + // trailing metadata. This results in a Trailers-Only response, + // which is required for retries, as per: + // https://github.com/grpc/proposal/blob/master/A6-client-retries.md#when-retries-are-valid + if (t->is_client || s->fetching_send_message != NULL || + s->flow_controlled_buffer.length != 0 || + s->send_trailing_metadata == NULL || + !is_default_initial_metadata(s->send_initial_metadata)) { + grpc_encode_header_options hopt = { + .stream_id = s->id, + .is_eof = false, + .use_true_binary_metadata = + t->settings + [GRPC_PEER_SETTINGS] + [GRPC_CHTTP2_SETTINGS_GRPC_ALLOW_TRUE_BINARY_METADATA] != 0, + .max_frame_size = t->settings[GRPC_PEER_SETTINGS] + [GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE], + .stats = &s->stats.outgoing}; + grpc_chttp2_encode_header(exec_ctx, &t->hpack_compressor, NULL, 0, + s->send_initial_metadata, &hopt, &t->outbuf); + now_writing = true; + t->ping_state.pings_before_data_required = + t->ping_policy.max_pings_without_data; + if (!t->is_client) { + t->ping_recv_state.last_ping_recv_time = + gpr_inf_past(GPR_CLOCK_MONOTONIC); + t->ping_recv_state.ping_strikes = 0; + } + } else { + GRPC_CHTTP2_IF_TRACING( + gpr_log(GPR_INFO, "not sending initial_metadata (Trailers-Only)")); + // When sending Trailers-Only, we need to move the :status and + // content-type headers to the trailers. + if (s->send_initial_metadata->idx.named.status != NULL) { + extra_headers_for_trailing_metadata + [num_extra_headers_for_trailing_metadata++] = + &s->send_initial_metadata->idx.named.status->md; + } + if (s->send_initial_metadata->idx.named.content_type != NULL) { + extra_headers_for_trailing_metadata + [num_extra_headers_for_trailing_metadata++] = + &s->send_initial_metadata->idx.named.content_type->md; + } + } s->send_initial_metadata = NULL; s->sent_initial_metadata = true; sent_initial_metadata = true; - now_writing = true; } /* send any window updates */ - if (s->announce_window > 0) { - uint32_t announce = s->announce_window; - grpc_slice_buffer_add(&t->outbuf, - grpc_chttp2_window_update_create( - s->id, s->announce_window, &s->stats.outgoing)); - GRPC_CHTTP2_FLOW_DEBIT_STREAM("write", t, s, announce_window, announce); + uint32_t stream_announce = grpc_chttp2_flowctl_maybe_send_stream_update( + &t->flow_control, &s->flow_control); + if (stream_announce > 0) { + grpc_slice_buffer_add( + &t->outbuf, grpc_chttp2_window_update_create(s->id, stream_announce, + &s->stats.outgoing)); + t->ping_state.pings_before_data_required = + t->ping_policy.max_pings_without_data; + if (!t->is_client) { + t->ping_recv_state.last_ping_recv_time = + gpr_inf_past(GPR_CLOCK_MONOTONIC); + t->ping_recv_state.ping_strikes = 0; + } } if (sent_initial_metadata) { /* send any body bytes, if allowed by flow control */ - if (s->flow_controlled_buffer.length > 0) { - uint32_t max_outgoing = - (uint32_t)GPR_MIN(t->settings[GRPC_ACKED_SETTINGS] - [GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE], - GPR_MIN(s->outgoing_window, t->outgoing_window)); + if (s->flow_controlled_buffer.length > 0 || + (s->stream_compression_send_enabled && + s->compressed_data_buffer->length > 0)) { + uint32_t stream_remote_window = (uint32_t)GPR_MAX( + 0, + s->flow_control.remote_window_delta + + (int64_t)t->settings[GRPC_PEER_SETTINGS] + [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]); + uint32_t max_outgoing = (uint32_t)GPR_MIN( + t->settings[GRPC_PEER_SETTINGS] + [GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE], + GPR_MIN(stream_remote_window, t->flow_control.remote_window)); if (max_outgoing > 0) { - uint32_t send_bytes = - (uint32_t)GPR_MIN(max_outgoing, s->flow_controlled_buffer.length); - bool is_last_data_frame = - s->fetching_send_message == NULL && - send_bytes == s->flow_controlled_buffer.length; - bool is_last_frame = - is_last_data_frame && s->send_trailing_metadata != NULL && - grpc_metadata_batch_is_empty(s->send_trailing_metadata); - grpc_chttp2_encode_data(s->id, &s->flow_controlled_buffer, send_bytes, - is_last_frame, &s->stats.outgoing, - &t->outbuf); - GRPC_CHTTP2_FLOW_DEBIT_STREAM("write", t, s, outgoing_window, - send_bytes); - GRPC_CHTTP2_FLOW_DEBIT_TRANSPORT("write", t, outgoing_window, - send_bytes); + bool is_last_data_frame = false; + bool is_last_frame = false; + if (s->stream_compression_send_enabled) { + while ((s->flow_controlled_buffer.length > 0 || + s->compressed_data_buffer->length > 0) && + max_outgoing > 0) { + if (s->compressed_data_buffer->length > 0) { + uint32_t send_bytes = (uint32_t)GPR_MIN( + max_outgoing, s->compressed_data_buffer->length); + is_last_data_frame = + (send_bytes == s->compressed_data_buffer->length && + s->flow_controlled_buffer.length == 0 && + s->fetching_send_message == NULL); + is_last_frame = + is_last_data_frame && s->send_trailing_metadata != NULL && + grpc_metadata_batch_is_empty(s->send_trailing_metadata); + grpc_chttp2_encode_data(s->id, s->compressed_data_buffer, + send_bytes, is_last_frame, + &s->stats.outgoing, &t->outbuf); + grpc_chttp2_flowctl_sent_data(&t->flow_control, + &s->flow_control, send_bytes); + max_outgoing -= send_bytes; + if (s->compressed_data_buffer->length == 0) { + s->sending_bytes += s->uncompressed_data_size; + } + } else { + if (s->stream_compression_ctx == NULL) { + s->stream_compression_ctx = + grpc_stream_compression_context_create( + GRPC_STREAM_COMPRESSION_COMPRESS); + } + s->uncompressed_data_size = s->flow_controlled_buffer.length; + GPR_ASSERT(grpc_stream_compress( + s->stream_compression_ctx, &s->flow_controlled_buffer, + s->compressed_data_buffer, NULL, MAX_SIZE_T, + GRPC_STREAM_COMPRESSION_FLUSH_SYNC)); + } + } + } else { + uint32_t send_bytes = (uint32_t)GPR_MIN( + max_outgoing, s->flow_controlled_buffer.length); + is_last_data_frame = s->fetching_send_message == NULL && + send_bytes == s->flow_controlled_buffer.length; + is_last_frame = + is_last_data_frame && s->send_trailing_metadata != NULL && + grpc_metadata_batch_is_empty(s->send_trailing_metadata); + grpc_chttp2_encode_data(s->id, &s->flow_controlled_buffer, + send_bytes, is_last_frame, + &s->stats.outgoing, &t->outbuf); + grpc_chttp2_flowctl_sent_data(&t->flow_control, &s->flow_control, + send_bytes); + s->sending_bytes += send_bytes; + } + t->ping_state.pings_before_data_required = + t->ping_policy.max_pings_without_data; + if (!t->is_client) { + t->ping_recv_state.last_ping_recv_time = + gpr_inf_past(GPR_CLOCK_MONOTONIC); + t->ping_recv_state.ping_strikes = 0; + } if (is_last_frame) { s->send_trailing_metadata = NULL; s->sent_trailing_metadata = true; if (!t->is_client && !s->read_closed) { grpc_slice_buffer_add(&t->outbuf, grpc_chttp2_rst_stream_create( - s->id, GRPC_CHTTP2_NO_ERROR, + s->id, GRPC_HTTP2_NO_ERROR, &s->stats.outgoing)); } } - s->sending_bytes += send_bytes; now_writing = true; - if (s->flow_controlled_buffer.length > 0) { + if (s->flow_controlled_buffer.length > 0 || + (s->stream_compression_send_enabled && + s->compressed_data_buffer->length > 0)) { GRPC_CHTTP2_STREAM_REF(s, "chttp2_writing:fork"); grpc_chttp2_list_add_writable_stream(t, s); } - } else if (t->outgoing_window == 0) { + } else if (t->flow_control.remote_window == 0) { grpc_chttp2_list_add_stalled_by_transport(t, s); now_writing = true; + } else if (stream_remote_window == 0) { + grpc_chttp2_list_add_stalled_by_stream(t, s); + now_writing = true; } } if (s->send_trailing_metadata != NULL && s->fetching_send_message == NULL && - s->flow_controlled_buffer.length == 0) { + s->flow_controlled_buffer.length == 0 && + (!s->stream_compression_send_enabled || + s->compressed_data_buffer->length == 0)) { + GRPC_CHTTP2_IF_TRACING(gpr_log(GPR_INFO, "sending trailing_metadata")); if (grpc_metadata_batch_is_empty(s->send_trailing_metadata)) { grpc_chttp2_encode_data(s->id, &s->flow_controlled_buffer, 0, true, &s->stats.outgoing, &t->outbuf); } else { - grpc_chttp2_encode_header( - &t->hpack_compressor, s->id, s->send_trailing_metadata, true, - t->settings[GRPC_ACKED_SETTINGS] - [GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE], - &s->stats.outgoing, &t->outbuf); + grpc_encode_header_options hopt = { + .stream_id = s->id, + .is_eof = true, + .use_true_binary_metadata = + t->settings + [GRPC_PEER_SETTINGS] + [GRPC_CHTTP2_SETTINGS_GRPC_ALLOW_TRUE_BINARY_METADATA] != + 0, + .max_frame_size = + t->settings[GRPC_PEER_SETTINGS] + [GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE], + .stats = &s->stats.outgoing}; + grpc_chttp2_encode_header(exec_ctx, &t->hpack_compressor, + extra_headers_for_trailing_metadata, + num_extra_headers_for_trailing_metadata, + s->send_trailing_metadata, &hopt, + &t->outbuf); } s->send_trailing_metadata = NULL; s->sent_trailing_metadata = true; if (!t->is_client && !s->read_closed) { grpc_slice_buffer_add( &t->outbuf, grpc_chttp2_rst_stream_create( - s->id, GRPC_CHTTP2_NO_ERROR, &s->stats.outgoing)); + s->id, GRPC_HTTP2_NO_ERROR, &s->stats.outgoing)); } now_writing = true; } @@ -212,21 +442,37 @@ bool grpc_chttp2_begin_write(grpc_exec_ctx *exec_ctx, } } - /* if the grpc_chttp2_transport is ready to send a window update, do so here - also; 3/4 is a magic number that will likely get tuned soon */ - if (t->announce_incoming_window > 0) { - uint32_t announced = - (uint32_t)GPR_MIN(t->announce_incoming_window, UINT32_MAX); - GRPC_CHTTP2_FLOW_DEBIT_TRANSPORT("write", t, announce_incoming_window, - announced); + uint32_t transport_announce = + grpc_chttp2_flowctl_maybe_send_transport_update(&t->flow_control); + if (transport_announce) { + maybe_initiate_ping(exec_ctx, t, + GRPC_CHTTP2_PING_BEFORE_TRANSPORT_WINDOW_UPDATE); grpc_transport_one_way_stats throwaway_stats; - grpc_slice_buffer_add(&t->outbuf, grpc_chttp2_window_update_create( - 0, announced, &throwaway_stats)); + grpc_slice_buffer_add( + &t->outbuf, grpc_chttp2_window_update_create(0, transport_announce, + &throwaway_stats)); + t->ping_state.pings_before_data_required = + t->ping_policy.max_pings_without_data; + if (!t->is_client) { + t->ping_recv_state.last_ping_recv_time = + gpr_inf_past(GPR_CLOCK_MONOTONIC); + t->ping_recv_state.ping_strikes = 0; + } } + for (size_t i = 0; i < t->ping_ack_count; i++) { + grpc_slice_buffer_add(&t->outbuf, + grpc_chttp2_ping_create(1, t->ping_acks[i])); + } + t->ping_ack_count = 0; + + maybe_initiate_ping(exec_ctx, t, GRPC_CHTTP2_PING_ON_NEXT_WRITE); + GPR_TIMER_END("grpc_chttp2_begin_write", 0); - return t->outbuf.count > 0; + return t->outbuf.count > 0 ? (partial_write ? GRPC_CHTTP2_PARTIAL_WRITE + : GRPC_CHTTP2_FULL_WRITE) + : GRPC_CHTTP2_NOTHING_TO_WRITE; } void grpc_chttp2_end_write(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, @@ -254,7 +500,7 @@ void grpc_chttp2_end_write(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, } GRPC_CHTTP2_STREAM_UNREF(exec_ctx, s, "chttp2_writing:end"); } - grpc_slice_buffer_reset_and_unref(&t->outbuf); + grpc_slice_buffer_reset_and_unref_internal(exec_ctx, &t->outbuf); GRPC_ERROR_UNREF(error); GPR_TIMER_END("grpc_chttp2_end_write", 0); } diff --git a/Sources/CgRPC/src/core/ext/transport/inproc/inproc_plugin.c b/Sources/CgRPC/src/core/ext/transport/inproc/inproc_plugin.c new file mode 100644 index 000000000..6a796a0b1 --- /dev/null +++ b/Sources/CgRPC/src/core/ext/transport/inproc/inproc_plugin.c @@ -0,0 +1,29 @@ +/* + * + * Copyright 2017 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 "src/core/ext/transport/inproc/inproc_transport.h" +#include "src/core/lib/debug/trace.h" + +grpc_tracer_flag grpc_inproc_trace = GRPC_TRACER_INITIALIZER(false, "inproc"); + +void grpc_inproc_plugin_init(void) { + grpc_register_tracer(&grpc_inproc_trace); + grpc_inproc_transport_init(); +} + +void grpc_inproc_plugin_shutdown(void) { grpc_inproc_transport_shutdown(); } diff --git a/Sources/CgRPC/src/core/ext/transport/inproc/inproc_transport.c b/Sources/CgRPC/src/core/ext/transport/inproc/inproc_transport.c new file mode 100644 index 000000000..6f4b429ee --- /dev/null +++ b/Sources/CgRPC/src/core/ext/transport/inproc/inproc_transport.c @@ -0,0 +1,1303 @@ +/* + * + * Copyright 2017 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 "src/core/ext/transport/inproc/inproc_transport.h" +#include +#include +#include +#include +#include +#include "src/core/lib/channel/channel_args.h" +#include "src/core/lib/slice/slice_internal.h" +#include "src/core/lib/surface/api_trace.h" +#include "src/core/lib/surface/channel.h" +#include "src/core/lib/surface/channel_stack_type.h" +#include "src/core/lib/surface/server.h" +#include "src/core/lib/transport/connectivity_state.h" +#include "src/core/lib/transport/error_utils.h" +#include "src/core/lib/transport/transport_impl.h" + +#define INPROC_LOG(...) \ + do { \ + if (GRPC_TRACER_ON(grpc_inproc_trace)) gpr_log(__VA_ARGS__); \ + } while (0) + +static const grpc_transport_vtable inproc_vtable; +static grpc_slice g_empty_slice; +static grpc_slice g_fake_path_key; +static grpc_slice g_fake_path_value; +static grpc_slice g_fake_auth_key; +static grpc_slice g_fake_auth_value; + +typedef struct { + gpr_mu mu; + gpr_refcount refs; +} shared_mu; + +typedef struct inproc_transport { + grpc_transport base; + shared_mu *mu; + gpr_refcount refs; + bool is_client; + grpc_connectivity_state_tracker connectivity; + void (*accept_stream_cb)(grpc_exec_ctx *exec_ctx, void *user_data, + grpc_transport *transport, const void *server_data); + void *accept_stream_data; + bool is_closed; + struct inproc_transport *other_side; + struct inproc_stream *stream_list; +} inproc_transport; + +typedef struct sb_list_entry { + grpc_slice_buffer sb; + struct sb_list_entry *next; +} sb_list_entry; + +// Specialize grpc_byte_stream for our use case +typedef struct { + grpc_byte_stream base; + sb_list_entry *le; + grpc_error *shutdown_error; +} inproc_slice_byte_stream; + +typedef struct { + // TODO (vjpai): Add some inlined elements to avoid alloc in simple cases + sb_list_entry *head; + sb_list_entry *tail; +} slice_buffer_list; + +static void slice_buffer_list_init(slice_buffer_list *l) { + l->head = NULL; + l->tail = NULL; +} + +static void sb_list_entry_destroy(grpc_exec_ctx *exec_ctx, sb_list_entry *le) { + grpc_slice_buffer_destroy_internal(exec_ctx, &le->sb); + gpr_free(le); +} + +static void slice_buffer_list_destroy(grpc_exec_ctx *exec_ctx, + slice_buffer_list *l) { + sb_list_entry *curr = l->head; + while (curr != NULL) { + sb_list_entry *le = curr; + curr = curr->next; + sb_list_entry_destroy(exec_ctx, le); + } + l->head = NULL; + l->tail = NULL; +} + +static bool slice_buffer_list_empty(slice_buffer_list *l) { + return l->head == NULL; +} + +static void slice_buffer_list_append_entry(slice_buffer_list *l, + sb_list_entry *next) { + next->next = NULL; + if (l->tail) { + l->tail->next = next; + l->tail = next; + } else { + l->head = next; + l->tail = next; + } +} + +static grpc_slice_buffer *slice_buffer_list_append(slice_buffer_list *l) { + sb_list_entry *next = gpr_malloc(sizeof(*next)); + grpc_slice_buffer_init(&next->sb); + slice_buffer_list_append_entry(l, next); + return &next->sb; +} + +static sb_list_entry *slice_buffer_list_pophead(slice_buffer_list *l) { + sb_list_entry *ret = l->head; + l->head = l->head->next; + if (l->head == NULL) { + l->tail = NULL; + } + return ret; +} + +typedef struct inproc_stream { + inproc_transport *t; + grpc_metadata_batch to_read_initial_md; + uint32_t to_read_initial_md_flags; + bool to_read_initial_md_filled; + slice_buffer_list to_read_message; + grpc_metadata_batch to_read_trailing_md; + bool to_read_trailing_md_filled; + bool reads_needed; + bool read_closure_scheduled; + grpc_closure read_closure; + // Write buffer used only during gap at init time when client-side + // stream is set up but server side stream is not yet set up + grpc_metadata_batch write_buffer_initial_md; + bool write_buffer_initial_md_filled; + uint32_t write_buffer_initial_md_flags; + gpr_timespec write_buffer_deadline; + slice_buffer_list write_buffer_message; + grpc_metadata_batch write_buffer_trailing_md; + bool write_buffer_trailing_md_filled; + grpc_error *write_buffer_cancel_error; + + struct inproc_stream *other_side; + bool other_side_closed; // won't talk anymore + bool write_buffer_other_side_closed; // on hold + grpc_stream_refcount *refs; + grpc_closure *closure_at_destroy; + + gpr_arena *arena; + + grpc_transport_stream_op_batch *recv_initial_md_op; + grpc_transport_stream_op_batch *recv_message_op; + grpc_transport_stream_op_batch *recv_trailing_md_op; + + inproc_slice_byte_stream recv_message_stream; + + bool initial_md_sent; + bool trailing_md_sent; + bool initial_md_recvd; + bool trailing_md_recvd; + + bool closed; + + grpc_error *cancel_self_error; + grpc_error *cancel_other_error; + + gpr_timespec deadline; + + bool listed; + struct inproc_stream *stream_list_prev; + struct inproc_stream *stream_list_next; +} inproc_stream; + +static bool inproc_slice_byte_stream_next(grpc_exec_ctx *exec_ctx, + grpc_byte_stream *bs, size_t max, + grpc_closure *on_complete) { + // Because inproc transport always provides the entire message atomically, + // the byte stream always has data available when this function is called. + // Thus, this function always returns true (unlike other transports) and + // there is never any need to schedule a closure + return true; +} + +static grpc_error *inproc_slice_byte_stream_pull(grpc_exec_ctx *exec_ctx, + grpc_byte_stream *bs, + grpc_slice *slice) { + inproc_slice_byte_stream *stream = (inproc_slice_byte_stream *)bs; + if (stream->shutdown_error != GRPC_ERROR_NONE) { + return GRPC_ERROR_REF(stream->shutdown_error); + } + *slice = grpc_slice_buffer_take_first(&stream->le->sb); + return GRPC_ERROR_NONE; +} + +static void inproc_slice_byte_stream_shutdown(grpc_exec_ctx *exec_ctx, + grpc_byte_stream *bs, + grpc_error *error) { + inproc_slice_byte_stream *stream = (inproc_slice_byte_stream *)bs; + GRPC_ERROR_UNREF(stream->shutdown_error); + stream->shutdown_error = error; +} + +static void inproc_slice_byte_stream_destroy(grpc_exec_ctx *exec_ctx, + grpc_byte_stream *bs) { + inproc_slice_byte_stream *stream = (inproc_slice_byte_stream *)bs; + sb_list_entry_destroy(exec_ctx, stream->le); + GRPC_ERROR_UNREF(stream->shutdown_error); +} + +static const grpc_byte_stream_vtable inproc_slice_byte_stream_vtable = { + inproc_slice_byte_stream_next, inproc_slice_byte_stream_pull, + inproc_slice_byte_stream_shutdown, inproc_slice_byte_stream_destroy}; + +void inproc_slice_byte_stream_init(inproc_slice_byte_stream *s, + sb_list_entry *le) { + s->base.length = (uint32_t)le->sb.length; + s->base.flags = 0; + s->base.vtable = &inproc_slice_byte_stream_vtable; + s->le = le; + s->shutdown_error = GRPC_ERROR_NONE; +} + +static void ref_transport(inproc_transport *t) { + INPROC_LOG(GPR_DEBUG, "ref_transport %p", t); + gpr_ref(&t->refs); +} + +static void really_destroy_transport(grpc_exec_ctx *exec_ctx, + inproc_transport *t) { + INPROC_LOG(GPR_DEBUG, "really_destroy_transport %p", t); + grpc_connectivity_state_destroy(exec_ctx, &t->connectivity); + if (gpr_unref(&t->mu->refs)) { + gpr_free(t->mu); + } + gpr_free(t); +} + +static void unref_transport(grpc_exec_ctx *exec_ctx, inproc_transport *t) { + INPROC_LOG(GPR_DEBUG, "unref_transport %p", t); + if (gpr_unref(&t->refs)) { + really_destroy_transport(exec_ctx, t); + } +} + +#ifndef NDEBUG +#define STREAM_REF(refs, reason) grpc_stream_ref(refs, reason) +#define STREAM_UNREF(e, refs, reason) grpc_stream_unref(e, refs, reason) +#else +#define STREAM_REF(refs, reason) grpc_stream_ref(refs) +#define STREAM_UNREF(e, refs, reason) grpc_stream_unref(e, refs) +#endif + +static void ref_stream(inproc_stream *s, const char *reason) { + INPROC_LOG(GPR_DEBUG, "ref_stream %p %s", s, reason); + STREAM_REF(s->refs, reason); +} + +static void unref_stream(grpc_exec_ctx *exec_ctx, inproc_stream *s, + const char *reason) { + INPROC_LOG(GPR_DEBUG, "unref_stream %p %s", s, reason); + STREAM_UNREF(exec_ctx, s->refs, reason); +} + +static void really_destroy_stream(grpc_exec_ctx *exec_ctx, inproc_stream *s) { + INPROC_LOG(GPR_DEBUG, "really_destroy_stream %p", s); + + slice_buffer_list_destroy(exec_ctx, &s->to_read_message); + slice_buffer_list_destroy(exec_ctx, &s->write_buffer_message); + GRPC_ERROR_UNREF(s->write_buffer_cancel_error); + GRPC_ERROR_UNREF(s->cancel_self_error); + GRPC_ERROR_UNREF(s->cancel_other_error); + + unref_transport(exec_ctx, s->t); + + if (s->closure_at_destroy) { + GRPC_CLOSURE_SCHED(exec_ctx, s->closure_at_destroy, GRPC_ERROR_NONE); + } +} + +static void read_state_machine(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error); + +static void log_metadata(const grpc_metadata_batch *md_batch, bool is_client, + bool is_initial) { + for (grpc_linked_mdelem *md = md_batch->list.head; md != NULL; + md = md->next) { + char *key = grpc_slice_to_c_string(GRPC_MDKEY(md->md)); + char *value = grpc_slice_to_c_string(GRPC_MDVALUE(md->md)); + gpr_log(GPR_INFO, "INPROC:%s:%s: %s: %s", is_initial ? "HDR" : "TRL", + is_client ? "CLI" : "SVR", key, value); + gpr_free(key); + gpr_free(value); + } +} + +static grpc_error *fill_in_metadata(grpc_exec_ctx *exec_ctx, inproc_stream *s, + const grpc_metadata_batch *metadata, + uint32_t flags, grpc_metadata_batch *out_md, + uint32_t *outflags, bool *markfilled) { + if (GRPC_TRACER_ON(grpc_inproc_trace)) { + log_metadata(metadata, s->t->is_client, outflags != NULL); + } + + if (outflags != NULL) { + *outflags = flags; + } + if (markfilled != NULL) { + *markfilled = true; + } + grpc_error *error = GRPC_ERROR_NONE; + for (grpc_linked_mdelem *elem = metadata->list.head; + (elem != NULL) && (error == GRPC_ERROR_NONE); elem = elem->next) { + grpc_linked_mdelem *nelem = gpr_arena_alloc(s->arena, sizeof(*nelem)); + nelem->md = grpc_mdelem_from_slices( + exec_ctx, grpc_slice_intern(GRPC_MDKEY(elem->md)), + grpc_slice_intern(GRPC_MDVALUE(elem->md))); + + error = grpc_metadata_batch_link_tail(exec_ctx, out_md, nelem); + } + return error; +} + +static int init_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt, + grpc_stream *gs, grpc_stream_refcount *refcount, + const void *server_data, gpr_arena *arena) { + INPROC_LOG(GPR_DEBUG, "init_stream %p %p %p", gt, gs, server_data); + inproc_transport *t = (inproc_transport *)gt; + inproc_stream *s = (inproc_stream *)gs; + s->arena = arena; + + s->refs = refcount; + // Ref this stream right now + ref_stream(s, "inproc_init_stream:init"); + + grpc_metadata_batch_init(&s->to_read_initial_md); + s->to_read_initial_md_flags = 0; + s->to_read_initial_md_filled = false; + grpc_metadata_batch_init(&s->to_read_trailing_md); + s->to_read_trailing_md_filled = false; + grpc_metadata_batch_init(&s->write_buffer_initial_md); + s->write_buffer_initial_md_flags = 0; + s->write_buffer_initial_md_filled = false; + grpc_metadata_batch_init(&s->write_buffer_trailing_md); + s->write_buffer_trailing_md_filled = false; + slice_buffer_list_init(&s->to_read_message); + slice_buffer_list_init(&s->write_buffer_message); + s->reads_needed = false; + s->read_closure_scheduled = false; + GRPC_CLOSURE_INIT(&s->read_closure, read_state_machine, s, + grpc_schedule_on_exec_ctx); + s->t = t; + s->closure_at_destroy = NULL; + s->other_side_closed = false; + + s->initial_md_sent = s->trailing_md_sent = s->initial_md_recvd = + s->trailing_md_recvd = false; + + s->closed = false; + + s->cancel_self_error = GRPC_ERROR_NONE; + s->cancel_other_error = GRPC_ERROR_NONE; + s->write_buffer_cancel_error = GRPC_ERROR_NONE; + s->deadline = gpr_inf_future(GPR_CLOCK_MONOTONIC); + s->write_buffer_deadline = gpr_inf_future(GPR_CLOCK_MONOTONIC); + + s->stream_list_prev = NULL; + gpr_mu_lock(&t->mu->mu); + s->listed = true; + ref_stream(s, "inproc_init_stream:list"); + s->stream_list_next = t->stream_list; + if (t->stream_list) { + t->stream_list->stream_list_prev = s; + } + t->stream_list = s; + gpr_mu_unlock(&t->mu->mu); + + if (!server_data) { + ref_transport(t); + inproc_transport *st = t->other_side; + ref_transport(st); + s->other_side = NULL; // will get filled in soon + // Pass the client-side stream address to the server-side for a ref + ref_stream(s, "inproc_init_stream:clt"); // ref it now on behalf of server + // side to avoid destruction + INPROC_LOG(GPR_DEBUG, "calling accept stream cb %p %p", + st->accept_stream_cb, st->accept_stream_data); + (*st->accept_stream_cb)(exec_ctx, st->accept_stream_data, &st->base, + (void *)s); + } else { + // This is the server-side and is being called through accept_stream_cb + inproc_stream *cs = (inproc_stream *)server_data; + s->other_side = cs; + // Ref the server-side stream on behalf of the client now + ref_stream(s, "inproc_init_stream:srv"); + + // Now we are about to affect the other side, so lock the transport + // to make sure that it doesn't get destroyed + gpr_mu_lock(&s->t->mu->mu); + cs->other_side = s; + // Now transfer from the other side's write_buffer if any to the to_read + // buffer + if (cs->write_buffer_initial_md_filled) { + fill_in_metadata(exec_ctx, s, &cs->write_buffer_initial_md, + cs->write_buffer_initial_md_flags, + &s->to_read_initial_md, &s->to_read_initial_md_flags, + &s->to_read_initial_md_filled); + s->deadline = gpr_time_min(s->deadline, cs->write_buffer_deadline); + grpc_metadata_batch_clear(exec_ctx, &cs->write_buffer_initial_md); + cs->write_buffer_initial_md_filled = false; + } + while (!slice_buffer_list_empty(&cs->write_buffer_message)) { + slice_buffer_list_append_entry( + &s->to_read_message, + slice_buffer_list_pophead(&cs->write_buffer_message)); + } + if (cs->write_buffer_trailing_md_filled) { + fill_in_metadata(exec_ctx, s, &cs->write_buffer_trailing_md, 0, + &s->to_read_trailing_md, NULL, + &s->to_read_trailing_md_filled); + grpc_metadata_batch_clear(exec_ctx, &cs->write_buffer_trailing_md); + cs->write_buffer_trailing_md_filled = false; + } + if (cs->write_buffer_cancel_error != GRPC_ERROR_NONE) { + s->cancel_other_error = cs->write_buffer_cancel_error; + cs->write_buffer_cancel_error = GRPC_ERROR_NONE; + } + + gpr_mu_unlock(&s->t->mu->mu); + } + return 0; // return value is not important +} + +static void close_stream_locked(grpc_exec_ctx *exec_ctx, inproc_stream *s) { + if (!s->closed) { + // Release the metadata that we would have written out + grpc_metadata_batch_destroy(exec_ctx, &s->write_buffer_initial_md); + grpc_metadata_batch_destroy(exec_ctx, &s->write_buffer_trailing_md); + + if (s->listed) { + inproc_stream *p = s->stream_list_prev; + inproc_stream *n = s->stream_list_next; + if (p != NULL) { + p->stream_list_next = n; + } else { + s->t->stream_list = n; + } + if (n != NULL) { + n->stream_list_prev = p; + } + s->listed = false; + unref_stream(exec_ctx, s, "close_stream:list"); + } + s->closed = true; + unref_stream(exec_ctx, s, "close_stream:closing"); + } +} + +// This function means that we are done talking/listening to the other side +static void close_other_side_locked(grpc_exec_ctx *exec_ctx, inproc_stream *s, + const char *reason) { + if (s->other_side != NULL) { + // First release the metadata that came from the other side's arena + grpc_metadata_batch_destroy(exec_ctx, &s->to_read_initial_md); + grpc_metadata_batch_destroy(exec_ctx, &s->to_read_trailing_md); + + unref_stream(exec_ctx, s->other_side, reason); + s->other_side_closed = true; + s->other_side = NULL; + } else if (!s->other_side_closed) { + s->write_buffer_other_side_closed = true; + } +} + +static void fail_helper_locked(grpc_exec_ctx *exec_ctx, inproc_stream *s, + grpc_error *error) { + INPROC_LOG(GPR_DEBUG, "read_state_machine %p fail_helper", s); + // If we're failing this side, we need to make sure that + // we also send or have already sent trailing metadata + if (!s->trailing_md_sent) { + // Send trailing md to the other side indicating cancellation + s->trailing_md_sent = true; + + grpc_metadata_batch fake_md; + grpc_metadata_batch_init(&fake_md); + + inproc_stream *other = s->other_side; + grpc_metadata_batch *dest = (other == NULL) ? &s->write_buffer_trailing_md + : &other->to_read_trailing_md; + bool *destfilled = (other == NULL) ? &s->write_buffer_trailing_md_filled + : &other->to_read_trailing_md_filled; + fill_in_metadata(exec_ctx, s, &fake_md, 0, dest, NULL, destfilled); + grpc_metadata_batch_destroy(exec_ctx, &fake_md); + + if (other != NULL) { + if (other->cancel_other_error == GRPC_ERROR_NONE) { + other->cancel_other_error = GRPC_ERROR_REF(error); + } + if (other->reads_needed) { + if (!other->read_closure_scheduled) { + GRPC_CLOSURE_SCHED(exec_ctx, &other->read_closure, + GRPC_ERROR_REF(error)); + other->read_closure_scheduled = true; + } + other->reads_needed = false; + } + } else if (s->write_buffer_cancel_error == GRPC_ERROR_NONE) { + s->write_buffer_cancel_error = GRPC_ERROR_REF(error); + } + } + if (s->recv_initial_md_op) { + grpc_error *err; + if (!s->t->is_client) { + // If this is a server, provide initial metadata with a path and authority + // since it expects that as well as no error yet + grpc_metadata_batch fake_md; + grpc_metadata_batch_init(&fake_md); + grpc_linked_mdelem *path_md = gpr_arena_alloc(s->arena, sizeof(*path_md)); + path_md->md = + grpc_mdelem_from_slices(exec_ctx, g_fake_path_key, g_fake_path_value); + GPR_ASSERT(grpc_metadata_batch_link_tail(exec_ctx, &fake_md, path_md) == + GRPC_ERROR_NONE); + grpc_linked_mdelem *auth_md = gpr_arena_alloc(s->arena, sizeof(*auth_md)); + auth_md->md = + grpc_mdelem_from_slices(exec_ctx, g_fake_auth_key, g_fake_auth_value); + GPR_ASSERT(grpc_metadata_batch_link_tail(exec_ctx, &fake_md, auth_md) == + GRPC_ERROR_NONE); + + fill_in_metadata( + exec_ctx, s, &fake_md, 0, + s->recv_initial_md_op->payload->recv_initial_metadata + .recv_initial_metadata, + s->recv_initial_md_op->payload->recv_initial_metadata.recv_flags, + NULL); + grpc_metadata_batch_destroy(exec_ctx, &fake_md); + err = GRPC_ERROR_NONE; + } else { + err = GRPC_ERROR_REF(error); + } + INPROC_LOG(GPR_DEBUG, + "fail_helper %p scheduling initial-metadata-ready %p %p", s, + error, err); + GRPC_CLOSURE_SCHED(exec_ctx, + s->recv_initial_md_op->payload->recv_initial_metadata + .recv_initial_metadata_ready, + err); + // Last use of err so no need to REF and then UNREF it + + if ((s->recv_initial_md_op != s->recv_message_op) && + (s->recv_initial_md_op != s->recv_trailing_md_op)) { + INPROC_LOG(GPR_DEBUG, + "fail_helper %p scheduling initial-metadata-on-complete %p", + error, s); + GRPC_CLOSURE_SCHED(exec_ctx, s->recv_initial_md_op->on_complete, + GRPC_ERROR_REF(error)); + } + s->recv_initial_md_op = NULL; + } + if (s->recv_message_op) { + INPROC_LOG(GPR_DEBUG, "fail_helper %p scheduling message-ready %p", s, + error); + GRPC_CLOSURE_SCHED( + exec_ctx, s->recv_message_op->payload->recv_message.recv_message_ready, + GRPC_ERROR_REF(error)); + if (s->recv_message_op != s->recv_trailing_md_op) { + INPROC_LOG(GPR_DEBUG, "fail_helper %p scheduling message-on-complete %p", + s, error); + GRPC_CLOSURE_SCHED(exec_ctx, s->recv_message_op->on_complete, + GRPC_ERROR_REF(error)); + } + s->recv_message_op = NULL; + } + if (s->recv_trailing_md_op) { + INPROC_LOG(GPR_DEBUG, + "fail_helper %p scheduling trailing-md-on-complete %p", s, + error); + GRPC_CLOSURE_SCHED(exec_ctx, s->recv_trailing_md_op->on_complete, + GRPC_ERROR_REF(error)); + s->recv_trailing_md_op = NULL; + } + close_other_side_locked(exec_ctx, s, "fail_helper:other_side"); + close_stream_locked(exec_ctx, s); + + GRPC_ERROR_UNREF(error); +} + +static void read_state_machine(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error) { + // This function gets called when we have contents in the unprocessed reads + // Get what we want based on our ops wanted + // Schedule our appropriate closures + // and then return to reads_needed state if still needed + + // Since this is a closure directly invoked by the combiner, it should not + // unref the error parameter explicitly; the combiner will do that implicitly + grpc_error *new_err = GRPC_ERROR_NONE; + + bool needs_close = false; + + INPROC_LOG(GPR_DEBUG, "read_state_machine %p", arg); + inproc_stream *s = (inproc_stream *)arg; + gpr_mu *mu = &s->t->mu->mu; // keep aside in case s gets closed + gpr_mu_lock(mu); + s->read_closure_scheduled = false; + // cancellation takes precedence + if (s->cancel_self_error != GRPC_ERROR_NONE) { + fail_helper_locked(exec_ctx, s, GRPC_ERROR_REF(s->cancel_self_error)); + goto done; + } else if (s->cancel_other_error != GRPC_ERROR_NONE) { + fail_helper_locked(exec_ctx, s, GRPC_ERROR_REF(s->cancel_other_error)); + goto done; + } else if (error != GRPC_ERROR_NONE) { + fail_helper_locked(exec_ctx, s, GRPC_ERROR_REF(error)); + goto done; + } + + if (s->recv_initial_md_op) { + if (!s->to_read_initial_md_filled) { + // We entered the state machine on some other kind of read even though + // we still haven't satisfied initial md . That's an error. + new_err = + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Unexpected frame sequencing"); + INPROC_LOG(GPR_DEBUG, + "read_state_machine %p scheduling on_complete errors for no " + "initial md %p", + s, new_err); + fail_helper_locked(exec_ctx, s, GRPC_ERROR_REF(new_err)); + goto done; + } else if (s->initial_md_recvd) { + new_err = + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Already recvd initial md"); + INPROC_LOG( + GPR_DEBUG, + "read_state_machine %p scheduling on_complete errors for already " + "recvd initial md %p", + s, new_err); + fail_helper_locked(exec_ctx, s, GRPC_ERROR_REF(new_err)); + goto done; + } + + s->initial_md_recvd = true; + new_err = fill_in_metadata( + exec_ctx, s, &s->to_read_initial_md, s->to_read_initial_md_flags, + s->recv_initial_md_op->payload->recv_initial_metadata + .recv_initial_metadata, + s->recv_initial_md_op->payload->recv_initial_metadata.recv_flags, NULL); + s->recv_initial_md_op->payload->recv_initial_metadata.recv_initial_metadata + ->deadline = s->deadline; + grpc_metadata_batch_clear(exec_ctx, &s->to_read_initial_md); + s->to_read_initial_md_filled = false; + INPROC_LOG(GPR_DEBUG, + "read_state_machine %p scheduling initial-metadata-ready %p", s, + new_err); + GRPC_CLOSURE_SCHED(exec_ctx, + s->recv_initial_md_op->payload->recv_initial_metadata + .recv_initial_metadata_ready, + GRPC_ERROR_REF(new_err)); + if ((s->recv_initial_md_op != s->recv_message_op) && + (s->recv_initial_md_op != s->recv_trailing_md_op)) { + INPROC_LOG( + GPR_DEBUG, + "read_state_machine %p scheduling initial-metadata-on-complete %p", s, + new_err); + GRPC_CLOSURE_SCHED(exec_ctx, s->recv_initial_md_op->on_complete, + GRPC_ERROR_REF(new_err)); + } + s->recv_initial_md_op = NULL; + + if (new_err != GRPC_ERROR_NONE) { + INPROC_LOG(GPR_DEBUG, + "read_state_machine %p scheduling on_complete errors2 %p", s, + new_err); + fail_helper_locked(exec_ctx, s, GRPC_ERROR_REF(new_err)); + goto done; + } + } + if (s->to_read_initial_md_filled) { + new_err = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Unexpected recv frame"); + fail_helper_locked(exec_ctx, s, GRPC_ERROR_REF(new_err)); + goto done; + } + if (!slice_buffer_list_empty(&s->to_read_message) && s->recv_message_op) { + inproc_slice_byte_stream_init( + &s->recv_message_stream, + slice_buffer_list_pophead(&s->to_read_message)); + *s->recv_message_op->payload->recv_message.recv_message = + &s->recv_message_stream.base; + INPROC_LOG(GPR_DEBUG, "read_state_machine %p scheduling message-ready", s); + GRPC_CLOSURE_SCHED( + exec_ctx, s->recv_message_op->payload->recv_message.recv_message_ready, + GRPC_ERROR_NONE); + if (s->recv_message_op != s->recv_trailing_md_op) { + INPROC_LOG(GPR_DEBUG, + "read_state_machine %p scheduling message-on-complete %p", s, + new_err); + GRPC_CLOSURE_SCHED(exec_ctx, s->recv_message_op->on_complete, + GRPC_ERROR_REF(new_err)); + } + s->recv_message_op = NULL; + } + if (s->to_read_trailing_md_filled) { + if (s->trailing_md_recvd) { + new_err = + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Already recvd trailing md"); + INPROC_LOG( + GPR_DEBUG, + "read_state_machine %p scheduling on_complete errors for already " + "recvd trailing md %p", + s, new_err); + fail_helper_locked(exec_ctx, s, GRPC_ERROR_REF(new_err)); + goto done; + } + if (s->recv_message_op != NULL) { + // This message needs to be wrapped up because it will never be + // satisfied + INPROC_LOG(GPR_DEBUG, "read_state_machine %p scheduling message-ready", + s); + GRPC_CLOSURE_SCHED( + exec_ctx, + s->recv_message_op->payload->recv_message.recv_message_ready, + GRPC_ERROR_NONE); + if (s->recv_message_op != s->recv_trailing_md_op) { + INPROC_LOG(GPR_DEBUG, + "read_state_machine %p scheduling message-on-complete %p", s, + new_err); + GRPC_CLOSURE_SCHED(exec_ctx, s->recv_message_op->on_complete, + GRPC_ERROR_REF(new_err)); + } + s->recv_message_op = NULL; + } + if (s->recv_trailing_md_op != NULL) { + // We wanted trailing metadata and we got it + s->trailing_md_recvd = true; + new_err = + fill_in_metadata(exec_ctx, s, &s->to_read_trailing_md, 0, + s->recv_trailing_md_op->payload + ->recv_trailing_metadata.recv_trailing_metadata, + NULL, NULL); + grpc_metadata_batch_clear(exec_ctx, &s->to_read_trailing_md); + s->to_read_trailing_md_filled = false; + + // We should schedule the recv_trailing_md_op completion if + // 1. this stream is the client-side + // 2. this stream is the server-side AND has already sent its trailing md + // (If the server hasn't already sent its trailing md, it doesn't have + // a final status, so don't mark this op complete) + if (s->t->is_client || s->trailing_md_sent) { + INPROC_LOG( + GPR_DEBUG, + "read_state_machine %p scheduling trailing-md-on-complete %p", s, + new_err); + GRPC_CLOSURE_SCHED(exec_ctx, s->recv_trailing_md_op->on_complete, + GRPC_ERROR_REF(new_err)); + s->recv_trailing_md_op = NULL; + needs_close = true; + } else { + INPROC_LOG(GPR_DEBUG, + "read_state_machine %p server needs to delay handling " + "trailing-md-on-complete %p", + s, new_err); + } + } else { + INPROC_LOG( + GPR_DEBUG, + "read_state_machine %p has trailing md but not yet waiting for it", + s); + } + } + if (s->trailing_md_recvd && s->recv_message_op) { + // No further message will come on this stream, so finish off the + // recv_message_op + INPROC_LOG(GPR_DEBUG, "read_state_machine %p scheduling message-ready", s); + GRPC_CLOSURE_SCHED( + exec_ctx, s->recv_message_op->payload->recv_message.recv_message_ready, + GRPC_ERROR_NONE); + if (s->recv_message_op != s->recv_trailing_md_op) { + INPROC_LOG(GPR_DEBUG, + "read_state_machine %p scheduling message-on-complete %p", s, + new_err); + GRPC_CLOSURE_SCHED(exec_ctx, s->recv_message_op->on_complete, + GRPC_ERROR_REF(new_err)); + } + s->recv_message_op = NULL; + } + if (s->recv_message_op || s->recv_trailing_md_op) { + // Didn't get the item we wanted so we still need to get + // rescheduled + INPROC_LOG(GPR_DEBUG, "read_state_machine %p still needs closure %p %p", s, + s->recv_message_op, s->recv_trailing_md_op); + s->reads_needed = true; + } +done: + if (needs_close) { + close_other_side_locked(exec_ctx, s, "read_state_machine"); + close_stream_locked(exec_ctx, s); + } + gpr_mu_unlock(mu); + GRPC_ERROR_UNREF(new_err); +} + +static grpc_closure do_nothing_closure; + +static bool cancel_stream_locked(grpc_exec_ctx *exec_ctx, inproc_stream *s, + grpc_error *error) { + bool ret = false; // was the cancel accepted + INPROC_LOG(GPR_DEBUG, "cancel_stream %p with %s", s, + grpc_error_string(error)); + if (s->cancel_self_error == GRPC_ERROR_NONE) { + ret = true; + s->cancel_self_error = GRPC_ERROR_REF(error); + if (s->reads_needed) { + if (!s->read_closure_scheduled) { + GRPC_CLOSURE_SCHED(exec_ctx, &s->read_closure, + GRPC_ERROR_REF(s->cancel_self_error)); + s->read_closure_scheduled = true; + } + s->reads_needed = false; + } + // Send trailing md to the other side indicating cancellation, even if we + // already have + s->trailing_md_sent = true; + + grpc_metadata_batch cancel_md; + grpc_metadata_batch_init(&cancel_md); + + inproc_stream *other = s->other_side; + grpc_metadata_batch *dest = (other == NULL) ? &s->write_buffer_trailing_md + : &other->to_read_trailing_md; + bool *destfilled = (other == NULL) ? &s->write_buffer_trailing_md_filled + : &other->to_read_trailing_md_filled; + fill_in_metadata(exec_ctx, s, &cancel_md, 0, dest, NULL, destfilled); + grpc_metadata_batch_destroy(exec_ctx, &cancel_md); + + if (other != NULL) { + if (other->cancel_other_error == GRPC_ERROR_NONE) { + other->cancel_other_error = GRPC_ERROR_REF(s->cancel_self_error); + } + if (other->reads_needed) { + if (!other->read_closure_scheduled) { + GRPC_CLOSURE_SCHED(exec_ctx, &other->read_closure, + GRPC_ERROR_REF(other->cancel_other_error)); + other->read_closure_scheduled = true; + } + other->reads_needed = false; + } + } else if (s->write_buffer_cancel_error == GRPC_ERROR_NONE) { + s->write_buffer_cancel_error = GRPC_ERROR_REF(s->cancel_self_error); + } + + // if we are a server and already received trailing md but + // couldn't complete that because we hadn't yet sent out trailing + // md, now's the chance + if (!s->t->is_client && s->trailing_md_recvd && s->recv_trailing_md_op) { + INPROC_LOG(GPR_DEBUG, + "cancel_stream %p scheduling trailing-md-on-complete %p", s, + s->cancel_self_error); + GRPC_CLOSURE_SCHED(exec_ctx, s->recv_trailing_md_op->on_complete, + GRPC_ERROR_REF(s->cancel_self_error)); + s->recv_trailing_md_op = NULL; + } + } + + close_other_side_locked(exec_ctx, s, "cancel_stream:other_side"); + close_stream_locked(exec_ctx, s); + + GRPC_ERROR_UNREF(error); + return ret; +} + +static void perform_stream_op(grpc_exec_ctx *exec_ctx, grpc_transport *gt, + grpc_stream *gs, + grpc_transport_stream_op_batch *op) { + INPROC_LOG(GPR_DEBUG, "perform_stream_op %p %p %p", gt, gs, op); + inproc_stream *s = (inproc_stream *)gs; + gpr_mu *mu = &s->t->mu->mu; // save aside in case s gets closed + gpr_mu_lock(mu); + + if (GRPC_TRACER_ON(grpc_inproc_trace)) { + if (op->send_initial_metadata) { + log_metadata(op->payload->send_initial_metadata.send_initial_metadata, + s->t->is_client, true); + } + if (op->send_trailing_metadata) { + log_metadata(op->payload->send_trailing_metadata.send_trailing_metadata, + s->t->is_client, false); + } + } + grpc_error *error = GRPC_ERROR_NONE; + grpc_closure *on_complete = op->on_complete; + if (on_complete == NULL) { + on_complete = &do_nothing_closure; + } + + if (op->cancel_stream) { + // Call cancel_stream_locked without ref'ing the cancel_error because + // this function is responsible to make sure that that field gets unref'ed + cancel_stream_locked(exec_ctx, s, op->payload->cancel_stream.cancel_error); + // this op can complete without an error + } else if (s->cancel_self_error != GRPC_ERROR_NONE) { + // already self-canceled so still give it an error + error = GRPC_ERROR_REF(s->cancel_self_error); + } else { + INPROC_LOG(GPR_DEBUG, "perform_stream_op %p%s%s%s%s%s%s", s, + op->send_initial_metadata ? " send_initial_metadata" : "", + op->send_message ? " send_message" : "", + op->send_trailing_metadata ? " send_trailing_metadata" : "", + op->recv_initial_metadata ? " recv_initial_metadata" : "", + op->recv_message ? " recv_message" : "", + op->recv_trailing_metadata ? " recv_trailing_metadata" : ""); + } + + bool needs_close = false; + + if (error == GRPC_ERROR_NONE && + (op->send_initial_metadata || op->send_message || + op->send_trailing_metadata)) { + inproc_stream *other = s->other_side; + if (s->t->is_closed) { + error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Endpoint already shutdown"); + } + if (error == GRPC_ERROR_NONE && op->send_initial_metadata) { + grpc_metadata_batch *dest = (other == NULL) ? &s->write_buffer_initial_md + : &other->to_read_initial_md; + uint32_t *destflags = (other == NULL) ? &s->write_buffer_initial_md_flags + : &other->to_read_initial_md_flags; + bool *destfilled = (other == NULL) ? &s->write_buffer_initial_md_filled + : &other->to_read_initial_md_filled; + if (*destfilled || s->initial_md_sent) { + // The buffer is already in use; that's an error! + INPROC_LOG(GPR_DEBUG, "Extra initial metadata %p", s); + error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Extra initial metadata"); + } else { + if (!other->closed) { + fill_in_metadata( + exec_ctx, s, + op->payload->send_initial_metadata.send_initial_metadata, + op->payload->send_initial_metadata.send_initial_metadata_flags, + dest, destflags, destfilled); + } + if (s->t->is_client) { + gpr_timespec *dl = + (other == NULL) ? &s->write_buffer_deadline : &other->deadline; + *dl = gpr_time_min(*dl, op->payload->send_initial_metadata + .send_initial_metadata->deadline); + s->initial_md_sent = true; + } + } + } + if (error == GRPC_ERROR_NONE && op->send_message) { + size_t remaining = op->payload->send_message.send_message->length; + grpc_slice_buffer *dest = slice_buffer_list_append( + (other == NULL) ? &s->write_buffer_message : &other->to_read_message); + do { + grpc_slice message_slice; + grpc_closure unused; + GPR_ASSERT(grpc_byte_stream_next(exec_ctx, + op->payload->send_message.send_message, + SIZE_MAX, &unused)); + error = grpc_byte_stream_pull( + exec_ctx, op->payload->send_message.send_message, &message_slice); + if (error != GRPC_ERROR_NONE) { + cancel_stream_locked(exec_ctx, s, GRPC_ERROR_REF(error)); + break; + } + GPR_ASSERT(error == GRPC_ERROR_NONE); + remaining -= GRPC_SLICE_LENGTH(message_slice); + grpc_slice_buffer_add(dest, message_slice); + } while (remaining != 0); + grpc_byte_stream_destroy(exec_ctx, + op->payload->send_message.send_message); + } + if (error == GRPC_ERROR_NONE && op->send_trailing_metadata) { + grpc_metadata_batch *dest = (other == NULL) ? &s->write_buffer_trailing_md + : &other->to_read_trailing_md; + bool *destfilled = (other == NULL) ? &s->write_buffer_trailing_md_filled + : &other->to_read_trailing_md_filled; + if (*destfilled || s->trailing_md_sent) { + // The buffer is already in use; that's an error! + INPROC_LOG(GPR_DEBUG, "Extra trailing metadata %p", s); + error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Extra trailing metadata"); + } else { + if (!other->closed) { + fill_in_metadata( + exec_ctx, s, + op->payload->send_trailing_metadata.send_trailing_metadata, 0, + dest, NULL, destfilled); + } + s->trailing_md_sent = true; + if (!s->t->is_client && s->trailing_md_recvd && + s->recv_trailing_md_op) { + INPROC_LOG(GPR_DEBUG, + "perform_stream_op %p scheduling trailing-md-on-complete", + s); + GRPC_CLOSURE_SCHED(exec_ctx, s->recv_trailing_md_op->on_complete, + GRPC_ERROR_NONE); + s->recv_trailing_md_op = NULL; + needs_close = true; + } + } + } + if (other != NULL && other->reads_needed) { + if (!other->read_closure_scheduled) { + GRPC_CLOSURE_SCHED(exec_ctx, &other->read_closure, error); + other->read_closure_scheduled = true; + } + other->reads_needed = false; + } + } + if (error == GRPC_ERROR_NONE && + (op->recv_initial_metadata || op->recv_message || + op->recv_trailing_metadata)) { + // If there are any reads, mark it so that the read closure will react to + // them + if (op->recv_initial_metadata) { + s->recv_initial_md_op = op; + } + if (op->recv_message) { + s->recv_message_op = op; + } + if (op->recv_trailing_metadata) { + s->recv_trailing_md_op = op; + } + + // We want to initiate the closure if: + // 1. There is initial metadata and something ready to take that + // 2. There is a message and something ready to take it + // 3. There is trailing metadata, even if nothing specifically wants + // that because that can shut down the message as well + if ((s->to_read_initial_md_filled && op->recv_initial_metadata) || + ((!slice_buffer_list_empty(&s->to_read_message) || + s->trailing_md_recvd) && + op->recv_message) || + (s->to_read_trailing_md_filled)) { + if (!s->read_closure_scheduled) { + GRPC_CLOSURE_SCHED(exec_ctx, &s->read_closure, GRPC_ERROR_NONE); + s->read_closure_scheduled = true; + } + } else { + s->reads_needed = true; + } + } else { + if (error != GRPC_ERROR_NONE) { + // Schedule op's read closures that we didn't push to read state machine + if (op->recv_initial_metadata) { + INPROC_LOG( + GPR_DEBUG, + "perform_stream_op error %p scheduling initial-metadata-ready %p", + s, error); + GRPC_CLOSURE_SCHED( + exec_ctx, + op->payload->recv_initial_metadata.recv_initial_metadata_ready, + GRPC_ERROR_REF(error)); + } + if (op->recv_message) { + INPROC_LOG( + GPR_DEBUG, + "perform_stream_op error %p scheduling recv message-ready %p", s, + error); + GRPC_CLOSURE_SCHED(exec_ctx, + op->payload->recv_message.recv_message_ready, + GRPC_ERROR_REF(error)); + } + } + INPROC_LOG(GPR_DEBUG, "perform_stream_op %p scheduling on_complete %p", s, + error); + GRPC_CLOSURE_SCHED(exec_ctx, on_complete, GRPC_ERROR_REF(error)); + } + if (needs_close) { + close_other_side_locked(exec_ctx, s, "perform_stream_op:other_side"); + close_stream_locked(exec_ctx, s); + } + gpr_mu_unlock(mu); + GRPC_ERROR_UNREF(error); +} + +static void close_transport_locked(grpc_exec_ctx *exec_ctx, + inproc_transport *t) { + INPROC_LOG(GPR_DEBUG, "close_transport %p %d", t, t->is_closed); + grpc_connectivity_state_set( + exec_ctx, &t->connectivity, GRPC_CHANNEL_SHUTDOWN, + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Closing transport."), + "close transport"); + if (!t->is_closed) { + t->is_closed = true; + /* Also end all streams on this transport */ + while (t->stream_list != NULL) { + // cancel_stream_locked also adjusts stream list + cancel_stream_locked( + exec_ctx, t->stream_list, + grpc_error_set_int( + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Transport closed"), + GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE)); + } + } +} + +static void perform_transport_op(grpc_exec_ctx *exec_ctx, grpc_transport *gt, + grpc_transport_op *op) { + inproc_transport *t = (inproc_transport *)gt; + INPROC_LOG(GPR_DEBUG, "perform_transport_op %p %p", t, op); + gpr_mu_lock(&t->mu->mu); + if (op->on_connectivity_state_change) { + grpc_connectivity_state_notify_on_state_change( + exec_ctx, &t->connectivity, op->connectivity_state, + op->on_connectivity_state_change); + } + if (op->set_accept_stream) { + t->accept_stream_cb = op->set_accept_stream_fn; + t->accept_stream_data = op->set_accept_stream_user_data; + } + if (op->on_consumed) { + GRPC_CLOSURE_SCHED(exec_ctx, op->on_consumed, GRPC_ERROR_NONE); + } + + bool do_close = false; + if (op->goaway_error != GRPC_ERROR_NONE) { + do_close = true; + GRPC_ERROR_UNREF(op->goaway_error); + } + if (op->disconnect_with_error != GRPC_ERROR_NONE) { + do_close = true; + GRPC_ERROR_UNREF(op->disconnect_with_error); + } + + if (do_close) { + close_transport_locked(exec_ctx, t); + } + gpr_mu_unlock(&t->mu->mu); +} + +static void destroy_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt, + grpc_stream *gs, + grpc_closure *then_schedule_closure) { + INPROC_LOG(GPR_DEBUG, "destroy_stream %p %p", gs, then_schedule_closure); + inproc_stream *s = (inproc_stream *)gs; + s->closure_at_destroy = then_schedule_closure; + really_destroy_stream(exec_ctx, s); +} + +static void destroy_transport(grpc_exec_ctx *exec_ctx, grpc_transport *gt) { + inproc_transport *t = (inproc_transport *)gt; + INPROC_LOG(GPR_DEBUG, "destroy_transport %p", t); + gpr_mu_lock(&t->mu->mu); + close_transport_locked(exec_ctx, t); + gpr_mu_unlock(&t->mu->mu); + unref_transport(exec_ctx, t->other_side); + unref_transport(exec_ctx, t); +} + +/******************************************************************************* + * Main inproc transport functions + */ +static void inproc_transports_create(grpc_exec_ctx *exec_ctx, + grpc_transport **server_transport, + const grpc_channel_args *server_args, + grpc_transport **client_transport, + const grpc_channel_args *client_args) { + INPROC_LOG(GPR_DEBUG, "inproc_transports_create"); + inproc_transport *st = gpr_zalloc(sizeof(*st)); + inproc_transport *ct = gpr_zalloc(sizeof(*ct)); + // Share one lock between both sides since both sides get affected + st->mu = ct->mu = gpr_malloc(sizeof(*st->mu)); + gpr_mu_init(&st->mu->mu); + gpr_ref_init(&st->mu->refs, 2); + st->base.vtable = &inproc_vtable; + ct->base.vtable = &inproc_vtable; + // Start each side of transport with 2 refs since they each have a ref + // to the other + gpr_ref_init(&st->refs, 2); + gpr_ref_init(&ct->refs, 2); + st->is_client = false; + ct->is_client = true; + grpc_connectivity_state_init(&st->connectivity, GRPC_CHANNEL_READY, + "inproc_server"); + grpc_connectivity_state_init(&ct->connectivity, GRPC_CHANNEL_READY, + "inproc_client"); + st->other_side = ct; + ct->other_side = st; + st->stream_list = NULL; + ct->stream_list = NULL; + *server_transport = (grpc_transport *)st; + *client_transport = (grpc_transport *)ct; +} + +grpc_channel *grpc_inproc_channel_create(grpc_server *server, + grpc_channel_args *args, + void *reserved) { + GRPC_API_TRACE("grpc_inproc_channel_create(server=%p, args=%p)", 2, + (server, args)); + + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + + const grpc_channel_args *server_args = grpc_server_get_channel_args(server); + + // Add a default authority channel argument for the client + + grpc_arg default_authority_arg; + default_authority_arg.type = GRPC_ARG_STRING; + default_authority_arg.key = GRPC_ARG_DEFAULT_AUTHORITY; + default_authority_arg.value.string = "inproc.authority"; + grpc_channel_args *client_args = + grpc_channel_args_copy_and_add(args, &default_authority_arg, 1); + + grpc_transport *server_transport; + grpc_transport *client_transport; + inproc_transports_create(&exec_ctx, &server_transport, server_args, + &client_transport, client_args); + + grpc_server_setup_transport(&exec_ctx, server, server_transport, NULL, + server_args); + grpc_channel *channel = + grpc_channel_create(&exec_ctx, "inproc", client_args, + GRPC_CLIENT_DIRECT_CHANNEL, client_transport); + + // Free up created channel args + grpc_channel_args_destroy(&exec_ctx, client_args); + + // Now finish scheduled operations + grpc_exec_ctx_finish(&exec_ctx); + + return channel; +} + +/******************************************************************************* + * INTEGRATION GLUE + */ + +static void set_pollset(grpc_exec_ctx *exec_ctx, grpc_transport *gt, + grpc_stream *gs, grpc_pollset *pollset) { + // Nothing to do here +} + +static void set_pollset_set(grpc_exec_ctx *exec_ctx, grpc_transport *gt, + grpc_stream *gs, grpc_pollset_set *pollset_set) { + // Nothing to do here +} + +static char *get_peer(grpc_exec_ctx *exec_ctx, grpc_transport *t) { + return gpr_strdup("inproc"); +} + +static grpc_endpoint *get_endpoint(grpc_exec_ctx *exec_ctx, grpc_transport *t) { + return NULL; +} + +static const grpc_transport_vtable inproc_vtable = { + sizeof(inproc_stream), "inproc", + init_stream, set_pollset, + set_pollset_set, perform_stream_op, + perform_transport_op, destroy_stream, + destroy_transport, get_peer, + get_endpoint}; + +/******************************************************************************* + * GLOBAL INIT AND DESTROY + */ +static void do_nothing(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {} + +void grpc_inproc_transport_init(void) { + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + GRPC_CLOSURE_INIT(&do_nothing_closure, do_nothing, NULL, + grpc_schedule_on_exec_ctx); + g_empty_slice = grpc_slice_from_static_buffer(NULL, 0); + + grpc_slice key_tmp = grpc_slice_from_static_string(":path"); + g_fake_path_key = grpc_slice_intern(key_tmp); + grpc_slice_unref_internal(&exec_ctx, key_tmp); + + g_fake_path_value = grpc_slice_from_static_string("/"); + + grpc_slice auth_tmp = grpc_slice_from_static_string(":authority"); + g_fake_auth_key = grpc_slice_intern(auth_tmp); + grpc_slice_unref_internal(&exec_ctx, auth_tmp); + + g_fake_auth_value = grpc_slice_from_static_string("inproc-fail"); + grpc_exec_ctx_finish(&exec_ctx); +} + +void grpc_inproc_transport_shutdown(void) { + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + grpc_slice_unref_internal(&exec_ctx, g_empty_slice); + grpc_slice_unref_internal(&exec_ctx, g_fake_path_key); + grpc_slice_unref_internal(&exec_ctx, g_fake_path_value); + grpc_slice_unref_internal(&exec_ctx, g_fake_auth_key); + grpc_slice_unref_internal(&exec_ctx, g_fake_auth_value); + grpc_exec_ctx_finish(&exec_ctx); +} diff --git a/Sources/CgRPC/src/core/ext/transport/inproc/inproc_transport.h b/Sources/CgRPC/src/core/ext/transport/inproc/inproc_transport.h new file mode 100644 index 000000000..37e6d99e9 --- /dev/null +++ b/Sources/CgRPC/src/core/ext/transport/inproc/inproc_transport.h @@ -0,0 +1,41 @@ +/* + * + * Copyright 2017 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 GRPC_CORE_EXT_TRANSPORT_INPROC_INPROC_TRANSPORT_H +#define GRPC_CORE_EXT_TRANSPORT_INPROC_INPROC_TRANSPORT_H + +#include "src/core/lib/transport/transport_impl.h" + +#ifdef __cplusplus +extern "C" { +#endif + +grpc_channel *grpc_inproc_channel_create(grpc_server *server, + grpc_channel_args *args, + void *reserved); + +extern grpc_tracer_flag grpc_inproc_trace; + +void grpc_inproc_transport_init(void); +void grpc_inproc_transport_shutdown(void); + +#ifdef __cplusplus +} +#endif + +#endif /* GRPC_CORE_EXT_TRANSPORT_INPROC_INPROC_TRANSPORT_H */ diff --git a/Sources/CgRPC/src/core/lib/channel/channel_args.c b/Sources/CgRPC/src/core/lib/channel/channel_args.c index 401a2ad4f..8fdef0bc6 100644 --- a/Sources/CgRPC/src/core/lib/channel/channel_args.c +++ b/Sources/CgRPC/src/core/lib/channel/channel_args.c @@ -1,47 +1,35 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 "src/core/lib/channel/channel_args.h" -#include -#include "src/core/lib/support/string.h" +#include + +#include +#include #include +#include #include #include #include #include -#include +#include "src/core/lib/channel/channel_args.h" +#include "src/core/lib/support/string.h" static grpc_arg copy_arg(const grpc_arg *src) { grpc_arg dst; @@ -126,9 +114,23 @@ grpc_channel_args *grpc_channel_args_copy(const grpc_channel_args *src) { return grpc_channel_args_copy_and_add(src, NULL, 0); } -grpc_channel_args *grpc_channel_args_merge(const grpc_channel_args *a, +grpc_channel_args *grpc_channel_args_union(const grpc_channel_args *a, const grpc_channel_args *b) { - return grpc_channel_args_copy_and_add(a, b->args, b->num_args); + const size_t max_out = (a->num_args + b->num_args); + grpc_arg *uniques = gpr_malloc(sizeof(*uniques) * max_out); + for (size_t i = 0; i < a->num_args; ++i) uniques[i] = a->args[i]; + + size_t uniques_idx = a->num_args; + for (size_t i = 0; i < b->num_args; ++i) { + const char *b_key = b->args[i].key; + if (grpc_channel_args_find(a, b_key) == NULL) { // not found + uniques[uniques_idx++] = b->args[i]; + } + } + grpc_channel_args *result = + grpc_channel_args_copy_and_add(NULL, uniques, uniques_idx); + gpr_free(uniques); + return result; } static int cmp_arg(const grpc_arg *a, const grpc_arg *b) { @@ -184,7 +186,7 @@ grpc_channel_args *grpc_channel_args_normalize(const grpc_channel_args *a) { return b; } -void grpc_channel_args_destroy(grpc_channel_args *a) { +void grpc_channel_args_destroy(grpc_exec_ctx *exec_ctx, grpc_channel_args *a) { size_t i; if (!a) return; for (i = 0; i < a->num_args; i++) { @@ -195,7 +197,8 @@ void grpc_channel_args_destroy(grpc_channel_args *a) { case GRPC_ARG_INTEGER: break; case GRPC_ARG_POINTER: - a->args[i].value.pointer.vtable->destroy(a->args[i].value.pointer.p); + a->args[i].value.pointer.vtable->destroy(exec_ctx, + a->args[i].value.pointer.p); break; } gpr_free(a->args[i].key); @@ -249,7 +252,8 @@ static int find_compression_algorithm_states_bitset(const grpc_channel_args *a, } grpc_channel_args *grpc_channel_args_compression_algorithm_set_state( - grpc_channel_args **a, grpc_compression_algorithm algorithm, int state) { + grpc_exec_ctx *exec_ctx, grpc_channel_args **a, + grpc_compression_algorithm algorithm, int state) { int *states_arg = NULL; grpc_channel_args *result = *a; const int states_arg_found = @@ -282,7 +286,7 @@ grpc_channel_args *grpc_channel_args_compression_algorithm_set_state( GPR_BITCLEAR((unsigned *)&tmp.value.integer, algorithm); } result = grpc_channel_args_copy_and_add(*a, &tmp, 1); - grpc_channel_args_destroy(*a); + grpc_channel_args_destroy(exec_ctx, *a); *a = result; } return result; @@ -327,7 +331,9 @@ const grpc_arg *grpc_channel_args_find(const grpc_channel_args *args, return NULL; } -int grpc_channel_arg_get_integer(grpc_arg *arg, grpc_integer_options options) { +int grpc_channel_arg_get_integer(const grpc_arg *arg, + const grpc_integer_options options) { + if (arg == NULL) return options.default_value; if (arg->type != GRPC_ARG_INTEGER) { gpr_log(GPR_ERROR, "%s ignored: it must be an integer", arg->key); return options.default_value; @@ -344,3 +350,52 @@ int grpc_channel_arg_get_integer(grpc_arg *arg, grpc_integer_options options) { } return arg->value.integer; } + +bool grpc_channel_arg_get_bool(const grpc_arg *arg, bool default_value) { + if (arg == NULL) return default_value; + if (arg->type != GRPC_ARG_INTEGER) { + gpr_log(GPR_ERROR, "%s ignored: it must be an integer", arg->key); + return default_value; + } + switch (arg->value.integer) { + case 0: + return false; + case 1: + return true; + default: + gpr_log(GPR_ERROR, "%s treated as bool but set to %d (assuming true)", + arg->key, arg->value.integer); + return true; + } +} + +bool grpc_channel_args_want_minimal_stack(const grpc_channel_args *args) { + return grpc_channel_arg_get_bool( + grpc_channel_args_find(args, GRPC_ARG_MINIMAL_STACK), false); +} + +grpc_arg grpc_channel_arg_string_create(char *name, char *value) { + grpc_arg arg; + arg.type = GRPC_ARG_STRING; + arg.key = name; + arg.value.string = value; + return arg; +} + +grpc_arg grpc_channel_arg_integer_create(char *name, int value) { + grpc_arg arg; + arg.type = GRPC_ARG_INTEGER; + arg.key = name; + arg.value.integer = value; + return arg; +} + +grpc_arg grpc_channel_arg_pointer_create( + char *name, void *value, const grpc_arg_pointer_vtable *vtable) { + grpc_arg arg; + arg.type = GRPC_ARG_POINTER; + arg.key = name; + arg.value.pointer.p = value; + arg.value.pointer.vtable = vtable; + return arg; +} diff --git a/Sources/CgRPC/src/core/lib/channel/channel_args.h b/Sources/CgRPC/src/core/lib/channel/channel_args.h index 88fc0e37a..f649a8d9e 100644 --- a/Sources/CgRPC/src/core/lib/channel/channel_args.h +++ b/Sources/CgRPC/src/core/lib/channel/channel_args.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -63,12 +48,12 @@ grpc_channel_args *grpc_channel_args_copy_and_add_and_remove( const grpc_channel_args *src, const char **to_remove, size_t num_to_remove, const grpc_arg *to_add, size_t num_to_add); -/** Concatenate args from \a a and \a b into a new instance */ -grpc_channel_args *grpc_channel_args_merge(const grpc_channel_args *a, +/** Perform the union of \a a and \a b, prioritizing \a a entries */ +grpc_channel_args *grpc_channel_args_union(const grpc_channel_args *a, const grpc_channel_args *b); /** Destroy arguments created by \a grpc_channel_args_copy */ -void grpc_channel_args_destroy(grpc_channel_args *a); +void grpc_channel_args_destroy(grpc_exec_ctx *exec_ctx, grpc_channel_args *a); /** Returns the compression algorithm set in \a a. */ grpc_compression_algorithm grpc_channel_args_get_compression_algorithm( @@ -88,7 +73,8 @@ grpc_channel_args *grpc_channel_args_set_compression_algorithm( * modified to point to the returned instance (which may be different from the * input value of \a a). */ grpc_channel_args *grpc_channel_args_compression_algorithm_set_state( - grpc_channel_args **a, grpc_compression_algorithm algorithm, int enabled); + grpc_exec_ctx *exec_ctx, grpc_channel_args **a, + grpc_compression_algorithm algorithm, int enabled); /** Returns the bitset representing the support state (true for enabled, false * for disabled) for compression algorithms. @@ -112,12 +98,24 @@ grpc_channel_args *grpc_channel_args_set_socket_mutator( const grpc_arg *grpc_channel_args_find(const grpc_channel_args *args, const char *name); +bool grpc_channel_args_want_minimal_stack(const grpc_channel_args *args); + typedef struct grpc_integer_options { int default_value; // Return this if value is outside of expected bounds. int min_value; int max_value; } grpc_integer_options; + /** Returns the value of \a arg, subject to the contraints in \a options. */ -int grpc_channel_arg_get_integer(grpc_arg *arg, grpc_integer_options options); +int grpc_channel_arg_get_integer(const grpc_arg *arg, + const grpc_integer_options options); + +bool grpc_channel_arg_get_bool(const grpc_arg *arg, bool default_value); + +// Helpers for creating channel args. +grpc_arg grpc_channel_arg_string_create(char *name, char *value); +grpc_arg grpc_channel_arg_integer_create(char *name, int value); +grpc_arg grpc_channel_arg_pointer_create(char *name, void *value, + const grpc_arg_pointer_vtable *vtable); #endif /* GRPC_CORE_LIB_CHANNEL_CHANNEL_ARGS_H */ diff --git a/Sources/CgRPC/src/core/lib/channel/channel_stack.c b/Sources/CgRPC/src/core/lib/channel/channel_stack.c index 1d0b7d4f3..0f8e33c4b 100644 --- a/Sources/CgRPC/src/core/lib/channel/channel_stack.c +++ b/Sources/CgRPC/src/core/lib/channel/channel_stack.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -38,7 +23,7 @@ #include #include -int grpc_trace_channel = 0; +grpc_tracer_flag grpc_trace_channel = GRPC_TRACER_INITIALIZER(false, "channel"); /* Memory layouts. @@ -166,40 +151,32 @@ void grpc_channel_stack_destroy(grpc_exec_ctx *exec_ctx, } } -grpc_error *grpc_call_stack_init( - grpc_exec_ctx *exec_ctx, grpc_channel_stack *channel_stack, - int initial_refs, grpc_iomgr_cb_func destroy, void *destroy_arg, - grpc_call_context_element *context, const void *transport_server_data, - grpc_mdstr *path, gpr_timespec start_time, gpr_timespec deadline, - grpc_call_stack *call_stack) { +grpc_error *grpc_call_stack_init(grpc_exec_ctx *exec_ctx, + grpc_channel_stack *channel_stack, + int initial_refs, grpc_iomgr_cb_func destroy, + void *destroy_arg, + const grpc_call_element_args *elem_args) { grpc_channel_element *channel_elems = CHANNEL_ELEMS_FROM_STACK(channel_stack); - grpc_call_element_args args; size_t count = channel_stack->count; grpc_call_element *call_elems; char *user_data; size_t i; - call_stack->count = count; - GRPC_STREAM_REF_INIT(&call_stack->refcount, initial_refs, destroy, + elem_args->call_stack->count = count; + GRPC_STREAM_REF_INIT(&elem_args->call_stack->refcount, initial_refs, destroy, destroy_arg, "CALL_STACK"); - call_elems = CALL_ELEMS_FROM_STACK(call_stack); + call_elems = CALL_ELEMS_FROM_STACK(elem_args->call_stack); user_data = ((char *)call_elems) + ROUND_UP_TO_ALIGNMENT_SIZE(count * sizeof(grpc_call_element)); /* init per-filter data */ grpc_error *first_error = GRPC_ERROR_NONE; - args.start_time = start_time; for (i = 0; i < count; i++) { - args.call_stack = call_stack; - args.server_transport_data = transport_server_data; - args.context = context; - args.path = path; - args.deadline = deadline; call_elems[i].filter = channel_elems[i].filter; call_elems[i].channel_data = channel_elems[i].channel_data; call_elems[i].call_data = user_data; - grpc_error *error = - call_elems[i].filter->init_call_elem(exec_ctx, &call_elems[i], &args); + grpc_error *error = call_elems[i].filter->init_call_elem( + exec_ctx, &call_elems[i], elem_args); if (error != GRPC_ERROR_NONE) { if (first_error == GRPC_ERROR_NONE) { first_error = error; @@ -240,22 +217,23 @@ void grpc_call_stack_ignore_set_pollset_or_pollset_set( void grpc_call_stack_destroy(grpc_exec_ctx *exec_ctx, grpc_call_stack *stack, const grpc_call_final_info *final_info, - void *and_free_memory) { + grpc_closure *then_schedule_closure) { grpc_call_element *elems = CALL_ELEMS_FROM_STACK(stack); size_t count = stack->count; size_t i; /* destroy per-filter data */ for (i = 0; i < count; i++) { - elems[i].filter->destroy_call_elem(exec_ctx, &elems[i], final_info, - i == count - 1 ? and_free_memory : NULL); + elems[i].filter->destroy_call_elem( + exec_ctx, &elems[i], final_info, + i == count - 1 ? then_schedule_closure : NULL); } } void grpc_call_next_op(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, - grpc_transport_stream_op *op) { + grpc_transport_stream_op_batch *op) { grpc_call_element *next_elem = elem + 1; - next_elem->filter->start_transport_stream_op(exec_ctx, next_elem, op); + next_elem->filter->start_transport_stream_op_batch(exec_ctx, next_elem, op); } char *grpc_call_next_get_peer(grpc_exec_ctx *exec_ctx, @@ -288,38 +266,11 @@ grpc_call_stack *grpc_call_stack_from_top_element(grpc_call_element *elem) { sizeof(grpc_call_stack))); } -static void destroy_op(grpc_exec_ctx *exec_ctx, void *op, grpc_error *error) { - gpr_free(op); -} - -void grpc_call_element_send_cancel(grpc_exec_ctx *exec_ctx, - grpc_call_element *elem) { - grpc_transport_stream_op *op = gpr_malloc(sizeof(*op)); - memset(op, 0, sizeof(*op)); - op->cancel_error = GRPC_ERROR_CANCELLED; - op->on_complete = grpc_closure_create(destroy_op, op); - elem->filter->start_transport_stream_op(exec_ctx, elem, op); -} - -void grpc_call_element_send_cancel_with_message(grpc_exec_ctx *exec_ctx, - grpc_call_element *elem, - grpc_status_code status, - grpc_slice *optional_message) { - grpc_transport_stream_op *op = gpr_malloc(sizeof(*op)); - memset(op, 0, sizeof(*op)); - op->on_complete = grpc_closure_create(destroy_op, op); - grpc_transport_stream_op_add_cancellation_with_message(op, status, - optional_message); - elem->filter->start_transport_stream_op(exec_ctx, elem, op); -} - -void grpc_call_element_send_close_with_message(grpc_exec_ctx *exec_ctx, - grpc_call_element *elem, - grpc_status_code status, - grpc_slice *optional_message) { - grpc_transport_stream_op *op = gpr_malloc(sizeof(*op)); - memset(op, 0, sizeof(*op)); - op->on_complete = grpc_closure_create(destroy_op, op); - grpc_transport_stream_op_add_close(op, status, optional_message); - elem->filter->start_transport_stream_op(exec_ctx, elem, op); +void grpc_call_element_signal_error(grpc_exec_ctx *exec_ctx, + grpc_call_element *elem, + grpc_error *error) { + grpc_transport_stream_op_batch *op = grpc_make_transport_stream_op(NULL); + op->cancel_stream = true; + op->payload->cancel_stream.cancel_error = error; + elem->filter->start_transport_stream_op_batch(exec_ctx, elem, op); } diff --git a/Sources/CgRPC/src/core/lib/channel/channel_stack.h b/Sources/CgRPC/src/core/lib/channel/channel_stack.h index d9d3a8523..a80f8aa82 100644 --- a/Sources/CgRPC/src/core/lib/channel/channel_stack.h +++ b/Sources/CgRPC/src/core/lib/channel/channel_stack.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -56,6 +41,7 @@ #include "src/core/lib/debug/trace.h" #include "src/core/lib/iomgr/polling_entity.h" +#include "src/core/lib/support/arena.h" #include "src/core/lib/transport/transport.h" #ifdef __cplusplus @@ -81,9 +67,10 @@ typedef struct { grpc_call_stack *call_stack; const void *server_transport_data; grpc_call_context_element *context; - grpc_mdstr *path; + grpc_slice path; gpr_timespec start_time; gpr_timespec deadline; + gpr_arena *arena; } grpc_call_element_args; typedef struct { @@ -110,9 +97,9 @@ typedef struct { typedef struct { /* Called to eg. send/receive data on a call. See grpc_call_next_op on how to call the next element in the stack */ - void (*start_transport_stream_op)(grpc_exec_ctx *exec_ctx, - grpc_call_element *elem, - grpc_transport_stream_op *op); + void (*start_transport_stream_op_batch)(grpc_exec_ctx *exec_ctx, + grpc_call_element *elem, + grpc_transport_stream_op_batch *op); /* Called to handle channel level operations - e.g. new calls, or transport closure. See grpc_channel_next_op on how to call the next element in the stack */ @@ -128,22 +115,23 @@ typedef struct { server_transport_data is an opaque pointer. If it is NULL, this call is on a client; if it is non-NULL, then it points to memory owned by the transport and is on the server. Most filters want to ignore this - argument. */ + argument. + Implementations may assume that elem->call_data is all zeros. */ grpc_error *(*init_call_elem)(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, - grpc_call_element_args *args); + const grpc_call_element_args *args); void (*set_pollset_or_pollset_set)(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, grpc_polling_entity *pollent); /* Destroy per call data. The filter does not need to do any chaining. The bottom filter of a stack will be passed a non-NULL pointer to - \a and_free_memory that should be passed to gpr_free when destruction - is complete. \a final_info contains data about the completed call, mainly - for reporting purposes. */ + \a then_schedule_closure that should be passed to GRPC_CLOSURE_SCHED when + destruction is complete. \a final_info contains data about the completed + call, mainly for reporting purposes. */ void (*destroy_call_elem)(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, const grpc_call_final_info *final_info, - void *and_free_memory); + grpc_closure *then_schedule_closure); /* sizeof(per channel data) */ size_t sizeof_channel_data; @@ -152,7 +140,8 @@ typedef struct { is what needs initializing. is_first, is_last designate this elements position in the stack, and are useful for asserting correct configuration by upper layer code. - The filter does not need to do any chaining */ + The filter does not need to do any chaining. + Implementations may assume that elem->call_data is all zeros. */ grpc_error *(*init_channel_elem)(grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, grpc_channel_element_args *args); @@ -234,19 +223,18 @@ void grpc_channel_stack_destroy(grpc_exec_ctx *exec_ctx, /* Initialize a call stack given a channel stack. transport_server_data is expected to be NULL on a client, or an opaque transport owned pointer on the server. */ -grpc_error *grpc_call_stack_init( - grpc_exec_ctx *exec_ctx, grpc_channel_stack *channel_stack, - int initial_refs, grpc_iomgr_cb_func destroy, void *destroy_arg, - grpc_call_context_element *context, const void *transport_server_data, - grpc_mdstr *path, gpr_timespec start_time, gpr_timespec deadline, - grpc_call_stack *call_stack); +grpc_error *grpc_call_stack_init(grpc_exec_ctx *exec_ctx, + grpc_channel_stack *channel_stack, + int initial_refs, grpc_iomgr_cb_func destroy, + void *destroy_arg, + const grpc_call_element_args *elem_args); /* Set a pollset or a pollset_set for a call stack: must occur before the first * op is started */ void grpc_call_stack_set_pollset_or_pollset_set(grpc_exec_ctx *exec_ctx, grpc_call_stack *call_stack, grpc_polling_entity *pollent); -#ifdef GRPC_STREAM_REFCOUNT_DEBUG +#ifndef NDEBUG #define GRPC_CALL_STACK_REF(call_stack, reason) \ grpc_stream_ref(&(call_stack)->refcount, reason) #define GRPC_CALL_STACK_UNREF(exec_ctx, call_stack, reason) \ @@ -269,7 +257,7 @@ void grpc_call_stack_set_pollset_or_pollset_set(grpc_exec_ctx *exec_ctx, /* Destroy a call stack */ void grpc_call_stack_destroy(grpc_exec_ctx *exec_ctx, grpc_call_stack *stack, const grpc_call_final_info *final_info, - void *and_free_memory); + grpc_closure *then_schedule_closure); /* Ignore set pollset{_set} - used by filters if they don't care about pollsets * at all. Does nothing. */ @@ -278,7 +266,7 @@ void grpc_call_stack_ignore_set_pollset_or_pollset_set( grpc_polling_entity *pollent); /* Call the next operation in a call stack */ void grpc_call_next_op(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, - grpc_transport_stream_op *op); + grpc_transport_stream_op_batch *op); /* Call the next operation (depending on call directionality) in a channel stack */ void grpc_channel_next_op(grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, @@ -297,25 +285,17 @@ grpc_channel_stack *grpc_channel_stack_from_top_element( grpc_call_stack *grpc_call_stack_from_top_element(grpc_call_element *elem); void grpc_call_log_op(char *file, int line, gpr_log_severity severity, - grpc_call_element *elem, grpc_transport_stream_op *op); - -void grpc_call_element_send_cancel(grpc_exec_ctx *exec_ctx, - grpc_call_element *cur_elem); - -void grpc_call_element_send_cancel_with_message(grpc_exec_ctx *exec_ctx, - grpc_call_element *cur_elem, - grpc_status_code status, - grpc_slice *optional_message); + grpc_call_element *elem, + grpc_transport_stream_op_batch *op); -void grpc_call_element_send_close_with_message(grpc_exec_ctx *exec_ctx, - grpc_call_element *cur_elem, - grpc_status_code status, - grpc_slice *optional_message); +void grpc_call_element_signal_error(grpc_exec_ctx *exec_ctx, + grpc_call_element *cur_elem, + grpc_error *error); -extern int grpc_trace_channel; +extern grpc_tracer_flag grpc_trace_channel; #define GRPC_CALL_LOG_OP(sev, elem, op) \ - if (grpc_trace_channel) grpc_call_log_op(sev, elem, op) + if (GRPC_TRACER_ON(grpc_trace_channel)) grpc_call_log_op(sev, elem, op) #ifdef __cplusplus } diff --git a/Sources/CgRPC/src/core/lib/channel/channel_stack_builder.c b/Sources/CgRPC/src/core/lib/channel/channel_stack_builder.c index b959517af..c369e3307 100644 --- a/Sources/CgRPC/src/core/lib/channel/channel_stack_builder.c +++ b/Sources/CgRPC/src/core/lib/channel/channel_stack_builder.c @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -38,7 +23,8 @@ #include #include -int grpc_trace_channel_stack_builder = 0; +grpc_tracer_flag grpc_trace_channel_stack_builder = + GRPC_TRACER_INITIALIZER(false, "channel_stack_builder"); typedef struct filter_node { struct filter_node *next; @@ -65,8 +51,7 @@ struct grpc_channel_stack_builder_iterator { }; grpc_channel_stack_builder *grpc_channel_stack_builder_create(void) { - grpc_channel_stack_builder *b = gpr_malloc(sizeof(*b)); - memset(b, 0, sizeof(*b)); + grpc_channel_stack_builder *b = gpr_zalloc(sizeof(*b)); b->begin.filter = NULL; b->end.filter = NULL; @@ -114,6 +99,17 @@ grpc_channel_stack_builder_create_iterator_at_last( return create_iterator_at_filter_node(builder, &builder->end); } +bool grpc_channel_stack_builder_iterator_is_end( + grpc_channel_stack_builder_iterator *iterator) { + return iterator->node == &iterator->builder->end; +} + +const char *grpc_channel_stack_builder_iterator_filter_name( + grpc_channel_stack_builder_iterator *iterator) { + if (iterator->node->filter == NULL) return NULL; + return iterator->node->filter->name; +} + bool grpc_channel_stack_builder_move_next( grpc_channel_stack_builder_iterator *iterator) { if (iterator->node == &iterator->builder->end) return false; @@ -138,9 +134,10 @@ void grpc_channel_stack_builder_set_name(grpc_channel_stack_builder *builder, } void grpc_channel_stack_builder_set_channel_arguments( - grpc_channel_stack_builder *builder, const grpc_channel_args *args) { + grpc_exec_ctx *exec_ctx, grpc_channel_stack_builder *builder, + const grpc_channel_args *args) { if (builder->args != NULL) { - grpc_channel_args_destroy(builder->args); + grpc_channel_args_destroy(exec_ctx, builder->args); } builder->args = grpc_channel_args_copy(args); } @@ -213,7 +210,8 @@ bool grpc_channel_stack_builder_add_filter_after( return true; } -void grpc_channel_stack_builder_destroy(grpc_channel_stack_builder *builder) { +void grpc_channel_stack_builder_destroy(grpc_exec_ctx *exec_ctx, + grpc_channel_stack_builder *builder) { filter_node *p = builder->begin.next; while (p != &builder->end) { filter_node *next = p->next; @@ -221,7 +219,7 @@ void grpc_channel_stack_builder_destroy(grpc_channel_stack_builder *builder) { p = next; } if (builder->args != NULL) { - grpc_channel_args_destroy(builder->args); + grpc_channel_args_destroy(exec_ctx, builder->args); } gpr_free(builder->target); gpr_free(builder); @@ -249,7 +247,7 @@ grpc_error *grpc_channel_stack_builder_finish( size_t channel_stack_size = grpc_channel_stack_size(filters, num_filters); // allocate memory, with prefix_bytes followed by channel_stack_size - *result = gpr_malloc(prefix_bytes + channel_stack_size); + *result = gpr_zalloc(prefix_bytes + channel_stack_size); // fetch a pointer to the channel stack grpc_channel_stack *channel_stack = (grpc_channel_stack *)((char *)(*result) + prefix_bytes); @@ -276,7 +274,7 @@ grpc_error *grpc_channel_stack_builder_finish( } } - grpc_channel_stack_builder_destroy(builder); + grpc_channel_stack_builder_destroy(exec_ctx, builder); gpr_free((grpc_channel_filter **)filters); return error; diff --git a/Sources/CgRPC/src/core/lib/channel/channel_stack_builder.h b/Sources/CgRPC/src/core/lib/channel/channel_stack_builder.h index 65bfebcab..d43e42796 100644 --- a/Sources/CgRPC/src/core/lib/channel/channel_stack_builder.h +++ b/Sources/CgRPC/src/core/lib/channel/channel_stack_builder.h @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -73,7 +58,8 @@ grpc_transport *grpc_channel_stack_builder_get_transport( /// Set channel arguments: copies args void grpc_channel_stack_builder_set_channel_arguments( - grpc_channel_stack_builder *builder, const grpc_channel_args *args); + grpc_exec_ctx *exec_ctx, grpc_channel_stack_builder *builder, + const grpc_channel_args *args); /// Return a borrowed pointer to the channel arguments const grpc_channel_args *grpc_channel_stack_builder_get_channel_arguments( @@ -97,6 +83,10 @@ bool grpc_channel_stack_builder_iterator_is_first( bool grpc_channel_stack_builder_iterator_is_end( grpc_channel_stack_builder_iterator *iterator); +/// What is the name of the filter at this iterator position? +const char *grpc_channel_stack_builder_iterator_filter_name( + grpc_channel_stack_builder_iterator *iterator); + /// Move an iterator to the next item bool grpc_channel_stack_builder_move_next( grpc_channel_stack_builder_iterator *iterator); @@ -157,9 +147,10 @@ grpc_error *grpc_channel_stack_builder_finish( void *destroy_arg, void **result); /// Destroy the builder without creating a channel stack -void grpc_channel_stack_builder_destroy(grpc_channel_stack_builder *builder); +void grpc_channel_stack_builder_destroy(grpc_exec_ctx *exec_ctx, + grpc_channel_stack_builder *builder); -extern int grpc_trace_channel_stack_builder; +extern grpc_tracer_flag grpc_trace_channel_stack_builder; #ifdef __cplusplus } diff --git a/Sources/CgRPC/src/core/lib/channel/compress_filter.c b/Sources/CgRPC/src/core/lib/channel/compress_filter.c deleted file mode 100644 index 0e336dc33..000000000 --- a/Sources/CgRPC/src/core/lib/channel/compress_filter.c +++ /dev/null @@ -1,337 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include -#include - -#include -#include -#include -#include - -#include "src/core/lib/channel/channel_args.h" -#include "src/core/lib/channel/compress_filter.h" -#include "src/core/lib/compression/algorithm_metadata.h" -#include "src/core/lib/compression/message_compress.h" -#include "src/core/lib/profiling/timers.h" -#include "src/core/lib/support/string.h" -#include "src/core/lib/transport/static_metadata.h" - -int grpc_compression_trace = 0; - -typedef struct call_data { - grpc_slice_buffer slices; /**< Buffers up input slices to be compressed */ - grpc_linked_mdelem compression_algorithm_storage; - grpc_linked_mdelem accept_encoding_storage; - uint32_t remaining_slice_bytes; - /** Compression algorithm we'll try to use. It may be given by incoming - * metadata, or by the channel's default compression settings. */ - grpc_compression_algorithm compression_algorithm; - /** If true, contents of \a compression_algorithm are authoritative */ - int has_compression_algorithm; - - grpc_transport_stream_op *send_op; - uint32_t send_length; - uint32_t send_flags; - grpc_slice incoming_slice; - grpc_slice_buffer_stream replacement_stream; - grpc_closure *post_send; - grpc_closure send_done; - grpc_closure got_slice; -} call_data; - -typedef struct channel_data { - /** The default, channel-level, compression algorithm */ - grpc_compression_algorithm default_compression_algorithm; - /** Bitset of enabled algorithms */ - uint32_t enabled_algorithms_bitset; - /** Supported compression algorithms */ - uint32_t supported_compression_algorithms; -} channel_data; - -/** For each \a md element from the incoming metadata, filter out the entry for - * "grpc-encoding", using its value to populate the call data's - * compression_algorithm field. */ -static grpc_mdelem *compression_md_filter(void *user_data, grpc_mdelem *md) { - grpc_call_element *elem = user_data; - call_data *calld = elem->call_data; - channel_data *channeld = elem->channel_data; - - if (md->key == GRPC_MDSTR_GRPC_INTERNAL_ENCODING_REQUEST) { - const char *md_c_str = grpc_mdstr_as_c_string(md->value); - if (!grpc_compression_algorithm_parse(md_c_str, strlen(md_c_str), - &calld->compression_algorithm)) { - gpr_log(GPR_ERROR, - "Invalid compression algorithm: '%s' (unknown). Ignoring.", - md_c_str); - calld->compression_algorithm = GRPC_COMPRESS_NONE; - } - if (!GPR_BITGET(channeld->enabled_algorithms_bitset, - calld->compression_algorithm)) { - gpr_log(GPR_ERROR, - "Invalid compression algorithm: '%s' (previously disabled). " - "Ignoring.", - md_c_str); - calld->compression_algorithm = GRPC_COMPRESS_NONE; - } - calld->has_compression_algorithm = 1; - return NULL; - } - - return md; -} - -static int skip_compression(grpc_call_element *elem, uint32_t flags) { - call_data *calld = elem->call_data; - channel_data *channeld = elem->channel_data; - - if (flags & (GRPC_WRITE_NO_COMPRESS | GRPC_WRITE_INTERNAL_COMPRESS)) { - return 1; - } - if (calld->has_compression_algorithm) { - if (calld->compression_algorithm == GRPC_COMPRESS_NONE) { - return 1; - } - return 0; /* we have an actual call-specific algorithm */ - } - /* no per-call compression override */ - return channeld->default_compression_algorithm == GRPC_COMPRESS_NONE; -} - -/** Filter initial metadata */ -static void process_send_initial_metadata( - grpc_call_element *elem, grpc_metadata_batch *initial_metadata) { - call_data *calld = elem->call_data; - channel_data *channeld = elem->channel_data; - /* Parse incoming request for compression. If any, it'll be available - * at calld->compression_algorithm */ - grpc_metadata_batch_filter(initial_metadata, compression_md_filter, elem); - if (!calld->has_compression_algorithm) { - /* If no algorithm was found in the metadata and we aren't - * exceptionally skipping compression, fall back to the channel - * default */ - calld->compression_algorithm = channeld->default_compression_algorithm; - calld->has_compression_algorithm = 1; /* GPR_TRUE */ - } - /* hint compression algorithm */ - grpc_metadata_batch_add_tail( - initial_metadata, &calld->compression_algorithm_storage, - grpc_compression_encoding_mdelem(calld->compression_algorithm)); - - /* convey supported compression algorithms */ - grpc_metadata_batch_add_tail(initial_metadata, - &calld->accept_encoding_storage, - GRPC_MDELEM_ACCEPT_ENCODING_FOR_ALGORITHMS( - channeld->supported_compression_algorithms)); -} - -static void continue_send_message(grpc_exec_ctx *exec_ctx, - grpc_call_element *elem); - -static void send_done(grpc_exec_ctx *exec_ctx, void *elemp, grpc_error *error) { - grpc_call_element *elem = elemp; - call_data *calld = elem->call_data; - grpc_slice_buffer_reset_and_unref(&calld->slices); - calld->post_send->cb(exec_ctx, calld->post_send->cb_arg, error); -} - -static void finish_send_message(grpc_exec_ctx *exec_ctx, - grpc_call_element *elem) { - call_data *calld = elem->call_data; - int did_compress; - grpc_slice_buffer tmp; - grpc_slice_buffer_init(&tmp); - did_compress = - grpc_msg_compress(calld->compression_algorithm, &calld->slices, &tmp); - if (did_compress) { - if (grpc_compression_trace) { - char *algo_name; - const size_t before_size = calld->slices.length; - const size_t after_size = tmp.length; - const float savings_ratio = 1.0f - (float)after_size / (float)before_size; - GPR_ASSERT(grpc_compression_algorithm_name(calld->compression_algorithm, - &algo_name)); - gpr_log(GPR_DEBUG, "Compressed[%s] %" PRIuPTR " bytes vs. %" PRIuPTR - " bytes (%.2f%% savings)", - algo_name, before_size, after_size, 100 * savings_ratio); - } - grpc_slice_buffer_swap(&calld->slices, &tmp); - calld->send_flags |= GRPC_WRITE_INTERNAL_COMPRESS; - } else { - if (grpc_compression_trace) { - char *algo_name; - GPR_ASSERT(grpc_compression_algorithm_name(calld->compression_algorithm, - &algo_name)); - gpr_log(GPR_DEBUG, - "Algorithm '%s' enabled but decided not to compress. Input size: " - "%" PRIuPTR, - algo_name, calld->slices.length); - } - } - - grpc_slice_buffer_destroy(&tmp); - - grpc_slice_buffer_stream_init(&calld->replacement_stream, &calld->slices, - calld->send_flags); - calld->send_op->send_message = &calld->replacement_stream.base; - calld->post_send = calld->send_op->on_complete; - calld->send_op->on_complete = &calld->send_done; - - grpc_call_next_op(exec_ctx, elem, calld->send_op); -} - -static void got_slice(grpc_exec_ctx *exec_ctx, void *elemp, grpc_error *error) { - grpc_call_element *elem = elemp; - call_data *calld = elem->call_data; - grpc_slice_buffer_add(&calld->slices, calld->incoming_slice); - if (calld->send_length == calld->slices.length) { - finish_send_message(exec_ctx, elem); - } else { - continue_send_message(exec_ctx, elem); - } -} - -static void continue_send_message(grpc_exec_ctx *exec_ctx, - grpc_call_element *elem) { - call_data *calld = elem->call_data; - while (grpc_byte_stream_next(exec_ctx, calld->send_op->send_message, - &calld->incoming_slice, ~(size_t)0, - &calld->got_slice)) { - grpc_slice_buffer_add(&calld->slices, calld->incoming_slice); - if (calld->send_length == calld->slices.length) { - finish_send_message(exec_ctx, elem); - break; - } - } -} - -static void compress_start_transport_stream_op(grpc_exec_ctx *exec_ctx, - grpc_call_element *elem, - grpc_transport_stream_op *op) { - call_data *calld = elem->call_data; - - GPR_TIMER_BEGIN("compress_start_transport_stream_op", 0); - - if (op->send_initial_metadata) { - process_send_initial_metadata(elem, op->send_initial_metadata); - } - if (op->send_message != NULL && - !skip_compression(elem, op->send_message->flags)) { - calld->send_op = op; - calld->send_length = op->send_message->length; - calld->send_flags = op->send_message->flags; - continue_send_message(exec_ctx, elem); - } else { - /* pass control down the stack */ - grpc_call_next_op(exec_ctx, elem, op); - } - - GPR_TIMER_END("compress_start_transport_stream_op", 0); -} - -/* Constructor for call_data */ -static grpc_error *init_call_elem(grpc_exec_ctx *exec_ctx, - grpc_call_element *elem, - grpc_call_element_args *args) { - /* grab pointers to our data from the call element */ - call_data *calld = elem->call_data; - - /* initialize members */ - grpc_slice_buffer_init(&calld->slices); - calld->has_compression_algorithm = 0; - grpc_closure_init(&calld->got_slice, got_slice, elem); - grpc_closure_init(&calld->send_done, send_done, elem); - - return GRPC_ERROR_NONE; -} - -/* Destructor for call_data */ -static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, - const grpc_call_final_info *final_info, - void *ignored) { - /* grab pointers to our data from the call element */ - call_data *calld = elem->call_data; - grpc_slice_buffer_destroy(&calld->slices); -} - -/* Constructor for channel_data */ -static grpc_error *init_channel_elem(grpc_exec_ctx *exec_ctx, - grpc_channel_element *elem, - grpc_channel_element_args *args) { - channel_data *channeld = elem->channel_data; - - channeld->enabled_algorithms_bitset = - grpc_channel_args_compression_algorithm_get_states(args->channel_args); - - channeld->default_compression_algorithm = - grpc_channel_args_get_compression_algorithm(args->channel_args); - /* Make sure the default isn't disabled. */ - if (!GPR_BITGET(channeld->enabled_algorithms_bitset, - channeld->default_compression_algorithm)) { - gpr_log(GPR_DEBUG, - "compression algorithm %d not enabled: switching to none", - channeld->default_compression_algorithm); - channeld->default_compression_algorithm = GRPC_COMPRESS_NONE; - } - - channeld->supported_compression_algorithms = 1; /* always support identity */ - for (grpc_compression_algorithm algo_idx = 1; - algo_idx < GRPC_COMPRESS_ALGORITHMS_COUNT; ++algo_idx) { - /* skip disabled algorithms */ - if (!GPR_BITGET(channeld->enabled_algorithms_bitset, algo_idx)) { - continue; - } - channeld->supported_compression_algorithms |= 1u << algo_idx; - } - - GPR_ASSERT(!args->is_last); - return GRPC_ERROR_NONE; -} - -/* Destructor for channel data */ -static void destroy_channel_elem(grpc_exec_ctx *exec_ctx, - grpc_channel_element *elem) {} - -const grpc_channel_filter grpc_compress_filter = { - compress_start_transport_stream_op, - grpc_channel_next_op, - sizeof(call_data), - init_call_elem, - grpc_call_stack_ignore_set_pollset_or_pollset_set, - destroy_call_elem, - sizeof(channel_data), - init_channel_elem, - destroy_channel_elem, - grpc_call_next_get_peer, - grpc_channel_next_get_info, - "compress"}; diff --git a/Sources/CgRPC/src/core/lib/channel/compress_filter.h b/Sources/CgRPC/src/core/lib/channel/compress_filter.h deleted file mode 100644 index e4a2a829d..000000000 --- a/Sources/CgRPC/src/core/lib/channel/compress_filter.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#ifndef GRPC_CORE_LIB_CHANNEL_COMPRESS_FILTER_H -#define GRPC_CORE_LIB_CHANNEL_COMPRESS_FILTER_H - -#include - -#include "src/core/lib/channel/channel_stack.h" - -extern int grpc_compression_trace; - -/** Compression filter for outgoing data. - * - * See for the available compression settings. - * - * Compression settings may come from: - * - Channel configuration, as established at channel creation time. - * - The metadata accompanying the outgoing data to be compressed. This is - * taken as a request only. We may choose not to honor it. The metadata key - * is given by \a GRPC_COMPRESSION_REQUEST_ALGORITHM_MD_KEY. - * - * Compression can be disabled for concrete messages (for instance in order to - * prevent CRIME/BEAST type attacks) by having the GRPC_WRITE_NO_COMPRESS set in - * the BEGIN_MESSAGE flags. - * - * The attempted compression mechanism is added to the resulting initial - * metadata under the'grpc-encoding' key. - * - * If compression is actually performed, BEGIN_MESSAGE's flag is modified to - * incorporate GRPC_WRITE_INTERNAL_COMPRESS. Otherwise, and regardless of the - * aforementioned 'grpc-encoding' metadata value, data will pass through - * uncompressed. */ - -extern const grpc_channel_filter grpc_compress_filter; - -#endif /* GRPC_CORE_LIB_CHANNEL_COMPRESS_FILTER_H */ diff --git a/Sources/CgRPC/src/core/lib/channel/connected_channel.c b/Sources/CgRPC/src/core/lib/channel/connected_channel.c index c2a36b555..af06ca802 100644 --- a/Sources/CgRPC/src/core/lib/channel/connected_channel.c +++ b/Sources/CgRPC/src/core/lib/channel/connected_channel.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -62,9 +47,9 @@ typedef struct connected_channel_call_data { void *unused; } call_data; /* Intercept a call operation and either push it directly up or translate it into transport stream operations */ -static void con_start_transport_stream_op(grpc_exec_ctx *exec_ctx, - grpc_call_element *elem, - grpc_transport_stream_op *op) { +static void con_start_transport_stream_op_batch( + grpc_exec_ctx *exec_ctx, grpc_call_element *elem, + grpc_transport_stream_op_batch *op) { call_data *calld = elem->call_data; channel_data *chand = elem->channel_data; GRPC_CALL_LOG_OP(GPR_INFO, elem, op); @@ -83,14 +68,15 @@ static void con_start_transport_op(grpc_exec_ctx *exec_ctx, /* Constructor for call_data */ static grpc_error *init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, - grpc_call_element_args *args) { + const grpc_call_element_args *args) { call_data *calld = elem->call_data; channel_data *chand = elem->channel_data; int r = grpc_transport_init_stream( exec_ctx, chand->transport, TRANSPORT_STREAM_FROM_CALL_DATA(calld), - &args->call_stack->refcount, args->server_transport_data); + &args->call_stack->refcount, args->server_transport_data, args->arena); return r == 0 ? GRPC_ERROR_NONE - : GRPC_ERROR_CREATE("transport stream initialization failed"); + : GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "transport stream initialization failed"); } static void set_pollset_or_pollset_set(grpc_exec_ctx *exec_ctx, @@ -105,12 +91,12 @@ static void set_pollset_or_pollset_set(grpc_exec_ctx *exec_ctx, /* Destructor for call_data */ static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, const grpc_call_final_info *final_info, - void *and_free_memory) { + grpc_closure *then_schedule_closure) { call_data *calld = elem->call_data; channel_data *chand = elem->channel_data; grpc_transport_destroy_stream(exec_ctx, chand->transport, TRANSPORT_STREAM_FROM_CALL_DATA(calld), - and_free_memory); + then_schedule_closure); } /* Constructor for channel_data */ @@ -127,7 +113,9 @@ static grpc_error *init_channel_elem(grpc_exec_ctx *exec_ctx, static void destroy_channel_elem(grpc_exec_ctx *exec_ctx, grpc_channel_element *elem) { channel_data *cd = (channel_data *)elem->channel_data; - grpc_transport_destroy(exec_ctx, cd->transport); + if (cd->transport) { + grpc_transport_destroy(exec_ctx, cd->transport); + } } static char *con_get_peer(grpc_exec_ctx *exec_ctx, grpc_call_element *elem) { @@ -140,8 +128,8 @@ static void con_get_channel_info(grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, const grpc_channel_info *channel_info) {} -static const grpc_channel_filter connected_channel_filter = { - con_start_transport_stream_op, +const grpc_channel_filter grpc_connected_filter = { + con_start_transport_stream_op_batch, con_start_transport_op, sizeof(call_data), init_call_elem, @@ -158,7 +146,7 @@ static const grpc_channel_filter connected_channel_filter = { static void bind_transport(grpc_channel_stack *channel_stack, grpc_channel_element *elem, void *t) { channel_data *cd = (channel_data *)elem->channel_data; - GPR_ASSERT(elem->filter == &connected_channel_filter); + GPR_ASSERT(elem->filter == &grpc_connected_filter); GPR_ASSERT(cd->transport == NULL); cd->transport = t; @@ -171,13 +159,14 @@ static void bind_transport(grpc_channel_stack *channel_stack, channel_stack->call_stack_size += grpc_transport_stream_size(t); } -bool grpc_add_connected_filter(grpc_channel_stack_builder *builder, +bool grpc_add_connected_filter(grpc_exec_ctx *exec_ctx, + grpc_channel_stack_builder *builder, void *arg_must_be_null) { GPR_ASSERT(arg_must_be_null == NULL); grpc_transport *t = grpc_channel_stack_builder_get_transport(builder); GPR_ASSERT(t != NULL); return grpc_channel_stack_builder_append_filter( - builder, &connected_channel_filter, bind_transport, t); + builder, &grpc_connected_filter, bind_transport, t); } grpc_stream *grpc_connected_channel_get_stream(grpc_call_element *elem) { diff --git a/Sources/CgRPC/src/core/lib/channel/connected_channel.h b/Sources/CgRPC/src/core/lib/channel/connected_channel.h index 3142d647b..10c98cce5 100644 --- a/Sources/CgRPC/src/core/lib/channel/connected_channel.h +++ b/Sources/CgRPC/src/core/lib/channel/connected_channel.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -36,7 +21,13 @@ #include "src/core/lib/channel/channel_stack_builder.h" -bool grpc_add_connected_filter(grpc_channel_stack_builder *builder, +extern const grpc_channel_filter grpc_connected_filter; + +bool grpc_add_connected_filter(grpc_exec_ctx *exec_ctx, + grpc_channel_stack_builder *builder, void *arg_must_be_null); +/* Debug helper to dig the transport stream out of a call element */ +grpc_stream *grpc_connected_channel_get_stream(grpc_call_element *elem); + #endif /* GRPC_CORE_LIB_CHANNEL_CONNECTED_CHANNEL_H */ diff --git a/Sources/CgRPC/src/core/lib/channel/context.h b/Sources/CgRPC/src/core/lib/channel/context.h index 6c931ad28..191bd6335 100644 --- a/Sources/CgRPC/src/core/lib/channel/context.h +++ b/Sources/CgRPC/src/core/lib/channel/context.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -50,6 +35,9 @@ typedef enum { /// Reserved for traffic_class_context. GRPC_CONTEXT_TRAFFIC, + /// Value is a \a grpc_grpclb_client_stats. + GRPC_GRPCLB_CLIENT_STATS, + GRPC_CONTEXT_COUNT } grpc_context_index; diff --git a/Sources/CgRPC/src/core/lib/channel/deadline_filter.h b/Sources/CgRPC/src/core/lib/channel/deadline_filter.h deleted file mode 100644 index 716a85256..000000000 --- a/Sources/CgRPC/src/core/lib/channel/deadline_filter.h +++ /dev/null @@ -1,98 +0,0 @@ -// -// Copyright 2016, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// - -#ifndef GRPC_CORE_LIB_CHANNEL_DEADLINE_FILTER_H -#define GRPC_CORE_LIB_CHANNEL_DEADLINE_FILTER_H - -#include "src/core/lib/channel/channel_stack.h" -#include "src/core/lib/iomgr/timer.h" - -// State used for filters that enforce call deadlines. -// Must be the first field in the filter's call_data. -typedef struct grpc_deadline_state { - // We take a reference to the call stack for the timer callback. - grpc_call_stack* call_stack; - // Guards access to timer_pending and timer. - gpr_mu timer_mu; - // True if the timer callback is currently pending. - bool timer_pending; - // The deadline timer. - grpc_timer timer; - // Closure to invoke when the call is complete. - // We use this to cancel the timer. - grpc_closure on_complete; - // The original on_complete closure, which we chain to after our own - // closure is invoked. - grpc_closure* next_on_complete; -} grpc_deadline_state; - -// -// NOTE: All of these functions require that the first field in -// elem->call_data is a grpc_deadline_state. -// - -void grpc_deadline_state_init(grpc_exec_ctx* exec_ctx, grpc_call_element* elem, - grpc_call_stack* call_stack); -void grpc_deadline_state_destroy(grpc_exec_ctx* exec_ctx, - grpc_call_element* elem); - -// Starts the timer with the specified deadline. -// Should be called from the filter's init_call_elem() method. -void grpc_deadline_state_start(grpc_exec_ctx* exec_ctx, grpc_call_element* elem, - gpr_timespec deadline); - -// Cancels the existing timer and starts a new one with new_deadline. -// -// Note: It is generally safe to call this with an earlier deadline -// value than the current one, but not the reverse. No checks are done -// to ensure that the timer callback is not invoked while it is in the -// process of being reset, which means that attempting to increase the -// deadline may result in the timer being called twice. -void grpc_deadline_state_reset(grpc_exec_ctx* exec_ctx, grpc_call_element* elem, - gpr_timespec new_deadline); - -// To be called from the client-side filter's start_transport_stream_op() -// method. Ensures that the deadline timer is cancelled when the call -// is completed. -// -// Note: It is the caller's responsibility to chain to the next filter if -// necessary after this function returns. -void grpc_deadline_state_client_start_transport_stream_op( - grpc_exec_ctx* exec_ctx, grpc_call_element* elem, - grpc_transport_stream_op* op); - -// Deadline filters for direct client channels and server channels. -// Note: Deadlines for non-direct client channels are handled by the -// client_channel filter. -extern const grpc_channel_filter grpc_client_deadline_filter; -extern const grpc_channel_filter grpc_server_deadline_filter; - -#endif /* GRPC_CORE_LIB_CHANNEL_DEADLINE_FILTER_H */ diff --git a/Sources/CgRPC/src/core/lib/channel/handshaker.c b/Sources/CgRPC/src/core/lib/channel/handshaker.c index 23edc826c..2cb83f411 100644 --- a/Sources/CgRPC/src/core/lib/channel/handshaker.c +++ b/Sources/CgRPC/src/core/lib/channel/handshaker.c @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -55,8 +40,8 @@ void grpc_handshaker_destroy(grpc_exec_ctx* exec_ctx, } void grpc_handshaker_shutdown(grpc_exec_ctx* exec_ctx, - grpc_handshaker* handshaker) { - handshaker->vtable->shutdown(exec_ctx, handshaker); + grpc_handshaker* handshaker, grpc_error* why) { + handshaker->vtable->shutdown(exec_ctx, handshaker, why); } void grpc_handshaker_do_handshake(grpc_exec_ctx* exec_ctx, @@ -86,21 +71,58 @@ struct grpc_handshake_manager { grpc_tcp_server_acceptor* acceptor; // Deadline timer across all handshakers. grpc_timer deadline_timer; + grpc_closure on_timeout; // The final callback and user_data to invoke after the last handshaker. grpc_closure on_handshake_done; void* user_data; // Handshaker args. grpc_handshaker_args args; + // Links to the previous and next managers in a list of all pending handshakes + // Used at server side only. + grpc_handshake_manager* prev; + grpc_handshake_manager* next; }; grpc_handshake_manager* grpc_handshake_manager_create() { - grpc_handshake_manager* mgr = gpr_malloc(sizeof(grpc_handshake_manager)); - memset(mgr, 0, sizeof(*mgr)); + grpc_handshake_manager* mgr = gpr_zalloc(sizeof(grpc_handshake_manager)); gpr_mu_init(&mgr->mu); gpr_ref_init(&mgr->refs, 1); return mgr; } +void grpc_handshake_manager_pending_list_add(grpc_handshake_manager** head, + grpc_handshake_manager* mgr) { + GPR_ASSERT(mgr->prev == NULL); + GPR_ASSERT(mgr->next == NULL); + mgr->next = *head; + if (*head) { + (*head)->prev = mgr; + } + *head = mgr; +} + +void grpc_handshake_manager_pending_list_remove(grpc_handshake_manager** head, + grpc_handshake_manager* mgr) { + if (mgr->next != NULL) { + mgr->next->prev = mgr->prev; + } + if (mgr->prev != NULL) { + mgr->prev->next = mgr->next; + } else { + GPR_ASSERT(*head == mgr); + *head = mgr->next; + } +} + +void grpc_handshake_manager_pending_list_shutdown_all( + grpc_exec_ctx* exec_ctx, grpc_handshake_manager* head, grpc_error* why) { + while (head != NULL) { + grpc_handshake_manager_shutdown(exec_ctx, head, GRPC_ERROR_REF(why)); + head = head->next; + } + GRPC_ERROR_UNREF(why); +} + static bool is_power_of_2(size_t n) { return (n & (n - 1)) == 0; } void grpc_handshake_manager_add(grpc_handshake_manager* mgr, @@ -140,14 +162,17 @@ void grpc_handshake_manager_destroy(grpc_exec_ctx* exec_ctx, } void grpc_handshake_manager_shutdown(grpc_exec_ctx* exec_ctx, - grpc_handshake_manager* mgr) { + grpc_handshake_manager* mgr, + grpc_error* why) { gpr_mu_lock(&mgr->mu); // Shutdown the handshaker that's currently in progress, if any. if (!mgr->shutdown && mgr->index > 0) { mgr->shutdown = true; - grpc_handshaker_shutdown(exec_ctx, mgr->handshakers[mgr->index - 1]); + grpc_handshaker_shutdown(exec_ctx, mgr->handshakers[mgr->index - 1], + GRPC_ERROR_REF(why)); } gpr_mu_unlock(&mgr->mu); + GRPC_ERROR_UNREF(why); } // Helper function to call either the next handshaker or the @@ -165,7 +190,7 @@ static bool call_next_handshaker_locked(grpc_exec_ctx* exec_ctx, // Cancel deadline timer, since we're invoking the on_handshake_done // callback now. grpc_timer_cancel(exec_ctx, &mgr->deadline_timer); - grpc_exec_ctx_sched(exec_ctx, &mgr->on_handshake_done, error, NULL); + GRPC_CLOSURE_SCHED(exec_ctx, &mgr->on_handshake_done, error); mgr->shutdown = true; } else { grpc_handshaker_do_handshake(exec_ctx, mgr->handshakers[mgr->index], @@ -196,7 +221,9 @@ static void call_next_handshaker(grpc_exec_ctx* exec_ctx, void* arg, static void on_timeout(grpc_exec_ctx* exec_ctx, void* arg, grpc_error* error) { grpc_handshake_manager* mgr = arg; if (error == GRPC_ERROR_NONE) { // Timer fired, rather than being cancelled. - grpc_handshake_manager_shutdown(exec_ctx, mgr); + grpc_handshake_manager_shutdown( + exec_ctx, mgr, + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Handshake timed out")); } grpc_handshake_manager_unref(exec_ctx, mgr); } @@ -218,13 +245,17 @@ void grpc_handshake_manager_do_handshake( grpc_slice_buffer_init(mgr->args.read_buffer); // Initialize state needed for calling handshakers. mgr->acceptor = acceptor; - grpc_closure_init(&mgr->call_next_handshaker, call_next_handshaker, mgr); - grpc_closure_init(&mgr->on_handshake_done, on_handshake_done, &mgr->args); + GRPC_CLOSURE_INIT(&mgr->call_next_handshaker, call_next_handshaker, mgr, + grpc_schedule_on_exec_ctx); + GRPC_CLOSURE_INIT(&mgr->on_handshake_done, on_handshake_done, &mgr->args, + grpc_schedule_on_exec_ctx); // Start deadline timer, which owns a ref. gpr_ref(&mgr->refs); + GRPC_CLOSURE_INIT(&mgr->on_timeout, on_timeout, mgr, + grpc_schedule_on_exec_ctx); grpc_timer_init(exec_ctx, &mgr->deadline_timer, gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC), - on_timeout, mgr, gpr_now(GPR_CLOCK_MONOTONIC)); + &mgr->on_timeout, gpr_now(GPR_CLOCK_MONOTONIC)); // Start first handshaker, which also owns a ref. gpr_ref(&mgr->refs); bool done = call_next_handshaker_locked(exec_ctx, mgr, GRPC_ERROR_NONE); diff --git a/Sources/CgRPC/src/core/lib/channel/handshaker.h b/Sources/CgRPC/src/core/lib/channel/handshaker.h index 450b7adae..eb9a59bd0 100644 --- a/Sources/CgRPC/src/core/lib/channel/handshaker.h +++ b/Sources/CgRPC/src/core/lib/channel/handshaker.h @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -86,7 +71,8 @@ typedef struct { /// Shuts down the handshaker (e.g., to clean up when the operation is /// aborted in the middle). - void (*shutdown)(grpc_exec_ctx* exec_ctx, grpc_handshaker* handshaker); + void (*shutdown)(grpc_exec_ctx* exec_ctx, grpc_handshaker* handshaker, + grpc_error* why); /// Performs handshaking, modifying \a args as needed (e.g., to /// replace \a endpoint with a wrapped endpoint). @@ -111,7 +97,7 @@ void grpc_handshaker_init(const grpc_handshaker_vtable* vtable, void grpc_handshaker_destroy(grpc_exec_ctx* exec_ctx, grpc_handshaker* handshaker); void grpc_handshaker_shutdown(grpc_exec_ctx* exec_ctx, - grpc_handshaker* handshaker); + grpc_handshaker* handshaker, grpc_error* why); void grpc_handshaker_do_handshake(grpc_exec_ctx* exec_ctx, grpc_handshaker* handshaker, grpc_tcp_server_acceptor* acceptor, @@ -141,7 +127,8 @@ void grpc_handshake_manager_destroy(grpc_exec_ctx* exec_ctx, /// The caller must still call grpc_handshake_manager_destroy() after /// calling this function. void grpc_handshake_manager_shutdown(grpc_exec_ctx* exec_ctx, - grpc_handshake_manager* mgr); + grpc_handshake_manager* mgr, + grpc_error* why); /// Invokes handshakers in the order they were added. /// Takes ownership of \a endpoint, and then passes that ownership to @@ -161,4 +148,20 @@ void grpc_handshake_manager_do_handshake( gpr_timespec deadline, grpc_tcp_server_acceptor* acceptor, grpc_iomgr_cb_func on_handshake_done, void* user_data); +/// Add \a mgr to the server side list of all pending handshake managers, the +/// list starts with \a *head. +// Not thread-safe. Caller needs to synchronize. +void grpc_handshake_manager_pending_list_add(grpc_handshake_manager** head, + grpc_handshake_manager* mgr); + +/// Remove \a mgr from the server side list of all pending handshake managers. +// Not thread-safe. Caller needs to synchronize. +void grpc_handshake_manager_pending_list_remove(grpc_handshake_manager** head, + grpc_handshake_manager* mgr); + +/// Shutdown all pending handshake managers on the server side. +// Not thread-safe. Caller needs to synchronize. +void grpc_handshake_manager_pending_list_shutdown_all( + grpc_exec_ctx* exec_ctx, grpc_handshake_manager* head, grpc_error* why); + #endif /* GRPC_CORE_LIB_CHANNEL_HANDSHAKER_H */ diff --git a/Sources/CgRPC/src/core/lib/channel/handshaker_factory.c b/Sources/CgRPC/src/core/lib/channel/handshaker_factory.c new file mode 100644 index 000000000..4deb280c6 --- /dev/null +++ b/Sources/CgRPC/src/core/lib/channel/handshaker_factory.c @@ -0,0 +1,39 @@ +/* + * + * Copyright 2016 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 "src/core/lib/channel/handshaker_factory.h" + +#include + +void grpc_handshaker_factory_add_handshakers( + grpc_exec_ctx *exec_ctx, grpc_handshaker_factory *handshaker_factory, + const grpc_channel_args *args, grpc_handshake_manager *handshake_mgr) { + if (handshaker_factory != NULL) { + GPR_ASSERT(handshaker_factory->vtable != NULL); + handshaker_factory->vtable->add_handshakers(exec_ctx, handshaker_factory, + args, handshake_mgr); + } +} + +void grpc_handshaker_factory_destroy( + grpc_exec_ctx *exec_ctx, grpc_handshaker_factory *handshaker_factory) { + if (handshaker_factory != NULL) { + GPR_ASSERT(handshaker_factory->vtable != NULL); + handshaker_factory->vtable->destroy(exec_ctx, handshaker_factory); + } +} diff --git a/Sources/CgRPC/src/core/lib/channel/handshaker_factory.h b/Sources/CgRPC/src/core/lib/channel/handshaker_factory.h new file mode 100644 index 000000000..6238e735d --- /dev/null +++ b/Sources/CgRPC/src/core/lib/channel/handshaker_factory.h @@ -0,0 +1,51 @@ +/* + * + * Copyright 2016 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 GRPC_CORE_LIB_CHANNEL_HANDSHAKER_FACTORY_H +#define GRPC_CORE_LIB_CHANNEL_HANDSHAKER_FACTORY_H + +#include + +#include "src/core/lib/channel/handshaker.h" +#include "src/core/lib/iomgr/exec_ctx.h" + +// A handshaker factory is used to create handshakers. + +typedef struct grpc_handshaker_factory grpc_handshaker_factory; + +typedef struct { + void (*add_handshakers)(grpc_exec_ctx *exec_ctx, + grpc_handshaker_factory *handshaker_factory, + const grpc_channel_args *args, + grpc_handshake_manager *handshake_mgr); + void (*destroy)(grpc_exec_ctx *exec_ctx, + grpc_handshaker_factory *handshaker_factory); +} grpc_handshaker_factory_vtable; + +struct grpc_handshaker_factory { + const grpc_handshaker_factory_vtable *vtable; +}; + +void grpc_handshaker_factory_add_handshakers( + grpc_exec_ctx *exec_ctx, grpc_handshaker_factory *handshaker_factory, + const grpc_channel_args *args, grpc_handshake_manager *handshake_mgr); + +void grpc_handshaker_factory_destroy( + grpc_exec_ctx *exec_ctx, grpc_handshaker_factory *handshaker_factory); + +#endif /* GRPC_CORE_LIB_CHANNEL_HANDSHAKER_FACTORY_H */ diff --git a/Sources/CgRPC/src/core/lib/channel/handshaker_registry.c b/Sources/CgRPC/src/core/lib/channel/handshaker_registry.c new file mode 100644 index 000000000..8c4bc3aa0 --- /dev/null +++ b/Sources/CgRPC/src/core/lib/channel/handshaker_registry.c @@ -0,0 +1,98 @@ +/* + * + * Copyright 2016 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 "src/core/lib/channel/handshaker_registry.h" + +#include + +#include + +// +// grpc_handshaker_factory_list +// + +typedef struct { + grpc_handshaker_factory** list; + size_t num_factories; +} grpc_handshaker_factory_list; + +static void grpc_handshaker_factory_list_register( + grpc_handshaker_factory_list* list, bool at_start, + grpc_handshaker_factory* factory) { + list->list = gpr_realloc( + list->list, (list->num_factories + 1) * sizeof(grpc_handshaker_factory*)); + if (at_start) { + memmove(list->list + 1, list->list, + sizeof(grpc_handshaker_factory*) * list->num_factories); + list->list[0] = factory; + } else { + list->list[list->num_factories] = factory; + } + ++list->num_factories; +} + +static void grpc_handshaker_factory_list_add_handshakers( + grpc_exec_ctx* exec_ctx, grpc_handshaker_factory_list* list, + const grpc_channel_args* args, grpc_handshake_manager* handshake_mgr) { + for (size_t i = 0; i < list->num_factories; ++i) { + grpc_handshaker_factory_add_handshakers(exec_ctx, list->list[i], args, + handshake_mgr); + } +} + +static void grpc_handshaker_factory_list_destroy( + grpc_exec_ctx* exec_ctx, grpc_handshaker_factory_list* list) { + for (size_t i = 0; i < list->num_factories; ++i) { + grpc_handshaker_factory_destroy(exec_ctx, list->list[i]); + } + gpr_free(list->list); +} + +// +// plugin +// + +static grpc_handshaker_factory_list + g_handshaker_factory_lists[NUM_HANDSHAKER_TYPES]; + +void grpc_handshaker_factory_registry_init() { + memset(g_handshaker_factory_lists, 0, sizeof(g_handshaker_factory_lists)); +} + +void grpc_handshaker_factory_registry_shutdown(grpc_exec_ctx* exec_ctx) { + for (size_t i = 0; i < NUM_HANDSHAKER_TYPES; ++i) { + grpc_handshaker_factory_list_destroy(exec_ctx, + &g_handshaker_factory_lists[i]); + } +} + +void grpc_handshaker_factory_register(bool at_start, + grpc_handshaker_type handshaker_type, + grpc_handshaker_factory* factory) { + grpc_handshaker_factory_list_register( + &g_handshaker_factory_lists[handshaker_type], at_start, factory); +} + +void grpc_handshakers_add(grpc_exec_ctx* exec_ctx, + grpc_handshaker_type handshaker_type, + const grpc_channel_args* args, + grpc_handshake_manager* handshake_mgr) { + grpc_handshaker_factory_list_add_handshakers( + exec_ctx, &g_handshaker_factory_lists[handshaker_type], args, + handshake_mgr); +} diff --git a/Sources/CgRPC/src/core/lib/channel/handshaker_registry.h b/Sources/CgRPC/src/core/lib/channel/handshaker_registry.h new file mode 100644 index 000000000..a3b2ac1dc --- /dev/null +++ b/Sources/CgRPC/src/core/lib/channel/handshaker_registry.h @@ -0,0 +1,48 @@ +/* + * + * Copyright 2016 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 GRPC_CORE_LIB_CHANNEL_HANDSHAKER_REGISTRY_H +#define GRPC_CORE_LIB_CHANNEL_HANDSHAKER_REGISTRY_H + +#include + +#include "src/core/lib/channel/handshaker_factory.h" +#include "src/core/lib/iomgr/exec_ctx.h" + +typedef enum { + HANDSHAKER_CLIENT = 0, + HANDSHAKER_SERVER, + NUM_HANDSHAKER_TYPES, // Must be last. +} grpc_handshaker_type; + +void grpc_handshaker_factory_registry_init(); +void grpc_handshaker_factory_registry_shutdown(grpc_exec_ctx* exec_ctx); + +/// Registers a new handshaker factory. Takes ownership. +/// If \a at_start is true, the new handshaker will be at the beginning of +/// the list. Otherwise, it will be added to the end. +void grpc_handshaker_factory_register(bool at_start, + grpc_handshaker_type handshaker_type, + grpc_handshaker_factory* factory); + +void grpc_handshakers_add(grpc_exec_ctx* exec_ctx, + grpc_handshaker_type handshaker_type, + const grpc_channel_args* args, + grpc_handshake_manager* handshake_mgr); + +#endif /* GRPC_CORE_LIB_CHANNEL_HANDSHAKER_REGISTRY_H */ diff --git a/Sources/CgRPC/src/core/lib/channel/http_client_filter.c b/Sources/CgRPC/src/core/lib/channel/http_client_filter.c deleted file mode 100644 index 1a2d08dda..000000000 --- a/Sources/CgRPC/src/core/lib/channel/http_client_filter.c +++ /dev/null @@ -1,495 +0,0 @@ -/* - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include "src/core/lib/channel/http_client_filter.h" -#include -#include -#include -#include -#include "src/core/lib/profiling/timers.h" -#include "src/core/lib/slice/percent_encoding.h" -#include "src/core/lib/support/string.h" -#include "src/core/lib/transport/static_metadata.h" -#include "src/core/lib/transport/transport_impl.h" - -#define EXPECTED_CONTENT_TYPE "application/grpc" -#define EXPECTED_CONTENT_TYPE_LENGTH sizeof(EXPECTED_CONTENT_TYPE) - 1 - -/* default maximum size of payload eligable for GET request */ -static const size_t kMaxPayloadSizeForGet = 2048; - -typedef struct call_data { - grpc_linked_mdelem method; - grpc_linked_mdelem scheme; - grpc_linked_mdelem authority; - grpc_linked_mdelem te_trailers; - grpc_linked_mdelem content_type; - grpc_linked_mdelem user_agent; - grpc_linked_mdelem payload_bin; - - grpc_metadata_batch *recv_initial_metadata; - grpc_metadata_batch *recv_trailing_metadata; - uint8_t *payload_bytes; - - /* Vars to read data off of send_message */ - grpc_transport_stream_op send_op; - uint32_t send_length; - uint32_t send_flags; - grpc_slice incoming_slice; - grpc_slice_buffer_stream replacement_stream; - grpc_slice_buffer slices; - /* flag that indicates that all slices of send_messages aren't availble */ - bool send_message_blocked; - - /** Closure to call when finished with the hc_on_recv hook */ - grpc_closure *on_done_recv_initial_metadata; - grpc_closure *on_done_recv_trailing_metadata; - grpc_closure *on_complete; - grpc_closure *post_send; - - /** Receive closures are chained: we inject this closure as the on_done_recv - up-call on transport_op, and remember to call our on_done_recv member - after handling it. */ - grpc_closure hc_on_recv_initial_metadata; - grpc_closure hc_on_recv_trailing_metadata; - grpc_closure hc_on_complete; - grpc_closure got_slice; - grpc_closure send_done; -} call_data; - -typedef struct channel_data { - grpc_mdelem *static_scheme; - grpc_mdelem *user_agent; - size_t max_payload_size_for_get; -} channel_data; - -typedef struct { - grpc_call_element *elem; - grpc_exec_ctx *exec_ctx; -} client_recv_filter_args; - -static grpc_mdelem *client_recv_filter(void *user_data, grpc_mdelem *md) { - client_recv_filter_args *a = user_data; - if (md == GRPC_MDELEM_STATUS_200) { - return NULL; - } else if (md->key == GRPC_MDSTR_STATUS) { - char *message_string; - gpr_asprintf(&message_string, "Received http2 header with status: %s", - grpc_mdstr_as_c_string(md->value)); - grpc_slice message = grpc_slice_from_copied_string(message_string); - gpr_free(message_string); - grpc_call_element_send_close_with_message(a->exec_ctx, a->elem, - GRPC_STATUS_CANCELLED, &message); - return NULL; - } else if (md->key == GRPC_MDSTR_GRPC_MESSAGE) { - grpc_slice pct_decoded_msg = - grpc_permissive_percent_decode_slice(md->value->slice); - if (grpc_slice_is_equivalent(pct_decoded_msg, md->value->slice)) { - grpc_slice_unref(pct_decoded_msg); - return md; - } else { - return grpc_mdelem_from_metadata_strings( - GRPC_MDSTR_GRPC_MESSAGE, grpc_mdstr_from_slice(pct_decoded_msg)); - } - } else if (md == GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC) { - return NULL; - } else if (md->key == GRPC_MDSTR_CONTENT_TYPE) { - const char *value_str = grpc_mdstr_as_c_string(md->value); - if (strncmp(value_str, EXPECTED_CONTENT_TYPE, - EXPECTED_CONTENT_TYPE_LENGTH) == 0 && - (value_str[EXPECTED_CONTENT_TYPE_LENGTH] == '+' || - value_str[EXPECTED_CONTENT_TYPE_LENGTH] == ';')) { - /* Although the C implementation doesn't (currently) generate them, - any custom +-suffix is explicitly valid. */ - /* TODO(klempner): We should consider preallocating common values such - as +proto or +json, or at least stashing them if we see them. */ - /* TODO(klempner): Should we be surfacing this to application code? */ - } else { - /* TODO(klempner): We're currently allowing this, but we shouldn't - see it without a proxy so log for now. */ - gpr_log(GPR_INFO, "Unexpected content-type '%s'", value_str); - } - return NULL; - } - return md; -} - -static void hc_on_recv_initial_metadata(grpc_exec_ctx *exec_ctx, - void *user_data, grpc_error *error) { - grpc_call_element *elem = user_data; - call_data *calld = elem->call_data; - client_recv_filter_args a; - a.elem = elem; - a.exec_ctx = exec_ctx; - grpc_metadata_batch_filter(calld->recv_initial_metadata, client_recv_filter, - &a); - grpc_closure_run(exec_ctx, calld->on_done_recv_initial_metadata, - GRPC_ERROR_REF(error)); -} - -static void hc_on_recv_trailing_metadata(grpc_exec_ctx *exec_ctx, - void *user_data, grpc_error *error) { - grpc_call_element *elem = user_data; - call_data *calld = elem->call_data; - client_recv_filter_args a; - a.elem = elem; - a.exec_ctx = exec_ctx; - grpc_metadata_batch_filter(calld->recv_trailing_metadata, client_recv_filter, - &a); - grpc_closure_run(exec_ctx, calld->on_done_recv_trailing_metadata, - GRPC_ERROR_REF(error)); -} - -static void hc_on_complete(grpc_exec_ctx *exec_ctx, void *user_data, - grpc_error *error) { - grpc_call_element *elem = user_data; - call_data *calld = elem->call_data; - if (calld->payload_bytes) { - gpr_free(calld->payload_bytes); - calld->payload_bytes = NULL; - } - calld->on_complete->cb(exec_ctx, calld->on_complete->cb_arg, error); -} - -static void send_done(grpc_exec_ctx *exec_ctx, void *elemp, grpc_error *error) { - grpc_call_element *elem = elemp; - call_data *calld = elem->call_data; - grpc_slice_buffer_reset_and_unref(&calld->slices); - calld->post_send->cb(exec_ctx, calld->post_send->cb_arg, error); -} - -static grpc_mdelem *client_strip_filter(void *user_data, grpc_mdelem *md) { - /* eat the things we'd like to set ourselves */ - if (md->key == GRPC_MDSTR_METHOD) return NULL; - if (md->key == GRPC_MDSTR_SCHEME) return NULL; - if (md->key == GRPC_MDSTR_TE) return NULL; - if (md->key == GRPC_MDSTR_CONTENT_TYPE) return NULL; - if (md->key == GRPC_MDSTR_USER_AGENT) return NULL; - return md; -} - -static void continue_send_message(grpc_exec_ctx *exec_ctx, - grpc_call_element *elem) { - call_data *calld = elem->call_data; - uint8_t *wrptr = calld->payload_bytes; - while (grpc_byte_stream_next(exec_ctx, calld->send_op.send_message, - &calld->incoming_slice, ~(size_t)0, - &calld->got_slice)) { - memcpy(wrptr, GRPC_SLICE_START_PTR(calld->incoming_slice), - GRPC_SLICE_LENGTH(calld->incoming_slice)); - wrptr += GRPC_SLICE_LENGTH(calld->incoming_slice); - grpc_slice_buffer_add(&calld->slices, calld->incoming_slice); - if (calld->send_length == calld->slices.length) { - calld->send_message_blocked = false; - break; - } - } -} - -static void got_slice(grpc_exec_ctx *exec_ctx, void *elemp, grpc_error *error) { - grpc_call_element *elem = elemp; - call_data *calld = elem->call_data; - calld->send_message_blocked = false; - grpc_slice_buffer_add(&calld->slices, calld->incoming_slice); - if (calld->send_length == calld->slices.length) { - /* Pass down the original send_message op that was blocked.*/ - grpc_slice_buffer_stream_init(&calld->replacement_stream, &calld->slices, - calld->send_flags); - calld->send_op.send_message = &calld->replacement_stream.base; - calld->post_send = calld->send_op.on_complete; - calld->send_op.on_complete = &calld->send_done; - grpc_call_next_op(exec_ctx, elem, &calld->send_op); - } else { - continue_send_message(exec_ctx, elem); - } -} - -static void hc_mutate_op(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, - grpc_transport_stream_op *op) { - /* grab pointers to our data from the call element */ - call_data *calld = elem->call_data; - channel_data *channeld = elem->channel_data; - - if (op->send_initial_metadata != NULL) { - /* Decide which HTTP VERB to use. We use GET if the request is marked - cacheable, and the operation contains both initial metadata and send - message, and the payload is below the size threshold, and all the data - for this request is immediately available. */ - grpc_mdelem *method = GRPC_MDELEM_METHOD_POST; - if ((op->send_initial_metadata_flags & - GRPC_INITIAL_METADATA_CACHEABLE_REQUEST) && - op->send_message != NULL && - op->send_message->length < channeld->max_payload_size_for_get) { - method = GRPC_MDELEM_METHOD_GET; - /* The following write to calld->send_message_blocked isn't racy with - reads in hc_start_transport_op (which deals with SEND_MESSAGE ops) because - being here means ops->send_message is not NULL, which is primarily - guarding the read there. */ - calld->send_message_blocked = true; - } else if (op->send_initial_metadata_flags & - GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST) { - method = GRPC_MDELEM_METHOD_PUT; - } - - /* Attempt to read the data from send_message and create a header field. */ - if (method == GRPC_MDELEM_METHOD_GET) { - /* allocate memory to hold the entire payload */ - calld->payload_bytes = gpr_malloc(op->send_message->length); - - /* read slices of send_message and copy into payload_bytes */ - calld->send_op = *op; - calld->send_length = op->send_message->length; - calld->send_flags = op->send_message->flags; - continue_send_message(exec_ctx, elem); - - if (calld->send_message_blocked == false) { - /* when all the send_message data is available, then create a MDELEM and - append to headers */ - grpc_mdelem *payload_bin = grpc_mdelem_from_metadata_strings( - GRPC_MDSTR_GRPC_PAYLOAD_BIN, - grpc_mdstr_from_buffer(calld->payload_bytes, - op->send_message->length)); - grpc_metadata_batch_add_tail(op->send_initial_metadata, - &calld->payload_bin, payload_bin); - calld->on_complete = op->on_complete; - op->on_complete = &calld->hc_on_complete; - op->send_message = NULL; - } else { - /* Not all data is available. Fall back to POST. */ - gpr_log(GPR_DEBUG, - "Request is marked Cacheable but not all data is available.\ - Falling back to POST"); - method = GRPC_MDELEM_METHOD_POST; - } - } - - grpc_metadata_batch_filter(op->send_initial_metadata, client_strip_filter, - elem); - /* Send : prefixed headers, which have to be before any application - layer headers. */ - grpc_metadata_batch_add_head(op->send_initial_metadata, &calld->method, - method); - grpc_metadata_batch_add_head(op->send_initial_metadata, &calld->scheme, - channeld->static_scheme); - grpc_metadata_batch_add_tail(op->send_initial_metadata, &calld->te_trailers, - GRPC_MDELEM_TE_TRAILERS); - grpc_metadata_batch_add_tail( - op->send_initial_metadata, &calld->content_type, - GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC); - grpc_metadata_batch_add_tail(op->send_initial_metadata, &calld->user_agent, - GRPC_MDELEM_REF(channeld->user_agent)); - } - - if (op->recv_initial_metadata != NULL) { - /* substitute our callback for the higher callback */ - calld->recv_initial_metadata = op->recv_initial_metadata; - calld->on_done_recv_initial_metadata = op->recv_initial_metadata_ready; - op->recv_initial_metadata_ready = &calld->hc_on_recv_initial_metadata; - } - - if (op->recv_trailing_metadata != NULL) { - /* substitute our callback for the higher callback */ - calld->recv_trailing_metadata = op->recv_trailing_metadata; - calld->on_done_recv_trailing_metadata = op->on_complete; - op->on_complete = &calld->hc_on_recv_trailing_metadata; - } -} - -static void hc_start_transport_op(grpc_exec_ctx *exec_ctx, - grpc_call_element *elem, - grpc_transport_stream_op *op) { - GPR_TIMER_BEGIN("hc_start_transport_op", 0); - GRPC_CALL_LOG_OP(GPR_INFO, elem, op); - hc_mutate_op(exec_ctx, elem, op); - GPR_TIMER_END("hc_start_transport_op", 0); - call_data *calld = elem->call_data; - if (op->send_message != NULL && calld->send_message_blocked) { - /* Don't forward the op. send_message contains slices that aren't ready - yet. The call will be forwarded by the op_complete of slice read call. */ - } else { - grpc_call_next_op(exec_ctx, elem, op); - } -} - -/* Constructor for call_data */ -static grpc_error *init_call_elem(grpc_exec_ctx *exec_ctx, - grpc_call_element *elem, - grpc_call_element_args *args) { - call_data *calld = elem->call_data; - calld->on_done_recv_initial_metadata = NULL; - calld->on_done_recv_trailing_metadata = NULL; - calld->on_complete = NULL; - calld->payload_bytes = NULL; - calld->send_message_blocked = false; - grpc_slice_buffer_init(&calld->slices); - grpc_closure_init(&calld->hc_on_recv_initial_metadata, - hc_on_recv_initial_metadata, elem); - grpc_closure_init(&calld->hc_on_recv_trailing_metadata, - hc_on_recv_trailing_metadata, elem); - grpc_closure_init(&calld->hc_on_complete, hc_on_complete, elem); - grpc_closure_init(&calld->got_slice, got_slice, elem); - grpc_closure_init(&calld->send_done, send_done, elem); - return GRPC_ERROR_NONE; -} - -/* Destructor for call_data */ -static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, - const grpc_call_final_info *final_info, - void *ignored) { - call_data *calld = elem->call_data; - grpc_slice_buffer_destroy(&calld->slices); -} - -static grpc_mdelem *scheme_from_args(const grpc_channel_args *args) { - unsigned i; - size_t j; - grpc_mdelem *valid_schemes[] = {GRPC_MDELEM_SCHEME_HTTP, - GRPC_MDELEM_SCHEME_HTTPS}; - if (args != NULL) { - for (i = 0; i < args->num_args; ++i) { - if (args->args[i].type == GRPC_ARG_STRING && - strcmp(args->args[i].key, GRPC_ARG_HTTP2_SCHEME) == 0) { - for (j = 0; j < GPR_ARRAY_SIZE(valid_schemes); j++) { - if (0 == strcmp(grpc_mdstr_as_c_string(valid_schemes[j]->value), - args->args[i].value.string)) { - return valid_schemes[j]; - } - } - } - } - } - return GRPC_MDELEM_SCHEME_HTTP; -} - -static size_t max_payload_size_from_args(const grpc_channel_args *args) { - if (args != NULL) { - for (size_t i = 0; i < args->num_args; ++i) { - if (0 == strcmp(args->args[i].key, GRPC_ARG_MAX_PAYLOAD_SIZE_FOR_GET)) { - if (args->args[i].type != GRPC_ARG_INTEGER) { - gpr_log(GPR_ERROR, "%s: must be an integer", - GRPC_ARG_MAX_PAYLOAD_SIZE_FOR_GET); - } else { - return (size_t)args->args[i].value.integer; - } - } - } - } - return kMaxPayloadSizeForGet; -} - -static grpc_mdstr *user_agent_from_args(const grpc_channel_args *args, - const char *transport_name) { - gpr_strvec v; - size_t i; - int is_first = 1; - char *tmp; - grpc_mdstr *result; - - gpr_strvec_init(&v); - - for (i = 0; args && i < args->num_args; i++) { - if (0 == strcmp(args->args[i].key, GRPC_ARG_PRIMARY_USER_AGENT_STRING)) { - if (args->args[i].type != GRPC_ARG_STRING) { - gpr_log(GPR_ERROR, "Channel argument '%s' should be a string", - GRPC_ARG_PRIMARY_USER_AGENT_STRING); - } else { - if (!is_first) gpr_strvec_add(&v, gpr_strdup(" ")); - is_first = 0; - gpr_strvec_add(&v, gpr_strdup(args->args[i].value.string)); - } - } - } - - gpr_asprintf(&tmp, "%sgrpc-c/%s (%s; %s; %s)", is_first ? "" : " ", - grpc_version_string(), GPR_PLATFORM_STRING, transport_name, - grpc_g_stands_for()); - is_first = 0; - gpr_strvec_add(&v, tmp); - - for (i = 0; args && i < args->num_args; i++) { - if (0 == strcmp(args->args[i].key, GRPC_ARG_SECONDARY_USER_AGENT_STRING)) { - if (args->args[i].type != GRPC_ARG_STRING) { - gpr_log(GPR_ERROR, "Channel argument '%s' should be a string", - GRPC_ARG_SECONDARY_USER_AGENT_STRING); - } else { - if (!is_first) gpr_strvec_add(&v, gpr_strdup(" ")); - is_first = 0; - gpr_strvec_add(&v, gpr_strdup(args->args[i].value.string)); - } - } - } - - tmp = gpr_strvec_flatten(&v, NULL); - gpr_strvec_destroy(&v); - result = grpc_mdstr_from_string(tmp); - gpr_free(tmp); - - return result; -} - -/* Constructor for channel_data */ -static grpc_error *init_channel_elem(grpc_exec_ctx *exec_ctx, - grpc_channel_element *elem, - grpc_channel_element_args *args) { - channel_data *chand = elem->channel_data; - GPR_ASSERT(!args->is_last); - GPR_ASSERT(args->optional_transport != NULL); - chand->static_scheme = scheme_from_args(args->channel_args); - chand->max_payload_size_for_get = - max_payload_size_from_args(args->channel_args); - chand->user_agent = grpc_mdelem_from_metadata_strings( - GRPC_MDSTR_USER_AGENT, - user_agent_from_args(args->channel_args, - args->optional_transport->vtable->name)); - return GRPC_ERROR_NONE; -} - -/* Destructor for channel data */ -static void destroy_channel_elem(grpc_exec_ctx *exec_ctx, - grpc_channel_element *elem) { - channel_data *chand = elem->channel_data; - GRPC_MDELEM_UNREF(chand->user_agent); -} - -const grpc_channel_filter grpc_http_client_filter = { - hc_start_transport_op, - grpc_channel_next_op, - sizeof(call_data), - init_call_elem, - grpc_call_stack_ignore_set_pollset_or_pollset_set, - destroy_call_elem, - sizeof(channel_data), - init_channel_elem, - destroy_channel_elem, - grpc_call_next_get_peer, - grpc_channel_next_get_info, - "http-client"}; diff --git a/Sources/CgRPC/src/core/lib/channel/http_client_filter.h b/Sources/CgRPC/src/core/lib/channel/http_client_filter.h deleted file mode 100644 index 9e6e106e9..000000000 --- a/Sources/CgRPC/src/core/lib/channel/http_client_filter.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#ifndef GRPC_CORE_LIB_CHANNEL_HTTP_CLIENT_FILTER_H -#define GRPC_CORE_LIB_CHANNEL_HTTP_CLIENT_FILTER_H - -#include "src/core/lib/channel/channel_stack.h" - -/* Processes metadata on the client side for HTTP2 transports */ -extern const grpc_channel_filter grpc_http_client_filter; - -/* Channel arg to override the http2 :scheme header */ -#define GRPC_ARG_HTTP2_SCHEME "grpc.http2_scheme" - -/* Channel arg to determine maximum size of payload eligable for GET request */ -#define GRPC_ARG_MAX_PAYLOAD_SIZE_FOR_GET "grpc.max_payload_size_for_get" - -#endif /* GRPC_CORE_LIB_CHANNEL_HTTP_CLIENT_FILTER_H */ diff --git a/Sources/CgRPC/src/core/lib/channel/http_server_filter.c b/Sources/CgRPC/src/core/lib/channel/http_server_filter.c deleted file mode 100644 index a5134ee21..000000000 --- a/Sources/CgRPC/src/core/lib/channel/http_server_filter.c +++ /dev/null @@ -1,376 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include "src/core/lib/channel/http_server_filter.h" - -#include -#include -#include -#include "src/core/lib/profiling/timers.h" -#include "src/core/lib/slice/percent_encoding.h" -#include "src/core/lib/transport/static_metadata.h" - -#define EXPECTED_CONTENT_TYPE "application/grpc" -#define EXPECTED_CONTENT_TYPE_LENGTH sizeof(EXPECTED_CONTENT_TYPE) - 1 - -extern int grpc_http_trace; - -typedef struct call_data { - uint8_t seen_path; - uint8_t seen_method; - uint8_t sent_status; - uint8_t seen_scheme; - uint8_t seen_te_trailers; - uint8_t seen_authority; - uint8_t seen_payload_bin; - grpc_linked_mdelem status; - grpc_linked_mdelem content_type; - - /* flag to ensure payload_bin is delivered only once */ - uint8_t payload_bin_delivered; - - grpc_metadata_batch *recv_initial_metadata; - bool *recv_idempotent_request; - bool *recv_cacheable_request; - /** Closure to call when finished with the hs_on_recv hook */ - grpc_closure *on_done_recv; - /** Closure to call when we retrieve read message from the payload-bin header - */ - grpc_closure *recv_message_ready; - grpc_closure *on_complete; - grpc_byte_stream **pp_recv_message; - grpc_slice_buffer read_slice_buffer; - grpc_slice_buffer_stream read_stream; - - /** Receive closures are chained: we inject this closure as the on_done_recv - up-call on transport_op, and remember to call our on_done_recv member - after handling it. */ - grpc_closure hs_on_recv; - grpc_closure hs_on_complete; - grpc_closure hs_recv_message_ready; -} call_data; - -typedef struct channel_data { uint8_t unused; } channel_data; - -typedef struct { - grpc_call_element *elem; - grpc_exec_ctx *exec_ctx; -} server_filter_args; - -static grpc_mdelem *server_filter_outgoing_metadata(void *user_data, - grpc_mdelem *md) { - if (md->key == GRPC_MDSTR_GRPC_MESSAGE) { - grpc_slice pct_encoded_msg = grpc_percent_encode_slice( - md->value->slice, grpc_compatible_percent_encoding_unreserved_bytes); - if (grpc_slice_is_equivalent(pct_encoded_msg, md->value->slice)) { - grpc_slice_unref(pct_encoded_msg); - return md; - } else { - return grpc_mdelem_from_metadata_strings( - GRPC_MDSTR_GRPC_MESSAGE, grpc_mdstr_from_slice(pct_encoded_msg)); - } - } else { - return md; - } -} - -static grpc_mdelem *server_filter(void *user_data, grpc_mdelem *md) { - server_filter_args *a = user_data; - grpc_call_element *elem = a->elem; - call_data *calld = elem->call_data; - - /* Check if it is one of the headers we care about. */ - if (md == GRPC_MDELEM_TE_TRAILERS || md == GRPC_MDELEM_METHOD_POST || - md == GRPC_MDELEM_METHOD_PUT || md == GRPC_MDELEM_METHOD_GET || - md == GRPC_MDELEM_SCHEME_HTTP || md == GRPC_MDELEM_SCHEME_HTTPS || - md == GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC) { - /* swallow it */ - if (md == GRPC_MDELEM_METHOD_POST) { - calld->seen_method = 1; - *calld->recv_idempotent_request = false; - *calld->recv_cacheable_request = false; - } else if (md == GRPC_MDELEM_METHOD_PUT) { - calld->seen_method = 1; - *calld->recv_idempotent_request = true; - } else if (md == GRPC_MDELEM_METHOD_GET) { - calld->seen_method = 1; - *calld->recv_cacheable_request = true; - } else if (md->key == GRPC_MDSTR_SCHEME) { - calld->seen_scheme = 1; - } else if (md == GRPC_MDELEM_TE_TRAILERS) { - calld->seen_te_trailers = 1; - } - /* TODO(klempner): Track that we've seen all the headers we should - require */ - return NULL; - } else if (md->key == GRPC_MDSTR_CONTENT_TYPE) { - const char *value_str = grpc_mdstr_as_c_string(md->value); - if (strncmp(value_str, EXPECTED_CONTENT_TYPE, - EXPECTED_CONTENT_TYPE_LENGTH) == 0 && - (value_str[EXPECTED_CONTENT_TYPE_LENGTH] == '+' || - value_str[EXPECTED_CONTENT_TYPE_LENGTH] == ';')) { - /* Although the C implementation doesn't (currently) generate them, - any custom +-suffix is explicitly valid. */ - /* TODO(klempner): We should consider preallocating common values such - as +proto or +json, or at least stashing them if we see them. */ - /* TODO(klempner): Should we be surfacing this to application code? */ - } else { - /* TODO(klempner): We're currently allowing this, but we shouldn't - see it without a proxy so log for now. */ - gpr_log(GPR_INFO, "Unexpected content-type '%s'", value_str); - } - return NULL; - } else if (md->key == GRPC_MDSTR_TE || md->key == GRPC_MDSTR_METHOD || - md->key == GRPC_MDSTR_SCHEME) { - gpr_log(GPR_ERROR, "Invalid %s: header: '%s'", - grpc_mdstr_as_c_string(md->key), grpc_mdstr_as_c_string(md->value)); - /* swallow it and error everything out. */ - /* TODO(klempner): We ought to generate more descriptive error messages - on the wire here. */ - grpc_call_element_send_cancel(a->exec_ctx, elem); - return NULL; - } else if (md->key == GRPC_MDSTR_PATH) { - if (calld->seen_path) { - gpr_log(GPR_ERROR, "Received :path twice"); - return NULL; - } - calld->seen_path = 1; - return md; - } else if (md->key == GRPC_MDSTR_AUTHORITY) { - calld->seen_authority = 1; - return md; - } else if (md->key == GRPC_MDSTR_HOST) { - /* translate host to :authority since :authority may be - omitted */ - grpc_mdelem *authority = grpc_mdelem_from_metadata_strings( - GRPC_MDSTR_AUTHORITY, GRPC_MDSTR_REF(md->value)); - calld->seen_authority = 1; - return authority; - } else if (md->key == GRPC_MDSTR_GRPC_PAYLOAD_BIN) { - /* Retrieve the payload from the value of the 'grpc-internal-payload-bin' - header field */ - calld->seen_payload_bin = 1; - grpc_slice_buffer_add(&calld->read_slice_buffer, - grpc_slice_ref(md->value->slice)); - grpc_slice_buffer_stream_init(&calld->read_stream, - &calld->read_slice_buffer, 0); - return NULL; - } else { - return md; - } -} - -static void hs_on_recv(grpc_exec_ctx *exec_ctx, void *user_data, - grpc_error *err) { - grpc_call_element *elem = user_data; - call_data *calld = elem->call_data; - if (err == GRPC_ERROR_NONE) { - server_filter_args a; - a.elem = elem; - a.exec_ctx = exec_ctx; - grpc_metadata_batch_filter(calld->recv_initial_metadata, server_filter, &a); - /* Have we seen the required http2 transport headers? - (:method, :scheme, content-type, with :path and :authority covered - at the channel level right now) */ - if (calld->seen_method && calld->seen_scheme && calld->seen_te_trailers && - calld->seen_path && calld->seen_authority) { - /* do nothing */ - } else { - err = GRPC_ERROR_CREATE("Bad incoming HTTP headers"); - if (!calld->seen_path) { - err = grpc_error_add_child(err, - GRPC_ERROR_CREATE("Missing :path header")); - } - if (!calld->seen_authority) { - err = grpc_error_add_child( - err, GRPC_ERROR_CREATE("Missing :authority header")); - } - if (!calld->seen_method) { - err = grpc_error_add_child(err, - GRPC_ERROR_CREATE("Missing :method header")); - } - if (!calld->seen_scheme) { - err = grpc_error_add_child(err, - GRPC_ERROR_CREATE("Missing :scheme header")); - } - if (!calld->seen_te_trailers) { - err = grpc_error_add_child( - err, GRPC_ERROR_CREATE("Missing te: trailers header")); - } - /* Error this call out */ - if (grpc_http_trace) { - const char *error_str = grpc_error_string(err); - gpr_log(GPR_ERROR, "Invalid http2 headers: %s", error_str); - grpc_error_free_string(error_str); - } - grpc_call_element_send_cancel(exec_ctx, elem); - } - } else { - GRPC_ERROR_REF(err); - } - calld->on_done_recv->cb(exec_ctx, calld->on_done_recv->cb_arg, err); - GRPC_ERROR_UNREF(err); -} - -static void hs_on_complete(grpc_exec_ctx *exec_ctx, void *user_data, - grpc_error *err) { - grpc_call_element *elem = user_data; - call_data *calld = elem->call_data; - /* Call recv_message_ready if we got the payload via the header field */ - if (calld->seen_payload_bin && calld->recv_message_ready != NULL) { - *calld->pp_recv_message = calld->payload_bin_delivered - ? NULL - : (grpc_byte_stream *)&calld->read_stream; - calld->recv_message_ready->cb(exec_ctx, calld->recv_message_ready->cb_arg, - err); - calld->recv_message_ready = NULL; - calld->payload_bin_delivered = true; - } - calld->on_complete->cb(exec_ctx, calld->on_complete->cb_arg, err); -} - -static void hs_recv_message_ready(grpc_exec_ctx *exec_ctx, void *user_data, - grpc_error *err) { - grpc_call_element *elem = user_data; - call_data *calld = elem->call_data; - if (calld->seen_payload_bin) { - /* do nothing. This is probably a GET request, and payload will be returned - in hs_on_complete callback. */ - } else { - calld->recv_message_ready->cb(exec_ctx, calld->recv_message_ready->cb_arg, - err); - } -} - -static void hs_mutate_op(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, - grpc_transport_stream_op *op) { - /* grab pointers to our data from the call element */ - call_data *calld = elem->call_data; - - if (op->send_initial_metadata != NULL && !calld->sent_status) { - calld->sent_status = 1; - grpc_metadata_batch_add_head(op->send_initial_metadata, &calld->status, - GRPC_MDELEM_STATUS_200); - grpc_metadata_batch_add_tail( - op->send_initial_metadata, &calld->content_type, - GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC); - } - - if (op->recv_initial_metadata) { - /* substitute our callback for the higher callback */ - GPR_ASSERT(op->recv_idempotent_request != NULL); - GPR_ASSERT(op->recv_cacheable_request != NULL); - calld->recv_initial_metadata = op->recv_initial_metadata; - calld->recv_idempotent_request = op->recv_idempotent_request; - calld->recv_cacheable_request = op->recv_cacheable_request; - calld->on_done_recv = op->recv_initial_metadata_ready; - op->recv_initial_metadata_ready = &calld->hs_on_recv; - } - - if (op->recv_message) { - calld->recv_message_ready = op->recv_message_ready; - calld->pp_recv_message = op->recv_message; - if (op->recv_message_ready) { - op->recv_message_ready = &calld->hs_recv_message_ready; - } - if (op->on_complete) { - calld->on_complete = op->on_complete; - op->on_complete = &calld->hs_on_complete; - } - } - - if (op->send_trailing_metadata) { - server_filter_args a = {elem, exec_ctx}; - grpc_metadata_batch_filter(op->send_trailing_metadata, - server_filter_outgoing_metadata, &a); - } -} - -static void hs_start_transport_op(grpc_exec_ctx *exec_ctx, - grpc_call_element *elem, - grpc_transport_stream_op *op) { - GRPC_CALL_LOG_OP(GPR_INFO, elem, op); - GPR_TIMER_BEGIN("hs_start_transport_op", 0); - hs_mutate_op(exec_ctx, elem, op); - grpc_call_next_op(exec_ctx, elem, op); - GPR_TIMER_END("hs_start_transport_op", 0); -} - -/* Constructor for call_data */ -static grpc_error *init_call_elem(grpc_exec_ctx *exec_ctx, - grpc_call_element *elem, - grpc_call_element_args *args) { - /* grab pointers to our data from the call element */ - call_data *calld = elem->call_data; - /* initialize members */ - memset(calld, 0, sizeof(*calld)); - grpc_closure_init(&calld->hs_on_recv, hs_on_recv, elem); - grpc_closure_init(&calld->hs_on_complete, hs_on_complete, elem); - grpc_closure_init(&calld->hs_recv_message_ready, hs_recv_message_ready, elem); - grpc_slice_buffer_init(&calld->read_slice_buffer); - return GRPC_ERROR_NONE; -} - -/* Destructor for call_data */ -static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, - const grpc_call_final_info *final_info, - void *ignored) { - call_data *calld = elem->call_data; - grpc_slice_buffer_destroy(&calld->read_slice_buffer); -} - -/* Constructor for channel_data */ -static grpc_error *init_channel_elem(grpc_exec_ctx *exec_ctx, - grpc_channel_element *elem, - grpc_channel_element_args *args) { - GPR_ASSERT(!args->is_last); - return GRPC_ERROR_NONE; -} - -/* Destructor for channel data */ -static void destroy_channel_elem(grpc_exec_ctx *exec_ctx, - grpc_channel_element *elem) {} - -const grpc_channel_filter grpc_http_server_filter = { - hs_start_transport_op, - grpc_channel_next_op, - sizeof(call_data), - init_call_elem, - grpc_call_stack_ignore_set_pollset_or_pollset_set, - destroy_call_elem, - sizeof(channel_data), - init_channel_elem, - destroy_channel_elem, - grpc_call_next_get_peer, - grpc_channel_next_get_info, - "http-server"}; diff --git a/Sources/CgRPC/src/core/lib/channel/http_server_filter.h b/Sources/CgRPC/src/core/lib/channel/http_server_filter.h deleted file mode 100644 index 77ba2d263..000000000 --- a/Sources/CgRPC/src/core/lib/channel/http_server_filter.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#ifndef GRPC_CORE_LIB_CHANNEL_HTTP_SERVER_FILTER_H -#define GRPC_CORE_LIB_CHANNEL_HTTP_SERVER_FILTER_H - -#include "src/core/lib/channel/channel_stack.h" - -/* Processes metadata on the client side for HTTP2 transports */ -extern const grpc_channel_filter grpc_http_server_filter; - -#endif /* GRPC_CORE_LIB_CHANNEL_HTTP_SERVER_FILTER_H */ diff --git a/Sources/CgRPC/src/core/lib/channel/message_size_filter.c b/Sources/CgRPC/src/core/lib/channel/message_size_filter.c deleted file mode 100644 index f05c78901..000000000 --- a/Sources/CgRPC/src/core/lib/channel/message_size_filter.c +++ /dev/null @@ -1,256 +0,0 @@ -// -// Copyright 2016, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// - -#include "src/core/lib/channel/message_size_filter.h" - -#include -#include - -#include -#include -#include -#include - -#include "src/core/lib/channel/channel_args.h" -#include "src/core/lib/support/string.h" -#include "src/core/lib/transport/service_config.h" - -typedef struct message_size_limits { - int max_send_size; - int max_recv_size; -} message_size_limits; - -static void* message_size_limits_copy(void* value) { - void* new_value = gpr_malloc(sizeof(message_size_limits)); - memcpy(new_value, value, sizeof(message_size_limits)); - return new_value; -} - -static const grpc_mdstr_hash_table_vtable message_size_limits_vtable = { - gpr_free, message_size_limits_copy}; - -static void* message_size_limits_create_from_json(const grpc_json* json) { - int max_request_message_bytes = -1; - int max_response_message_bytes = -1; - for (grpc_json* field = json->child; field != NULL; field = field->next) { - if (field->key == NULL) continue; - if (strcmp(field->key, "maxRequestMessageBytes") == 0) { - if (max_request_message_bytes >= 0) return NULL; // Duplicate. - if (field->type != GRPC_JSON_STRING) return NULL; - max_request_message_bytes = gpr_parse_nonnegative_int(field->value); - if (max_request_message_bytes == -1) return NULL; - } else if (strcmp(field->key, "maxResponseMessageBytes") == 0) { - if (max_response_message_bytes >= 0) return NULL; // Duplicate. - if (field->type != GRPC_JSON_STRING) return NULL; - max_response_message_bytes = gpr_parse_nonnegative_int(field->value); - if (max_response_message_bytes == -1) return NULL; - } - } - message_size_limits* value = gpr_malloc(sizeof(message_size_limits)); - value->max_send_size = max_request_message_bytes; - value->max_recv_size = max_response_message_bytes; - return value; -} - -typedef struct call_data { - int max_send_size; - int max_recv_size; - // Receive closures are chained: we inject this closure as the - // recv_message_ready up-call on transport_stream_op, and remember to - // call our next_recv_message_ready member after handling it. - grpc_closure recv_message_ready; - // Used by recv_message_ready. - grpc_byte_stream** recv_message; - // Original recv_message_ready callback, invoked after our own. - grpc_closure* next_recv_message_ready; -} call_data; - -typedef struct channel_data { - int max_send_size; - int max_recv_size; - // Maps path names to message_size_limits structs. - grpc_mdstr_hash_table* method_limit_table; -} channel_data; - -// Callback invoked when we receive a message. Here we check the max -// receive message size. -static void recv_message_ready(grpc_exec_ctx* exec_ctx, void* user_data, - grpc_error* error) { - grpc_call_element* elem = user_data; - call_data* calld = elem->call_data; - if (*calld->recv_message != NULL && calld->max_recv_size >= 0 && - (*calld->recv_message)->length > (size_t)calld->max_recv_size) { - char* message_string; - gpr_asprintf(&message_string, - "Received message larger than max (%u vs. %d)", - (*calld->recv_message)->length, calld->max_recv_size); - grpc_error* new_error = grpc_error_set_int( - GRPC_ERROR_CREATE(message_string), GRPC_ERROR_INT_GRPC_STATUS, - GRPC_STATUS_INVALID_ARGUMENT); - if (error == GRPC_ERROR_NONE) { - error = new_error; - } else { - error = grpc_error_add_child(error, new_error); - GRPC_ERROR_UNREF(new_error); - } - gpr_free(message_string); - } - // Invoke the next callback. - grpc_exec_ctx_sched(exec_ctx, calld->next_recv_message_ready, error, NULL); -} - -// Start transport stream op. -static void start_transport_stream_op(grpc_exec_ctx* exec_ctx, - grpc_call_element* elem, - grpc_transport_stream_op* op) { - call_data* calld = elem->call_data; - // Check max send message size. - if (op->send_message != NULL && calld->max_send_size >= 0 && - op->send_message->length > (size_t)calld->max_send_size) { - char* message_string; - gpr_asprintf(&message_string, "Sent message larger than max (%u vs. %d)", - op->send_message->length, calld->max_send_size); - grpc_slice message = grpc_slice_from_copied_string(message_string); - gpr_free(message_string); - grpc_call_element_send_close_with_message( - exec_ctx, elem, GRPC_STATUS_INVALID_ARGUMENT, &message); - } - // Inject callback for receiving a message. - if (op->recv_message_ready != NULL) { - calld->next_recv_message_ready = op->recv_message_ready; - calld->recv_message = op->recv_message; - op->recv_message_ready = &calld->recv_message_ready; - } - // Chain to the next filter. - grpc_call_next_op(exec_ctx, elem, op); -} - -// Constructor for call_data. -static grpc_error* init_call_elem(grpc_exec_ctx* exec_ctx, - grpc_call_element* elem, - grpc_call_element_args* args) { - channel_data* chand = elem->channel_data; - call_data* calld = elem->call_data; - calld->next_recv_message_ready = NULL; - grpc_closure_init(&calld->recv_message_ready, recv_message_ready, elem); - // Get max sizes from channel data, then merge in per-method config values. - // Note: Per-method config is only available on the client, so we - // apply the max request size to the send limit and the max response - // size to the receive limit. - calld->max_send_size = chand->max_send_size; - calld->max_recv_size = chand->max_recv_size; - if (chand->method_limit_table != NULL) { - message_size_limits* limits = - grpc_method_config_table_get(chand->method_limit_table, args->path); - if (limits != NULL) { - if (limits->max_send_size >= 0 && - (limits->max_send_size < calld->max_send_size || - calld->max_send_size < 0)) { - calld->max_send_size = limits->max_send_size; - } - if (limits->max_recv_size >= 0 && - (limits->max_recv_size < calld->max_recv_size || - calld->max_recv_size < 0)) { - calld->max_recv_size = limits->max_recv_size; - } - } - } - return GRPC_ERROR_NONE; -} - -// Destructor for call_data. -static void destroy_call_elem(grpc_exec_ctx* exec_ctx, grpc_call_element* elem, - const grpc_call_final_info* final_info, - void* ignored) {} - -// Constructor for channel_data. -static grpc_error* init_channel_elem(grpc_exec_ctx* exec_ctx, - grpc_channel_element* elem, - grpc_channel_element_args* args) { - GPR_ASSERT(!args->is_last); - channel_data* chand = elem->channel_data; - memset(chand, 0, sizeof(*chand)); - chand->max_send_size = GRPC_DEFAULT_MAX_SEND_MESSAGE_LENGTH; - chand->max_recv_size = GRPC_DEFAULT_MAX_RECV_MESSAGE_LENGTH; - for (size_t i = 0; i < args->channel_args->num_args; ++i) { - if (strcmp(args->channel_args->args[i].key, - GRPC_ARG_MAX_SEND_MESSAGE_LENGTH) == 0) { - const grpc_integer_options options = { - GRPC_DEFAULT_MAX_SEND_MESSAGE_LENGTH, 0, INT_MAX}; - chand->max_send_size = - grpc_channel_arg_get_integer(&args->channel_args->args[i], options); - } - if (strcmp(args->channel_args->args[i].key, - GRPC_ARG_MAX_RECEIVE_MESSAGE_LENGTH) == 0) { - const grpc_integer_options options = { - GRPC_DEFAULT_MAX_RECV_MESSAGE_LENGTH, 0, INT_MAX}; - chand->max_recv_size = - grpc_channel_arg_get_integer(&args->channel_args->args[i], options); - } - } - // Get method config table from channel args. - const grpc_arg* channel_arg = - grpc_channel_args_find(args->channel_args, GRPC_ARG_SERVICE_CONFIG); - if (channel_arg != NULL) { - GPR_ASSERT(channel_arg->type == GRPC_ARG_STRING); - grpc_service_config* service_config = - grpc_service_config_create(channel_arg->value.string); - if (service_config != NULL) { - chand->method_limit_table = - grpc_service_config_create_method_config_table( - service_config, message_size_limits_create_from_json, - &message_size_limits_vtable); - grpc_service_config_destroy(service_config); - } - } - return GRPC_ERROR_NONE; -} - -// Destructor for channel_data. -static void destroy_channel_elem(grpc_exec_ctx* exec_ctx, - grpc_channel_element* elem) { - channel_data* chand = elem->channel_data; - grpc_mdstr_hash_table_unref(chand->method_limit_table); -} - -const grpc_channel_filter grpc_message_size_filter = { - start_transport_stream_op, - grpc_channel_next_op, - sizeof(call_data), - init_call_elem, - grpc_call_stack_ignore_set_pollset_or_pollset_set, - destroy_call_elem, - sizeof(channel_data), - init_channel_elem, - destroy_channel_elem, - grpc_call_next_get_peer, - grpc_channel_next_get_info, - "message_size"}; diff --git a/Sources/CgRPC/src/core/lib/channel/message_size_filter.h b/Sources/CgRPC/src/core/lib/channel/message_size_filter.h deleted file mode 100644 index a88ff7f81..000000000 --- a/Sources/CgRPC/src/core/lib/channel/message_size_filter.h +++ /dev/null @@ -1,39 +0,0 @@ -// -// Copyright 2016, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// - -#ifndef GRPC_CORE_LIB_CHANNEL_MESSAGE_SIZE_FILTER_H -#define GRPC_CORE_LIB_CHANNEL_MESSAGE_SIZE_FILTER_H - -#include "src/core/lib/channel/channel_stack.h" - -extern const grpc_channel_filter grpc_message_size_filter; - -#endif /* GRPC_CORE_LIB_CHANNEL_MESSAGE_SIZE_FILTER_H */ diff --git a/Sources/CgRPC/src/core/lib/compression/algorithm_metadata.h b/Sources/CgRPC/src/core/lib/compression/algorithm_metadata.h index 1f9cc15f2..4717af6e2 100644 --- a/Sources/CgRPC/src/core/lib/compression/algorithm_metadata.h +++ b/Sources/CgRPC/src/core/lib/compression/algorithm_metadata.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -38,16 +23,16 @@ #include "src/core/lib/transport/metadata.h" /** Return compression algorithm based metadata value */ -grpc_mdstr *grpc_compression_algorithm_mdstr( +grpc_slice grpc_compression_algorithm_slice( grpc_compression_algorithm algorithm); /** Return compression algorithm based metadata element (grpc-encoding: xxx) */ -grpc_mdelem *grpc_compression_encoding_mdelem( +grpc_mdelem grpc_compression_encoding_mdelem( grpc_compression_algorithm algorithm); /** Find compression algorithm based on passed in mdstr - returns * GRPC_COMPRESS_ALGORITHM_COUNT on failure */ -grpc_compression_algorithm grpc_compression_algorithm_from_mdstr( - grpc_mdstr *str); +grpc_compression_algorithm grpc_compression_algorithm_from_slice( + grpc_slice str); #endif /* GRPC_CORE_LIB_COMPRESSION_ALGORITHM_METADATA_H */ diff --git a/Sources/CgRPC/src/core/lib/compression/compression.c b/Sources/CgRPC/src/core/lib/compression/compression.c index 54efb5e85..8deae2798 100644 --- a/Sources/CgRPC/src/core/lib/compression/compression.c +++ b/Sources/CgRPC/src/core/lib/compression/compression.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -41,30 +26,24 @@ #include "src/core/lib/surface/api_trace.h" #include "src/core/lib/transport/static_metadata.h" -int grpc_compression_algorithm_parse(const char *name, size_t name_length, +int grpc_compression_algorithm_parse(grpc_slice name, grpc_compression_algorithm *algorithm) { /* we use strncmp not only because it's safer (even though in this case it * doesn't matter, given that we are comparing against string literals, but * because this way we needn't have "name" nil-terminated (useful for slice * data, for example) */ - GRPC_API_TRACE( - "grpc_compression_algorithm_parse(" - "name=%*.*s, name_length=%lu, algorithm=%p)", - 5, ((int)name_length, (int)name_length, name, (unsigned long)name_length, - algorithm)); - if (name_length == 0) { - return 0; - } - if (strncmp(name, "identity", name_length) == 0) { + if (grpc_slice_eq(name, GRPC_MDSTR_IDENTITY)) { *algorithm = GRPC_COMPRESS_NONE; - } else if (strncmp(name, "gzip", name_length) == 0) { + return 1; + } else if (grpc_slice_eq(name, GRPC_MDSTR_GZIP)) { *algorithm = GRPC_COMPRESS_GZIP; - } else if (strncmp(name, "deflate", name_length) == 0) { + return 1; + } else if (grpc_slice_eq(name, GRPC_MDSTR_DEFLATE)) { *algorithm = GRPC_COMPRESS_DEFLATE; + return 1; } else { return 0; } - return 1; } int grpc_compression_algorithm_name(grpc_compression_algorithm algorithm, @@ -87,15 +66,15 @@ int grpc_compression_algorithm_name(grpc_compression_algorithm algorithm, return 0; } -grpc_compression_algorithm grpc_compression_algorithm_from_mdstr( - grpc_mdstr *str) { - if (str == GRPC_MDSTR_IDENTITY) return GRPC_COMPRESS_NONE; - if (str == GRPC_MDSTR_DEFLATE) return GRPC_COMPRESS_DEFLATE; - if (str == GRPC_MDSTR_GZIP) return GRPC_COMPRESS_GZIP; +grpc_compression_algorithm grpc_compression_algorithm_from_slice( + grpc_slice str) { + if (grpc_slice_eq(str, GRPC_MDSTR_IDENTITY)) return GRPC_COMPRESS_NONE; + if (grpc_slice_eq(str, GRPC_MDSTR_DEFLATE)) return GRPC_COMPRESS_DEFLATE; + if (grpc_slice_eq(str, GRPC_MDSTR_GZIP)) return GRPC_COMPRESS_GZIP; return GRPC_COMPRESS_ALGORITHMS_COUNT; } -grpc_mdstr *grpc_compression_algorithm_mdstr( +grpc_slice grpc_compression_algorithm_slice( grpc_compression_algorithm algorithm) { switch (algorithm) { case GRPC_COMPRESS_NONE: @@ -105,12 +84,12 @@ grpc_mdstr *grpc_compression_algorithm_mdstr( case GRPC_COMPRESS_GZIP: return GRPC_MDSTR_GZIP; case GRPC_COMPRESS_ALGORITHMS_COUNT: - return NULL; + return grpc_empty_slice(); } - return NULL; + return grpc_empty_slice(); } -grpc_mdelem *grpc_compression_encoding_mdelem( +grpc_mdelem grpc_compression_encoding_mdelem( grpc_compression_algorithm algorithm) { switch (algorithm) { case GRPC_COMPRESS_NONE: @@ -122,7 +101,7 @@ grpc_mdelem *grpc_compression_encoding_mdelem( default: break; } - return NULL; + return GRPC_MDNULL; } void grpc_compression_options_init(grpc_compression_options *opts) { diff --git a/Sources/CgRPC/src/core/lib/compression/message_compress.c b/Sources/CgRPC/src/core/lib/compression/message_compress.c index 6c245acf6..c051e2886 100644 --- a/Sources/CgRPC/src/core/lib/compression/message_compress.c +++ b/Sources/CgRPC/src/core/lib/compression/message_compress.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -40,15 +25,17 @@ #include +#include "src/core/lib/slice/slice_internal.h" + #define OUTPUT_BLOCK_SIZE 1024 -static int zlib_body(z_stream* zs, grpc_slice_buffer* input, - grpc_slice_buffer* output, +static int zlib_body(grpc_exec_ctx* exec_ctx, z_stream* zs, + grpc_slice_buffer* input, grpc_slice_buffer* output, int (*flate)(z_stream* zs, int flush)) { int r; int flush; size_t i; - grpc_slice outbuf = grpc_slice_malloc(OUTPUT_BLOCK_SIZE); + grpc_slice outbuf = GRPC_SLICE_MALLOC(OUTPUT_BLOCK_SIZE); const uInt uint_max = ~(uInt)0; GPR_ASSERT(GRPC_SLICE_LENGTH(outbuf) <= uint_max); @@ -63,7 +50,7 @@ static int zlib_body(z_stream* zs, grpc_slice_buffer* input, do { if (zs->avail_out == 0) { grpc_slice_buffer_add_indexed(output, outbuf); - outbuf = grpc_slice_malloc(OUTPUT_BLOCK_SIZE); + outbuf = GRPC_SLICE_MALLOC(OUTPUT_BLOCK_SIZE); GPR_ASSERT(GRPC_SLICE_LENGTH(outbuf) <= uint_max); zs->avail_out = (uInt)GRPC_SLICE_LENGTH(outbuf); zs->next_out = GRPC_SLICE_START_PTR(outbuf); @@ -87,7 +74,7 @@ static int zlib_body(z_stream* zs, grpc_slice_buffer* input, return 1; error: - grpc_slice_unref(outbuf); + grpc_slice_unref_internal(exec_ctx, outbuf); return 0; } @@ -97,8 +84,8 @@ static void* zalloc_gpr(void* opaque, unsigned int items, unsigned int size) { static void zfree_gpr(void* opaque, void* address) { gpr_free(address); } -static int zlib_compress(grpc_slice_buffer* input, grpc_slice_buffer* output, - int gzip) { +static int zlib_compress(grpc_exec_ctx* exec_ctx, grpc_slice_buffer* input, + grpc_slice_buffer* output, int gzip) { z_stream zs; int r; size_t i; @@ -110,10 +97,11 @@ static int zlib_compress(grpc_slice_buffer* input, grpc_slice_buffer* output, r = deflateInit2(&zs, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 15 | (gzip ? 16 : 0), 8, Z_DEFAULT_STRATEGY); GPR_ASSERT(r == Z_OK); - r = zlib_body(&zs, input, output, deflate) && output->length < input->length; + r = zlib_body(exec_ctx, &zs, input, output, deflate) && + output->length < input->length; if (!r) { for (i = count_before; i < output->count; i++) { - grpc_slice_unref(output->slices[i]); + grpc_slice_unref_internal(exec_ctx, output->slices[i]); } output->count = count_before; output->length = length_before; @@ -122,8 +110,8 @@ static int zlib_compress(grpc_slice_buffer* input, grpc_slice_buffer* output, return r; } -static int zlib_decompress(grpc_slice_buffer* input, grpc_slice_buffer* output, - int gzip) { +static int zlib_decompress(grpc_exec_ctx* exec_ctx, grpc_slice_buffer* input, + grpc_slice_buffer* output, int gzip) { z_stream zs; int r; size_t i; @@ -134,10 +122,10 @@ static int zlib_decompress(grpc_slice_buffer* input, grpc_slice_buffer* output, zs.zfree = zfree_gpr; r = inflateInit2(&zs, 15 | (gzip ? 16 : 0)); GPR_ASSERT(r == Z_OK); - r = zlib_body(&zs, input, output, inflate); + r = zlib_body(exec_ctx, &zs, input, output, inflate); if (!r) { for (i = count_before; i < output->count; i++) { - grpc_slice_unref(output->slices[i]); + grpc_slice_unref_internal(exec_ctx, output->slices[i]); } output->count = count_before; output->length = length_before; @@ -149,12 +137,13 @@ static int zlib_decompress(grpc_slice_buffer* input, grpc_slice_buffer* output, static int copy(grpc_slice_buffer* input, grpc_slice_buffer* output) { size_t i; for (i = 0; i < input->count; i++) { - grpc_slice_buffer_add(output, grpc_slice_ref(input->slices[i])); + grpc_slice_buffer_add(output, grpc_slice_ref_internal(input->slices[i])); } return 1; } -static int compress_inner(grpc_compression_algorithm algorithm, +static int compress_inner(grpc_exec_ctx* exec_ctx, + grpc_compression_algorithm algorithm, grpc_slice_buffer* input, grpc_slice_buffer* output) { switch (algorithm) { case GRPC_COMPRESS_NONE: @@ -162,9 +151,9 @@ static int compress_inner(grpc_compression_algorithm algorithm, rely on that here */ return 0; case GRPC_COMPRESS_DEFLATE: - return zlib_compress(input, output, 0); + return zlib_compress(exec_ctx, input, output, 0); case GRPC_COMPRESS_GZIP: - return zlib_compress(input, output, 1); + return zlib_compress(exec_ctx, input, output, 1); case GRPC_COMPRESS_ALGORITHMS_COUNT: break; } @@ -172,24 +161,26 @@ static int compress_inner(grpc_compression_algorithm algorithm, return 0; } -int grpc_msg_compress(grpc_compression_algorithm algorithm, +int grpc_msg_compress(grpc_exec_ctx* exec_ctx, + grpc_compression_algorithm algorithm, grpc_slice_buffer* input, grpc_slice_buffer* output) { - if (!compress_inner(algorithm, input, output)) { + if (!compress_inner(exec_ctx, algorithm, input, output)) { copy(input, output); return 0; } return 1; } -int grpc_msg_decompress(grpc_compression_algorithm algorithm, +int grpc_msg_decompress(grpc_exec_ctx* exec_ctx, + grpc_compression_algorithm algorithm, grpc_slice_buffer* input, grpc_slice_buffer* output) { switch (algorithm) { case GRPC_COMPRESS_NONE: return copy(input, output); case GRPC_COMPRESS_DEFLATE: - return zlib_decompress(input, output, 0); + return zlib_decompress(exec_ctx, input, output, 0); case GRPC_COMPRESS_GZIP: - return zlib_decompress(input, output, 1); + return zlib_decompress(exec_ctx, input, output, 1); case GRPC_COMPRESS_ALGORITHMS_COUNT: break; } diff --git a/Sources/CgRPC/src/core/lib/compression/message_compress.h b/Sources/CgRPC/src/core/lib/compression/message_compress.h index 448d36a86..ca8ca37f8 100644 --- a/Sources/CgRPC/src/core/lib/compression/message_compress.h +++ b/Sources/CgRPC/src/core/lib/compression/message_compress.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -40,13 +25,15 @@ /* compress 'input' to 'output' using 'algorithm'. On success, appends compressed slices to output and returns 1. On failure, appends uncompressed slices to output and returns 0. */ -int grpc_msg_compress(grpc_compression_algorithm algorithm, +int grpc_msg_compress(grpc_exec_ctx* exec_ctx, + grpc_compression_algorithm algorithm, grpc_slice_buffer* input, grpc_slice_buffer* output); /* decompress 'input' to 'output' using 'algorithm'. On success, appends slices to output and returns 1. On failure, output is unchanged, and returns 0. */ -int grpc_msg_decompress(grpc_compression_algorithm algorithm, +int grpc_msg_decompress(grpc_exec_ctx* exec_ctx, + grpc_compression_algorithm algorithm, grpc_slice_buffer* input, grpc_slice_buffer* output); #endif /* GRPC_CORE_LIB_COMPRESSION_MESSAGE_COMPRESS_H */ diff --git a/Sources/CgRPC/src/core/lib/compression/stream_compression.c b/Sources/CgRPC/src/core/lib/compression/stream_compression.c new file mode 100644 index 000000000..df13d53e0 --- /dev/null +++ b/Sources/CgRPC/src/core/lib/compression/stream_compression.c @@ -0,0 +1,191 @@ +/* + * + * Copyright 2017 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 +#include + +#include "src/core/lib/compression/stream_compression.h" +#include "src/core/lib/iomgr/exec_ctx.h" +#include "src/core/lib/slice/slice_internal.h" + +#define OUTPUT_BLOCK_SIZE (1024) + +static bool gzip_flate(grpc_stream_compression_context *ctx, + grpc_slice_buffer *in, grpc_slice_buffer *out, + size_t *output_size, size_t max_output_size, int flush, + bool *end_of_context) { + GPR_ASSERT(flush == 0 || flush == Z_SYNC_FLUSH || flush == Z_FINISH); + /* Full flush is not allowed when inflating. */ + GPR_ASSERT(!(ctx->flate == inflate && (flush == Z_FINISH))); + + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + int r; + bool eoc = false; + size_t original_max_output_size = max_output_size; + while (max_output_size > 0 && (in->length > 0 || flush) && !eoc) { + size_t slice_size = max_output_size < OUTPUT_BLOCK_SIZE ? max_output_size + : OUTPUT_BLOCK_SIZE; + grpc_slice slice_out = GRPC_SLICE_MALLOC(slice_size); + ctx->zs.avail_out = (uInt)slice_size; + ctx->zs.next_out = GRPC_SLICE_START_PTR(slice_out); + while (ctx->zs.avail_out > 0 && in->length > 0 && !eoc) { + grpc_slice slice = grpc_slice_buffer_take_first(in); + ctx->zs.avail_in = (uInt)GRPC_SLICE_LENGTH(slice); + ctx->zs.next_in = GRPC_SLICE_START_PTR(slice); + r = ctx->flate(&ctx->zs, Z_NO_FLUSH); + if (r < 0 && r != Z_BUF_ERROR) { + gpr_log(GPR_ERROR, "zlib error (%d)", r); + grpc_slice_unref_internal(&exec_ctx, slice_out); + grpc_exec_ctx_finish(&exec_ctx); + return false; + } else if (r == Z_STREAM_END && ctx->flate == inflate) { + eoc = true; + } + if (ctx->zs.avail_in > 0) { + grpc_slice_buffer_undo_take_first( + in, + grpc_slice_sub(slice, GRPC_SLICE_LENGTH(slice) - ctx->zs.avail_in, + GRPC_SLICE_LENGTH(slice))); + } + grpc_slice_unref_internal(&exec_ctx, slice); + } + if (flush != 0 && ctx->zs.avail_out > 0 && !eoc) { + GPR_ASSERT(in->length == 0); + r = ctx->flate(&ctx->zs, flush); + if (flush == Z_SYNC_FLUSH) { + switch (r) { + case Z_OK: + /* Maybe flush is not complete; just made some partial progress. */ + if (ctx->zs.avail_out > 0) { + flush = 0; + } + break; + case Z_BUF_ERROR: + case Z_STREAM_END: + flush = 0; + break; + default: + gpr_log(GPR_ERROR, "zlib error (%d)", r); + grpc_slice_unref_internal(&exec_ctx, slice_out); + grpc_exec_ctx_finish(&exec_ctx); + return false; + } + } else if (flush == Z_FINISH) { + switch (r) { + case Z_OK: + case Z_BUF_ERROR: + /* Wait for the next loop to assign additional output space. */ + GPR_ASSERT(ctx->zs.avail_out == 0); + break; + case Z_STREAM_END: + flush = 0; + break; + default: + gpr_log(GPR_ERROR, "zlib error (%d)", r); + grpc_slice_unref_internal(&exec_ctx, slice_out); + grpc_exec_ctx_finish(&exec_ctx); + return false; + } + } + } + + if (ctx->zs.avail_out == 0) { + grpc_slice_buffer_add(out, slice_out); + } else if (ctx->zs.avail_out < slice_size) { + slice_out.data.refcounted.length -= ctx->zs.avail_out; + grpc_slice_buffer_add(out, slice_out); + } else { + grpc_slice_unref_internal(&exec_ctx, slice_out); + } + max_output_size -= (slice_size - ctx->zs.avail_out); + } + grpc_exec_ctx_finish(&exec_ctx); + if (end_of_context) { + *end_of_context = eoc; + } + if (output_size) { + *output_size = original_max_output_size - max_output_size; + } + return true; +} + +bool grpc_stream_compress(grpc_stream_compression_context *ctx, + grpc_slice_buffer *in, grpc_slice_buffer *out, + size_t *output_size, size_t max_output_size, + grpc_stream_compression_flush flush) { + GPR_ASSERT(ctx->flate == deflate); + int gzip_flush; + switch (flush) { + case GRPC_STREAM_COMPRESSION_FLUSH_NONE: + gzip_flush = 0; + break; + case GRPC_STREAM_COMPRESSION_FLUSH_SYNC: + gzip_flush = Z_SYNC_FLUSH; + break; + case GRPC_STREAM_COMPRESSION_FLUSH_FINISH: + gzip_flush = Z_FINISH; + break; + default: + gzip_flush = 0; + } + return gzip_flate(ctx, in, out, output_size, max_output_size, gzip_flush, + NULL); +} + +bool grpc_stream_decompress(grpc_stream_compression_context *ctx, + grpc_slice_buffer *in, grpc_slice_buffer *out, + size_t *output_size, size_t max_output_size, + bool *end_of_context) { + GPR_ASSERT(ctx->flate == inflate); + return gzip_flate(ctx, in, out, output_size, max_output_size, Z_SYNC_FLUSH, + end_of_context); +} + +grpc_stream_compression_context *grpc_stream_compression_context_create( + grpc_stream_compression_method method) { + grpc_stream_compression_context *ctx = + gpr_zalloc(sizeof(grpc_stream_compression_context)); + int r; + if (ctx == NULL) { + return NULL; + } + if (method == GRPC_STREAM_COMPRESSION_DECOMPRESS) { + r = inflateInit2(&ctx->zs, 0x1F); + ctx->flate = inflate; + } else { + r = deflateInit2(&ctx->zs, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 0x1F, 8, + Z_DEFAULT_STRATEGY); + ctx->flate = deflate; + } + if (r != Z_OK) { + gpr_free(ctx); + return NULL; + } + + return ctx; +} + +void grpc_stream_compression_context_destroy( + grpc_stream_compression_context *ctx) { + if (ctx->flate == inflate) { + inflateEnd(&ctx->zs); + } else { + deflateEnd(&ctx->zs); + } + gpr_free(ctx); +} diff --git a/Sources/CgRPC/src/core/lib/compression/stream_compression.h b/Sources/CgRPC/src/core/lib/compression/stream_compression.h new file mode 100644 index 000000000..844dff81a --- /dev/null +++ b/Sources/CgRPC/src/core/lib/compression/stream_compression.h @@ -0,0 +1,90 @@ +/* + * + * Copyright 2017 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 GRPC_CORE_LIB_COMPRESSION_STREAM_COMPRESSION_H +#define GRPC_CORE_LIB_COMPRESSION_STREAM_COMPRESSION_H + +#include + +#include +#include + +/* Stream compression/decompression context */ +typedef struct grpc_stream_compression_context { + z_stream zs; + int (*flate)(z_stream *zs, int flush); +} grpc_stream_compression_context; + +typedef enum grpc_stream_compression_method { + GRPC_STREAM_COMPRESSION_COMPRESS = 0, + GRPC_STREAM_COMPRESSION_DECOMPRESS, + GRPC_STREAM_COMPRESSION_METHOD_COUNT +} grpc_stream_compression_method; + +typedef enum grpc_stream_compression_flush { + GRPC_STREAM_COMPRESSION_FLUSH_NONE = 0, + GRPC_STREAM_COMPRESSION_FLUSH_SYNC, + GRPC_STREAM_COMPRESSION_FLUSH_FINISH, + GRPC_STREAM_COMPRESSION_FLUSH_COUNT +} grpc_stream_compression_flush; + +/** + * Compress bytes provided in \a in with a given context, with an optional flush + * at the end of compression. Emits at most \a max_output_size compressed bytes + * into \a out. If all the bytes in input buffer \a in are depleted and \a flush + * is not GRPC_STREAM_COMPRESSION_FLUSH_NONE, the corresponding flush method is + * executed. The total number of bytes emitted is outputed in \a output_size. + * + * A SYNC flush indicates that the entire messages in \a in can be decompressed + * from \a out. A FINISH flush implies a SYNC flush, and that any further + * compression will not be dependent on the state of the current context and any + * previous compressed bytes. It allows corresponding decompression context to + * be dropped when reaching this boundary. + */ +bool grpc_stream_compress(grpc_stream_compression_context *ctx, + grpc_slice_buffer *in, grpc_slice_buffer *out, + size_t *output_size, size_t max_output_size, + grpc_stream_compression_flush flush); + +/** + * Decompress bytes provided in \a in with a given context. Emits at most \a + * max_output_size decompressed bytes into \a out. If decompression process + * reached the end of a gzip stream, \a end_of_context is set to true; otherwise + * it is set to false. The total number of bytes emitted is outputed in \a + * output_size. + */ +bool grpc_stream_decompress(grpc_stream_compression_context *ctx, + grpc_slice_buffer *in, grpc_slice_buffer *out, + size_t *output_size, size_t max_output_size, + bool *end_of_context); + +/** + * Creates a stream compression context. \a pending_bytes_buffer is the input + * buffer for compression/decompression operations. \a method specifies whether + * the context is for compression or decompression. + */ +grpc_stream_compression_context *grpc_stream_compression_context_create( + grpc_stream_compression_method method); + +/** + * Destroys a stream compression context. + */ +void grpc_stream_compression_context_destroy( + grpc_stream_compression_context *ctx); + +#endif diff --git a/Sources/CgRPC/src/core/lib/debug/trace.c b/Sources/CgRPC/src/core/lib/debug/trace.c index c56046785..c6c1853e2 100644 --- a/Sources/CgRPC/src/core/lib/debug/trace.c +++ b/Sources/CgRPC/src/core/lib/debug/trace.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -35,24 +20,29 @@ #include -#include #include #include #include "src/core/lib/support/env.h" +int grpc_tracer_set_enabled(const char *name, int enabled); + typedef struct tracer { - const char *name; - int *flag; + grpc_tracer_flag *flag; struct tracer *next; } tracer; static tracer *tracers; -void grpc_register_tracer(const char *name, int *flag) { +#ifdef GRPC_THREADSAFE_TRACER +#define TRACER_SET(flag, on) gpr_atm_no_barrier_store(&(flag).value, (on)) +#else +#define TRACER_SET(flag, on) (flag).value = (on) +#endif + +void grpc_register_tracer(grpc_tracer_flag *flag) { tracer *t = gpr_malloc(sizeof(*t)); - t->name = name; t->flag = flag; t->next = tracers; - *flag = 0; + TRACER_SET(*flag, false); tracers = t; } @@ -101,6 +91,14 @@ static void parse(const char *s) { gpr_free(strings); } +static void list_tracers() { + gpr_log(GPR_DEBUG, "available tracers:"); + tracer *t; + for (t = tracers; t; t = t->next) { + gpr_log(GPR_DEBUG, "\t%s", t->flag->name); + } +} + void grpc_tracer_init(const char *env_var) { char *e = gpr_getenv(env_var); if (e != NULL) { @@ -121,13 +119,21 @@ int grpc_tracer_set_enabled(const char *name, int enabled) { tracer *t; if (0 == strcmp(name, "all")) { for (t = tracers; t; t = t->next) { - *t->flag = enabled; + TRACER_SET(*t->flag, enabled); + } + } else if (0 == strcmp(name, "list_tracers")) { + list_tracers(); + } else if (0 == strcmp(name, "refcount")) { + for (t = tracers; t; t = t->next) { + if (strstr(t->flag->name, "refcount") != NULL) { + TRACER_SET(*t->flag, enabled); + } } } else { int found = 0; for (t = tracers; t; t = t->next) { - if (0 == strcmp(name, t->name)) { - *t->flag = enabled; + if (0 == strcmp(name, t->flag->name)) { + TRACER_SET(*t->flag, enabled); found = 1; } } diff --git a/Sources/CgRPC/src/core/lib/debug/trace.h b/Sources/CgRPC/src/core/lib/debug/trace.h index 7afc38db7..dd9e6a30f 100644 --- a/Sources/CgRPC/src/core/lib/debug/trace.h +++ b/Sources/CgRPC/src/core/lib/debug/trace.h @@ -1,42 +1,54 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 GRPC_CORE_LIB_DEBUG_TRACE_H #define GRPC_CORE_LIB_DEBUG_TRACE_H +#include #include +#include -void grpc_register_tracer(const char *name, int *flag); +#if defined(__has_feature) +#if __has_feature(thread_sanitizer) +#define GRPC_THREADSAFE_TRACER +#endif +#endif + +typedef struct { +#ifdef GRPC_THREADSAFE_TRACER + gpr_atm value; +#else + bool value; +#endif + char *name; +} grpc_tracer_flag; + +#ifdef GRPC_THREADSAFE_TRACER +#define GRPC_TRACER_ON(flag) (gpr_atm_no_barrier_load(&(flag).value) != 0) +#define GRPC_TRACER_INITIALIZER(on, name) \ + { (gpr_atm)(on), (name) } +#else +#define GRPC_TRACER_ON(flag) ((flag).value) +#define GRPC_TRACER_INITIALIZER(on, name) \ + { (on), (name) } +#endif + +void grpc_register_tracer(grpc_tracer_flag *flag); void grpc_tracer_init(const char *env_var_name); void grpc_tracer_shutdown(void); diff --git a/Sources/CgRPC/src/core/lib/http/format_request.c b/Sources/CgRPC/src/core/lib/http/format_request.c index 024664b6e..f887726ee 100644 --- a/Sources/CgRPC/src/core/lib/http/format_request.c +++ b/Sources/CgRPC/src/core/lib/http/format_request.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/http/format_request.h b/Sources/CgRPC/src/core/lib/http/format_request.h index 1c8e3f68c..12b42e42f 100644 --- a/Sources/CgRPC/src/core/lib/http/format_request.h +++ b/Sources/CgRPC/src/core/lib/http/format_request.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/http/httpcli.c b/Sources/CgRPC/src/core/lib/http/httpcli.c index 1035f3110..77af7b7c0 100644 --- a/Sources/CgRPC/src/core/lib/http/httpcli.c +++ b/Sources/CgRPC/src/core/lib/http/httpcli.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -40,6 +25,7 @@ #include #include +#include "src/core/lib/channel/channel_args.h" #include "src/core/lib/http/format_request.h" #include "src/core/lib/http/parser.h" #include "src/core/lib/iomgr/endpoint.h" @@ -47,6 +33,7 @@ #include "src/core/lib/iomgr/resolve_address.h" #include "src/core/lib/iomgr/sockaddr_utils.h" #include "src/core/lib/iomgr/tcp_client.h" +#include "src/core/lib/slice/slice_internal.h" #include "src/core/lib/support/string.h" typedef struct { @@ -92,8 +79,9 @@ void grpc_httpcli_context_init(grpc_httpcli_context *context) { context->pollset_set = grpc_pollset_set_create(); } -void grpc_httpcli_context_destroy(grpc_httpcli_context *context) { - grpc_pollset_set_destroy(context->pollset_set); +void grpc_httpcli_context_destroy(grpc_exec_ctx *exec_ctx, + grpc_httpcli_context *context) { + grpc_pollset_set_destroy(exec_ctx, context->pollset_set); } static void next_address(grpc_exec_ctx *exec_ctx, internal_request *req, @@ -103,7 +91,7 @@ static void finish(grpc_exec_ctx *exec_ctx, internal_request *req, grpc_error *error) { grpc_polling_entity_del_from_pollset_set(exec_ctx, req->pollent, req->context->pollset_set); - grpc_exec_ctx_sched(exec_ctx, req->on_done, error, NULL); + GRPC_CLOSURE_SCHED(exec_ctx, req->on_done, error); grpc_http_parser_destroy(&req->parser); if (req->addresses != NULL) { grpc_resolved_addresses_destroy(req->addresses); @@ -111,26 +99,28 @@ static void finish(grpc_exec_ctx *exec_ctx, internal_request *req, if (req->ep != NULL) { grpc_endpoint_destroy(exec_ctx, req->ep); } - grpc_slice_unref(req->request_text); + grpc_slice_unref_internal(exec_ctx, req->request_text); gpr_free(req->host); gpr_free(req->ssl_host_override); grpc_iomgr_unregister_object(&req->iomgr_obj); - grpc_slice_buffer_destroy(&req->incoming); - grpc_slice_buffer_destroy(&req->outgoing); + grpc_slice_buffer_destroy_internal(exec_ctx, &req->incoming); + grpc_slice_buffer_destroy_internal(exec_ctx, &req->outgoing); GRPC_ERROR_UNREF(req->overall_error); - grpc_resource_quota_internal_unref(exec_ctx, req->resource_quota); + grpc_resource_quota_unref_internal(exec_ctx, req->resource_quota); gpr_free(req); } static void append_error(internal_request *req, grpc_error *error) { if (req->overall_error == GRPC_ERROR_NONE) { - req->overall_error = GRPC_ERROR_CREATE("Failed HTTP/1 client request"); + req->overall_error = + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Failed HTTP/1 client request"); } grpc_resolved_address *addr = &req->addresses->addrs[req->next_address - 1]; char *addr_text = grpc_sockaddr_to_uri(addr); req->overall_error = grpc_error_add_child( req->overall_error, - grpc_error_set_str(error, GRPC_ERROR_STR_TARGET_ADDRESS, addr_text)); + grpc_error_set_str(error, GRPC_ERROR_STR_TARGET_ADDRESS, + grpc_slice_from_copied_string(addr_text))); gpr_free(addr_text); } @@ -178,7 +168,7 @@ static void done_write(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { } static void start_write(grpc_exec_ctx *exec_ctx, internal_request *req) { - grpc_slice_ref(req->request_text); + grpc_slice_ref_internal(req->request_text); grpc_slice_buffer_add(&req->outgoing, req->request_text); grpc_endpoint_write(exec_ctx, req->ep, &req->outgoing, &req->done_write); } @@ -188,8 +178,8 @@ static void on_handshake_done(grpc_exec_ctx *exec_ctx, void *arg, internal_request *req = arg; if (!ep) { - next_address(exec_ctx, req, - GRPC_ERROR_CREATE("Unexplained handshake failure")); + next_address(exec_ctx, req, GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "Unexplained handshake failure")); return; } @@ -219,17 +209,16 @@ static void next_address(grpc_exec_ctx *exec_ctx, internal_request *req, } if (req->next_address == req->addresses->naddrs) { finish(exec_ctx, req, - GRPC_ERROR_CREATE_REFERENCING("Failed HTTP requests to all targets", - &req->overall_error, 1)); + GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( + "Failed HTTP requests to all targets", &req->overall_error, 1)); return; } addr = &req->addresses->addrs[req->next_address++]; - grpc_closure_init(&req->connected, on_connected, req); - grpc_arg arg; - arg.key = GRPC_ARG_RESOURCE_QUOTA; - arg.type = GRPC_ARG_POINTER; - arg.value.pointer.p = req->resource_quota; - arg.value.pointer.vtable = grpc_resource_quota_arg_vtable(); + GRPC_CLOSURE_INIT(&req->connected, on_connected, req, + grpc_schedule_on_exec_ctx); + grpc_arg arg = grpc_channel_arg_pointer_create( + GRPC_ARG_RESOURCE_QUOTA, req->resource_quota, + grpc_resource_quota_arg_vtable()); grpc_channel_args args = {1, &arg}; grpc_tcp_client_connect(exec_ctx, &req->connected, &req->ep, req->context->pollset_set, &args, addr, @@ -239,7 +228,7 @@ static void next_address(grpc_exec_ctx *exec_ctx, internal_request *req, static void on_resolved(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { internal_request *req = arg; if (error != GRPC_ERROR_NONE) { - finish(exec_ctx, req, error); + finish(exec_ctx, req, GRPC_ERROR_REF(error)); return; } req->next_address = 0; @@ -265,9 +254,10 @@ static void internal_request_begin(grpc_exec_ctx *exec_ctx, req->context = context; req->pollent = pollent; req->overall_error = GRPC_ERROR_NONE; - req->resource_quota = grpc_resource_quota_internal_ref(resource_quota); - grpc_closure_init(&req->on_read, on_read, req); - grpc_closure_init(&req->done_write, done_write, req); + req->resource_quota = grpc_resource_quota_ref_internal(resource_quota); + GRPC_CLOSURE_INIT(&req->on_read, on_read, req, grpc_schedule_on_exec_ctx); + GRPC_CLOSURE_INIT(&req->done_write, done_write, req, + grpc_schedule_on_exec_ctx); grpc_slice_buffer_init(&req->incoming); grpc_slice_buffer_init(&req->outgoing); grpc_iomgr_register_object(&req->iomgr_obj, name); @@ -277,9 +267,11 @@ static void internal_request_begin(grpc_exec_ctx *exec_ctx, GPR_ASSERT(pollent); grpc_polling_entity_add_to_pollset_set(exec_ctx, req->pollent, req->context->pollset_set); - grpc_resolve_address(exec_ctx, request->host, req->handshaker->default_port, - req->context->pollset_set, - grpc_closure_create(on_resolved, req), &req->addresses); + grpc_resolve_address( + exec_ctx, request->host, req->handshaker->default_port, + req->context->pollset_set, + GRPC_CLOSURE_CREATE(on_resolved, req, grpc_schedule_on_exec_ctx), + &req->addresses); } void grpc_httpcli_get(grpc_exec_ctx *exec_ctx, grpc_httpcli_context *context, diff --git a/Sources/CgRPC/src/core/lib/http/httpcli.h b/Sources/CgRPC/src/core/lib/http/httpcli.h index 11e03b44d..809618695 100644 --- a/Sources/CgRPC/src/core/lib/http/httpcli.h +++ b/Sources/CgRPC/src/core/lib/http/httpcli.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -83,7 +68,8 @@ typedef struct grpc_httpcli_request { typedef struct grpc_http_response grpc_httpcli_response; void grpc_httpcli_context_init(grpc_httpcli_context *context); -void grpc_httpcli_context_destroy(grpc_httpcli_context *context); +void grpc_httpcli_context_destroy(grpc_exec_ctx *exec_ctx, + grpc_httpcli_context *context); /* Asynchronously perform a HTTP GET. 'context' specifies the http context under which to do the get diff --git a/Sources/CgRPC/src/core/lib/http/httpcli_security_connector.c b/Sources/CgRPC/src/core/lib/http/httpcli_security_connector.c index 14cdb1dab..97c288652 100644 --- a/Sources/CgRPC/src/core/lib/http/httpcli_security_connector.c +++ b/Sources/CgRPC/src/core/lib/http/httpcli_security_connector.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -40,21 +25,25 @@ #include #include "src/core/lib/channel/channel_args.h" +#include "src/core/lib/channel/handshaker_registry.h" #include "src/core/lib/security/transport/security_handshaker.h" +#include "src/core/lib/slice/slice_internal.h" #include "src/core/lib/support/string.h" -#include "src/core/lib/tsi/ssl_transport_security.h" +#include "src/core/tsi/ssl_transport_security.h" +#include "src/core/tsi/transport_security_adapter.h" typedef struct { grpc_channel_security_connector base; - tsi_ssl_handshaker_factory *handshaker_factory; + 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) { +static void httpcli_ssl_destroy(grpc_exec_ctx *exec_ctx, + grpc_security_connector *sc) { grpc_httpcli_ssl_channel_security_connector *c = (grpc_httpcli_ssl_channel_security_connector *)sc; if (c->handshaker_factory != NULL) { - tsi_ssl_handshaker_factory_destroy(c->handshaker_factory); + tsi_ssl_client_handshaker_factory_destroy(c->handshaker_factory); } if (c->secure_peer_name != NULL) gpr_free(c->secure_peer_name); gpr_free(sc); @@ -67,7 +56,7 @@ static void httpcli_ssl_add_handshakers(grpc_exec_ctx *exec_ctx, (grpc_httpcli_ssl_channel_security_connector *)sc; tsi_handshaker *handshaker = NULL; if (c->handshaker_factory != NULL) { - tsi_result result = tsi_ssl_handshaker_factory_create_handshaker( + 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.", @@ -76,7 +65,8 @@ static void httpcli_ssl_add_handshakers(grpc_exec_ctx *exec_ctx, } grpc_handshake_manager_add( handshake_mgr, - grpc_security_handshaker_create(exec_ctx, handshaker, &sc->base)); + grpc_security_handshaker_create( + exec_ctx, tsi_create_adapter_handshaker(handshaker), &sc->base)); } static void httpcli_ssl_check_peer(grpc_exec_ctx *exec_ctx, @@ -93,10 +83,10 @@ static void httpcli_ssl_check_peer(grpc_exec_ctx *exec_ctx, char *msg; gpr_asprintf(&msg, "Peer name %s is not in peer certificate", c->secure_peer_name); - error = GRPC_ERROR_CREATE(msg); + error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg); gpr_free(msg); } - grpc_exec_ctx_sched(exec_ctx, on_peer_checked, error, NULL); + GRPC_CLOSURE_SCHED(exec_ctx, on_peer_checked, error); tsi_peer_destruct(&peer); } @@ -104,7 +94,7 @@ static grpc_security_connector_vtable httpcli_ssl_vtable = { httpcli_ssl_destroy, httpcli_ssl_check_peer}; static grpc_security_status httpcli_ssl_channel_security_connector_create( - const unsigned char *pem_root_certs, size_t pem_root_certs_size, + grpc_exec_ctx *exec_ctx, const char *pem_root_certs, const char *secure_peer_name, grpc_channel_security_connector **sc) { tsi_result result = TSI_OK; grpc_httpcli_ssl_channel_security_connector *c; @@ -115,8 +105,7 @@ static grpc_security_status httpcli_ssl_channel_security_connector_create( return GRPC_SECURITY_ERROR; } - c = gpr_malloc(sizeof(grpc_httpcli_ssl_channel_security_connector)); - memset(c, 0, sizeof(grpc_httpcli_ssl_channel_security_connector)); + c = gpr_zalloc(sizeof(grpc_httpcli_ssl_channel_security_connector)); gpr_ref_init(&c->base.base.refcount, 1); c->base.base.vtable = &httpcli_ssl_vtable; @@ -124,12 +113,11 @@ static grpc_security_status httpcli_ssl_channel_security_connector_create( c->secure_peer_name = gpr_strdup(secure_peer_name); } result = tsi_create_ssl_client_handshaker_factory( - NULL, 0, NULL, 0, pem_root_certs, pem_root_certs_size, NULL, NULL, NULL, - 0, &c->handshaker_factory); + NULL, pem_root_certs, NULL, NULL, 0, &c->handshaker_factory); 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); + httpcli_ssl_destroy(exec_ctx, &c->base.base); *sc = NULL; return GRPC_SECURITY_ERROR; } @@ -153,11 +141,11 @@ static void on_handshake_done(grpc_exec_ctx *exec_ctx, void *arg, if (error != GRPC_ERROR_NONE) { const char *msg = grpc_error_string(error); gpr_log(GPR_ERROR, "Secure transport setup failed: %s", msg); - grpc_error_free_string(msg); + c->func(exec_ctx, c->arg, NULL); } else { - grpc_channel_args_destroy(args->args); - grpc_slice_buffer_destroy(args->read_buffer); + grpc_channel_args_destroy(exec_ctx, args->args); + grpc_slice_buffer_destroy_internal(exec_ctx, args->read_buffer); gpr_free(args->read_buffer); c->func(exec_ctx, c->arg, args->endpoint); } @@ -170,11 +158,9 @@ static void ssl_handshake(grpc_exec_ctx *exec_ctx, void *arg, gpr_timespec deadline, void (*on_done)(grpc_exec_ctx *exec_ctx, void *arg, grpc_endpoint *endpoint)) { - grpc_channel_security_connector *sc = NULL; - const unsigned char *pem_root_certs = NULL; on_done_closure *c = gpr_malloc(sizeof(*c)); - size_t pem_root_certs_size = grpc_get_default_ssl_roots(&pem_root_certs); - if (pem_root_certs == NULL || pem_root_certs_size == 0) { + const char *pem_root_certs = grpc_get_default_ssl_roots(); + if (pem_root_certs == NULL) { gpr_log(GPR_ERROR, "Could not get default pem root certs."); on_done(exec_ctx, arg, NULL); gpr_free(c); @@ -182,16 +168,17 @@ static void ssl_handshake(grpc_exec_ctx *exec_ctx, void *arg, } c->func = on_done; c->arg = arg; - c->handshake_mgr = grpc_handshake_manager_create(); + grpc_channel_security_connector *sc = NULL; GPR_ASSERT(httpcli_ssl_channel_security_connector_create( - pem_root_certs, pem_root_certs_size, host, &sc) == - GRPC_SECURITY_OK); - grpc_channel_security_connector_add_handshakers(exec_ctx, sc, - c->handshake_mgr); + exec_ctx, pem_root_certs, host, &sc) == GRPC_SECURITY_OK); + grpc_arg channel_arg = grpc_security_connector_to_arg(&sc->base); + grpc_channel_args args = {1, &channel_arg}; + c->handshake_mgr = grpc_handshake_manager_create(); + grpc_handshakers_add(exec_ctx, HANDSHAKER_CLIENT, &args, c->handshake_mgr); grpc_handshake_manager_do_handshake( exec_ctx, c->handshake_mgr, tcp, NULL /* channel_args */, deadline, NULL /* acceptor */, on_handshake_done, c /* user_data */); - GRPC_SECURITY_CONNECTOR_UNREF(&sc->base, "httpcli"); + GRPC_SECURITY_CONNECTOR_UNREF(exec_ctx, &sc->base, "httpcli"); } const grpc_httpcli_handshaker grpc_httpcli_ssl = {"https", ssl_handshake}; diff --git a/Sources/CgRPC/src/core/lib/http/parser.c b/Sources/CgRPC/src/core/lib/http/parser.c index 2f84adc18..9c5e93f4e 100644 --- a/Sources/CgRPC/src/core/lib/http/parser.c +++ b/Sources/CgRPC/src/core/lib/http/parser.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -40,7 +25,7 @@ #include #include -int grpc_http1_trace = 0; +grpc_tracer_flag grpc_http1_trace = GRPC_TRACER_INITIALIZER(false, "http1"); static char *buf2str(void *buffer, size_t length) { char *out = gpr_malloc(length + 1); @@ -54,26 +39,36 @@ static grpc_error *handle_response_line(grpc_http_parser *parser) { uint8_t *cur = beg; uint8_t *end = beg + parser->cur_line_length; - if (cur == end || *cur++ != 'H') return GRPC_ERROR_CREATE("Expected 'H'"); - if (cur == end || *cur++ != 'T') return GRPC_ERROR_CREATE("Expected 'T'"); - if (cur == end || *cur++ != 'T') return GRPC_ERROR_CREATE("Expected 'T'"); - if (cur == end || *cur++ != 'P') return GRPC_ERROR_CREATE("Expected 'P'"); - if (cur == end || *cur++ != '/') return GRPC_ERROR_CREATE("Expected '/'"); - if (cur == end || *cur++ != '1') return GRPC_ERROR_CREATE("Expected '1'"); - if (cur == end || *cur++ != '.') return GRPC_ERROR_CREATE("Expected '.'"); + if (cur == end || *cur++ != 'H') + return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected 'H'"); + if (cur == end || *cur++ != 'T') + return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected 'T'"); + if (cur == end || *cur++ != 'T') + return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected 'T'"); + if (cur == end || *cur++ != 'P') + return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected 'P'"); + if (cur == end || *cur++ != '/') + return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected '/'"); + if (cur == end || *cur++ != '1') + return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected '1'"); + if (cur == end || *cur++ != '.') + return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected '.'"); if (cur == end || *cur < '0' || *cur++ > '1') { - return GRPC_ERROR_CREATE("Expected HTTP/1.0 or HTTP/1.1"); + return GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "Expected HTTP/1.0 or HTTP/1.1"); } - if (cur == end || *cur++ != ' ') return GRPC_ERROR_CREATE("Expected ' '"); + if (cur == end || *cur++ != ' ') + return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected ' '"); if (cur == end || *cur < '1' || *cur++ > '9') - return GRPC_ERROR_CREATE("Expected status code"); + return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected status code"); if (cur == end || *cur < '0' || *cur++ > '9') - return GRPC_ERROR_CREATE("Expected status code"); + return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected status code"); if (cur == end || *cur < '0' || *cur++ > '9') - return GRPC_ERROR_CREATE("Expected status code"); + return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected status code"); parser->http.response->status = (cur[-3] - '0') * 100 + (cur[-2] - '0') * 10 + (cur[-1] - '0'); - if (cur == end || *cur++ != ' ') return GRPC_ERROR_CREATE("Expected ' '"); + if (cur == end || *cur++ != ' ') + return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected ' '"); /* we don't really care about the status code message */ @@ -89,24 +84,33 @@ static grpc_error *handle_request_line(grpc_http_parser *parser) { while (cur != end && *cur++ != ' ') ; - if (cur == end) return GRPC_ERROR_CREATE("No method on HTTP request line"); + if (cur == end) + return GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "No method on HTTP request line"); parser->http.request->method = buf2str(beg, (size_t)(cur - beg - 1)); beg = cur; while (cur != end && *cur++ != ' ') ; - if (cur == end) return GRPC_ERROR_CREATE("No path on HTTP request line"); + if (cur == end) + return GRPC_ERROR_CREATE_FROM_STATIC_STRING("No path on HTTP request line"); parser->http.request->path = buf2str(beg, (size_t)(cur - beg - 1)); - if (cur == end || *cur++ != 'H') return GRPC_ERROR_CREATE("Expected 'H'"); - if (cur == end || *cur++ != 'T') return GRPC_ERROR_CREATE("Expected 'T'"); - if (cur == end || *cur++ != 'T') return GRPC_ERROR_CREATE("Expected 'T'"); - if (cur == end || *cur++ != 'P') return GRPC_ERROR_CREATE("Expected 'P'"); - if (cur == end || *cur++ != '/') return GRPC_ERROR_CREATE("Expected '/'"); + if (cur == end || *cur++ != 'H') + return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected 'H'"); + if (cur == end || *cur++ != 'T') + return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected 'T'"); + if (cur == end || *cur++ != 'T') + return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected 'T'"); + if (cur == end || *cur++ != 'P') + return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected 'P'"); + if (cur == end || *cur++ != '/') + return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected '/'"); vers_major = (uint8_t)(*cur++ - '1' + 1); ++cur; if (cur == end) - return GRPC_ERROR_CREATE("End of line in HTTP version string"); + return GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "End of line in HTTP version string"); vers_minor = (uint8_t)(*cur++ - '1' + 1); if (vers_major == 1) { @@ -115,18 +119,19 @@ static grpc_error *handle_request_line(grpc_http_parser *parser) { } else if (vers_minor == 1) { parser->http.request->version = GRPC_HTTP_HTTP11; } else { - return GRPC_ERROR_CREATE( + return GRPC_ERROR_CREATE_FROM_STATIC_STRING( "Expected one of HTTP/1.0, HTTP/1.1, or HTTP/2.0"); } } else if (vers_major == 2) { if (vers_minor == 0) { parser->http.request->version = GRPC_HTTP_HTTP20; } else { - return GRPC_ERROR_CREATE( + return GRPC_ERROR_CREATE_FROM_STATIC_STRING( "Expected one of HTTP/1.0, HTTP/1.1, or HTTP/2.0"); } } else { - return GRPC_ERROR_CREATE("Expected one of HTTP/1.0, HTTP/1.1, or HTTP/2.0"); + return GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "Expected one of HTTP/1.0, HTTP/1.1, or HTTP/2.0"); } return GRPC_ERROR_NONE; @@ -139,7 +144,8 @@ static grpc_error *handle_first_line(grpc_http_parser *parser) { case GRPC_HTTP_RESPONSE: return handle_response_line(parser); } - GPR_UNREACHABLE_CODE(return GRPC_ERROR_CREATE("Should never reach here")); + GPR_UNREACHABLE_CODE( + return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Should never reach here")); } static grpc_error *add_header(grpc_http_parser *parser) { @@ -154,7 +160,8 @@ static grpc_error *add_header(grpc_http_parser *parser) { GPR_ASSERT(cur != end); if (*cur == ' ' || *cur == '\t') { - error = GRPC_ERROR_CREATE("Continued header lines not supported yet"); + error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "Continued header lines not supported yet"); goto done; } @@ -162,7 +169,8 @@ static grpc_error *add_header(grpc_http_parser *parser) { cur++; } if (cur == end) { - error = GRPC_ERROR_CREATE("Didn't find ':' in header string"); + error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "Didn't find ':' in header string"); goto done; } GPR_ASSERT(cur >= beg); @@ -222,7 +230,8 @@ static grpc_error *finish_line(grpc_http_parser *parser, } break; case GRPC_HTTP_BODY: - GPR_UNREACHABLE_CODE(return GRPC_ERROR_CREATE("Should never reach here")); + GPR_UNREACHABLE_CODE(return GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "Should never reach here")); } parser->cur_line_length = 0; @@ -240,7 +249,8 @@ static grpc_error *addbyte_body(grpc_http_parser *parser, uint8_t byte) { body_length = &parser->http.request->body_length; body = &parser->http.request->body; } else { - GPR_UNREACHABLE_CODE(return GRPC_ERROR_CREATE("Should never reach here")); + GPR_UNREACHABLE_CODE( + return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Should never reach here")); } if (*body_length == parser->body_capacity) { @@ -283,10 +293,11 @@ static grpc_error *addbyte(grpc_http_parser *parser, uint8_t byte, case GRPC_HTTP_FIRST_LINE: case GRPC_HTTP_HEADERS: if (parser->cur_line_length >= GRPC_HTTP_PARSER_MAX_HEADER_LENGTH) { - if (grpc_http1_trace) - gpr_log(GPR_ERROR, "HTTP client max line length (%d) exceeded", + if (GRPC_TRACER_ON(grpc_http1_trace)) + gpr_log(GPR_ERROR, "HTTP header max line length (%d) exceeded", GRPC_HTTP_PARSER_MAX_HEADER_LENGTH); - return GRPC_ERROR_NONE; + return GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "HTTP header max line length exceeded"); } parser->cur_line[parser->cur_line_length] = byte; parser->cur_line_length++; @@ -347,7 +358,7 @@ grpc_error *grpc_http_parser_parse(grpc_http_parser *parser, grpc_slice slice, grpc_error *grpc_http_parser_eof(grpc_http_parser *parser) { if (parser->state != GRPC_HTTP_BODY) { - return GRPC_ERROR_CREATE("Did not finish headers"); + return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Did not finish headers"); } return GRPC_ERROR_NONE; } diff --git a/Sources/CgRPC/src/core/lib/http/parser.h b/Sources/CgRPC/src/core/lib/http/parser.h index a68011dd4..c8dced390 100644 --- a/Sources/CgRPC/src/core/lib/http/parser.h +++ b/Sources/CgRPC/src/core/lib/http/parser.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -36,6 +21,7 @@ #include #include +#include "src/core/lib/debug/trace.h" #include "src/core/lib/iomgr/error.h" /* Maximum length of a header string of the form 'Key: Value\r\n' */ @@ -121,6 +107,6 @@ grpc_error *grpc_http_parser_eof(grpc_http_parser *parser); void grpc_http_request_destroy(grpc_http_request *request); void grpc_http_response_destroy(grpc_http_response *response); -extern int grpc_http1_trace; +extern grpc_tracer_flag grpc_http1_trace; #endif /* GRPC_CORE_LIB_HTTP_PARSER_H */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/closure.c b/Sources/CgRPC/src/core/lib/iomgr/closure.c index c6ddc7673..26f9cbe0f 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/closure.c +++ b/Sources/CgRPC/src/core/lib/iomgr/closure.c @@ -1,66 +1,77 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 "src/core/lib/iomgr/closure.h" +#include #include +#include #include "src/core/lib/profiling/timers.h" -void grpc_closure_init(grpc_closure *closure, grpc_iomgr_cb_func cb, - void *cb_arg) { +#ifndef NDEBUG +grpc_tracer_flag grpc_trace_closure = GRPC_TRACER_INITIALIZER(false, "closure"); +#endif + +#ifndef NDEBUG +grpc_closure *grpc_closure_init(const char *file, int line, + grpc_closure *closure, grpc_iomgr_cb_func cb, + void *cb_arg, + grpc_closure_scheduler *scheduler) { +#else +grpc_closure *grpc_closure_init(grpc_closure *closure, grpc_iomgr_cb_func cb, + void *cb_arg, + grpc_closure_scheduler *scheduler) { +#endif closure->cb = cb; closure->cb_arg = cb_arg; + closure->scheduler = scheduler; +#ifndef NDEBUG + closure->scheduled = false; + closure->file_initiated = NULL; + closure->line_initiated = 0; + closure->run = false; + closure->file_created = file; + closure->line_created = line; +#endif + return closure; } void grpc_closure_list_init(grpc_closure_list *closure_list) { closure_list->head = closure_list->tail = NULL; } -void grpc_closure_list_append(grpc_closure_list *closure_list, +bool grpc_closure_list_append(grpc_closure_list *closure_list, grpc_closure *closure, grpc_error *error) { if (closure == NULL) { GRPC_ERROR_UNREF(error); - return; + return false; } closure->error_data.error = error; closure->next_data.next = NULL; - if (closure_list->head == NULL) { + bool was_empty = (closure_list->head == NULL); + if (was_empty) { closure_list->head = closure; } else { closure_list->tail->next_data.next = closure; } closure_list->tail = closure; + return was_empty; } void grpc_closure_list_fail_all(grpc_closure_list *list, @@ -105,20 +116,90 @@ static void closure_wrapper(grpc_exec_ctx *exec_ctx, void *arg, cb(exec_ctx, cb_arg, error); } -grpc_closure *grpc_closure_create(grpc_iomgr_cb_func cb, void *cb_arg) { +#ifndef NDEBUG +grpc_closure *grpc_closure_create(const char *file, int line, + grpc_iomgr_cb_func cb, void *cb_arg, + grpc_closure_scheduler *scheduler) { +#else +grpc_closure *grpc_closure_create(grpc_iomgr_cb_func cb, void *cb_arg, + grpc_closure_scheduler *scheduler) { +#endif wrapped_closure *wc = gpr_malloc(sizeof(*wc)); wc->cb = cb; wc->cb_arg = cb_arg; - grpc_closure_init(&wc->wrapper, closure_wrapper, wc); +#ifndef NDEBUG + grpc_closure_init(file, line, &wc->wrapper, closure_wrapper, wc, scheduler); +#else + grpc_closure_init(&wc->wrapper, closure_wrapper, wc, scheduler); +#endif return &wc->wrapper; } +#ifndef NDEBUG +void grpc_closure_run(const char *file, int line, grpc_exec_ctx *exec_ctx, + grpc_closure *c, grpc_error *error) { +#else void grpc_closure_run(grpc_exec_ctx *exec_ctx, grpc_closure *c, grpc_error *error) { +#endif GPR_TIMER_BEGIN("grpc_closure_run", 0); if (c != NULL) { - c->cb(exec_ctx, c->cb_arg, error); +#ifndef NDEBUG + c->file_initiated = file; + c->line_initiated = line; + c->run = true; +#endif + assert(c->cb); + c->scheduler->vtable->run(exec_ctx, c, error); + } else { + GRPC_ERROR_UNREF(error); } - GRPC_ERROR_UNREF(error); GPR_TIMER_END("grpc_closure_run", 0); } + +#ifndef NDEBUG +void grpc_closure_sched(const char *file, int line, grpc_exec_ctx *exec_ctx, + grpc_closure *c, grpc_error *error) { +#else +void grpc_closure_sched(grpc_exec_ctx *exec_ctx, grpc_closure *c, + grpc_error *error) { +#endif + GPR_TIMER_BEGIN("grpc_closure_sched", 0); + if (c != NULL) { +#ifndef NDEBUG + GPR_ASSERT(!c->scheduled); + c->scheduled = true; + c->file_initiated = file; + c->line_initiated = line; + c->run = false; +#endif + assert(c->cb); + c->scheduler->vtable->sched(exec_ctx, c, error); + } else { + GRPC_ERROR_UNREF(error); + } + GPR_TIMER_END("grpc_closure_sched", 0); +} + +#ifndef NDEBUG +void grpc_closure_list_sched(const char *file, int line, + grpc_exec_ctx *exec_ctx, grpc_closure_list *list) { +#else +void grpc_closure_list_sched(grpc_exec_ctx *exec_ctx, grpc_closure_list *list) { +#endif + grpc_closure *c = list->head; + while (c != NULL) { + grpc_closure *next = c->next_data.next; +#ifndef NDEBUG + GPR_ASSERT(!c->scheduled); + c->scheduled = true; + c->file_initiated = file; + c->line_initiated = line; + c->run = false; +#endif + assert(c->cb); + c->scheduler->vtable->sched(exec_ctx, c, c->error_data.error); + c = next; + } + list->head = list->tail = NULL; +} diff --git a/Sources/CgRPC/src/core/lib/iomgr/closure.h b/Sources/CgRPC/src/core/lib/iomgr/closure.h index 2b4b271ea..cd32a4ba3 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/closure.h +++ b/Sources/CgRPC/src/core/lib/iomgr/closure.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -35,16 +20,22 @@ #define GRPC_CORE_LIB_IOMGR_CLOSURE_H #include + +#include #include #include "src/core/lib/iomgr/error.h" #include "src/core/lib/support/mpscq.h" +#ifdef __cplusplus +extern "C" { +#endif + struct grpc_closure; typedef struct grpc_closure grpc_closure; -/* forward declaration for exec_ctx.h */ -struct grpc_exec_ctx; -typedef struct grpc_exec_ctx grpc_exec_ctx; +#ifndef NDEBUG +extern grpc_tracer_flag grpc_trace_closure; +#endif typedef struct grpc_closure_list { grpc_closure *head; @@ -55,10 +46,29 @@ typedef struct grpc_closure_list { * * \param arg Arbitrary input. * \param error GRPC_ERROR_NONE if no error occurred, otherwise some grpc_error - * describing what went wrong */ + * describing what went wrong. + * Error contract: it is not the cb's job to unref this error; + * the closure scheduler will do that after the cb returns */ typedef void (*grpc_iomgr_cb_func)(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error); +typedef struct grpc_closure_scheduler grpc_closure_scheduler; + +typedef struct grpc_closure_scheduler_vtable { + /* NOTE: for all these functions, closure->scheduler == the scheduler that was + used to find this vtable */ + void (*run)(grpc_exec_ctx *exec_ctx, grpc_closure *closure, + grpc_error *error); + void (*sched)(grpc_exec_ctx *exec_ctx, grpc_closure *closure, + grpc_error *error); + const char *name; +} grpc_closure_scheduler_vtable; + +/** Abstract type that can schedule closures for execution */ +struct grpc_closure_scheduler { + const grpc_closure_scheduler_vtable *vtable; +}; + /** A closure over a grpc_iomgr_cb_func. */ struct grpc_closure { /** Once queued, next indicates the next queued closure; before then, scratch @@ -75,19 +85,57 @@ struct grpc_closure { /** Arguments to be passed to "cb". */ void *cb_arg; + /** Scheduler to schedule against: NULL to schedule against current execution + context */ + grpc_closure_scheduler *scheduler; + /** Once queued, the result of the closure. Before then: scratch space */ union { grpc_error *error; uintptr_t scratch; } error_data; + +// extra tracing and debugging for grpc_closure. This incurs a decent amount of +// overhead per closure, so it must be enabled at compile time. +#ifndef NDEBUG + bool scheduled; + bool run; // true = run, false = scheduled + const char *file_created; + int line_created; + const char *file_initiated; + int line_initiated; +#endif }; -/** Initializes \a closure with \a cb and \a cb_arg. */ -void grpc_closure_init(grpc_closure *closure, grpc_iomgr_cb_func cb, - void *cb_arg); +/** Initializes \a closure with \a cb and \a cb_arg. Returns \a closure. */ +#ifndef NDEBUG +grpc_closure *grpc_closure_init(const char *file, int line, + grpc_closure *closure, grpc_iomgr_cb_func cb, + void *cb_arg, + grpc_closure_scheduler *scheduler); +#define GRPC_CLOSURE_INIT(closure, cb, cb_arg, scheduler) \ + grpc_closure_init(__FILE__, __LINE__, closure, cb, cb_arg, scheduler) +#else +grpc_closure *grpc_closure_init(grpc_closure *closure, grpc_iomgr_cb_func cb, + void *cb_arg, + grpc_closure_scheduler *scheduler); +#define GRPC_CLOSURE_INIT(closure, cb, cb_arg, scheduler) \ + grpc_closure_init(closure, cb, cb_arg, scheduler) +#endif /* Create a heap allocated closure: try to avoid except for very rare events */ -grpc_closure *grpc_closure_create(grpc_iomgr_cb_func cb, void *cb_arg); +#ifndef NDEBUG +grpc_closure *grpc_closure_create(const char *file, int line, + grpc_iomgr_cb_func cb, void *cb_arg, + grpc_closure_scheduler *scheduler); +#define GRPC_CLOSURE_CREATE(cb, cb_arg, scheduler) \ + grpc_closure_create(__FILE__, __LINE__, cb, cb_arg, scheduler) +#else +grpc_closure *grpc_closure_create(grpc_iomgr_cb_func cb, void *cb_arg, + grpc_closure_scheduler *scheduler); +#define GRPC_CLOSURE_CREATE(cb, cb_arg, scheduler) \ + grpc_closure_create(cb, cb_arg, scheduler) +#endif #define GRPC_CLOSURE_LIST_INIT \ { NULL, NULL } @@ -95,8 +143,9 @@ grpc_closure *grpc_closure_create(grpc_iomgr_cb_func cb, void *cb_arg); void grpc_closure_list_init(grpc_closure_list *list); /** add \a closure to the end of \a list - and set \a closure's result to \a error */ -void grpc_closure_list_append(grpc_closure_list *list, grpc_closure *closure, + and set \a closure's result to \a error + Returns true if \a list becomes non-empty */ +bool grpc_closure_list_append(grpc_closure_list *list, grpc_closure *closure, grpc_error *error); /** force all success bits in \a list to false */ @@ -112,7 +161,48 @@ bool grpc_closure_list_empty(grpc_closure_list list); /** Run a closure directly. Caller ensures that no locks are being held above. * Note that calling this at the end of a closure callback function itself is * by definition safe. */ +#ifndef NDEBUG +void grpc_closure_run(const char *file, int line, grpc_exec_ctx *exec_ctx, + grpc_closure *closure, grpc_error *error); +#define GRPC_CLOSURE_RUN(exec_ctx, closure, error) \ + grpc_closure_run(__FILE__, __LINE__, exec_ctx, closure, error) +#else void grpc_closure_run(grpc_exec_ctx *exec_ctx, grpc_closure *closure, grpc_error *error); +#define GRPC_CLOSURE_RUN(exec_ctx, closure, error) \ + grpc_closure_run(exec_ctx, closure, error) +#endif + +/** Schedule a closure to be run. Does not need to be run from a safe point. */ +#ifndef NDEBUG +void grpc_closure_sched(const char *file, int line, grpc_exec_ctx *exec_ctx, + grpc_closure *closure, grpc_error *error); +#define GRPC_CLOSURE_SCHED(exec_ctx, closure, error) \ + grpc_closure_sched(__FILE__, __LINE__, exec_ctx, closure, error) +#else +void grpc_closure_sched(grpc_exec_ctx *exec_ctx, grpc_closure *closure, + grpc_error *error); +#define GRPC_CLOSURE_SCHED(exec_ctx, closure, error) \ + grpc_closure_sched(exec_ctx, closure, error) +#endif + +/** Schedule all closures in a list to be run. Does not need to be run from a + * safe point. */ +#ifndef NDEBUG +void grpc_closure_list_sched(const char *file, int line, + grpc_exec_ctx *exec_ctx, + grpc_closure_list *closure_list); +#define GRPC_CLOSURE_LIST_SCHED(exec_ctx, closure_list) \ + grpc_closure_list_sched(__FILE__, __LINE__, exec_ctx, closure_list) +#else +void grpc_closure_list_sched(grpc_exec_ctx *exec_ctx, + grpc_closure_list *closure_list); +#define GRPC_CLOSURE_LIST_SCHED(exec_ctx, closure_list) \ + grpc_closure_list_sched(exec_ctx, closure_list) +#endif + +#ifdef __cplusplus +} +#endif #endif /* GRPC_CORE_LIB_IOMGR_CLOSURE_H */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/combiner.c b/Sources/CgRPC/src/core/lib/iomgr/combiner.c index cfc67020a..9b66987b6 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/combiner.c +++ b/Sources/CgRPC/src/core/lib/iomgr/combiner.c @@ -1,53 +1,40 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 "src/core/lib/iomgr/combiner.h" +#include #include #include #include -#include "src/core/lib/iomgr/workqueue.h" +#include "src/core/lib/iomgr/executor.h" #include "src/core/lib/profiling/timers.h" -int grpc_combiner_trace = 0; +grpc_tracer_flag grpc_combiner_trace = + GRPC_TRACER_INITIALIZER(false, "combiner"); -#define GRPC_COMBINER_TRACE(fn) \ - do { \ - if (grpc_combiner_trace) { \ - fn; \ - } \ +#define GRPC_COMBINER_TRACE(fn) \ + do { \ + if (GRPC_TRACER_ON(grpc_combiner_trace)) { \ + fn; \ + } \ } while (0) #define STATE_UNORPHANED 1 @@ -55,58 +42,45 @@ int grpc_combiner_trace = 0; struct grpc_combiner { grpc_combiner *next_combiner_on_this_exec_ctx; - grpc_workqueue *optional_workqueue; + grpc_closure_scheduler scheduler; + grpc_closure_scheduler finally_scheduler; gpr_mpscq queue; + // either: + // a pointer to the initiating exec ctx if that is the only exec_ctx that has + // ever queued to this combiner, or NULL. If this is non-null, it's not + // dereferencable (since the initiating exec_ctx may have gone out of scope) + gpr_atm initiating_exec_ctx_or_null; // state is: // lower bit - zero if orphaned (STATE_UNORPHANED) // other bits - number of items queued on the lock (STATE_ELEM_COUNT_LOW_BIT) gpr_atm state; - // number of elements in the list that are covered by a poller: if >0, we can - // offload safely - gpr_atm elements_covered_by_poller; bool time_to_execute_final_list; - bool final_list_covered_by_poller; grpc_closure_list final_list; grpc_closure offload; + gpr_refcount refs; }; -static void offload(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error); - -typedef struct { - grpc_error *error; - bool covered_by_poller; -} error_data; - -static uintptr_t pack_error_data(error_data d) { - return ((uintptr_t)d.error) | (d.covered_by_poller ? 1 : 0); -} +static void combiner_exec(grpc_exec_ctx *exec_ctx, grpc_closure *closure, + grpc_error *error); +static void combiner_finally_exec(grpc_exec_ctx *exec_ctx, + grpc_closure *closure, grpc_error *error); -static error_data unpack_error_data(uintptr_t p) { - return (error_data){(grpc_error *)(p & ~(uintptr_t)1), p & 1}; -} +static const grpc_closure_scheduler_vtable scheduler = { + combiner_exec, combiner_exec, "combiner:immediately"}; +static const grpc_closure_scheduler_vtable finally_scheduler = { + combiner_finally_exec, combiner_finally_exec, "combiner:finally"}; -static bool is_covered_by_poller(grpc_combiner *lock) { - return lock->final_list_covered_by_poller || - gpr_atm_acq_load(&lock->elements_covered_by_poller) > 0; -} - -#define IS_COVERED_BY_POLLER_FMT "(final=%d elems=%" PRIdPTR ")->%d" -#define IS_COVERED_BY_POLLER_ARGS(lock) \ - (lock)->final_list_covered_by_poller, \ - gpr_atm_acq_load(&(lock)->elements_covered_by_poller), \ - is_covered_by_poller((lock)) +static void offload(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error); -grpc_combiner *grpc_combiner_create(grpc_workqueue *optional_workqueue) { - grpc_combiner *lock = gpr_malloc(sizeof(*lock)); - lock->next_combiner_on_this_exec_ctx = NULL; - lock->time_to_execute_final_list = false; - lock->optional_workqueue = optional_workqueue; - lock->final_list_covered_by_poller = false; +grpc_combiner *grpc_combiner_create(void) { + grpc_combiner *lock = gpr_zalloc(sizeof(*lock)); + gpr_ref_init(&lock->refs, 1); + lock->scheduler.vtable = &scheduler; + lock->finally_scheduler.vtable = &finally_scheduler; gpr_atm_no_barrier_store(&lock->state, STATE_UNORPHANED); - gpr_atm_no_barrier_store(&lock->elements_covered_by_poller, 0); gpr_mpscq_init(&lock->queue); grpc_closure_list_init(&lock->final_list); - grpc_closure_init(&lock->offload, offload, lock); + GRPC_CLOSURE_INIT(&lock->offload, offload, lock, grpc_executor_scheduler); GRPC_COMBINER_TRACE(gpr_log(GPR_DEBUG, "C:%p create", lock)); return lock; } @@ -115,11 +89,10 @@ static void really_destroy(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { GRPC_COMBINER_TRACE(gpr_log(GPR_DEBUG, "C:%p really_destroy", lock)); GPR_ASSERT(gpr_atm_no_barrier_load(&lock->state) == 0); gpr_mpscq_destroy(&lock->queue); - GRPC_WORKQUEUE_UNREF(exec_ctx, lock->optional_workqueue, "combiner"); gpr_free(lock); } -void grpc_combiner_destroy(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { +static void start_destroy(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { gpr_atm old_state = gpr_atm_full_fetch_add(&lock->state, -STATE_UNORPHANED); GRPC_COMBINER_TRACE(gpr_log( GPR_DEBUG, "C:%p really_destroy old_state=%" PRIdPTR, lock, old_state)); @@ -128,6 +101,32 @@ void grpc_combiner_destroy(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { } } +#ifndef NDEBUG +#define GRPC_COMBINER_DEBUG_SPAM(op, delta) \ + if (GRPC_TRACER_ON(grpc_combiner_trace)) { \ + gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, \ + "C:%p %s %" PRIdPTR " --> %" PRIdPTR " %s", lock, (op), \ + gpr_atm_no_barrier_load(&lock->refs.count), \ + gpr_atm_no_barrier_load(&lock->refs.count) + (delta), reason); \ + } +#else +#define GRPC_COMBINER_DEBUG_SPAM(op, delta) +#endif + +void grpc_combiner_unref(grpc_exec_ctx *exec_ctx, + grpc_combiner *lock GRPC_COMBINER_DEBUG_ARGS) { + GRPC_COMBINER_DEBUG_SPAM("UNREF", -1); + if (gpr_unref(&lock->refs)) { + start_destroy(exec_ctx, lock); + } +} + +grpc_combiner *grpc_combiner_ref(grpc_combiner *lock GRPC_COMBINER_DEBUG_ARGS) { + GRPC_COMBINER_DEBUG_SPAM(" REF", 1); + gpr_ref(&lock->refs); + return lock; +} + static void push_last_on_exec_ctx(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { lock->next_combiner_on_this_exec_ctx = NULL; @@ -148,26 +147,37 @@ static void push_first_on_exec_ctx(grpc_exec_ctx *exec_ctx, } } -void grpc_combiner_execute(grpc_exec_ctx *exec_ctx, grpc_combiner *lock, - grpc_closure *cl, grpc_error *error, - bool covered_by_poller) { +#define COMBINER_FROM_CLOSURE_SCHEDULER(closure, scheduler_name) \ + ((grpc_combiner *)(((char *)((closure)->scheduler)) - \ + offsetof(grpc_combiner, scheduler_name))) + +static void combiner_exec(grpc_exec_ctx *exec_ctx, grpc_closure *cl, + grpc_error *error) { GPR_TIMER_BEGIN("combiner.execute", 0); + grpc_combiner *lock = COMBINER_FROM_CLOSURE_SCHEDULER(cl, scheduler); gpr_atm last = gpr_atm_full_fetch_add(&lock->state, STATE_ELEM_COUNT_LOW_BIT); - GRPC_COMBINER_TRACE(gpr_log( - GPR_DEBUG, "C:%p grpc_combiner_execute c=%p cov=%d last=%" PRIdPTR, lock, - cl, covered_by_poller, last)); - GPR_ASSERT(last & STATE_UNORPHANED); // ensure lock has not been destroyed - cl->error_data.scratch = - pack_error_data((error_data){error, covered_by_poller}); - if (covered_by_poller) { - gpr_atm_no_barrier_fetch_add(&lock->elements_covered_by_poller, 1); - } - gpr_mpscq_push(&lock->queue, &cl->next_data.atm_next); + GRPC_COMBINER_TRACE(gpr_log(GPR_DEBUG, + "C:%p grpc_combiner_execute c=%p last=%" PRIdPTR, + lock, cl, last)); if (last == 1) { + gpr_atm_no_barrier_store(&lock->initiating_exec_ctx_or_null, + (gpr_atm)exec_ctx); // first element on this list: add it to the list of combiner locks // executing within this exec_ctx push_last_on_exec_ctx(exec_ctx, lock); + } else { + // there may be a race with setting here: if that happens, we may delay + // offload for one or two actions, and that's fine + gpr_atm initiator = + gpr_atm_no_barrier_load(&lock->initiating_exec_ctx_or_null); + if (initiator != 0 && initiator != (gpr_atm)exec_ctx) { + gpr_atm_no_barrier_store(&lock->initiating_exec_ctx_or_null, 0); + } } + GPR_ASSERT(last & STATE_UNORPHANED); // ensure lock has not been destroyed + assert(cl->cb); + cl->error_data.error = error; + gpr_mpscq_push(&lock->queue, &cl->next_data.atm_next); GPR_TIMER_END("combiner.execute", 0); } @@ -186,10 +196,8 @@ static void offload(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { static void queue_offload(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { move_next(exec_ctx); - GRPC_COMBINER_TRACE(gpr_log(GPR_DEBUG, "C:%p queue_offload --> %p", lock, - lock->optional_workqueue)); - grpc_workqueue_enqueue(exec_ctx, lock->optional_workqueue, &lock->offload, - GRPC_ERROR_NONE); + GRPC_COMBINER_TRACE(gpr_log(GPR_DEBUG, "C:%p queue_offload", lock)); + GRPC_CLOSURE_SCHED(exec_ctx, &lock->offload, GRPC_ERROR_NONE); } bool grpc_combiner_continue_exec_ctx(grpc_exec_ctx *exec_ctx) { @@ -200,22 +208,23 @@ bool grpc_combiner_continue_exec_ctx(grpc_exec_ctx *exec_ctx) { return false; } - GRPC_COMBINER_TRACE( - gpr_log(GPR_DEBUG, - "C:%p grpc_combiner_continue_exec_ctx workqueue=%p " - "is_covered_by_poller=" IS_COVERED_BY_POLLER_FMT - " exec_ctx_ready_to_finish=%d " - "time_to_execute_final_list=%d", - lock, lock->optional_workqueue, IS_COVERED_BY_POLLER_ARGS(lock), - grpc_exec_ctx_ready_to_finish(exec_ctx), - lock->time_to_execute_final_list)); - - if (lock->optional_workqueue != NULL && is_covered_by_poller(lock) && - grpc_exec_ctx_ready_to_finish(exec_ctx)) { + bool contended = + gpr_atm_no_barrier_load(&lock->initiating_exec_ctx_or_null) == 0; + + GRPC_COMBINER_TRACE(gpr_log(GPR_DEBUG, + "C:%p grpc_combiner_continue_exec_ctx " + "contended=%d " + "exec_ctx_ready_to_finish=%d " + "time_to_execute_final_list=%d", + lock, contended, + grpc_exec_ctx_ready_to_finish(exec_ctx), + lock->time_to_execute_final_list)); + + if (contended && grpc_exec_ctx_ready_to_finish(exec_ctx) && + grpc_executor_is_threaded()) { GPR_TIMER_MARK("offload_from_finished_exec_ctx", 0); - // this execution context wants to move on, and we have a workqueue (and - // so can help the execution context out): schedule remaining work to be - // picked up on the workqueue + // this execution context wants to move on: schedule remaining work to be + // picked up on the executor queue_offload(exec_ctx, lock); GPR_TIMER_END("combiner.continue_exec_ctx", 0); return true; @@ -232,26 +241,23 @@ bool grpc_combiner_continue_exec_ctx(grpc_exec_ctx *exec_ctx) { // queue is in an inconsistent state: use this as a cue that we should // go off and do something else for a while (and come back later) GPR_TIMER_MARK("delay_busy", 0); - if (lock->optional_workqueue != NULL && is_covered_by_poller(lock)) { - queue_offload(exec_ctx, lock); - } + queue_offload(exec_ctx, lock); GPR_TIMER_END("combiner.continue_exec_ctx", 0); return true; } GPR_TIMER_BEGIN("combiner.exec1", 0); grpc_closure *cl = (grpc_closure *)n; - error_data err = unpack_error_data(cl->error_data.scratch); - cl->cb(exec_ctx, cl->cb_arg, err.error); - if (err.covered_by_poller) { - gpr_atm_no_barrier_fetch_add(&lock->elements_covered_by_poller, -1); - } - GRPC_ERROR_UNREF(err.error); + grpc_error *cl_err = cl->error_data.error; +#ifndef NDEBUG + cl->scheduled = false; +#endif + cl->cb(exec_ctx, cl->cb_arg, cl_err); + GRPC_ERROR_UNREF(cl_err); GPR_TIMER_END("combiner.exec1", 0); } else { grpc_closure *c = lock->final_list.head; GPR_ASSERT(c != NULL); grpc_closure_list_init(&lock->final_list); - lock->final_list_covered_by_poller = false; int loops = 0; while (c != NULL) { GPR_TIMER_BEGIN("combiner.exec_1final", 0); @@ -259,6 +265,9 @@ bool grpc_combiner_continue_exec_ctx(grpc_exec_ctx *exec_ctx) { gpr_log(GPR_DEBUG, "C:%p execute_final[%d] c=%p", lock, loops, c)); grpc_closure *next = c->next_data.next; grpc_error *error = c->error_data.error; +#ifndef NDEBUG + c->scheduled = false; +#endif c->cb(exec_ctx, c->cb_arg, error); GRPC_ERROR_UNREF(error); c = next; @@ -312,23 +321,22 @@ bool grpc_combiner_continue_exec_ctx(grpc_exec_ctx *exec_ctx) { } static void enqueue_finally(grpc_exec_ctx *exec_ctx, void *closure, - grpc_error *error) { - grpc_combiner_execute_finally(exec_ctx, exec_ctx->active_combiner, closure, - GRPC_ERROR_REF(error), false); -} + grpc_error *error); -void grpc_combiner_execute_finally(grpc_exec_ctx *exec_ctx, grpc_combiner *lock, - grpc_closure *closure, grpc_error *error, - bool covered_by_poller) { - GRPC_COMBINER_TRACE(gpr_log( - GPR_DEBUG, "C:%p grpc_combiner_execute_finally c=%p; ac=%p; cov=%d", lock, - closure, exec_ctx->active_combiner, covered_by_poller)); +static void combiner_finally_exec(grpc_exec_ctx *exec_ctx, + grpc_closure *closure, grpc_error *error) { + grpc_combiner *lock = + COMBINER_FROM_CLOSURE_SCHEDULER(closure, finally_scheduler); + GRPC_COMBINER_TRACE(gpr_log(GPR_DEBUG, + "C:%p grpc_combiner_execute_finally c=%p; ac=%p", + lock, closure, exec_ctx->active_combiner)); GPR_TIMER_BEGIN("combiner.execute_finally", 0); if (exec_ctx->active_combiner != lock) { GPR_TIMER_MARK("slowpath", 0); - grpc_combiner_execute(exec_ctx, lock, - grpc_closure_create(enqueue_finally, closure), error, - false); + GRPC_CLOSURE_SCHED(exec_ctx, + GRPC_CLOSURE_CREATE(enqueue_finally, closure, + grpc_combiner_scheduler(lock)), + error); GPR_TIMER_END("combiner.execute_finally", 0); return; } @@ -336,9 +344,20 @@ void grpc_combiner_execute_finally(grpc_exec_ctx *exec_ctx, grpc_combiner *lock, if (grpc_closure_list_empty(lock->final_list)) { gpr_atm_full_fetch_add(&lock->state, STATE_ELEM_COUNT_LOW_BIT); } - if (covered_by_poller) { - lock->final_list_covered_by_poller = true; - } grpc_closure_list_append(&lock->final_list, closure, error); GPR_TIMER_END("combiner.execute_finally", 0); } + +static void enqueue_finally(grpc_exec_ctx *exec_ctx, void *closure, + grpc_error *error) { + combiner_finally_exec(exec_ctx, closure, GRPC_ERROR_REF(error)); +} + +grpc_closure_scheduler *grpc_combiner_scheduler(grpc_combiner *combiner) { + return &combiner->scheduler; +} + +grpc_closure_scheduler *grpc_combiner_finally_scheduler( + grpc_combiner *combiner) { + return &combiner->finally_scheduler; +} diff --git a/Sources/CgRPC/src/core/lib/iomgr/combiner.h b/Sources/CgRPC/src/core/lib/iomgr/combiner.h index d04eeed83..8e0434369 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/combiner.h +++ b/Sources/CgRPC/src/core/lib/iomgr/combiner.h @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -37,6 +22,7 @@ #include #include +#include "src/core/lib/debug/trace.h" #include "src/core/lib/iomgr/exec_ctx.h" #include "src/core/lib/support/mpscq.h" @@ -47,20 +33,34 @@ // Initialize the lock, with an optional workqueue to shift load to when // necessary -grpc_combiner *grpc_combiner_create(grpc_workqueue *optional_workqueue); -// Destroy the lock -void grpc_combiner_destroy(grpc_exec_ctx *exec_ctx, grpc_combiner *lock); -// Execute \a action within the lock. -void grpc_combiner_execute(grpc_exec_ctx *exec_ctx, grpc_combiner *lock, - grpc_closure *closure, grpc_error *error, - bool covered_by_poller); -// Execute \a action within the lock just prior to unlocking. -void grpc_combiner_execute_finally(grpc_exec_ctx *exec_ctx, grpc_combiner *lock, - grpc_closure *closure, grpc_error *error, - bool covered_by_poller); +grpc_combiner *grpc_combiner_create(void); + +#ifndef NDEBUG +#define GRPC_COMBINER_DEBUG_ARGS \ + , const char *file, int line, const char *reason +#define GRPC_COMBINER_REF(combiner, reason) \ + grpc_combiner_ref((combiner), __FILE__, __LINE__, (reason)) +#define GRPC_COMBINER_UNREF(exec_ctx, combiner, reason) \ + grpc_combiner_unref((exec_ctx), (combiner), __FILE__, __LINE__, (reason)) +#else +#define GRPC_COMBINER_DEBUG_ARGS +#define GRPC_COMBINER_REF(combiner, reason) grpc_combiner_ref((combiner)) +#define GRPC_COMBINER_UNREF(exec_ctx, combiner, reason) \ + grpc_combiner_unref((exec_ctx), (combiner)) +#endif + +// Ref/unref the lock, for when we're sharing the lock ownership +// Prefer to use the macros above +grpc_combiner *grpc_combiner_ref(grpc_combiner *lock GRPC_COMBINER_DEBUG_ARGS); +void grpc_combiner_unref(grpc_exec_ctx *exec_ctx, + grpc_combiner *lock GRPC_COMBINER_DEBUG_ARGS); +// Fetch a scheduler to schedule closures against +grpc_closure_scheduler *grpc_combiner_scheduler(grpc_combiner *lock); +// Scheduler to execute \a action within the lock just prior to unlocking. +grpc_closure_scheduler *grpc_combiner_finally_scheduler(grpc_combiner *lock); bool grpc_combiner_continue_exec_ctx(grpc_exec_ctx *exec_ctx); -extern int grpc_combiner_trace; +extern grpc_tracer_flag grpc_combiner_trace; #endif /* GRPC_CORE_LIB_IOMGR_COMBINER_H */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/endpoint.c b/Sources/CgRPC/src/core/lib/iomgr/endpoint.c index 2d300f456..37cce335c 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/endpoint.c +++ b/Sources/CgRPC/src/core/lib/iomgr/endpoint.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -54,8 +39,9 @@ void grpc_endpoint_add_to_pollset_set(grpc_exec_ctx* exec_ctx, ep->vtable->add_to_pollset_set(exec_ctx, ep, pollset_set); } -void grpc_endpoint_shutdown(grpc_exec_ctx* exec_ctx, grpc_endpoint* ep) { - ep->vtable->shutdown(exec_ctx, ep); +void grpc_endpoint_shutdown(grpc_exec_ctx* exec_ctx, grpc_endpoint* ep, + grpc_error* why) { + ep->vtable->shutdown(exec_ctx, ep, why); } void grpc_endpoint_destroy(grpc_exec_ctx* exec_ctx, grpc_endpoint* ep) { @@ -68,10 +54,6 @@ char* grpc_endpoint_get_peer(grpc_endpoint* ep) { int grpc_endpoint_get_fd(grpc_endpoint* ep) { return ep->vtable->get_fd(ep); } -grpc_workqueue* grpc_endpoint_get_workqueue(grpc_endpoint* ep) { - return ep->vtable->get_workqueue(ep); -} - grpc_resource_user* grpc_endpoint_get_resource_user(grpc_endpoint* ep) { return ep->vtable->get_resource_user(ep); } diff --git a/Sources/CgRPC/src/core/lib/iomgr/endpoint.h b/Sources/CgRPC/src/core/lib/iomgr/endpoint.h index 1609b64f2..8f0523a98 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/endpoint.h +++ b/Sources/CgRPC/src/core/lib/iomgr/endpoint.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -52,12 +37,11 @@ struct grpc_endpoint_vtable { grpc_slice_buffer *slices, grpc_closure *cb); void (*write)(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, grpc_slice_buffer *slices, grpc_closure *cb); - grpc_workqueue *(*get_workqueue)(grpc_endpoint *ep); void (*add_to_pollset)(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, grpc_pollset *pollset); void (*add_to_pollset_set)(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, grpc_pollset_set *pollset); - void (*shutdown)(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep); + void (*shutdown)(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, grpc_error *why); void (*destroy)(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep); grpc_resource_user *(*get_resource_user)(grpc_endpoint *ep); char *(*get_peer)(grpc_endpoint *ep); @@ -78,9 +62,6 @@ char *grpc_endpoint_get_peer(grpc_endpoint *ep); */ int grpc_endpoint_get_fd(grpc_endpoint *ep); -/* Retrieve a reference to the workqueue associated with this endpoint */ -grpc_workqueue *grpc_endpoint_get_workqueue(grpc_endpoint *ep); - /* Write slices out to the socket. If the connection is ready for more data after the end of the call, it @@ -96,7 +77,8 @@ void grpc_endpoint_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, /* Causes any pending and future read/write callbacks to run immediately with success==0 */ -void grpc_endpoint_shutdown(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep); +void grpc_endpoint_shutdown(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, + grpc_error *why); void grpc_endpoint_destroy(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep); /* Add an endpoint to a pollset, so that when the pollset is polled, events from diff --git a/Sources/CgRPC/src/core/lib/iomgr/endpoint_pair.h b/Sources/CgRPC/src/core/lib/iomgr/endpoint_pair.h index f9de0c715..b60e62fc3 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/endpoint_pair.h +++ b/Sources/CgRPC/src/core/lib/iomgr/endpoint_pair.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -41,8 +26,7 @@ typedef struct { grpc_endpoint *server; } grpc_endpoint_pair; -grpc_endpoint_pair grpc_iomgr_create_endpoint_pair( - const char *name, grpc_resource_quota *resource_quota, - size_t read_slice_size); +grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(const char *name, + grpc_channel_args *args); #endif /* GRPC_CORE_LIB_IOMGR_ENDPOINT_PAIR_H */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/endpoint_pair_posix.c b/Sources/CgRPC/src/core/lib/iomgr/endpoint_pair_posix.c index b9ff969e8..3ade2148b 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/endpoint_pair_posix.c +++ b/Sources/CgRPC/src/core/lib/iomgr/endpoint_pair_posix.c @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -62,22 +47,25 @@ static void create_sockets(int sv[2]) { GPR_ASSERT(grpc_set_socket_no_sigpipe_if_possible(sv[1]) == GRPC_ERROR_NONE); } -grpc_endpoint_pair grpc_iomgr_create_endpoint_pair( - const char *name, grpc_resource_quota *resource_quota, - size_t read_slice_size) { +grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(const char *name, + grpc_channel_args *args) { int sv[2]; grpc_endpoint_pair p; char *final_name; create_sockets(sv); + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + gpr_asprintf(&final_name, "%s:client", name); - p.client = grpc_tcp_create(grpc_fd_create(sv[1], final_name), resource_quota, - read_slice_size, "socketpair-server"); + p.client = grpc_tcp_create(&exec_ctx, grpc_fd_create(sv[1], final_name), args, + "socketpair-server"); gpr_free(final_name); gpr_asprintf(&final_name, "%s:server", name); - p.server = grpc_tcp_create(grpc_fd_create(sv[0], final_name), resource_quota, - read_slice_size, "socketpair-client"); + p.server = grpc_tcp_create(&exec_ctx, grpc_fd_create(sv[0], final_name), args, + "socketpair-client"); gpr_free(final_name); + + grpc_exec_ctx_finish(&exec_ctx); return p; } diff --git a/Sources/CgRPC/src/core/lib/iomgr/endpoint_pair_uv.c b/Sources/CgRPC/src/core/lib/iomgr/endpoint_pair_uv.c index ff24894c6..ff72fe049 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/endpoint_pair_uv.c +++ b/Sources/CgRPC/src/core/lib/iomgr/endpoint_pair_uv.c @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -41,9 +26,8 @@ #include "src/core/lib/iomgr/endpoint_pair.h" -grpc_endpoint_pair grpc_iomgr_create_endpoint_pair( - const char *name, grpc_resource_quota *resource_quota, - size_t read_slice_size) { +grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(const char *name, + grpc_channel_args *args) { grpc_endpoint_pair endpoint_pair; // TODO(mlumish): implement this properly under libuv GPR_ASSERT(false && diff --git a/Sources/CgRPC/src/core/lib/iomgr/endpoint_pair_windows.c b/Sources/CgRPC/src/core/lib/iomgr/endpoint_pair_windows.c index 93f71b745..782fa2fd6 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/endpoint_pair_windows.c +++ b/Sources/CgRPC/src/core/lib/iomgr/endpoint_pair_windows.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -83,15 +68,18 @@ static void create_sockets(SOCKET sv[2]) { } grpc_endpoint_pair grpc_iomgr_create_endpoint_pair( - const char *name, grpc_resource_quota *resource_quota, - size_t read_slice_size) { + const char *name, grpc_channel_args *channel_args) { SOCKET sv[2]; grpc_endpoint_pair p; create_sockets(sv); - p.client = grpc_tcp_create(grpc_winsocket_create(sv[1], "endpoint:client"), - resource_quota, "endpoint:server"); - p.server = grpc_tcp_create(grpc_winsocket_create(sv[0], "endpoint:server"), - resource_quota, "endpoint:client"); + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + p.client = grpc_tcp_create(&exec_ctx, + grpc_winsocket_create(sv[1], "endpoint:client"), + channel_args, "endpoint:server"); + p.server = grpc_tcp_create(&exec_ctx, + grpc_winsocket_create(sv[0], "endpoint:server"), + channel_args, "endpoint:client"); + grpc_exec_ctx_finish(&exec_ctx); return p; } diff --git a/Sources/CgRPC/src/core/lib/iomgr/error.c b/Sources/CgRPC/src/core/lib/iomgr/error.c index f6bb3a047..3759dda99 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/error.c +++ b/Sources/CgRPC/src/core/lib/iomgr/error.c @@ -1,45 +1,27 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 "src/core/lib/iomgr/error.h" -#include -#include #include #include #include -#include #include #include #include @@ -48,47 +30,15 @@ #include #endif +#include "src/core/lib/debug/trace.h" +#include "src/core/lib/iomgr/error_internal.h" #include "src/core/lib/profiling/timers.h" +#include "src/core/lib/slice/slice_internal.h" -static void destroy_integer(void *key) {} - -static void *copy_integer(void *key) { return key; } - -static long compare_integers(void *key1, void *key2) { - return GPR_ICMP((uintptr_t)key1, (uintptr_t)key2); -} - -static void destroy_string(void *str) { gpr_free(str); } - -static void *copy_string(void *str) { return gpr_strdup(str); } - -static void destroy_err(void *err) { GRPC_ERROR_UNREF(err); } - -static void *copy_err(void *err) { return GRPC_ERROR_REF(err); } - -static void destroy_time(void *tm) { gpr_free(tm); } - -static gpr_timespec *box_time(gpr_timespec tm) { - gpr_timespec *out = gpr_malloc(sizeof(*out)); - *out = tm; - return out; -} - -static void *copy_time(void *tm) { return box_time(*(gpr_timespec *)tm); } - -static const gpr_avl_vtable avl_vtable_ints = {destroy_integer, copy_integer, - compare_integers, - destroy_integer, copy_integer}; - -static const gpr_avl_vtable avl_vtable_strs = {destroy_integer, copy_integer, - compare_integers, destroy_string, - copy_string}; - -static const gpr_avl_vtable avl_vtable_times = { - destroy_integer, copy_integer, compare_integers, destroy_time, copy_time}; - -static const gpr_avl_vtable avl_vtable_errs = { - destroy_integer, copy_integer, compare_integers, destroy_err, copy_err}; +#ifndef NDEBUG +grpc_tracer_flag grpc_trace_error_refcount = + GRPC_TRACER_INITIALIZER(false, "error_refcount"); +#endif static const char *error_int_name(grpc_error_ints key) { switch (key) { @@ -122,12 +72,18 @@ static const char *error_int_name(grpc_error_ints key) { return "limit"; case GRPC_ERROR_INT_OCCURRED_DURING_WRITE: return "occurred_during_write"; + case GRPC_ERROR_INT_MAX: + GPR_UNREACHABLE_CODE(return "unknown"); } GPR_UNREACHABLE_CODE(return "unknown"); } static const char *error_str_name(grpc_error_strs key) { switch (key) { + case GRPC_ERROR_STR_KEY: + return "key"; + case GRPC_ERROR_STR_VALUE: + return "value"; case GRPC_ERROR_STR_DESCRIPTION: return "description"; case GRPC_ERROR_STR_OS_ERROR: @@ -148,6 +104,8 @@ static const char *error_str_name(grpc_error_strs key) { return "filename"; case GRPC_ERROR_STR_QUEUED_BUFFERS: return "queued_buffers"; + case GRPC_ERROR_STR_MAX: + GPR_UNREACHABLE_CODE(return "unknown"); } GPR_UNREACHABLE_CODE(return "unknown"); } @@ -156,127 +114,314 @@ static const char *error_time_name(grpc_error_times key) { switch (key) { case GRPC_ERROR_TIME_CREATED: return "created"; + case GRPC_ERROR_TIME_MAX: + GPR_UNREACHABLE_CODE(return "unknown"); } GPR_UNREACHABLE_CODE(return "unknown"); } -struct grpc_error { - gpr_refcount refs; - gpr_avl ints; - gpr_avl strs; - gpr_avl times; - gpr_avl errs; - uintptr_t next_err; -}; - -static bool is_special(grpc_error *err) { +bool grpc_error_is_special(grpc_error *err) { return err == GRPC_ERROR_NONE || err == GRPC_ERROR_OOM || err == GRPC_ERROR_CANCELLED; } -#ifdef GRPC_ERROR_REFCOUNT_DEBUG -grpc_error *grpc_error_ref(grpc_error *err, const char *file, int line, - const char *func) { - if (is_special(err)) return err; - gpr_log(GPR_DEBUG, "%p: %" PRIdPTR " -> %" PRIdPTR " [%s:%d %s]", err, - err->refs.count, err->refs.count + 1, file, line, func); - gpr_ref(&err->refs); +#ifndef NDEBUG +grpc_error *grpc_error_ref(grpc_error *err, const char *file, int line) { + if (grpc_error_is_special(err)) return err; + if (GRPC_TRACER_ON(grpc_trace_error_refcount)) { + gpr_log(GPR_DEBUG, "%p: %" PRIdPTR " -> %" PRIdPTR " [%s:%d]", err, + gpr_atm_no_barrier_load(&err->atomics.refs.count), + gpr_atm_no_barrier_load(&err->atomics.refs.count) + 1, file, line); + } + gpr_ref(&err->atomics.refs); return err; } #else grpc_error *grpc_error_ref(grpc_error *err) { - if (is_special(err)) return err; - gpr_ref(&err->refs); + if (grpc_error_is_special(err)) return err; + gpr_ref(&err->atomics.refs); return err; } #endif +static void unref_errs(grpc_error *err) { + uint8_t slot = err->first_err; + while (slot != UINT8_MAX) { + grpc_linked_error *lerr = (grpc_linked_error *)(err->arena + slot); + GRPC_ERROR_UNREF(lerr->err); + GPR_ASSERT(err->last_err == slot ? lerr->next == UINT8_MAX + : lerr->next != UINT8_MAX); + slot = lerr->next; + } +} + +static void unref_slice(grpc_slice slice) { + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + grpc_slice_unref_internal(&exec_ctx, slice); + grpc_exec_ctx_finish(&exec_ctx); +} + +static void unref_strs(grpc_error *err) { + for (size_t which = 0; which < GRPC_ERROR_STR_MAX; ++which) { + uint8_t slot = err->strs[which]; + if (slot != UINT8_MAX) { + unref_slice(*(grpc_slice *)(err->arena + slot)); + } + } +} + static void error_destroy(grpc_error *err) { - GPR_ASSERT(!is_special(err)); - gpr_avl_unref(err->ints); - gpr_avl_unref(err->strs); - gpr_avl_unref(err->errs); - gpr_avl_unref(err->times); + GPR_ASSERT(!grpc_error_is_special(err)); + unref_errs(err); + unref_strs(err); + gpr_free((void *)gpr_atm_acq_load(&err->atomics.error_string)); gpr_free(err); } -#ifdef GRPC_ERROR_REFCOUNT_DEBUG -void grpc_error_unref(grpc_error *err, const char *file, int line, - const char *func) { - if (is_special(err)) return; - gpr_log(GPR_DEBUG, "%p: %" PRIdPTR " -> %" PRIdPTR " [%s:%d %s]", err, - err->refs.count, err->refs.count - 1, file, line, func); - if (gpr_unref(&err->refs)) { +#ifndef NDEBUG +void grpc_error_unref(grpc_error *err, const char *file, int line) { + if (grpc_error_is_special(err)) return; + if (GRPC_TRACER_ON(grpc_trace_error_refcount)) { + gpr_log(GPR_DEBUG, "%p: %" PRIdPTR " -> %" PRIdPTR " [%s:%d]", err, + gpr_atm_no_barrier_load(&err->atomics.refs.count), + gpr_atm_no_barrier_load(&err->atomics.refs.count) - 1, file, line); + } + if (gpr_unref(&err->atomics.refs)) { error_destroy(err); } } #else void grpc_error_unref(grpc_error *err) { - if (is_special(err)) return; - if (gpr_unref(&err->refs)) { + if (grpc_error_is_special(err)) return; + if (gpr_unref(&err->atomics.refs)) { error_destroy(err); } } #endif -grpc_error *grpc_error_create(const char *file, int line, const char *desc, +static uint8_t get_placement(grpc_error **err, size_t size) { + GPR_ASSERT(*err); + uint8_t slots = (uint8_t)(size / sizeof(intptr_t)); + if ((*err)->arena_size + slots > (*err)->arena_capacity) { + (*err)->arena_capacity = + (uint8_t)GPR_MIN(UINT8_MAX - 1, (3 * (*err)->arena_capacity / 2)); + if ((*err)->arena_size + slots > (*err)->arena_capacity) { + return UINT8_MAX; + } +#ifndef NDEBUG + grpc_error *orig = *err; +#endif + *err = gpr_realloc( + *err, sizeof(grpc_error) + (*err)->arena_capacity * sizeof(intptr_t)); +#ifndef NDEBUG + if (GRPC_TRACER_ON(grpc_trace_error_refcount)) { + if (*err != orig) { + gpr_log(GPR_DEBUG, "realloc %p -> %p", orig, *err); + } + } +#endif + } + uint8_t placement = (*err)->arena_size; + (*err)->arena_size = (uint8_t)((*err)->arena_size + slots); + return placement; +} + +static void internal_set_int(grpc_error **err, grpc_error_ints which, + intptr_t value) { + uint8_t slot = (*err)->ints[which]; + if (slot == UINT8_MAX) { + slot = get_placement(err, sizeof(value)); + if (slot == UINT8_MAX) { + gpr_log(GPR_ERROR, "Error %p is full, dropping int {\"%s\":%" PRIiPTR "}", + *err, error_int_name(which), value); + return; + } + } + (*err)->ints[which] = slot; + (*err)->arena[slot] = value; +} + +static void internal_set_str(grpc_error **err, grpc_error_strs which, + grpc_slice value) { + uint8_t slot = (*err)->strs[which]; + if (slot == UINT8_MAX) { + slot = get_placement(err, sizeof(value)); + if (slot == UINT8_MAX) { + const char *str = grpc_slice_to_c_string(value); + gpr_log(GPR_ERROR, "Error %p is full, dropping string {\"%s\":\"%s\"}", + *err, error_str_name(which), str); + gpr_free((void *)str); + return; + } + } else { + unref_slice(*(grpc_slice *)((*err)->arena + slot)); + } + (*err)->strs[which] = slot; + memcpy((*err)->arena + slot, &value, sizeof(value)); +} + +static char *fmt_time(gpr_timespec tm); +static void internal_set_time(grpc_error **err, grpc_error_times which, + gpr_timespec value) { + uint8_t slot = (*err)->times[which]; + if (slot == UINT8_MAX) { + slot = get_placement(err, sizeof(value)); + if (slot == UINT8_MAX) { + const char *time_str = fmt_time(value); + gpr_log(GPR_ERROR, "Error %p is full, dropping \"%s\":\"%s\"}", *err, + error_time_name(which), time_str); + gpr_free((void *)time_str); + return; + } + } + (*err)->times[which] = slot; + memcpy((*err)->arena + slot, &value, sizeof(value)); +} + +static void internal_add_error(grpc_error **err, grpc_error *new) { + grpc_linked_error new_last = {new, UINT8_MAX}; + uint8_t slot = get_placement(err, sizeof(grpc_linked_error)); + if (slot == UINT8_MAX) { + gpr_log(GPR_ERROR, "Error %p is full, dropping error %p = %s", *err, new, + grpc_error_string(new)); + GRPC_ERROR_UNREF(new); + return; + } + if ((*err)->first_err == UINT8_MAX) { + GPR_ASSERT((*err)->last_err == UINT8_MAX); + (*err)->last_err = slot; + (*err)->first_err = slot; + } else { + GPR_ASSERT((*err)->last_err != UINT8_MAX); + grpc_linked_error *old_last = + (grpc_linked_error *)((*err)->arena + (*err)->last_err); + old_last->next = slot; + (*err)->last_err = slot; + } + memcpy((*err)->arena + slot, &new_last, sizeof(grpc_linked_error)); +} + +#define SLOTS_PER_INT (sizeof(intptr_t) / sizeof(intptr_t)) +#define SLOTS_PER_STR (sizeof(grpc_slice) / sizeof(intptr_t)) +#define SLOTS_PER_TIME (sizeof(gpr_timespec) / sizeof(intptr_t)) +#define SLOTS_PER_LINKED_ERROR (sizeof(grpc_linked_error) / sizeof(intptr_t)) + +// size of storing one int and two slices and a timespec. For line, desc, file, +// and time created +#define DEFAULT_ERROR_CAPACITY \ + (SLOTS_PER_INT + (SLOTS_PER_STR * 2) + SLOTS_PER_TIME) + +// It is very common to include and extra int and string in an error +#define SURPLUS_CAPACITY (2 * SLOTS_PER_INT + SLOTS_PER_TIME) + +grpc_error *grpc_error_create(const char *file, int line, grpc_slice desc, grpc_error **referencing, size_t num_referencing) { GPR_TIMER_BEGIN("grpc_error_create", 0); - grpc_error *err = gpr_malloc(sizeof(*err)); + uint8_t initial_arena_capacity = (uint8_t)( + DEFAULT_ERROR_CAPACITY + + (uint8_t)(num_referencing * SLOTS_PER_LINKED_ERROR) + SURPLUS_CAPACITY); + grpc_error *err = + gpr_malloc(sizeof(*err) + initial_arena_capacity * sizeof(intptr_t)); if (err == NULL) { // TODO(ctiller): make gpr_malloc return NULL return GRPC_ERROR_OOM; } -#ifdef GRPC_ERROR_REFCOUNT_DEBUG - gpr_log(GPR_DEBUG, "%p create [%s:%d]", err, file, line); +#ifndef NDEBUG + if (GRPC_TRACER_ON(grpc_trace_error_refcount)) { + gpr_log(GPR_DEBUG, "%p create [%s:%d]", err, file, line); + } #endif - err->ints = gpr_avl_add(gpr_avl_create(&avl_vtable_ints), - (void *)(uintptr_t)GRPC_ERROR_INT_FILE_LINE, - (void *)(uintptr_t)line); - err->strs = gpr_avl_add( - gpr_avl_add(gpr_avl_create(&avl_vtable_strs), - (void *)(uintptr_t)GRPC_ERROR_STR_FILE, gpr_strdup(file)), - (void *)(uintptr_t)GRPC_ERROR_STR_DESCRIPTION, gpr_strdup(desc)); - err->errs = gpr_avl_create(&avl_vtable_errs); - err->next_err = 0; - for (size_t i = 0; i < num_referencing; i++) { + + err->arena_size = 0; + err->arena_capacity = initial_arena_capacity; + err->first_err = UINT8_MAX; + err->last_err = UINT8_MAX; + + memset(err->ints, UINT8_MAX, GRPC_ERROR_INT_MAX); + memset(err->strs, UINT8_MAX, GRPC_ERROR_STR_MAX); + memset(err->times, UINT8_MAX, GRPC_ERROR_TIME_MAX); + + internal_set_int(&err, GRPC_ERROR_INT_FILE_LINE, line); + internal_set_str(&err, GRPC_ERROR_STR_FILE, + grpc_slice_from_static_string(file)); + internal_set_str(&err, GRPC_ERROR_STR_DESCRIPTION, desc); + + for (size_t i = 0; i < num_referencing; ++i) { if (referencing[i] == GRPC_ERROR_NONE) continue; - err->errs = gpr_avl_add(err->errs, (void *)(err->next_err++), - GRPC_ERROR_REF(referencing[i])); + internal_add_error( + &err, + GRPC_ERROR_REF( + referencing[i])); // TODO(ncteisen), change ownership semantics } - err->times = gpr_avl_add(gpr_avl_create(&avl_vtable_times), - (void *)(uintptr_t)GRPC_ERROR_TIME_CREATED, - box_time(gpr_now(GPR_CLOCK_REALTIME))); - gpr_ref_init(&err->refs, 1); + + internal_set_time(&err, GRPC_ERROR_TIME_CREATED, gpr_now(GPR_CLOCK_REALTIME)); + + gpr_atm_no_barrier_store(&err->atomics.error_string, 0); + gpr_ref_init(&err->atomics.refs, 1); GPR_TIMER_END("grpc_error_create", 0); return err; } +static void ref_strs(grpc_error *err) { + for (size_t i = 0; i < GRPC_ERROR_STR_MAX; ++i) { + uint8_t slot = err->strs[i]; + if (slot != UINT8_MAX) { + grpc_slice_ref_internal(*(grpc_slice *)(err->arena + slot)); + } + } +} + +static void ref_errs(grpc_error *err) { + uint8_t slot = err->first_err; + while (slot != UINT8_MAX) { + grpc_linked_error *lerr = (grpc_linked_error *)(err->arena + slot); + GRPC_ERROR_REF(lerr->err); + slot = lerr->next; + } +} + static grpc_error *copy_error_and_unref(grpc_error *in) { GPR_TIMER_BEGIN("copy_error_and_unref", 0); grpc_error *out; - if (is_special(in)) { - if (in == GRPC_ERROR_NONE) - out = GRPC_ERROR_CREATE("no error"); - else if (in == GRPC_ERROR_OOM) - out = GRPC_ERROR_CREATE("oom"); - else if (in == GRPC_ERROR_CANCELLED) - out = - grpc_error_set_int(GRPC_ERROR_CREATE("cancelled"), - GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_CANCELLED); - else - out = GRPC_ERROR_CREATE("unknown"); + if (grpc_error_is_special(in)) { + out = GRPC_ERROR_CREATE_FROM_STATIC_STRING("unknown"); + if (in == GRPC_ERROR_NONE) { + internal_set_str(&out, GRPC_ERROR_STR_DESCRIPTION, + grpc_slice_from_static_string("no error")); + internal_set_int(&out, GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_OK); + } else if (in == GRPC_ERROR_OOM) { + internal_set_str(&out, GRPC_ERROR_STR_DESCRIPTION, + grpc_slice_from_static_string("oom")); + } else if (in == GRPC_ERROR_CANCELLED) { + internal_set_str(&out, GRPC_ERROR_STR_DESCRIPTION, + grpc_slice_from_static_string("cancelled")); + internal_set_int(&out, GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_CANCELLED); + } + } else if (gpr_ref_is_unique(&in->atomics.refs)) { + out = in; } else { - out = gpr_malloc(sizeof(*out)); -#ifdef GRPC_ERROR_REFCOUNT_DEBUG - gpr_log(GPR_DEBUG, "%p create copying %p", out, in); + uint8_t new_arena_capacity = in->arena_capacity; + // the returned err will be added to, so we ensure this is room to avoid + // unneeded allocations. + if (in->arena_capacity - in->arena_size < (uint8_t)SLOTS_PER_STR) { + new_arena_capacity = (uint8_t)(3 * new_arena_capacity / 2); + } + out = gpr_malloc(sizeof(*in) + new_arena_capacity * sizeof(intptr_t)); +#ifndef NDEBUG + if (GRPC_TRACER_ON(grpc_trace_error_refcount)) { + gpr_log(GPR_DEBUG, "%p create copying %p", out, in); + } #endif - out->ints = gpr_avl_ref(in->ints); - out->strs = gpr_avl_ref(in->strs); - out->errs = gpr_avl_ref(in->errs); - out->times = gpr_avl_ref(in->times); - out->next_err = in->next_err; - gpr_ref_init(&out->refs, 1); + // bulk memcpy of the rest of the struct. + size_t skip = sizeof(&out->atomics); + memcpy((void *)((uintptr_t)out + skip), (void *)((uintptr_t)in + skip), + sizeof(*in) + (in->arena_size * sizeof(intptr_t)) - skip); + // manually set the atomics and the new capacity + gpr_atm_no_barrier_store(&out->atomics.error_string, 0); + gpr_ref_init(&out->atomics.refs, 1); + out->arena_capacity = new_arena_capacity; + ref_strs(out); + ref_errs(out); GRPC_ERROR_UNREF(in); } GPR_TIMER_END("copy_error_and_unref", 0); @@ -287,25 +432,40 @@ grpc_error *grpc_error_set_int(grpc_error *src, grpc_error_ints which, intptr_t value) { GPR_TIMER_BEGIN("grpc_error_set_int", 0); grpc_error *new = copy_error_and_unref(src); - new->ints = gpr_avl_add(new->ints, (void *)(uintptr_t)which, (void *)value); + internal_set_int(&new, which, value); GPR_TIMER_END("grpc_error_set_int", 0); return new; } +typedef struct { + grpc_error *error; + grpc_status_code code; + const char *msg; +} special_error_status_map; +static special_error_status_map error_status_map[] = { + {GRPC_ERROR_NONE, GRPC_STATUS_OK, ""}, + {GRPC_ERROR_CANCELLED, GRPC_STATUS_CANCELLED, "Cancelled"}, + {GRPC_ERROR_OOM, GRPC_STATUS_RESOURCE_EXHAUSTED, "Out of memory"}, +}; + bool grpc_error_get_int(grpc_error *err, grpc_error_ints which, intptr_t *p) { GPR_TIMER_BEGIN("grpc_error_get_int", 0); - void *pp; - if (is_special(err)) { - if (err == GRPC_ERROR_CANCELLED && which == GRPC_ERROR_INT_GRPC_STATUS) { - *p = GRPC_STATUS_CANCELLED; - GPR_TIMER_END("grpc_error_get_int", 0); - return true; + if (grpc_error_is_special(err)) { + if (which == GRPC_ERROR_INT_GRPC_STATUS) { + for (size_t i = 0; i < GPR_ARRAY_SIZE(error_status_map); i++) { + if (error_status_map[i].error == err) { + if (p != NULL) *p = error_status_map[i].code; + GPR_TIMER_END("grpc_error_get_int", 0); + return true; + } + } } GPR_TIMER_END("grpc_error_get_int", 0); return false; } - if (gpr_avl_maybe_get(err->ints, (void *)(uintptr_t)which, &pp)) { - if (p != NULL) *p = (intptr_t)pp; + uint8_t slot = err->ints[which]; + if (slot != UINT8_MAX) { + if (p != NULL) *p = err->arena[slot]; GPR_TIMER_END("grpc_error_get_int", 0); return true; } @@ -314,82 +474,40 @@ bool grpc_error_get_int(grpc_error *err, grpc_error_ints which, intptr_t *p) { } grpc_error *grpc_error_set_str(grpc_error *src, grpc_error_strs which, - const char *value) { + grpc_slice str) { GPR_TIMER_BEGIN("grpc_error_set_str", 0); grpc_error *new = copy_error_and_unref(src); - new->strs = - gpr_avl_add(new->strs, (void *)(uintptr_t)which, gpr_strdup(value)); + internal_set_str(&new, which, str); GPR_TIMER_END("grpc_error_set_str", 0); return new; } -const char *grpc_error_get_str(grpc_error *err, grpc_error_strs which) { - if (is_special(err)) return NULL; - return gpr_avl_get(err->strs, (void *)(uintptr_t)which); -} - -typedef struct { - grpc_error *error; - grpc_status_code code; - const char *msg; -} special_error_status_map; -static special_error_status_map error_status_map[] = { - {GRPC_ERROR_NONE, GRPC_STATUS_OK, ""}, - {GRPC_ERROR_CANCELLED, GRPC_STATUS_CANCELLED, "RPC cancelled"}, - {GRPC_ERROR_OOM, GRPC_STATUS_RESOURCE_EXHAUSTED, "Out of memory"}, -}; - -static grpc_error *recursively_find_error_with_status(grpc_error *error, - intptr_t *status) { - // If the error itself has a status code, return it. - if (grpc_error_get_int(error, GRPC_ERROR_INT_GRPC_STATUS, status)) { - return error; - } - // Otherwise, search through its children. - intptr_t key = 0; - while (true) { - grpc_error *child_error = gpr_avl_get(error->errs, (void *)key++); - if (child_error == NULL) break; - grpc_error *result = - recursively_find_error_with_status(child_error, status); - if (result != NULL) return result; - } - return NULL; -} - -void grpc_error_get_status(grpc_error *error, grpc_status_code *code, - const char **msg) { - // Handle special errors via the static map. - for (size_t i = 0; i < GPR_ARRAY_SIZE(error_status_map); ++i) { - if (error == error_status_map[i].error) { - *code = error_status_map[i].code; - *msg = error_status_map[i].msg; - return; +bool grpc_error_get_str(grpc_error *err, grpc_error_strs which, + grpc_slice *str) { + if (grpc_error_is_special(err)) { + if (which == GRPC_ERROR_STR_GRPC_MESSAGE) { + for (size_t i = 0; i < GPR_ARRAY_SIZE(error_status_map); i++) { + if (error_status_map[i].error == err) { + *str = grpc_slice_from_static_string(error_status_map[i].msg); + return true; + } + } } + return false; } - // Populate code. - // Start with the parent error and recurse through the tree of children - // until we find the first one that has a status code. - intptr_t status = GRPC_STATUS_UNKNOWN; // Default in case we don't find one. - grpc_error *found_error = recursively_find_error_with_status(error, &status); - *code = (grpc_status_code)status; - // Now populate msg. - // If we found an error with a status code above, use that; otherwise, - // fall back to using the parent error. - if (found_error == NULL) found_error = error; - // If the error has a status message, use it. Otherwise, fall back to - // the error description. - *msg = grpc_error_get_str(found_error, GRPC_ERROR_STR_GRPC_MESSAGE); - if (*msg == NULL) { - *msg = grpc_error_get_str(found_error, GRPC_ERROR_STR_DESCRIPTION); - if (*msg == NULL) *msg = "uknown error"; // Just in case. + uint8_t slot = err->strs[which]; + if (slot != UINT8_MAX) { + *str = *(grpc_slice *)(err->arena + slot); + return true; + } else { + return false; } } grpc_error *grpc_error_add_child(grpc_error *src, grpc_error *child) { GPR_TIMER_BEGIN("grpc_error_add_child", 0); grpc_error *new = copy_error_and_unref(src); - new->errs = gpr_avl_add(new->errs, (void *)(new->next_err++), child); + internal_add_error(&new, child); GPR_TIMER_END("grpc_error_add_child", 0); return new; } @@ -409,42 +527,6 @@ typedef struct { size_t cap_kvs; } kv_pairs; -static void append_kv(kv_pairs *kvs, char *key, char *value) { - if (kvs->num_kvs == kvs->cap_kvs) { - kvs->cap_kvs = GPR_MAX(3 * kvs->cap_kvs / 2, 4); - kvs->kvs = gpr_realloc(kvs->kvs, sizeof(*kvs->kvs) * kvs->cap_kvs); - } - kvs->kvs[kvs->num_kvs].key = key; - kvs->kvs[kvs->num_kvs].value = value; - kvs->num_kvs++; -} - -static void collect_kvs(gpr_avl_node *node, char *key(void *k), - char *fmt(void *v), kv_pairs *kvs) { - if (node == NULL) return; - append_kv(kvs, key(node->key), fmt(node->value)); - collect_kvs(node->left, key, fmt, kvs); - collect_kvs(node->right, key, fmt, kvs); -} - -static char *key_int(void *p) { - return gpr_strdup(error_int_name((grpc_error_ints)(uintptr_t)p)); -} - -static char *key_str(void *p) { - return gpr_strdup(error_str_name((grpc_error_strs)(uintptr_t)p)); -} - -static char *key_time(void *p) { - return gpr_strdup(error_time_name((grpc_error_times)(uintptr_t)p)); -} - -static char *fmt_int(void *p) { - char *s; - gpr_asprintf(&s, "%" PRIdPTR, (intptr_t)p); - return s; -} - static void append_chr(char c, char **s, size_t *sz, size_t *cap) { if (*sz == *cap) { *cap = GPR_MAX(8, 3 * *cap / 2); @@ -459,13 +541,14 @@ static void append_str(const char *str, char **s, size_t *sz, size_t *cap) { } } -static void append_esc_str(const char *str, char **s, size_t *sz, size_t *cap) { +static void append_esc_str(const uint8_t *str, size_t len, char **s, size_t *sz, + size_t *cap) { static const char *hex = "0123456789abcdef"; append_chr('"', s, sz, cap); - for (const uint8_t *c = (const uint8_t *)str; *c; c++) { - if (*c < 32 || *c >= 127) { + for (size_t i = 0; i < len; i++, str++) { + if (*str < 32 || *str >= 127) { append_chr('\\', s, sz, cap); - switch (*c) { + switch (*str) { case '\b': append_chr('b', s, sz, cap); break; @@ -485,28 +568,76 @@ static void append_esc_str(const char *str, char **s, size_t *sz, size_t *cap) { append_chr('u', s, sz, cap); append_chr('0', s, sz, cap); append_chr('0', s, sz, cap); - append_chr(hex[*c >> 4], s, sz, cap); - append_chr(hex[*c & 0x0f], s, sz, cap); + append_chr(hex[*str >> 4], s, sz, cap); + append_chr(hex[*str & 0x0f], s, sz, cap); break; } } else { - append_chr((char)*c, s, sz, cap); + append_chr((char)*str, s, sz, cap); } } append_chr('"', s, sz, cap); } -static char *fmt_str(void *p) { +static void append_kv(kv_pairs *kvs, char *key, char *value) { + if (kvs->num_kvs == kvs->cap_kvs) { + kvs->cap_kvs = GPR_MAX(3 * kvs->cap_kvs / 2, 4); + kvs->kvs = gpr_realloc(kvs->kvs, sizeof(*kvs->kvs) * kvs->cap_kvs); + } + kvs->kvs[kvs->num_kvs].key = key; + kvs->kvs[kvs->num_kvs].value = value; + kvs->num_kvs++; +} + +static char *key_int(grpc_error_ints which) { + return gpr_strdup(error_int_name(which)); +} + +static char *fmt_int(intptr_t p) { + char *s; + gpr_asprintf(&s, "%" PRIdPTR, p); + return s; +} + +static void collect_ints_kvs(grpc_error *err, kv_pairs *kvs) { + for (size_t which = 0; which < GRPC_ERROR_INT_MAX; ++which) { + uint8_t slot = err->ints[which]; + if (slot != UINT8_MAX) { + append_kv(kvs, key_int((grpc_error_ints)which), + fmt_int(err->arena[slot])); + } + } +} + +static char *key_str(grpc_error_strs which) { + return gpr_strdup(error_str_name(which)); +} + +static char *fmt_str(grpc_slice slice) { char *s = NULL; size_t sz = 0; size_t cap = 0; - append_esc_str(p, &s, &sz, &cap); + append_esc_str((const uint8_t *)GRPC_SLICE_START_PTR(slice), + GRPC_SLICE_LENGTH(slice), &s, &sz, &cap); append_chr(0, &s, &sz, &cap); return s; } -static char *fmt_time(void *p) { - gpr_timespec tm = *(gpr_timespec *)p; +static void collect_strs_kvs(grpc_error *err, kv_pairs *kvs) { + for (size_t which = 0; which < GRPC_ERROR_STR_MAX; ++which) { + uint8_t slot = err->strs[which]; + if (slot != UINT8_MAX) { + append_kv(kvs, key_str((grpc_error_strs)which), + fmt_str(*(grpc_slice *)(err->arena + slot))); + } + } +} + +static char *key_time(grpc_error_times which) { + return gpr_strdup(error_time_name(which)); +} + +static char *fmt_time(gpr_timespec tm) { char *out; char *pfx = "!!"; switch (tm.clock_type) { @@ -527,25 +658,37 @@ static char *fmt_time(void *p) { return out; } -static void add_errs(gpr_avl_node *n, char **s, size_t *sz, size_t *cap, - bool *first) { - if (n == NULL) return; - add_errs(n->left, s, sz, cap, first); - if (!*first) append_chr(',', s, sz, cap); - *first = false; - const char *e = grpc_error_string(n->value); - append_str(e, s, sz, cap); - grpc_error_free_string(e); - add_errs(n->right, s, sz, cap, first); +static void collect_times_kvs(grpc_error *err, kv_pairs *kvs) { + for (size_t which = 0; which < GRPC_ERROR_TIME_MAX; ++which) { + uint8_t slot = err->times[which]; + if (slot != UINT8_MAX) { + append_kv(kvs, key_time((grpc_error_times)which), + fmt_time(*(gpr_timespec *)(err->arena + slot))); + } + } +} + +static void add_errs(grpc_error *err, char **s, size_t *sz, size_t *cap) { + uint8_t slot = err->first_err; + bool first = true; + while (slot != UINT8_MAX) { + grpc_linked_error *lerr = (grpc_linked_error *)(err->arena + slot); + if (!first) append_chr(',', s, sz, cap); + first = false; + const char *e = grpc_error_string(lerr->err); + append_str(e, s, sz, cap); + GPR_ASSERT(err->last_err == slot ? lerr->next == UINT8_MAX + : lerr->next != UINT8_MAX); + slot = lerr->next; + } } static char *errs_string(grpc_error *err) { char *s = NULL; size_t sz = 0; size_t cap = 0; - bool first = true; append_chr('[', &s, &sz, &cap); - add_errs(err->errs.root, &s, &sz, &cap, &first); + add_errs(err, &s, &sz, &cap); append_chr(']', &s, &sz, &cap); append_chr(0, &s, &sz, &cap); return s; @@ -557,7 +700,7 @@ static int cmp_kvs(const void *a, const void *b) { return strcmp(ka->key, kb->key); } -static const char *finish_kvs(kv_pairs *kvs) { +static char *finish_kvs(kv_pairs *kvs) { char *s = NULL; size_t sz = 0; size_t cap = 0; @@ -565,7 +708,8 @@ static const char *finish_kvs(kv_pairs *kvs) { append_chr('{', &s, &sz, &cap); for (size_t i = 0; i < kvs->num_kvs; i++) { if (i != 0) append_chr(',', &s, &sz, &cap); - append_esc_str(kvs->kvs[i].key, &s, &sz, &cap); + append_esc_str((const uint8_t *)kvs->kvs[i].key, strlen(kvs->kvs[i].key), + &s, &sz, &cap); gpr_free(kvs->kvs[i].key); append_chr(':', &s, &sz, &cap); append_str(kvs->kvs[i].value, &s, &sz, &cap); @@ -578,32 +722,37 @@ static const char *finish_kvs(kv_pairs *kvs) { return s; } -void grpc_error_free_string(const char *str) { - if (str == no_error_string) return; - if (str == oom_error_string) return; - if (str == cancelled_error_string) return; - gpr_free((char *)str); -} - const char *grpc_error_string(grpc_error *err) { GPR_TIMER_BEGIN("grpc_error_string", 0); if (err == GRPC_ERROR_NONE) return no_error_string; if (err == GRPC_ERROR_OOM) return oom_error_string; if (err == GRPC_ERROR_CANCELLED) return cancelled_error_string; + void *p = (void *)gpr_atm_acq_load(&err->atomics.error_string); + if (p != NULL) { + GPR_TIMER_END("grpc_error_string", 0); + return p; + } + kv_pairs kvs; memset(&kvs, 0, sizeof(kvs)); - collect_kvs(err->ints.root, key_int, fmt_int, &kvs); - collect_kvs(err->strs.root, key_str, fmt_str, &kvs); - collect_kvs(err->times.root, key_time, fmt_time, &kvs); - if (!gpr_avl_is_empty(err->errs)) { + collect_ints_kvs(err, &kvs); + collect_strs_kvs(err, &kvs); + collect_times_kvs(err, &kvs); + if (err->first_err != UINT8_MAX) { append_kv(&kvs, gpr_strdup("referenced_errors"), errs_string(err)); } qsort(kvs.kvs, kvs.num_kvs, sizeof(kv_pair), cmp_kvs); - const char *out = finish_kvs(&kvs); + char *out = finish_kvs(&kvs); + + if (!gpr_atm_rel_cas(&err->atomics.error_string, 0, (gpr_atm)out)) { + gpr_free(out); + out = (char *)gpr_atm_no_barrier_load(&err->atomics.error_string); + } + GPR_TIMER_END("grpc_error_string", 0); return out; } @@ -612,10 +761,14 @@ grpc_error *grpc_os_error(const char *file, int line, int err, const char *call_name) { return grpc_error_set_str( grpc_error_set_str( - grpc_error_set_int(grpc_error_create(file, line, "OS Error", NULL, 0), - GRPC_ERROR_INT_ERRNO, err), - GRPC_ERROR_STR_OS_ERROR, strerror(err)), - GRPC_ERROR_STR_SYSCALL, call_name); + grpc_error_set_int( + grpc_error_create(file, line, + grpc_slice_from_static_string("OS Error"), NULL, + 0), + GRPC_ERROR_INT_ERRNO, err), + GRPC_ERROR_STR_OS_ERROR, + grpc_slice_from_static_string(strerror(err))), + GRPC_ERROR_STR_SYSCALL, grpc_slice_from_copied_string(call_name)); } #ifdef GPR_WINDOWS @@ -624,10 +777,13 @@ grpc_error *grpc_wsa_error(const char *file, int line, int err, char *utf8_message = gpr_format_message(err); grpc_error *error = grpc_error_set_str( grpc_error_set_str( - grpc_error_set_int(grpc_error_create(file, line, "OS Error", NULL, 0), - GRPC_ERROR_INT_WSA_ERROR, err), - GRPC_ERROR_STR_OS_ERROR, utf8_message), - GRPC_ERROR_STR_SYSCALL, call_name); + grpc_error_set_int( + grpc_error_create(file, line, + grpc_slice_from_static_string("OS Error"), NULL, + 0), + GRPC_ERROR_INT_WSA_ERROR, err), + GRPC_ERROR_STR_OS_ERROR, grpc_slice_from_copied_string(utf8_message)), + GRPC_ERROR_STR_SYSCALL, grpc_slice_from_static_string(call_name)); gpr_free(utf8_message); return error; } @@ -638,7 +794,6 @@ bool grpc_log_if_error(const char *what, grpc_error *error, const char *file, if (error == GRPC_ERROR_NONE) return true; const char *msg = grpc_error_string(error); gpr_log(file, line, GPR_LOG_SEVERITY_ERROR, "%s: %s", what, msg); - grpc_error_free_string(msg); GRPC_ERROR_UNREF(error); return false; } diff --git a/Sources/CgRPC/src/core/lib/iomgr/error.h b/Sources/CgRPC/src/core/lib/iomgr/error.h index f3f3b80a0..b36294869 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/error.h +++ b/Sources/CgRPC/src/core/lib/iomgr/error.h @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -37,38 +22,26 @@ #include #include +#include #include #include +#include "src/core/lib/debug/trace.h" + #ifdef __cplusplus extern "C" { #endif /// Opaque representation of an error. -/// Errors are refcounted objects that represent the result of an operation. -/// Ownership laws: -/// if a grpc_error is returned by a function, the caller owns a ref to that -/// instance -/// if a grpc_error is passed to a grpc_closure callback function (functions -/// with the signature: -/// void (*f)(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error)) -/// then those functions do not own a ref to error (but are free to manually -/// take a reference). -/// if a grpc_error is passed to *ANY OTHER FUNCTION* then that function takes -/// ownership of the error -/// Errors have: -/// a set of ints, strings, and timestamps that describe the error -/// always present are: -/// GRPC_ERROR_STR_FILE, GRPC_ERROR_INT_FILE_LINE - source location the error -/// was generated -/// GRPC_ERROR_STR_DESCRIPTION - a human readable description of the error -/// GRPC_ERROR_TIME_CREATED - a timestamp indicating when the error happened -/// an error can also have children; these are other errors that are believed -/// to have contributed to this one. By accumulating children, we can begin -/// to root cause high level failures from low level failures, without having -/// to derive execution paths from log lines +/// See https://github.com/grpc/grpc/blob/master/doc/core/grpc-error.md for a +/// full write up of this object. + typedef struct grpc_error grpc_error; +#ifndef NDEBUG +extern grpc_tracer_flag grpc_trace_error_refcount; +#endif + typedef enum { /// 'errno' from the operating system GRPC_ERROR_INT_ERRNO, @@ -102,6 +75,9 @@ typedef enum { GRPC_ERROR_INT_LIMIT, /// chttp2: did the error occur while a write was in progress GRPC_ERROR_INT_OCCURRED_DURING_WRITE, + + /// Must always be last + GRPC_ERROR_INT_MAX, } grpc_error_ints; typedef enum { @@ -124,27 +100,36 @@ typedef enum { /// filename that we were trying to read/write when this error occurred GRPC_ERROR_STR_FILENAME, /// which data was queued for writing when the error occurred - GRPC_ERROR_STR_QUEUED_BUFFERS + GRPC_ERROR_STR_QUEUED_BUFFERS, + /// key associated with the error + GRPC_ERROR_STR_KEY, + /// value associated with the error + GRPC_ERROR_STR_VALUE, + + /// Must always be last + GRPC_ERROR_STR_MAX, } grpc_error_strs; typedef enum { /// timestamp of error creation GRPC_ERROR_TIME_CREATED, + + /// Must always be last + GRPC_ERROR_TIME_MAX, } grpc_error_times; /// The following "special" errors can be propagated without allocating memory. -/// They are always even so that other code (particularly combiner locks) can -/// safely use the lower bit for themselves. +/// They are always even so that other code (particularly combiner locks, +/// polling engines) can safely use the lower bit for themselves. #define GRPC_ERROR_NONE ((grpc_error *)NULL) #define GRPC_ERROR_OOM ((grpc_error *)2) #define GRPC_ERROR_CANCELLED ((grpc_error *)4) const char *grpc_error_string(grpc_error *error); -void grpc_error_free_string(const char *str); /// Create an error - but use GRPC_ERROR_CREATE instead -grpc_error *grpc_error_create(const char *file, int line, const char *desc, +grpc_error *grpc_error_create(const char *file, int line, grpc_slice desc, grpc_error **referencing, size_t num_referencing); /// Create an error (this is the preferred way of generating an error that is /// not due to a system call - for system calls, use GRPC_OS_ERROR or @@ -154,23 +139,27 @@ grpc_error *grpc_error_create(const char *file, int line, const char *desc, /// err = grpc_error_create(x, y, z, r, nr) is equivalent to: /// err = grpc_error_create(x, y, z, NULL, 0); /// for (i=0; i +#include // TODO, do we need this? + +#include + +typedef struct grpc_linked_error grpc_linked_error; + +struct grpc_linked_error { + grpc_error *err; + uint8_t next; +}; + +// c core representation of an error. See error.h for high level description of +// this object. +struct grpc_error { + // All atomics in grpc_error must be stored in this nested struct. The rest of + // the object is memcpy-ed in bulk in copy_and_unref. + struct atomics { + gpr_refcount refs; + gpr_atm error_string; + } atomics; + // These arrays index into dynamic arena at the bottom of the struct. + // UINT8_MAX is used as a sentinel value. + uint8_t ints[GRPC_ERROR_INT_MAX]; + uint8_t strs[GRPC_ERROR_STR_MAX]; + uint8_t times[GRPC_ERROR_TIME_MAX]; + // The child errors are stored in the arena, but are effectively a linked list + // structure, since they are contained withing grpc_linked_error objects. + uint8_t first_err; + uint8_t last_err; + // The arena is dynamically reallocated with a grow factor of 1.5. + uint8_t arena_size; + uint8_t arena_capacity; + intptr_t arena[0]; +}; + +bool grpc_error_is_special(grpc_error *err); + +#endif /* GRPC_CORE_LIB_IOMGR_ERROR_INTERNAL_H */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/ev_epoll1_linux.c b/Sources/CgRPC/src/core/lib/iomgr/ev_epoll1_linux.c new file mode 100644 index 000000000..90e0ce36c --- /dev/null +++ b/Sources/CgRPC/src/core/lib/iomgr/ev_epoll1_linux.c @@ -0,0 +1,1084 @@ +/* + * + * Copyright 2017 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 "src/core/lib/iomgr/port.h" + +/* This polling engine is only relevant on linux kernels supporting epoll() */ +#ifdef GRPC_LINUX_EPOLL + +#include "src/core/lib/iomgr/ev_epoll1_linux.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "src/core/lib/iomgr/ev_posix.h" +#include "src/core/lib/iomgr/iomgr_internal.h" +#include "src/core/lib/iomgr/lockfree_event.h" +#include "src/core/lib/iomgr/wakeup_fd_posix.h" +#include "src/core/lib/profiling/timers.h" +#include "src/core/lib/support/block_annotate.h" +#include "src/core/lib/support/string.h" + +static grpc_wakeup_fd global_wakeup_fd; +static int g_epfd; + +/******************************************************************************* + * Fd Declarations + */ + +struct grpc_fd { + int fd; + + gpr_atm read_closure; + gpr_atm write_closure; + + struct grpc_fd *freelist_next; + + /* The pollset that last noticed that the fd is readable. The actual type + * stored in this is (grpc_pollset *) */ + gpr_atm read_notifier_pollset; + + grpc_iomgr_object iomgr_object; +}; + +static void fd_global_init(void); +static void fd_global_shutdown(void); + +/******************************************************************************* + * Pollset Declarations + */ + +typedef enum { UNKICKED, KICKED, DESIGNATED_POLLER } kick_state; + +static const char *kick_state_string(kick_state st) { + switch (st) { + case UNKICKED: + return "UNKICKED"; + case KICKED: + return "KICKED"; + case DESIGNATED_POLLER: + return "DESIGNATED_POLLER"; + } + GPR_UNREACHABLE_CODE(return "UNKNOWN"); +} + +struct grpc_pollset_worker { + kick_state kick_state; + int kick_state_mutator; // which line of code last changed kick state + bool initialized_cv; + grpc_pollset_worker *next; + grpc_pollset_worker *prev; + gpr_cv cv; + grpc_closure_list schedule_on_end_work; +}; + +#define SET_KICK_STATE(worker, state) \ + do { \ + (worker)->kick_state = (state); \ + (worker)->kick_state_mutator = __LINE__; \ + } while (false) + +#define MAX_NEIGHBOURHOODS 1024 + +typedef struct pollset_neighbourhood { + gpr_mu mu; + grpc_pollset *active_root; + char pad[GPR_CACHELINE_SIZE]; +} pollset_neighbourhood; + +struct grpc_pollset { + gpr_mu mu; + pollset_neighbourhood *neighbourhood; + bool reassigning_neighbourhood; + grpc_pollset_worker *root_worker; + bool kicked_without_poller; + + /* Set to true if the pollset is observed to have no workers available to + * poll */ + bool seen_inactive; + bool shutting_down; /* Is the pollset shutting down ? */ + grpc_closure *shutdown_closure; /* Called after after shutdown is complete */ + + /* Number of workers who are *about-to* attach themselves to the pollset + * worker list */ + int begin_refs; + + grpc_pollset *next; + grpc_pollset *prev; +}; + +/******************************************************************************* + * Pollset-set Declarations + */ + +struct grpc_pollset_set { + char unused; +}; + +/******************************************************************************* + * Common helpers + */ + +static bool append_error(grpc_error **composite, grpc_error *error, + const char *desc) { + if (error == GRPC_ERROR_NONE) return true; + if (*composite == GRPC_ERROR_NONE) { + *composite = GRPC_ERROR_CREATE_FROM_COPIED_STRING(desc); + } + *composite = grpc_error_add_child(*composite, error); + return false; +} + +/******************************************************************************* + * Fd Definitions + */ + +/* We need to keep a freelist not because of any concerns of malloc performance + * but instead so that implementations with multiple threads in (for example) + * epoll_wait deal with the race between pollset removal and incoming poll + * notifications. + * + * The problem is that the poller ultimately holds a reference to this + * object, so it is very difficult to know when is safe to free it, at least + * without some expensive synchronization. + * + * If we keep the object freelisted, in the worst case losing this race just + * becomes a spurious read notification on a reused fd. + */ + +/* The alarm system needs to be able to wakeup 'some poller' sometimes + * (specifically when a new alarm needs to be triggered earlier than the next + * alarm 'epoch'). This wakeup_fd gives us something to alert on when such a + * case occurs. */ + +static grpc_fd *fd_freelist = NULL; +static gpr_mu fd_freelist_mu; + +static void fd_global_init(void) { gpr_mu_init(&fd_freelist_mu); } + +static void fd_global_shutdown(void) { + gpr_mu_lock(&fd_freelist_mu); + gpr_mu_unlock(&fd_freelist_mu); + while (fd_freelist != NULL) { + grpc_fd *fd = fd_freelist; + fd_freelist = fd_freelist->freelist_next; + gpr_free(fd); + } + gpr_mu_destroy(&fd_freelist_mu); +} + +static grpc_fd *fd_create(int fd, const char *name) { + grpc_fd *new_fd = NULL; + + gpr_mu_lock(&fd_freelist_mu); + if (fd_freelist != NULL) { + new_fd = fd_freelist; + fd_freelist = fd_freelist->freelist_next; + } + gpr_mu_unlock(&fd_freelist_mu); + + if (new_fd == NULL) { + new_fd = gpr_malloc(sizeof(grpc_fd)); + } + + new_fd->fd = fd; + grpc_lfev_init(&new_fd->read_closure); + grpc_lfev_init(&new_fd->write_closure); + gpr_atm_no_barrier_store(&new_fd->read_notifier_pollset, (gpr_atm)NULL); + + new_fd->freelist_next = NULL; + + char *fd_name; + gpr_asprintf(&fd_name, "%s fd=%d", name, fd); + grpc_iomgr_register_object(&new_fd->iomgr_object, fd_name); +#ifndef NDEBUG + if (GRPC_TRACER_ON(grpc_trace_fd_refcount)) { + gpr_log(GPR_DEBUG, "FD %d %p create %s", fd, new_fd, fd_name); + } +#endif + gpr_free(fd_name); + + struct epoll_event ev = {.events = (uint32_t)(EPOLLIN | EPOLLOUT | EPOLLET), + .data.ptr = new_fd}; + if (epoll_ctl(g_epfd, EPOLL_CTL_ADD, fd, &ev) != 0) { + gpr_log(GPR_ERROR, "epoll_ctl failed: %s", strerror(errno)); + } + + return new_fd; +} + +static int fd_wrapped_fd(grpc_fd *fd) { return fd->fd; } + +/* if 'releasing_fd' is true, it means that we are going to detach the internal + * fd from grpc_fd structure (i.e which means we should not be calling + * shutdown() syscall on that fd) */ +static void fd_shutdown_internal(grpc_exec_ctx *exec_ctx, grpc_fd *fd, + grpc_error *why, bool releasing_fd) { + if (grpc_lfev_set_shutdown(exec_ctx, &fd->read_closure, + GRPC_ERROR_REF(why))) { + if (!releasing_fd) { + shutdown(fd->fd, SHUT_RDWR); + } + grpc_lfev_set_shutdown(exec_ctx, &fd->write_closure, GRPC_ERROR_REF(why)); + } + GRPC_ERROR_UNREF(why); +} + +/* Might be called multiple times */ +static void fd_shutdown(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_error *why) { + fd_shutdown_internal(exec_ctx, fd, why, false); +} + +static void fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd, + grpc_closure *on_done, int *release_fd, + bool already_closed, const char *reason) { + grpc_error *error = GRPC_ERROR_NONE; + bool is_release_fd = (release_fd != NULL); + + if (!grpc_lfev_is_shutdown(&fd->read_closure)) { + fd_shutdown_internal(exec_ctx, fd, + GRPC_ERROR_CREATE_FROM_COPIED_STRING(reason), + is_release_fd); + } + + /* If release_fd is not NULL, we should be relinquishing control of the file + descriptor fd->fd (but we still own the grpc_fd structure). */ + if (is_release_fd) { + *release_fd = fd->fd; + } else if (!already_closed) { + close(fd->fd); + } + + GRPC_CLOSURE_SCHED(exec_ctx, on_done, GRPC_ERROR_REF(error)); + + grpc_iomgr_unregister_object(&fd->iomgr_object); + grpc_lfev_destroy(&fd->read_closure); + grpc_lfev_destroy(&fd->write_closure); + + gpr_mu_lock(&fd_freelist_mu); + fd->freelist_next = fd_freelist; + fd_freelist = fd; + gpr_mu_unlock(&fd_freelist_mu); +} + +static grpc_pollset *fd_get_read_notifier_pollset(grpc_exec_ctx *exec_ctx, + grpc_fd *fd) { + gpr_atm notifier = gpr_atm_acq_load(&fd->read_notifier_pollset); + return (grpc_pollset *)notifier; +} + +static bool fd_is_shutdown(grpc_fd *fd) { + return grpc_lfev_is_shutdown(&fd->read_closure); +} + +static void fd_notify_on_read(grpc_exec_ctx *exec_ctx, grpc_fd *fd, + grpc_closure *closure) { + grpc_lfev_notify_on(exec_ctx, &fd->read_closure, closure, "read"); +} + +static void fd_notify_on_write(grpc_exec_ctx *exec_ctx, grpc_fd *fd, + grpc_closure *closure) { + grpc_lfev_notify_on(exec_ctx, &fd->write_closure, closure, "write"); +} + +static void fd_become_readable(grpc_exec_ctx *exec_ctx, grpc_fd *fd, + grpc_pollset *notifier) { + grpc_lfev_set_ready(exec_ctx, &fd->read_closure, "read"); + /* Use release store to match with acquire load in fd_get_read_notifier */ + gpr_atm_rel_store(&fd->read_notifier_pollset, (gpr_atm)notifier); +} + +static void fd_become_writable(grpc_exec_ctx *exec_ctx, grpc_fd *fd) { + grpc_lfev_set_ready(exec_ctx, &fd->write_closure, "write"); +} + +/******************************************************************************* + * Pollset Definitions + */ + +GPR_TLS_DECL(g_current_thread_pollset); +GPR_TLS_DECL(g_current_thread_worker); +static gpr_atm g_active_poller; +static pollset_neighbourhood *g_neighbourhoods; +static size_t g_num_neighbourhoods; + +/* Return true if first in list */ +static bool worker_insert(grpc_pollset *pollset, grpc_pollset_worker *worker) { + if (pollset->root_worker == NULL) { + pollset->root_worker = worker; + worker->next = worker->prev = worker; + return true; + } else { + worker->next = pollset->root_worker; + worker->prev = worker->next->prev; + worker->next->prev = worker; + worker->prev->next = worker; + return false; + } +} + +/* Return true if last in list */ +typedef enum { EMPTIED, NEW_ROOT, REMOVED } worker_remove_result; + +static worker_remove_result worker_remove(grpc_pollset *pollset, + grpc_pollset_worker *worker) { + if (worker == pollset->root_worker) { + if (worker == worker->next) { + pollset->root_worker = NULL; + return EMPTIED; + } else { + pollset->root_worker = worker->next; + worker->prev->next = worker->next; + worker->next->prev = worker->prev; + return NEW_ROOT; + } + } else { + worker->prev->next = worker->next; + worker->next->prev = worker->prev; + return REMOVED; + } +} + +static size_t choose_neighbourhood(void) { + return (size_t)gpr_cpu_current_cpu() % g_num_neighbourhoods; +} + +static grpc_error *pollset_global_init(void) { + gpr_tls_init(&g_current_thread_pollset); + gpr_tls_init(&g_current_thread_worker); + gpr_atm_no_barrier_store(&g_active_poller, 0); + global_wakeup_fd.read_fd = -1; + grpc_error *err = grpc_wakeup_fd_init(&global_wakeup_fd); + if (err != GRPC_ERROR_NONE) return err; + struct epoll_event ev = {.events = (uint32_t)(EPOLLIN | EPOLLET), + .data.ptr = &global_wakeup_fd}; + if (epoll_ctl(g_epfd, EPOLL_CTL_ADD, global_wakeup_fd.read_fd, &ev) != 0) { + return GRPC_OS_ERROR(errno, "epoll_ctl"); + } + g_num_neighbourhoods = GPR_CLAMP(gpr_cpu_num_cores(), 1, MAX_NEIGHBOURHOODS); + g_neighbourhoods = + gpr_zalloc(sizeof(*g_neighbourhoods) * g_num_neighbourhoods); + for (size_t i = 0; i < g_num_neighbourhoods; i++) { + gpr_mu_init(&g_neighbourhoods[i].mu); + } + return GRPC_ERROR_NONE; +} + +static void pollset_global_shutdown(void) { + gpr_tls_destroy(&g_current_thread_pollset); + gpr_tls_destroy(&g_current_thread_worker); + if (global_wakeup_fd.read_fd != -1) grpc_wakeup_fd_destroy(&global_wakeup_fd); + for (size_t i = 0; i < g_num_neighbourhoods; i++) { + gpr_mu_destroy(&g_neighbourhoods[i].mu); + } + gpr_free(g_neighbourhoods); +} + +static void pollset_init(grpc_pollset *pollset, gpr_mu **mu) { + gpr_mu_init(&pollset->mu); + *mu = &pollset->mu; + pollset->neighbourhood = &g_neighbourhoods[choose_neighbourhood()]; + pollset->seen_inactive = true; +} + +static void pollset_destroy(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset) { + gpr_mu_lock(&pollset->mu); + if (!pollset->seen_inactive) { + pollset_neighbourhood *neighbourhood = pollset->neighbourhood; + gpr_mu_unlock(&pollset->mu); + retry_lock_neighbourhood: + gpr_mu_lock(&neighbourhood->mu); + gpr_mu_lock(&pollset->mu); + if (!pollset->seen_inactive) { + if (pollset->neighbourhood != neighbourhood) { + gpr_mu_unlock(&neighbourhood->mu); + neighbourhood = pollset->neighbourhood; + gpr_mu_unlock(&pollset->mu); + goto retry_lock_neighbourhood; + } + pollset->prev->next = pollset->next; + pollset->next->prev = pollset->prev; + if (pollset == pollset->neighbourhood->active_root) { + pollset->neighbourhood->active_root = + pollset->next == pollset ? NULL : pollset->next; + } + } + gpr_mu_unlock(&pollset->neighbourhood->mu); + } + gpr_mu_unlock(&pollset->mu); + gpr_mu_destroy(&pollset->mu); +} + +static grpc_error *pollset_kick_all(grpc_pollset *pollset) { + grpc_error *error = GRPC_ERROR_NONE; + if (pollset->root_worker != NULL) { + grpc_pollset_worker *worker = pollset->root_worker; + do { + switch (worker->kick_state) { + case KICKED: + break; + case UNKICKED: + SET_KICK_STATE(worker, KICKED); + if (worker->initialized_cv) { + gpr_cv_signal(&worker->cv); + } + break; + case DESIGNATED_POLLER: + SET_KICK_STATE(worker, KICKED); + append_error(&error, grpc_wakeup_fd_wakeup(&global_wakeup_fd), + "pollset_kick_all"); + break; + } + + worker = worker->next; + } while (worker != pollset->root_worker); + } + // TODO: sreek. Check if we need to set 'kicked_without_poller' to true here + // in the else case + + return error; +} + +static void pollset_maybe_finish_shutdown(grpc_exec_ctx *exec_ctx, + grpc_pollset *pollset) { + if (pollset->shutdown_closure != NULL && pollset->root_worker == NULL && + pollset->begin_refs == 0) { + GRPC_CLOSURE_SCHED(exec_ctx, pollset->shutdown_closure, GRPC_ERROR_NONE); + pollset->shutdown_closure = NULL; + } +} + +static void pollset_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, + grpc_closure *closure) { + GPR_ASSERT(pollset->shutdown_closure == NULL); + GPR_ASSERT(!pollset->shutting_down); + pollset->shutdown_closure = closure; + pollset->shutting_down = true; + GRPC_LOG_IF_ERROR("pollset_shutdown", pollset_kick_all(pollset)); + pollset_maybe_finish_shutdown(exec_ctx, pollset); +} + +#define MAX_EPOLL_EVENTS 100 + +static int poll_deadline_to_millis_timeout(gpr_timespec deadline, + gpr_timespec now) { + gpr_timespec timeout; + if (gpr_time_cmp(deadline, gpr_inf_future(deadline.clock_type)) == 0) { + return -1; + } + + if (gpr_time_cmp(deadline, now) <= 0) { + return 0; + } + + static const gpr_timespec round_up = { + .clock_type = GPR_TIMESPAN, .tv_sec = 0, .tv_nsec = GPR_NS_PER_MS - 1}; + timeout = gpr_time_sub(deadline, now); + int millis = gpr_time_to_millis(gpr_time_add(timeout, round_up)); + return millis >= 1 ? millis : 1; +} + +static grpc_error *pollset_epoll(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, + gpr_timespec now, gpr_timespec deadline) { + struct epoll_event events[MAX_EPOLL_EVENTS]; + static const char *err_desc = "pollset_poll"; + + int timeout = poll_deadline_to_millis_timeout(deadline, now); + + if (timeout != 0) { + GRPC_SCHEDULING_START_BLOCKING_REGION; + } + int r; + do { + r = epoll_wait(g_epfd, events, MAX_EPOLL_EVENTS, timeout); + } while (r < 0 && errno == EINTR); + if (timeout != 0) { + GRPC_SCHEDULING_END_BLOCKING_REGION; + } + + if (r < 0) return GRPC_OS_ERROR(errno, "epoll_wait"); + + grpc_error *error = GRPC_ERROR_NONE; + for (int i = 0; i < r; i++) { + void *data_ptr = events[i].data.ptr; + if (data_ptr == &global_wakeup_fd) { + append_error(&error, grpc_wakeup_fd_consume_wakeup(&global_wakeup_fd), + err_desc); + } else { + grpc_fd *fd = (grpc_fd *)(data_ptr); + bool cancel = (events[i].events & (EPOLLERR | EPOLLHUP)) != 0; + bool read_ev = (events[i].events & (EPOLLIN | EPOLLPRI)) != 0; + bool write_ev = (events[i].events & EPOLLOUT) != 0; + if (read_ev || cancel) { + fd_become_readable(exec_ctx, fd, pollset); + } + if (write_ev || cancel) { + fd_become_writable(exec_ctx, fd); + } + } + } + + return error; +} + +static bool begin_worker(grpc_pollset *pollset, grpc_pollset_worker *worker, + grpc_pollset_worker **worker_hdl, gpr_timespec *now, + gpr_timespec deadline) { + if (worker_hdl != NULL) *worker_hdl = worker; + worker->initialized_cv = false; + SET_KICK_STATE(worker, UNKICKED); + worker->schedule_on_end_work = (grpc_closure_list)GRPC_CLOSURE_LIST_INIT; + pollset->begin_refs++; + + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_ERROR, "PS:%p BEGIN_STARTS:%p", pollset, worker); + } + + if (pollset->seen_inactive) { + // pollset has been observed to be inactive, we need to move back to the + // active list + bool is_reassigning = false; + if (!pollset->reassigning_neighbourhood) { + is_reassigning = true; + pollset->reassigning_neighbourhood = true; + pollset->neighbourhood = &g_neighbourhoods[choose_neighbourhood()]; + } + pollset_neighbourhood *neighbourhood = pollset->neighbourhood; + gpr_mu_unlock(&pollset->mu); + // pollset unlocked: state may change (even worker->kick_state) + retry_lock_neighbourhood: + gpr_mu_lock(&neighbourhood->mu); + gpr_mu_lock(&pollset->mu); + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_ERROR, "PS:%p BEGIN_REORG:%p kick_state=%s is_reassigning=%d", + pollset, worker, kick_state_string(worker->kick_state), + is_reassigning); + } + if (pollset->seen_inactive) { + if (neighbourhood != pollset->neighbourhood) { + gpr_mu_unlock(&neighbourhood->mu); + neighbourhood = pollset->neighbourhood; + gpr_mu_unlock(&pollset->mu); + goto retry_lock_neighbourhood; + } + pollset->seen_inactive = false; + if (neighbourhood->active_root == NULL) { + neighbourhood->active_root = pollset->next = pollset->prev = pollset; + /* TODO: sreek. Why would this worker state be other than UNKICKED + * here ? (since the worker isn't added to the pollset yet, there is no + * way it can be "found" by other threads to get kicked). */ + + /* If there is no designated poller, make this the designated poller */ + if (worker->kick_state == UNKICKED && + gpr_atm_no_barrier_cas(&g_active_poller, 0, (gpr_atm)worker)) { + SET_KICK_STATE(worker, DESIGNATED_POLLER); + } + } else { + pollset->next = neighbourhood->active_root; + pollset->prev = pollset->next->prev; + pollset->next->prev = pollset->prev->next = pollset; + } + } + if (is_reassigning) { + GPR_ASSERT(pollset->reassigning_neighbourhood); + pollset->reassigning_neighbourhood = false; + } + gpr_mu_unlock(&neighbourhood->mu); + } + + worker_insert(pollset, worker); + pollset->begin_refs--; + if (worker->kick_state == UNKICKED && !pollset->kicked_without_poller) { + GPR_ASSERT(gpr_atm_no_barrier_load(&g_active_poller) != (gpr_atm)worker); + worker->initialized_cv = true; + gpr_cv_init(&worker->cv); + while (worker->kick_state == UNKICKED && !pollset->shutting_down) { + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_ERROR, "PS:%p BEGIN_WAIT:%p kick_state=%s shutdown=%d", + pollset, worker, kick_state_string(worker->kick_state), + pollset->shutting_down); + } + + if (gpr_cv_wait(&worker->cv, &pollset->mu, deadline) && + worker->kick_state == UNKICKED) { + /* If gpr_cv_wait returns true (i.e a timeout), pretend that the worker + received a kick */ + SET_KICK_STATE(worker, KICKED); + } + } + *now = gpr_now(now->clock_type); + } + + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_ERROR, + "PS:%p BEGIN_DONE:%p kick_state=%s shutdown=%d " + "kicked_without_poller: %d", + pollset, worker, kick_state_string(worker->kick_state), + pollset->shutting_down, pollset->kicked_without_poller); + } + + /* We release pollset lock in this function at a couple of places: + * 1. Briefly when assigning pollset to a neighbourhood + * 2. When doing gpr_cv_wait() + * It is possible that 'kicked_without_poller' was set to true during (1) and + * 'shutting_down' is set to true during (1) or (2). If either of them is + * true, this worker cannot do polling */ + /* TODO(sreek): Perhaps there is a better way to handle kicked_without_poller + * case; especially when the worker is the DESIGNATED_POLLER */ + + if (pollset->kicked_without_poller) { + pollset->kicked_without_poller = false; + return false; + } + + return worker->kick_state == DESIGNATED_POLLER && !pollset->shutting_down; +} + +static bool check_neighbourhood_for_available_poller( + pollset_neighbourhood *neighbourhood) { + bool found_worker = false; + do { + grpc_pollset *inspect = neighbourhood->active_root; + if (inspect == NULL) { + break; + } + gpr_mu_lock(&inspect->mu); + GPR_ASSERT(!inspect->seen_inactive); + grpc_pollset_worker *inspect_worker = inspect->root_worker; + if (inspect_worker != NULL) { + do { + switch (inspect_worker->kick_state) { + case UNKICKED: + if (gpr_atm_no_barrier_cas(&g_active_poller, 0, + (gpr_atm)inspect_worker)) { + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_DEBUG, " .. choose next poller to be %p", + inspect_worker); + } + SET_KICK_STATE(inspect_worker, DESIGNATED_POLLER); + if (inspect_worker->initialized_cv) { + gpr_cv_signal(&inspect_worker->cv); + } + } else { + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_DEBUG, " .. beaten to choose next poller"); + } + } + // even if we didn't win the cas, there's a worker, we can stop + found_worker = true; + break; + case KICKED: + break; + case DESIGNATED_POLLER: + found_worker = true; // ok, so someone else found the worker, but + // we'll accept that + break; + } + inspect_worker = inspect_worker->next; + } while (!found_worker && inspect_worker != inspect->root_worker); + } + if (!found_worker) { + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_DEBUG, " .. mark pollset %p inactive", inspect); + } + inspect->seen_inactive = true; + if (inspect == neighbourhood->active_root) { + neighbourhood->active_root = + inspect->next == inspect ? NULL : inspect->next; + } + inspect->next->prev = inspect->prev; + inspect->prev->next = inspect->next; + inspect->next = inspect->prev = NULL; + } + gpr_mu_unlock(&inspect->mu); + } while (!found_worker); + return found_worker; +} + +static void end_worker(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, + grpc_pollset_worker *worker, + grpc_pollset_worker **worker_hdl) { + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_DEBUG, "PS:%p END_WORKER:%p", pollset, worker); + } + if (worker_hdl != NULL) *worker_hdl = NULL; + /* Make sure we appear kicked */ + SET_KICK_STATE(worker, KICKED); + grpc_closure_list_move(&worker->schedule_on_end_work, + &exec_ctx->closure_list); + if (gpr_atm_no_barrier_load(&g_active_poller) == (gpr_atm)worker) { + if (worker->next != worker && worker->next->kick_state == UNKICKED) { + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_DEBUG, " .. choose next poller to be peer %p", worker); + } + GPR_ASSERT(worker->next->initialized_cv); + gpr_atm_no_barrier_store(&g_active_poller, (gpr_atm)worker->next); + SET_KICK_STATE(worker->next, DESIGNATED_POLLER); + gpr_cv_signal(&worker->next->cv); + if (grpc_exec_ctx_has_work(exec_ctx)) { + gpr_mu_unlock(&pollset->mu); + grpc_exec_ctx_flush(exec_ctx); + gpr_mu_lock(&pollset->mu); + } + } else { + gpr_atm_no_barrier_store(&g_active_poller, 0); + size_t poller_neighbourhood_idx = + (size_t)(pollset->neighbourhood - g_neighbourhoods); + gpr_mu_unlock(&pollset->mu); + bool found_worker = false; + bool scan_state[MAX_NEIGHBOURHOODS]; + for (size_t i = 0; !found_worker && i < g_num_neighbourhoods; i++) { + pollset_neighbourhood *neighbourhood = + &g_neighbourhoods[(poller_neighbourhood_idx + i) % + g_num_neighbourhoods]; + if (gpr_mu_trylock(&neighbourhood->mu)) { + found_worker = + check_neighbourhood_for_available_poller(neighbourhood); + gpr_mu_unlock(&neighbourhood->mu); + scan_state[i] = true; + } else { + scan_state[i] = false; + } + } + for (size_t i = 0; !found_worker && i < g_num_neighbourhoods; i++) { + if (scan_state[i]) continue; + pollset_neighbourhood *neighbourhood = + &g_neighbourhoods[(poller_neighbourhood_idx + i) % + g_num_neighbourhoods]; + gpr_mu_lock(&neighbourhood->mu); + found_worker = check_neighbourhood_for_available_poller(neighbourhood); + gpr_mu_unlock(&neighbourhood->mu); + } + grpc_exec_ctx_flush(exec_ctx); + gpr_mu_lock(&pollset->mu); + } + } else if (grpc_exec_ctx_has_work(exec_ctx)) { + gpr_mu_unlock(&pollset->mu); + grpc_exec_ctx_flush(exec_ctx); + gpr_mu_lock(&pollset->mu); + } + if (worker->initialized_cv) { + gpr_cv_destroy(&worker->cv); + } + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_DEBUG, " .. remove worker"); + } + if (EMPTIED == worker_remove(pollset, worker)) { + pollset_maybe_finish_shutdown(exec_ctx, pollset); + } + GPR_ASSERT(gpr_atm_no_barrier_load(&g_active_poller) != (gpr_atm)worker); +} + +/* pollset->po.mu lock must be held by the caller before calling this. + The function pollset_work() may temporarily release the lock (pollset->po.mu) + during the course of its execution but it will always re-acquire the lock and + ensure that it is held by the time the function returns */ +static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, + grpc_pollset_worker **worker_hdl, + gpr_timespec now, gpr_timespec deadline) { + grpc_pollset_worker worker; + grpc_error *error = GRPC_ERROR_NONE; + static const char *err_desc = "pollset_work"; + if (pollset->kicked_without_poller) { + pollset->kicked_without_poller = false; + return GRPC_ERROR_NONE; + } + if (begin_worker(pollset, &worker, worker_hdl, &now, deadline)) { + gpr_tls_set(&g_current_thread_pollset, (intptr_t)pollset); + gpr_tls_set(&g_current_thread_worker, (intptr_t)&worker); + GPR_ASSERT(!pollset->shutting_down); + GPR_ASSERT(!pollset->seen_inactive); + gpr_mu_unlock(&pollset->mu); + append_error(&error, pollset_epoll(exec_ctx, pollset, now, deadline), + err_desc); + gpr_mu_lock(&pollset->mu); + gpr_tls_set(&g_current_thread_worker, 0); + } else { + gpr_tls_set(&g_current_thread_pollset, (intptr_t)pollset); + } + end_worker(exec_ctx, pollset, &worker, worker_hdl); + gpr_tls_set(&g_current_thread_pollset, 0); + return error; +} + +static grpc_error *pollset_kick(grpc_pollset *pollset, + grpc_pollset_worker *specific_worker) { + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_strvec log; + gpr_strvec_init(&log); + char *tmp; + gpr_asprintf( + &tmp, "PS:%p KICK:%p curps=%p curworker=%p root=%p", pollset, + specific_worker, (void *)gpr_tls_get(&g_current_thread_pollset), + (void *)gpr_tls_get(&g_current_thread_worker), pollset->root_worker); + gpr_strvec_add(&log, tmp); + if (pollset->root_worker != NULL) { + gpr_asprintf(&tmp, " {kick_state=%s next=%p {kick_state=%s}}", + kick_state_string(pollset->root_worker->kick_state), + pollset->root_worker->next, + kick_state_string(pollset->root_worker->next->kick_state)); + gpr_strvec_add(&log, tmp); + } + if (specific_worker != NULL) { + gpr_asprintf(&tmp, " worker_kick_state=%s", + kick_state_string(specific_worker->kick_state)); + gpr_strvec_add(&log, tmp); + } + tmp = gpr_strvec_flatten(&log, NULL); + gpr_strvec_destroy(&log); + gpr_log(GPR_ERROR, "%s", tmp); + gpr_free(tmp); + } + if (specific_worker == NULL) { + if (gpr_tls_get(&g_current_thread_pollset) != (intptr_t)pollset) { + grpc_pollset_worker *root_worker = pollset->root_worker; + if (root_worker == NULL) { + pollset->kicked_without_poller = true; + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_ERROR, " .. kicked_without_poller"); + } + return GRPC_ERROR_NONE; + } + grpc_pollset_worker *next_worker = root_worker->next; + if (root_worker->kick_state == KICKED) { + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_ERROR, " .. already kicked %p", root_worker); + } + SET_KICK_STATE(root_worker, KICKED); + return GRPC_ERROR_NONE; + } else if (next_worker->kick_state == KICKED) { + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_ERROR, " .. already kicked %p", next_worker); + } + SET_KICK_STATE(next_worker, KICKED); + return GRPC_ERROR_NONE; + } else if (root_worker == + next_worker && // only try and wake up a poller if + // there is no next worker + root_worker == (grpc_pollset_worker *)gpr_atm_no_barrier_load( + &g_active_poller)) { + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_ERROR, " .. kicked %p", root_worker); + } + SET_KICK_STATE(root_worker, KICKED); + return grpc_wakeup_fd_wakeup(&global_wakeup_fd); + } else if (next_worker->kick_state == UNKICKED) { + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_ERROR, " .. kicked %p", next_worker); + } + GPR_ASSERT(next_worker->initialized_cv); + SET_KICK_STATE(next_worker, KICKED); + gpr_cv_signal(&next_worker->cv); + return GRPC_ERROR_NONE; + } else if (next_worker->kick_state == DESIGNATED_POLLER) { + if (root_worker->kick_state != DESIGNATED_POLLER) { + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log( + GPR_ERROR, + " .. kicked root non-poller %p (initialized_cv=%d) (poller=%p)", + root_worker, root_worker->initialized_cv, next_worker); + } + SET_KICK_STATE(root_worker, KICKED); + if (root_worker->initialized_cv) { + gpr_cv_signal(&root_worker->cv); + } + return GRPC_ERROR_NONE; + } else { + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_ERROR, " .. non-root poller %p (root=%p)", next_worker, + root_worker); + } + SET_KICK_STATE(next_worker, KICKED); + return grpc_wakeup_fd_wakeup(&global_wakeup_fd); + } + } else { + GPR_ASSERT(next_worker->kick_state == KICKED); + SET_KICK_STATE(next_worker, KICKED); + return GRPC_ERROR_NONE; + } + } else { + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_ERROR, " .. kicked while waking up"); + } + return GRPC_ERROR_NONE; + } + } else if (specific_worker->kick_state == KICKED) { + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_ERROR, " .. specific worker already kicked"); + } + return GRPC_ERROR_NONE; + } else if (gpr_tls_get(&g_current_thread_worker) == + (intptr_t)specific_worker) { + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_ERROR, " .. mark %p kicked", specific_worker); + } + SET_KICK_STATE(specific_worker, KICKED); + return GRPC_ERROR_NONE; + } else if (specific_worker == + (grpc_pollset_worker *)gpr_atm_no_barrier_load(&g_active_poller)) { + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_ERROR, " .. kick active poller"); + } + SET_KICK_STATE(specific_worker, KICKED); + return grpc_wakeup_fd_wakeup(&global_wakeup_fd); + } else if (specific_worker->initialized_cv) { + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_ERROR, " .. kick waiting worker"); + } + SET_KICK_STATE(specific_worker, KICKED); + gpr_cv_signal(&specific_worker->cv); + return GRPC_ERROR_NONE; + } else { + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_ERROR, " .. kick non-waiting worker"); + } + SET_KICK_STATE(specific_worker, KICKED); + return GRPC_ERROR_NONE; + } +} + +static void pollset_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, + grpc_fd *fd) {} + +/******************************************************************************* + * Pollset-set Definitions + */ + +static grpc_pollset_set *pollset_set_create(void) { + return (grpc_pollset_set *)((intptr_t)0xdeafbeef); +} + +static void pollset_set_destroy(grpc_exec_ctx *exec_ctx, + grpc_pollset_set *pss) {} + +static void pollset_set_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset_set *pss, + grpc_fd *fd) {} + +static void pollset_set_del_fd(grpc_exec_ctx *exec_ctx, grpc_pollset_set *pss, + grpc_fd *fd) {} + +static void pollset_set_add_pollset(grpc_exec_ctx *exec_ctx, + grpc_pollset_set *pss, grpc_pollset *ps) {} + +static void pollset_set_del_pollset(grpc_exec_ctx *exec_ctx, + grpc_pollset_set *pss, grpc_pollset *ps) {} + +static void pollset_set_add_pollset_set(grpc_exec_ctx *exec_ctx, + grpc_pollset_set *bag, + grpc_pollset_set *item) {} + +static void pollset_set_del_pollset_set(grpc_exec_ctx *exec_ctx, + grpc_pollset_set *bag, + grpc_pollset_set *item) {} + +/******************************************************************************* + * Event engine binding + */ + +static void shutdown_engine(void) { + fd_global_shutdown(); + pollset_global_shutdown(); + close(g_epfd); +} + +static const grpc_event_engine_vtable vtable = { + .pollset_size = sizeof(grpc_pollset), + + .fd_create = fd_create, + .fd_wrapped_fd = fd_wrapped_fd, + .fd_orphan = fd_orphan, + .fd_shutdown = fd_shutdown, + .fd_is_shutdown = fd_is_shutdown, + .fd_notify_on_read = fd_notify_on_read, + .fd_notify_on_write = fd_notify_on_write, + .fd_get_read_notifier_pollset = fd_get_read_notifier_pollset, + + .pollset_init = pollset_init, + .pollset_shutdown = pollset_shutdown, + .pollset_destroy = pollset_destroy, + .pollset_work = pollset_work, + .pollset_kick = pollset_kick, + .pollset_add_fd = pollset_add_fd, + + .pollset_set_create = pollset_set_create, + .pollset_set_destroy = pollset_set_destroy, + .pollset_set_add_pollset = pollset_set_add_pollset, + .pollset_set_del_pollset = pollset_set_del_pollset, + .pollset_set_add_pollset_set = pollset_set_add_pollset_set, + .pollset_set_del_pollset_set = pollset_set_del_pollset_set, + .pollset_set_add_fd = pollset_set_add_fd, + .pollset_set_del_fd = pollset_set_del_fd, + + .shutdown_engine = shutdown_engine, +}; + +/* It is possible that GLIBC has epoll but the underlying kernel doesn't. + * Create a dummy epoll_fd to make sure epoll support is available */ +const grpc_event_engine_vtable *grpc_init_epoll1_linux(bool explicit_request) { + /* TODO(sreek): Temporarily disable this poller unless explicitly requested + * via GRPC_POLL_STRATEGY */ + if (!explicit_request) { + return NULL; + } + + if (!grpc_has_wakeup_fd()) { + return NULL; + } + + g_epfd = epoll_create1(EPOLL_CLOEXEC); + if (g_epfd < 0) { + gpr_log(GPR_ERROR, "epoll unavailable"); + return NULL; + } + + fd_global_init(); + + if (!GRPC_LOG_IF_ERROR("pollset_global_init", pollset_global_init())) { + close(g_epfd); + fd_global_shutdown(); + return NULL; + } + + gpr_log(GPR_ERROR, "grpc epoll fd: %d", g_epfd); + + return &vtable; +} + +#else /* defined(GRPC_LINUX_EPOLL) */ +#if defined(GRPC_POSIX_SOCKET) +#include "src/core/lib/iomgr/ev_posix.h" +/* If GRPC_LINUX_EPOLL is not defined, it means epoll is not available. Return + * NULL */ +const grpc_event_engine_vtable *grpc_init_epoll1_linux(bool explicit_request) { + return NULL; +} +#endif /* defined(GRPC_POSIX_SOCKET) */ +#endif /* !defined(GRPC_LINUX_EPOLL) */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/ev_epoll1_linux.h b/Sources/CgRPC/src/core/lib/iomgr/ev_epoll1_linux.h new file mode 100644 index 000000000..0696e0df4 --- /dev/null +++ b/Sources/CgRPC/src/core/lib/iomgr/ev_epoll1_linux.h @@ -0,0 +1,29 @@ +/* + * + * Copyright 2017 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 GRPC_CORE_LIB_IOMGR_EV_EPOLL1_LINUX_H +#define GRPC_CORE_LIB_IOMGR_EV_EPOLL1_LINUX_H + +#include "src/core/lib/iomgr/ev_posix.h" +#include "src/core/lib/iomgr/port.h" + +// a polling engine that utilizes a singleton epoll set and turnstile polling + +const grpc_event_engine_vtable *grpc_init_epoll1_linux(bool explicit_request); + +#endif /* GRPC_CORE_LIB_IOMGR_EV_EPOLL1_LINUX_H */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/ev_epoll_limited_pollers_linux.c b/Sources/CgRPC/src/core/lib/iomgr/ev_epoll_limited_pollers_linux.c new file mode 100644 index 000000000..f2f3e1570 --- /dev/null +++ b/Sources/CgRPC/src/core/lib/iomgr/ev_epoll_limited_pollers_linux.c @@ -0,0 +1,1957 @@ +/* + * + * Copyright 2017 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 "src/core/lib/iomgr/port.h" + +/* This polling engine is only relevant on linux kernels supporting epoll() */ +#ifdef GRPC_LINUX_EPOLL + +#include "src/core/lib/iomgr/ev_epoll_limited_pollers_linux.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "src/core/lib/debug/trace.h" +#include "src/core/lib/iomgr/ev_posix.h" +#include "src/core/lib/iomgr/iomgr_internal.h" +#include "src/core/lib/iomgr/lockfree_event.h" +#include "src/core/lib/iomgr/timer.h" +#include "src/core/lib/iomgr/wakeup_fd_posix.h" +#include "src/core/lib/profiling/timers.h" +#include "src/core/lib/support/block_annotate.h" +#include "src/core/lib/support/env.h" + +#define GRPC_POLLING_TRACE(fmt, ...) \ + if (GRPC_TRACER_ON(grpc_polling_trace)) { \ + gpr_log(GPR_INFO, (fmt), __VA_ARGS__); \ + } + +#define GRPC_POLLSET_KICK_BROADCAST ((grpc_pollset_worker *)1) + +/* The maximum number of polling threads per polling island. By default no + limit */ +static int g_max_pollers_per_pi = INT_MAX; + +static int grpc_wakeup_signal = -1; +static bool is_grpc_wakeup_signal_initialized = false; + +/* Implements the function defined in grpc_posix.h. This function might be + * called before even calling grpc_init() to set either a different signal to + * use. If signum == -1, then the use of signals is disabled */ +static void grpc_use_signal(int signum) { + grpc_wakeup_signal = signum; + is_grpc_wakeup_signal_initialized = true; + + if (grpc_wakeup_signal < 0) { + gpr_log(GPR_INFO, + "Use of signals is disabled. Epoll engine will not be used"); + } else { + gpr_log(GPR_INFO, "epoll engine will be using signal: %d", + grpc_wakeup_signal); + } +} + +struct polling_island; + +typedef enum { + POLL_OBJ_FD, + POLL_OBJ_POLLSET, + POLL_OBJ_POLLSET_SET +} poll_obj_type; + +typedef struct poll_obj { +#ifndef NDEBUG + poll_obj_type obj_type; +#endif + gpr_mu mu; + struct polling_island *pi; +} poll_obj; + +static const char *poll_obj_string(poll_obj_type po_type) { + switch (po_type) { + case POLL_OBJ_FD: + return "fd"; + case POLL_OBJ_POLLSET: + return "pollset"; + case POLL_OBJ_POLLSET_SET: + return "pollset_set"; + } + + GPR_UNREACHABLE_CODE(return "UNKNOWN"); +} + +/******************************************************************************* + * Fd Declarations + */ + +#define FD_FROM_PO(po) ((grpc_fd *)(po)) + +struct grpc_fd { + poll_obj po; + + int fd; + /* refst format: + bit 0 : 1=Active / 0=Orphaned + bits 1-n : refcount + Ref/Unref by two to avoid altering the orphaned bit */ + gpr_atm refst; + + /* The fd is either closed or we relinquished control of it. In either + cases, this indicates that the 'fd' on this structure is no longer + valid */ + bool orphaned; + + gpr_atm read_closure; + gpr_atm write_closure; + + struct grpc_fd *freelist_next; + grpc_closure *on_done_closure; + + /* The pollset that last noticed that the fd is readable. The actual type + * stored in this is (grpc_pollset *) */ + gpr_atm read_notifier_pollset; + + grpc_iomgr_object iomgr_object; +}; + +/* Reference counting for fds */ +#ifndef NDEBUG +static void fd_ref(grpc_fd *fd, const char *reason, const char *file, int line); +static void fd_unref(grpc_fd *fd, const char *reason, const char *file, + int line); +#define GRPC_FD_REF(fd, reason) fd_ref(fd, reason, __FILE__, __LINE__) +#define GRPC_FD_UNREF(fd, reason) fd_unref(fd, reason, __FILE__, __LINE__) +#else +static void fd_ref(grpc_fd *fd); +static void fd_unref(grpc_fd *fd); +#define GRPC_FD_REF(fd, reason) fd_ref(fd) +#define GRPC_FD_UNREF(fd, reason) fd_unref(fd) +#endif + +static void fd_global_init(void); +static void fd_global_shutdown(void); + +/******************************************************************************* + * Polling island Declarations + */ + +#ifndef NDEBUG + +#define PI_ADD_REF(p, r) pi_add_ref_dbg((p), (r), __FILE__, __LINE__) +#define PI_UNREF(exec_ctx, p, r) \ + pi_unref_dbg((exec_ctx), (p), (r), __FILE__, __LINE__) + +#else + +#define PI_ADD_REF(p, r) pi_add_ref((p)) +#define PI_UNREF(exec_ctx, p, r) pi_unref((exec_ctx), (p)) + +#endif + +typedef struct worker_node { + struct worker_node *next; + struct worker_node *prev; +} worker_node; + +/* This is also used as grpc_workqueue (by directly casing it) */ +typedef struct polling_island { + gpr_mu mu; + /* Ref count. Use PI_ADD_REF() and PI_UNREF() macros to increment/decrement + the refcount. + Once the ref count becomes zero, this structure is destroyed which means + we should ensure that there is never a scenario where a PI_ADD_REF() is + racing with a PI_UNREF() that just made the ref_count zero. */ + gpr_atm ref_count; + + /* Pointer to the polling_island this merged into. + * merged_to value is only set once in polling_island's lifetime (and that too + * only if the island is merged with another island). Because of this, we can + * use gpr_atm type here so that we can do atomic access on this and reduce + * lock contention on 'mu' mutex. + * + * Note that if this field is not NULL (i.e not 0), all the remaining fields + * (except mu and ref_count) are invalid and must be ignored. */ + gpr_atm merged_to; + + /* Number of threads currently polling on this island */ + gpr_atm poller_count; + + /* The list of workers waiting to do polling on this polling island */ + gpr_mu worker_list_mu; + worker_node worker_list_head; + + /* The fd of the underlying epoll set */ + int epoll_fd; + + /* The file descriptors in the epoll set */ + size_t fd_cnt; + size_t fd_capacity; + grpc_fd **fds; +} polling_island; + +/******************************************************************************* + * Pollset Declarations + */ +#define WORKER_FROM_WORKER_LIST_NODE(p) \ + (struct grpc_pollset_worker *)(((char *)(p)) - \ + offsetof(grpc_pollset_worker, pi_list_link)) +struct grpc_pollset_worker { + /* Thread id of this worker */ + pthread_t pt_id; + + /* Used to prevent a worker from getting kicked multiple times */ + gpr_atm is_kicked; + + struct grpc_pollset_worker *next; + struct grpc_pollset_worker *prev; + + /* Indicates if it is this worker's turn to do epoll */ + gpr_atm is_polling_turn; + + /* Node in the polling island's worker list. */ + worker_node pi_list_link; +}; + +struct grpc_pollset { + poll_obj po; + + grpc_pollset_worker root_worker; + bool kicked_without_pollers; + + bool shutting_down; /* Is the pollset shutting down ? */ + bool finish_shutdown_called; /* Is the 'finish_shutdown_locked()' called ? */ + grpc_closure *shutdown_done; /* Called after after shutdown is complete */ +}; + +/******************************************************************************* + * Pollset-set Declarations + */ +struct grpc_pollset_set { + poll_obj po; +}; + +/******************************************************************************* + * Common helpers + */ + +static bool append_error(grpc_error **composite, grpc_error *error, + const char *desc) { + if (error == GRPC_ERROR_NONE) return true; + if (*composite == GRPC_ERROR_NONE) { + *composite = GRPC_ERROR_CREATE_FROM_COPIED_STRING(desc); + } + *composite = grpc_error_add_child(*composite, error); + return false; +} + +/******************************************************************************* + * Polling island Definitions + */ + +/* The wakeup fd that is used to wake up all threads in a Polling island. This + is useful in the polling island merge operation where we need to wakeup all + the threads currently polling the smaller polling island (so that they can + start polling the new/merged polling island) + + NOTE: This fd is initialized to be readable and MUST NOT be consumed i.e the + threads that woke up MUST NOT call grpc_wakeup_fd_consume_wakeup() */ +static grpc_wakeup_fd polling_island_wakeup_fd; + +/* The polling island being polled right now. + See comments in workqueue_maybe_wakeup for why this is tracked. */ +static __thread polling_island *g_current_thread_polling_island; + +/* Forward declaration */ +static void polling_island_delete(grpc_exec_ctx *exec_ctx, polling_island *pi); + +#ifdef GRPC_TSAN +/* Currently TSAN may incorrectly flag data races between epoll_ctl and + epoll_wait for any grpc_fd structs that are added to the epoll set via + epoll_ctl and are returned (within a very short window) via epoll_wait(). + + To work-around this race, we establish a happens-before relation between + the code just-before epoll_ctl() and the code after epoll_wait() by using + this atomic */ +gpr_atm g_epoll_sync; +#endif /* defined(GRPC_TSAN) */ + +static void pi_add_ref(polling_island *pi); +static void pi_unref(grpc_exec_ctx *exec_ctx, polling_island *pi); + +#ifndef NDEBUG +static void pi_add_ref_dbg(polling_island *pi, const char *reason, + const char *file, int line) { + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_atm old_cnt = gpr_atm_acq_load(&pi->ref_count); + gpr_log(GPR_DEBUG, "Add ref pi: %p, old:%" PRIdPTR " -> new:%" PRIdPTR + " (%s) - (%s, %d)", + pi, old_cnt, old_cnt + 1, reason, file, line); + } + pi_add_ref(pi); +} + +static void pi_unref_dbg(grpc_exec_ctx *exec_ctx, polling_island *pi, + const char *reason, const char *file, int line) { + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_atm old_cnt = gpr_atm_acq_load(&pi->ref_count); + gpr_log(GPR_DEBUG, "Unref pi: %p, old:%" PRIdPTR " -> new:%" PRIdPTR + " (%s) - (%s, %d)", + pi, old_cnt, (old_cnt - 1), reason, file, line); + } + pi_unref(exec_ctx, pi); +} +#endif + +static void pi_add_ref(polling_island *pi) { + gpr_atm_no_barrier_fetch_add(&pi->ref_count, 1); +} + +static void pi_unref(grpc_exec_ctx *exec_ctx, polling_island *pi) { + /* If ref count went to zero, delete the polling island. + Note that this deletion not be done under a lock. Once the ref count goes + to zero, we are guaranteed that no one else holds a reference to the + polling island (and that there is no racing pi_add_ref() call either). + + Also, if we are deleting the polling island and the merged_to field is + non-empty, we should remove a ref to the merged_to polling island + */ + if (1 == gpr_atm_full_fetch_add(&pi->ref_count, -1)) { + polling_island *next = (polling_island *)gpr_atm_acq_load(&pi->merged_to); + polling_island_delete(exec_ctx, pi); + if (next != NULL) { + PI_UNREF(exec_ctx, next, "pi_delete"); /* Recursive call */ + } + } +} + +static void worker_node_init(worker_node *node) { + node->next = node->prev = node; +} + +/* Not thread safe. Do under a list-level lock */ +static void push_back_worker_node(worker_node *head, worker_node *node) { + node->next = head; + node->prev = head->prev; + head->prev->next = node; + head->prev = node; +} + +/* Not thread safe. Do under a list-level lock */ +static void remove_worker_node(worker_node *node) { + node->next->prev = node->prev; + node->prev->next = node->next; + /* If node's next and prev point to itself, the node is considered detached + * from the list*/ + node->next = node->prev = node; +} + +/* Not thread safe. Do under a list-level lock */ +static worker_node *pop_front_worker_node(worker_node *head) { + worker_node *node = head->next; + if (node != head) { + remove_worker_node(node); + } else { + node = NULL; + } + + return node; +} + +/* Returns true if the node's next and prev are pointing to itself (which + indicates that the node is not in the list */ +static bool is_worker_node_detached(worker_node *node) { + return (node->next == node->prev && node->next == node); +} + +/* The caller is expected to hold pi->mu lock before calling this function + */ +static void polling_island_add_fds_locked(polling_island *pi, grpc_fd **fds, + size_t fd_count, bool add_fd_refs, + grpc_error **error) { + int err; + size_t i; + struct epoll_event ev; + char *err_msg; + const char *err_desc = "polling_island_add_fds"; + +#ifdef GRPC_TSAN + /* See the definition of g_epoll_sync for more context */ + gpr_atm_rel_store(&g_epoll_sync, (gpr_atm)0); +#endif /* defined(GRPC_TSAN) */ + + for (i = 0; i < fd_count; i++) { + ev.events = (uint32_t)(EPOLLIN | EPOLLOUT | EPOLLET); + ev.data.ptr = fds[i]; + err = epoll_ctl(pi->epoll_fd, EPOLL_CTL_ADD, fds[i]->fd, &ev); + + if (err < 0) { + if (errno != EEXIST) { + gpr_asprintf( + &err_msg, + "epoll_ctl (epoll_fd: %d) add fd: %d failed with error: %d (%s)", + pi->epoll_fd, fds[i]->fd, errno, strerror(errno)); + append_error(error, GRPC_OS_ERROR(errno, err_msg), err_desc); + gpr_free(err_msg); + } + + continue; + } + + if (pi->fd_cnt == pi->fd_capacity) { + pi->fd_capacity = GPR_MAX(pi->fd_capacity + 8, pi->fd_cnt * 3 / 2); + pi->fds = gpr_realloc(pi->fds, sizeof(grpc_fd *) * pi->fd_capacity); + } + + pi->fds[pi->fd_cnt++] = fds[i]; + if (add_fd_refs) { + GRPC_FD_REF(fds[i], "polling_island"); + } + } +} + +/* The caller is expected to hold pi->mu before calling this */ +static void polling_island_add_wakeup_fd_locked(polling_island *pi, + grpc_wakeup_fd *wakeup_fd, + grpc_error **error) { + struct epoll_event ev; + int err; + char *err_msg; + const char *err_desc = "polling_island_add_wakeup_fd"; + + ev.events = (uint32_t)(EPOLLIN | EPOLLET); + ev.data.ptr = wakeup_fd; + err = epoll_ctl(pi->epoll_fd, EPOLL_CTL_ADD, + GRPC_WAKEUP_FD_GET_READ_FD(wakeup_fd), &ev); + if (err < 0 && errno != EEXIST) { + gpr_asprintf(&err_msg, + "epoll_ctl (epoll_fd: %d) add wakeup fd: %d failed with " + "error: %d (%s)", + pi->epoll_fd, GRPC_WAKEUP_FD_GET_READ_FD(wakeup_fd), errno, + strerror(errno)); + append_error(error, GRPC_OS_ERROR(errno, err_msg), err_desc); + gpr_free(err_msg); + } +} + +/* The caller is expected to hold pi->mu lock before calling this function */ +static void polling_island_remove_all_fds_locked(polling_island *pi, + bool remove_fd_refs, + grpc_error **error) { + int err; + size_t i; + char *err_msg; + const char *err_desc = "polling_island_remove_fds"; + + for (i = 0; i < pi->fd_cnt; i++) { + err = epoll_ctl(pi->epoll_fd, EPOLL_CTL_DEL, pi->fds[i]->fd, NULL); + if (err < 0 && errno != ENOENT) { + gpr_asprintf(&err_msg, + "epoll_ctl (epoll_fd: %d) delete fds[%zu]: %d failed with " + "error: %d (%s)", + pi->epoll_fd, i, pi->fds[i]->fd, errno, strerror(errno)); + append_error(error, GRPC_OS_ERROR(errno, err_msg), err_desc); + gpr_free(err_msg); + } + + if (remove_fd_refs) { + GRPC_FD_UNREF(pi->fds[i], "polling_island"); + } + } + + pi->fd_cnt = 0; +} + +/* The caller is expected to hold pi->mu lock before calling this function */ +static void polling_island_remove_fd_locked(polling_island *pi, grpc_fd *fd, + bool is_fd_closed, + grpc_error **error) { + int err; + size_t i; + char *err_msg; + const char *err_desc = "polling_island_remove_fd"; + + /* If fd is already closed, then it would have been automatically been removed + from the epoll set */ + if (!is_fd_closed) { + err = epoll_ctl(pi->epoll_fd, EPOLL_CTL_DEL, fd->fd, NULL); + if (err < 0 && errno != ENOENT) { + gpr_asprintf( + &err_msg, + "epoll_ctl (epoll_fd: %d) del fd: %d failed with error: %d (%s)", + pi->epoll_fd, fd->fd, errno, strerror(errno)); + append_error(error, GRPC_OS_ERROR(errno, err_msg), err_desc); + gpr_free(err_msg); + } + } + + for (i = 0; i < pi->fd_cnt; i++) { + if (pi->fds[i] == fd) { + pi->fds[i] = pi->fds[--pi->fd_cnt]; + GRPC_FD_UNREF(fd, "polling_island"); + break; + } + } +} + +/* Might return NULL in case of an error */ +static polling_island *polling_island_create(grpc_exec_ctx *exec_ctx, + grpc_fd *initial_fd, + grpc_error **error) { + polling_island *pi = NULL; + const char *err_desc = "polling_island_create"; + + *error = GRPC_ERROR_NONE; + + pi = gpr_malloc(sizeof(*pi)); + gpr_mu_init(&pi->mu); + pi->fd_cnt = 0; + pi->fd_capacity = 0; + pi->fds = NULL; + pi->epoll_fd = -1; + + gpr_atm_rel_store(&pi->ref_count, 0); + gpr_atm_rel_store(&pi->poller_count, 0); + gpr_atm_rel_store(&pi->merged_to, (gpr_atm)NULL); + + gpr_mu_init(&pi->worker_list_mu); + worker_node_init(&pi->worker_list_head); + + pi->epoll_fd = epoll_create1(EPOLL_CLOEXEC); + + if (pi->epoll_fd < 0) { + append_error(error, GRPC_OS_ERROR(errno, "epoll_create1"), err_desc); + goto done; + } + + if (initial_fd != NULL) { + polling_island_add_fds_locked(pi, &initial_fd, 1, true, error); + } + +done: + if (*error != GRPC_ERROR_NONE) { + polling_island_delete(exec_ctx, pi); + pi = NULL; + } + return pi; +} + +static void polling_island_delete(grpc_exec_ctx *exec_ctx, polling_island *pi) { + GPR_ASSERT(pi->fd_cnt == 0); + + if (pi->epoll_fd >= 0) { + close(pi->epoll_fd); + } + gpr_mu_destroy(&pi->mu); + gpr_mu_destroy(&pi->worker_list_mu); + GPR_ASSERT(is_worker_node_detached(&pi->worker_list_head)); + + gpr_free(pi->fds); + gpr_free(pi); +} + +/* Attempts to gets the last polling island in the linked list (liked by the + * 'merged_to' field). Since this does not lock the polling island, there are no + * guarantees that the island returned is the last island */ +static polling_island *polling_island_maybe_get_latest(polling_island *pi) { + polling_island *next = (polling_island *)gpr_atm_acq_load(&pi->merged_to); + while (next != NULL) { + pi = next; + next = (polling_island *)gpr_atm_acq_load(&pi->merged_to); + } + + return pi; +} + +/* Gets the lock on the *latest* polling island i.e the last polling island in + the linked list (linked by the 'merged_to' field). Call gpr_mu_unlock on the + returned polling island's mu. + Usage: To lock/unlock polling island "pi", do the following: + polling_island *pi_latest = polling_island_lock(pi); + ... + ... critical section .. + ... + gpr_mu_unlock(&pi_latest->mu); // NOTE: use pi_latest->mu. NOT pi->mu */ +static polling_island *polling_island_lock(polling_island *pi) { + polling_island *next = NULL; + + while (true) { + next = (polling_island *)gpr_atm_acq_load(&pi->merged_to); + if (next == NULL) { + /* Looks like 'pi' is the last node in the linked list but unless we check + this by holding the pi->mu lock, we cannot be sure (i.e without the + pi->mu lock, we don't prevent island merges). + To be absolutely sure, check once more by holding the pi->mu lock */ + gpr_mu_lock(&pi->mu); + next = (polling_island *)gpr_atm_acq_load(&pi->merged_to); + if (next == NULL) { + /* pi is infact the last node and we have the pi->mu lock. we're done */ + break; + } + + /* pi->merged_to is not NULL i.e pi isn't the last node anymore. pi->mu + * isn't the lock we are interested in. Continue traversing the list */ + gpr_mu_unlock(&pi->mu); + } + + pi = next; + } + + return pi; +} + +/* Gets the lock on the *latest* polling islands in the linked lists pointed by + *p and *q (and also updates *p and *q to point to the latest polling islands) + + This function is needed because calling the following block of code to obtain + locks on polling islands (*p and *q) is prone to deadlocks. + { + polling_island_lock(*p, true); + polling_island_lock(*q, true); + } + + Usage/example: + polling_island *p1; + polling_island *p2; + .. + polling_island_lock_pair(&p1, &p2); + .. + .. Critical section with both p1 and p2 locked + .. + // Release locks: Always call polling_island_unlock_pair() to release locks + polling_island_unlock_pair(p1, p2); +*/ +static void polling_island_lock_pair(polling_island **p, polling_island **q) { + polling_island *pi_1 = *p; + polling_island *pi_2 = *q; + polling_island *next_1 = NULL; + polling_island *next_2 = NULL; + + /* The algorithm is simple: + - Go to the last polling islands in the linked lists *pi_1 and *pi_2 (and + keep updating pi_1 and pi_2) + - Then obtain locks on the islands by following a lock order rule of + locking polling_island with lower address first + Special case: Before obtaining the locks, check if pi_1 and pi_2 are + pointing to the same island. If that is the case, we can just call + polling_island_lock() + - After obtaining both the locks, double check that the polling islands + are still the last polling islands in their respective linked lists + (this is because there might have been polling island merges before + we got the lock) + - If the polling islands are the last islands, we are done. If not, + release the locks and continue the process from the first step */ + while (true) { + next_1 = (polling_island *)gpr_atm_acq_load(&pi_1->merged_to); + while (next_1 != NULL) { + pi_1 = next_1; + next_1 = (polling_island *)gpr_atm_acq_load(&pi_1->merged_to); + } + + next_2 = (polling_island *)gpr_atm_acq_load(&pi_2->merged_to); + while (next_2 != NULL) { + pi_2 = next_2; + next_2 = (polling_island *)gpr_atm_acq_load(&pi_2->merged_to); + } + + if (pi_1 == pi_2) { + pi_1 = pi_2 = polling_island_lock(pi_1); + break; + } + + if (pi_1 < pi_2) { + gpr_mu_lock(&pi_1->mu); + gpr_mu_lock(&pi_2->mu); + } else { + gpr_mu_lock(&pi_2->mu); + gpr_mu_lock(&pi_1->mu); + } + + next_1 = (polling_island *)gpr_atm_acq_load(&pi_1->merged_to); + next_2 = (polling_island *)gpr_atm_acq_load(&pi_2->merged_to); + if (next_1 == NULL && next_2 == NULL) { + break; + } + + gpr_mu_unlock(&pi_1->mu); + gpr_mu_unlock(&pi_2->mu); + } + + *p = pi_1; + *q = pi_2; +} + +static void polling_island_unlock_pair(polling_island *p, polling_island *q) { + if (p == q) { + gpr_mu_unlock(&p->mu); + } else { + gpr_mu_unlock(&p->mu); + gpr_mu_unlock(&q->mu); + } +} + +static polling_island *polling_island_merge(polling_island *p, + polling_island *q, + grpc_error **error) { + /* Get locks on both the polling islands */ + polling_island_lock_pair(&p, &q); + + if (p != q) { + /* Make sure that p points to the polling island with fewer fds than q */ + if (p->fd_cnt > q->fd_cnt) { + GPR_SWAP(polling_island *, p, q); + } + + /* Merge p with q i.e move all the fds from p (The one with fewer fds) to q + Note that the refcounts on the fds being moved will not change here. + This is why the last param in the following two functions is 'false') */ + polling_island_add_fds_locked(q, p->fds, p->fd_cnt, false, error); + polling_island_remove_all_fds_locked(p, false, error); + + /* Wakeup all the pollers (if any) on p so that they pickup this change */ + polling_island_add_wakeup_fd_locked(p, &polling_island_wakeup_fd, error); + + /* Add the 'merged_to' link from p --> q */ + gpr_atm_rel_store(&p->merged_to, (gpr_atm)q); + PI_ADD_REF(q, "pi_merge"); /* To account for the new incoming ref from p */ + } + /* else if p == q, nothing needs to be done */ + + polling_island_unlock_pair(p, q); + + /* Return the merged polling island (Note that no merge would have happened + if p == q which is ok) */ + return q; +} + +static grpc_error *polling_island_global_init() { + grpc_error *error = GRPC_ERROR_NONE; + + error = grpc_wakeup_fd_init(&polling_island_wakeup_fd); + if (error == GRPC_ERROR_NONE) { + error = grpc_wakeup_fd_wakeup(&polling_island_wakeup_fd); + } + + return error; +} + +static void polling_island_global_shutdown() { + grpc_wakeup_fd_destroy(&polling_island_wakeup_fd); +} + +/******************************************************************************* + * Fd Definitions + */ + +/* We need to keep a freelist not because of any concerns of malloc performance + * but instead so that implementations with multiple threads in (for example) + * epoll_wait deal with the race between pollset removal and incoming poll + * notifications. + * + * The problem is that the poller ultimately holds a reference to this + * object, so it is very difficult to know when is safe to free it, at least + * without some expensive synchronization. + * + * If we keep the object freelisted, in the worst case losing this race just + * becomes a spurious read notification on a reused fd. + */ + +/* The alarm system needs to be able to wakeup 'some poller' sometimes + * (specifically when a new alarm needs to be triggered earlier than the next + * alarm 'epoch'). This wakeup_fd gives us something to alert on when such a + * case occurs. */ + +static grpc_fd *fd_freelist = NULL; +static gpr_mu fd_freelist_mu; + +#ifndef NDEBUG +#define REF_BY(fd, n, reason) ref_by(fd, n, reason, __FILE__, __LINE__) +#define UNREF_BY(fd, n, reason) unref_by(fd, n, reason, __FILE__, __LINE__) +static void ref_by(grpc_fd *fd, int n, const char *reason, const char *file, + int line) { + if (GRPC_TRACER_ON(grpc_trace_fd_refcount)) { + gpr_log(GPR_DEBUG, + "FD %d %p ref %d %" PRIdPTR " -> %" PRIdPTR " [%s; %s:%d]", + fd->fd, fd, n, gpr_atm_no_barrier_load(&fd->refst), + gpr_atm_no_barrier_load(&fd->refst) + n, reason, file, line); + } +#else +#define REF_BY(fd, n, reason) ref_by(fd, n) +#define UNREF_BY(fd, n, reason) unref_by(fd, n) +static void ref_by(grpc_fd *fd, int n) { +#endif + GPR_ASSERT(gpr_atm_no_barrier_fetch_add(&fd->refst, n) > 0); +} + +#ifndef NDEBUG +static void unref_by(grpc_fd *fd, int n, const char *reason, const char *file, + int line) { + if (GRPC_TRACER_ON(grpc_trace_fd_refcount)) { + gpr_log(GPR_DEBUG, + "FD %d %p unref %d %" PRIdPTR " -> %" PRIdPTR " [%s; %s:%d]", + fd->fd, fd, n, gpr_atm_no_barrier_load(&fd->refst), + gpr_atm_no_barrier_load(&fd->refst) - n, reason, file, line); + } +#else +static void unref_by(grpc_fd *fd, int n) { +#endif + gpr_atm old = gpr_atm_full_fetch_add(&fd->refst, -n); + if (old == n) { + /* Add the fd to the freelist */ + gpr_mu_lock(&fd_freelist_mu); + fd->freelist_next = fd_freelist; + fd_freelist = fd; + grpc_iomgr_unregister_object(&fd->iomgr_object); + + grpc_lfev_destroy(&fd->read_closure); + grpc_lfev_destroy(&fd->write_closure); + + gpr_mu_unlock(&fd_freelist_mu); + } else { + GPR_ASSERT(old > n); + } +} + +/* Increment refcount by two to avoid changing the orphan bit */ +#ifndef NDEBUG +static void fd_ref(grpc_fd *fd, const char *reason, const char *file, + int line) { + ref_by(fd, 2, reason, file, line); +} + +static void fd_unref(grpc_fd *fd, const char *reason, const char *file, + int line) { + unref_by(fd, 2, reason, file, line); +} +#else +static void fd_ref(grpc_fd *fd) { ref_by(fd, 2); } +static void fd_unref(grpc_fd *fd) { unref_by(fd, 2); } +#endif + +static void fd_global_init(void) { gpr_mu_init(&fd_freelist_mu); } + +static void fd_global_shutdown(void) { + gpr_mu_lock(&fd_freelist_mu); + gpr_mu_unlock(&fd_freelist_mu); + while (fd_freelist != NULL) { + grpc_fd *fd = fd_freelist; + fd_freelist = fd_freelist->freelist_next; + gpr_mu_destroy(&fd->po.mu); + gpr_free(fd); + } + gpr_mu_destroy(&fd_freelist_mu); +} + +static grpc_fd *fd_create(int fd, const char *name) { + grpc_fd *new_fd = NULL; + + gpr_mu_lock(&fd_freelist_mu); + if (fd_freelist != NULL) { + new_fd = fd_freelist; + fd_freelist = fd_freelist->freelist_next; + } + gpr_mu_unlock(&fd_freelist_mu); + + if (new_fd == NULL) { + new_fd = gpr_malloc(sizeof(grpc_fd)); + gpr_mu_init(&new_fd->po.mu); + } + + /* Note: It is not really needed to get the new_fd->po.mu lock here. If this + * is a newly created fd (or an fd we got from the freelist), no one else + * would be holding a lock to it anyway. */ + gpr_mu_lock(&new_fd->po.mu); + new_fd->po.pi = NULL; +#ifndef NDEBUG + new_fd->po.obj_type = POLL_OBJ_FD; +#endif + + gpr_atm_rel_store(&new_fd->refst, (gpr_atm)1); + new_fd->fd = fd; + new_fd->orphaned = false; + grpc_lfev_init(&new_fd->read_closure); + grpc_lfev_init(&new_fd->write_closure); + gpr_atm_no_barrier_store(&new_fd->read_notifier_pollset, (gpr_atm)NULL); + + new_fd->freelist_next = NULL; + new_fd->on_done_closure = NULL; + + gpr_mu_unlock(&new_fd->po.mu); + + char *fd_name; + gpr_asprintf(&fd_name, "%s fd=%d", name, fd); + grpc_iomgr_register_object(&new_fd->iomgr_object, fd_name); +#ifndef NDEBUG + if (GRPC_TRACER_ON(grpc_trace_fd_refcount)) { + gpr_log(GPR_DEBUG, "FD %d %p create %s", fd, new_fd, fd_name); + } +#endif + gpr_free(fd_name); + return new_fd; +} + +static int fd_wrapped_fd(grpc_fd *fd) { + int ret_fd = -1; + gpr_mu_lock(&fd->po.mu); + if (!fd->orphaned) { + ret_fd = fd->fd; + } + gpr_mu_unlock(&fd->po.mu); + + return ret_fd; +} + +static void fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd, + grpc_closure *on_done, int *release_fd, + bool already_closed, const char *reason) { + grpc_error *error = GRPC_ERROR_NONE; + polling_island *unref_pi = NULL; + + gpr_mu_lock(&fd->po.mu); + fd->on_done_closure = on_done; + + /* Remove the active status but keep referenced. We want this grpc_fd struct + to be alive (and not added to freelist) until the end of this function */ + REF_BY(fd, 1, reason); + + /* Remove the fd from the polling island: + - Get a lock on the latest polling island (i.e the last island in the + linked list pointed by fd->po.pi). This is the island that + would actually contain the fd + - Remove the fd from the latest polling island + - Unlock the latest polling island + - Set fd->po.pi to NULL (but remove the ref on the polling island + before doing this.) */ + if (fd->po.pi != NULL) { + polling_island *pi_latest = polling_island_lock(fd->po.pi); + polling_island_remove_fd_locked(pi_latest, fd, already_closed, &error); + gpr_mu_unlock(&pi_latest->mu); + + unref_pi = fd->po.pi; + fd->po.pi = NULL; + } + + /* If release_fd is not NULL, we should be relinquishing control of the file + descriptor fd->fd (but we still own the grpc_fd structure). */ + if (release_fd != NULL) { + *release_fd = fd->fd; + } else { + close(fd->fd); + } + + fd->orphaned = true; + + GRPC_CLOSURE_SCHED(exec_ctx, fd->on_done_closure, GRPC_ERROR_REF(error)); + + gpr_mu_unlock(&fd->po.mu); + UNREF_BY(fd, 2, reason); /* Drop the reference */ + if (unref_pi != NULL) { + /* Unref stale polling island here, outside the fd lock above. + The polling island owns a workqueue which owns an fd, and unreffing + inside the lock can cause an eventual lock loop that makes TSAN very + unhappy. */ + PI_UNREF(exec_ctx, unref_pi, "fd_orphan"); + } + GRPC_LOG_IF_ERROR("fd_orphan", GRPC_ERROR_REF(error)); + GRPC_ERROR_UNREF(error); +} + +static grpc_pollset *fd_get_read_notifier_pollset(grpc_exec_ctx *exec_ctx, + grpc_fd *fd) { + gpr_atm notifier = gpr_atm_acq_load(&fd->read_notifier_pollset); + return (grpc_pollset *)notifier; +} + +static bool fd_is_shutdown(grpc_fd *fd) { + return grpc_lfev_is_shutdown(&fd->read_closure); +} + +/* Might be called multiple times */ +static void fd_shutdown(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_error *why) { + if (grpc_lfev_set_shutdown(exec_ctx, &fd->read_closure, + GRPC_ERROR_REF(why))) { + shutdown(fd->fd, SHUT_RDWR); + grpc_lfev_set_shutdown(exec_ctx, &fd->write_closure, GRPC_ERROR_REF(why)); + } + GRPC_ERROR_UNREF(why); +} + +static void fd_notify_on_read(grpc_exec_ctx *exec_ctx, grpc_fd *fd, + grpc_closure *closure) { + grpc_lfev_notify_on(exec_ctx, &fd->read_closure, closure, "read"); +} + +static void fd_notify_on_write(grpc_exec_ctx *exec_ctx, grpc_fd *fd, + grpc_closure *closure) { + grpc_lfev_notify_on(exec_ctx, &fd->write_closure, closure, "write"); +} + +/******************************************************************************* + * Pollset Definitions + */ +GPR_TLS_DECL(g_current_thread_pollset); +GPR_TLS_DECL(g_current_thread_worker); +static __thread bool g_initialized_sigmask; +static __thread sigset_t g_orig_sigmask; +static __thread sigset_t g_wakeup_sig_set; + +static void sig_handler(int sig_num) { +#ifdef GRPC_EPOLL_DEBUG + gpr_log(GPR_INFO, "Received signal %d", sig_num); +#endif +} + +static void pollset_worker_init(grpc_pollset_worker *worker) { + worker->pt_id = pthread_self(); + worker->next = worker->prev = NULL; + gpr_atm_no_barrier_store(&worker->is_kicked, (gpr_atm)0); + gpr_atm_no_barrier_store(&worker->is_polling_turn, (gpr_atm)0); + worker_node_init(&worker->pi_list_link); +} + +static void poller_kick_init() { signal(grpc_wakeup_signal, sig_handler); } + +/* Global state management */ +static grpc_error *pollset_global_init(void) { + gpr_tls_init(&g_current_thread_pollset); + gpr_tls_init(&g_current_thread_worker); + poller_kick_init(); + return GRPC_ERROR_NONE; +} + +static void pollset_global_shutdown(void) { + gpr_tls_destroy(&g_current_thread_pollset); + gpr_tls_destroy(&g_current_thread_worker); +} + +static grpc_error *worker_kick(grpc_pollset_worker *worker, + gpr_atm *is_kicked) { + grpc_error *err = GRPC_ERROR_NONE; + + /* Kick the worker only if it was not already kicked */ + if (gpr_atm_no_barrier_cas(is_kicked, (gpr_atm)0, (gpr_atm)1)) { + GRPC_POLLING_TRACE( + "pollset_worker_kick: Kicking worker: %p (thread id: %ld)", + (void *)worker, (long int)worker->pt_id); + int err_num = pthread_kill(worker->pt_id, grpc_wakeup_signal); + if (err_num != 0) { + err = GRPC_OS_ERROR(err_num, "pthread_kill"); + } + } + return err; +} + +static grpc_error *pollset_worker_kick(grpc_pollset_worker *worker) { + return worker_kick(worker, &worker->is_kicked); +} + +static grpc_error *poller_kick(grpc_pollset_worker *worker) { + return worker_kick(worker, &worker->is_polling_turn); +} + +/* Return 1 if the pollset has active threads in pollset_work (pollset must + * be locked) */ +static int pollset_has_workers(grpc_pollset *p) { + return p->root_worker.next != &p->root_worker; +} + +static void remove_worker(grpc_pollset *p, grpc_pollset_worker *worker) { + worker->prev->next = worker->next; + worker->next->prev = worker->prev; +} + +static grpc_pollset_worker *pop_front_worker(grpc_pollset *p) { + if (pollset_has_workers(p)) { + grpc_pollset_worker *w = p->root_worker.next; + remove_worker(p, w); + return w; + } else { + return NULL; + } +} + +static void push_back_worker(grpc_pollset *p, grpc_pollset_worker *worker) { + worker->next = &p->root_worker; + worker->prev = worker->next->prev; + worker->prev->next = worker->next->prev = worker; +} + +static void push_front_worker(grpc_pollset *p, grpc_pollset_worker *worker) { + worker->prev = &p->root_worker; + worker->next = worker->prev->next; + worker->prev->next = worker->next->prev = worker; +} + +/* p->mu must be held before calling this function */ +static grpc_error *pollset_kick(grpc_pollset *p, + grpc_pollset_worker *specific_worker) { + GPR_TIMER_BEGIN("pollset_kick", 0); + grpc_error *error = GRPC_ERROR_NONE; + const char *err_desc = "Kick Failure"; + grpc_pollset_worker *worker = specific_worker; + if (worker != NULL) { + if (worker == GRPC_POLLSET_KICK_BROADCAST) { + if (pollset_has_workers(p)) { + GPR_TIMER_BEGIN("pollset_kick.broadcast", 0); + for (worker = p->root_worker.next; worker != &p->root_worker; + worker = worker->next) { + if (gpr_tls_get(&g_current_thread_worker) != (intptr_t)worker) { + append_error(&error, pollset_worker_kick(worker), err_desc); + } + } + GPR_TIMER_END("pollset_kick.broadcast", 0); + } else { + p->kicked_without_pollers = true; + } + } else { + GPR_TIMER_MARK("kicked_specifically", 0); + if (gpr_tls_get(&g_current_thread_worker) != (intptr_t)worker) { + append_error(&error, pollset_worker_kick(worker), err_desc); + } + } + } else if (gpr_tls_get(&g_current_thread_pollset) != (intptr_t)p) { + /* Since worker == NULL, it means that we can kick "any" worker on this + pollset 'p'. If 'p' happens to be the same pollset this thread is + currently polling (i.e in pollset_work() function), then there is no need + to kick any other worker since the current thread can just absorb the + kick. This is the reason why we enter this case only when + g_current_thread_pollset is != p */ + + GPR_TIMER_MARK("kick_anonymous", 0); + worker = pop_front_worker(p); + if (worker != NULL) { + GPR_TIMER_MARK("finally_kick", 0); + push_back_worker(p, worker); + append_error(&error, pollset_worker_kick(worker), err_desc); + } else { + GPR_TIMER_MARK("kicked_no_pollers", 0); + p->kicked_without_pollers = true; + } + } + + GPR_TIMER_END("pollset_kick", 0); + GRPC_LOG_IF_ERROR("pollset_kick", GRPC_ERROR_REF(error)); + return error; +} + +static void pollset_init(grpc_pollset *pollset, gpr_mu **mu) { + gpr_mu_init(&pollset->po.mu); + *mu = &pollset->po.mu; + pollset->po.pi = NULL; +#ifndef NDEBUG + pollset->po.obj_type = POLL_OBJ_POLLSET; +#endif + + pollset->root_worker.next = pollset->root_worker.prev = &pollset->root_worker; + pollset->kicked_without_pollers = false; + + pollset->shutting_down = false; + pollset->finish_shutdown_called = false; + pollset->shutdown_done = NULL; +} + +/* Convert millis to timespec (clock-type is assumed to be GPR_TIMESPAN) */ +static struct timespec millis_to_timespec(int millis) { + struct timespec linux_ts; + gpr_timespec gpr_ts; + + if (millis == -1) { + gpr_ts = gpr_inf_future(GPR_TIMESPAN); + } else { + gpr_ts = gpr_time_from_millis(millis, GPR_TIMESPAN); + } + + linux_ts.tv_sec = (time_t)gpr_ts.tv_sec; + linux_ts.tv_nsec = gpr_ts.tv_nsec; + return linux_ts; +} + +/* Convert a timespec to milliseconds: + - Very small or negative poll times are clamped to zero to do a non-blocking + poll (which becomes spin polling) + - Other small values are rounded up to one millisecond + - Longer than a millisecond polls are rounded up to the next nearest + millisecond to avoid spinning + - Infinite timeouts are converted to -1 */ +static int poll_deadline_to_millis_timeout(gpr_timespec deadline, + gpr_timespec now) { + gpr_timespec timeout; + static const int64_t max_spin_polling_us = 10; + if (gpr_time_cmp(deadline, gpr_inf_future(deadline.clock_type)) == 0) { + return -1; + } + + if (gpr_time_cmp(deadline, gpr_time_add(now, gpr_time_from_micros( + max_spin_polling_us, + GPR_TIMESPAN))) <= 0) { + return 0; + } + timeout = gpr_time_sub(deadline, now); + int millis = gpr_time_to_millis(gpr_time_add( + timeout, gpr_time_from_nanos(GPR_NS_PER_MS - 1, GPR_TIMESPAN))); + return millis >= 1 ? millis : 1; +} + +static void fd_become_readable(grpc_exec_ctx *exec_ctx, grpc_fd *fd, + grpc_pollset *notifier) { + grpc_lfev_set_ready(exec_ctx, &fd->read_closure, "read"); + + /* Note, it is possible that fd_become_readable might be called twice with + different 'notifier's when an fd becomes readable and it is in two epoll + sets (This can happen briefly during polling island merges). In such cases + it does not really matter which notifer is set as the read_notifier_pollset + (They would both point to the same polling island anyway) */ + /* Use release store to match with acquire load in fd_get_read_notifier */ + gpr_atm_rel_store(&fd->read_notifier_pollset, (gpr_atm)notifier); +} + +static void fd_become_writable(grpc_exec_ctx *exec_ctx, grpc_fd *fd) { + grpc_lfev_set_ready(exec_ctx, &fd->write_closure, "write"); +} + +static void pollset_release_polling_island(grpc_exec_ctx *exec_ctx, + grpc_pollset *ps, char *reason) { + if (ps->po.pi != NULL) { + PI_UNREF(exec_ctx, ps->po.pi, reason); + } + ps->po.pi = NULL; +} + +static void finish_shutdown_locked(grpc_exec_ctx *exec_ctx, + grpc_pollset *pollset) { + /* The pollset cannot have any workers if we are at this stage */ + GPR_ASSERT(!pollset_has_workers(pollset)); + + pollset->finish_shutdown_called = true; + + /* Release the ref and set pollset->po.pi to NULL */ + pollset_release_polling_island(exec_ctx, pollset, "ps_shutdown"); + GRPC_CLOSURE_SCHED(exec_ctx, pollset->shutdown_done, GRPC_ERROR_NONE); +} + +/* pollset->po.mu lock must be held by the caller before calling this */ +static void pollset_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, + grpc_closure *closure) { + GPR_TIMER_BEGIN("pollset_shutdown", 0); + GPR_ASSERT(!pollset->shutting_down); + pollset->shutting_down = true; + pollset->shutdown_done = closure; + pollset_kick(pollset, GRPC_POLLSET_KICK_BROADCAST); + + /* If the pollset has any workers, we cannot call finish_shutdown_locked() + because it would release the underlying polling island. In such a case, we + let the last worker call finish_shutdown_locked() from pollset_work() */ + if (!pollset_has_workers(pollset)) { + GPR_ASSERT(!pollset->finish_shutdown_called); + GPR_TIMER_MARK("pollset_shutdown.finish_shutdown_locked", 0); + finish_shutdown_locked(exec_ctx, pollset); + } + GPR_TIMER_END("pollset_shutdown", 0); +} + +/* pollset_shutdown is guaranteed to be called before pollset_destroy. So other + * than destroying the mutexes, there is nothing special that needs to be done + * here */ +static void pollset_destroy(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset) { + GPR_ASSERT(!pollset_has_workers(pollset)); + gpr_mu_destroy(&pollset->po.mu); +} + +/* NOTE: This function may modify 'now' */ +static bool acquire_polling_lease(grpc_pollset_worker *worker, + polling_island *pi, gpr_timespec deadline, + gpr_timespec *now) { + bool is_lease_acquired = false; + + gpr_mu_lock(&pi->worker_list_mu); // LOCK + long num_pollers = gpr_atm_no_barrier_load(&pi->poller_count); + + if (num_pollers >= g_max_pollers_per_pi) { + push_back_worker_node(&pi->worker_list_head, &worker->pi_list_link); + gpr_mu_unlock(&pi->worker_list_mu); // UNLOCK + + bool is_timeout = false; + int ret; + int timeout_ms = poll_deadline_to_millis_timeout(deadline, *now); + if (timeout_ms == -1) { + ret = sigwaitinfo(&g_wakeup_sig_set, NULL); + } else { + struct timespec sigwait_timeout = millis_to_timespec(timeout_ms); + GRPC_SCHEDULING_START_BLOCKING_REGION; + ret = sigtimedwait(&g_wakeup_sig_set, NULL, &sigwait_timeout); + GRPC_SCHEDULING_END_BLOCKING_REGION; + } + + if (ret == -1) { + if (errno == EAGAIN) { + is_timeout = true; + } else { + /* NOTE: This should not happen. If we see these log messages, it means + we are most likely doing something incorrect in the setup * needed + for sigwaitinfo/sigtimedwait */ + gpr_log(GPR_ERROR, + "sigtimedwait failed with retcode: %d (timeout_ms: %d)", errno, + timeout_ms); + } + } + + /* Did the worker come out of sigtimedwait due to a thread that just + exited epoll and kicking it (in release_polling_lease function). */ + bool is_polling_turn = gpr_atm_acq_load(&worker->is_polling_turn); + + /* Did the worker come out of sigtimedwait due to a thread alerting it that + some completion event was (likely) available in the completion queue */ + bool is_kicked = gpr_atm_no_barrier_load(&worker->is_kicked); + + if (is_kicked || is_timeout) { + *now = deadline; /* Essentially make the epoll timeout = 0 */ + } else if (is_polling_turn) { + *now = gpr_now(GPR_CLOCK_MONOTONIC); /* Reduce the epoll timeout */ + } + + gpr_mu_lock(&pi->worker_list_mu); // LOCK + /* The node might have already been removed from the list by the poller + that kicked this. However it is safe to call 'remove_worker_node' on + an already detached node */ + remove_worker_node(&worker->pi_list_link); + /* It is important to read the num_pollers again under the lock so that we + * have the latest num_pollers value that doesn't change while we are doing + * the "(num_pollers < g_max_pollers_per_pi)" a a few lines below */ + num_pollers = gpr_atm_no_barrier_load(&pi->poller_count); + } + + if (num_pollers < g_max_pollers_per_pi) { + gpr_atm_no_barrier_fetch_add(&pi->poller_count, 1); + is_lease_acquired = true; + } + + gpr_mu_unlock(&pi->worker_list_mu); // UNLOCK + return is_lease_acquired; +} + +static void release_polling_lease(polling_island *pi, grpc_error **error) { + gpr_mu_lock(&pi->worker_list_mu); + + gpr_atm_no_barrier_fetch_add(&pi->poller_count, -1); + worker_node *node = pop_front_worker_node(&pi->worker_list_head); + if (node != NULL) { + grpc_pollset_worker *next_worker = WORKER_FROM_WORKER_LIST_NODE(node); + append_error(error, poller_kick(next_worker), "poller kick error"); + } + + gpr_mu_unlock(&pi->worker_list_mu); +} + +#define GRPC_EPOLL_MAX_EVENTS 100 +static void pollset_do_epoll_pwait(grpc_exec_ctx *exec_ctx, int epoll_fd, + grpc_pollset *pollset, polling_island *pi, + grpc_pollset_worker *worker, + gpr_timespec now, gpr_timespec deadline, + sigset_t *sig_mask, grpc_error **error) { + /* Only g_max_pollers_per_pi threads can be doing polling in parallel. + If we cannot get a lease, we cannot continue to do epoll_pwait() */ + if (!acquire_polling_lease(worker, pi, deadline, &now)) { + return; + } + + struct epoll_event ep_ev[GRPC_EPOLL_MAX_EVENTS]; + int ep_rv; + char *err_msg; + const char *err_desc = "pollset_work_and_unlock"; + + /* timeout_ms is the time between 'now' and 'deadline' */ + int timeout_ms = poll_deadline_to_millis_timeout(deadline, now); + + GRPC_SCHEDULING_START_BLOCKING_REGION; + ep_rv = + epoll_pwait(epoll_fd, ep_ev, GRPC_EPOLL_MAX_EVENTS, timeout_ms, sig_mask); + GRPC_SCHEDULING_END_BLOCKING_REGION; + + /* Give back the lease right away so that some other thread can enter */ + release_polling_lease(pi, error); + + if (ep_rv < 0) { + if (errno != EINTR) { + gpr_asprintf(&err_msg, + "epoll_wait() epoll fd: %d failed with error: %d (%s)", + epoll_fd, errno, strerror(errno)); + append_error(error, GRPC_OS_ERROR(errno, err_msg), err_desc); + } else { + /* We were interrupted. Save an interation by doing a zero timeout + epoll_wait to see if there are any other events of interest */ + GRPC_POLLING_TRACE("pollset_work: pollset: %p, worker: %p received kick", + (void *)pollset, (void *)worker); + ep_rv = epoll_wait(epoll_fd, ep_ev, GRPC_EPOLL_MAX_EVENTS, 0); + } + } + +#ifdef GRPC_TSAN + /* See the definition of g_poll_sync for more details */ + gpr_atm_acq_load(&g_epoll_sync); +#endif /* defined(GRPC_TSAN) */ + + for (int i = 0; i < ep_rv; ++i) { + void *data_ptr = ep_ev[i].data.ptr; + if (data_ptr == &polling_island_wakeup_fd) { + GRPC_POLLING_TRACE( + "pollset_work: pollset: %p, worker: %p polling island (epoll_fd: " + "%d) got merged", + (void *)pollset, (void *)worker, epoll_fd); + /* This means that our polling island is merged with a different + island. We do not have to do anything here since the subsequent call + to the function pollset_work_and_unlock() will pick up the correct + epoll_fd */ + } else { + grpc_fd *fd = data_ptr; + int cancel = ep_ev[i].events & (EPOLLERR | EPOLLHUP); + int read_ev = ep_ev[i].events & (EPOLLIN | EPOLLPRI); + int write_ev = ep_ev[i].events & EPOLLOUT; + if (read_ev || cancel) { + fd_become_readable(exec_ctx, fd, pollset); + } + if (write_ev || cancel) { + fd_become_writable(exec_ctx, fd); + } + } + } +} + +/* Note: sig_mask contains the signal mask to use *during* epoll_wait() */ +static void pollset_work_and_unlock(grpc_exec_ctx *exec_ctx, + grpc_pollset *pollset, + grpc_pollset_worker *worker, + gpr_timespec now, gpr_timespec deadline, + sigset_t *sig_mask, grpc_error **error) { + int epoll_fd = -1; + polling_island *pi = NULL; + GPR_TIMER_BEGIN("pollset_work_and_unlock", 0); + + /* We need to get the epoll_fd to wait on. The epoll_fd is in inside the + latest polling island pointed by pollset->po.pi + + Since epoll_fd is immutable, it is safe to read it without a lock on the + polling island. There is however a possibility that the polling island from + which we got the epoll_fd, got merged with another island in the meantime. + This is okay because in such a case, we will wakeup right-away from + epoll_pwait() (because any merge will poison the old polling island's epoll + set 'polling_island_wakeup_fd') and then pick up the latest polling_island + the next time this function - pollset_work_and_unlock()) is called */ + + if (pollset->po.pi == NULL) { + pollset->po.pi = polling_island_create(exec_ctx, NULL, error); + if (pollset->po.pi == NULL) { + GPR_TIMER_END("pollset_work_and_unlock", 0); + return; /* Fatal error. Cannot continue */ + } + + PI_ADD_REF(pollset->po.pi, "ps"); + GRPC_POLLING_TRACE("pollset_work: pollset: %p created new pi: %p", + (void *)pollset, (void *)pollset->po.pi); + } + + pi = polling_island_maybe_get_latest(pollset->po.pi); + epoll_fd = pi->epoll_fd; + + /* Update the pollset->po.pi since the island being pointed by + pollset->po.pi maybe older than the one pointed by pi) */ + if (pollset->po.pi != pi) { + /* Always do PI_ADD_REF before PI_UNREF because PI_UNREF may cause the + polling island to be deleted */ + PI_ADD_REF(pi, "ps"); + PI_UNREF(exec_ctx, pollset->po.pi, "ps"); + pollset->po.pi = pi; + } + + /* Add an extra ref so that the island does not get destroyed (which means + the epoll_fd won't be closed) while we are are doing an epoll_wait() on the + epoll_fd */ + PI_ADD_REF(pi, "ps_work"); + gpr_mu_unlock(&pollset->po.mu); + + g_current_thread_polling_island = pi; + pollset_do_epoll_pwait(exec_ctx, epoll_fd, pollset, pi, worker, now, deadline, + sig_mask, error); + g_current_thread_polling_island = NULL; + + GPR_ASSERT(pi != NULL); + + /* Before leaving, release the extra ref we added to the polling island. It + is important to use "pi" here (i.e our old copy of pollset->po.pi + that we got before releasing the polling island lock). This is because + pollset->po.pi pointer might get udpated in other parts of the + code when there is an island merge while we are doing epoll_wait() above */ + PI_UNREF(exec_ctx, pi, "ps_work"); + + GPR_TIMER_END("pollset_work_and_unlock", 0); +} + +/* pollset->po.mu lock must be held by the caller before calling this. + The function pollset_work() may temporarily release the lock (pollset->po.mu) + during the course of its execution but it will always re-acquire the lock and + ensure that it is held by the time the function returns */ +static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, + grpc_pollset_worker **worker_hdl, + gpr_timespec now, gpr_timespec deadline) { + GPR_TIMER_BEGIN("pollset_work", 0); + grpc_error *error = GRPC_ERROR_NONE; + + grpc_pollset_worker worker; + pollset_worker_init(&worker); + + if (worker_hdl) *worker_hdl = &worker; + + gpr_tls_set(&g_current_thread_pollset, (intptr_t)pollset); + gpr_tls_set(&g_current_thread_worker, (intptr_t)&worker); + + if (pollset->kicked_without_pollers) { + /* If the pollset was kicked without pollers, pretend that the current + worker got the kick and skip polling. A kick indicates that there is some + work that needs attention like an event on the completion queue or an + alarm */ + GPR_TIMER_MARK("pollset_work.kicked_without_pollers", 0); + pollset->kicked_without_pollers = 0; + } else if (!pollset->shutting_down) { + /* We use the posix-signal with number 'grpc_wakeup_signal' for waking up + (i.e 'kicking') a worker in the pollset. A 'kick' is a way to inform the + worker that there is some pending work that needs immediate attention + (like an event on the completion queue, or a polling island merge that + results in a new epoll-fd to wait on) and that the worker should not + spend time waiting in epoll_pwait(). + + A worker can be kicked anytime from the point it is added to the pollset + via push_front_worker() (or push_back_worker()) to the point it is + removed via remove_worker(). + If the worker is kicked before/during it calls epoll_pwait(), it should + immediately exit from epoll_wait(). If the worker is kicked after it + returns from epoll_wait(), then nothing really needs to be done. + + To accomplish this, we mask 'grpc_wakeup_signal' on this thread at all + times *except* when it is in epoll_pwait(). This way, the worker never + misses acting on a kick */ + + if (!g_initialized_sigmask) { + sigemptyset(&g_wakeup_sig_set); + sigaddset(&g_wakeup_sig_set, grpc_wakeup_signal); + pthread_sigmask(SIG_BLOCK, &g_wakeup_sig_set, &g_orig_sigmask); + sigdelset(&g_orig_sigmask, grpc_wakeup_signal); + g_initialized_sigmask = true; + /* new_mask: The new thread mask which blocks 'grpc_wakeup_signal'. + This is the mask used at all times *except during + epoll_wait()*" + g_orig_sigmask: The thread mask which allows 'grpc_wakeup_signal' and + this is the mask to use *during epoll_wait()* + + The new_mask is set on the worker before it is added to the pollset + (i.e before it can be kicked) */ + } + + push_front_worker(pollset, &worker); /* Add worker to pollset */ + + pollset_work_and_unlock(exec_ctx, pollset, &worker, now, deadline, + &g_orig_sigmask, &error); + grpc_exec_ctx_flush(exec_ctx); + + gpr_mu_lock(&pollset->po.mu); + + /* Note: There is no need to reset worker.is_kicked to 0 since we are no + longer going to use this worker */ + remove_worker(pollset, &worker); + } + + /* If we are the last worker on the pollset (i.e pollset_has_workers() is + false at this point) and the pollset is shutting down, we may have to + finish the shutdown process by calling finish_shutdown_locked(). + See pollset_shutdown() for more details. + + Note: Continuing to access pollset here is safe; it is the caller's + responsibility to not destroy a pollset when it has outstanding calls to + pollset_work() */ + if (pollset->shutting_down && !pollset_has_workers(pollset) && + !pollset->finish_shutdown_called) { + GPR_TIMER_MARK("pollset_work.finish_shutdown_locked", 0); + finish_shutdown_locked(exec_ctx, pollset); + + gpr_mu_unlock(&pollset->po.mu); + grpc_exec_ctx_flush(exec_ctx); + gpr_mu_lock(&pollset->po.mu); + } + + if (worker_hdl) *worker_hdl = NULL; + + gpr_tls_set(&g_current_thread_pollset, (intptr_t)0); + gpr_tls_set(&g_current_thread_worker, (intptr_t)0); + + GPR_TIMER_END("pollset_work", 0); + + GRPC_LOG_IF_ERROR("pollset_work", GRPC_ERROR_REF(error)); + return error; +} + +static void add_poll_object(grpc_exec_ctx *exec_ctx, poll_obj *bag, + poll_obj_type bag_type, poll_obj *item, + poll_obj_type item_type) { + GPR_TIMER_BEGIN("add_poll_object", 0); + +#ifndef NDEBUG + GPR_ASSERT(item->obj_type == item_type); + GPR_ASSERT(bag->obj_type == bag_type); +#endif + + grpc_error *error = GRPC_ERROR_NONE; + polling_island *pi_new = NULL; + + gpr_mu_lock(&bag->mu); + gpr_mu_lock(&item->mu); + +retry: + /* + * 1) If item->pi and bag->pi are both non-NULL and equal, do nothing + * 2) If item->pi and bag->pi are both NULL, create a new polling island (with + * a refcount of 2) and point item->pi and bag->pi to the new island + * 3) If exactly one of item->pi or bag->pi is NULL, update it to point to + * the other's non-NULL pi + * 4) Finally if item->pi and bag-pi are non-NULL and not-equal, merge the + * polling islands and update item->pi and bag->pi to point to the new + * island + */ + + /* Early out if we are trying to add an 'fd' to a 'bag' but the fd is already + * orphaned */ + if (item_type == POLL_OBJ_FD && (FD_FROM_PO(item))->orphaned) { + gpr_mu_unlock(&item->mu); + gpr_mu_unlock(&bag->mu); + return; + } + + if (item->pi == bag->pi) { + pi_new = item->pi; + if (pi_new == NULL) { + /* GPR_ASSERT(item->pi == bag->pi == NULL) */ + + /* If we are adding an fd to a bag (i.e pollset or pollset_set), then + * we need to do some extra work to make TSAN happy */ + if (item_type == POLL_OBJ_FD) { + /* Unlock before creating a new polling island: the polling island will + create a workqueue which creates a file descriptor, and holding an fd + lock here can eventually cause a loop to appear to TSAN (making it + unhappy). We don't think it's a real loop (there's an epoch point + where that loop possibility disappears), but the advantages of + keeping TSAN happy outweigh any performance advantage we might have + by keeping the lock held. */ + gpr_mu_unlock(&item->mu); + pi_new = polling_island_create(exec_ctx, FD_FROM_PO(item), &error); + gpr_mu_lock(&item->mu); + + /* Need to reverify any assumptions made between the initial lock and + getting to this branch: if they've changed, we need to throw away our + work and figure things out again. */ + if (item->pi != NULL) { + GRPC_POLLING_TRACE( + "add_poll_object: Raced creating new polling island. pi_new: %p " + "(fd: %d, %s: %p)", + (void *)pi_new, FD_FROM_PO(item)->fd, poll_obj_string(bag_type), + (void *)bag); + /* No need to lock 'pi_new' here since this is a new polling island + and no one has a reference to it yet */ + polling_island_remove_all_fds_locked(pi_new, true, &error); + + /* Ref and unref so that the polling island gets deleted during unref + */ + PI_ADD_REF(pi_new, "dance_of_destruction"); + PI_UNREF(exec_ctx, pi_new, "dance_of_destruction"); + goto retry; + } + } else { + pi_new = polling_island_create(exec_ctx, NULL, &error); + } + + GRPC_POLLING_TRACE( + "add_poll_object: Created new polling island. pi_new: %p (%s: %p, " + "%s: %p)", + (void *)pi_new, poll_obj_string(item_type), (void *)item, + poll_obj_string(bag_type), (void *)bag); + } else { + GRPC_POLLING_TRACE( + "add_poll_object: Same polling island. pi: %p (%s, %s)", + (void *)pi_new, poll_obj_string(item_type), + poll_obj_string(bag_type)); + } + } else if (item->pi == NULL) { + /* GPR_ASSERT(bag->pi != NULL) */ + /* Make pi_new point to latest pi*/ + pi_new = polling_island_lock(bag->pi); + + if (item_type == POLL_OBJ_FD) { + grpc_fd *fd = FD_FROM_PO(item); + polling_island_add_fds_locked(pi_new, &fd, 1, true, &error); + } + + gpr_mu_unlock(&pi_new->mu); + GRPC_POLLING_TRACE( + "add_poll_obj: item->pi was NULL. pi_new: %p (item(%s): %p, " + "bag(%s): %p)", + (void *)pi_new, poll_obj_string(item_type), (void *)item, + poll_obj_string(bag_type), (void *)bag); + } else if (bag->pi == NULL) { + /* GPR_ASSERT(item->pi != NULL) */ + /* Make pi_new to point to latest pi */ + pi_new = polling_island_lock(item->pi); + gpr_mu_unlock(&pi_new->mu); + GRPC_POLLING_TRACE( + "add_poll_obj: bag->pi was NULL. pi_new: %p (item(%s): %p, " + "bag(%s): %p)", + (void *)pi_new, poll_obj_string(item_type), (void *)item, + poll_obj_string(bag_type), (void *)bag); + } else { + pi_new = polling_island_merge(item->pi, bag->pi, &error); + GRPC_POLLING_TRACE( + "add_poll_obj: polling islands merged. pi_new: %p (item(%s): %p, " + "bag(%s): %p)", + (void *)pi_new, poll_obj_string(item_type), (void *)item, + poll_obj_string(bag_type), (void *)bag); + } + + /* At this point, pi_new is the polling island that both item->pi and bag->pi + MUST be pointing to */ + + if (item->pi != pi_new) { + PI_ADD_REF(pi_new, poll_obj_string(item_type)); + if (item->pi != NULL) { + PI_UNREF(exec_ctx, item->pi, poll_obj_string(item_type)); + } + item->pi = pi_new; + } + + if (bag->pi != pi_new) { + PI_ADD_REF(pi_new, poll_obj_string(bag_type)); + if (bag->pi != NULL) { + PI_UNREF(exec_ctx, bag->pi, poll_obj_string(bag_type)); + } + bag->pi = pi_new; + } + + gpr_mu_unlock(&item->mu); + gpr_mu_unlock(&bag->mu); + + GRPC_LOG_IF_ERROR("add_poll_object", error); + GPR_TIMER_END("add_poll_object", 0); +} + +static void pollset_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, + grpc_fd *fd) { + add_poll_object(exec_ctx, &pollset->po, POLL_OBJ_POLLSET, &fd->po, + POLL_OBJ_FD); +} + +/******************************************************************************* + * Pollset-set Definitions + */ + +static grpc_pollset_set *pollset_set_create(void) { + grpc_pollset_set *pss = gpr_malloc(sizeof(*pss)); + gpr_mu_init(&pss->po.mu); + pss->po.pi = NULL; +#ifndef NDEBUG + pss->po.obj_type = POLL_OBJ_POLLSET_SET; +#endif + return pss; +} + +static void pollset_set_destroy(grpc_exec_ctx *exec_ctx, + grpc_pollset_set *pss) { + gpr_mu_destroy(&pss->po.mu); + + if (pss->po.pi != NULL) { + PI_UNREF(exec_ctx, pss->po.pi, "pss_destroy"); + } + + gpr_free(pss); +} + +static void pollset_set_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset_set *pss, + grpc_fd *fd) { + add_poll_object(exec_ctx, &pss->po, POLL_OBJ_POLLSET_SET, &fd->po, + POLL_OBJ_FD); +} + +static void pollset_set_del_fd(grpc_exec_ctx *exec_ctx, grpc_pollset_set *pss, + grpc_fd *fd) { + /* Nothing to do */ +} + +static void pollset_set_add_pollset(grpc_exec_ctx *exec_ctx, + grpc_pollset_set *pss, grpc_pollset *ps) { + add_poll_object(exec_ctx, &pss->po, POLL_OBJ_POLLSET_SET, &ps->po, + POLL_OBJ_POLLSET); +} + +static void pollset_set_del_pollset(grpc_exec_ctx *exec_ctx, + grpc_pollset_set *pss, grpc_pollset *ps) { + /* Nothing to do */ +} + +static void pollset_set_add_pollset_set(grpc_exec_ctx *exec_ctx, + grpc_pollset_set *bag, + grpc_pollset_set *item) { + add_poll_object(exec_ctx, &bag->po, POLL_OBJ_POLLSET_SET, &item->po, + POLL_OBJ_POLLSET_SET); +} + +static void pollset_set_del_pollset_set(grpc_exec_ctx *exec_ctx, + grpc_pollset_set *bag, + grpc_pollset_set *item) { + /* Nothing to do */ +} + +/******************************************************************************* + * Event engine binding + */ + +static void shutdown_engine(void) { + fd_global_shutdown(); + pollset_global_shutdown(); + polling_island_global_shutdown(); +} + +static const grpc_event_engine_vtable vtable = { + .pollset_size = sizeof(grpc_pollset), + + .fd_create = fd_create, + .fd_wrapped_fd = fd_wrapped_fd, + .fd_orphan = fd_orphan, + .fd_shutdown = fd_shutdown, + .fd_is_shutdown = fd_is_shutdown, + .fd_notify_on_read = fd_notify_on_read, + .fd_notify_on_write = fd_notify_on_write, + .fd_get_read_notifier_pollset = fd_get_read_notifier_pollset, + + .pollset_init = pollset_init, + .pollset_shutdown = pollset_shutdown, + .pollset_destroy = pollset_destroy, + .pollset_work = pollset_work, + .pollset_kick = pollset_kick, + .pollset_add_fd = pollset_add_fd, + + .pollset_set_create = pollset_set_create, + .pollset_set_destroy = pollset_set_destroy, + .pollset_set_add_pollset = pollset_set_add_pollset, + .pollset_set_del_pollset = pollset_set_del_pollset, + .pollset_set_add_pollset_set = pollset_set_add_pollset_set, + .pollset_set_del_pollset_set = pollset_set_del_pollset_set, + .pollset_set_add_fd = pollset_set_add_fd, + .pollset_set_del_fd = pollset_set_del_fd, + + .shutdown_engine = shutdown_engine, +}; + +/* It is possible that GLIBC has epoll but the underlying kernel doesn't. + * Create a dummy epoll_fd to make sure epoll support is available */ +static bool is_epoll_available() { + int fd = epoll_create1(EPOLL_CLOEXEC); + if (fd < 0) { + gpr_log( + GPR_ERROR, + "epoll_create1 failed with error: %d. Not using epoll polling engine", + fd); + return false; + } + close(fd); + return true; +} + +/* This is mainly for testing purposes. Checks to see if environment variable + * GRPC_MAX_POLLERS_PER_PI is set and if so, assigns that value to + * g_max_pollers_per_pi (any negative value is considered INT_MAX) */ +static void set_max_pollers_per_island() { + char *s = gpr_getenv("GRPC_MAX_POLLERS_PER_PI"); + if (s) { + g_max_pollers_per_pi = (int)strtol(s, NULL, 10); + if (g_max_pollers_per_pi < 0) { + g_max_pollers_per_pi = INT_MAX; + } + } else { + g_max_pollers_per_pi = INT_MAX; + } + + gpr_log(GPR_INFO, "Max number of pollers per polling island: %d", + g_max_pollers_per_pi); +} + +const grpc_event_engine_vtable *grpc_init_epoll_limited_pollers_linux( + bool explicitly_requested) { + if (!explicitly_requested) { + return NULL; + } + + /* If use of signals is disabled, we cannot use epoll engine*/ + if (is_grpc_wakeup_signal_initialized && grpc_wakeup_signal < 0) { + return NULL; + } + + if (!grpc_has_wakeup_fd()) { + return NULL; + } + + if (!is_epoll_available()) { + return NULL; + } + + if (!is_grpc_wakeup_signal_initialized) { + grpc_use_signal(SIGRTMIN + 6); + } + + set_max_pollers_per_island(); + + fd_global_init(); + + if (!GRPC_LOG_IF_ERROR("pollset_global_init", pollset_global_init())) { + return NULL; + } + + if (!GRPC_LOG_IF_ERROR("polling_island_global_init", + polling_island_global_init())) { + return NULL; + } + + return &vtable; +} + +#else /* defined(GRPC_LINUX_EPOLL) */ +#if defined(GRPC_POSIX_SOCKET) +#include "src/core/lib/iomgr/ev_posix.h" +/* If GRPC_LINUX_EPOLL is not defined, it means epoll is not available. Return + * NULL */ +const grpc_event_engine_vtable *grpc_init_epoll_limited_pollers_linux( + bool explicitly_requested) { + return NULL; +} +#endif /* defined(GRPC_POSIX_SOCKET) */ +#endif /* !defined(GRPC_LINUX_EPOLL) */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/ev_epoll_limited_pollers_linux.h b/Sources/CgRPC/src/core/lib/iomgr/ev_epoll_limited_pollers_linux.h new file mode 100644 index 000000000..1d6af5f52 --- /dev/null +++ b/Sources/CgRPC/src/core/lib/iomgr/ev_epoll_limited_pollers_linux.h @@ -0,0 +1,28 @@ +/* + * + * 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 GRPC_CORE_LIB_IOMGR_EV_EPOLL_LIMITED_POLLERS_LINUX_H +#define GRPC_CORE_LIB_IOMGR_EV_EPOLL_LIMITED_POLLERS_LINUX_H + +#include "src/core/lib/iomgr/ev_posix.h" +#include "src/core/lib/iomgr/port.h" + +const grpc_event_engine_vtable *grpc_init_epoll_limited_pollers_linux( + bool explicitly_requested); + +#endif /* GRPC_CORE_LIB_IOMGR_EV_EPOLL_LIMITED_POLLERS_LINUX_H */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/ev_epoll_linux.h b/Sources/CgRPC/src/core/lib/iomgr/ev_epoll_linux.h deleted file mode 100644 index 8fc3ff59a..000000000 --- a/Sources/CgRPC/src/core/lib/iomgr/ev_epoll_linux.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#ifndef GRPC_CORE_LIB_IOMGR_EV_EPOLL_LINUX_H -#define GRPC_CORE_LIB_IOMGR_EV_EPOLL_LINUX_H - -#include "src/core/lib/iomgr/ev_posix.h" -#include "src/core/lib/iomgr/port.h" - -const grpc_event_engine_vtable *grpc_init_epoll_linux(void); - -#ifdef GRPC_LINUX_EPOLL -void *grpc_fd_get_polling_island(grpc_fd *fd); -void *grpc_pollset_get_polling_island(grpc_pollset *ps); -bool grpc_are_polling_islands_equal(void *p, void *q); -#endif /* defined(GRPC_LINUX_EPOLL) */ - -#endif /* GRPC_CORE_LIB_IOMGR_EV_EPOLL_LINUX_H */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/ev_epoll_thread_pool_linux.c b/Sources/CgRPC/src/core/lib/iomgr/ev_epoll_thread_pool_linux.c new file mode 100644 index 000000000..07c8eadf4 --- /dev/null +++ b/Sources/CgRPC/src/core/lib/iomgr/ev_epoll_thread_pool_linux.c @@ -0,0 +1,1182 @@ +/* + * + * Copyright 2017 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 "src/core/lib/iomgr/port.h" + +/* This polling engine is only relevant on linux kernels supporting epoll() */ +#ifdef GRPC_LINUX_EPOLL + +#include "src/core/lib/iomgr/ev_epoll_thread_pool_linux.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "src/core/lib/iomgr/ev_posix.h" +#include "src/core/lib/iomgr/iomgr_internal.h" +#include "src/core/lib/iomgr/lockfree_event.h" +#include "src/core/lib/iomgr/timer.h" +#include "src/core/lib/iomgr/wakeup_fd_posix.h" +#include "src/core/lib/profiling/timers.h" +#include "src/core/lib/support/block_annotate.h" + +/* TODO: sreek - Move this to init.c and initialize this like other tracers. */ +#define GRPC_POLLING_TRACE(fmt, ...) \ + if (GRPC_TRACER_ON(grpc_polling_trace)) { \ + gpr_log(GPR_INFO, (fmt), __VA_ARGS__); \ + } + +/* The alarm system needs to be able to wakeup 'some poller' sometimes + * (specifically when a new alarm needs to be triggered earlier than the next + * alarm 'epoch'). This wakeup_fd gives us something to alert on when such a + * case occurs. */ + +struct epoll_set; + +#define GRPC_POLLSET_KICK_BROADCAST ((grpc_pollset_worker *)1) + +/******************************************************************************* + * Fd Declarations + */ +struct grpc_fd { + gpr_mu mu; + struct epoll_set *eps; + + int fd; + + /* The fd is either closed or we relinquished control of it. In either cases, + this indicates that the 'fd' on this structure is no longer valid */ + bool orphaned; + + gpr_atm read_closure; + gpr_atm write_closure; + + struct grpc_fd *freelist_next; + grpc_closure *on_done_closure; + + grpc_iomgr_object iomgr_object; +}; + +static void fd_global_init(void); +static void fd_global_shutdown(void); + +/******************************************************************************* + * epoll set Declarations + */ + +#ifndef NDEBUG + +#define EPS_ADD_REF(p, r) eps_add_ref_dbg((p), (r), __FILE__, __LINE__) +#define EPS_UNREF(exec_ctx, p, r) \ + eps_unref_dbg((exec_ctx), (p), (r), __FILE__, __LINE__) + +#else + +#define EPS_ADD_REF(p, r) eps_add_ref((p)) +#define EPS_UNREF(exec_ctx, p, r) eps_unref((exec_ctx), (p)) + +#endif + +typedef struct epoll_set { + /* Mutex poller should acquire to poll this. This enforces that only one + * poller can be polling on epoll_set at any time */ + gpr_mu mu; + + /* Ref count. Use EPS_ADD_REF() and EPS_UNREF() macros to increment/decrement + the refcount. Once the ref count becomes zero, this structure is destroyed + which means we should ensure that there is never a scenario where a + EPS_ADD_REF() is racing with a EPS_UNREF() that just made the ref_count + zero. */ + gpr_atm ref_count; + + /* Number of threads currently polling on this epoll set*/ + gpr_atm poller_count; + + /* Is the epoll set shutdown */ + gpr_atm is_shutdown; + + /* The fd of the underlying epoll set */ + int epoll_fd; +} epoll_set; + +/******************************************************************************* + * Pollset Declarations + */ +struct grpc_pollset_worker { + gpr_cv kick_cv; + + struct grpc_pollset_worker *next; + struct grpc_pollset_worker *prev; +}; + +struct grpc_pollset { + gpr_mu mu; + struct epoll_set *eps; + + grpc_pollset_worker root_worker; + bool kicked_without_pollers; + + bool shutting_down; /* Is the pollset shutting down ? */ + bool finish_shutdown_called; /* Is the 'finish_shutdown_locked()' called ? */ + grpc_closure *shutdown_done; /* Called after after shutdown is complete */ +}; + +/******************************************************************************* + * Pollset-set Declarations + */ +struct grpc_pollset_set { + char unused; +}; + +/***************************************************************************** + * Dedicated polling threads and pollsets - Declarations + */ + +size_t g_num_eps = 1; +struct epoll_set **g_epoll_sets = NULL; +gpr_atm g_next_eps; +size_t g_num_threads_per_eps = 1; +gpr_thd_id *g_poller_threads = NULL; + +/* Used as read-notifier pollsets for fds. We won't be using read notifier + * pollsets with this polling engine. So it does not matter what pollset we + * return */ +grpc_pollset g_read_notifier; + +static void add_fd_to_eps(grpc_fd *fd); +static bool init_epoll_sets(); +static void shutdown_epoll_sets(); +static void poller_thread_loop(void *arg); +static void start_poller_threads(); +static void shutdown_poller_threads(); + +/******************************************************************************* + * Common helpers + */ + +static bool append_error(grpc_error **composite, grpc_error *error, + const char *desc) { + if (error == GRPC_ERROR_NONE) return true; + if (*composite == GRPC_ERROR_NONE) { + *composite = GRPC_ERROR_CREATE_FROM_COPIED_STRING(desc); + } + *composite = grpc_error_add_child(*composite, error); + return false; +} + +/******************************************************************************* + * epoll set Definitions + */ + +/* The wakeup fd that is used to wake up all threads in an epoll_set informing + that the epoll set is shutdown. This wakeup fd initialized to be readable + and MUST NOT be consumed i.e the threads that woke up MUST NOT call + grpc_wakeup_fd_consume_wakeup() */ +static grpc_wakeup_fd epoll_set_wakeup_fd; + +/* The epoll set being polled right now. + See comments in workqueue_maybe_wakeup for why this is tracked. */ +static __thread epoll_set *g_current_thread_epoll_set; + +/* Forward declaration */ +static void epoll_set_delete(epoll_set *eps); + +#ifdef GRPC_TSAN +/* Currently TSAN may incorrectly flag data races between epoll_ctl and + epoll_wait for any grpc_fd structs that are added to the epoll set via + epoll_ctl and are returned (within a very short window) via epoll_wait(). + + To work-around this race, we establish a happens-before relation between + the code just-before epoll_ctl() and the code after epoll_wait() by using + this atomic */ +gpr_atm g_epoll_sync; +#endif /* defined(GRPC_TSAN) */ + +static void eps_add_ref(epoll_set *eps); +static void eps_unref(grpc_exec_ctx *exec_ctx, epoll_set *eps); + +#ifndef NDEBUG +static void eps_add_ref_dbg(epoll_set *eps, const char *reason, + const char *file, int line) { + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_atm old_cnt = gpr_atm_acq_load(&eps->ref_count); + gpr_log(GPR_DEBUG, "Add ref eps: %p, old:%" PRIdPTR " -> new:%" PRIdPTR + " (%s) - (%s, %d)", + eps, old_cnt, old_cnt + 1, reason, file, line); + } + eps_add_ref(eps); +} + +static void eps_unref_dbg(grpc_exec_ctx *exec_ctx, epoll_set *eps, + const char *reason, const char *file, int line) { + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_atm old_cnt = gpr_atm_acq_load(&eps->ref_count); + gpr_log(GPR_DEBUG, "Unref eps: %p, old:%" PRIdPTR " -> new:%" PRIdPTR + " (%s) - (%s, %d)", + eps, old_cnt, (old_cnt - 1), reason, file, line); + } + eps_unref(exec_ctx, eps); +} +#endif + +static void eps_add_ref(epoll_set *eps) { + gpr_atm_no_barrier_fetch_add(&eps->ref_count, 1); +} + +static void eps_unref(grpc_exec_ctx *exec_ctx, epoll_set *eps) { + /* If ref count went to zero, delete the epoll set. This deletion is + not done under a lock since once the ref count goes to zero, we are + guaranteed that no one else holds a reference to the epoll set (and + that there is no racing eps_add_ref() call either).*/ + if (1 == gpr_atm_full_fetch_add(&eps->ref_count, -1)) { + epoll_set_delete(eps); + } +} + +static void epoll_set_add_fd_locked(epoll_set *eps, grpc_fd *fd, + grpc_error **error) { + int err; + struct epoll_event ev; + char *err_msg; + const char *err_desc = "epoll_set_add_fd_locked"; + +#ifdef GRPC_TSAN + /* See the definition of g_epoll_sync for more context */ + gpr_atm_rel_store(&g_epoll_sync, (gpr_atm)0); +#endif /* defined(GRPC_TSAN) */ + + ev.events = (uint32_t)(EPOLLIN | EPOLLOUT | EPOLLET); + ev.data.ptr = fd; + err = epoll_ctl(eps->epoll_fd, EPOLL_CTL_ADD, fd->fd, &ev); + if (err < 0 && errno != EEXIST) { + gpr_asprintf( + &err_msg, + "epoll_ctl (epoll_fd: %d) add fd: %d failed with error: %d (%s)", + eps->epoll_fd, fd->fd, errno, strerror(errno)); + append_error(error, GRPC_OS_ERROR(errno, err_msg), err_desc); + gpr_free(err_msg); + } +} + +static void epoll_set_add_wakeup_fd_locked(epoll_set *eps, + grpc_wakeup_fd *wakeup_fd, + grpc_error **error) { + struct epoll_event ev; + int err; + char *err_msg; + const char *err_desc = "epoll_set_add_wakeup_fd"; + + ev.events = (uint32_t)(EPOLLIN | EPOLLET); + ev.data.ptr = wakeup_fd; + err = epoll_ctl(eps->epoll_fd, EPOLL_CTL_ADD, + GRPC_WAKEUP_FD_GET_READ_FD(wakeup_fd), &ev); + if (err < 0 && errno != EEXIST) { + gpr_asprintf(&err_msg, + "epoll_ctl (epoll_fd: %d) add wakeup fd: %d failed with " + "error: %d (%s)", + eps->epoll_fd, GRPC_WAKEUP_FD_GET_READ_FD(wakeup_fd), errno, + strerror(errno)); + append_error(error, GRPC_OS_ERROR(errno, err_msg), err_desc); + gpr_free(err_msg); + } +} + +static void epoll_set_remove_fd(epoll_set *eps, grpc_fd *fd, bool is_fd_closed, + grpc_error **error) { + int err; + char *err_msg; + const char *err_desc = "epoll_set_remove_fd"; + + /* If fd is already closed, then it would have been automatically been removed + from the epoll set */ + if (!is_fd_closed) { + err = epoll_ctl(eps->epoll_fd, EPOLL_CTL_DEL, fd->fd, NULL); + if (err < 0 && errno != ENOENT) { + gpr_asprintf( + &err_msg, + "epoll_ctl (epoll_fd: %d) del fd: %d failed with error: %d (%s)", + eps->epoll_fd, fd->fd, errno, strerror(errno)); + append_error(error, GRPC_OS_ERROR(errno, err_msg), err_desc); + gpr_free(err_msg); + } + } +} + +/* Might return NULL in case of an error */ +static epoll_set *epoll_set_create(grpc_error **error) { + epoll_set *eps = NULL; + const char *err_desc = "epoll_set_create"; + + *error = GRPC_ERROR_NONE; + + eps = gpr_malloc(sizeof(*eps)); + eps->epoll_fd = -1; + + gpr_mu_init(&eps->mu); + + gpr_atm_rel_store(&eps->ref_count, 0); + gpr_atm_rel_store(&eps->poller_count, 0); + + gpr_atm_rel_store(&eps->is_shutdown, false); + + eps->epoll_fd = epoll_create1(EPOLL_CLOEXEC); + + if (eps->epoll_fd < 0) { + append_error(error, GRPC_OS_ERROR(errno, "epoll_create1"), err_desc); + goto done; + } + +done: + if (*error != GRPC_ERROR_NONE) { + epoll_set_delete(eps); + eps = NULL; + } + return eps; +} + +static void epoll_set_delete(epoll_set *eps) { + if (eps->epoll_fd >= 0) { + close(eps->epoll_fd); + } + + gpr_mu_destroy(&eps->mu); + + gpr_free(eps); +} + +static grpc_error *epoll_set_global_init() { + grpc_error *error = GRPC_ERROR_NONE; + + error = grpc_wakeup_fd_init(&epoll_set_wakeup_fd); + if (error == GRPC_ERROR_NONE) { + error = grpc_wakeup_fd_wakeup(&epoll_set_wakeup_fd); + } + + return error; +} + +static void epoll_set_global_shutdown() { + grpc_wakeup_fd_destroy(&epoll_set_wakeup_fd); +} + +/******************************************************************************* + * Fd Definitions + */ + +/* We need to keep a freelist not because of any concerns of malloc performance + * but instead so that implementations with multiple threads in (for example) + * epoll_wait deal with the race between pollset removal and incoming poll + * notifications. + * + * The problem is that the poller ultimately holds a reference to this + * object, so it is very difficult to know when is safe to free it, at least + * without some expensive synchronization. + * + * If we keep the object freelisted, in the worst case losing this race just + * becomes a spurious read notification on a reused fd. + */ + +static grpc_fd *fd_freelist = NULL; +static gpr_mu fd_freelist_mu; + +static grpc_fd *get_fd_from_freelist() { + grpc_fd *new_fd = NULL; + + gpr_mu_lock(&fd_freelist_mu); + if (fd_freelist != NULL) { + new_fd = fd_freelist; + fd_freelist = fd_freelist->freelist_next; + } + gpr_mu_unlock(&fd_freelist_mu); + return new_fd; +} + +static void add_fd_to_freelist(grpc_fd *fd) { + gpr_mu_lock(&fd_freelist_mu); + fd->freelist_next = fd_freelist; + fd_freelist = fd; + grpc_iomgr_unregister_object(&fd->iomgr_object); + + grpc_lfev_destroy(&fd->read_closure); + grpc_lfev_destroy(&fd->write_closure); + + gpr_mu_unlock(&fd_freelist_mu); +} + +static void fd_global_init(void) { gpr_mu_init(&fd_freelist_mu); } + +static void fd_global_shutdown(void) { + gpr_mu_lock(&fd_freelist_mu); + gpr_mu_unlock(&fd_freelist_mu); + while (fd_freelist != NULL) { + grpc_fd *fd = fd_freelist; + fd_freelist = fd_freelist->freelist_next; + gpr_mu_destroy(&fd->mu); + gpr_free(fd); + } + gpr_mu_destroy(&fd_freelist_mu); +} + +static grpc_fd *fd_create(int fd, const char *name) { + grpc_fd *new_fd = get_fd_from_freelist(); + if (new_fd == NULL) { + new_fd = gpr_malloc(sizeof(grpc_fd)); + gpr_mu_init(&new_fd->mu); + } + + /* Note: It is not really needed to get the new_fd->mu lock here. If this + * is a newly created fd (or an fd we got from the freelist), no one else + * would be holding a lock to it anyway. */ + gpr_mu_lock(&new_fd->mu); + new_fd->eps = NULL; + + new_fd->fd = fd; + new_fd->orphaned = false; + grpc_lfev_init(&new_fd->read_closure); + grpc_lfev_init(&new_fd->write_closure); + + new_fd->freelist_next = NULL; + new_fd->on_done_closure = NULL; + + gpr_mu_unlock(&new_fd->mu); + + char *fd_name; + gpr_asprintf(&fd_name, "%s fd=%d", name, fd); + grpc_iomgr_register_object(&new_fd->iomgr_object, fd_name); + gpr_log(GPR_DEBUG, "FD %d %p create %s", fd, (void *)new_fd, fd_name); + gpr_free(fd_name); + + /* Associate the fd with one of the eps */ + add_fd_to_eps(new_fd); + return new_fd; +} + +static int fd_wrapped_fd(grpc_fd *fd) { + int ret_fd = -1; + gpr_mu_lock(&fd->mu); + if (!fd->orphaned) { + ret_fd = fd->fd; + } + gpr_mu_unlock(&fd->mu); + + return ret_fd; +} + +static void fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd, + grpc_closure *on_done, int *release_fd, + bool already_closed, const char *reason) { + bool is_fd_closed = already_closed; + grpc_error *error = GRPC_ERROR_NONE; + epoll_set *unref_eps = NULL; + + gpr_mu_lock(&fd->mu); + fd->on_done_closure = on_done; + + /* If release_fd is not NULL, we should be relinquishing control of the file + descriptor fd->fd (but we still own the grpc_fd structure). */ + if (release_fd != NULL) { + *release_fd = fd->fd; + } else if (!is_fd_closed) { + close(fd->fd); + is_fd_closed = true; + } + + fd->orphaned = true; + + /* Remove the fd from the epoll set */ + if (fd->eps != NULL) { + epoll_set_remove_fd(fd->eps, fd, is_fd_closed, &error); + unref_eps = fd->eps; + fd->eps = NULL; + } + + GRPC_CLOSURE_SCHED(exec_ctx, fd->on_done_closure, GRPC_ERROR_REF(error)); + + gpr_mu_unlock(&fd->mu); + + /* We are done with this fd. Release it (i.e add back to freelist) */ + add_fd_to_freelist(fd); + + if (unref_eps != NULL) { + /* Unref stale epoll set here, outside the fd lock above. + The epoll set owns a workqueue which owns an fd, and unreffing + inside the lock can cause an eventual lock loop that makes TSAN very + unhappy. */ + EPS_UNREF(exec_ctx, unref_eps, "fd_orphan"); + } + GRPC_LOG_IF_ERROR("fd_orphan", GRPC_ERROR_REF(error)); + GRPC_ERROR_UNREF(error); +} + +/* This polling engine doesn't really need the read notifier functionality. So + * it just returns a dummy read notifier pollset */ +static grpc_pollset *fd_get_read_notifier_pollset(grpc_exec_ctx *exec_ctx, + grpc_fd *fd) { + return &g_read_notifier; +} + +static bool fd_is_shutdown(grpc_fd *fd) { + return grpc_lfev_is_shutdown(&fd->read_closure); +} + +/* Might be called multiple times */ +static void fd_shutdown(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_error *why) { + if (grpc_lfev_set_shutdown(exec_ctx, &fd->read_closure, + GRPC_ERROR_REF(why))) { + shutdown(fd->fd, SHUT_RDWR); + grpc_lfev_set_shutdown(exec_ctx, &fd->write_closure, GRPC_ERROR_REF(why)); + } + GRPC_ERROR_UNREF(why); +} + +static void fd_notify_on_read(grpc_exec_ctx *exec_ctx, grpc_fd *fd, + grpc_closure *closure) { + grpc_lfev_notify_on(exec_ctx, &fd->read_closure, closure, "read"); +} + +static void fd_notify_on_write(grpc_exec_ctx *exec_ctx, grpc_fd *fd, + grpc_closure *closure) { + grpc_lfev_notify_on(exec_ctx, &fd->write_closure, closure, "write"); +} + +/******************************************************************************* + * Pollset Definitions + */ +/* TODO: sreek - Not needed anymore */ +GPR_TLS_DECL(g_current_thread_pollset); +GPR_TLS_DECL(g_current_thread_worker); + +static void pollset_worker_init(grpc_pollset_worker *worker) { + worker->next = worker->prev = NULL; + gpr_cv_init(&worker->kick_cv); +} + +/* Global state management */ +static grpc_error *pollset_global_init(void) { + gpr_tls_init(&g_current_thread_pollset); + gpr_tls_init(&g_current_thread_worker); + return GRPC_ERROR_NONE; +} + +static void pollset_global_shutdown(void) { + gpr_tls_destroy(&g_current_thread_pollset); + gpr_tls_destroy(&g_current_thread_worker); +} + +static grpc_error *pollset_worker_kick(grpc_pollset_worker *worker) { + gpr_cv_signal(&worker->kick_cv); + return GRPC_ERROR_NONE; +} + +/* Return 1 if the pollset has active threads in pollset_work (pollset must + * be locked) */ +static int pollset_has_workers(grpc_pollset *p) { + return p->root_worker.next != &p->root_worker; +} + +static void remove_worker(grpc_pollset *p, grpc_pollset_worker *worker) { + worker->prev->next = worker->next; + worker->next->prev = worker->prev; +} + +static grpc_pollset_worker *pop_front_worker(grpc_pollset *p) { + if (pollset_has_workers(p)) { + grpc_pollset_worker *w = p->root_worker.next; + remove_worker(p, w); + return w; + } else { + return NULL; + } +} + +static void push_back_worker(grpc_pollset *p, grpc_pollset_worker *worker) { + worker->next = &p->root_worker; + worker->prev = worker->next->prev; + worker->prev->next = worker->next->prev = worker; +} + +static void push_front_worker(grpc_pollset *p, grpc_pollset_worker *worker) { + worker->prev = &p->root_worker; + worker->next = worker->prev->next; + worker->prev->next = worker->next->prev = worker; +} + +/* p->mu must be held before calling this function */ +static grpc_error *pollset_kick(grpc_pollset *p, + grpc_pollset_worker *specific_worker) { + GPR_TIMER_BEGIN("pollset_kick", 0); + grpc_error *error = GRPC_ERROR_NONE; + const char *err_desc = "Kick Failure"; + grpc_pollset_worker *worker = specific_worker; + if (worker != NULL) { + if (worker == GRPC_POLLSET_KICK_BROADCAST) { + if (pollset_has_workers(p)) { + GPR_TIMER_BEGIN("pollset_kick.broadcast", 0); + for (worker = p->root_worker.next; worker != &p->root_worker; + worker = worker->next) { + if (gpr_tls_get(&g_current_thread_worker) != (intptr_t)worker) { + append_error(&error, pollset_worker_kick(worker), err_desc); + } + } + GPR_TIMER_END("pollset_kick.broadcast", 0); + } else { + p->kicked_without_pollers = true; + } + } else { + GPR_TIMER_MARK("kicked_specifically", 0); + if (gpr_tls_get(&g_current_thread_worker) != (intptr_t)worker) { + append_error(&error, pollset_worker_kick(worker), err_desc); + } + } + } else if (gpr_tls_get(&g_current_thread_pollset) != (intptr_t)p) { + /* Since worker == NULL, it means that we can kick "any" worker on this + pollset 'p'. If 'p' happens to be the same pollset this thread is + currently polling (i.e in pollset_work() function), then there is no need + to kick any other worker since the current thread can just absorb the + kick. This is the reason why we enter this case only when + g_current_thread_pollset is != p */ + + GPR_TIMER_MARK("kick_anonymous", 0); + worker = pop_front_worker(p); + if (worker != NULL) { + GPR_TIMER_MARK("finally_kick", 0); + push_back_worker(p, worker); + append_error(&error, pollset_worker_kick(worker), err_desc); + } else { + GPR_TIMER_MARK("kicked_no_pollers", 0); + p->kicked_without_pollers = true; + } + } + + GPR_TIMER_END("pollset_kick", 0); + GRPC_LOG_IF_ERROR("pollset_kick", GRPC_ERROR_REF(error)); + return error; +} + +static void pollset_init(grpc_pollset *pollset, gpr_mu **mu) { + gpr_mu_init(&pollset->mu); + *mu = &pollset->mu; + pollset->eps = NULL; + + pollset->root_worker.next = pollset->root_worker.prev = &pollset->root_worker; + pollset->kicked_without_pollers = false; + + pollset->shutting_down = false; + pollset->finish_shutdown_called = false; + pollset->shutdown_done = NULL; +} + +static void fd_become_readable(grpc_exec_ctx *exec_ctx, grpc_fd *fd) { + grpc_lfev_set_ready(exec_ctx, &fd->read_closure, "read"); +} + +static void fd_become_writable(grpc_exec_ctx *exec_ctx, grpc_fd *fd) { + grpc_lfev_set_ready(exec_ctx, &fd->write_closure, "write"); +} + +static void pollset_release_epoll_set(grpc_exec_ctx *exec_ctx, grpc_pollset *ps, + char *reason) { + if (ps->eps != NULL) { + EPS_UNREF(exec_ctx, ps->eps, reason); + } + ps->eps = NULL; +} + +static void finish_shutdown_locked(grpc_exec_ctx *exec_ctx, + grpc_pollset *pollset) { + /* The pollset cannot have any workers if we are at this stage */ + GPR_ASSERT(!pollset_has_workers(pollset)); + + pollset->finish_shutdown_called = true; + + /* Release the ref and set pollset->eps to NULL */ + pollset_release_epoll_set(exec_ctx, pollset, "ps_shutdown"); + GRPC_CLOSURE_SCHED(exec_ctx, pollset->shutdown_done, GRPC_ERROR_NONE); +} + +/* pollset->mu lock must be held by the caller before calling this */ +static void pollset_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, + grpc_closure *closure) { + GPR_TIMER_BEGIN("pollset_shutdown", 0); + GPR_ASSERT(!pollset->shutting_down); + pollset->shutting_down = true; + pollset->shutdown_done = closure; + pollset_kick(pollset, GRPC_POLLSET_KICK_BROADCAST); + + /* If the pollset has any workers, we cannot call finish_shutdown_locked() + because it would release the underlying epoll set. In such a case, we + let the last worker call finish_shutdown_locked() from pollset_work() */ + if (!pollset_has_workers(pollset)) { + GPR_ASSERT(!pollset->finish_shutdown_called); + GPR_TIMER_MARK("pollset_shutdown.finish_shutdown_locked", 0); + finish_shutdown_locked(exec_ctx, pollset); + } + GPR_TIMER_END("pollset_shutdown", 0); +} + +/* pollset_shutdown is guaranteed to be called before pollset_destroy. So other + * than destroying the mutexes, there is nothing special that needs to be done + * here */ +static void pollset_destroy(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset) { + GPR_ASSERT(!pollset_has_workers(pollset)); + gpr_mu_destroy(&pollset->mu); +} + +/* Blocking call */ +static void acquire_epoll_lease(epoll_set *eps) { + if (g_num_threads_per_eps > 1) { + gpr_mu_lock(&eps->mu); + } +} + +static void release_epoll_lease(epoll_set *eps) { + if (g_num_threads_per_eps > 1) { + gpr_mu_unlock(&eps->mu); + } +} + +#define GRPC_EPOLL_MAX_EVENTS 100 +static void do_epoll_wait(grpc_exec_ctx *exec_ctx, int epoll_fd, epoll_set *eps, + grpc_error **error) { + struct epoll_event ep_ev[GRPC_EPOLL_MAX_EVENTS]; + int ep_rv; + char *err_msg; + const char *err_desc = "do_epoll_wait"; + + int timeout_ms = -1; + + GRPC_SCHEDULING_START_BLOCKING_REGION; + acquire_epoll_lease(eps); + ep_rv = epoll_wait(epoll_fd, ep_ev, GRPC_EPOLL_MAX_EVENTS, timeout_ms); + release_epoll_lease(eps); + GRPC_SCHEDULING_END_BLOCKING_REGION; + + if (ep_rv < 0) { + gpr_asprintf(&err_msg, + "epoll_wait() epoll fd: %d failed with error: %d (%s)", + epoll_fd, errno, strerror(errno)); + append_error(error, GRPC_OS_ERROR(errno, err_msg), err_desc); + } + +#ifdef GRPC_TSAN + /* See the definition of g_poll_sync for more details */ + gpr_atm_acq_load(&g_epoll_sync); +#endif /* defined(GRPC_TSAN) */ + + for (int i = 0; i < ep_rv; ++i) { + void *data_ptr = ep_ev[i].data.ptr; + if (data_ptr == &epoll_set_wakeup_fd) { + gpr_atm_rel_store(&eps->is_shutdown, 1); + gpr_log(GPR_INFO, "pollset poller: shutdown set"); + } else { + grpc_fd *fd = data_ptr; + int cancel = ep_ev[i].events & (EPOLLERR | EPOLLHUP); + int read_ev = ep_ev[i].events & (EPOLLIN | EPOLLPRI); + int write_ev = ep_ev[i].events & EPOLLOUT; + if (read_ev || cancel) { + fd_become_readable(exec_ctx, fd); + } + if (write_ev || cancel) { + fd_become_writable(exec_ctx, fd); + } + } + } +} + +static void epoll_set_work(grpc_exec_ctx *exec_ctx, epoll_set *eps, + grpc_error **error) { + int epoll_fd = -1; + GPR_TIMER_BEGIN("epoll_set_work", 0); + + /* Since epoll_fd is immutable, it is safe to read it without a lock on the + epoll set. */ + epoll_fd = eps->epoll_fd; + + gpr_atm_no_barrier_fetch_add(&eps->poller_count, 1); + g_current_thread_epoll_set = eps; + + do_epoll_wait(exec_ctx, epoll_fd, eps, error); + + g_current_thread_epoll_set = NULL; + gpr_atm_no_barrier_fetch_add(&eps->poller_count, -1); + + GPR_TIMER_END("epoll_set_work", 0); +} + +/* pollset->mu lock must be held by the caller before calling this. + The function pollset_work() may temporarily release the lock (pollset->mu) + during the course of its execution but it will always re-acquire the lock and + ensure that it is held by the time the function returns */ +static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, + grpc_pollset_worker **worker_hdl, + gpr_timespec now, gpr_timespec deadline) { + GPR_TIMER_BEGIN("pollset_work", 0); + grpc_error *error = GRPC_ERROR_NONE; + + grpc_pollset_worker worker; + pollset_worker_init(&worker); + + if (worker_hdl) *worker_hdl = &worker; + + gpr_tls_set(&g_current_thread_pollset, (intptr_t)pollset); + gpr_tls_set(&g_current_thread_worker, (intptr_t)&worker); + + if (pollset->kicked_without_pollers) { + /* If the pollset was kicked without pollers, pretend that the current + worker got the kick and skip polling. A kick indicates that there is some + work that needs attention like an event on the completion queue or an + alarm */ + GPR_TIMER_MARK("pollset_work.kicked_without_pollers", 0); + pollset->kicked_without_pollers = 0; + } else if (!pollset->shutting_down) { + push_front_worker(pollset, &worker); + + gpr_cv_wait(&worker.kick_cv, &pollset->mu, + gpr_convert_clock_type(deadline, GPR_CLOCK_REALTIME)); + /* pollset->mu locked here */ + + remove_worker(pollset, &worker); + } + + /* If we are the last worker on the pollset (i.e pollset_has_workers() is + false at this point) and the pollset is shutting down, we may have to + finish the shutdown process by calling finish_shutdown_locked(). + See pollset_shutdown() for more details. + + Note: Continuing to access pollset here is safe; it is the caller's + responsibility to not destroy a pollset when it has outstanding calls to + pollset_work() */ + if (pollset->shutting_down && !pollset_has_workers(pollset) && + !pollset->finish_shutdown_called) { + GPR_TIMER_MARK("pollset_work.finish_shutdown_locked", 0); + finish_shutdown_locked(exec_ctx, pollset); + + gpr_mu_unlock(&pollset->mu); + grpc_exec_ctx_flush(exec_ctx); + gpr_mu_lock(&pollset->mu); + } + + if (worker_hdl) *worker_hdl = NULL; + + gpr_tls_set(&g_current_thread_pollset, (intptr_t)0); + gpr_tls_set(&g_current_thread_worker, (intptr_t)0); + + GPR_TIMER_END("pollset_work", 0); + + GRPC_LOG_IF_ERROR("pollset_work", GRPC_ERROR_REF(error)); + return error; +} + +static void pollset_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, + grpc_fd *fd) { + /* Nothing to do */ +} + +/******************************************************************************* + * Pollset-set Definitions + */ +grpc_pollset_set g_dummy_pollset_set; +static grpc_pollset_set *pollset_set_create(void) { + return &g_dummy_pollset_set; +} + +static void pollset_set_destroy(grpc_exec_ctx *exec_ctx, + grpc_pollset_set *pss) { + /* Nothing to do */ +} + +static void pollset_set_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset_set *pss, + grpc_fd *fd) { + /* Nothing to do */ +} + +static void pollset_set_del_fd(grpc_exec_ctx *exec_ctx, grpc_pollset_set *pss, + grpc_fd *fd) { + /* Nothing to do */ +} + +static void pollset_set_add_pollset(grpc_exec_ctx *exec_ctx, + grpc_pollset_set *pss, grpc_pollset *ps) { + /* Nothing to do */ +} + +static void pollset_set_del_pollset(grpc_exec_ctx *exec_ctx, + grpc_pollset_set *pss, grpc_pollset *ps) { + /* Nothing to do */ +} + +static void pollset_set_add_pollset_set(grpc_exec_ctx *exec_ctx, + grpc_pollset_set *bag, + grpc_pollset_set *item) { + /* Nothing to do */ +} + +static void pollset_set_del_pollset_set(grpc_exec_ctx *exec_ctx, + grpc_pollset_set *bag, + grpc_pollset_set *item) { + /* Nothing to do */ +} + +/******************************************************************************* + * Event engine binding + */ + +static void shutdown_engine(void) { + shutdown_poller_threads(); + shutdown_epoll_sets(); + fd_global_shutdown(); + pollset_global_shutdown(); + epoll_set_global_shutdown(); + gpr_log(GPR_INFO, "ev-epoll-threadpool engine shutdown complete"); +} + +static const grpc_event_engine_vtable vtable = { + .pollset_size = sizeof(grpc_pollset), + + .fd_create = fd_create, + .fd_wrapped_fd = fd_wrapped_fd, + .fd_orphan = fd_orphan, + .fd_shutdown = fd_shutdown, + .fd_is_shutdown = fd_is_shutdown, + .fd_notify_on_read = fd_notify_on_read, + .fd_notify_on_write = fd_notify_on_write, + .fd_get_read_notifier_pollset = fd_get_read_notifier_pollset, + + .pollset_init = pollset_init, + .pollset_shutdown = pollset_shutdown, + .pollset_destroy = pollset_destroy, + .pollset_work = pollset_work, + .pollset_kick = pollset_kick, + .pollset_add_fd = pollset_add_fd, + + .pollset_set_create = pollset_set_create, + .pollset_set_destroy = pollset_set_destroy, + .pollset_set_add_pollset = pollset_set_add_pollset, + .pollset_set_del_pollset = pollset_set_del_pollset, + .pollset_set_add_pollset_set = pollset_set_add_pollset_set, + .pollset_set_del_pollset_set = pollset_set_del_pollset_set, + .pollset_set_add_fd = pollset_set_add_fd, + .pollset_set_del_fd = pollset_set_del_fd, + + .shutdown_engine = shutdown_engine, +}; + +/***************************************************************************** + * Dedicated polling threads and pollsets - Definitions + */ +static void add_fd_to_eps(grpc_fd *fd) { + GPR_ASSERT(fd->eps == NULL); + GPR_TIMER_BEGIN("add_fd_to_eps", 0); + + grpc_error *error = GRPC_ERROR_NONE; + size_t idx = (size_t)gpr_atm_no_barrier_fetch_add(&g_next_eps, 1) % g_num_eps; + epoll_set *eps = g_epoll_sets[idx]; + + gpr_mu_lock(&fd->mu); + + if (fd->orphaned) { + gpr_mu_unlock(&fd->mu); + return; /* Early out */ + } + + epoll_set_add_fd_locked(eps, fd, &error); + EPS_ADD_REF(eps, "fd"); + fd->eps = eps; + + GRPC_POLLING_TRACE("add_fd_to_eps (fd: %d, eps idx = %" PRIdPTR ")", fd->fd, + idx); + gpr_mu_unlock(&fd->mu); + + GRPC_LOG_IF_ERROR("add_fd_to_eps", error); + GPR_TIMER_END("add_fd_to_eps", 0); +} + +static bool init_epoll_sets() { + grpc_error *error = GRPC_ERROR_NONE; + bool is_success = true; + + g_epoll_sets = (epoll_set **)malloc(g_num_eps * sizeof(epoll_set *)); + + for (size_t i = 0; i < g_num_eps; i++) { + g_epoll_sets[i] = epoll_set_create(&error); + if (g_epoll_sets[i] == NULL) { + gpr_log(GPR_ERROR, "Error in creating a epoll set"); + g_num_eps = i; /* Helps cleanup */ + shutdown_epoll_sets(); + is_success = false; + goto done; + } + + EPS_ADD_REF(g_epoll_sets[i], "init_epoll_sets"); + } + + gpr_atm_no_barrier_store(&g_next_eps, 0); + gpr_mu *mu; + pollset_init(&g_read_notifier, &mu); + +done: + GRPC_LOG_IF_ERROR("init_epoll_sets", error); + return is_success; +} + +static void shutdown_epoll_sets() { + if (!g_epoll_sets) { + return; + } + + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + for (size_t i = 0; i < g_num_eps; i++) { + EPS_UNREF(&exec_ctx, g_epoll_sets[i], "shutdown_epoll_sets"); + } + grpc_exec_ctx_flush(&exec_ctx); + + gpr_free(g_epoll_sets); + g_epoll_sets = NULL; + pollset_destroy(&exec_ctx, &g_read_notifier); + grpc_exec_ctx_finish(&exec_ctx); +} + +static void poller_thread_loop(void *arg) { + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + grpc_error *error = GRPC_ERROR_NONE; + epoll_set *eps = (epoll_set *)arg; + + while (!gpr_atm_acq_load(&eps->is_shutdown)) { + epoll_set_work(&exec_ctx, eps, &error); + grpc_exec_ctx_flush(&exec_ctx); + } + + grpc_exec_ctx_finish(&exec_ctx); + GRPC_LOG_IF_ERROR("poller_thread_loop", error); +} + +/* g_epoll_sets MUST be initialized before calling this */ +static void start_poller_threads() { + GPR_ASSERT(g_epoll_sets); + + gpr_log(GPR_INFO, "Starting poller threads"); + + size_t num_threads = g_num_eps * g_num_threads_per_eps; + g_poller_threads = (gpr_thd_id *)malloc(num_threads * sizeof(gpr_thd_id)); + gpr_thd_options options = gpr_thd_options_default(); + gpr_thd_options_set_joinable(&options); + + for (size_t i = 0; i < num_threads; i++) { + gpr_thd_new(&g_poller_threads[i], poller_thread_loop, + (void *)g_epoll_sets[i % g_num_eps], &options); + } +} + +static void shutdown_poller_threads() { + GPR_ASSERT(g_poller_threads); + GPR_ASSERT(g_epoll_sets); + grpc_error *error = GRPC_ERROR_NONE; + + gpr_log(GPR_INFO, "Shutting down pollers"); + + epoll_set *eps = NULL; + size_t num_threads = g_num_eps * g_num_threads_per_eps; + for (size_t i = 0; i < num_threads; i++) { + eps = g_epoll_sets[i]; + epoll_set_add_wakeup_fd_locked(eps, &epoll_set_wakeup_fd, &error); + } + + for (size_t i = 0; i < g_num_eps; i++) { + gpr_thd_join(g_poller_threads[i]); + } + + GRPC_LOG_IF_ERROR("shutdown_poller_threads", error); + gpr_free(g_poller_threads); + g_poller_threads = NULL; +} + +/****************************************************************************/ + +/* It is possible that GLIBC has epoll but the underlying kernel doesn't. + * Create a dummy epoll_fd to make sure epoll support is available */ +static bool is_epoll_available() { + int fd = epoll_create1(EPOLL_CLOEXEC); + if (fd < 0) { + gpr_log( + GPR_ERROR, + "epoll_create1 failed with error: %d. Not using epoll polling engine", + fd); + return false; + } + close(fd); + return true; +} + +const grpc_event_engine_vtable *grpc_init_epoll_thread_pool_linux( + bool requested_explicitly) { + if (!requested_explicitly) return NULL; + + if (!grpc_has_wakeup_fd()) { + return NULL; + } + + if (!is_epoll_available()) { + return NULL; + } + + fd_global_init(); + + if (!GRPC_LOG_IF_ERROR("pollset_global_init", pollset_global_init())) { + return NULL; + } + + if (!GRPC_LOG_IF_ERROR("epoll_set_global_init", epoll_set_global_init())) { + return NULL; + } + + if (!init_epoll_sets()) { + return NULL; + } + + /* TODO (sreek): Maynot be a good idea to start threads here (especially if + * this engine doesn't get picked. Consider introducing an engine_init + * function in the vtable */ + start_poller_threads(); + return &vtable; +} + +#else /* defined(GRPC_LINUX_EPOLL) */ +#if defined(GRPC_POSIX_SOCKET) +#include "src/core/lib/iomgr/ev_posix.h" +/* If GRPC_LINUX_EPOLL is not defined, it means epoll is not available. Return + * NULL */ +const grpc_event_engine_vtable *grpc_init_epoll_thread_pool_linux( + bool requested_explicitly) { + return NULL; +} +#endif /* defined(GRPC_POSIX_SOCKET) */ +#endif /* !defined(GRPC_LINUX_EPOLL) */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/ev_epoll_thread_pool_linux.h b/Sources/CgRPC/src/core/lib/iomgr/ev_epoll_thread_pool_linux.h new file mode 100644 index 000000000..2ca68cc9d --- /dev/null +++ b/Sources/CgRPC/src/core/lib/iomgr/ev_epoll_thread_pool_linux.h @@ -0,0 +1,28 @@ +/* + * + * Copyright 2017 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 GRPC_CORE_LIB_IOMGR_EV_EPOLL_THREAD_POOL_LINUX_H +#define GRPC_CORE_LIB_IOMGR_EV_EPOLL_THREAD_POOL_LINUX_H + +#include "src/core/lib/iomgr/ev_posix.h" +#include "src/core/lib/iomgr/port.h" + +const grpc_event_engine_vtable *grpc_init_epoll_thread_pool_linux( + bool requested_explicitly); + +#endif /* GRPC_CORE_LIB_IOMGR_EV_EPOLL_THREAD_POOL_LINUX_H */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/ev_epollex_linux.c b/Sources/CgRPC/src/core/lib/iomgr/ev_epollex_linux.c new file mode 100644 index 000000000..770d1fd0a --- /dev/null +++ b/Sources/CgRPC/src/core/lib/iomgr/ev_epollex_linux.c @@ -0,0 +1,1448 @@ +/* + * + * Copyright 2017 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 "src/core/lib/iomgr/port.h" + +/* This polling engine is only relevant on linux kernels supporting epoll() */ +#ifdef GRPC_LINUX_EPOLL + +#include "src/core/lib/iomgr/ev_epollex_linux.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "src/core/lib/iomgr/ev_posix.h" +#include "src/core/lib/iomgr/iomgr_internal.h" +#include "src/core/lib/iomgr/is_epollexclusive_available.h" +#include "src/core/lib/iomgr/lockfree_event.h" +#include "src/core/lib/iomgr/sys_epoll_wrapper.h" +#include "src/core/lib/iomgr/timer.h" +#include "src/core/lib/iomgr/wakeup_fd_posix.h" +#include "src/core/lib/profiling/timers.h" +#include "src/core/lib/support/block_annotate.h" +#include "src/core/lib/support/spinlock.h" + +/******************************************************************************* + * Pollset-set sibling link + */ + +typedef enum { + PO_POLLING_GROUP, + PO_POLLSET_SET, + PO_POLLSET, + PO_FD, /* ordering is important: we always want to lock pollsets before fds: + this guarantees that using an fd as a pollable is safe */ + PO_EMPTY_POLLABLE, + PO_COUNT +} polling_obj_type; + +typedef struct polling_obj polling_obj; +typedef struct polling_group polling_group; + +struct polling_obj { + gpr_mu mu; + polling_obj_type type; + polling_group *group; + struct polling_obj *next; + struct polling_obj *prev; +}; + +struct polling_group { + polling_obj po; + gpr_refcount refs; +}; + +static void po_init(polling_obj *po, polling_obj_type type); +static void po_destroy(polling_obj *po); +static void po_join(grpc_exec_ctx *exec_ctx, polling_obj *a, polling_obj *b); +static int po_cmp(polling_obj *a, polling_obj *b); + +static void pg_create(grpc_exec_ctx *exec_ctx, polling_obj **initial_po, + size_t initial_po_count); +static polling_group *pg_ref(polling_group *pg); +static void pg_unref(polling_group *pg); +static void pg_merge(grpc_exec_ctx *exec_ctx, polling_group *a, + polling_group *b); +static void pg_join(grpc_exec_ctx *exec_ctx, polling_group *pg, + polling_obj *po); + +/******************************************************************************* + * pollable Declarations + */ + +typedef struct pollable { + polling_obj po; + int epfd; + grpc_wakeup_fd wakeup; + grpc_pollset_worker *root_worker; +} pollable; + +static const char *polling_obj_type_string(polling_obj_type t) { + switch (t) { + case PO_POLLING_GROUP: + return "polling_group"; + case PO_POLLSET_SET: + return "pollset_set"; + case PO_POLLSET: + return "pollset"; + case PO_FD: + return "fd"; + case PO_EMPTY_POLLABLE: + return "empty_pollable"; + case PO_COUNT: + return ""; + } + return ""; +} + +static char *pollable_desc(pollable *p) { + char *out; + gpr_asprintf(&out, "type=%s group=%p epfd=%d wakeup=%d", + polling_obj_type_string(p->po.type), p->po.group, p->epfd, + p->wakeup.read_fd); + return out; +} + +static pollable g_empty_pollable; + +static void pollable_init(pollable *p, polling_obj_type type); +static void pollable_destroy(pollable *p); +/* ensure that p->epfd, p->wakeup are initialized; p->po.mu must be held */ +static grpc_error *pollable_materialize(pollable *p); + +/******************************************************************************* + * Fd Declarations + */ + +struct grpc_fd { + pollable pollable; + int fd; + /* refst format: + bit 0 : 1=Active / 0=Orphaned + bits 1-n : refcount + Ref/Unref by two to avoid altering the orphaned bit */ + gpr_atm refst; + + /* The fd is either closed or we relinquished control of it. In either + cases, this indicates that the 'fd' on this structure is no longer + valid */ + gpr_mu orphaned_mu; + bool orphaned; + + gpr_atm read_closure; + gpr_atm write_closure; + + struct grpc_fd *freelist_next; + grpc_closure *on_done_closure; + + /* The pollset that last noticed that the fd is readable. The actual type + * stored in this is (grpc_pollset *) */ + gpr_atm read_notifier_pollset; + + grpc_iomgr_object iomgr_object; +}; + +static void fd_global_init(void); +static void fd_global_shutdown(void); + +/******************************************************************************* + * Pollset Declarations + */ + +typedef struct pollset_worker_link { + grpc_pollset_worker *next; + grpc_pollset_worker *prev; +} pollset_worker_link; + +typedef enum { + PWL_POLLSET, + PWL_POLLABLE, + POLLSET_WORKER_LINK_COUNT +} pollset_worker_links; + +struct grpc_pollset_worker { + bool kicked; + bool initialized_cv; + pollset_worker_link links[POLLSET_WORKER_LINK_COUNT]; + gpr_cv cv; + grpc_pollset *pollset; + pollable *pollable; +}; + +#define MAX_EPOLL_EVENTS 100 +#define MAX_EPOLL_EVENTS_HANDLED_EACH_POLL_CALL 5 + +struct grpc_pollset { + pollable pollable; + pollable *current_pollable; + int kick_alls_pending; + bool kicked_without_poller; + grpc_closure *shutdown_closure; + grpc_pollset_worker *root_worker; + + int event_cursor; + int event_count; + struct epoll_event events[MAX_EPOLL_EVENTS]; +}; + +/******************************************************************************* + * Pollset-set Declarations + */ +struct grpc_pollset_set { + polling_obj po; +}; + +/******************************************************************************* + * Common helpers + */ + +static bool append_error(grpc_error **composite, grpc_error *error, + const char *desc) { + if (error == GRPC_ERROR_NONE) return true; + if (*composite == GRPC_ERROR_NONE) { + *composite = GRPC_ERROR_CREATE_FROM_COPIED_STRING(desc); + } + *composite = grpc_error_add_child(*composite, error); + return false; +} + +/******************************************************************************* + * Fd Definitions + */ + +/* We need to keep a freelist not because of any concerns of malloc performance + * but instead so that implementations with multiple threads in (for example) + * epoll_wait deal with the race between pollset removal and incoming poll + * notifications. + * + * The problem is that the poller ultimately holds a reference to this + * object, so it is very difficult to know when is safe to free it, at least + * without some expensive synchronization. + * + * If we keep the object freelisted, in the worst case losing this race just + * becomes a spurious read notification on a reused fd. + */ + +/* The alarm system needs to be able to wakeup 'some poller' sometimes + * (specifically when a new alarm needs to be triggered earlier than the next + * alarm 'epoch'). This wakeup_fd gives us something to alert on when such a + * case occurs. */ + +static grpc_fd *fd_freelist = NULL; +static gpr_mu fd_freelist_mu; + +#ifndef NDEBUG +#define REF_BY(fd, n, reason) ref_by(fd, n, reason, __FILE__, __LINE__) +#define UNREF_BY(ec, fd, n, reason) \ + unref_by(ec, fd, n, reason, __FILE__, __LINE__) +static void ref_by(grpc_fd *fd, int n, const char *reason, const char *file, + int line) { + if (GRPC_TRACER_ON(grpc_trace_fd_refcount)) { + gpr_log(GPR_DEBUG, + "FD %d %p ref %d %" PRIdPTR " -> %" PRIdPTR " [%s; %s:%d]", + fd->fd, fd, n, gpr_atm_no_barrier_load(&fd->refst), + gpr_atm_no_barrier_load(&fd->refst) + n, reason, file, line); + } +#else +#define REF_BY(fd, n, reason) ref_by(fd, n) +#define UNREF_BY(ec, fd, n, reason) unref_by(ec, fd, n) +static void ref_by(grpc_fd *fd, int n) { +#endif + GPR_ASSERT(gpr_atm_no_barrier_fetch_add(&fd->refst, n) > 0); +} + +static void fd_destroy(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { + grpc_fd *fd = arg; + /* Add the fd to the freelist */ + grpc_iomgr_unregister_object(&fd->iomgr_object); + pollable_destroy(&fd->pollable); + gpr_mu_destroy(&fd->orphaned_mu); + gpr_mu_lock(&fd_freelist_mu); + fd->freelist_next = fd_freelist; + fd_freelist = fd; + + grpc_lfev_destroy(&fd->read_closure); + grpc_lfev_destroy(&fd->write_closure); + + gpr_mu_unlock(&fd_freelist_mu); +} + +#ifndef NDEBUG +static void unref_by(grpc_exec_ctx *exec_ctx, grpc_fd *fd, int n, + const char *reason, const char *file, int line) { + if (GRPC_TRACER_ON(grpc_trace_fd_refcount)) { + gpr_log(GPR_DEBUG, + "FD %d %p unref %d %" PRIdPTR " -> %" PRIdPTR " [%s; %s:%d]", + fd->fd, fd, n, gpr_atm_no_barrier_load(&fd->refst), + gpr_atm_no_barrier_load(&fd->refst) - n, reason, file, line); + } +#else +static void unref_by(grpc_exec_ctx *exec_ctx, grpc_fd *fd, int n) { +#endif + gpr_atm old = gpr_atm_full_fetch_add(&fd->refst, -n); + if (old == n) { + GRPC_CLOSURE_SCHED(exec_ctx, GRPC_CLOSURE_CREATE(fd_destroy, fd, + grpc_schedule_on_exec_ctx), + GRPC_ERROR_NONE); + } else { + GPR_ASSERT(old > n); + } +} + +static void fd_global_init(void) { gpr_mu_init(&fd_freelist_mu); } + +static void fd_global_shutdown(void) { + gpr_mu_lock(&fd_freelist_mu); + gpr_mu_unlock(&fd_freelist_mu); + while (fd_freelist != NULL) { + grpc_fd *fd = fd_freelist; + fd_freelist = fd_freelist->freelist_next; + gpr_free(fd); + } + gpr_mu_destroy(&fd_freelist_mu); +} + +static grpc_fd *fd_create(int fd, const char *name) { + grpc_fd *new_fd = NULL; + + gpr_mu_lock(&fd_freelist_mu); + if (fd_freelist != NULL) { + new_fd = fd_freelist; + fd_freelist = fd_freelist->freelist_next; + } + gpr_mu_unlock(&fd_freelist_mu); + + if (new_fd == NULL) { + new_fd = gpr_malloc(sizeof(grpc_fd)); + } + + pollable_init(&new_fd->pollable, PO_FD); + + gpr_atm_rel_store(&new_fd->refst, (gpr_atm)1); + new_fd->fd = fd; + gpr_mu_init(&new_fd->orphaned_mu); + new_fd->orphaned = false; + grpc_lfev_init(&new_fd->read_closure); + grpc_lfev_init(&new_fd->write_closure); + gpr_atm_no_barrier_store(&new_fd->read_notifier_pollset, (gpr_atm)NULL); + + new_fd->freelist_next = NULL; + new_fd->on_done_closure = NULL; + + char *fd_name; + gpr_asprintf(&fd_name, "%s fd=%d", name, fd); + grpc_iomgr_register_object(&new_fd->iomgr_object, fd_name); +#ifndef NDEBUG + if (GRPC_TRACER_ON(grpc_trace_fd_refcount)) { + gpr_log(GPR_DEBUG, "FD %d %p create %s", fd, new_fd, fd_name); + } +#endif + gpr_free(fd_name); + return new_fd; +} + +static int fd_wrapped_fd(grpc_fd *fd) { + int ret_fd = -1; + gpr_mu_lock(&fd->orphaned_mu); + if (!fd->orphaned) { + ret_fd = fd->fd; + } + gpr_mu_unlock(&fd->orphaned_mu); + + return ret_fd; +} + +static void fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd, + grpc_closure *on_done, int *release_fd, + bool already_closed, const char *reason) { + bool is_fd_closed = already_closed; + grpc_error *error = GRPC_ERROR_NONE; + + gpr_mu_lock(&fd->pollable.po.mu); + gpr_mu_lock(&fd->orphaned_mu); + fd->on_done_closure = on_done; + + /* If release_fd is not NULL, we should be relinquishing control of the file + descriptor fd->fd (but we still own the grpc_fd structure). */ + if (release_fd != NULL) { + *release_fd = fd->fd; + } else if (!is_fd_closed) { + close(fd->fd); + is_fd_closed = true; + } + + fd->orphaned = true; + + if (!is_fd_closed) { + gpr_log(GPR_DEBUG, "TODO: handle fd removal?"); + } + + /* Remove the active status but keep referenced. We want this grpc_fd struct + to be alive (and not added to freelist) until the end of this function */ + REF_BY(fd, 1, reason); + + GRPC_CLOSURE_SCHED(exec_ctx, fd->on_done_closure, GRPC_ERROR_REF(error)); + + gpr_mu_unlock(&fd->orphaned_mu); + gpr_mu_unlock(&fd->pollable.po.mu); + UNREF_BY(exec_ctx, fd, 2, reason); /* Drop the reference */ + GRPC_LOG_IF_ERROR("fd_orphan", GRPC_ERROR_REF(error)); + GRPC_ERROR_UNREF(error); +} + +static grpc_pollset *fd_get_read_notifier_pollset(grpc_exec_ctx *exec_ctx, + grpc_fd *fd) { + gpr_atm notifier = gpr_atm_acq_load(&fd->read_notifier_pollset); + return (grpc_pollset *)notifier; +} + +static bool fd_is_shutdown(grpc_fd *fd) { + return grpc_lfev_is_shutdown(&fd->read_closure); +} + +/* Might be called multiple times */ +static void fd_shutdown(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_error *why) { + if (grpc_lfev_set_shutdown(exec_ctx, &fd->read_closure, + GRPC_ERROR_REF(why))) { + shutdown(fd->fd, SHUT_RDWR); + grpc_lfev_set_shutdown(exec_ctx, &fd->write_closure, GRPC_ERROR_REF(why)); + } + GRPC_ERROR_UNREF(why); +} + +static void fd_notify_on_read(grpc_exec_ctx *exec_ctx, grpc_fd *fd, + grpc_closure *closure) { + grpc_lfev_notify_on(exec_ctx, &fd->read_closure, closure, "read"); +} + +static void fd_notify_on_write(grpc_exec_ctx *exec_ctx, grpc_fd *fd, + grpc_closure *closure) { + grpc_lfev_notify_on(exec_ctx, &fd->write_closure, closure, "write"); +} + +/******************************************************************************* + * Pollable Definitions + */ + +static void pollable_init(pollable *p, polling_obj_type type) { + po_init(&p->po, type); + p->root_worker = NULL; + p->epfd = -1; +} + +static void pollable_destroy(pollable *p) { + po_destroy(&p->po); + if (p->epfd != -1) { + close(p->epfd); + grpc_wakeup_fd_destroy(&p->wakeup); + } +} + +/* ensure that p->epfd, p->wakeup are initialized; p->po.mu must be held */ +static grpc_error *pollable_materialize(pollable *p) { + if (p->epfd == -1) { + int new_epfd = epoll_create1(EPOLL_CLOEXEC); + if (new_epfd < 0) { + return GRPC_OS_ERROR(errno, "epoll_create1"); + } + grpc_error *err = grpc_wakeup_fd_init(&p->wakeup); + if (err != GRPC_ERROR_NONE) { + close(new_epfd); + return err; + } + struct epoll_event ev = {.events = (uint32_t)(EPOLLIN | EPOLLET), + .data.ptr = (void *)(1 | (intptr_t)&p->wakeup)}; + if (epoll_ctl(new_epfd, EPOLL_CTL_ADD, p->wakeup.read_fd, &ev) != 0) { + err = GRPC_OS_ERROR(errno, "epoll_ctl"); + close(new_epfd); + grpc_wakeup_fd_destroy(&p->wakeup); + return err; + } + + p->epfd = new_epfd; + } + return GRPC_ERROR_NONE; +} + +/* pollable must be materialized */ +static grpc_error *pollable_add_fd(pollable *p, grpc_fd *fd) { + grpc_error *error = GRPC_ERROR_NONE; + static const char *err_desc = "pollable_add_fd"; + const int epfd = p->epfd; + GPR_ASSERT(epfd != -1); + + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_DEBUG, "add fd %p (%d) to pollable %p", fd, fd->fd, p); + } + + gpr_mu_lock(&fd->orphaned_mu); + if (fd->orphaned) { + gpr_mu_unlock(&fd->orphaned_mu); + return GRPC_ERROR_NONE; + } + struct epoll_event ev_fd = { + .events = (uint32_t)(EPOLLET | EPOLLIN | EPOLLOUT | EPOLLEXCLUSIVE), + .data.ptr = fd}; + if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd->fd, &ev_fd) != 0) { + switch (errno) { + case EEXIST: + break; + default: + append_error(&error, GRPC_OS_ERROR(errno, "epoll_ctl"), err_desc); + } + } + gpr_mu_unlock(&fd->orphaned_mu); + + return error; +} + +/******************************************************************************* + * Pollset Definitions + */ + +GPR_TLS_DECL(g_current_thread_pollset); +GPR_TLS_DECL(g_current_thread_worker); + +/* Global state management */ +static grpc_error *pollset_global_init(void) { + gpr_tls_init(&g_current_thread_pollset); + gpr_tls_init(&g_current_thread_worker); + pollable_init(&g_empty_pollable, PO_EMPTY_POLLABLE); + return GRPC_ERROR_NONE; +} + +static void pollset_global_shutdown(void) { + pollable_destroy(&g_empty_pollable); + gpr_tls_destroy(&g_current_thread_pollset); + gpr_tls_destroy(&g_current_thread_worker); +} + +static void pollset_maybe_finish_shutdown(grpc_exec_ctx *exec_ctx, + grpc_pollset *pollset) { + if (pollset->shutdown_closure != NULL && pollset->root_worker == NULL && + pollset->kick_alls_pending == 0) { + GRPC_CLOSURE_SCHED(exec_ctx, pollset->shutdown_closure, GRPC_ERROR_NONE); + pollset->shutdown_closure = NULL; + } +} + +static void do_kick_all(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error_unused) { + grpc_error *error = GRPC_ERROR_NONE; + grpc_pollset *pollset = arg; + gpr_mu_lock(&pollset->pollable.po.mu); + if (pollset->root_worker != NULL) { + grpc_pollset_worker *worker = pollset->root_worker; + do { + if (worker->pollable != &pollset->pollable) { + gpr_mu_lock(&worker->pollable->po.mu); + } + if (worker->initialized_cv && worker != pollset->root_worker) { + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_DEBUG, "PS:%p kickall_via_cv %p (pollable %p vs %p)", + pollset, worker, &pollset->pollable, worker->pollable); + } + worker->kicked = true; + gpr_cv_signal(&worker->cv); + } else { + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_DEBUG, "PS:%p kickall_via_wakeup %p (pollable %p vs %p)", + pollset, worker, &pollset->pollable, worker->pollable); + } + append_error(&error, grpc_wakeup_fd_wakeup(&worker->pollable->wakeup), + "pollset_shutdown"); + } + if (worker->pollable != &pollset->pollable) { + gpr_mu_unlock(&worker->pollable->po.mu); + } + + worker = worker->links[PWL_POLLSET].next; + } while (worker != pollset->root_worker); + } + pollset->kick_alls_pending--; + pollset_maybe_finish_shutdown(exec_ctx, pollset); + gpr_mu_unlock(&pollset->pollable.po.mu); + GRPC_LOG_IF_ERROR("kick_all", error); +} + +static void pollset_kick_all(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset) { + pollset->kick_alls_pending++; + GRPC_CLOSURE_SCHED(exec_ctx, GRPC_CLOSURE_CREATE(do_kick_all, pollset, + grpc_schedule_on_exec_ctx), + GRPC_ERROR_NONE); +} + +static grpc_error *pollset_kick_inner(grpc_pollset *pollset, pollable *p, + grpc_pollset_worker *specific_worker) { + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_DEBUG, + "PS:%p kick %p tls_pollset=%p tls_worker=%p " + "root_worker=(pollset:%p pollable:%p)", + p, specific_worker, (void *)gpr_tls_get(&g_current_thread_pollset), + (void *)gpr_tls_get(&g_current_thread_worker), pollset->root_worker, + p->root_worker); + } + if (specific_worker == NULL) { + if (gpr_tls_get(&g_current_thread_pollset) != (intptr_t)pollset) { + if (pollset->root_worker == NULL) { + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_DEBUG, "PS:%p kicked_any_without_poller", p); + } + pollset->kicked_without_poller = true; + return GRPC_ERROR_NONE; + } else { + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_DEBUG, "PS:%p kicked_any_via_wakeup_fd", p); + } + grpc_error *err = pollable_materialize(p); + if (err != GRPC_ERROR_NONE) return err; + return grpc_wakeup_fd_wakeup(&p->wakeup); + } + } else { + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_DEBUG, "PS:%p kicked_any_but_awake", p); + } + return GRPC_ERROR_NONE; + } + } else if (specific_worker->kicked) { + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_DEBUG, "PS:%p kicked_specific_but_already_kicked", p); + } + return GRPC_ERROR_NONE; + } else if (gpr_tls_get(&g_current_thread_worker) == + (intptr_t)specific_worker) { + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_DEBUG, "PS:%p kicked_specific_but_awake", p); + } + specific_worker->kicked = true; + return GRPC_ERROR_NONE; + } else if (specific_worker == p->root_worker) { + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_DEBUG, "PS:%p kicked_specific_via_wakeup_fd", p); + } + grpc_error *err = pollable_materialize(p); + if (err != GRPC_ERROR_NONE) return err; + specific_worker->kicked = true; + return grpc_wakeup_fd_wakeup(&p->wakeup); + } else { + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_DEBUG, "PS:%p kicked_specific_via_cv", p); + } + specific_worker->kicked = true; + gpr_cv_signal(&specific_worker->cv); + return GRPC_ERROR_NONE; + } +} + +/* p->po.mu must be held before calling this function */ +static grpc_error *pollset_kick(grpc_pollset *pollset, + grpc_pollset_worker *specific_worker) { + pollable *p = pollset->current_pollable; + if (p != &pollset->pollable) { + gpr_mu_lock(&p->po.mu); + } + grpc_error *error = pollset_kick_inner(pollset, p, specific_worker); + if (p != &pollset->pollable) { + gpr_mu_unlock(&p->po.mu); + } + return error; +} + +static void pollset_init(grpc_pollset *pollset, gpr_mu **mu) { + pollable_init(&pollset->pollable, PO_POLLSET); + pollset->current_pollable = &g_empty_pollable; + pollset->kicked_without_poller = false; + pollset->shutdown_closure = NULL; + pollset->root_worker = NULL; + *mu = &pollset->pollable.po.mu; +} + +/* Convert a timespec to milliseconds: + - Very small or negative poll times are clamped to zero to do a non-blocking + poll (which becomes spin polling) + - Other small values are rounded up to one millisecond + - Longer than a millisecond polls are rounded up to the next nearest + millisecond to avoid spinning + - Infinite timeouts are converted to -1 */ +static int poll_deadline_to_millis_timeout(gpr_timespec deadline, + gpr_timespec now) { + gpr_timespec timeout; + if (gpr_time_cmp(deadline, gpr_inf_future(deadline.clock_type)) == 0) { + return -1; + } + + if (gpr_time_cmp(deadline, now) <= 0) { + return 0; + } + + static const gpr_timespec round_up = { + .clock_type = GPR_TIMESPAN, .tv_sec = 0, .tv_nsec = GPR_NS_PER_MS - 1}; + timeout = gpr_time_sub(deadline, now); + int millis = gpr_time_to_millis(gpr_time_add(timeout, round_up)); + return millis >= 1 ? millis : 1; +} + +static void fd_become_readable(grpc_exec_ctx *exec_ctx, grpc_fd *fd, + grpc_pollset *notifier) { + grpc_lfev_set_ready(exec_ctx, &fd->read_closure, "read"); + + /* Note, it is possible that fd_become_readable might be called twice with + different 'notifier's when an fd becomes readable and it is in two epoll + sets (This can happen briefly during polling island merges). In such cases + it does not really matter which notifer is set as the read_notifier_pollset + (They would both point to the same polling island anyway) */ + /* Use release store to match with acquire load in fd_get_read_notifier */ + gpr_atm_rel_store(&fd->read_notifier_pollset, (gpr_atm)notifier); +} + +static void fd_become_writable(grpc_exec_ctx *exec_ctx, grpc_fd *fd) { + grpc_lfev_set_ready(exec_ctx, &fd->write_closure, "write"); +} + +static grpc_error *fd_become_pollable_locked(grpc_fd *fd) { + grpc_error *error = GRPC_ERROR_NONE; + static const char *err_desc = "fd_become_pollable"; + if (append_error(&error, pollable_materialize(&fd->pollable), err_desc)) { + append_error(&error, pollable_add_fd(&fd->pollable, fd), err_desc); + } + return error; +} + +/* pollset->po.mu lock must be held by the caller before calling this */ +static void pollset_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, + grpc_closure *closure) { + GPR_ASSERT(pollset->shutdown_closure == NULL); + pollset->shutdown_closure = closure; + pollset_kick_all(exec_ctx, pollset); + pollset_maybe_finish_shutdown(exec_ctx, pollset); +} + +static bool pollset_is_pollable_fd(grpc_pollset *pollset, pollable *p) { + return p != &g_empty_pollable && p != &pollset->pollable; +} + +static grpc_error *pollset_process_events(grpc_exec_ctx *exec_ctx, + grpc_pollset *pollset, bool drain) { + static const char *err_desc = "pollset_process_events"; + grpc_error *error = GRPC_ERROR_NONE; + for (int i = 0; (drain || i < MAX_EPOLL_EVENTS_HANDLED_EACH_POLL_CALL) && + pollset->event_cursor != pollset->event_count; + i++) { + int n = pollset->event_cursor++; + struct epoll_event *ev = &pollset->events[n]; + void *data_ptr = ev->data.ptr; + if (1 & (intptr_t)data_ptr) { + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_DEBUG, "PS:%p got pollset_wakeup %p", pollset, data_ptr); + } + append_error(&error, grpc_wakeup_fd_consume_wakeup( + (void *)((~(intptr_t)1) & (intptr_t)data_ptr)), + err_desc); + } else { + grpc_fd *fd = (grpc_fd *)data_ptr; + bool cancel = (ev->events & (EPOLLERR | EPOLLHUP)) != 0; + bool read_ev = (ev->events & (EPOLLIN | EPOLLPRI)) != 0; + bool write_ev = (ev->events & EPOLLOUT) != 0; + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_DEBUG, + "PS:%p got fd %p: cancel=%d read=%d " + "write=%d", + pollset, fd, cancel, read_ev, write_ev); + } + if (read_ev || cancel) { + fd_become_readable(exec_ctx, fd, pollset); + } + if (write_ev || cancel) { + fd_become_writable(exec_ctx, fd); + } + } + } + + return error; +} + +/* pollset_shutdown is guaranteed to be called before pollset_destroy. */ +static void pollset_destroy(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset) { + pollable_destroy(&pollset->pollable); + if (pollset_is_pollable_fd(pollset, pollset->current_pollable)) { + UNREF_BY(exec_ctx, (grpc_fd *)pollset->current_pollable, 2, + "pollset_pollable"); + } + GRPC_LOG_IF_ERROR("pollset_process_events", + pollset_process_events(exec_ctx, pollset, true)); +} + +static grpc_error *pollset_epoll(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, + pollable *p, gpr_timespec now, + gpr_timespec deadline) { + int timeout = poll_deadline_to_millis_timeout(deadline, now); + + if (GRPC_TRACER_ON(grpc_polling_trace)) { + char *desc = pollable_desc(p); + gpr_log(GPR_DEBUG, "PS:%p poll %p[%s] for %dms", pollset, p, desc, timeout); + gpr_free(desc); + } + + if (timeout != 0) { + GRPC_SCHEDULING_START_BLOCKING_REGION; + } + int r; + do { + r = epoll_wait(p->epfd, pollset->events, MAX_EPOLL_EVENTS, timeout); + } while (r < 0 && errno == EINTR); + if (timeout != 0) { + GRPC_SCHEDULING_END_BLOCKING_REGION; + } + + if (r < 0) return GRPC_OS_ERROR(errno, "epoll_wait"); + + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_DEBUG, "PS:%p poll %p got %d events", pollset, p, r); + } + + pollset->event_cursor = 0; + pollset->event_count = r; + + return GRPC_ERROR_NONE; +} + +/* Return true if first in list */ +static bool worker_insert(grpc_pollset_worker **root, pollset_worker_links link, + grpc_pollset_worker *worker) { + if (*root == NULL) { + *root = worker; + worker->links[link].next = worker->links[link].prev = worker; + return true; + } else { + worker->links[link].next = *root; + worker->links[link].prev = worker->links[link].next->links[link].prev; + worker->links[link].next->links[link].prev = worker; + worker->links[link].prev->links[link].next = worker; + return false; + } +} + +/* Return true if last in list */ +typedef enum { EMPTIED, NEW_ROOT, REMOVED } worker_remove_result; + +static worker_remove_result worker_remove(grpc_pollset_worker **root, + pollset_worker_links link, + grpc_pollset_worker *worker) { + if (worker == *root) { + if (worker == worker->links[link].next) { + *root = NULL; + return EMPTIED; + } else { + *root = worker->links[link].next; + worker->links[link].prev->links[link].next = worker->links[link].next; + worker->links[link].next->links[link].prev = worker->links[link].prev; + return NEW_ROOT; + } + } else { + worker->links[link].prev->links[link].next = worker->links[link].next; + worker->links[link].next->links[link].prev = worker->links[link].prev; + return REMOVED; + } +} + +/* Return true if this thread should poll */ +static bool begin_worker(grpc_pollset *pollset, grpc_pollset_worker *worker, + grpc_pollset_worker **worker_hdl, gpr_timespec *now, + gpr_timespec deadline) { + bool do_poll = true; + if (worker_hdl != NULL) *worker_hdl = worker; + worker->initialized_cv = false; + worker->kicked = false; + worker->pollset = pollset; + worker->pollable = pollset->current_pollable; + + if (pollset_is_pollable_fd(pollset, worker->pollable)) { + REF_BY((grpc_fd *)worker->pollable, 2, "one_poll"); + } + + worker_insert(&pollset->root_worker, PWL_POLLSET, worker); + if (!worker_insert(&worker->pollable->root_worker, PWL_POLLABLE, worker)) { + worker->initialized_cv = true; + gpr_cv_init(&worker->cv); + if (worker->pollable != &pollset->pollable) { + gpr_mu_unlock(&pollset->pollable.po.mu); + } + if (GRPC_TRACER_ON(grpc_polling_trace) && + worker->pollable->root_worker != worker) { + gpr_log(GPR_DEBUG, "PS:%p wait %p w=%p for %dms", pollset, + worker->pollable, worker, + poll_deadline_to_millis_timeout(deadline, *now)); + } + while (do_poll && worker->pollable->root_worker != worker) { + if (gpr_cv_wait(&worker->cv, &worker->pollable->po.mu, deadline)) { + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_DEBUG, "PS:%p timeout_wait %p w=%p", pollset, + worker->pollable, worker); + } + do_poll = false; + } else if (worker->kicked) { + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_DEBUG, "PS:%p wakeup %p w=%p", pollset, worker->pollable, + worker); + } + do_poll = false; + } else if (GRPC_TRACER_ON(grpc_polling_trace) && + worker->pollable->root_worker != worker) { + gpr_log(GPR_DEBUG, "PS:%p spurious_wakeup %p w=%p", pollset, + worker->pollable, worker); + } + } + if (worker->pollable != &pollset->pollable) { + gpr_mu_unlock(&worker->pollable->po.mu); + gpr_mu_lock(&pollset->pollable.po.mu); + gpr_mu_lock(&worker->pollable->po.mu); + } + *now = gpr_now(now->clock_type); + } + + return do_poll && pollset->shutdown_closure == NULL && + pollset->current_pollable == worker->pollable; +} + +static void end_worker(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, + grpc_pollset_worker *worker, + grpc_pollset_worker **worker_hdl) { + if (NEW_ROOT == + worker_remove(&worker->pollable->root_worker, PWL_POLLABLE, worker)) { + gpr_cv_signal(&worker->pollable->root_worker->cv); + } + if (worker->initialized_cv) { + gpr_cv_destroy(&worker->cv); + } + if (pollset_is_pollable_fd(pollset, worker->pollable)) { + UNREF_BY(exec_ctx, (grpc_fd *)worker->pollable, 2, "one_poll"); + } + if (EMPTIED == worker_remove(&pollset->root_worker, PWL_POLLSET, worker)) { + pollset_maybe_finish_shutdown(exec_ctx, pollset); + } +} + +/* pollset->po.mu lock must be held by the caller before calling this. + The function pollset_work() may temporarily release the lock (pollset->po.mu) + during the course of its execution but it will always re-acquire the lock and + ensure that it is held by the time the function returns */ +static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, + grpc_pollset_worker **worker_hdl, + gpr_timespec now, gpr_timespec deadline) { + grpc_pollset_worker worker; + if (0 && GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_DEBUG, "PS:%p work hdl=%p worker=%p now=%" PRId64 + ".%09d deadline=%" PRId64 ".%09d kwp=%d root_worker=%p", + pollset, worker_hdl, &worker, now.tv_sec, now.tv_nsec, + deadline.tv_sec, deadline.tv_nsec, pollset->kicked_without_poller, + pollset->root_worker); + } + grpc_error *error = GRPC_ERROR_NONE; + static const char *err_desc = "pollset_work"; + if (pollset->kicked_without_poller) { + pollset->kicked_without_poller = false; + return GRPC_ERROR_NONE; + } + if (pollset->current_pollable != &pollset->pollable) { + gpr_mu_lock(&pollset->current_pollable->po.mu); + } + if (begin_worker(pollset, &worker, worker_hdl, &now, deadline)) { + gpr_tls_set(&g_current_thread_pollset, (intptr_t)pollset); + gpr_tls_set(&g_current_thread_worker, (intptr_t)&worker); + GPR_ASSERT(!pollset->shutdown_closure); + append_error(&error, pollable_materialize(worker.pollable), err_desc); + if (worker.pollable != &pollset->pollable) { + gpr_mu_unlock(&worker.pollable->po.mu); + } + gpr_mu_unlock(&pollset->pollable.po.mu); + if (pollset->event_cursor == pollset->event_count) { + append_error(&error, pollset_epoll(exec_ctx, pollset, worker.pollable, + now, deadline), + err_desc); + } + append_error(&error, pollset_process_events(exec_ctx, pollset, false), + err_desc); + gpr_mu_lock(&pollset->pollable.po.mu); + if (worker.pollable != &pollset->pollable) { + gpr_mu_lock(&worker.pollable->po.mu); + } + gpr_tls_set(&g_current_thread_pollset, 0); + gpr_tls_set(&g_current_thread_worker, 0); + pollset_maybe_finish_shutdown(exec_ctx, pollset); + } + end_worker(exec_ctx, pollset, &worker, worker_hdl); + if (worker.pollable != &pollset->pollable) { + gpr_mu_unlock(&worker.pollable->po.mu); + } + if (grpc_exec_ctx_has_work(exec_ctx)) { + gpr_mu_unlock(&pollset->pollable.po.mu); + grpc_exec_ctx_flush(exec_ctx); + gpr_mu_lock(&pollset->pollable.po.mu); + } + return error; +} + +static void unref_fd_no_longer_poller(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error) { + grpc_fd *fd = arg; + UNREF_BY(exec_ctx, fd, 2, "pollset_pollable"); +} + +/* expects pollsets locked, flag whether fd is locked or not */ +static grpc_error *pollset_add_fd_locked(grpc_exec_ctx *exec_ctx, + grpc_pollset *pollset, grpc_fd *fd, + bool fd_locked) { + static const char *err_desc = "pollset_add_fd"; + grpc_error *error = GRPC_ERROR_NONE; + if (pollset->current_pollable == &g_empty_pollable) { + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_DEBUG, + "PS:%p add fd %p; transition pollable from empty to fd", pollset, + fd); + } + /* empty pollable --> single fd pollable */ + pollset_kick_all(exec_ctx, pollset); + pollset->current_pollable = &fd->pollable; + if (!fd_locked) gpr_mu_lock(&fd->pollable.po.mu); + append_error(&error, fd_become_pollable_locked(fd), err_desc); + if (!fd_locked) gpr_mu_unlock(&fd->pollable.po.mu); + REF_BY(fd, 2, "pollset_pollable"); + } else if (pollset->current_pollable == &pollset->pollable) { + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_DEBUG, "PS:%p add fd %p; already multipolling", pollset, fd); + } + append_error(&error, pollable_add_fd(pollset->current_pollable, fd), + err_desc); + } else if (pollset->current_pollable != &fd->pollable) { + grpc_fd *had_fd = (grpc_fd *)pollset->current_pollable; + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_DEBUG, + "PS:%p add fd %p; transition pollable from fd %p to multipoller", + pollset, fd, had_fd); + } + /* Introduce a spurious completion. + If we do not, then it may be that the fd-specific epoll set consumed + a completion without being polled, leading to a missed edge going up. */ + grpc_lfev_set_ready(exec_ctx, &had_fd->read_closure, "read"); + grpc_lfev_set_ready(exec_ctx, &had_fd->write_closure, "write"); + pollset_kick_all(exec_ctx, pollset); + pollset->current_pollable = &pollset->pollable; + if (append_error(&error, pollable_materialize(&pollset->pollable), + err_desc)) { + pollable_add_fd(&pollset->pollable, had_fd); + pollable_add_fd(&pollset->pollable, fd); + } + GRPC_CLOSURE_SCHED(exec_ctx, + GRPC_CLOSURE_CREATE(unref_fd_no_longer_poller, had_fd, + grpc_schedule_on_exec_ctx), + GRPC_ERROR_NONE); + } + return error; +} + +static void pollset_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, + grpc_fd *fd) { + gpr_mu_lock(&pollset->pollable.po.mu); + grpc_error *error = pollset_add_fd_locked(exec_ctx, pollset, fd, false); + gpr_mu_unlock(&pollset->pollable.po.mu); + GRPC_LOG_IF_ERROR("pollset_add_fd", error); +} + +/******************************************************************************* + * Pollset-set Definitions + */ + +static grpc_pollset_set *pollset_set_create(void) { + grpc_pollset_set *pss = gpr_zalloc(sizeof(*pss)); + po_init(&pss->po, PO_POLLSET_SET); + return pss; +} + +static void pollset_set_destroy(grpc_exec_ctx *exec_ctx, + grpc_pollset_set *pss) { + po_destroy(&pss->po); + gpr_free(pss); +} + +static void pollset_set_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset_set *pss, + grpc_fd *fd) { + po_join(exec_ctx, &pss->po, &fd->pollable.po); +} + +static void pollset_set_del_fd(grpc_exec_ctx *exec_ctx, grpc_pollset_set *pss, + grpc_fd *fd) {} + +static void pollset_set_add_pollset(grpc_exec_ctx *exec_ctx, + grpc_pollset_set *pss, grpc_pollset *ps) { + po_join(exec_ctx, &pss->po, &ps->pollable.po); +} + +static void pollset_set_del_pollset(grpc_exec_ctx *exec_ctx, + grpc_pollset_set *pss, grpc_pollset *ps) {} + +static void pollset_set_add_pollset_set(grpc_exec_ctx *exec_ctx, + grpc_pollset_set *bag, + grpc_pollset_set *item) { + po_join(exec_ctx, &bag->po, &item->po); +} + +static void pollset_set_del_pollset_set(grpc_exec_ctx *exec_ctx, + grpc_pollset_set *bag, + grpc_pollset_set *item) {} + +static void po_init(polling_obj *po, polling_obj_type type) { + gpr_mu_init(&po->mu); + po->type = type; + po->group = NULL; + po->next = po; + po->prev = po; +} + +static polling_group *pg_lock_latest(polling_group *pg) { + /* assumes pg unlocked; consumes ref, returns ref */ + gpr_mu_lock(&pg->po.mu); + while (pg->po.group != NULL) { + polling_group *new_pg = pg_ref(pg->po.group); + gpr_mu_unlock(&pg->po.mu); + pg_unref(pg); + pg = new_pg; + gpr_mu_lock(&pg->po.mu); + } + return pg; +} + +static void po_destroy(polling_obj *po) { + if (po->group != NULL) { + polling_group *pg = pg_lock_latest(po->group); + po->prev->next = po->next; + po->next->prev = po->prev; + gpr_mu_unlock(&pg->po.mu); + pg_unref(pg); + } + gpr_mu_destroy(&po->mu); +} + +static polling_group *pg_ref(polling_group *pg) { + gpr_ref(&pg->refs); + return pg; +} + +static void pg_unref(polling_group *pg) { + if (gpr_unref(&pg->refs)) { + po_destroy(&pg->po); + gpr_free(pg); + } +} + +static int po_cmp(polling_obj *a, polling_obj *b) { + if (a == b) return 0; + if (a->type < b->type) return -1; + if (a->type > b->type) return 1; + if (a < b) return -1; + assert(a > b); + return 1; +} + +static void po_join(grpc_exec_ctx *exec_ctx, polling_obj *a, polling_obj *b) { + switch (po_cmp(a, b)) { + case 0: + return; + case 1: + GPR_SWAP(polling_obj *, a, b); + /* fall through */ + case -1: + gpr_mu_lock(&a->mu); + gpr_mu_lock(&b->mu); + + if (a->group == NULL) { + if (b->group == NULL) { + polling_obj *initial_po[] = {a, b}; + pg_create(exec_ctx, initial_po, GPR_ARRAY_SIZE(initial_po)); + gpr_mu_unlock(&a->mu); + gpr_mu_unlock(&b->mu); + } else { + polling_group *b_group = pg_ref(b->group); + gpr_mu_unlock(&b->mu); + gpr_mu_unlock(&a->mu); + pg_join(exec_ctx, b_group, a); + } + } else if (b->group == NULL) { + polling_group *a_group = pg_ref(a->group); + gpr_mu_unlock(&a->mu); + gpr_mu_unlock(&b->mu); + pg_join(exec_ctx, a_group, b); + } else if (a->group == b->group) { + /* nothing to do */ + gpr_mu_unlock(&a->mu); + gpr_mu_unlock(&b->mu); + } else { + polling_group *a_group = pg_ref(a->group); + polling_group *b_group = pg_ref(b->group); + gpr_mu_unlock(&a->mu); + gpr_mu_unlock(&b->mu); + pg_merge(exec_ctx, a_group, b_group); + } + } +} + +static void pg_notify(grpc_exec_ctx *exec_ctx, polling_obj *a, polling_obj *b) { + if (a->type == PO_FD && b->type == PO_POLLSET) { + pollset_add_fd_locked(exec_ctx, (grpc_pollset *)b, (grpc_fd *)a, true); + } else if (a->type == PO_POLLSET && b->type == PO_FD) { + pollset_add_fd_locked(exec_ctx, (grpc_pollset *)a, (grpc_fd *)b, true); + } +} + +static void pg_broadcast(grpc_exec_ctx *exec_ctx, polling_group *from, + polling_group *to) { + for (polling_obj *a = from->po.next; a != &from->po; a = a->next) { + for (polling_obj *b = to->po.next; b != &to->po; b = b->next) { + if (po_cmp(a, b) < 0) { + gpr_mu_lock(&a->mu); + gpr_mu_lock(&b->mu); + } else { + GPR_ASSERT(po_cmp(a, b) != 0); + gpr_mu_lock(&b->mu); + gpr_mu_lock(&a->mu); + } + pg_notify(exec_ctx, a, b); + gpr_mu_unlock(&a->mu); + gpr_mu_unlock(&b->mu); + } + } +} + +static void pg_create(grpc_exec_ctx *exec_ctx, polling_obj **initial_po, + size_t initial_po_count) { + /* assumes all polling objects in initial_po are locked */ + polling_group *pg = gpr_malloc(sizeof(*pg)); + po_init(&pg->po, PO_POLLING_GROUP); + gpr_ref_init(&pg->refs, (int)initial_po_count); + for (size_t i = 0; i < initial_po_count; i++) { + GPR_ASSERT(initial_po[i]->group == NULL); + initial_po[i]->group = pg; + } + for (size_t i = 1; i < initial_po_count; i++) { + initial_po[i]->prev = initial_po[i - 1]; + } + for (size_t i = 0; i < initial_po_count - 1; i++) { + initial_po[i]->next = initial_po[i + 1]; + } + initial_po[0]->prev = &pg->po; + initial_po[initial_po_count - 1]->next = &pg->po; + pg->po.next = initial_po[0]; + pg->po.prev = initial_po[initial_po_count - 1]; + for (size_t i = 1; i < initial_po_count; i++) { + for (size_t j = 0; j < i; j++) { + pg_notify(exec_ctx, initial_po[i], initial_po[j]); + } + } +} + +static void pg_join(grpc_exec_ctx *exec_ctx, polling_group *pg, + polling_obj *po) { + /* assumes neither pg nor po are locked; consumes one ref to pg */ + pg = pg_lock_latest(pg); + /* pg locked */ + for (polling_obj *existing = pg->po.next /* skip pg - it's just a stub */; + existing != &pg->po; existing = existing->next) { + if (po_cmp(po, existing) < 0) { + gpr_mu_lock(&po->mu); + gpr_mu_lock(&existing->mu); + } else { + GPR_ASSERT(po_cmp(po, existing) != 0); + gpr_mu_lock(&existing->mu); + gpr_mu_lock(&po->mu); + } + /* pg, po, existing locked */ + if (po->group != NULL) { + gpr_mu_unlock(&pg->po.mu); + polling_group *po_group = pg_ref(po->group); + gpr_mu_unlock(&po->mu); + gpr_mu_unlock(&existing->mu); + pg_merge(exec_ctx, pg, po_group); + /* early exit: polling obj picked up a group during joining: we needed + to do a full merge */ + return; + } + pg_notify(exec_ctx, po, existing); + gpr_mu_unlock(&po->mu); + gpr_mu_unlock(&existing->mu); + } + gpr_mu_lock(&po->mu); + if (po->group != NULL) { + gpr_mu_unlock(&pg->po.mu); + polling_group *po_group = pg_ref(po->group); + gpr_mu_unlock(&po->mu); + pg_merge(exec_ctx, pg, po_group); + /* early exit: polling obj picked up a group during joining: we needed + to do a full merge */ + return; + } + po->group = pg; + po->next = &pg->po; + po->prev = pg->po.prev; + po->prev->next = po->next->prev = po; + gpr_mu_unlock(&pg->po.mu); + gpr_mu_unlock(&po->mu); +} + +static void pg_merge(grpc_exec_ctx *exec_ctx, polling_group *a, + polling_group *b) { + for (;;) { + if (a == b) { + pg_unref(a); + pg_unref(b); + return; + } + if (a > b) GPR_SWAP(polling_group *, a, b); + gpr_mu_lock(&a->po.mu); + gpr_mu_lock(&b->po.mu); + if (a->po.group != NULL) { + polling_group *m2 = pg_ref(a->po.group); + gpr_mu_unlock(&a->po.mu); + gpr_mu_unlock(&b->po.mu); + pg_unref(a); + a = m2; + } else if (b->po.group != NULL) { + polling_group *m2 = pg_ref(b->po.group); + gpr_mu_unlock(&a->po.mu); + gpr_mu_unlock(&b->po.mu); + pg_unref(b); + b = m2; + } else { + break; + } + } + polling_group **unref = NULL; + size_t unref_count = 0; + size_t unref_cap = 0; + b->po.group = a; + pg_broadcast(exec_ctx, a, b); + pg_broadcast(exec_ctx, b, a); + while (b->po.next != &b->po) { + polling_obj *po = b->po.next; + gpr_mu_lock(&po->mu); + if (unref_count == unref_cap) { + unref_cap = GPR_MAX(8, 3 * unref_cap / 2); + unref = gpr_realloc(unref, unref_cap * sizeof(*unref)); + } + unref[unref_count++] = po->group; + po->group = pg_ref(a); + // unlink from b + po->prev->next = po->next; + po->next->prev = po->prev; + // link to a + po->next = &a->po; + po->prev = a->po.prev; + po->next->prev = po->prev->next = po; + gpr_mu_unlock(&po->mu); + } + gpr_mu_unlock(&a->po.mu); + gpr_mu_unlock(&b->po.mu); + for (size_t i = 0; i < unref_count; i++) { + pg_unref(unref[i]); + } + gpr_free(unref); + pg_unref(b); +} + +/******************************************************************************* + * Event engine binding + */ + +static void shutdown_engine(void) { + fd_global_shutdown(); + pollset_global_shutdown(); +} + +static const grpc_event_engine_vtable vtable = { + .pollset_size = sizeof(grpc_pollset), + + .fd_create = fd_create, + .fd_wrapped_fd = fd_wrapped_fd, + .fd_orphan = fd_orphan, + .fd_shutdown = fd_shutdown, + .fd_is_shutdown = fd_is_shutdown, + .fd_notify_on_read = fd_notify_on_read, + .fd_notify_on_write = fd_notify_on_write, + .fd_get_read_notifier_pollset = fd_get_read_notifier_pollset, + + .pollset_init = pollset_init, + .pollset_shutdown = pollset_shutdown, + .pollset_destroy = pollset_destroy, + .pollset_work = pollset_work, + .pollset_kick = pollset_kick, + .pollset_add_fd = pollset_add_fd, + + .pollset_set_create = pollset_set_create, + .pollset_set_destroy = pollset_set_destroy, + .pollset_set_add_pollset = pollset_set_add_pollset, + .pollset_set_del_pollset = pollset_set_del_pollset, + .pollset_set_add_pollset_set = pollset_set_add_pollset_set, + .pollset_set_del_pollset_set = pollset_set_del_pollset_set, + .pollset_set_add_fd = pollset_set_add_fd, + .pollset_set_del_fd = pollset_set_del_fd, + + .shutdown_engine = shutdown_engine, +}; + +const grpc_event_engine_vtable *grpc_init_epollex_linux( + bool explicitly_requested) { + if (!grpc_has_wakeup_fd()) { + return NULL; + } + + if (!grpc_is_epollexclusive_available()) { + return NULL; + } + + fd_global_init(); + + if (!GRPC_LOG_IF_ERROR("pollset_global_init", pollset_global_init())) { + pollset_global_shutdown(); + fd_global_shutdown(); + return NULL; + } + + return &vtable; +} + +#else /* defined(GRPC_LINUX_EPOLL) */ +#if defined(GRPC_POSIX_SOCKET) +#include "src/core/lib/iomgr/ev_posix.h" +/* If GRPC_LINUX_EPOLL is not defined, it means epoll is not available. Return + * NULL */ +const grpc_event_engine_vtable *grpc_init_epollex_linux( + bool explicitly_requested) { + return NULL; +} +#endif /* defined(GRPC_POSIX_SOCKET) */ + +#endif /* !defined(GRPC_LINUX_EPOLL) */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/ev_epollex_linux.h b/Sources/CgRPC/src/core/lib/iomgr/ev_epollex_linux.h new file mode 100644 index 000000000..cff9b43c0 --- /dev/null +++ b/Sources/CgRPC/src/core/lib/iomgr/ev_epollex_linux.h @@ -0,0 +1,28 @@ +/* + * + * 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 GRPC_CORE_LIB_IOMGR_EV_EPOLLEX_LINUX_H +#define GRPC_CORE_LIB_IOMGR_EV_EPOLLEX_LINUX_H + +#include "src/core/lib/iomgr/ev_posix.h" +#include "src/core/lib/iomgr/port.h" + +const grpc_event_engine_vtable *grpc_init_epollex_linux( + bool explicitly_requested); + +#endif /* GRPC_CORE_LIB_IOMGR_EV_EPOLLEX_LINUX_H */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/ev_epoll_linux.c b/Sources/CgRPC/src/core/lib/iomgr/ev_epollsig_linux.c similarity index 75% rename from Sources/CgRPC/src/core/lib/iomgr/ev_epoll_linux.c rename to Sources/CgRPC/src/core/lib/iomgr/ev_epollsig_linux.c index 1b15e0eb4..070d75e42 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/ev_epoll_linux.c +++ b/Sources/CgRPC/src/core/lib/iomgr/ev_epollsig_linux.c @@ -1,43 +1,27 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 #include "src/core/lib/iomgr/port.h" /* This polling engine is only relevant on linux kernels supporting epoll() */ #ifdef GRPC_LINUX_EPOLL -#include "src/core/lib/iomgr/ev_epoll_linux.h" +#include "src/core/lib/iomgr/ev_epollsig_linux.h" #include #include @@ -57,29 +41,22 @@ #include "src/core/lib/iomgr/ev_posix.h" #include "src/core/lib/iomgr/iomgr_internal.h" +#include "src/core/lib/iomgr/lockfree_event.h" +#include "src/core/lib/iomgr/timer.h" #include "src/core/lib/iomgr/wakeup_fd_posix.h" -#include "src/core/lib/iomgr/workqueue.h" #include "src/core/lib/profiling/timers.h" #include "src/core/lib/support/block_annotate.h" -/* TODO: sreek - Move this to init.c and initialize this like other tracers. */ -static int grpc_polling_trace = 0; /* Disabled by default */ -#define GRPC_POLLING_TRACE(fmt, ...) \ - if (grpc_polling_trace) { \ - gpr_log(GPR_INFO, (fmt), __VA_ARGS__); \ - } +#define GRPC_POLLSET_KICK_BROADCAST ((grpc_pollset_worker *)1) -/* Uncomment the following enable extra checks on poll_object operations */ -/* #define PO_DEBUG */ +#define GRPC_POLLING_TRACE(...) \ + if (GRPC_TRACER_ON(grpc_polling_trace)) { \ + gpr_log(GPR_INFO, __VA_ARGS__); \ + } static int grpc_wakeup_signal = -1; static bool is_grpc_wakeup_signal_initialized = false; -/* TODO: sreek: Right now, this wakes up all pollers. In future we should make - * sure to wake up one polling thread (which can wake up other threads if - * needed) */ -static grpc_wakeup_fd global_wakeup_fd; - /* Implements the function defined in grpc_posix.h. This function might be * called before even calling grpc_init() to set either a different signal to * use. If signum == -1, then the use of signals is disabled */ @@ -105,7 +82,7 @@ typedef enum { } poll_obj_type; typedef struct poll_obj { -#ifdef PO_DEBUG +#ifndef NDEBUG poll_obj_type obj_type; #endif gpr_mu mu; @@ -141,30 +118,26 @@ struct grpc_fd { Ref/Unref by two to avoid altering the orphaned bit */ gpr_atm refst; - /* Indicates that the fd is shutdown and that any pending read/write closures - should fail */ - bool shutdown; - - /* The fd is either closed or we relinquished control of it. In either cases, - this indicates that the 'fd' on this structure is no longer valid */ + /* The fd is either closed or we relinquished control of it. In either + cases, this indicates that the 'fd' on this structure is no longer + valid */ bool orphaned; - /* TODO: sreek - Move this to a lockfree implementation */ - grpc_closure *read_closure; - grpc_closure *write_closure; + gpr_atm read_closure; + gpr_atm write_closure; struct grpc_fd *freelist_next; grpc_closure *on_done_closure; - /* The pollset that last noticed that the fd is readable */ - grpc_pollset *read_notifier_pollset; + /* The pollset that last noticed that the fd is readable. The actual type + * stored in this is (grpc_pollset *) */ + gpr_atm read_notifier_pollset; grpc_iomgr_object iomgr_object; }; /* Reference counting for fds */ -// #define GRPC_FD_REF_COUNT_DEBUG -#ifdef GRPC_FD_REF_COUNT_DEBUG +#ifndef NDEBUG static void fd_ref(grpc_fd *fd, const char *reason, const char *file, int line); static void fd_unref(grpc_fd *fd, const char *reason, const char *file, int line); @@ -180,25 +153,22 @@ static void fd_unref(grpc_fd *fd); static void fd_global_init(void); static void fd_global_shutdown(void); -#define CLOSURE_NOT_READY ((grpc_closure *)0) -#define CLOSURE_READY ((grpc_closure *)1) - /******************************************************************************* * Polling island Declarations */ -#ifdef GRPC_WORKQUEUE_REFCOUNT_DEBUG +#ifndef NDEBUG #define PI_ADD_REF(p, r) pi_add_ref_dbg((p), (r), __FILE__, __LINE__) #define PI_UNREF(exec_ctx, p, r) \ pi_unref_dbg((exec_ctx), (p), (r), __FILE__, __LINE__) -#else /* defined(GRPC_WORKQUEUE_REFCOUNT_DEBUG) */ +#else #define PI_ADD_REF(p, r) pi_add_ref((p)) #define PI_UNREF(exec_ctx, p, r) pi_unref((exec_ctx), (p)) -#endif /* !defined(GRPC_PI_REF_COUNT_DEBUG) */ +#endif /* This is also used as grpc_workqueue (by directly casing it) */ typedef struct polling_island { @@ -222,15 +192,6 @@ typedef struct polling_island { /* Number of threads currently polling on this island */ gpr_atm poller_count; - /* Mutex guarding the read end of the workqueue (must be held to pop from - * workqueue_items) */ - gpr_mu workqueue_read_mu; - /* Queue of closures to be executed */ - gpr_mpscq workqueue_items; - /* Count of items in workqueue_items */ - gpr_atm workqueue_item_count; - /* Wakeup fd used to wake pollers to check the contents of workqueue_items */ - grpc_wakeup_fd workqueue_wakeup_fd; /* The fd of the underlying epoll set */ int epoll_fd; @@ -280,7 +241,7 @@ static bool append_error(grpc_error **composite, grpc_error *error, const char *desc) { if (error == GRPC_ERROR_NONE) return true; if (*composite == GRPC_ERROR_NONE) { - *composite = GRPC_ERROR_CREATE(desc); + *composite = GRPC_ERROR_CREATE_FROM_COPIED_STRING(desc); } *composite = grpc_error_add_child(*composite, error); return false; @@ -320,51 +281,27 @@ gpr_atm g_epoll_sync; static void pi_add_ref(polling_island *pi); static void pi_unref(grpc_exec_ctx *exec_ctx, polling_island *pi); -#ifdef GRPC_WORKQUEUE_REFCOUNT_DEBUG +#ifndef NDEBUG static void pi_add_ref_dbg(polling_island *pi, const char *reason, const char *file, int line) { - long old_cnt = gpr_atm_acq_load(&pi->ref_count); + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_atm old_cnt = gpr_atm_acq_load(&pi->ref_count); + gpr_log(GPR_DEBUG, "Add ref pi: %p, old:%" PRIdPTR " -> new:%" PRIdPTR + " (%s) - (%s, %d)", + pi, old_cnt, old_cnt + 1, reason, file, line); + } pi_add_ref(pi); - gpr_log(GPR_DEBUG, "Add ref pi: %p, old: %ld -> new:%ld (%s) - (%s, %d)", - (void *)pi, old_cnt, old_cnt + 1, reason, file, line); } static void pi_unref_dbg(grpc_exec_ctx *exec_ctx, polling_island *pi, const char *reason, const char *file, int line) { - long old_cnt = gpr_atm_acq_load(&pi->ref_count); - pi_unref(exec_ctx, pi); - gpr_log(GPR_DEBUG, "Unref pi: %p, old:%ld -> new:%ld (%s) - (%s, %d)", - (void *)pi, old_cnt, (old_cnt - 1), reason, file, line); -} - -static grpc_workqueue *workqueue_ref(grpc_workqueue *workqueue, - const char *file, int line, - const char *reason) { - if (workqueue != NULL) { - pi_add_ref_dbg((polling_island *)workqueue, reason, file, line); - } - return workqueue; -} - -static void workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue, - const char *file, int line, const char *reason) { - if (workqueue != NULL) { - pi_unref_dbg(exec_ctx, (polling_island *)workqueue, reason, file, line); - } -} -#else -static grpc_workqueue *workqueue_ref(grpc_workqueue *workqueue) { - if (workqueue != NULL) { - pi_add_ref((polling_island *)workqueue); - } - return workqueue; -} - -static void workqueue_unref(grpc_exec_ctx *exec_ctx, - grpc_workqueue *workqueue) { - if (workqueue != NULL) { - pi_unref(exec_ctx, (polling_island *)workqueue); + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_atm old_cnt = gpr_atm_acq_load(&pi->ref_count); + gpr_log(GPR_DEBUG, "Unref pi: %p, old:%" PRIdPTR " -> new:%" PRIdPTR + " (%s) - (%s, %d)", + pi, old_cnt, (old_cnt - 1), reason, file, line); } + pi_unref(exec_ctx, pi); } #endif @@ -452,8 +389,8 @@ static void polling_island_add_wakeup_fd_locked(polling_island *pi, gpr_asprintf(&err_msg, "epoll_ctl (epoll_fd: %d) add wakeup fd: %d failed with " "error: %d (%s)", - pi->epoll_fd, GRPC_WAKEUP_FD_GET_READ_FD(&global_wakeup_fd), - errno, strerror(errno)); + pi->epoll_fd, GRPC_WAKEUP_FD_GET_READ_FD(wakeup_fd), errno, + strerror(errno)); append_error(error, GRPC_OS_ERROR(errno, err_msg), err_desc); gpr_free(err_msg); } @@ -535,19 +472,10 @@ static polling_island *polling_island_create(grpc_exec_ctx *exec_ctx, pi->fds = NULL; pi->epoll_fd = -1; - gpr_mu_init(&pi->workqueue_read_mu); - gpr_mpscq_init(&pi->workqueue_items); - gpr_atm_rel_store(&pi->workqueue_item_count, 0); - gpr_atm_rel_store(&pi->ref_count, 0); gpr_atm_rel_store(&pi->poller_count, 0); gpr_atm_rel_store(&pi->merged_to, (gpr_atm)NULL); - if (!append_error(error, grpc_wakeup_fd_init(&pi->workqueue_wakeup_fd), - err_desc)) { - goto done; - } - pi->epoll_fd = epoll_create1(EPOLL_CLOEXEC); if (pi->epoll_fd < 0) { @@ -555,9 +483,6 @@ static polling_island *polling_island_create(grpc_exec_ctx *exec_ctx, goto done; } - polling_island_add_wakeup_fd_locked(pi, &global_wakeup_fd, error); - polling_island_add_wakeup_fd_locked(pi, &pi->workqueue_wakeup_fd, error); - if (initial_fd != NULL) { polling_island_add_fds_locked(pi, &initial_fd, 1, true, error); } @@ -576,11 +501,7 @@ static void polling_island_delete(grpc_exec_ctx *exec_ctx, polling_island *pi) { if (pi->epoll_fd >= 0) { close(pi->epoll_fd); } - GPR_ASSERT(gpr_atm_no_barrier_load(&pi->workqueue_item_count) == 0); - gpr_mu_destroy(&pi->workqueue_read_mu); - gpr_mpscq_destroy(&pi->workqueue_items); gpr_mu_destroy(&pi->mu); - grpc_wakeup_fd_destroy(&pi->workqueue_wakeup_fd); gpr_free(pi->fds); gpr_free(pi); } @@ -725,45 +646,6 @@ static void polling_island_unlock_pair(polling_island *p, polling_island *q) { } } -static void workqueue_maybe_wakeup(polling_island *pi) { - /* If this thread is the current poller, then it may be that it's about to - decrement the current poller count, so we need to look past this thread */ - bool is_current_poller = (g_current_thread_polling_island == pi); - gpr_atm min_current_pollers_for_wakeup = is_current_poller ? 1 : 0; - gpr_atm current_pollers = gpr_atm_no_barrier_load(&pi->poller_count); - /* Only issue a wakeup if it's likely that some poller could come in and take - it right now. Note that since we do an anticipatory mpscq_pop every poll - loop, it's ok if we miss the wakeup here, as we'll get the work item when - the next poller enters anyway. */ - if (current_pollers > min_current_pollers_for_wakeup) { - GRPC_LOG_IF_ERROR("workqueue_wakeup_fd", - grpc_wakeup_fd_wakeup(&pi->workqueue_wakeup_fd)); - } -} - -static void workqueue_move_items_to_parent(polling_island *q) { - polling_island *p = (polling_island *)gpr_atm_no_barrier_load(&q->merged_to); - if (p == NULL) { - return; - } - gpr_mu_lock(&q->workqueue_read_mu); - int num_added = 0; - while (gpr_atm_no_barrier_load(&q->workqueue_item_count) > 0) { - gpr_mpscq_node *n = gpr_mpscq_pop(&q->workqueue_items); - if (n != NULL) { - gpr_atm_no_barrier_fetch_add(&q->workqueue_item_count, -1); - gpr_atm_no_barrier_fetch_add(&p->workqueue_item_count, 1); - gpr_mpscq_push(&p->workqueue_items, n); - num_added++; - } - } - gpr_mu_unlock(&q->workqueue_read_mu); - if (num_added > 0) { - workqueue_maybe_wakeup(p); - } - workqueue_move_items_to_parent(p); -} - static polling_island *polling_island_merge(polling_island *p, polling_island *q, grpc_error **error) { @@ -788,8 +670,6 @@ static polling_island *polling_island_merge(polling_island *p, /* Add the 'merged_to' link from p --> q */ gpr_atm_rel_store(&p->merged_to, (gpr_atm)q); PI_ADD_REF(q, "pi_merge"); /* To account for the new incoming ref from p */ - - workqueue_move_items_to_parent(q); } /* else if p == q, nothing needs to be done */ @@ -800,26 +680,6 @@ static polling_island *polling_island_merge(polling_island *p, return q; } -static void workqueue_enqueue(grpc_exec_ctx *exec_ctx, - grpc_workqueue *workqueue, grpc_closure *closure, - grpc_error *error) { - GPR_TIMER_BEGIN("workqueue.enqueue", 0); - /* take a ref to the workqueue: otherwise it can happen that whatever events - * this kicks off ends up destroying the workqueue before this function - * completes */ - GRPC_WORKQUEUE_REF(workqueue, "enqueue"); - polling_island *pi = (polling_island *)workqueue; - gpr_atm last = gpr_atm_no_barrier_fetch_add(&pi->workqueue_item_count, 1); - closure->error_data.error = error; - gpr_mpscq_push(&pi->workqueue_items, &closure->next_data.atm_next); - if (last == 0) { - workqueue_maybe_wakeup(pi); - } - workqueue_move_items_to_parent(pi); - GRPC_WORKQUEUE_UNREF(exec_ctx, workqueue, "enqueue"); - GPR_TIMER_END("workqueue.enqueue", 0); -} - static grpc_error *polling_island_global_init() { grpc_error *error = GRPC_ERROR_NONE; @@ -860,14 +720,17 @@ static void polling_island_global_shutdown() { static grpc_fd *fd_freelist = NULL; static gpr_mu fd_freelist_mu; -#ifdef GRPC_FD_REF_COUNT_DEBUG +#ifndef NDEBUG #define REF_BY(fd, n, reason) ref_by(fd, n, reason, __FILE__, __LINE__) #define UNREF_BY(fd, n, reason) unref_by(fd, n, reason, __FILE__, __LINE__) static void ref_by(grpc_fd *fd, int n, const char *reason, const char *file, int line) { - gpr_log(GPR_DEBUG, "FD %d %p ref %d %ld -> %ld [%s; %s:%d]", fd->fd, - (void *)fd, n, gpr_atm_no_barrier_load(&fd->refst), - gpr_atm_no_barrier_load(&fd->refst) + n, reason, file, line); + if (GRPC_TRACER_ON(grpc_trace_fd_refcount)) { + gpr_log(GPR_DEBUG, + "FD %d %p ref %d %" PRIdPTR " -> %" PRIdPTR " [%s; %s:%d]", + fd->fd, fd, n, gpr_atm_no_barrier_load(&fd->refst), + gpr_atm_no_barrier_load(&fd->refst) + n, reason, file, line); + } #else #define REF_BY(fd, n, reason) ref_by(fd, n) #define UNREF_BY(fd, n, reason) unref_by(fd, n) @@ -876,18 +739,19 @@ static void ref_by(grpc_fd *fd, int n) { GPR_ASSERT(gpr_atm_no_barrier_fetch_add(&fd->refst, n) > 0); } -#ifdef GRPC_FD_REF_COUNT_DEBUG +#ifndef NDEBUG static void unref_by(grpc_fd *fd, int n, const char *reason, const char *file, int line) { - gpr_atm old; - gpr_log(GPR_DEBUG, "FD %d %p unref %d %ld -> %ld [%s; %s:%d]", fd->fd, - (void *)fd, n, gpr_atm_no_barrier_load(&fd->refst), - gpr_atm_no_barrier_load(&fd->refst) - n, reason, file, line); + if (GRPC_TRACER_ON(grpc_trace_fd_refcount)) { + gpr_log(GPR_DEBUG, + "FD %d %p unref %d %" PRIdPTR " -> %" PRIdPTR " [%s; %s:%d]", + fd->fd, fd, n, gpr_atm_no_barrier_load(&fd->refst), + gpr_atm_no_barrier_load(&fd->refst) - n, reason, file, line); + } #else static void unref_by(grpc_fd *fd, int n) { - gpr_atm old; #endif - old = gpr_atm_full_fetch_add(&fd->refst, -n); + gpr_atm old = gpr_atm_full_fetch_add(&fd->refst, -n); if (old == n) { /* Add the fd to the freelist */ gpr_mu_lock(&fd_freelist_mu); @@ -895,6 +759,9 @@ static void unref_by(grpc_fd *fd, int n) { fd_freelist = fd; grpc_iomgr_unregister_object(&fd->iomgr_object); + grpc_lfev_destroy(&fd->read_closure); + grpc_lfev_destroy(&fd->write_closure); + gpr_mu_unlock(&fd_freelist_mu); } else { GPR_ASSERT(old > n); @@ -902,7 +769,7 @@ static void unref_by(grpc_fd *fd, int n) { } /* Increment refcount by two to avoid changing the orphan bit */ -#ifdef GRPC_FD_REF_COUNT_DEBUG +#ifndef NDEBUG static void fd_ref(grpc_fd *fd, const char *reason, const char *file, int line) { ref_by(fd, 2, reason, file, line); @@ -951,28 +818,25 @@ static grpc_fd *fd_create(int fd, const char *name) { * would be holding a lock to it anyway. */ gpr_mu_lock(&new_fd->po.mu); new_fd->po.pi = NULL; -#ifdef PO_DEBUG +#ifndef NDEBUG new_fd->po.obj_type = POLL_OBJ_FD; #endif gpr_atm_rel_store(&new_fd->refst, (gpr_atm)1); new_fd->fd = fd; - new_fd->shutdown = false; new_fd->orphaned = false; - new_fd->read_closure = CLOSURE_NOT_READY; - new_fd->write_closure = CLOSURE_NOT_READY; + grpc_lfev_init(&new_fd->read_closure); + grpc_lfev_init(&new_fd->write_closure); + gpr_atm_no_barrier_store(&new_fd->read_notifier_pollset, (gpr_atm)NULL); + new_fd->freelist_next = NULL; new_fd->on_done_closure = NULL; - new_fd->read_notifier_pollset = NULL; gpr_mu_unlock(&new_fd->po.mu); char *fd_name; gpr_asprintf(&fd_name, "%s fd=%d", name, fd); grpc_iomgr_register_object(&new_fd->iomgr_object, fd_name); -#ifdef GRPC_FD_REF_COUNT_DEBUG - gpr_log(GPR_DEBUG, "FD %d %p create %s", fd, (void *)new_fd, fd_name); -#endif gpr_free(fd_name); return new_fd; } @@ -990,25 +854,13 @@ static int fd_wrapped_fd(grpc_fd *fd) { static void fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_closure *on_done, int *release_fd, - const char *reason) { - bool is_fd_closed = false; + bool already_closed, const char *reason) { grpc_error *error = GRPC_ERROR_NONE; polling_island *unref_pi = NULL; gpr_mu_lock(&fd->po.mu); fd->on_done_closure = on_done; - /* If release_fd is not NULL, we should be relinquishing control of the file - descriptor fd->fd (but we still own the grpc_fd structure). */ - if (release_fd != NULL) { - *release_fd = fd->fd; - } else { - close(fd->fd); - is_fd_closed = true; - } - - fd->orphaned = true; - /* Remove the active status but keep referenced. We want this grpc_fd struct to be alive (and not added to freelist) until the end of this function */ REF_BY(fd, 1, reason); @@ -1023,15 +875,24 @@ static void fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd, before doing this.) */ if (fd->po.pi != NULL) { polling_island *pi_latest = polling_island_lock(fd->po.pi); - polling_island_remove_fd_locked(pi_latest, fd, is_fd_closed, &error); + polling_island_remove_fd_locked(pi_latest, fd, already_closed, &error); gpr_mu_unlock(&pi_latest->mu); unref_pi = fd->po.pi; fd->po.pi = NULL; } - grpc_exec_ctx_sched(exec_ctx, fd->on_done_closure, GRPC_ERROR_REF(error), - NULL); + /* If release_fd is not NULL, we should be relinquishing control of the file + descriptor fd->fd (but we still own the grpc_fd structure). */ + if (release_fd != NULL) { + *release_fd = fd->fd; + } else { + close(fd->fd); + } + + fd->orphaned = true; + + GRPC_CLOSURE_SCHED(exec_ctx, fd->on_done_closure, GRPC_ERROR_REF(error)); gpr_mu_unlock(&fd->po.mu); UNREF_BY(fd, 2, reason); /* Drop the reference */ @@ -1042,112 +903,41 @@ static void fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd, unhappy. */ PI_UNREF(exec_ctx, unref_pi, "fd_orphan"); } - GRPC_LOG_IF_ERROR("fd_orphan", GRPC_ERROR_REF(error)); - GRPC_ERROR_UNREF(error); -} - -static grpc_error *fd_shutdown_error(bool shutdown) { - if (!shutdown) { - return GRPC_ERROR_NONE; - } else { - return GRPC_ERROR_CREATE("FD shutdown"); - } -} - -static void notify_on_locked(grpc_exec_ctx *exec_ctx, grpc_fd *fd, - grpc_closure **st, grpc_closure *closure) { - if (fd->shutdown) { - grpc_exec_ctx_sched(exec_ctx, closure, GRPC_ERROR_CREATE("FD shutdown"), - NULL); - } else if (*st == CLOSURE_NOT_READY) { - /* not ready ==> switch to a waiting state by setting the closure */ - *st = closure; - } else if (*st == CLOSURE_READY) { - /* already ready ==> queue the closure to run immediately */ - *st = CLOSURE_NOT_READY; - grpc_exec_ctx_sched(exec_ctx, closure, fd_shutdown_error(fd->shutdown), - NULL); - } else { - /* upcallptr was set to a different closure. This is an error! */ - gpr_log(GPR_ERROR, - "User called a notify_on function with a previous callback still " - "pending"); - abort(); - } -} - -/* returns 1 if state becomes not ready */ -static int set_ready_locked(grpc_exec_ctx *exec_ctx, grpc_fd *fd, - grpc_closure **st) { - if (*st == CLOSURE_READY) { - /* duplicate ready ==> ignore */ - return 0; - } else if (*st == CLOSURE_NOT_READY) { - /* not ready, and not waiting ==> flag ready */ - *st = CLOSURE_READY; - return 0; - } else { - /* waiting ==> queue closure */ - grpc_exec_ctx_sched(exec_ctx, *st, fd_shutdown_error(fd->shutdown), NULL); - *st = CLOSURE_NOT_READY; - return 1; + if (error != GRPC_ERROR_NONE) { + const char *msg = grpc_error_string(error); + gpr_log(GPR_DEBUG, "fd_orphan: %s", msg); } + GRPC_ERROR_UNREF(error); } static grpc_pollset *fd_get_read_notifier_pollset(grpc_exec_ctx *exec_ctx, grpc_fd *fd) { - grpc_pollset *notifier = NULL; - - gpr_mu_lock(&fd->po.mu); - notifier = fd->read_notifier_pollset; - gpr_mu_unlock(&fd->po.mu); - - return notifier; + gpr_atm notifier = gpr_atm_acq_load(&fd->read_notifier_pollset); + return (grpc_pollset *)notifier; } static bool fd_is_shutdown(grpc_fd *fd) { - gpr_mu_lock(&fd->po.mu); - const bool r = fd->shutdown; - gpr_mu_unlock(&fd->po.mu); - return r; + return grpc_lfev_is_shutdown(&fd->read_closure); } /* Might be called multiple times */ -static void fd_shutdown(grpc_exec_ctx *exec_ctx, grpc_fd *fd) { - gpr_mu_lock(&fd->po.mu); - /* Do the actual shutdown only once */ - if (!fd->shutdown) { - fd->shutdown = true; - +static void fd_shutdown(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_error *why) { + if (grpc_lfev_set_shutdown(exec_ctx, &fd->read_closure, + GRPC_ERROR_REF(why))) { shutdown(fd->fd, SHUT_RDWR); - /* Flush any pending read and write closures. Since fd->shutdown is 'true' - at this point, the closures would be called with 'success = false' */ - set_ready_locked(exec_ctx, fd, &fd->read_closure); - set_ready_locked(exec_ctx, fd, &fd->write_closure); + grpc_lfev_set_shutdown(exec_ctx, &fd->write_closure, GRPC_ERROR_REF(why)); } - gpr_mu_unlock(&fd->po.mu); + GRPC_ERROR_UNREF(why); } static void fd_notify_on_read(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_closure *closure) { - gpr_mu_lock(&fd->po.mu); - notify_on_locked(exec_ctx, fd, &fd->read_closure, closure); - gpr_mu_unlock(&fd->po.mu); + grpc_lfev_notify_on(exec_ctx, &fd->read_closure, closure, "read"); } static void fd_notify_on_write(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_closure *closure) { - gpr_mu_lock(&fd->po.mu); - notify_on_locked(exec_ctx, fd, &fd->write_closure, closure); - gpr_mu_unlock(&fd->po.mu); -} - -static grpc_workqueue *fd_get_workqueue(grpc_fd *fd) { - gpr_mu_lock(&fd->po.mu); - grpc_workqueue *workqueue = - GRPC_WORKQUEUE_REF((grpc_workqueue *)fd->po.pi, "fd_get_workqueue"); - gpr_mu_unlock(&fd->po.mu); - return workqueue; + grpc_lfev_notify_on(exec_ctx, &fd->write_closure, closure, "write"); } /******************************************************************************* @@ -1171,11 +961,10 @@ static grpc_error *pollset_global_init(void) { gpr_tls_init(&g_current_thread_pollset); gpr_tls_init(&g_current_thread_worker); poller_kick_init(); - return grpc_wakeup_fd_init(&global_wakeup_fd); + return GRPC_ERROR_NONE; } static void pollset_global_shutdown(void) { - grpc_wakeup_fd_destroy(&global_wakeup_fd); gpr_tls_destroy(&g_current_thread_pollset); gpr_tls_destroy(&g_current_thread_worker); } @@ -1187,7 +976,7 @@ static grpc_error *pollset_worker_kick(grpc_pollset_worker *worker) { if (gpr_atm_no_barrier_cas(&worker->is_kicked, (gpr_atm)0, (gpr_atm)1)) { GRPC_POLLING_TRACE( "pollset_worker_kick: Kicking worker: %p (thread id: %ld)", - (void *)worker, worker->pt_id); + (void *)worker, (long int)worker->pt_id); int err_num = pthread_kill(worker->pt_id, grpc_wakeup_signal); if (err_num != 0) { err = GRPC_OS_ERROR(err_num, "pthread_kill"); @@ -1281,15 +1070,11 @@ static grpc_error *pollset_kick(grpc_pollset *p, return error; } -static grpc_error *kick_poller(void) { - return grpc_wakeup_fd_wakeup(&global_wakeup_fd); -} - static void pollset_init(grpc_pollset *pollset, gpr_mu **mu) { gpr_mu_init(&pollset->po.mu); *mu = &pollset->po.mu; pollset->po.pi = NULL; -#ifdef PO_DEBUG +#ifndef NDEBUG pollset->po.obj_type = POLL_OBJ_POLLSET; #endif @@ -1322,24 +1107,26 @@ static int poll_deadline_to_millis_timeout(gpr_timespec deadline, return 0; } timeout = gpr_time_sub(deadline, now); - return gpr_time_to_millis(gpr_time_add( + int millis = gpr_time_to_millis(gpr_time_add( timeout, gpr_time_from_nanos(GPR_NS_PER_MS - 1, GPR_TIMESPAN))); + return millis >= 1 ? millis : 1; } static void fd_become_readable(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_pollset *notifier) { - /* Need the fd->po.mu since we might be racing with fd_notify_on_read */ - gpr_mu_lock(&fd->po.mu); - set_ready_locked(exec_ctx, fd, &fd->read_closure); - fd->read_notifier_pollset = notifier; - gpr_mu_unlock(&fd->po.mu); + grpc_lfev_set_ready(exec_ctx, &fd->read_closure, "read"); + + /* Note, it is possible that fd_become_readable might be called twice with + different 'notifier's when an fd becomes readable and it is in two epoll + sets (This can happen briefly during polling island merges). In such cases + it does not really matter which notifer is set as the read_notifier_pollset + (They would both point to the same polling island anyway) */ + /* Use release store to match with acquire load in fd_get_read_notifier */ + gpr_atm_rel_store(&fd->read_notifier_pollset, (gpr_atm)notifier); } static void fd_become_writable(grpc_exec_ctx *exec_ctx, grpc_fd *fd) { - /* Need the fd->po.mu since we might be racing with fd_notify_on_write */ - gpr_mu_lock(&fd->po.mu); - set_ready_locked(exec_ctx, fd, &fd->write_closure); - gpr_mu_unlock(&fd->po.mu); + grpc_lfev_set_ready(exec_ctx, &fd->write_closure, "write"); } static void pollset_release_polling_island(grpc_exec_ctx *exec_ctx, @@ -1359,7 +1146,7 @@ static void finish_shutdown_locked(grpc_exec_ctx *exec_ctx, /* Release the ref and set pollset->po.pi to NULL */ pollset_release_polling_island(exec_ctx, pollset, "ps_shutdown"); - grpc_exec_ctx_sched(exec_ctx, pollset->shutdown_done, GRPC_ERROR_NONE, NULL); + GRPC_CLOSURE_SCHED(exec_ctx, pollset->shutdown_done, GRPC_ERROR_NONE); } /* pollset->po.mu lock must be held by the caller before calling this */ @@ -1385,43 +1172,11 @@ static void pollset_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, /* pollset_shutdown is guaranteed to be called before pollset_destroy. So other * than destroying the mutexes, there is nothing special that needs to be done * here */ -static void pollset_destroy(grpc_pollset *pollset) { +static void pollset_destroy(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset) { GPR_ASSERT(!pollset_has_workers(pollset)); gpr_mu_destroy(&pollset->po.mu); } -static void pollset_reset(grpc_pollset *pollset) { - GPR_ASSERT(pollset->shutting_down); - GPR_ASSERT(!pollset_has_workers(pollset)); - pollset->shutting_down = false; - pollset->finish_shutdown_called = false; - pollset->kicked_without_pollers = false; - pollset->shutdown_done = NULL; - GPR_ASSERT(pollset->po.pi == NULL); -} - -static bool maybe_do_workqueue_work(grpc_exec_ctx *exec_ctx, - polling_island *pi) { - if (gpr_mu_trylock(&pi->workqueue_read_mu)) { - gpr_mpscq_node *n = gpr_mpscq_pop(&pi->workqueue_items); - gpr_mu_unlock(&pi->workqueue_read_mu); - if (n != NULL) { - if (gpr_atm_full_fetch_add(&pi->workqueue_item_count, -1) > 1) { - workqueue_maybe_wakeup(pi); - } - grpc_closure *c = (grpc_closure *)n; - grpc_closure_run(exec_ctx, c, c->error_data.error); - return true; - } else if (gpr_atm_no_barrier_load(&pi->workqueue_item_count) > 0) { - /* n == NULL might mean there's work but it's not available to be popped - * yet - try to ensure another workqueue wakes up to check shortly if so - */ - workqueue_maybe_wakeup(pi); - } - } - return false; -} - #define GRPC_EPOLL_MAX_EVENTS 100 /* Note: sig_mask contains the signal mask to use *during* epoll_wait() */ static void pollset_work_and_unlock(grpc_exec_ctx *exec_ctx, @@ -1477,74 +1232,61 @@ static void pollset_work_and_unlock(grpc_exec_ctx *exec_ctx, PI_ADD_REF(pi, "ps_work"); gpr_mu_unlock(&pollset->po.mu); - /* If we get some workqueue work to do, it might end up completing an item on - the completion queue, so there's no need to poll... so we skip that and - redo the complete loop to verify */ - if (!maybe_do_workqueue_work(exec_ctx, pi)) { - gpr_atm_no_barrier_fetch_add(&pi->poller_count, 1); - g_current_thread_polling_island = pi; - - GRPC_SCHEDULING_START_BLOCKING_REGION; - ep_rv = epoll_pwait(epoll_fd, ep_ev, GRPC_EPOLL_MAX_EVENTS, timeout_ms, - sig_mask); - GRPC_SCHEDULING_END_BLOCKING_REGION; - if (ep_rv < 0) { - if (errno != EINTR) { - gpr_asprintf(&err_msg, - "epoll_wait() epoll fd: %d failed with error: %d (%s)", - epoll_fd, errno, strerror(errno)); - append_error(error, GRPC_OS_ERROR(errno, err_msg), err_desc); - } else { - /* We were interrupted. Save an interation by doing a zero timeout - epoll_wait to see if there are any other events of interest */ - GRPC_POLLING_TRACE( - "pollset_work: pollset: %p, worker: %p received kick", - (void *)pollset, (void *)worker); - ep_rv = epoll_wait(epoll_fd, ep_ev, GRPC_EPOLL_MAX_EVENTS, 0); - } + gpr_atm_no_barrier_fetch_add(&pi->poller_count, 1); + g_current_thread_polling_island = pi; + + GRPC_SCHEDULING_START_BLOCKING_REGION; + ep_rv = + epoll_pwait(epoll_fd, ep_ev, GRPC_EPOLL_MAX_EVENTS, timeout_ms, sig_mask); + GRPC_SCHEDULING_END_BLOCKING_REGION; + if (ep_rv < 0) { + if (errno != EINTR) { + gpr_asprintf(&err_msg, + "epoll_wait() epoll fd: %d failed with error: %d (%s)", + epoll_fd, errno, strerror(errno)); + append_error(error, GRPC_OS_ERROR(errno, err_msg), err_desc); + } else { + /* We were interrupted. Save an interation by doing a zero timeout + epoll_wait to see if there are any other events of interest */ + GRPC_POLLING_TRACE("pollset_work: pollset: %p, worker: %p received kick", + (void *)pollset, (void *)worker); + ep_rv = epoll_wait(epoll_fd, ep_ev, GRPC_EPOLL_MAX_EVENTS, 0); } + } #ifdef GRPC_TSAN - /* See the definition of g_poll_sync for more details */ - gpr_atm_acq_load(&g_epoll_sync); + /* See the definition of g_poll_sync for more details */ + gpr_atm_acq_load(&g_epoll_sync); #endif /* defined(GRPC_TSAN) */ - for (int i = 0; i < ep_rv; ++i) { - void *data_ptr = ep_ev[i].data.ptr; - if (data_ptr == &global_wakeup_fd) { - append_error(error, grpc_wakeup_fd_consume_wakeup(&global_wakeup_fd), - err_desc); - } else if (data_ptr == &pi->workqueue_wakeup_fd) { - append_error(error, grpc_wakeup_fd_consume_wakeup(&global_wakeup_fd), - err_desc); - maybe_do_workqueue_work(exec_ctx, pi); - } else if (data_ptr == &polling_island_wakeup_fd) { - GRPC_POLLING_TRACE( - "pollset_work: pollset: %p, worker: %p polling island (epoll_fd: " - "%d) got merged", - (void *)pollset, (void *)worker, epoll_fd); - /* This means that our polling island is merged with a different - island. We do not have to do anything here since the subsequent call - to the function pollset_work_and_unlock() will pick up the correct - epoll_fd */ - } else { - grpc_fd *fd = data_ptr; - int cancel = ep_ev[i].events & (EPOLLERR | EPOLLHUP); - int read_ev = ep_ev[i].events & (EPOLLIN | EPOLLPRI); - int write_ev = ep_ev[i].events & EPOLLOUT; - if (read_ev || cancel) { - fd_become_readable(exec_ctx, fd, pollset); - } - if (write_ev || cancel) { - fd_become_writable(exec_ctx, fd); - } + for (int i = 0; i < ep_rv; ++i) { + void *data_ptr = ep_ev[i].data.ptr; + if (data_ptr == &polling_island_wakeup_fd) { + GRPC_POLLING_TRACE( + "pollset_work: pollset: %p, worker: %p polling island (epoll_fd: " + "%d) got merged", + (void *)pollset, (void *)worker, epoll_fd); + /* This means that our polling island is merged with a different + island. We do not have to do anything here since the subsequent call + to the function pollset_work_and_unlock() will pick up the correct + epoll_fd */ + } else { + grpc_fd *fd = data_ptr; + int cancel = ep_ev[i].events & (EPOLLERR | EPOLLHUP); + int read_ev = ep_ev[i].events & (EPOLLIN | EPOLLPRI); + int write_ev = ep_ev[i].events & EPOLLOUT; + if (read_ev || cancel) { + fd_become_readable(exec_ctx, fd, pollset); + } + if (write_ev || cancel) { + fd_become_writable(exec_ctx, fd); } } - - g_current_thread_polling_island = NULL; - gpr_atm_no_barrier_fetch_add(&pi->poller_count, -1); } + g_current_thread_polling_island = NULL; + gpr_atm_no_barrier_fetch_add(&pi->poller_count, -1); + GPR_ASSERT(pi != NULL); /* Before leaving, release the extra ref we added to the polling island. It @@ -1575,7 +1317,7 @@ static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, worker.pt_id = pthread_self(); gpr_atm_no_barrier_store(&worker.is_kicked, (gpr_atm)0); - *worker_hdl = &worker; + if (worker_hdl) *worker_hdl = &worker; gpr_tls_set(&g_current_thread_pollset, (intptr_t)pollset); gpr_tls_set(&g_current_thread_worker, (intptr_t)&worker); @@ -1653,7 +1395,7 @@ static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, gpr_mu_lock(&pollset->po.mu); } - *worker_hdl = NULL; + if (worker_hdl) *worker_hdl = NULL; gpr_tls_set(&g_current_thread_pollset, (intptr_t)0); gpr_tls_set(&g_current_thread_worker, (intptr_t)0); @@ -1669,7 +1411,7 @@ static void add_poll_object(grpc_exec_ctx *exec_ctx, poll_obj *bag, poll_obj_type item_type) { GPR_TIMER_BEGIN("add_poll_object", 0); -#ifdef PO_DEBUG +#ifndef NDEBUG GPR_ASSERT(item->obj_type == item_type); GPR_ASSERT(bag->obj_type == bag_type); #endif @@ -1729,7 +1471,7 @@ static void add_poll_object(grpc_exec_ctx *exec_ctx, poll_obj *bag, (void *)pi_new, FD_FROM_PO(item)->fd, poll_obj_string(bag_type), (void *)bag); /* No need to lock 'pi_new' here since this is a new polling island - * and no one has a reference to it yet */ + and no one has a reference to it yet */ polling_island_remove_all_fds_locked(pi_new, true, &error); /* Ref and unref so that the polling island gets deleted during unref @@ -1828,19 +1570,18 @@ static grpc_pollset_set *pollset_set_create(void) { grpc_pollset_set *pss = gpr_malloc(sizeof(*pss)); gpr_mu_init(&pss->po.mu); pss->po.pi = NULL; -#ifdef PO_DEBUG +#ifndef NDEBUG pss->po.obj_type = POLL_OBJ_POLLSET_SET; #endif return pss; } -static void pollset_set_destroy(grpc_pollset_set *pss) { +static void pollset_set_destroy(grpc_exec_ctx *exec_ctx, + grpc_pollset_set *pss) { gpr_mu_destroy(&pss->po.mu); if (pss->po.pi != NULL) { - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - PI_UNREF(&exec_ctx, pss->po.pi, "pss_destroy"); - grpc_exec_ctx_finish(&exec_ctx); + PI_UNREF(exec_ctx, pss->po.pi, "pss_destroy"); } gpr_free(pss); @@ -1936,11 +1677,9 @@ static const grpc_event_engine_vtable vtable = { .fd_notify_on_read = fd_notify_on_read, .fd_notify_on_write = fd_notify_on_write, .fd_get_read_notifier_pollset = fd_get_read_notifier_pollset, - .fd_get_workqueue = fd_get_workqueue, .pollset_init = pollset_init, .pollset_shutdown = pollset_shutdown, - .pollset_reset = pollset_reset, .pollset_destroy = pollset_destroy, .pollset_work = pollset_work, .pollset_kick = pollset_kick, @@ -1955,12 +1694,6 @@ static const grpc_event_engine_vtable vtable = { .pollset_set_add_fd = pollset_set_add_fd, .pollset_set_del_fd = pollset_set_del_fd, - .kick_poller = kick_poller, - - .workqueue_ref = workqueue_ref, - .workqueue_unref = workqueue_unref, - .workqueue_enqueue = workqueue_enqueue, - .shutdown_engine = shutdown_engine, }; @@ -1979,7 +1712,8 @@ static bool is_epoll_available() { return true; } -const grpc_event_engine_vtable *grpc_init_epoll_linux(void) { +const grpc_event_engine_vtable *grpc_init_epollsig_linux( + bool explicit_request) { /* If use of signals is disabled, we cannot use epoll engine*/ if (is_grpc_wakeup_signal_initialized && grpc_wakeup_signal < 0) { return NULL; @@ -1994,7 +1728,13 @@ const grpc_event_engine_vtable *grpc_init_epoll_linux(void) { } if (!is_grpc_wakeup_signal_initialized) { - grpc_use_signal(SIGRTMIN + 6); + /* TODO(ctiller): when other epoll engines are ready, remove the true || to + * force this to be explitly chosen if needed */ + if (true || explicit_request) { + grpc_use_signal(SIGRTMIN + 6); + } else { + return NULL; + } } fd_global_init(); @@ -2016,7 +1756,10 @@ const grpc_event_engine_vtable *grpc_init_epoll_linux(void) { #include "src/core/lib/iomgr/ev_posix.h" /* If GRPC_LINUX_EPOLL is not defined, it means epoll is not available. Return * NULL */ -const grpc_event_engine_vtable *grpc_init_epoll_linux(void) { return NULL; } +const grpc_event_engine_vtable *grpc_init_epollsig_linux( + bool explicit_request) { + return NULL; +} #endif /* defined(GRPC_POSIX_SOCKET) */ void grpc_use_signal(int signum) {} diff --git a/Sources/CgRPC/src/core/lib/iomgr/ev_epollsig_linux.h b/Sources/CgRPC/src/core/lib/iomgr/ev_epollsig_linux.h new file mode 100644 index 000000000..88328682b --- /dev/null +++ b/Sources/CgRPC/src/core/lib/iomgr/ev_epollsig_linux.h @@ -0,0 +1,33 @@ +/* + * + * 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 GRPC_CORE_LIB_IOMGR_EV_EPOLLSIG_LINUX_H +#define GRPC_CORE_LIB_IOMGR_EV_EPOLLSIG_LINUX_H + +#include "src/core/lib/iomgr/ev_posix.h" +#include "src/core/lib/iomgr/port.h" + +const grpc_event_engine_vtable *grpc_init_epollsig_linux(bool explicit_request); + +#ifdef GRPC_LINUX_EPOLL +void *grpc_fd_get_polling_island(grpc_fd *fd); +void *grpc_pollset_get_polling_island(grpc_pollset *ps); +bool grpc_are_polling_islands_equal(void *p, void *q); +#endif /* defined(GRPC_LINUX_EPOLL) */ + +#endif /* GRPC_CORE_LIB_IOMGR_EV_EPOLLSIG_LINUX_H */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/ev_poll_posix.c b/Sources/CgRPC/src/core/lib/iomgr/ev_poll_posix.c index 21b28e555..9472a8e52 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/ev_poll_posix.c +++ b/Sources/CgRPC/src/core/lib/iomgr/ev_poll_posix.c @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -52,10 +37,14 @@ #include #include "src/core/lib/iomgr/iomgr_internal.h" +#include "src/core/lib/iomgr/timer.h" #include "src/core/lib/iomgr/wakeup_fd_cv.h" #include "src/core/lib/iomgr/wakeup_fd_posix.h" #include "src/core/lib/profiling/timers.h" #include "src/core/lib/support/block_annotate.h" +#include "src/core/lib/support/murmur_hash.h" + +#define GRPC_POLLSET_KICK_BROADCAST ((grpc_pollset_worker *)1) /******************************************************************************* * FD declarations @@ -82,6 +71,7 @@ struct grpc_fd { int shutdown; int closed; int released; + grpc_error *shutdown_error; /* The watcher list. @@ -120,8 +110,6 @@ struct grpc_fd { grpc_pollset *read_notifier_pollset; }; -static grpc_wakeup_fd global_wakeup_fd; - /* Begin polling on an fd. Registers that the given pollset is interested in this fd - so that if read or writability interest changes, the pollset can be kicked to pick up that @@ -147,9 +135,7 @@ static void fd_end_poll(grpc_exec_ctx *exec_ctx, grpc_fd_watcher *rec, /* Return 1 if this fd is orphaned, 0 otherwise */ static bool fd_is_orphaned(grpc_fd *fd); -/* Reference counting for fds */ -/*#define GRPC_FD_REF_COUNT_DEBUG*/ -#ifdef GRPC_FD_REF_COUNT_DEBUG +#ifndef NDEBUG static void fd_ref(grpc_fd *fd, const char *reason, const char *file, int line); static void fd_unref(grpc_fd *fd, const char *reason, const char *file, int line); @@ -190,6 +176,7 @@ struct grpc_pollset { int kicked_without_pollers; grpc_closure *shutdown_done; grpc_closure_list idle_jobs; + int pollset_set_count; /* all polled fds */ size_t fd_count; size_t fd_capacity; @@ -227,7 +214,7 @@ static grpc_error *pollset_kick_ext(grpc_pollset *p, /* Return 1 if the pollset has active threads in pollset_work (pollset must * be locked) */ -static int pollset_has_workers(grpc_pollset *pollset); +static bool pollset_has_workers(grpc_pollset *pollset); /******************************************************************************* * pollset_set definitions @@ -253,36 +240,60 @@ struct grpc_pollset_set { * condition variable polling definitions */ +#define POLLCV_THREAD_GRACE_MS 1000 #define CV_POLL_PERIOD_MS 1000 #define CV_DEFAULT_TABLE_SIZE 16 -typedef enum poll_status_t { INPROGRESS, COMPLETED, CANCELLED } poll_status_t; - -typedef struct poll_args { +typedef struct poll_result { gpr_refcount refcount; - gpr_cv *cv; + cv_node *watchers; + int watchcount; struct pollfd *fds; nfds_t nfds; - int timeout; int retval; int err; - gpr_atm status; + int completed; +} poll_result; + +typedef struct poll_args { + gpr_cv trigger; + int trigger_set; + struct pollfd *fds; + nfds_t nfds; + poll_result *result; + struct poll_args *next; + struct poll_args *prev; } poll_args; +// This is a 2-tiered cache, we mantain a hash table +// of active poll calls, so we can wait on the result +// of that call. We also maintain a freelist of inactive +// poll threads. +typedef struct poll_hash_table { + poll_args *free_pollers; + poll_args **active_pollers; + unsigned int size; + unsigned int count; +} poll_hash_table; + +poll_hash_table poll_cache; cv_fd_table g_cvfds; /******************************************************************************* * fd_posix.c */ -#ifdef GRPC_FD_REF_COUNT_DEBUG +#ifndef NDEBUG #define REF_BY(fd, n, reason) ref_by(fd, n, reason, __FILE__, __LINE__) #define UNREF_BY(fd, n, reason) unref_by(fd, n, reason, __FILE__, __LINE__) static void ref_by(grpc_fd *fd, int n, const char *reason, const char *file, int line) { - gpr_log(GPR_DEBUG, "FD %d %p ref %d %d -> %d [%s; %s:%d]", fd->fd, fd, n, - gpr_atm_no_barrier_load(&fd->refst), - gpr_atm_no_barrier_load(&fd->refst) + n, reason, file, line); + if (GRPC_TRACER_ON(grpc_trace_fd_refcount)) { + gpr_log(GPR_DEBUG, + "FD %d %p ref %d %" PRIdPTR " -> %" PRIdPTR " [%s; %s:%d]", + fd->fd, fd, n, gpr_atm_no_barrier_load(&fd->refst), + gpr_atm_no_barrier_load(&fd->refst) + n, reason, file, line); + } #else #define REF_BY(fd, n, reason) ref_by(fd, n) #define UNREF_BY(fd, n, reason) unref_by(fd, n) @@ -291,21 +302,23 @@ static void ref_by(grpc_fd *fd, int n) { GPR_ASSERT(gpr_atm_no_barrier_fetch_add(&fd->refst, n) > 0); } -#ifdef GRPC_FD_REF_COUNT_DEBUG +#ifndef NDEBUG static void unref_by(grpc_fd *fd, int n, const char *reason, const char *file, int line) { - gpr_atm old; - gpr_log(GPR_DEBUG, "FD %d %p unref %d %d -> %d [%s; %s:%d]", fd->fd, fd, n, - gpr_atm_no_barrier_load(&fd->refst), - gpr_atm_no_barrier_load(&fd->refst) - n, reason, file, line); + if (GRPC_TRACER_ON(grpc_trace_fd_refcount)) { + gpr_log(GPR_DEBUG, + "FD %d %p unref %d %" PRIdPTR " -> %" PRIdPTR " [%s; %s:%d]", + fd->fd, fd, n, gpr_atm_no_barrier_load(&fd->refst), + gpr_atm_no_barrier_load(&fd->refst) - n, reason, file, line); + } #else static void unref_by(grpc_fd *fd, int n) { - gpr_atm old; #endif - old = gpr_atm_full_fetch_add(&fd->refst, -n); + gpr_atm old = gpr_atm_full_fetch_add(&fd->refst, -n); if (old == n) { gpr_mu_destroy(&fd->mu); grpc_iomgr_unregister_object(&fd->iomgr_object); + if (fd->shutdown) GRPC_ERROR_UNREF(fd->shutdown_error); gpr_free(fd); } else { GPR_ASSERT(old > n); @@ -332,9 +345,6 @@ static grpc_fd *fd_create(int fd, const char *name) { gpr_asprintf(&name2, "%s fd=%d", name, fd); grpc_iomgr_register_object(&r->iomgr_object, name2); gpr_free(name2); -#ifdef GRPC_FD_REF_COUNT_DEBUG - gpr_log(GPR_DEBUG, "FD %d %p create %s", fd, r, name); -#endif return r; } @@ -397,7 +407,7 @@ static void close_fd_locked(grpc_exec_ctx *exec_ctx, grpc_fd *fd) { if (!fd->released) { close(fd->fd); } - grpc_exec_ctx_sched(exec_ctx, fd->on_done_closure, GRPC_ERROR_NONE, NULL); + GRPC_CLOSURE_SCHED(exec_ctx, fd->on_done_closure, GRPC_ERROR_NONE); } static int fd_wrapped_fd(grpc_fd *fd) { @@ -410,13 +420,14 @@ static int fd_wrapped_fd(grpc_fd *fd) { static void fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_closure *on_done, int *release_fd, - const char *reason) { + bool already_closed, const char *reason) { fd->on_done_closure = on_done; fd->released = release_fd != NULL; - if (!fd->released) { - shutdown(fd->fd, SHUT_RDWR); - } else { + if (release_fd != NULL) { *release_fd = fd->fd; + fd->released = true; + } else if (already_closed) { + fd->released = true; } gpr_mu_lock(&fd->mu); REF_BY(fd, 1, reason); /* remove active status, but keep referenced */ @@ -430,7 +441,7 @@ static void fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd, } /* increment refcount by two to avoid changing the orphan bit */ -#ifdef GRPC_FD_REF_COUNT_DEBUG +#ifndef NDEBUG static void fd_ref(grpc_fd *fd, const char *reason, const char *file, int line) { ref_by(fd, 2, reason, file, line); @@ -446,27 +457,27 @@ static void fd_ref(grpc_fd *fd) { ref_by(fd, 2); } static void fd_unref(grpc_fd *fd) { unref_by(fd, 2); } #endif -static grpc_error *fd_shutdown_error(bool shutdown) { - if (!shutdown) { +static grpc_error *fd_shutdown_error(grpc_fd *fd) { + if (!fd->shutdown) { return GRPC_ERROR_NONE; } else { - return GRPC_ERROR_CREATE("FD shutdown"); + return GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( + "FD shutdown", &fd->shutdown_error, 1); } } static void notify_on_locked(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_closure **st, grpc_closure *closure) { if (fd->shutdown) { - grpc_exec_ctx_sched(exec_ctx, closure, GRPC_ERROR_CREATE("FD shutdown"), - NULL); + GRPC_CLOSURE_SCHED(exec_ctx, closure, + GRPC_ERROR_CREATE_FROM_STATIC_STRING("FD shutdown")); } else if (*st == CLOSURE_NOT_READY) { /* not ready ==> switch to a waiting state by setting the closure */ *st = closure; } else if (*st == CLOSURE_READY) { /* already ready ==> queue the closure to run immediately */ *st = CLOSURE_NOT_READY; - grpc_exec_ctx_sched(exec_ctx, closure, fd_shutdown_error(fd->shutdown), - NULL); + GRPC_CLOSURE_SCHED(exec_ctx, closure, fd_shutdown_error(fd)); maybe_wake_one_watcher_locked(fd); } else { /* upcallptr was set to a different closure. This is an error! */ @@ -489,7 +500,7 @@ static int set_ready_locked(grpc_exec_ctx *exec_ctx, grpc_fd *fd, return 0; } else { /* waiting ==> queue closure */ - grpc_exec_ctx_sched(exec_ctx, *st, fd_shutdown_error(fd->shutdown), NULL); + GRPC_CLOSURE_SCHED(exec_ctx, *st, fd_shutdown_error(fd)); *st = CLOSURE_NOT_READY; return 1; } @@ -500,15 +511,18 @@ static void set_read_notifier_pollset_locked( fd->read_notifier_pollset = read_notifier_pollset; } -static void fd_shutdown(grpc_exec_ctx *exec_ctx, grpc_fd *fd) { +static void fd_shutdown(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_error *why) { gpr_mu_lock(&fd->mu); /* only shutdown once */ if (!fd->shutdown) { fd->shutdown = 1; + fd->shutdown_error = why; /* signal read/write closed to OS so that future operations fail */ shutdown(fd->fd, SHUT_RDWR); set_ready_locked(exec_ctx, fd, &fd->read_closure); set_ready_locked(exec_ctx, fd, &fd->write_closure); + } else { + GRPC_ERROR_UNREF(why); } gpr_mu_unlock(&fd->mu); } @@ -643,8 +657,6 @@ static void fd_end_poll(grpc_exec_ctx *exec_ctx, grpc_fd_watcher *watcher, GRPC_FD_UNREF(fd, "poll"); } -static grpc_workqueue *fd_get_workqueue(grpc_fd *fd) { return NULL; } - /******************************************************************************* * pollset_posix.c */ @@ -657,10 +669,18 @@ static void remove_worker(grpc_pollset *p, grpc_pollset_worker *worker) { worker->next->prev = worker->prev; } -static int pollset_has_workers(grpc_pollset *p) { +static bool pollset_has_workers(grpc_pollset *p) { return p->root_worker.next != &p->root_worker; } +static bool pollset_in_pollset_sets(grpc_pollset *p) { + return p->pollset_set_count; +} + +static bool pollset_has_observers(grpc_pollset *p) { + return pollset_has_workers(p) || pollset_in_pollset_sets(p); +} + static grpc_pollset_worker *pop_front_worker(grpc_pollset *p) { if (pollset_has_workers(p)) { grpc_pollset_worker *w = p->root_worker.next; @@ -686,7 +706,7 @@ static void push_front_worker(grpc_pollset *p, grpc_pollset_worker *worker) { static void kick_append_error(grpc_error **composite, grpc_error *error) { if (error == GRPC_ERROR_NONE) return; if (*composite == GRPC_ERROR_NONE) { - *composite = GRPC_ERROR_CREATE("Kick Failure"); + *composite = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Kick Failure"); } *composite = grpc_error_add_child(*composite, error); } @@ -771,19 +791,14 @@ static grpc_error *pollset_kick(grpc_pollset *p, static grpc_error *pollset_global_init(void) { gpr_tls_init(&g_current_thread_poller); gpr_tls_init(&g_current_thread_worker); - return grpc_wakeup_fd_init(&global_wakeup_fd); + return GRPC_ERROR_NONE; } static void pollset_global_shutdown(void) { - grpc_wakeup_fd_destroy(&global_wakeup_fd); gpr_tls_destroy(&g_current_thread_poller); gpr_tls_destroy(&g_current_thread_worker); } -static grpc_error *kick_poller(void) { - return grpc_wakeup_fd_wakeup(&global_wakeup_fd); -} - /* main interface */ static void pollset_init(grpc_pollset *pollset, gpr_mu **mu) { @@ -799,9 +814,10 @@ static void pollset_init(grpc_pollset *pollset, gpr_mu **mu) { pollset->fd_count = 0; pollset->fd_capacity = 0; pollset->fds = NULL; + pollset->pollset_set_count = 0; } -static void pollset_destroy(grpc_pollset *pollset) { +static void pollset_destroy(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset) { GPR_ASSERT(!pollset_has_workers(pollset)); GPR_ASSERT(pollset->idle_jobs.head == pollset->idle_jobs.tail); while (pollset->local_wakeup_cache) { @@ -814,16 +830,6 @@ static void pollset_destroy(grpc_pollset *pollset) { gpr_mu_destroy(&pollset->mu); } -static void pollset_reset(grpc_pollset *pollset) { - GPR_ASSERT(pollset->shutting_down); - GPR_ASSERT(!pollset_has_workers(pollset)); - GPR_ASSERT(pollset->idle_jobs.head == pollset->idle_jobs.tail); - GPR_ASSERT(pollset->fd_count == 0); - pollset->shutting_down = 0; - pollset->called_shutdown = 0; - pollset->kicked_without_pollers = 0; -} - static void pollset_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, grpc_fd *fd) { gpr_mu_lock(&pollset->mu); @@ -852,13 +858,13 @@ static void finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset) { GRPC_FD_UNREF(pollset->fds[i], "multipoller"); } pollset->fd_count = 0; - grpc_exec_ctx_sched(exec_ctx, pollset->shutdown_done, GRPC_ERROR_NONE, NULL); + GRPC_CLOSURE_SCHED(exec_ctx, pollset->shutdown_done, GRPC_ERROR_NONE); } static void work_combine_error(grpc_error **composite, grpc_error *error) { if (error == GRPC_ERROR_NONE) return; if (*composite == GRPC_ERROR_NONE) { - *composite = GRPC_ERROR_CREATE("pollset_work"); + *composite = GRPC_ERROR_CREATE_FROM_STATIC_STRING("pollset_work"); } *composite = grpc_error_add_child(*composite, error); } @@ -867,7 +873,7 @@ static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, grpc_pollset_worker **worker_hdl, gpr_timespec now, gpr_timespec deadline) { grpc_pollset_worker worker; - *worker_hdl = &worker; + if (worker_hdl) *worker_hdl = &worker; grpc_error *error = GRPC_ERROR_NONE; /* Avoid malloc for small number of elements. */ @@ -901,7 +907,7 @@ static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, if (!pollset_has_workers(pollset) && !grpc_closure_list_empty(pollset->idle_jobs)) { GPR_TIMER_MARK("pollset_work.idle_jobs", 0); - grpc_exec_ctx_enqueue_list(exec_ctx, &pollset->idle_jobs, NULL); + GRPC_CLOSURE_LIST_SCHED(exec_ctx, &pollset->idle_jobs); goto done; } /* If we're shutting down then we don't execute any extended work */ @@ -948,13 +954,10 @@ static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, } fd_count = 0; - pfd_count = 2; - pfds[0].fd = GRPC_WAKEUP_FD_GET_READ_FD(&global_wakeup_fd); + pfd_count = 1; + pfds[0].fd = GRPC_WAKEUP_FD_GET_READ_FD(&worker.wakeup_fd->fd); pfds[0].events = POLLIN; pfds[0].revents = 0; - pfds[1].fd = GRPC_WAKEUP_FD_GET_READ_FD(&worker.wakeup_fd->fd); - pfds[1].events = POLLIN; - pfds[1].revents = 0; for (i = 0; i < pollset->fd_count; i++) { if (fd_is_orphaned(pollset->fds[i])) { GRPC_FD_UNREF(pollset->fds[i], "multipoller"); @@ -970,7 +973,7 @@ static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, pollset->fd_count = fd_count; gpr_mu_unlock(&pollset->mu); - for (i = 2; i < pfd_count; i++) { + for (i = 1; i < pfd_count; i++) { grpc_fd *fd = watchers[i].fd; pfds[i].events = (short)fd_begin_poll(fd, pollset, &worker, POLLIN, POLLOUT, &watchers[i]); @@ -988,7 +991,7 @@ static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, work_combine_error(&error, GRPC_OS_ERROR(errno, "poll")); } - for (i = 2; i < pfd_count; i++) { + for (i = 1; i < pfd_count; i++) { if (watchers[i].fd == NULL) { fd_end_poll(exec_ctx, &watchers[i], 0, 0, NULL); } else { @@ -998,19 +1001,15 @@ static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, } } } else if (r == 0) { - for (i = 2; i < pfd_count; i++) { + for (i = 1; i < pfd_count; i++) { fd_end_poll(exec_ctx, &watchers[i], 0, 0, NULL); } } else { if (pfds[0].revents & POLLIN_CHECK) { - work_combine_error(&error, - grpc_wakeup_fd_consume_wakeup(&global_wakeup_fd)); - } - if (pfds[1].revents & POLLIN_CHECK) { work_combine_error( &error, grpc_wakeup_fd_consume_wakeup(&worker.wakeup_fd->fd)); } - for (i = 2; i < pfd_count; i++) { + for (i = 1; i < pfd_count; i++) { if (watchers[i].fd == NULL) { fd_end_poll(exec_ctx, &watchers[i], 0, 0, NULL); } else { @@ -1070,7 +1069,7 @@ static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, if (pollset->shutting_down) { if (pollset_has_workers(pollset)) { pollset_kick(pollset, NULL); - } else if (!pollset->called_shutdown) { + } else if (!pollset->called_shutdown && !pollset_has_observers(pollset)) { pollset->called_shutdown = 1; gpr_mu_unlock(&pollset->mu); finish_shutdown(exec_ctx, pollset); @@ -1081,13 +1080,13 @@ static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, * TODO(dklempner): Can we refactor the shutdown logic to avoid this? */ gpr_mu_lock(&pollset->mu); } else if (!grpc_closure_list_empty(pollset->idle_jobs)) { - grpc_exec_ctx_enqueue_list(exec_ctx, &pollset->idle_jobs, NULL); + GRPC_CLOSURE_LIST_SCHED(exec_ctx, &pollset->idle_jobs); gpr_mu_unlock(&pollset->mu); grpc_exec_ctx_flush(exec_ctx); gpr_mu_lock(&pollset->mu); } } - *worker_hdl = NULL; + if (worker_hdl) *worker_hdl = NULL; GPR_TIMER_END("pollset_work", 0); GRPC_LOG_IF_ERROR("pollset_work", GRPC_ERROR_REF(error)); return error; @@ -1100,9 +1099,9 @@ static void pollset_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, pollset->shutdown_done = closure; pollset_kick(pollset, GRPC_POLLSET_KICK_BROADCAST); if (!pollset_has_workers(pollset)) { - grpc_exec_ctx_enqueue_list(exec_ctx, &pollset->idle_jobs, NULL); + GRPC_CLOSURE_LIST_SCHED(exec_ctx, &pollset->idle_jobs); } - if (!pollset->called_shutdown && !pollset_has_workers(pollset)) { + if (!pollset->called_shutdown && !pollset_has_observers(pollset)) { pollset->called_shutdown = 1; finish_shutdown(exec_ctx, pollset); } @@ -1130,18 +1129,32 @@ static int poll_deadline_to_millis_timeout(gpr_timespec deadline, */ static grpc_pollset_set *pollset_set_create(void) { - grpc_pollset_set *pollset_set = gpr_malloc(sizeof(*pollset_set)); - memset(pollset_set, 0, sizeof(*pollset_set)); + grpc_pollset_set *pollset_set = gpr_zalloc(sizeof(*pollset_set)); gpr_mu_init(&pollset_set->mu); return pollset_set; } -static void pollset_set_destroy(grpc_pollset_set *pollset_set) { +static void pollset_set_destroy(grpc_exec_ctx *exec_ctx, + grpc_pollset_set *pollset_set) { size_t i; gpr_mu_destroy(&pollset_set->mu); for (i = 0; i < pollset_set->fd_count; i++) { GRPC_FD_UNREF(pollset_set->fds[i], "pollset_set"); } + for (i = 0; i < pollset_set->pollset_count; i++) { + grpc_pollset *pollset = pollset_set->pollsets[i]; + gpr_mu_lock(&pollset->mu); + pollset->pollset_set_count--; + /* check shutdown */ + if (pollset->shutting_down && !pollset->called_shutdown && + !pollset_has_observers(pollset)) { + pollset->called_shutdown = 1; + gpr_mu_unlock(&pollset->mu); + finish_shutdown(exec_ctx, pollset); + } else { + gpr_mu_unlock(&pollset->mu); + } + } gpr_free(pollset_set->pollsets); gpr_free(pollset_set->pollset_sets); gpr_free(pollset_set->fds); @@ -1152,6 +1165,9 @@ static void pollset_set_add_pollset(grpc_exec_ctx *exec_ctx, grpc_pollset_set *pollset_set, grpc_pollset *pollset) { size_t i, j; + gpr_mu_lock(&pollset->mu); + pollset->pollset_set_count++; + gpr_mu_unlock(&pollset->mu); gpr_mu_lock(&pollset_set->mu); if (pollset_set->pollset_count == pollset_set->pollset_capacity) { pollset_set->pollset_capacity = @@ -1187,6 +1203,17 @@ static void pollset_set_del_pollset(grpc_exec_ctx *exec_ctx, } } gpr_mu_unlock(&pollset_set->mu); + gpr_mu_lock(&pollset->mu); + pollset->pollset_set_count--; + /* check shutdown */ + if (pollset->shutting_down && !pollset->called_shutdown && + !pollset_has_observers(pollset)) { + pollset->called_shutdown = 1; + gpr_mu_unlock(&pollset->mu); + finish_shutdown(exec_ctx, pollset); + } else { + gpr_mu_unlock(&pollset->mu); + } } static void pollset_set_add_pollset_set(grpc_exec_ctx *exec_ctx, @@ -1269,72 +1296,208 @@ static void pollset_set_del_fd(grpc_exec_ctx *exec_ctx, } /******************************************************************************* - * workqueue stubs + * Condition Variable polling extensions */ -#ifdef GRPC_WORKQUEUE_REFCOUNT_DEBUG -static grpc_workqueue *workqueue_ref(grpc_workqueue *workqueue, - const char *file, int line, - const char *reason) { - return workqueue; +static void run_poll(void *args); +static void cache_poller_locked(poll_args *args); + +static void cache_insert_locked(poll_args *args) { + uint32_t key = gpr_murmur_hash3(args->fds, args->nfds * sizeof(struct pollfd), + 0xDEADBEEF); + key = key % poll_cache.size; + if (poll_cache.active_pollers[key]) { + poll_cache.active_pollers[key]->prev = args; + } + args->next = poll_cache.active_pollers[key]; + args->prev = NULL; + poll_cache.active_pollers[key] = args; + poll_cache.count++; } -static void workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue, - const char *file, int line, const char *reason) {} -#else -static grpc_workqueue *workqueue_ref(grpc_workqueue *workqueue) { - return workqueue; + +static void init_result(poll_args *pargs) { + pargs->result = gpr_malloc(sizeof(poll_result)); + gpr_ref_init(&pargs->result->refcount, 1); + pargs->result->watchers = NULL; + pargs->result->watchcount = 0; + pargs->result->fds = gpr_malloc(sizeof(struct pollfd) * pargs->nfds); + memcpy(pargs->result->fds, pargs->fds, sizeof(struct pollfd) * pargs->nfds); + pargs->result->nfds = pargs->nfds; + pargs->result->retval = 0; + pargs->result->err = 0; + pargs->result->completed = 0; } -static void workqueue_unref(grpc_exec_ctx *exec_ctx, - grpc_workqueue *workqueue) {} -#endif -static void workqueue_enqueue(grpc_exec_ctx *exec_ctx, - grpc_workqueue *workqueue, grpc_closure *closure, - grpc_error *error) { - grpc_exec_ctx_sched(exec_ctx, closure, error, NULL); +// Creates a poll_args object for a given arguments to poll(). +// This object may return a poll_args in the cache. +static poll_args *get_poller_locked(struct pollfd *fds, nfds_t count) { + uint32_t key = + gpr_murmur_hash3(fds, count * sizeof(struct pollfd), 0xDEADBEEF); + key = key % poll_cache.size; + poll_args *curr = poll_cache.active_pollers[key]; + while (curr) { + if (curr->nfds == count && + memcmp(curr->fds, fds, count * sizeof(struct pollfd)) == 0) { + gpr_free(fds); + return curr; + } + curr = curr->next; + } + + if (poll_cache.free_pollers) { + poll_args *pargs = poll_cache.free_pollers; + poll_cache.free_pollers = pargs->next; + if (poll_cache.free_pollers) { + poll_cache.free_pollers->prev = NULL; + } + pargs->fds = fds; + pargs->nfds = count; + pargs->next = NULL; + pargs->prev = NULL; + init_result(pargs); + cache_poller_locked(pargs); + return pargs; + } + + poll_args *pargs = gpr_malloc(sizeof(struct poll_args)); + gpr_cv_init(&pargs->trigger); + pargs->fds = fds; + pargs->nfds = count; + pargs->next = NULL; + pargs->prev = NULL; + pargs->trigger_set = 0; + init_result(pargs); + cache_poller_locked(pargs); + gpr_thd_id t_id; + gpr_thd_options opt = gpr_thd_options_default(); + gpr_ref(&g_cvfds.pollcount); + gpr_thd_options_set_detached(&opt); + GPR_ASSERT(gpr_thd_new(&t_id, &run_poll, pargs, &opt)); + return pargs; } -/******************************************************************************* - * Condition Variable polling extensions - */ +static void cache_delete_locked(poll_args *args) { + if (!args->prev) { + uint32_t key = gpr_murmur_hash3( + args->fds, args->nfds * sizeof(struct pollfd), 0xDEADBEEF); + key = key % poll_cache.size; + GPR_ASSERT(poll_cache.active_pollers[key] == args); + poll_cache.active_pollers[key] = args->next; + } else { + args->prev->next = args->next; + } + + if (args->next) { + args->next->prev = args->prev; + } -static void decref_poll_args(poll_args *args) { - if (gpr_unref(&args->refcount)) { - gpr_free(args->fds); - gpr_cv_destroy(args->cv); - gpr_free(args->cv); - gpr_free(args); + poll_cache.count--; + if (poll_cache.free_pollers) { + poll_cache.free_pollers->prev = args; } + args->prev = NULL; + args->next = poll_cache.free_pollers; + gpr_free(args->fds); + poll_cache.free_pollers = args; } -// Poll in a background thread -static void run_poll(void *arg) { - int timeout, retval; - poll_args *pargs = (poll_args *)arg; - while (gpr_atm_no_barrier_load(&pargs->status) == INPROGRESS) { - if (pargs->timeout < 0) { - timeout = CV_POLL_PERIOD_MS; - } else { - timeout = GPR_MIN(CV_POLL_PERIOD_MS, pargs->timeout); - pargs->timeout -= timeout; +static void cache_poller_locked(poll_args *args) { + if (poll_cache.count + 1 > poll_cache.size / 2) { + poll_args **old_active_pollers = poll_cache.active_pollers; + poll_cache.size = poll_cache.size * 2; + poll_cache.count = 0; + poll_cache.active_pollers = gpr_malloc(sizeof(void *) * poll_cache.size); + for (unsigned int i = 0; i < poll_cache.size; i++) { + poll_cache.active_pollers[i] = NULL; } - retval = g_cvfds.poll(pargs->fds, pargs->nfds, timeout); - if (retval != 0 || pargs->timeout == 0) { - pargs->retval = retval; - pargs->err = errno; - break; + for (unsigned int i = 0; i < poll_cache.size / 2; i++) { + poll_args *curr = old_active_pollers[i]; + poll_args *next = NULL; + while (curr) { + next = curr->next; + cache_insert_locked(curr); + curr = next; + } } + gpr_free(old_active_pollers); } - gpr_mu_lock(&g_cvfds.mu); - if (gpr_atm_no_barrier_load(&pargs->status) == INPROGRESS) { - // Signal main thread that the poll completed - gpr_atm_no_barrier_store(&pargs->status, COMPLETED); - gpr_cv_signal(pargs->cv); + + cache_insert_locked(args); +} + +static void cache_destroy_locked(poll_args *args) { + if (args->next) { + args->next->prev = args->prev; + } + + if (args->prev) { + args->prev->next = args->next; + } else { + poll_cache.free_pollers = args->next; } - decref_poll_args(pargs); - g_cvfds.pollcount--; - if (g_cvfds.shutdown && g_cvfds.pollcount == 0) { - gpr_cv_signal(&g_cvfds.shutdown_complete); + + gpr_free(args); +} + +static void decref_poll_result(poll_result *res) { + if (gpr_unref(&res->refcount)) { + GPR_ASSERT(!res->watchers); + gpr_free(res->fds); + gpr_free(res); + } +} + +void remove_cvn(cv_node **head, cv_node *target) { + if (target->next) { + target->next->prev = target->prev; + } + + if (target->prev) { + target->prev->next = target->next; + } else { + *head = target->next; + } +} + +gpr_timespec thread_grace; + +// Poll in a background thread +static void run_poll(void *args) { + poll_args *pargs = (poll_args *)args; + while (1) { + poll_result *result = pargs->result; + int retval = g_cvfds.poll(result->fds, result->nfds, CV_POLL_PERIOD_MS); + gpr_mu_lock(&g_cvfds.mu); + if (retval != 0) { + result->completed = 1; + result->retval = retval; + result->err = errno; + cv_node *watcher = result->watchers; + while (watcher) { + gpr_cv_signal(watcher->cv); + watcher = watcher->next; + } + } + if (result->watchcount == 0 || result->completed) { + cache_delete_locked(pargs); + decref_poll_result(result); + // Leave this polling thread alive for a grace period to do another poll() + // op + gpr_timespec deadline = gpr_now(GPR_CLOCK_REALTIME); + deadline = gpr_time_add(deadline, thread_grace); + pargs->trigger_set = 0; + gpr_cv_wait(&pargs->trigger, &g_cvfds.mu, deadline); + if (!pargs->trigger_set) { + cache_destroy_locked(pargs); + break; + } + } + gpr_mu_unlock(&g_cvfds.mu); + } + + // We still have the lock here + if (gpr_unref(&g_cvfds.pollcount)) { + gpr_cv_signal(&g_cvfds.shutdown_cv); } gpr_mu_unlock(&g_cvfds.mu); } @@ -1343,24 +1506,29 @@ static void run_poll(void *arg) { static int cvfd_poll(struct pollfd *fds, nfds_t nfds, int timeout) { unsigned int i; int res, idx; - gpr_cv *pollcv; - cv_node *cvn, *prev; + cv_node *pollcv; int skip_poll = 0; nfds_t nsockfds = 0; - gpr_thd_id t_id; - gpr_thd_options opt; - poll_args *pargs = NULL; + poll_result *result = NULL; gpr_mu_lock(&g_cvfds.mu); - pollcv = gpr_malloc(sizeof(gpr_cv)); - gpr_cv_init(pollcv); + pollcv = gpr_malloc(sizeof(cv_node)); + pollcv->next = NULL; + gpr_cv pollcv_cv; + gpr_cv_init(&pollcv_cv); + pollcv->cv = &pollcv_cv; + cv_node *fd_cvs = gpr_malloc(nfds * sizeof(cv_node)); + for (i = 0; i < nfds; i++) { fds[i].revents = 0; if (fds[i].fd < 0 && (fds[i].events & POLLIN)) { idx = FD_TO_IDX(fds[i].fd); - cvn = gpr_malloc(sizeof(cv_node)); - cvn->cv = pollcv; - cvn->next = g_cvfds.cvfds[idx].cvs; - g_cvfds.cvfds[idx].cvs = cvn; + fd_cvs[i].cv = &pollcv_cv; + fd_cvs[i].prev = NULL; + fd_cvs[i].next = g_cvfds.cvfds[idx].cvs; + if (g_cvfds.cvfds[idx].cvs) { + g_cvfds.cvfds[idx].cvs->prev = &(fd_cvs[i]); + } + g_cvfds.cvfds[idx].cvs = &(fd_cvs[i]); // Don't bother polling if a wakeup fd is ready if (g_cvfds.cvfds[idx].is_set) { skip_poll = 1; @@ -1370,81 +1538,68 @@ static int cvfd_poll(struct pollfd *fds, nfds_t nfds, int timeout) { } } + gpr_timespec deadline = gpr_now(GPR_CLOCK_REALTIME); + if (timeout < 0) { + deadline = gpr_inf_future(GPR_CLOCK_REALTIME); + } else { + deadline = + gpr_time_add(deadline, gpr_time_from_millis(timeout, GPR_TIMESPAN)); + } + res = 0; if (!skip_poll && nsockfds > 0) { - pargs = gpr_malloc(sizeof(struct poll_args)); - // Both the main thread and calling thread get a reference - gpr_ref_init(&pargs->refcount, 2); - pargs->cv = pollcv; - pargs->fds = gpr_malloc(sizeof(struct pollfd) * nsockfds); - pargs->nfds = nsockfds; - pargs->timeout = timeout; - pargs->retval = 0; - pargs->err = 0; - gpr_atm_no_barrier_store(&pargs->status, INPROGRESS); + struct pollfd *pollfds = gpr_malloc(sizeof(struct pollfd) * nsockfds); idx = 0; for (i = 0; i < nfds; i++) { if (fds[i].fd >= 0) { - pargs->fds[idx].fd = fds[i].fd; - pargs->fds[idx].events = fds[i].events; - pargs->fds[idx].revents = 0; + pollfds[idx].fd = fds[i].fd; + pollfds[idx].events = fds[i].events; + pollfds[idx].revents = 0; idx++; } } - g_cvfds.pollcount++; - opt = gpr_thd_options_default(); - gpr_thd_options_set_detached(&opt); - gpr_thd_new(&t_id, &run_poll, pargs, &opt); - // We want the poll() thread to trigger the deadline, so wait forever here - gpr_cv_wait(pollcv, &g_cvfds.mu, gpr_inf_future(GPR_CLOCK_MONOTONIC)); - if (gpr_atm_no_barrier_load(&pargs->status) == COMPLETED) { - res = pargs->retval; - errno = pargs->err; - } else { - errno = 0; - gpr_atm_no_barrier_store(&pargs->status, CANCELLED); + poll_args *pargs = get_poller_locked(pollfds, nsockfds); + result = pargs->result; + pollcv->next = result->watchers; + pollcv->prev = NULL; + if (result->watchers) { + result->watchers->prev = pollcv; } + result->watchers = pollcv; + result->watchcount++; + gpr_ref(&result->refcount); + + pargs->trigger_set = 1; + gpr_cv_signal(&pargs->trigger); + gpr_cv_wait(&pollcv_cv, &g_cvfds.mu, deadline); + res = result->retval; + errno = result->err; + result->watchcount--; + remove_cvn(&result->watchers, pollcv); } else if (!skip_poll) { - gpr_timespec deadline = gpr_now(GPR_CLOCK_REALTIME); - deadline = - gpr_time_add(deadline, gpr_time_from_millis(timeout, GPR_TIMESPAN)); - gpr_cv_wait(pollcv, &g_cvfds.mu, deadline); + gpr_cv_wait(&pollcv_cv, &g_cvfds.mu, deadline); } idx = 0; for (i = 0; i < nfds; i++) { if (fds[i].fd < 0 && (fds[i].events & POLLIN)) { - cvn = g_cvfds.cvfds[FD_TO_IDX(fds[i].fd)].cvs; - prev = NULL; - while (cvn->cv != pollcv) { - prev = cvn; - cvn = cvn->next; - GPR_ASSERT(cvn); - } - if (!prev) { - g_cvfds.cvfds[FD_TO_IDX(fds[i].fd)].cvs = cvn->next; - } else { - prev->next = cvn->next; - } - gpr_free(cvn); - + remove_cvn(&g_cvfds.cvfds[FD_TO_IDX(fds[i].fd)].cvs, &(fd_cvs[i])); if (g_cvfds.cvfds[FD_TO_IDX(fds[i].fd)].is_set) { fds[i].revents = POLLIN; if (res >= 0) res++; } - } else if (!skip_poll && fds[i].fd >= 0 && - gpr_atm_no_barrier_load(&pargs->status) == COMPLETED) { - fds[i].revents = pargs->fds[idx].revents; + } else if (!skip_poll && fds[i].fd >= 0 && result->completed) { + fds[i].revents = result->fds[idx].revents; idx++; } } - if (pargs) { - decref_poll_args(pargs); - } else { - gpr_cv_destroy(pollcv); - gpr_free(pollcv); + gpr_free(fd_cvs); + gpr_free(pollcv); + if (result) { + decref_poll_result(result); } + gpr_mu_unlock(&g_cvfds.mu); return res; @@ -1453,12 +1608,12 @@ static int cvfd_poll(struct pollfd *fds, nfds_t nfds, int timeout) { static void global_cv_fd_table_init() { gpr_mu_init(&g_cvfds.mu); gpr_mu_lock(&g_cvfds.mu); - gpr_cv_init(&g_cvfds.shutdown_complete); - g_cvfds.shutdown = 0; - g_cvfds.pollcount = 0; + gpr_cv_init(&g_cvfds.shutdown_cv); + gpr_ref_init(&g_cvfds.pollcount, 1); g_cvfds.size = CV_DEFAULT_TABLE_SIZE; g_cvfds.cvfds = gpr_malloc(sizeof(fd_node) * CV_DEFAULT_TABLE_SIZE); g_cvfds.free_fds = NULL; + thread_grace = gpr_time_from_millis(POLLCV_THREAD_GRACE_MS, GPR_TIMESPAN); for (int i = 0; i < CV_DEFAULT_TABLE_SIZE; i++) { g_cvfds.cvfds[i].is_set = 0; g_cvfds.cvfds[i].cvs = NULL; @@ -1468,23 +1623,35 @@ static void global_cv_fd_table_init() { // Override the poll function with one that supports cvfds g_cvfds.poll = grpc_poll_function; grpc_poll_function = &cvfd_poll; + + // Initialize the cache + poll_cache.size = 32; + poll_cache.count = 0; + poll_cache.free_pollers = NULL; + poll_cache.active_pollers = gpr_malloc(sizeof(void *) * 32); + for (unsigned int i = 0; i < poll_cache.size; i++) { + poll_cache.active_pollers[i] = NULL; + } + gpr_mu_unlock(&g_cvfds.mu); } static void global_cv_fd_table_shutdown() { gpr_mu_lock(&g_cvfds.mu); - g_cvfds.shutdown = 1; // Attempt to wait for all abandoned poll() threads to terminate // Not doing so will result in reported memory leaks - if (g_cvfds.pollcount > 0) { - int res = gpr_cv_wait(&g_cvfds.shutdown_complete, &g_cvfds.mu, + if (!gpr_unref(&g_cvfds.pollcount)) { + int res = gpr_cv_wait(&g_cvfds.shutdown_cv, &g_cvfds.mu, gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_seconds(3, GPR_TIMESPAN))); GPR_ASSERT(res == 0); } - gpr_cv_destroy(&g_cvfds.shutdown_complete); + gpr_cv_destroy(&g_cvfds.shutdown_cv); grpc_poll_function = g_cvfds.poll; gpr_free(g_cvfds.cvfds); + + gpr_free(poll_cache.active_pollers); + gpr_mu_unlock(&g_cvfds.mu); gpr_mu_destroy(&g_cvfds.mu); } @@ -1511,11 +1678,9 @@ static const grpc_event_engine_vtable vtable = { .fd_notify_on_read = fd_notify_on_read, .fd_notify_on_write = fd_notify_on_write, .fd_get_read_notifier_pollset = fd_get_read_notifier_pollset, - .fd_get_workqueue = fd_get_workqueue, .pollset_init = pollset_init, .pollset_shutdown = pollset_shutdown, - .pollset_reset = pollset_reset, .pollset_destroy = pollset_destroy, .pollset_work = pollset_work, .pollset_kick = pollset_kick, @@ -1530,16 +1695,10 @@ static const grpc_event_engine_vtable vtable = { .pollset_set_add_fd = pollset_set_add_fd, .pollset_set_del_fd = pollset_set_del_fd, - .kick_poller = kick_poller, - - .workqueue_ref = workqueue_ref, - .workqueue_unref = workqueue_unref, - .workqueue_enqueue = workqueue_enqueue, - .shutdown_engine = shutdown_engine, }; -const grpc_event_engine_vtable *grpc_init_poll_posix(void) { +const grpc_event_engine_vtable *grpc_init_poll_posix(bool explicit_request) { if (!grpc_has_wakeup_fd()) { return NULL; } @@ -1549,7 +1708,7 @@ const grpc_event_engine_vtable *grpc_init_poll_posix(void) { return &vtable; } -const grpc_event_engine_vtable *grpc_init_poll_cv_posix(void) { +const grpc_event_engine_vtable *grpc_init_poll_cv_posix(bool explicit_request) { global_cv_fd_table_init(); grpc_enable_cv_wakeup_fds(1); if (!GRPC_LOG_IF_ERROR("pollset_global_init", pollset_global_init())) { diff --git a/Sources/CgRPC/src/core/lib/iomgr/ev_poll_posix.h b/Sources/CgRPC/src/core/lib/iomgr/ev_poll_posix.h index 202ffca14..d444e6094 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/ev_poll_posix.h +++ b/Sources/CgRPC/src/core/lib/iomgr/ev_poll_posix.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015-2016, Google Inc. - * All rights reserved. + * Copyright 2015-2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -36,7 +21,7 @@ #include "src/core/lib/iomgr/ev_posix.h" -const grpc_event_engine_vtable *grpc_init_poll_posix(void); -const grpc_event_engine_vtable *grpc_init_poll_cv_posix(void); +const grpc_event_engine_vtable *grpc_init_poll_posix(bool explicit_request); +const grpc_event_engine_vtable *grpc_init_poll_cv_posix(bool explicit_request); #endif /* GRPC_CORE_LIB_IOMGR_EV_POLL_POSIX_H */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/ev_posix.c b/Sources/CgRPC/src/core/lib/iomgr/ev_posix.c index ab139895f..91f8cd548 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/ev_posix.c +++ b/Sources/CgRPC/src/core/lib/iomgr/ev_posix.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -44,18 +29,34 @@ #include #include -#include "src/core/lib/iomgr/ev_epoll_linux.h" +#include "src/core/lib/debug/trace.h" +#include "src/core/lib/iomgr/ev_epoll1_linux.h" +#include "src/core/lib/iomgr/ev_epoll_limited_pollers_linux.h" +#include "src/core/lib/iomgr/ev_epoll_thread_pool_linux.h" +#include "src/core/lib/iomgr/ev_epollex_linux.h" +#include "src/core/lib/iomgr/ev_epollsig_linux.h" #include "src/core/lib/iomgr/ev_poll_posix.h" #include "src/core/lib/support/env.h" +grpc_tracer_flag grpc_polling_trace = + GRPC_TRACER_INITIALIZER(false, "polling"); /* Disabled by default */ + +#ifndef NDEBUG +grpc_tracer_flag grpc_trace_fd_refcount = + GRPC_TRACER_INITIALIZER(false, "fd_refcount"); +#endif + /** Default poll() function - a pointer so that it can be overridden by some * tests */ grpc_poll_function_type grpc_poll_function = poll; +grpc_wakeup_fd grpc_global_wakeup_fd; + static const grpc_event_engine_vtable *g_event_engine; static const char *g_poll_strategy_name = NULL; -typedef const grpc_event_engine_vtable *(*event_engine_factory_fn)(void); +typedef const grpc_event_engine_vtable *(*event_engine_factory_fn)( + bool explicit_request); typedef struct { const char *name; @@ -63,9 +64,13 @@ typedef struct { } event_engine_factory; static const event_engine_factory g_factories[] = { - {"epoll", grpc_init_epoll_linux}, + {"epollsig", grpc_init_epollsig_linux}, + {"epoll1", grpc_init_epoll1_linux}, + {"epoll-threadpool", grpc_init_epoll_thread_pool_linux}, + {"epoll-limited", grpc_init_epoll_limited_pollers_linux}, {"poll", grpc_init_poll_posix}, {"poll-cv", grpc_init_poll_cv_posix}, + {"epollex", grpc_init_epollex_linux}, }; static void add(const char *beg, const char *end, char ***ss, size_t *ns) { @@ -100,7 +105,8 @@ static bool is(const char *want, const char *have) { static void try_engine(const char *engine) { for (size_t i = 0; i < GPR_ARRAY_SIZE(g_factories); i++) { if (is(engine, g_factories[i].name)) { - if ((g_event_engine = g_factories[i].factory())) { + if ((g_event_engine = g_factories[i].factory( + 0 == strcmp(engine, g_factories[i].name)))) { g_poll_strategy_name = g_factories[i].name; gpr_log(GPR_DEBUG, "Using polling engine: %s", g_factories[i].name); return; @@ -109,10 +115,22 @@ static void try_engine(const char *engine) { } } +/* This should be used for testing purposes ONLY */ +void grpc_set_event_engine_test_only( + const grpc_event_engine_vtable *ev_engine) { + g_event_engine = ev_engine; +} + +const grpc_event_engine_vtable *grpc_get_event_engine_test_only() { + return g_event_engine; +} + /* Call this only after calling grpc_event_engine_init() */ const char *grpc_get_poll_strategy_name() { return g_poll_strategy_name; } void grpc_event_engine_init(void) { + grpc_register_tracer(&grpc_polling_trace); + char *s = gpr_getenv("GRPC_POLL_STRATEGY"); if (s == NULL) { s = gpr_strdup("all"); @@ -147,21 +165,18 @@ grpc_fd *grpc_fd_create(int fd, const char *name) { return g_event_engine->fd_create(fd, name); } -grpc_workqueue *grpc_fd_get_workqueue(grpc_fd *fd) { - return g_event_engine->fd_get_workqueue(fd); -} - int grpc_fd_wrapped_fd(grpc_fd *fd) { return g_event_engine->fd_wrapped_fd(fd); } void grpc_fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_closure *on_done, - int *release_fd, const char *reason) { - g_event_engine->fd_orphan(exec_ctx, fd, on_done, release_fd, reason); + int *release_fd, bool already_closed, const char *reason) { + g_event_engine->fd_orphan(exec_ctx, fd, on_done, release_fd, already_closed, + reason); } -void grpc_fd_shutdown(grpc_exec_ctx *exec_ctx, grpc_fd *fd) { - g_event_engine->fd_shutdown(exec_ctx, fd); +void grpc_fd_shutdown(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_error *why) { + g_event_engine->fd_shutdown(exec_ctx, fd, why); } bool grpc_fd_is_shutdown(grpc_fd *fd) { @@ -189,12 +204,8 @@ void grpc_pollset_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, g_event_engine->pollset_shutdown(exec_ctx, pollset, closure); } -void grpc_pollset_reset(grpc_pollset *pollset) { - g_event_engine->pollset_reset(pollset); -} - -void grpc_pollset_destroy(grpc_pollset *pollset) { - g_event_engine->pollset_destroy(pollset); +void grpc_pollset_destroy(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset) { + g_event_engine->pollset_destroy(exec_ctx, pollset); } grpc_error *grpc_pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, @@ -217,8 +228,9 @@ grpc_pollset_set *grpc_pollset_set_create(void) { return g_event_engine->pollset_set_create(); } -void grpc_pollset_set_destroy(grpc_pollset_set *pollset_set) { - g_event_engine->pollset_set_destroy(pollset_set); +void grpc_pollset_set_destroy(grpc_exec_ctx *exec_ctx, + grpc_pollset_set *pollset_set) { + g_event_engine->pollset_set_destroy(exec_ctx, pollset_set); } void grpc_pollset_set_add_pollset(grpc_exec_ctx *exec_ctx, @@ -255,29 +267,4 @@ void grpc_pollset_set_del_fd(grpc_exec_ctx *exec_ctx, g_event_engine->pollset_set_del_fd(exec_ctx, pollset_set, fd); } -grpc_error *grpc_kick_poller(void) { return g_event_engine->kick_poller(); } - -#ifdef GRPC_WORKQUEUE_REFCOUNT_DEBUG -grpc_workqueue *grpc_workqueue_ref(grpc_workqueue *workqueue, const char *file, - int line, const char *reason) { - return g_event_engine->workqueue_ref(workqueue, file, line, reason); -} -void grpc_workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue, - const char *file, int line, const char *reason) { - g_event_engine->workqueue_unref(exec_ctx, workqueue, file, line, reason); -} -#else -grpc_workqueue *grpc_workqueue_ref(grpc_workqueue *workqueue) { - return g_event_engine->workqueue_ref(workqueue); -} -void grpc_workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue) { - g_event_engine->workqueue_unref(exec_ctx, workqueue); -} -#endif - -void grpc_workqueue_enqueue(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue, - grpc_closure *closure, grpc_error *error) { - g_event_engine->workqueue_enqueue(exec_ctx, workqueue, closure, error); -} - #endif // GRPC_POSIX_SOCKET diff --git a/Sources/CgRPC/src/core/lib/iomgr/ev_posix.h b/Sources/CgRPC/src/core/lib/iomgr/ev_posix.h index cb5832539..1108e46ef 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/ev_posix.h +++ b/Sources/CgRPC/src/core/lib/iomgr/ev_posix.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -36,11 +21,13 @@ #include +#include "src/core/lib/debug/trace.h" #include "src/core/lib/iomgr/exec_ctx.h" #include "src/core/lib/iomgr/pollset.h" #include "src/core/lib/iomgr/pollset_set.h" #include "src/core/lib/iomgr/wakeup_fd_posix.h" -#include "src/core/lib/iomgr/workqueue.h" + +extern grpc_tracer_flag grpc_polling_trace; /* Disabled by default */ typedef struct grpc_fd grpc_fd; @@ -50,22 +37,20 @@ typedef struct grpc_event_engine_vtable { grpc_fd *(*fd_create)(int fd, const char *name); int (*fd_wrapped_fd)(grpc_fd *fd); void (*fd_orphan)(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_closure *on_done, - int *release_fd, const char *reason); - void (*fd_shutdown)(grpc_exec_ctx *exec_ctx, grpc_fd *fd); + int *release_fd, bool already_closed, const char *reason); + void (*fd_shutdown)(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_error *why); void (*fd_notify_on_read)(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_closure *closure); void (*fd_notify_on_write)(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_closure *closure); bool (*fd_is_shutdown)(grpc_fd *fd); - grpc_workqueue *(*fd_get_workqueue)(grpc_fd *fd); grpc_pollset *(*fd_get_read_notifier_pollset)(grpc_exec_ctx *exec_ctx, grpc_fd *fd); void (*pollset_init)(grpc_pollset *pollset, gpr_mu **mu); void (*pollset_shutdown)(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, grpc_closure *closure); - void (*pollset_reset)(grpc_pollset *pollset); - void (*pollset_destroy)(grpc_pollset *pollset); + void (*pollset_destroy)(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset); grpc_error *(*pollset_work)(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, grpc_pollset_worker **worker, gpr_timespec now, gpr_timespec deadline); @@ -75,7 +60,8 @@ typedef struct grpc_event_engine_vtable { struct grpc_fd *fd); grpc_pollset_set *(*pollset_set_create)(void); - void (*pollset_set_destroy)(grpc_pollset_set *pollset_set); + void (*pollset_set_destroy)(grpc_exec_ctx *exec_ctx, + grpc_pollset_set *pollset_set); void (*pollset_set_add_pollset)(grpc_exec_ctx *exec_ctx, grpc_pollset_set *pollset_set, grpc_pollset *pollset); @@ -93,21 +79,7 @@ typedef struct grpc_event_engine_vtable { void (*pollset_set_del_fd)(grpc_exec_ctx *exec_ctx, grpc_pollset_set *pollset_set, grpc_fd *fd); - grpc_error *(*kick_poller)(void); - void (*shutdown_engine)(void); - -#ifdef GRPC_WORKQUEUE_REFCOUNT_DEBUG - grpc_workqueue *(*workqueue_ref)(grpc_workqueue *workqueue, const char *file, - int line, const char *reason); - void (*workqueue_unref)(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue, - const char *file, int line, const char *reason); -#else - grpc_workqueue *(*workqueue_ref)(grpc_workqueue *workqueue); - void (*workqueue_unref)(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue); -#endif - void (*workqueue_enqueue)(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue, - grpc_closure *closure, grpc_error *error); } grpc_event_engine_vtable; void grpc_event_engine_init(void); @@ -121,9 +93,6 @@ const char *grpc_get_poll_strategy_name(); This takes ownership of closing fd. */ grpc_fd *grpc_fd_create(int fd, const char *name); -/* Get a workqueue that's associated with this fd */ -grpc_workqueue *grpc_fd_get_workqueue(grpc_fd *fd); - /* Return the wrapped fd, or -1 if it has been released or closed. */ int grpc_fd_wrapped_fd(grpc_fd *fd); @@ -135,13 +104,13 @@ int grpc_fd_wrapped_fd(grpc_fd *fd); notify_on_write. MUST NOT be called with a pollset lock taken */ void grpc_fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_closure *on_done, - int *release_fd, const char *reason); + int *release_fd, bool already_closed, const char *reason); /* Has grpc_fd_shutdown been called on an fd? */ bool grpc_fd_is_shutdown(grpc_fd *fd); /* Cause any current and future callbacks to fail. */ -void grpc_fd_shutdown(grpc_exec_ctx *exec_ctx, grpc_fd *fd); +void grpc_fd_shutdown(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_error *why); /* Register read interest, causing read_cb to be called once when fd becomes readable, on deadline specified by deadline, or on shutdown triggered by @@ -184,4 +153,9 @@ void grpc_pollset_set_del_fd(grpc_exec_ctx *exec_ctx, typedef int (*grpc_poll_function_type)(struct pollfd *, nfds_t, int); extern grpc_poll_function_type grpc_poll_function; +/* WARNING: The following two functions should be used for testing purposes + * ONLY */ +void grpc_set_event_engine_test_only(const grpc_event_engine_vtable *); +const grpc_event_engine_vtable *grpc_get_event_engine_test_only(); + #endif /* GRPC_CORE_LIB_IOMGR_EV_POSIX_H */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/ev_windows.c b/Sources/CgRPC/src/core/lib/iomgr/ev_windows.c new file mode 100644 index 000000000..c24dfaeaf --- /dev/null +++ b/Sources/CgRPC/src/core/lib/iomgr/ev_windows.c @@ -0,0 +1,28 @@ +/* + * + * 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 "src/core/lib/iomgr/port.h" + +#ifdef GRPC_WINSOCK_SOCKET + +#include "src/core/lib/debug/trace.h" + +grpc_tracer_flag grpc_polling_trace = + GRPC_TRACER_INITIALIZER(false, "polling"); /* Disabled by default */ + +#endif // GRPC_WINSOCK_SOCKET diff --git a/Sources/CgRPC/src/core/lib/iomgr/exec_ctx.c b/Sources/CgRPC/src/core/lib/iomgr/exec_ctx.c index 604713e57..41c69add1 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/exec_ctx.c +++ b/Sources/CgRPC/src/core/lib/iomgr/exec_ctx.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -38,15 +23,19 @@ #include #include "src/core/lib/iomgr/combiner.h" -#include "src/core/lib/iomgr/workqueue.h" #include "src/core/lib/profiling/timers.h" bool grpc_exec_ctx_ready_to_finish(grpc_exec_ctx *exec_ctx) { - if (!exec_ctx->cached_ready_to_finish) { - exec_ctx->cached_ready_to_finish = exec_ctx->check_ready_to_finish( - exec_ctx, exec_ctx->check_ready_to_finish_arg); + if ((exec_ctx->flags & GRPC_EXEC_CTX_FLAG_IS_FINISHED) == 0) { + if (exec_ctx->check_ready_to_finish(exec_ctx, + exec_ctx->check_ready_to_finish_arg)) { + exec_ctx->flags |= GRPC_EXEC_CTX_FLAG_IS_FINISHED; + return true; + } + return false; + } else { + return true; } - return exec_ctx->cached_ready_to_finish; } bool grpc_never_ready_to_finish(grpc_exec_ctx *exec_ctx, void *arg_ignored) { @@ -57,7 +46,36 @@ bool grpc_always_ready_to_finish(grpc_exec_ctx *exec_ctx, void *arg_ignored) { return true; } -#ifndef GRPC_EXECUTION_CONTEXT_SANITIZER +bool grpc_exec_ctx_has_work(grpc_exec_ctx *exec_ctx) { + return exec_ctx->active_combiner != NULL || + !grpc_closure_list_empty(exec_ctx->closure_list); +} + +void grpc_exec_ctx_finish(grpc_exec_ctx *exec_ctx) { + exec_ctx->flags |= GRPC_EXEC_CTX_FLAG_IS_FINISHED; + grpc_exec_ctx_flush(exec_ctx); +} + +static void exec_ctx_run(grpc_exec_ctx *exec_ctx, grpc_closure *closure, + grpc_error *error) { +#ifndef NDEBUG + closure->scheduled = false; + if (GRPC_TRACER_ON(grpc_trace_closure)) { + gpr_log(GPR_DEBUG, "running closure %p: created [%s:%d]: %s [%s:%d]", + closure, closure->file_created, closure->line_created, + closure->run ? "run" : "scheduled", closure->file_initiated, + closure->line_initiated); + } +#endif + closure->cb(exec_ctx, closure->cb_arg, error); +#ifndef NDEBUG + if (GRPC_TRACER_ON(grpc_trace_closure)) { + gpr_log(GPR_DEBUG, "closure %p finished", closure); + } +#endif + GRPC_ERROR_UNREF(error); +} + bool grpc_exec_ctx_flush(grpc_exec_ctx *exec_ctx) { bool did_something = 0; GPR_TIMER_BEGIN("grpc_exec_ctx_flush", 0); @@ -67,8 +85,9 @@ bool grpc_exec_ctx_flush(grpc_exec_ctx *exec_ctx) { exec_ctx->closure_list.head = exec_ctx->closure_list.tail = NULL; while (c != NULL) { grpc_closure *next = c->next_data.next; + grpc_error *error = c->error_data.error; did_something = true; - grpc_closure_run(exec_ctx, c, c->error_data.error); + exec_ctx_run(exec_ctx, c, error); c = next; } } else if (!grpc_combiner_continue_exec_ctx(exec_ctx)) { @@ -76,137 +95,19 @@ bool grpc_exec_ctx_flush(grpc_exec_ctx *exec_ctx) { } } GPR_ASSERT(exec_ctx->active_combiner == NULL); - if (exec_ctx->stealing_from_workqueue != NULL) { - if (grpc_exec_ctx_ready_to_finish(exec_ctx)) { - grpc_workqueue_enqueue(exec_ctx, exec_ctx->stealing_from_workqueue, - exec_ctx->stolen_closure, - exec_ctx->stolen_closure->error_data.error); - GRPC_WORKQUEUE_UNREF(exec_ctx, exec_ctx->stealing_from_workqueue, - "exec_ctx_sched"); - exec_ctx->stealing_from_workqueue = NULL; - exec_ctx->stolen_closure = NULL; - } else { - grpc_closure *c = exec_ctx->stolen_closure; - GRPC_WORKQUEUE_UNREF(exec_ctx, exec_ctx->stealing_from_workqueue, - "exec_ctx_sched"); - exec_ctx->stealing_from_workqueue = NULL; - exec_ctx->stolen_closure = NULL; - grpc_error *error = c->error_data.error; - GPR_TIMER_BEGIN("grpc_exec_ctx_flush.stolen_cb", 0); - c->cb(exec_ctx, c->cb_arg, error); - GRPC_ERROR_UNREF(error); - GPR_TIMER_END("grpc_exec_ctx_flush.stolen_cb", 0); - grpc_exec_ctx_flush(exec_ctx); - did_something = true; - } - } GPR_TIMER_END("grpc_exec_ctx_flush", 0); return did_something; } -void grpc_exec_ctx_finish(grpc_exec_ctx *exec_ctx) { - exec_ctx->cached_ready_to_finish = true; - grpc_exec_ctx_flush(exec_ctx); -} - -void grpc_exec_ctx_sched(grpc_exec_ctx *exec_ctx, grpc_closure *closure, - grpc_error *error, - grpc_workqueue *offload_target_or_null) { - GPR_TIMER_BEGIN("grpc_exec_ctx_sched", 0); - if (offload_target_or_null == NULL) { - grpc_closure_list_append(&exec_ctx->closure_list, closure, error); - } else if (exec_ctx->stealing_from_workqueue == NULL) { - exec_ctx->stealing_from_workqueue = offload_target_or_null; - closure->error_data.error = error; - exec_ctx->stolen_closure = closure; - } else if (exec_ctx->stealing_from_workqueue != offload_target_or_null) { - grpc_workqueue_enqueue(exec_ctx, offload_target_or_null, closure, error); - GRPC_WORKQUEUE_UNREF(exec_ctx, offload_target_or_null, "exec_ctx_sched"); - } else { /* stealing_from_workqueue == offload_target_or_null */ - grpc_workqueue_enqueue(exec_ctx, offload_target_or_null, - exec_ctx->stolen_closure, - exec_ctx->stolen_closure->error_data.error); - closure->error_data.error = error; - exec_ctx->stolen_closure = closure; - GRPC_WORKQUEUE_UNREF(exec_ctx, offload_target_or_null, "exec_ctx_sched"); - } - GPR_TIMER_END("grpc_exec_ctx_sched", 0); -} - -void grpc_exec_ctx_enqueue_list(grpc_exec_ctx *exec_ctx, - grpc_closure_list *list, - grpc_workqueue *offload_target_or_null) { - grpc_closure_list_move(list, &exec_ctx->closure_list); +static void exec_ctx_sched(grpc_exec_ctx *exec_ctx, grpc_closure *closure, + grpc_error *error) { + grpc_closure_list_append(&exec_ctx->closure_list, closure, error); } void grpc_exec_ctx_global_init(void) {} void grpc_exec_ctx_global_shutdown(void) {} -#else -static gpr_mu g_mu; -static gpr_cv g_cv; -static int g_threads = 0; - -static void run_closure(void *arg) { - grpc_closure *closure = arg; - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - closure->cb(&exec_ctx, closure->cb_arg, (closure->final_data & 1) != 0); - grpc_exec_ctx_finish(&exec_ctx); - gpr_mu_lock(&g_mu); - if (--g_threads == 0) { - gpr_cv_signal(&g_cv); - } - gpr_mu_unlock(&g_mu); -} - -static void start_closure(grpc_closure *closure) { - gpr_thd_id id; - gpr_mu_lock(&g_mu); - g_threads++; - gpr_mu_unlock(&g_mu); - gpr_thd_new(&id, run_closure, closure, NULL); -} - -bool grpc_exec_ctx_flush(grpc_exec_ctx *exec_ctx) { return false; } - -void grpc_exec_ctx_finish(grpc_exec_ctx *exec_ctx) {} - -void grpc_exec_ctx_enqueue(grpc_exec_ctx *exec_ctx, grpc_closure *closure, - bool success, - grpc_workqueue *offload_target_or_null) { - GPR_ASSERT(offload_target_or_null == NULL); - if (closure == NULL) return; - closure->final_data = success; - start_closure(closure); -} - -void grpc_exec_ctx_enqueue_list(grpc_exec_ctx *exec_ctx, - grpc_closure_list *list, - grpc_workqueue *offload_target_or_null) { - GPR_ASSERT(offload_target_or_null == NULL); - if (list == NULL) return; - grpc_closure *p = list->head; - while (p) { - grpc_closure *start = p; - p = grpc_closure_next(start); - start_closure(start); - } - grpc_closure_list r = GRPC_CLOSURE_LIST_INIT; - *list = r; -} - -void grpc_exec_ctx_global_init(void) { - gpr_mu_init(&g_mu); - gpr_cv_init(&g_cv); -} - -void grpc_exec_ctx_global_shutdown(void) { - gpr_mu_lock(&g_mu); - while (g_threads != 0) { - gpr_cv_wait(&g_cv, &g_mu, gpr_inf_future(GPR_CLOCK_REALTIME)); - } - gpr_mu_unlock(&g_mu); - gpr_mu_destroy(&g_mu); - gpr_cv_destroy(&g_cv); -} -#endif +static const grpc_closure_scheduler_vtable exec_ctx_scheduler_vtable = { + exec_ctx_run, exec_ctx_sched, "exec_ctx"}; +static grpc_closure_scheduler exec_ctx_scheduler = {&exec_ctx_scheduler_vtable}; +grpc_closure_scheduler *grpc_schedule_on_exec_ctx = &exec_ctx_scheduler; diff --git a/Sources/CgRPC/src/core/lib/iomgr/exec_ctx.h b/Sources/CgRPC/src/core/lib/iomgr/exec_ctx.h index 7e50cb982..a0d2a965d 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/exec_ctx.h +++ b/Sources/CgRPC/src/core/lib/iomgr/exec_ctx.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -43,6 +28,13 @@ typedef struct grpc_workqueue grpc_workqueue; typedef struct grpc_combiner grpc_combiner; +/* This exec_ctx is ready to return: either pre-populated, or cached as soon as + the finish_check returns true */ +#define GRPC_EXEC_CTX_FLAG_IS_FINISHED 1 +/* The exec_ctx's thread is (potentially) owned by a call or channel: care + should be given to not delete said call/channel from this exec_ctx */ +#define GRPC_EXEC_CTX_FLAG_THREAD_RESOURCE_LOOP 2 + /** Execution context. * A bag of data that collects information along a callstack. * Generally created at public API entry points, and passed down as @@ -63,50 +55,30 @@ typedef struct grpc_combiner grpc_combiner; * - Instances are always passed as the first argument to a function that * takes it, and always as a pointer (grpc_exec_ctx is never copied). */ -#ifndef GRPC_EXECUTION_CONTEXT_SANITIZER struct grpc_exec_ctx { grpc_closure_list closure_list; - /** The workqueue we're stealing work from. - As items are queued to the execution context, we try to steal one - workqueue item and execute it inline (assuming the exec_ctx is not - finished) - doing so does not invalidate the workqueue's contract, and - provides a small latency win in cases where we get a hit */ - grpc_workqueue *stealing_from_workqueue; - /** The workqueue item that was stolen from the workqueue above. When new - items are scheduled to be offloaded to that workqueue, we need to update - this like a 1-deep fifo to maintain the invariant that workqueue items - queued by one thread are started in order */ - grpc_closure *stolen_closure; /** currently active combiner: updated only via combiner.c */ grpc_combiner *active_combiner; /** last active combiner in the active combiner list */ grpc_combiner *last_combiner; - bool cached_ready_to_finish; + uintptr_t flags; void *check_ready_to_finish_arg; bool (*check_ready_to_finish)(grpc_exec_ctx *exec_ctx, void *arg); }; /* initializer for grpc_exec_ctx: prefer to use GRPC_EXEC_CTX_INIT whenever possible */ -#define GRPC_EXEC_CTX_INIT_WITH_FINISH_CHECK(finish_check, finish_check_arg) \ - { \ - GRPC_CLOSURE_LIST_INIT, NULL, NULL, NULL, NULL, false, finish_check_arg, \ - finish_check \ - } -#else -struct grpc_exec_ctx { - bool cached_ready_to_finish; - void *check_ready_to_finish_arg; - bool (*check_ready_to_finish)(grpc_exec_ctx *exec_ctx, void *arg); -}; -#define GRPC_EXEC_CTX_INIT_WITH_FINISH_CHECK(finish_check, finish_check_arg) \ - { false, finish_check_arg, finish_check } -#endif +#define GRPC_EXEC_CTX_INITIALIZER(flags, finish_check, finish_check_arg) \ + { GRPC_CLOSURE_LIST_INIT, NULL, NULL, flags, finish_check_arg, finish_check } /* initialize an execution context at the top level of an API call into grpc (this is safe to use elsewhere, though possibly not as efficient) */ #define GRPC_EXEC_CTX_INIT \ - GRPC_EXEC_CTX_INIT_WITH_FINISH_CHECK(grpc_always_ready_to_finish, NULL) + GRPC_EXEC_CTX_INITIALIZER(GRPC_EXEC_CTX_FLAG_IS_FINISHED, NULL, NULL) + +extern grpc_closure_scheduler *grpc_schedule_on_exec_ctx; + +bool grpc_exec_ctx_has_work(grpc_exec_ctx *exec_ctx); /** Flush any work that has been enqueued onto this grpc_exec_ctx. * Caller must guarantee that no interfering locks are held. @@ -115,14 +87,6 @@ bool grpc_exec_ctx_flush(grpc_exec_ctx *exec_ctx); /** Finish any pending work for a grpc_exec_ctx. Must be called before * the instance is destroyed, or work may be lost. */ void grpc_exec_ctx_finish(grpc_exec_ctx *exec_ctx); -/** Add a closure to be executed in the future. - If \a offload_target_or_null is NULL, the closure will be executed at the - next exec_ctx.{finish,flush} point. - If \a offload_target_or_null is non-NULL, the closure will be scheduled - against the workqueue, and a reference to the workqueue will be consumed. */ -void grpc_exec_ctx_sched(grpc_exec_ctx *exec_ctx, grpc_closure *closure, - grpc_error *error, - grpc_workqueue *offload_target_or_null); /** Returns true if we'd like to leave this execution context as soon as possible: useful for deciding whether to do something more or not depending on outside context */ @@ -131,11 +95,6 @@ bool grpc_exec_ctx_ready_to_finish(grpc_exec_ctx *exec_ctx); bool grpc_never_ready_to_finish(grpc_exec_ctx *exec_ctx, void *arg_ignored); /** A finish check that is always ready to finish */ bool grpc_always_ready_to_finish(grpc_exec_ctx *exec_ctx, void *arg_ignored); -/** Add a list of closures to be executed at the next flush/finish point. - * Leaves \a list empty. */ -void grpc_exec_ctx_enqueue_list(grpc_exec_ctx *exec_ctx, - grpc_closure_list *list, - grpc_workqueue *offload_target_or_null); void grpc_exec_ctx_global_init(void); diff --git a/Sources/CgRPC/src/core/lib/iomgr/executor.c b/Sources/CgRPC/src/core/lib/iomgr/executor.c index 8d7535d6f..7621a7fe7 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/executor.c +++ b/Sources/CgRPC/src/core/lib/iomgr/executor.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -36,108 +21,175 @@ #include #include +#include #include #include #include +#include +#include + #include "src/core/lib/iomgr/exec_ctx.h" +#include "src/core/lib/support/spinlock.h" + +#define MAX_DEPTH 2 -typedef struct grpc_executor_data { - int busy; /**< is the thread currently running? */ - int shutting_down; /**< has \a grpc_shutdown() been invoked? */ - int pending_join; /**< has the thread finished but not been joined? */ - grpc_closure_list closures; /**< collection of pending work */ - gpr_thd_id tid; /**< thread id of the thread, only valid if \a busy or \a - pending_join are true */ - gpr_thd_options options; +typedef struct { gpr_mu mu; -} grpc_executor; + gpr_cv cv; + grpc_closure_list elems; + size_t depth; + bool shutdown; + gpr_thd_id id; +} thread_state; + +static thread_state *g_thread_state; +static size_t g_max_threads; +static gpr_atm g_cur_threads; +static gpr_spinlock g_adding_thread_lock = GPR_SPINLOCK_STATIC_INITIALIZER; + +GPR_TLS_DECL(g_this_thread_state); + +static void executor_thread(void *arg); -static grpc_executor g_executor; +static size_t run_closures(grpc_exec_ctx *exec_ctx, grpc_closure_list list) { + size_t n = 0; -void grpc_executor_init() { - memset(&g_executor, 0, sizeof(grpc_executor)); - gpr_mu_init(&g_executor.mu); - g_executor.options = gpr_thd_options_default(); - gpr_thd_options_set_joinable(&g_executor.options); + grpc_closure *c = list.head; + while (c != NULL) { + grpc_closure *next = c->next_data.next; + grpc_error *error = c->error_data.error; +#ifndef NDEBUG + c->scheduled = false; +#endif + c->cb(exec_ctx, c->cb_arg, error); + GRPC_ERROR_UNREF(error); + c = next; + n++; + } + + return n; } -/* thread body */ -static void closure_exec_thread_func(void *ignored) { - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - while (1) { - gpr_mu_lock(&g_executor.mu); - if (g_executor.shutting_down != 0) { - gpr_mu_unlock(&g_executor.mu); - break; +bool grpc_executor_is_threaded() { + return gpr_atm_no_barrier_load(&g_cur_threads) > 0; +} + +void grpc_executor_set_threading(grpc_exec_ctx *exec_ctx, bool threading) { + gpr_atm cur_threads = gpr_atm_no_barrier_load(&g_cur_threads); + if (threading) { + if (cur_threads > 0) return; + g_max_threads = GPR_MAX(1, 2 * gpr_cpu_num_cores()); + gpr_atm_no_barrier_store(&g_cur_threads, 1); + gpr_tls_init(&g_this_thread_state); + g_thread_state = gpr_zalloc(sizeof(thread_state) * g_max_threads); + for (size_t i = 0; i < g_max_threads; i++) { + gpr_mu_init(&g_thread_state[i].mu); + gpr_cv_init(&g_thread_state[i].cv); + g_thread_state[i].elems = (grpc_closure_list)GRPC_CLOSURE_LIST_INIT; + } + + gpr_thd_options opt = gpr_thd_options_default(); + gpr_thd_options_set_joinable(&opt); + gpr_thd_new(&g_thread_state[0].id, executor_thread, &g_thread_state[0], + &opt); + } else { + if (cur_threads == 0) return; + for (size_t i = 0; i < g_max_threads; i++) { + gpr_mu_lock(&g_thread_state[i].mu); + g_thread_state[i].shutdown = true; + gpr_cv_signal(&g_thread_state[i].cv); + gpr_mu_unlock(&g_thread_state[i].mu); + } + /* ensure no thread is adding a new thread... once this is past, then + no thread will try to add a new one either (since shutdown is true) */ + gpr_spinlock_lock(&g_adding_thread_lock); + gpr_spinlock_unlock(&g_adding_thread_lock); + for (gpr_atm i = 0; i < g_cur_threads; i++) { + gpr_thd_join(g_thread_state[i].id); + } + gpr_atm_no_barrier_store(&g_cur_threads, 0); + for (size_t i = 0; i < g_max_threads; i++) { + gpr_mu_destroy(&g_thread_state[i].mu); + gpr_cv_destroy(&g_thread_state[i].cv); + run_closures(exec_ctx, g_thread_state[i].elems); + } + gpr_free(g_thread_state); + gpr_tls_destroy(&g_this_thread_state); + } +} + +void grpc_executor_init(grpc_exec_ctx *exec_ctx) { + gpr_atm_no_barrier_store(&g_cur_threads, 0); + grpc_executor_set_threading(exec_ctx, true); +} + +void grpc_executor_shutdown(grpc_exec_ctx *exec_ctx) { + grpc_executor_set_threading(exec_ctx, false); +} + +static void executor_thread(void *arg) { + thread_state *ts = arg; + gpr_tls_set(&g_this_thread_state, (intptr_t)ts); + + grpc_exec_ctx exec_ctx = + GRPC_EXEC_CTX_INITIALIZER(0, grpc_never_ready_to_finish, NULL); + + size_t subtract_depth = 0; + for (;;) { + gpr_mu_lock(&ts->mu); + ts->depth -= subtract_depth; + while (grpc_closure_list_empty(ts->elems) && !ts->shutdown) { + gpr_cv_wait(&ts->cv, &ts->mu, gpr_inf_future(GPR_CLOCK_REALTIME)); } - if (grpc_closure_list_empty(g_executor.closures)) { - /* no more work, time to die */ - GPR_ASSERT(g_executor.busy == 1); - g_executor.busy = 0; - gpr_mu_unlock(&g_executor.mu); + if (ts->shutdown) { + gpr_mu_unlock(&ts->mu); break; - } else { - grpc_exec_ctx_enqueue_list(&exec_ctx, &g_executor.closures, NULL); } - gpr_mu_unlock(&g_executor.mu); + grpc_closure_list exec = ts->elems; + ts->elems = (grpc_closure_list)GRPC_CLOSURE_LIST_INIT; + gpr_mu_unlock(&ts->mu); + + subtract_depth = run_closures(&exec_ctx, exec); grpc_exec_ctx_flush(&exec_ctx); } grpc_exec_ctx_finish(&exec_ctx); } -/* Spawn the thread if new work has arrived a no thread is up */ -static void maybe_spawn_locked() { - if (grpc_closure_list_empty(g_executor.closures) == 1) { +static void executor_push(grpc_exec_ctx *exec_ctx, grpc_closure *closure, + grpc_error *error) { + size_t cur_thread_count = (size_t)gpr_atm_no_barrier_load(&g_cur_threads); + if (cur_thread_count == 0) { + grpc_closure_list_append(&exec_ctx->closure_list, closure, error); return; } - if (g_executor.shutting_down == 1) { - return; + thread_state *ts = (thread_state *)gpr_tls_get(&g_this_thread_state); + if (ts == NULL) { + ts = &g_thread_state[GPR_HASH_POINTER(exec_ctx, cur_thread_count)]; } - - if (g_executor.busy != 0) { - /* Thread still working. New work will be picked up by already running - * thread. Not spawning anything. */ - return; - } else if (g_executor.pending_join != 0) { - /* Pickup the remains of the previous incarnations of the thread. */ - gpr_thd_join(g_executor.tid); - g_executor.pending_join = 0; + gpr_mu_lock(&ts->mu); + if (grpc_closure_list_empty(ts->elems)) { + gpr_cv_signal(&ts->cv); } + grpc_closure_list_append(&ts->elems, closure, error); + ts->depth++; + bool try_new_thread = ts->depth > MAX_DEPTH && + cur_thread_count < g_max_threads && !ts->shutdown; + gpr_mu_unlock(&ts->mu); + if (try_new_thread && gpr_spinlock_trylock(&g_adding_thread_lock)) { + cur_thread_count = (size_t)gpr_atm_no_barrier_load(&g_cur_threads); + if (cur_thread_count < g_max_threads) { + gpr_atm_no_barrier_store(&g_cur_threads, cur_thread_count + 1); - /* All previous instances of the thread should have been joined at this point. - * Spawn time! */ - g_executor.busy = 1; - gpr_thd_new(&g_executor.tid, closure_exec_thread_func, NULL, - &g_executor.options); - g_executor.pending_join = 1; -} - -void grpc_executor_push(grpc_closure *closure, grpc_error *error) { - gpr_mu_lock(&g_executor.mu); - if (g_executor.shutting_down == 0) { - grpc_closure_list_append(&g_executor.closures, closure, error); - maybe_spawn_locked(); + gpr_thd_options opt = gpr_thd_options_default(); + gpr_thd_options_set_joinable(&opt); + gpr_thd_new(&g_thread_state[cur_thread_count].id, executor_thread, + &g_thread_state[cur_thread_count], &opt); + } + gpr_spinlock_unlock(&g_adding_thread_lock); } - gpr_mu_unlock(&g_executor.mu); } -void grpc_executor_shutdown() { - int pending_join; - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - - gpr_mu_lock(&g_executor.mu); - pending_join = g_executor.pending_join; - g_executor.shutting_down = 1; - gpr_mu_unlock(&g_executor.mu); - /* we can release the lock at this point despite the access to the closure - * list below because we aren't accepting new work */ - - /* Execute pending callbacks, some may be performing cleanups */ - grpc_exec_ctx_enqueue_list(&exec_ctx, &g_executor.closures, NULL); - grpc_exec_ctx_finish(&exec_ctx); - GPR_ASSERT(grpc_closure_list_empty(g_executor.closures)); - if (pending_join) { - gpr_thd_join(g_executor.tid); - } - gpr_mu_destroy(&g_executor.mu); -} +static const grpc_closure_scheduler_vtable executor_vtable = { + executor_push, executor_push, "executor"}; +static grpc_closure_scheduler executor_scheduler = {&executor_vtable}; +grpc_closure_scheduler *grpc_executor_scheduler = &executor_scheduler; diff --git a/Sources/CgRPC/src/core/lib/iomgr/executor.h b/Sources/CgRPC/src/core/lib/iomgr/executor.h index da9dcd07d..c3382a0a1 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/executor.h +++ b/Sources/CgRPC/src/core/lib/iomgr/executor.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -41,13 +26,18 @@ * This mechanism is meant to outsource work (grpc_closure instances) to a * thread, for those cases where blocking isn't an option but there isn't a * non-blocking solution available. */ -void grpc_executor_init(); +void grpc_executor_init(grpc_exec_ctx *exec_ctx); -/** Enqueue \a closure for its eventual execution of \a f(arg) on a separate - * thread */ -void grpc_executor_push(grpc_closure *closure, grpc_error *error); +extern grpc_closure_scheduler *grpc_executor_scheduler; /** Shutdown the executor, running all pending work as part of the call */ -void grpc_executor_shutdown(); +void grpc_executor_shutdown(grpc_exec_ctx *exec_ctx); + +/** Is the executor multi-threaded? */ +bool grpc_executor_is_threaded(); + +/* enable/disable threading - must be called after grpc_executor_init and before + grpc_executor_shutdown */ +void grpc_executor_set_threading(grpc_exec_ctx *exec_ctx, bool enable); #endif /* GRPC_CORE_LIB_IOMGR_EXECUTOR_H */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/gethostname.h b/Sources/CgRPC/src/core/lib/iomgr/gethostname.h new file mode 100644 index 000000000..9c6b9d8d4 --- /dev/null +++ b/Sources/CgRPC/src/core/lib/iomgr/gethostname.h @@ -0,0 +1,26 @@ +/* + * + * Copyright 2017 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 GRPC_CORE_LIB_IOMGR_GETHOSTNAME_H +#define GRPC_CORE_LIB_IOMGR_GETHOSTNAME_H + +// Returns the hostname of the local machine. +// Caller takes ownership of result. +char *grpc_gethostname(); + +#endif /* GRPC_CORE_LIB_IOMGR_GETHOSTNAME_H */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/gethostname_fallback.c b/Sources/CgRPC/src/core/lib/iomgr/gethostname_fallback.c new file mode 100644 index 000000000..622946156 --- /dev/null +++ b/Sources/CgRPC/src/core/lib/iomgr/gethostname_fallback.c @@ -0,0 +1,27 @@ +/* + * + * Copyright 2017 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 "src/core/lib/iomgr/port.h" + +#ifdef GRPC_GETHOSTNAME_FALLBACK + +#include + +char *grpc_gethostname() { return NULL; } + +#endif // GRPC_GETHOSTNAME_FALLBACK diff --git a/Sources/CgRPC/src/core/lib/iomgr/gethostname_host_name_max.c b/Sources/CgRPC/src/core/lib/iomgr/gethostname_host_name_max.c new file mode 100644 index 000000000..4d0511412 --- /dev/null +++ b/Sources/CgRPC/src/core/lib/iomgr/gethostname_host_name_max.c @@ -0,0 +1,37 @@ +/* + * + * Copyright 2017 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 "src/core/lib/iomgr/port.h" + +#ifdef GRPC_POSIX_HOST_NAME_MAX + +#include +#include + +#include + +char *grpc_gethostname() { + char *hostname = (char *)gpr_malloc(HOST_NAME_MAX); + if (gethostname(hostname, HOST_NAME_MAX) != 0) { + gpr_free(hostname); + return NULL; + } + return hostname; +} + +#endif // GRPC_POSIX_HOST_NAME_MAX diff --git a/Sources/CgRPC/src/core/lib/iomgr/gethostname_sysconf.c b/Sources/CgRPC/src/core/lib/iomgr/gethostname_sysconf.c new file mode 100644 index 000000000..51bac5d69 --- /dev/null +++ b/Sources/CgRPC/src/core/lib/iomgr/gethostname_sysconf.c @@ -0,0 +1,37 @@ +/* + * + * Copyright 2017 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 "src/core/lib/iomgr/port.h" + +#ifdef GRPC_POSIX_SYSCONF + +#include + +#include + +char *grpc_gethostname() { + size_t host_name_max = (size_t)sysconf(_SC_HOST_NAME_MAX); + char *hostname = (char *)gpr_malloc(host_name_max); + if (gethostname(hostname, host_name_max) != 0) { + gpr_free(hostname); + return NULL; + } + return hostname; +} + +#endif // GRPC_POSIX_SYSCONF diff --git a/Sources/CgRPC/src/core/lib/iomgr/iocp_windows.c b/Sources/CgRPC/src/core/lib/iomgr/iocp_windows.c index 60ebe4367..e343f8a79 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/iocp_windows.c +++ b/Sources/CgRPC/src/core/lib/iomgr/iocp_windows.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -80,7 +65,6 @@ grpc_iocp_work_status grpc_iocp_work(grpc_exec_ctx *exec_ctx, LPOVERLAPPED overlapped; grpc_winsocket *socket; grpc_winsocket_callback_info *info; - grpc_closure *closure = NULL; success = GetQueuedCompletionStatus( g_iocp, &bytes, &completion_key, &overlapped, deadline_to_millis_timeout(deadline, gpr_now(deadline.clock_type))); diff --git a/Sources/CgRPC/src/core/lib/iomgr/iocp_windows.h b/Sources/CgRPC/src/core/lib/iomgr/iocp_windows.h index 011fee38f..9c89e868c 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/iocp_windows.h +++ b/Sources/CgRPC/src/core/lib/iomgr/iocp_windows.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/iomgr.c b/Sources/CgRPC/src/core/lib/iomgr/iomgr.c index 3470b5ac8..3d19953ee 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/iomgr.c +++ b/Sources/CgRPC/src/core/lib/iomgr/iomgr.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -44,9 +29,11 @@ #include #include "src/core/lib/iomgr/exec_ctx.h" +#include "src/core/lib/iomgr/executor.h" #include "src/core/lib/iomgr/iomgr_internal.h" #include "src/core/lib/iomgr/network_status_tracker.h" #include "src/core/lib/iomgr/timer.h" +#include "src/core/lib/iomgr/timer_manager.h" #include "src/core/lib/support/env.h" #include "src/core/lib/support/string.h" @@ -55,11 +42,12 @@ static gpr_cv g_rcv; static int g_shutdown; static grpc_iomgr_object g_root_object; -void grpc_iomgr_init(void) { +void grpc_iomgr_init(grpc_exec_ctx *exec_ctx) { g_shutdown = 0; gpr_mu_init(&g_mu); gpr_cv_init(&g_rcv); grpc_exec_ctx_global_init(); + grpc_executor_init(exec_ctx); grpc_timer_list_init(gpr_now(GPR_CLOCK_MONOTONIC)); g_root_object.next = g_root_object.prev = &g_root_object; g_root_object.name = "root"; @@ -67,6 +55,8 @@ void grpc_iomgr_init(void) { grpc_iomgr_platform_init(); } +void grpc_iomgr_start(grpc_exec_ctx *exec_ctx) { grpc_timer_manager_init(); } + static size_t count_objects(void) { grpc_iomgr_object *obj; size_t n = 0; @@ -83,13 +73,14 @@ static void dump_objects(const char *kind) { } } -void grpc_iomgr_shutdown(void) { +void grpc_iomgr_shutdown(grpc_exec_ctx *exec_ctx) { gpr_timespec shutdown_deadline = gpr_time_add( gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_seconds(10, GPR_TIMESPAN)); gpr_timespec last_warning_time = gpr_now(GPR_CLOCK_REALTIME); - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + grpc_timer_manager_shutdown(); grpc_iomgr_platform_flush(); + grpc_executor_shutdown(exec_ctx); gpr_mu_lock(&g_mu); g_shutdown = 1; @@ -104,10 +95,10 @@ void grpc_iomgr_shutdown(void) { } last_warning_time = gpr_now(GPR_CLOCK_REALTIME); } - if (grpc_timer_check(&exec_ctx, gpr_inf_future(GPR_CLOCK_MONOTONIC), - NULL)) { + if (grpc_timer_check(exec_ctx, gpr_inf_future(GPR_CLOCK_MONOTONIC), NULL) == + GRPC_TIMERS_FIRED) { gpr_mu_unlock(&g_mu); - grpc_exec_ctx_flush(&exec_ctx); + grpc_exec_ctx_flush(exec_ctx); grpc_iomgr_platform_flush(); gpr_mu_lock(&g_mu); continue; @@ -139,8 +130,8 @@ void grpc_iomgr_shutdown(void) { } gpr_mu_unlock(&g_mu); - grpc_timer_list_shutdown(&exec_ctx); - grpc_exec_ctx_finish(&exec_ctx); + grpc_timer_list_shutdown(exec_ctx); + grpc_exec_ctx_flush(exec_ctx); /* ensure all threads have left g_mu */ gpr_mu_lock(&g_mu); diff --git a/Sources/CgRPC/src/core/lib/iomgr/iomgr.h b/Sources/CgRPC/src/core/lib/iomgr/iomgr.h index c1cfaf302..e3cd6ebe7 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/iomgr.h +++ b/Sources/CgRPC/src/core/lib/iomgr/iomgr.h @@ -1,45 +1,35 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 GRPC_CORE_LIB_IOMGR_IOMGR_H #define GRPC_CORE_LIB_IOMGR_IOMGR_H +#include #include "src/core/lib/iomgr/port.h" /** Initializes the iomgr. */ -void grpc_iomgr_init(void); +void grpc_iomgr_init(grpc_exec_ctx *exec_ctx); -/** Signals the intention to shutdown the iomgr. */ -void grpc_iomgr_shutdown(void); +/** Starts any background threads for iomgr. */ +void grpc_iomgr_start(grpc_exec_ctx *exec_ctx); + +/** Signals the intention to shutdown the iomgr. Expects to be able to flush + * exec_ctx. */ +void grpc_iomgr_shutdown(grpc_exec_ctx *exec_ctx); #endif /* GRPC_CORE_LIB_IOMGR_IOMGR_H */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/iomgr_internal.h b/Sources/CgRPC/src/core/lib/iomgr/iomgr_internal.h index 805be1f1e..836d82515 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/iomgr_internal.h +++ b/Sources/CgRPC/src/core/lib/iomgr/iomgr_internal.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/iomgr_posix.c b/Sources/CgRPC/src/core/lib/iomgr/iomgr_posix.c index f5ee0c9ee..f5875a247 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/iomgr_posix.c +++ b/Sources/CgRPC/src/core/lib/iomgr/iomgr_posix.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -43,7 +28,7 @@ void grpc_iomgr_platform_init(void) { grpc_wakeup_fd_global_init(); grpc_event_engine_init(); - grpc_register_tracer("tcp", &grpc_tcp_trace); + grpc_register_tracer(&grpc_tcp_trace); } void grpc_iomgr_platform_flush(void) {} diff --git a/Sources/CgRPC/src/core/lib/iomgr/iomgr_posix.h b/Sources/CgRPC/src/core/lib/iomgr/iomgr_posix.h index d5eade962..f7a4af6a8 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/iomgr_posix.h +++ b/Sources/CgRPC/src/core/lib/iomgr/iomgr_posix.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/iomgr_uv.c b/Sources/CgRPC/src/core/lib/iomgr/iomgr_uv.c index 96516ff16..df5d23af3 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/iomgr_uv.c +++ b/Sources/CgRPC/src/core/lib/iomgr/iomgr_uv.c @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -36,12 +21,20 @@ #ifdef GRPC_UV #include "src/core/lib/debug/trace.h" +#include "src/core/lib/iomgr/executor.h" +#include "src/core/lib/iomgr/iomgr_uv.h" #include "src/core/lib/iomgr/pollset_uv.h" #include "src/core/lib/iomgr/tcp_uv.h" +gpr_thd_id g_init_thread; + void grpc_iomgr_platform_init(void) { + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_pollset_global_init(); - grpc_register_tracer("tcp", &grpc_tcp_trace); + grpc_register_tracer(&grpc_tcp_trace); + grpc_executor_set_threading(&exec_ctx, false); + g_init_thread = gpr_thd_currentid(); + grpc_exec_ctx_finish(&exec_ctx); } void grpc_iomgr_platform_flush(void) {} void grpc_iomgr_platform_shutdown(void) { grpc_pollset_global_shutdown(); } diff --git a/Sources/CgRPC/src/core/lib/iomgr/iomgr_uv.h b/Sources/CgRPC/src/core/lib/iomgr/iomgr_uv.h new file mode 100644 index 000000000..3b4daaa73 --- /dev/null +++ b/Sources/CgRPC/src/core/lib/iomgr/iomgr_uv.h @@ -0,0 +1,37 @@ +/* + * + * Copyright 2017 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 GRPC_CORE_LIB_IOMGR_IOMGR_UV_H +#define GRPC_CORE_LIB_IOMGR_IOMGR_UV_H + +#include "src/core/lib/iomgr/iomgr_internal.h" + +#include + +/* The thread ID of the thread on which grpc was initialized. Used to verify + * that all calls into libuv are made on that same thread */ +extern gpr_thd_id g_init_thread; + +#ifdef GRPC_UV_THREAD_CHECK +#define GRPC_UV_ASSERT_SAME_THREAD() \ + GPR_ASSERT(gpr_thd_currentid() == g_init_thread) +#else +#define GRPC_UV_ASSERT_SAME_THREAD() +#endif /* GRPC_UV_THREAD_CHECK */ + +#endif /* GRPC_CORE_LIB_IOMGR_IOMGR_UV_H */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/iomgr_windows.c b/Sources/CgRPC/src/core/lib/iomgr/iomgr_windows.c index b659264ed..630370166 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/iomgr_windows.c +++ b/Sources/CgRPC/src/core/lib/iomgr/iomgr_windows.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/is_epollexclusive_available.c b/Sources/CgRPC/src/core/lib/iomgr/is_epollexclusive_available.c new file mode 100644 index 000000000..e8a7d4d52 --- /dev/null +++ b/Sources/CgRPC/src/core/lib/iomgr/is_epollexclusive_available.c @@ -0,0 +1,101 @@ +/* + * + * Copyright 2017 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 "src/core/lib/iomgr/port.h" + +#include "src/core/lib/iomgr/is_epollexclusive_available.h" + +#ifdef GRPC_LINUX_EPOLL + +#include + +#include +#include +#include + +#include "src/core/lib/iomgr/sys_epoll_wrapper.h" + +/* This polling engine is only relevant on linux kernels supporting epoll() */ +bool grpc_is_epollexclusive_available(void) { + static bool logged_why_not = false; + + int fd = epoll_create1(EPOLL_CLOEXEC); + if (fd < 0) { + if (!logged_why_not) { + gpr_log(GPR_ERROR, + "epoll_create1 failed with error: %d. Not using epollex polling " + "engine.", + fd); + logged_why_not = true; + } + return false; + } + int evfd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); + if (evfd < 0) { + if (!logged_why_not) { + gpr_log(GPR_ERROR, + "eventfd failed with error: %d. Not using epollex polling " + "engine.", + fd); + logged_why_not = true; + } + close(fd); + return false; + } + struct epoll_event ev = { + /* choose events that should cause an error on + EPOLLEXCLUSIVE enabled kernels - specifically the combination of + EPOLLONESHOT and EPOLLEXCLUSIVE */ + .events = (uint32_t)(EPOLLET | EPOLLIN | EPOLLEXCLUSIVE | EPOLLONESHOT), + .data.ptr = NULL}; + if (epoll_ctl(fd, EPOLL_CTL_ADD, evfd, &ev) != 0) { + if (errno != EINVAL) { + if (!logged_why_not) { + gpr_log( + GPR_ERROR, + "epoll_ctl with EPOLLEXCLUSIVE | EPOLLONESHOT failed with error: " + "%d. Not using epollex polling engine.", + errno); + logged_why_not = true; + } + close(fd); + close(evfd); + return false; + } + } else { + if (!logged_why_not) { + gpr_log(GPR_ERROR, + "epoll_ctl with EPOLLEXCLUSIVE | EPOLLONESHOT succeeded. This is " + "evidence of no EPOLLEXCLUSIVE support. Not using " + "epollex polling engine."); + logged_why_not = true; + } + close(fd); + close(evfd); + return false; + } + close(evfd); + close(fd); + return true; +} + +#else + +bool grpc_is_epollexclusive_available(void) { return false; } + +#endif diff --git a/Sources/CgRPC/src/core/lib/iomgr/is_epollexclusive_available.h b/Sources/CgRPC/src/core/lib/iomgr/is_epollexclusive_available.h new file mode 100644 index 000000000..1d2e133a3 --- /dev/null +++ b/Sources/CgRPC/src/core/lib/iomgr/is_epollexclusive_available.h @@ -0,0 +1,26 @@ +/* + * + * 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 GRPC_CORE_LIB_IOMGR_IS_EPOLLEXCLUSIVE_AVAILABLE_H +#define GRPC_CORE_LIB_IOMGR_IS_EPOLLEXCLUSIVE_AVAILABLE_H + +#include + +bool grpc_is_epollexclusive_available(void); + +#endif /* GRPC_CORE_LIB_IOMGR_IS_EPOLLEXCLUSIVE_AVAILABLE_H */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/load_file.c b/Sources/CgRPC/src/core/lib/iomgr/load_file.c index 217bc5da5..ba77a52af 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/load_file.c +++ b/Sources/CgRPC/src/core/lib/iomgr/load_file.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -47,7 +32,7 @@ grpc_error *grpc_load_file(const char *filename, int add_null_terminator, grpc_slice *output) { unsigned char *contents = NULL; size_t contents_size = 0; - grpc_slice result = gpr_empty_slice(); + grpc_slice result = grpc_empty_slice(); FILE *file; size_t bytes_read = 0; grpc_error *error = GRPC_ERROR_NONE; @@ -78,9 +63,12 @@ grpc_error *grpc_load_file(const char *filename, int add_null_terminator, *output = result; if (file != NULL) fclose(file); if (error != GRPC_ERROR_NONE) { - grpc_error *error_out = grpc_error_set_str( - GRPC_ERROR_CREATE_REFERENCING("Failed to load file", &error, 1), - GRPC_ERROR_STR_FILENAME, filename); + grpc_error *error_out = + grpc_error_set_str(GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( + "Failed to load file", &error, 1), + GRPC_ERROR_STR_FILENAME, + grpc_slice_from_copied_string( + filename)); // TODO(ncteisen), always static? GRPC_ERROR_UNREF(error); error = error_out; } diff --git a/Sources/CgRPC/src/core/lib/iomgr/load_file.h b/Sources/CgRPC/src/core/lib/iomgr/load_file.h index 73ee8c3ab..db1ffb3d6 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/load_file.h +++ b/Sources/CgRPC/src/core/lib/iomgr/load_file.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/lockfree_event.c b/Sources/CgRPC/src/core/lib/iomgr/lockfree_event.c new file mode 100644 index 000000000..f967b22ba --- /dev/null +++ b/Sources/CgRPC/src/core/lib/iomgr/lockfree_event.c @@ -0,0 +1,241 @@ +/* + * + * Copyright 2017 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 "src/core/lib/iomgr/lockfree_event.h" + +#include + +#include "src/core/lib/debug/trace.h" + +extern grpc_tracer_flag grpc_polling_trace; + +/* 'state' holds the to call when the fd is readable or writable respectively. + It can contain one of the following values: + CLOSURE_READY : The fd has an I/O event of interest but there is no + closure yet to execute + + CLOSURE_NOT_READY : The fd has no I/O event of interest + + closure ptr : The closure to be executed when the fd has an I/O + event of interest + + shutdown_error | FD_SHUTDOWN_BIT : + 'shutdown_error' field ORed with FD_SHUTDOWN_BIT. + This indicates that the fd is shutdown. Since all + memory allocations are word-aligned, the lower two + bits of the shutdown_error pointer are always 0. So + it is safe to OR these with FD_SHUTDOWN_BIT + + Valid state transitions: + + <-----3------ CLOSURE_NOT_READY ----1----> CLOSURE_READY + | | ^ | ^ | | + | | | | | | | + | +--------------4----------+ 6 +---------2---------------+ | + | | | + | v | + +-----5-------> [shutdown_error | FD_SHUTDOWN_BIT] <----7---------+ + + For 1, 4 : See grpc_lfev_set_ready() function + For 2, 3 : See grpc_lfev_notify_on() function + For 5,6,7: See grpc_lfev_set_shutdown() function */ + +#define CLOSURE_NOT_READY ((gpr_atm)0) +#define CLOSURE_READY ((gpr_atm)2) + +#define FD_SHUTDOWN_BIT ((gpr_atm)1) + +void grpc_lfev_init(gpr_atm *state) { + gpr_atm_no_barrier_store(state, CLOSURE_NOT_READY); +} + +void grpc_lfev_destroy(gpr_atm *state) { + gpr_atm curr = gpr_atm_no_barrier_load(state); + if (curr & FD_SHUTDOWN_BIT) { + GRPC_ERROR_UNREF((grpc_error *)(curr & ~FD_SHUTDOWN_BIT)); + } else { + GPR_ASSERT(curr == CLOSURE_NOT_READY || curr == CLOSURE_READY); + } +} + +bool grpc_lfev_is_shutdown(gpr_atm *state) { + gpr_atm curr = gpr_atm_no_barrier_load(state); + return (curr & FD_SHUTDOWN_BIT) != 0; +} + +void grpc_lfev_notify_on(grpc_exec_ctx *exec_ctx, gpr_atm *state, + grpc_closure *closure, const char *variable) { + while (true) { + gpr_atm curr = gpr_atm_no_barrier_load(state); + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_ERROR, "lfev_notify_on[%s]: %p curr=%p closure=%p", variable, + state, (void *)curr, closure); + } + switch (curr) { + case CLOSURE_NOT_READY: { + /* CLOSURE_NOT_READY -> . + + We're guaranteed by API that there's an acquire barrier before here, + so there's no need to double-dip and this can be a release-only. + + The release itself pairs with the acquire half of a set_ready full + barrier. */ + if (gpr_atm_rel_cas(state, CLOSURE_NOT_READY, (gpr_atm)closure)) { + return; /* Successful. Return */ + } + + break; /* retry */ + } + + case CLOSURE_READY: { + /* Change the state to CLOSURE_NOT_READY. Schedule the closure if + successful. If not, the state most likely transitioned to shutdown. + We should retry. + + This can be a no-barrier cas since the state is being transitioned to + CLOSURE_NOT_READY; set_ready and set_shutdown do not schedule any + closure when transitioning out of CLOSURE_NO_READY state (i.e there + is no other code that needs to 'happen-after' this) */ + if (gpr_atm_no_barrier_cas(state, CLOSURE_READY, CLOSURE_NOT_READY)) { + GRPC_CLOSURE_SCHED(exec_ctx, closure, GRPC_ERROR_NONE); + return; /* Successful. Return */ + } + + break; /* retry */ + } + + default: { + /* 'curr' is either a closure or the fd is shutdown(in which case 'curr' + contains a pointer to the shutdown-error). If the fd is shutdown, + schedule the closure with the shutdown error */ + if ((curr & FD_SHUTDOWN_BIT) > 0) { + grpc_error *shutdown_err = (grpc_error *)(curr & ~FD_SHUTDOWN_BIT); + GRPC_CLOSURE_SCHED(exec_ctx, closure, + GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( + "FD Shutdown", &shutdown_err, 1)); + return; + } + + /* There is already a closure!. This indicates a bug in the code */ + gpr_log(GPR_ERROR, + "notify_on called with a previous callback still pending"); + abort(); + } + } + } + + GPR_UNREACHABLE_CODE(return ); +} + +bool grpc_lfev_set_shutdown(grpc_exec_ctx *exec_ctx, gpr_atm *state, + grpc_error *shutdown_err) { + gpr_atm new_state = (gpr_atm)shutdown_err | FD_SHUTDOWN_BIT; + + while (true) { + gpr_atm curr = gpr_atm_no_barrier_load(state); + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_ERROR, "lfev_set_shutdown: %p curr=%p err=%s", state, + (void *)curr, grpc_error_string(shutdown_err)); + } + switch (curr) { + case CLOSURE_READY: + case CLOSURE_NOT_READY: + /* Need a full barrier here so that the initial load in notify_on + doesn't need a barrier */ + if (gpr_atm_full_cas(state, curr, new_state)) { + return true; /* early out */ + } + break; /* retry */ + + default: { + /* 'curr' is either a closure or the fd is already shutdown */ + + /* If fd is already shutdown, we are done */ + if ((curr & FD_SHUTDOWN_BIT) > 0) { + GRPC_ERROR_UNREF(shutdown_err); + return false; + } + + /* Fd is not shutdown. Schedule the closure and move the state to + shutdown state. + Needs an acquire to pair with setting the closure (and get a + happens-after on that edge), and a release to pair with anything + loading the shutdown state. */ + if (gpr_atm_full_cas(state, curr, new_state)) { + GRPC_CLOSURE_SCHED(exec_ctx, (grpc_closure *)curr, + GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( + "FD Shutdown", &shutdown_err, 1)); + return true; + } + + /* 'curr' was a closure but now changed to a different state. We will + have to retry */ + break; + } + } + } + + GPR_UNREACHABLE_CODE(return false); +} + +void grpc_lfev_set_ready(grpc_exec_ctx *exec_ctx, gpr_atm *state, + const char *variable) { + while (true) { + gpr_atm curr = gpr_atm_no_barrier_load(state); + + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_ERROR, "lfev_set_ready[%s]: %p curr=%p", variable, state, + (void *)curr); + } + + switch (curr) { + case CLOSURE_READY: { + /* Already ready. We are done here */ + return; + } + + case CLOSURE_NOT_READY: { + /* No barrier required as we're transitioning to a state that does not + involve a closure */ + if (gpr_atm_no_barrier_cas(state, CLOSURE_NOT_READY, CLOSURE_READY)) { + return; /* early out */ + } + break; /* retry */ + } + + default: { + /* 'curr' is either a closure or the fd is shutdown */ + if ((curr & FD_SHUTDOWN_BIT) > 0) { + /* The fd is shutdown. Do nothing */ + return; + } + /* Full cas: acquire pairs with this cas' release in the event of a + spurious set_ready; release pairs with this or the acquire in + notify_on (or set_shutdown) */ + else if (gpr_atm_full_cas(state, curr, CLOSURE_NOT_READY)) { + GRPC_CLOSURE_SCHED(exec_ctx, (grpc_closure *)curr, GRPC_ERROR_NONE); + return; + } + /* else the state changed again (only possible by either a racing + set_ready or set_shutdown functions. In both these cases, the closure + would have been scheduled for execution. So we are done here */ + return; + } + } + } +} diff --git a/Sources/CgRPC/src/core/lib/iomgr/lockfree_event.h b/Sources/CgRPC/src/core/lib/iomgr/lockfree_event.h new file mode 100644 index 000000000..6a14a0f3b --- /dev/null +++ b/Sources/CgRPC/src/core/lib/iomgr/lockfree_event.h @@ -0,0 +1,40 @@ +/* + * + * Copyright 2017 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 GRPC_CORE_LIB_IOMGR_LOCKFREE_EVENT_H +#define GRPC_CORE_LIB_IOMGR_LOCKFREE_EVENT_H + +/* Lock free event notification for file descriptors */ + +#include + +#include "src/core/lib/iomgr/exec_ctx.h" + +void grpc_lfev_init(gpr_atm *state); +void grpc_lfev_destroy(gpr_atm *state); +bool grpc_lfev_is_shutdown(gpr_atm *state); + +void grpc_lfev_notify_on(grpc_exec_ctx *exec_ctx, gpr_atm *state, + grpc_closure *closure, const char *variable); +/* Returns true on first successful shutdown */ +bool grpc_lfev_set_shutdown(grpc_exec_ctx *exec_ctx, gpr_atm *state, + grpc_error *shutdown_err); +void grpc_lfev_set_ready(grpc_exec_ctx *exec_ctx, gpr_atm *state, + const char *variable); + +#endif /* GRPC_CORE_LIB_IOMGR_LOCKFREE_EVENT_H */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/nameser.h b/Sources/CgRPC/src/core/lib/iomgr/nameser.h new file mode 100644 index 000000000..daed6de51 --- /dev/null +++ b/Sources/CgRPC/src/core/lib/iomgr/nameser.h @@ -0,0 +1,104 @@ +/* + * + * Copyright 2017 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 GRPC_CORE_LIB_IOMGR_NAMESER_H +#define GRPC_CORE_LIB_IOMGR_NAMESER_H + +#include "src/core/lib/iomgr/port.h" + +#ifdef GRPC_HAVE_ARPA_NAMESER + +#include + +#else /* GRPC_HAVE_ARPA_NAMESER */ + +typedef enum __ns_class { + ns_c_invalid = 0, /* Cookie. */ + ns_c_in = 1, /* Internet. */ + ns_c_2 = 2, /* unallocated/unsupported. */ + ns_c_chaos = 3, /* MIT Chaos-net. */ + ns_c_hs = 4, /* MIT Hesiod. */ + /* Query class values which do not appear in resource records */ + ns_c_none = 254, /* for prereq. sections in update requests */ + ns_c_any = 255, /* Wildcard match. */ + ns_c_max = 65536 +} ns_class; + +typedef enum __ns_type { + ns_t_invalid = 0, /* Cookie. */ + ns_t_a = 1, /* Host address. */ + ns_t_ns = 2, /* Authoritative server. */ + ns_t_md = 3, /* Mail destination. */ + ns_t_mf = 4, /* Mail forwarder. */ + ns_t_cname = 5, /* Canonical name. */ + ns_t_soa = 6, /* Start of authority zone. */ + ns_t_mb = 7, /* Mailbox domain name. */ + ns_t_mg = 8, /* Mail group member. */ + ns_t_mr = 9, /* Mail rename name. */ + ns_t_null = 10, /* Null resource record. */ + ns_t_wks = 11, /* Well known service. */ + ns_t_ptr = 12, /* Domain name pointer. */ + ns_t_hinfo = 13, /* Host information. */ + ns_t_minfo = 14, /* Mailbox information. */ + ns_t_mx = 15, /* Mail routing information. */ + ns_t_txt = 16, /* Text strings. */ + ns_t_rp = 17, /* Responsible person. */ + ns_t_afsdb = 18, /* AFS cell database. */ + ns_t_x25 = 19, /* X_25 calling address. */ + ns_t_isdn = 20, /* ISDN calling address. */ + ns_t_rt = 21, /* Router. */ + ns_t_nsap = 22, /* NSAP address. */ + ns_t_nsap_ptr = 23, /* Reverse NSAP lookup (deprecated). */ + ns_t_sig = 24, /* Security signature. */ + ns_t_key = 25, /* Security key. */ + ns_t_px = 26, /* X.400 mail mapping. */ + ns_t_gpos = 27, /* Geographical position (withdrawn). */ + ns_t_aaaa = 28, /* Ip6 Address. */ + ns_t_loc = 29, /* Location Information. */ + ns_t_nxt = 30, /* Next domain (security). */ + ns_t_eid = 31, /* Endpoint identifier. */ + ns_t_nimloc = 32, /* Nimrod Locator. */ + ns_t_srv = 33, /* Server Selection. */ + ns_t_atma = 34, /* ATM Address */ + ns_t_naptr = 35, /* Naming Authority PoinTeR */ + ns_t_kx = 36, /* Key Exchange */ + ns_t_cert = 37, /* Certification record */ + ns_t_a6 = 38, /* IPv6 address (deprecates AAAA) */ + ns_t_dname = 39, /* Non-terminal DNAME (for IPv6) */ + ns_t_sink = 40, /* Kitchen sink (experimentatl) */ + ns_t_opt = 41, /* EDNS0 option (meta-RR) */ + ns_t_apl = 42, /* Address prefix list (RFC3123) */ + ns_t_ds = 43, /* Delegation Signer (RFC4034) */ + ns_t_sshfp = 44, /* SSH Key Fingerprint (RFC4255) */ + ns_t_rrsig = 46, /* Resource Record Signature (RFC4034) */ + ns_t_nsec = 47, /* Next Secure (RFC4034) */ + ns_t_dnskey = 48, /* DNS Public Key (RFC4034) */ + ns_t_tkey = 249, /* Transaction key */ + ns_t_tsig = 250, /* Transaction signature. */ + ns_t_ixfr = 251, /* Incremental zone transfer. */ + ns_t_axfr = 252, /* Transfer zone of authority. */ + ns_t_mailb = 253, /* Transfer mailbox records. */ + ns_t_maila = 254, /* Transfer mail agent records. */ + ns_t_any = 255, /* Wildcard match. */ + ns_t_zxfr = 256, /* BIND-specific, nonstandard. */ + ns_t_max = 65536 +} ns_type; + +#endif /* GRPC_HAVE_ARPA_NAMESER */ + +#endif /* GRPC_CORE_LIB_IOMGR_NAMESER_H */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/network_status_tracker.c b/Sources/CgRPC/src/core/lib/iomgr/network_status_tracker.c index a5ca9ed2c..4e5c1d540 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/network_status_tracker.c +++ b/Sources/CgRPC/src/core/lib/iomgr/network_status_tracker.c @@ -1,124 +1,33 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 -#include #include "src/core/lib/iomgr/endpoint.h" -typedef struct endpoint_ll_node { - grpc_endpoint *ep; - struct endpoint_ll_node *next; -} endpoint_ll_node; - -static endpoint_ll_node *head = NULL; -static gpr_mu g_endpoint_mutex; - -void grpc_network_status_shutdown(void) { - if (head != NULL) { - gpr_log(GPR_ERROR, - "Memory leaked as not all network endpoints were shut down"); - } - gpr_mu_destroy(&g_endpoint_mutex); -} +void grpc_network_status_shutdown(void) {} void grpc_network_status_init(void) { - gpr_mu_init(&g_endpoint_mutex); // TODO(makarandd): Install callback with OS to monitor network status. } -void grpc_destroy_network_status_monitor() { - for (endpoint_ll_node *curr = head; curr != NULL;) { - endpoint_ll_node *next = curr->next; - gpr_free(curr); - curr = next; - } - gpr_mu_destroy(&g_endpoint_mutex); -} - -void grpc_network_status_register_endpoint(grpc_endpoint *ep) { - gpr_mu_lock(&g_endpoint_mutex); - if (head == NULL) { - head = (endpoint_ll_node *)gpr_malloc(sizeof(endpoint_ll_node)); - head->ep = ep; - head->next = NULL; - } else { - endpoint_ll_node *prev_head = head; - head = (endpoint_ll_node *)gpr_malloc(sizeof(endpoint_ll_node)); - head->ep = ep; - head->next = prev_head; - } - gpr_mu_unlock(&g_endpoint_mutex); -} +void grpc_destroy_network_status_monitor() {} -void grpc_network_status_unregister_endpoint(grpc_endpoint *ep) { - gpr_mu_lock(&g_endpoint_mutex); - GPR_ASSERT(head); - bool found = false; - endpoint_ll_node *prev = head; - // if we're unregistering the head, just move head to the next - if (ep == head->ep) { - head = head->next; - gpr_free(prev); - found = true; - } else { - for (endpoint_ll_node *curr = head->next; curr != NULL; curr = curr->next) { - if (ep == curr->ep) { - prev->next = curr->next; - gpr_free(curr); - found = true; - break; - } - prev = curr; - } - } - gpr_mu_unlock(&g_endpoint_mutex); - GPR_ASSERT(found); -} +void grpc_network_status_register_endpoint(grpc_endpoint *ep) { (void)ep; } -// Walk the linked-list from head and execute shutdown. It is possible that -// other threads might be in the process of shutdown as well, but that has -// no side effect since endpoint shutdown is idempotent. -void grpc_network_status_shutdown_all_endpoints() { - gpr_mu_lock(&g_endpoint_mutex); - if (head == NULL) { - gpr_mu_unlock(&g_endpoint_mutex); - return; - } - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; +void grpc_network_status_unregister_endpoint(grpc_endpoint *ep) { (void)ep; } - for (endpoint_ll_node *curr = head; curr != NULL; curr = curr->next) { - curr->ep->vtable->shutdown(&exec_ctx, curr->ep); - } - gpr_mu_unlock(&g_endpoint_mutex); - grpc_exec_ctx_finish(&exec_ctx); -} +void grpc_network_status_shutdown_all_endpoints() {} diff --git a/Sources/CgRPC/src/core/lib/iomgr/network_status_tracker.h b/Sources/CgRPC/src/core/lib/iomgr/network_status_tracker.h index 67cb645f4..c0295c1f7 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/network_status_tracker.h +++ b/Sources/CgRPC/src/core/lib/iomgr/network_status_tracker.h @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/polling_entity.c b/Sources/CgRPC/src/core/lib/iomgr/polling_entity.c index d1686aa12..74d8794af 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/polling_entity.c +++ b/Sources/CgRPC/src/core/lib/iomgr/polling_entity.c @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/polling_entity.h b/Sources/CgRPC/src/core/lib/iomgr/polling_entity.h index e81531053..971fd88b4 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/polling_entity.h +++ b/Sources/CgRPC/src/core/lib/iomgr/polling_entity.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -38,9 +23,8 @@ #include "src/core/lib/iomgr/pollset_set.h" /* A grpc_polling_entity is a pollset-or-pollset_set container. It allows - * functions that - * accept a pollset XOR a pollset_set to do so through an abstract interface. - * No ownership is taken. */ + * functions that accept a pollset XOR a pollset_set to do so through an + * abstract interface. No ownership is taken. */ typedef struct grpc_polling_entity { union { @@ -64,18 +48,14 @@ grpc_pollset_set *grpc_polling_entity_pollset_set(grpc_polling_entity *pollent); bool grpc_polling_entity_is_empty(const grpc_polling_entity *pollent); /** Add the pollset or pollset_set in \a pollent to the destination pollset_set - * \a - * pss_dst */ + * \a * pss_dst */ void grpc_polling_entity_add_to_pollset_set(grpc_exec_ctx *exec_ctx, grpc_polling_entity *pollent, grpc_pollset_set *pss_dst); /** Delete the pollset or pollset_set in \a pollent from the destination - * pollset_set \a - * pss_dst */ + * pollset_set \a * pss_dst */ void grpc_polling_entity_del_from_pollset_set(grpc_exec_ctx *exec_ctx, grpc_polling_entity *pollent, grpc_pollset_set *pss_dst); -/* pollset_set specific */ - #endif /* GRPC_CORE_LIB_IOMGR_POLLING_ENTITY_H */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/pollset.h b/Sources/CgRPC/src/core/lib/iomgr/pollset.h index 8d9edc840..a609a3877 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/pollset.h +++ b/Sources/CgRPC/src/core/lib/iomgr/pollset.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -40,7 +25,9 @@ #include "src/core/lib/iomgr/exec_ctx.h" -#define GRPC_POLLSET_KICK_BROADCAST ((grpc_pollset_worker *)1) +#ifndef NDEBUG +extern grpc_tracer_flag grpc_trace_fd_refcount; +#endif /* A grpc_pollset is a set of file descriptors that a higher level item is interested in. For example: @@ -53,15 +40,13 @@ typedef struct grpc_pollset grpc_pollset; typedef struct grpc_pollset_worker grpc_pollset_worker; size_t grpc_pollset_size(void); +/* Initialize a pollset: assumes *pollset contains all zeros */ void grpc_pollset_init(grpc_pollset *pollset, gpr_mu **mu); /* Begin shutting down the pollset, and call closure when done. * pollset's mutex must be held */ void grpc_pollset_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, grpc_closure *closure); -/** Reset the pollset to its initial state (perhaps with some cached objects); - * must have been previously shutdown */ -void grpc_pollset_reset(grpc_pollset *pollset); -void grpc_pollset_destroy(grpc_pollset *pollset); +void grpc_pollset_destroy(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset); /* Do some work on a pollset. May involve invoking asynchronous callbacks, or actually polling file @@ -77,6 +62,10 @@ void grpc_pollset_destroy(grpc_pollset *pollset); and it is guaranteed that it will not be released by grpc_pollset_work AFTER worker has been destroyed. + It's legal for worker to be NULL: in that case, this specific thread can not + be directly woken with a kick, but maybe be indirectly (with a kick against + the pollset as a whole). + Tries not to block past deadline. May call grpc_closure_list_run on grpc_closure_list, without holding the pollset @@ -86,8 +75,7 @@ grpc_error *grpc_pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, gpr_timespec deadline) GRPC_MUST_USE_RESULT; /* Break one polling thread out of polling work for this pollset. - If specific_worker is GRPC_POLLSET_KICK_BROADCAST, kick ALL the workers. - Otherwise, if specific_worker is non-NULL, then kick that worker. */ + If specific_worker is non-NULL, then kick that worker. */ grpc_error *grpc_pollset_kick(grpc_pollset *pollset, grpc_pollset_worker *specific_worker) GRPC_MUST_USE_RESULT; diff --git a/Sources/CgRPC/src/core/lib/iomgr/pollset_set.h b/Sources/CgRPC/src/core/lib/iomgr/pollset_set.h index 34bb728c4..29c0f0356 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/pollset_set.h +++ b/Sources/CgRPC/src/core/lib/iomgr/pollset_set.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -44,7 +29,8 @@ typedef struct grpc_pollset_set grpc_pollset_set; grpc_pollset_set *grpc_pollset_set_create(void); -void grpc_pollset_set_destroy(grpc_pollset_set *pollset_set); +void grpc_pollset_set_destroy(grpc_exec_ctx *exec_ctx, + grpc_pollset_set *pollset_set); void grpc_pollset_set_add_pollset(grpc_exec_ctx *exec_ctx, grpc_pollset_set *pollset_set, grpc_pollset *pollset); diff --git a/Sources/CgRPC/src/core/lib/iomgr/pollset_set_uv.c b/Sources/CgRPC/src/core/lib/iomgr/pollset_set_uv.c index e5ef8b29e..90186edbb 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/pollset_set_uv.c +++ b/Sources/CgRPC/src/core/lib/iomgr/pollset_set_uv.c @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -41,7 +26,8 @@ grpc_pollset_set* grpc_pollset_set_create(void) { return (grpc_pollset_set*)((intptr_t)0xdeafbeef); } -void grpc_pollset_set_destroy(grpc_pollset_set* pollset_set) {} +void grpc_pollset_set_destroy(grpc_exec_ctx* exec_ctx, + grpc_pollset_set* pollset_set) {} void grpc_pollset_set_add_pollset(grpc_exec_ctx* exec_ctx, grpc_pollset_set* pollset_set, diff --git a/Sources/CgRPC/src/core/lib/iomgr/pollset_set_windows.c b/Sources/CgRPC/src/core/lib/iomgr/pollset_set_windows.c index 645650db9..2105a47ad 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/pollset_set_windows.c +++ b/Sources/CgRPC/src/core/lib/iomgr/pollset_set_windows.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -42,7 +27,8 @@ grpc_pollset_set* grpc_pollset_set_create(void) { return (grpc_pollset_set*)((intptr_t)0xdeafbeef); } -void grpc_pollset_set_destroy(grpc_pollset_set* pollset_set) {} +void grpc_pollset_set_destroy(grpc_exec_ctx* exec_ctx, + grpc_pollset_set* pollset_set) {} void grpc_pollset_set_add_pollset(grpc_exec_ctx* exec_ctx, grpc_pollset_set* pollset_set, diff --git a/Sources/CgRPC/src/core/lib/iomgr/pollset_set_windows.h b/Sources/CgRPC/src/core/lib/iomgr/pollset_set_windows.h index 0356749b1..1173f760a 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/pollset_set_windows.h +++ b/Sources/CgRPC/src/core/lib/iomgr/pollset_set_windows.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/pollset_uv.c b/Sources/CgRPC/src/core/lib/iomgr/pollset_uv.c index 3a74b842b..a79fe89d3 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/pollset_uv.c +++ b/Sources/CgRPC/src/core/lib/iomgr/pollset_uv.c @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -39,12 +24,21 @@ #include +#include #include #include +#include "src/core/lib/iomgr/iomgr_uv.h" #include "src/core/lib/iomgr/pollset.h" #include "src/core/lib/iomgr/pollset_uv.h" +#include "src/core/lib/debug/trace.h" + +#ifndef NDEBUG +grpc_tracer_flag grpc_trace_fd_refcount = + GRPC_TRACER_INITIALIZER(false, "fd_refcount"); +#endif + struct grpc_pollset { uv_timer_t timer; int shutting_down; @@ -57,36 +51,59 @@ int grpc_pollset_work_run_loop; gpr_mu grpc_polling_mu; +/* This is used solely to kick the uv loop, by setting a callback to be run + immediately in the next loop iteration. + Note: In the future, if there is a bug that involves missing wakeups in the + future, try adding a uv_async_t to kick the loop differently */ +uv_timer_t *dummy_uv_handle; + size_t grpc_pollset_size() { return sizeof(grpc_pollset); } +void dummy_timer_cb(uv_timer_t *handle) {} + +void dummy_handle_close_cb(uv_handle_t *handle) { gpr_free(handle); } + void grpc_pollset_global_init(void) { gpr_mu_init(&grpc_polling_mu); + dummy_uv_handle = gpr_malloc(sizeof(uv_timer_t)); + uv_timer_init(uv_default_loop(), dummy_uv_handle); grpc_pollset_work_run_loop = 1; } -void grpc_pollset_global_shutdown(void) { gpr_mu_destroy(&grpc_polling_mu); } +void grpc_pollset_global_shutdown(void) { + GRPC_UV_ASSERT_SAME_THREAD(); + gpr_mu_destroy(&grpc_polling_mu); + uv_close((uv_handle_t *)dummy_uv_handle, dummy_handle_close_cb); +} + +static void timer_run_cb(uv_timer_t *timer) {} + +static void timer_close_cb(uv_handle_t *handle) { handle->data = (void *)1; } void grpc_pollset_init(grpc_pollset *pollset, gpr_mu **mu) { + GRPC_UV_ASSERT_SAME_THREAD(); *mu = &grpc_polling_mu; - memset(pollset, 0, sizeof(grpc_pollset)); uv_timer_init(uv_default_loop(), &pollset->timer); pollset->shutting_down = 0; } -static void timer_close_cb(uv_handle_t *handle) { handle->data = (void *)1; } - void grpc_pollset_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, grpc_closure *closure) { GPR_ASSERT(!pollset->shutting_down); + GRPC_UV_ASSERT_SAME_THREAD(); pollset->shutting_down = 1; if (grpc_pollset_work_run_loop) { // Drain any pending UV callbacks without blocking uv_run(uv_default_loop(), UV_RUN_NOWAIT); + } else { + // kick the loop once + uv_timer_start(dummy_uv_handle, dummy_timer_cb, 0, 0); } - grpc_exec_ctx_sched(exec_ctx, closure, GRPC_ERROR_NONE, NULL); + GRPC_CLOSURE_SCHED(exec_ctx, closure, GRPC_ERROR_NONE); } -void grpc_pollset_destroy(grpc_pollset *pollset) { +void grpc_pollset_destroy(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset) { + GRPC_UV_ASSERT_SAME_THREAD(); uv_close((uv_handle_t *)&pollset->timer, timer_close_cb); // timer.data is a boolean indicating that the timer has finished closing pollset->timer.data = (void *)0; @@ -97,17 +114,11 @@ void grpc_pollset_destroy(grpc_pollset *pollset) { } } -void grpc_pollset_reset(grpc_pollset *pollset) { - GPR_ASSERT(pollset->shutting_down); - pollset->shutting_down = 0; -} - -static void timer_run_cb(uv_timer_t *timer) {} - grpc_error *grpc_pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, grpc_pollset_worker **worker_hdl, gpr_timespec now, gpr_timespec deadline) { uint64_t timeout; + GRPC_UV_ASSERT_SAME_THREAD(); gpr_mu_unlock(&grpc_polling_mu); if (grpc_pollset_work_run_loop) { if (gpr_time_cmp(deadline, now) >= 0) { @@ -136,6 +147,8 @@ grpc_error *grpc_pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, grpc_error *grpc_pollset_kick(grpc_pollset *pollset, grpc_pollset_worker *specific_worker) { + GRPC_UV_ASSERT_SAME_THREAD(); + uv_timer_start(dummy_uv_handle, dummy_timer_cb, 0, 0); return GRPC_ERROR_NONE; } diff --git a/Sources/CgRPC/src/core/lib/iomgr/pollset_uv.h b/Sources/CgRPC/src/core/lib/iomgr/pollset_uv.h index 0715eb429..566c110ca 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/pollset_uv.h +++ b/Sources/CgRPC/src/core/lib/iomgr/pollset_uv.h @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/pollset_windows.c b/Sources/CgRPC/src/core/lib/iomgr/pollset_windows.c index 5540303e4..ea017a605 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/pollset_windows.c +++ b/Sources/CgRPC/src/core/lib/iomgr/pollset_windows.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -43,6 +28,13 @@ #include "src/core/lib/iomgr/pollset.h" #include "src/core/lib/iomgr/pollset_windows.h" +#define GRPC_POLLSET_KICK_BROADCAST ((grpc_pollset_worker *)1) + +#ifndef NDEBUG +grpc_tracer_flag grpc_trace_fd_refcount = + GRPC_TRACER_INITIALIZER(false, "fd_refcount"); +#endif + gpr_mu grpc_polling_mu; static grpc_pollset_worker *g_active_poller; static grpc_pollset_worker g_global_root_worker; @@ -98,7 +90,6 @@ size_t grpc_pollset_size(void) { return sizeof(grpc_pollset); } void grpc_pollset_init(grpc_pollset *pollset, gpr_mu **mu) { *mu = &grpc_polling_mu; - memset(pollset, 0, sizeof(*pollset)); pollset->root_worker.links[GRPC_POLLSET_WORKER_LINK_POLLSET].next = pollset->root_worker.links[GRPC_POLLSET_WORKER_LINK_POLLSET].prev = &pollset->root_worker; @@ -109,29 +100,19 @@ void grpc_pollset_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, pollset->shutting_down = 1; grpc_pollset_kick(pollset, GRPC_POLLSET_KICK_BROADCAST); if (!pollset->is_iocp_worker) { - grpc_exec_ctx_sched(exec_ctx, closure, GRPC_ERROR_NONE, NULL); + GRPC_CLOSURE_SCHED(exec_ctx, closure, GRPC_ERROR_NONE); } else { pollset->on_shutdown = closure; } } -void grpc_pollset_destroy(grpc_pollset *pollset) {} - -void grpc_pollset_reset(grpc_pollset *pollset) { - GPR_ASSERT(pollset->shutting_down); - GPR_ASSERT( - !has_workers(&pollset->root_worker, GRPC_POLLSET_WORKER_LINK_POLLSET)); - pollset->shutting_down = 0; - pollset->is_iocp_worker = 0; - pollset->kicked_without_pollers = 0; - pollset->on_shutdown = NULL; -} +void grpc_pollset_destroy(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset) {} grpc_error *grpc_pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, grpc_pollset_worker **worker_hdl, gpr_timespec now, gpr_timespec deadline) { grpc_pollset_worker worker; - *worker_hdl = &worker; + if (worker_hdl) *worker_hdl = &worker; int added_worker = 0; worker.links[GRPC_POLLSET_WORKER_LINK_POLLSET].next = @@ -167,8 +148,7 @@ grpc_error *grpc_pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, } if (pollset->shutting_down && pollset->on_shutdown != NULL) { - grpc_exec_ctx_sched(exec_ctx, pollset->on_shutdown, GRPC_ERROR_NONE, - NULL); + GRPC_CLOSURE_SCHED(exec_ctx, pollset->on_shutdown, GRPC_ERROR_NONE); pollset->on_shutdown = NULL; } goto done; @@ -197,7 +177,7 @@ grpc_error *grpc_pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, remove_worker(&worker, GRPC_POLLSET_WORKER_LINK_POLLSET); } gpr_cv_destroy(&worker.cv); - *worker_hdl = NULL; + if (worker_hdl) *worker_hdl = NULL; return GRPC_ERROR_NONE; } @@ -239,6 +219,4 @@ grpc_error *grpc_pollset_kick(grpc_pollset *p, return GRPC_ERROR_NONE; } -void grpc_kick_poller(void) { grpc_iocp_kick(); } - #endif /* GRPC_WINSOCK_SOCKET */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/pollset_windows.h b/Sources/CgRPC/src/core/lib/iomgr/pollset_windows.h index 2642013af..71878c3d3 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/pollset_windows.h +++ b/Sources/CgRPC/src/core/lib/iomgr/pollset_windows.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/port.h b/Sources/CgRPC/src/core/lib/iomgr/port.h index f1897bb91..42033d0ba 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/port.h +++ b/Sources/CgRPC/src/core/lib/iomgr/port.h @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -39,6 +24,8 @@ #if defined(GRPC_UV) // Do nothing #elif defined(GPR_MANYLINUX1) +#define GRPC_HAVE_ARPA_NAMESER 1 +#define GRPC_HAVE_IFADDRS 1 #define GRPC_HAVE_IPV6_RECVPKTINFO 1 #define GRPC_HAVE_IP_PKTINFO 1 #define GRPC_HAVE_MSG_NOSIGNAL 1 @@ -65,11 +52,14 @@ #define GRPC_POSIX_WAKEUP_FD 1 #define GRPC_TIMER_USE_GENERIC 1 #elif defined(GPR_LINUX) +#define GRPC_HAVE_ARPA_NAMESER 1 +#define GRPC_HAVE_IFADDRS 1 #define GRPC_HAVE_IPV6_RECVPKTINFO 1 #define GRPC_HAVE_IP_PKTINFO 1 #define GRPC_HAVE_MSG_NOSIGNAL 1 #define GRPC_HAVE_UNIX_SOCKET 1 #define GRPC_LINUX_MULTIPOLL_WITH_EPOLL 1 +#define GRPC_POSIX_HOST_NAME_MAX 1 #define GRPC_POSIX_SOCKET 1 #define GRPC_POSIX_SOCKETADDR 1 #define GRPC_POSIX_WAKEUP_FD 1 @@ -83,6 +73,11 @@ #define GRPC_LINUX_SOCKETUTILS 1 #endif #endif +#ifndef __GLIBC__ +#define GRPC_LINUX_EPOLL 1 +#define GRPC_LINUX_EVENTFD 1 +#define GRPC_MSG_IOVLEN_TYPE int +#endif #ifndef GRPC_LINUX_EVENTFD #define GRPC_POSIX_NO_SPECIAL_WAKEUP_FD 1 #endif @@ -90,6 +85,8 @@ #define GRPC_POSIX_SOCKETUTILS #endif #elif defined(GPR_APPLE) +#define GRPC_HAVE_ARPA_NAMESER 1 +#define GRPC_HAVE_IFADDRS 1 #define GRPC_HAVE_SO_NOSIGPIPE 1 #define GRPC_HAVE_UNIX_SOCKET 1 #define GRPC_MSG_IOVLEN_TYPE int @@ -97,9 +94,12 @@ #define GRPC_POSIX_SOCKET 1 #define GRPC_POSIX_SOCKETADDR 1 #define GRPC_POSIX_SOCKETUTILS 1 +#define GRPC_POSIX_SYSCONF 1 #define GRPC_POSIX_WAKEUP_FD 1 #define GRPC_TIMER_USE_GENERIC 1 #elif defined(GPR_FREEBSD) +#define GRPC_HAVE_ARPA_NAMESER 1 +#define GRPC_HAVE_IFADDRS 1 #define GRPC_HAVE_IPV6_RECVPKTINFO 1 #define GRPC_HAVE_SO_NOSIGPIPE 1 #define GRPC_HAVE_UNIX_SOCKET 1 @@ -110,6 +110,7 @@ #define GRPC_POSIX_WAKEUP_FD 1 #define GRPC_TIMER_USE_GENERIC 1 #elif defined(GPR_NACL) +#define GRPC_HAVE_ARPA_NAMESER 1 #define GRPC_POSIX_NO_SPECIAL_WAKEUP_FD 1 #define GRPC_POSIX_SOCKET 1 #define GRPC_POSIX_SOCKETADDR 1 @@ -126,4 +127,11 @@ #error Must define exactly one of GRPC_POSIX_SOCKET, GRPC_WINSOCK_SOCKET, GPR_CUSTOM_SOCKET #endif +#if defined(GRPC_POSIX_HOST_NAME_MAX) && defined(GRPC_POSIX_SYSCONF) +#error "Cannot define both GRPC_POSIX_HOST_NAME_MAX and GRPC_POSIX_SYSCONF" +#endif +#if !defined(GRPC_POSIX_HOST_NAME_MAX) && !defined(GRPC_POSIX_SYSCONF) +#define GRPC_GETHOSTNAME_FALLBACK 1 +#endif + #endif /* GRPC_CORE_LIB_IOMGR_PORT_H */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/resolve_address.h b/Sources/CgRPC/src/core/lib/iomgr/resolve_address.h index e03d16fa4..fe1dd7857 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/resolve_address.h +++ b/Sources/CgRPC/src/core/lib/iomgr/resolve_address.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/resolve_address_posix.c b/Sources/CgRPC/src/core/lib/iomgr/resolve_address_posix.c index 821932e56..35dedc23d 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/resolve_address_posix.c +++ b/Sources/CgRPC/src/core/lib/iomgr/resolve_address_posix.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -73,14 +58,16 @@ static grpc_error *blocking_resolve_address_impl( /* parse name, splitting it into host and port parts */ gpr_split_host_port(name, &host, &port); if (host == NULL) { - err = grpc_error_set_str(GRPC_ERROR_CREATE("unparseable host:port"), - GRPC_ERROR_STR_TARGET_ADDRESS, name); + err = grpc_error_set_str( + GRPC_ERROR_CREATE_FROM_STATIC_STRING("unparseable host:port"), + GRPC_ERROR_STR_TARGET_ADDRESS, grpc_slice_from_copied_string(name)); goto done; } if (port == NULL) { if (default_port == NULL) { - err = grpc_error_set_str(GRPC_ERROR_CREATE("no port in name"), - GRPC_ERROR_STR_TARGET_ADDRESS, name); + err = grpc_error_set_str( + GRPC_ERROR_CREATE_FROM_STATIC_STRING("no port in name"), + GRPC_ERROR_STR_TARGET_ADDRESS, grpc_slice_from_copied_string(name)); goto done; } port = gpr_strdup(default_port); @@ -112,11 +99,15 @@ static grpc_error *blocking_resolve_address_impl( if (s != 0) { err = grpc_error_set_str( grpc_error_set_str( - grpc_error_set_str(grpc_error_set_int(GRPC_ERROR_CREATE("OS Error"), - GRPC_ERROR_INT_ERRNO, s), - GRPC_ERROR_STR_OS_ERROR, gai_strerror(s)), - GRPC_ERROR_STR_SYSCALL, "getaddrinfo"), - GRPC_ERROR_STR_TARGET_ADDRESS, name); + grpc_error_set_str( + grpc_error_set_int( + GRPC_ERROR_CREATE_FROM_STATIC_STRING("OS Error"), + GRPC_ERROR_INT_ERRNO, s), + GRPC_ERROR_STR_OS_ERROR, + grpc_slice_from_static_string(gai_strerror(s))), + GRPC_ERROR_STR_SYSCALL, + grpc_slice_from_static_string("getaddrinfo")), + GRPC_ERROR_STR_TARGET_ADDRESS, grpc_slice_from_copied_string(name)); goto done; } @@ -163,10 +154,9 @@ typedef struct { static void do_request_thread(grpc_exec_ctx *exec_ctx, void *rp, grpc_error *error) { request *r = rp; - grpc_exec_ctx_sched( + GRPC_CLOSURE_SCHED( exec_ctx, r->on_done, - grpc_blocking_resolve_address(r->name, r->default_port, r->addrs_out), - NULL); + grpc_blocking_resolve_address(r->name, r->default_port, r->addrs_out)); gpr_free(r->name); gpr_free(r->default_port); gpr_free(r); @@ -185,12 +175,13 @@ static void resolve_address_impl(grpc_exec_ctx *exec_ctx, const char *name, grpc_closure *on_done, grpc_resolved_addresses **addrs) { request *r = gpr_malloc(sizeof(request)); - grpc_closure_init(&r->request_closure, do_request_thread, r); + GRPC_CLOSURE_INIT(&r->request_closure, do_request_thread, r, + grpc_executor_scheduler); r->name = gpr_strdup(name); r->default_port = gpr_strdup(default_port); r->on_done = on_done; r->addrs_out = addrs; - grpc_executor_push(&r->request_closure, GRPC_ERROR_NONE); + GRPC_CLOSURE_SCHED(exec_ctx, &r->request_closure, GRPC_ERROR_NONE); } void (*grpc_resolve_address)( diff --git a/Sources/CgRPC/src/core/lib/iomgr/resolve_address_uv.c b/Sources/CgRPC/src/core/lib/iomgr/resolve_address_uv.c index 3269c4f09..2d438e8b4 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/resolve_address_uv.c +++ b/Sources/CgRPC/src/core/lib/iomgr/resolve_address_uv.c @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -40,10 +25,12 @@ #include #include #include +#include #include "src/core/lib/iomgr/closure.h" #include "src/core/lib/iomgr/error.h" #include "src/core/lib/iomgr/exec_ctx.h" +#include "src/core/lib/iomgr/iomgr_uv.h" #include "src/core/lib/iomgr/resolve_address.h" #include "src/core/lib/iomgr/sockaddr.h" #include "src/core/lib/iomgr/sockaddr_utils.h" @@ -54,8 +41,37 @@ typedef struct request { grpc_closure *on_done; grpc_resolved_addresses **addresses; struct addrinfo *hints; + char *host; + char *port; } request; +static int retry_named_port_failure(int status, request *r, + uv_getaddrinfo_cb getaddrinfo_cb) { + if (status != 0) { + // This loop is copied from resolve_address_posix.c + char *svc[][2] = {{"http", "80"}, {"https", "443"}}; + for (size_t i = 0; i < GPR_ARRAY_SIZE(svc); i++) { + if (strcmp(r->port, svc[i][0]) == 0) { + int retry_status; + uv_getaddrinfo_t *req = gpr_malloc(sizeof(uv_getaddrinfo_t)); + req->data = r; + r->port = gpr_strdup(svc[i][1]); + retry_status = uv_getaddrinfo(uv_default_loop(), req, getaddrinfo_cb, + r->host, r->port, r->hints); + if (retry_status < 0 || getaddrinfo_cb == NULL) { + // The callback will not be called + gpr_free(req); + } + return retry_status; + } + } + } + /* If this function calls uv_getaddrinfo, it will return that function's + return value. That function only returns numbers <=0, so we can safely + return 1 to indicate that we never retried */ + return 1; +} + static grpc_error *handle_addrinfo_result(int status, struct addrinfo *result, grpc_resolved_addresses **addresses) { struct addrinfo *resp; @@ -63,9 +79,10 @@ static grpc_error *handle_addrinfo_result(int status, struct addrinfo *result, if (status != 0) { grpc_error *error; *addresses = NULL; - error = GRPC_ERROR_CREATE("getaddrinfo failed"); + error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("getaddrinfo failed"); error = - grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR, uv_strerror(status)); + grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR, + grpc_slice_from_static_string(uv_strerror(status))); return error; } (*addresses) = gpr_malloc(sizeof(grpc_resolved_addresses)); @@ -97,13 +114,26 @@ static void getaddrinfo_callback(uv_getaddrinfo_t *req, int status, request *r = (request *)req->data; grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_error *error; + int retry_status; + char *port = r->port; + + gpr_free(req); + retry_status = retry_named_port_failure(status, r, getaddrinfo_callback); + if (retry_status == 0) { + /* The request is being retried. It is using its own port string, so we free + * the original one */ + gpr_free(port); + return; + } + /* Either no retry was attempted, or the retry failed. Either way, the + original error probably has more interesting information */ error = handle_addrinfo_result(status, res, r->addresses); - grpc_exec_ctx_sched(&exec_ctx, r->on_done, error, NULL); + GRPC_CLOSURE_SCHED(&exec_ctx, r->on_done, error); grpc_exec_ctx_finish(&exec_ctx); - gpr_free(r->hints); + gpr_free(r->host); + gpr_free(r->port); gpr_free(r); - gpr_free(req); uv_freeaddrinfo(res); } @@ -113,18 +143,19 @@ static grpc_error *try_split_host_port(const char *name, /* parse name, splitting it into host and port parts */ grpc_error *error; gpr_split_host_port(name, host, port); - if (host == NULL) { + if (*host == NULL) { char *msg; gpr_asprintf(&msg, "unparseable host:port: '%s'", name); - error = GRPC_ERROR_CREATE(msg); + error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg); gpr_free(msg); return error; } - if (port == NULL) { + if (*port == NULL) { + // TODO(murgatroid99): add tests for this case if (default_port == NULL) { char *msg; gpr_asprintf(&msg, "no port in name '%s'", name); - error = GRPC_ERROR_CREATE(msg); + error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg); gpr_free(msg); return error; } @@ -142,6 +173,9 @@ static grpc_error *blocking_resolve_address_impl( uv_getaddrinfo_t req; int s; grpc_error *err; + int retry_status; + + GRPC_UV_ASSERT_SAME_THREAD(); req.addrinfo = NULL; @@ -157,6 +191,12 @@ static grpc_error *blocking_resolve_address_impl( hints.ai_flags = AI_PASSIVE; /* for wildcard IP address */ s = uv_getaddrinfo(uv_default_loop(), &req, NULL, host, port, &hints); + request r = { + .addresses = addresses, .hints = &hints, .host = host, .port = port}; + retry_status = retry_named_port_failure(s, &r, NULL); + if (retry_status <= 0) { + s = retry_status; + } err = handle_addrinfo_result(s, req.addrinfo, addresses); done: @@ -184,21 +224,26 @@ static void resolve_address_impl(grpc_exec_ctx *exec_ctx, const char *name, grpc_pollset_set *interested_parties, grpc_closure *on_done, grpc_resolved_addresses **addrs) { - uv_getaddrinfo_t *req; - request *r; - struct addrinfo *hints; - char *host; - char *port; + uv_getaddrinfo_t *req = NULL; + request *r = NULL; + struct addrinfo *hints = NULL; + char *host = NULL; + char *port = NULL; grpc_error *err; int s; + GRPC_UV_ASSERT_SAME_THREAD(); err = try_split_host_port(name, default_port, &host, &port); if (err != GRPC_ERROR_NONE) { - grpc_exec_ctx_sched(exec_ctx, on_done, err, NULL); + GRPC_CLOSURE_SCHED(exec_ctx, on_done, err); + gpr_free(host); + gpr_free(port); return; } r = gpr_malloc(sizeof(request)); r->on_done = on_done; r->addresses = addrs; + r->host = host; + r->port = port; req = gpr_malloc(sizeof(uv_getaddrinfo_t)); req->data = r; @@ -215,12 +260,15 @@ static void resolve_address_impl(grpc_exec_ctx *exec_ctx, const char *name, if (s != 0) { *addrs = NULL; - err = GRPC_ERROR_CREATE("getaddrinfo failed"); - err = grpc_error_set_str(err, GRPC_ERROR_STR_OS_ERROR, uv_strerror(s)); - grpc_exec_ctx_sched(exec_ctx, on_done, err, NULL); + err = GRPC_ERROR_CREATE_FROM_STATIC_STRING("getaddrinfo failed"); + err = grpc_error_set_str(err, GRPC_ERROR_STR_OS_ERROR, + grpc_slice_from_static_string(uv_strerror(s))); + GRPC_CLOSURE_SCHED(exec_ctx, on_done, err); gpr_free(r); gpr_free(req); gpr_free(hints); + gpr_free(host); + gpr_free(port); } } diff --git a/Sources/CgRPC/src/core/lib/iomgr/resolve_address_windows.c b/Sources/CgRPC/src/core/lib/iomgr/resolve_address_windows.c index fada5ecbe..45cfd7248 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/resolve_address_windows.c +++ b/Sources/CgRPC/src/core/lib/iomgr/resolve_address_windows.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -78,7 +63,7 @@ static grpc_error *blocking_resolve_address_impl( if (host == NULL) { char *msg; gpr_asprintf(&msg, "unparseable host:port: '%s'", name); - error = GRPC_ERROR_CREATE(msg); + error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg); gpr_free(msg); goto done; } @@ -86,7 +71,7 @@ static grpc_error *blocking_resolve_address_impl( if (default_port == NULL) { char *msg; gpr_asprintf(&msg, "no port in name '%s'", name); - error = GRPC_ERROR_CREATE(msg); + error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg); gpr_free(msg); goto done; } @@ -154,7 +139,7 @@ static void do_request_thread(grpc_exec_ctx *exec_ctx, void *rp, } else { GRPC_ERROR_REF(error); } - grpc_exec_ctx_sched(exec_ctx, r->on_done, error, NULL); + GRPC_CLOSURE_SCHED(exec_ctx, r->on_done, error); gpr_free(r->name); gpr_free(r->default_port); gpr_free(r); @@ -173,12 +158,13 @@ static void resolve_address_impl(grpc_exec_ctx *exec_ctx, const char *name, grpc_closure *on_done, grpc_resolved_addresses **addresses) { request *r = gpr_malloc(sizeof(request)); - grpc_closure_init(&r->request_closure, do_request_thread, r); + GRPC_CLOSURE_INIT(&r->request_closure, do_request_thread, r, + grpc_executor_scheduler); r->name = gpr_strdup(name); r->default_port = gpr_strdup(default_port); r->on_done = on_done; r->addresses = addresses; - grpc_executor_push(&r->request_closure, GRPC_ERROR_NONE); + GRPC_CLOSURE_SCHED(exec_ctx, &r->request_closure, GRPC_ERROR_NONE); } void (*grpc_resolve_address)( diff --git a/Sources/CgRPC/src/core/lib/iomgr/resource_quota.c b/Sources/CgRPC/src/core/lib/iomgr/resource_quota.c index 213d29600..a31d9eef9 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/resource_quota.c +++ b/Sources/CgRPC/src/core/lib/iomgr/resource_quota.c @@ -1,38 +1,25 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 "src/core/lib/iomgr/resource_quota.h" +#include +#include #include #include @@ -42,7 +29,10 @@ #include "src/core/lib/iomgr/combiner.h" -int grpc_resource_quota_trace = 0; +grpc_tracer_flag grpc_resource_quota_trace = + GRPC_TRACER_INITIALIZER(false, "resource_quota"); + +#define MEMORY_USAGE_ESTIMATION_MAX 65536 /* Internal linked list pointers for a resource user */ typedef struct { @@ -126,15 +116,20 @@ struct grpc_resource_quota { /* refcount */ gpr_refcount refs; + /* estimate of current memory usage + scaled to the range [0..RESOURCE_USAGE_ESTIMATION_MAX] */ + gpr_atm memory_usage_estimation; + /* Master combiner lock: all activity on a quota executes under this combiner - * (so no mutex is needed for this data structure) - */ + * (so no mutex is needed for this data structure) */ grpc_combiner *combiner; /* Size of the resource quota */ int64_t size; /* Amount of free memory in the resource quota */ int64_t free_pool; + gpr_atm last_size; + /* Has rq_step been scheduled to occur? */ bool step_scheduled; /* Are we currently reclaiming memory */ @@ -257,17 +252,32 @@ static void rq_step(grpc_exec_ctx *exec_ctx, void *rq, grpc_error *error) { } done: - grpc_resource_quota_internal_unref(exec_ctx, resource_quota); + grpc_resource_quota_unref_internal(exec_ctx, resource_quota); } static void rq_step_sched(grpc_exec_ctx *exec_ctx, grpc_resource_quota *resource_quota) { if (resource_quota->step_scheduled) return; resource_quota->step_scheduled = true; - grpc_resource_quota_internal_ref(resource_quota); - grpc_combiner_execute_finally(exec_ctx, resource_quota->combiner, - &resource_quota->rq_step_closure, - GRPC_ERROR_NONE, false); + grpc_resource_quota_ref_internal(resource_quota); + GRPC_CLOSURE_SCHED(exec_ctx, &resource_quota->rq_step_closure, + GRPC_ERROR_NONE); +} + +/* update the atomically available resource estimate - use no barriers since + timeliness of delivery really doesn't matter much */ +static void rq_update_estimate(grpc_resource_quota *resource_quota) { + gpr_atm memory_usage_estimation = MEMORY_USAGE_ESTIMATION_MAX; + if (resource_quota->size != 0) { + memory_usage_estimation = + GPR_CLAMP((gpr_atm)((1.0 - + ((double)resource_quota->free_pool) / + ((double)resource_quota->size)) * + MEMORY_USAGE_ESTIMATION_MAX), + 0, MEMORY_USAGE_ESTIMATION_MAX); + } + gpr_atm_no_barrier_store(&resource_quota->memory_usage_estimation, + memory_usage_estimation); } /* returns true if all allocations are completed */ @@ -282,19 +292,21 @@ static bool rq_alloc(grpc_exec_ctx *exec_ctx, int64_t amt = -resource_user->free_pool; resource_user->free_pool = 0; resource_quota->free_pool -= amt; - if (grpc_resource_quota_trace) { + rq_update_estimate(resource_quota); + if (GRPC_TRACER_ON(grpc_resource_quota_trace)) { gpr_log(GPR_DEBUG, "RQ %s %s: grant alloc %" PRId64 " bytes; rq_free_pool -> %" PRId64, resource_quota->name, resource_user->name, amt, resource_quota->free_pool); } - } else if (grpc_resource_quota_trace && resource_user->free_pool >= 0) { + } else if (GRPC_TRACER_ON(grpc_resource_quota_trace) && + resource_user->free_pool >= 0) { gpr_log(GPR_DEBUG, "RQ %s %s: discard already satisfied alloc request", resource_quota->name, resource_user->name); } if (resource_user->free_pool >= 0) { resource_user->allocating = false; - grpc_exec_ctx_enqueue_list(exec_ctx, &resource_user->on_allocated, NULL); + GRPC_CLOSURE_LIST_SCHED(exec_ctx, &resource_user->on_allocated); gpr_mu_unlock(&resource_user->mu); } else { rulist_add_head(resource_user, GRPC_RULIST_AWAITING_ALLOCATION); @@ -316,7 +328,8 @@ static bool rq_reclaim_from_per_user_free_pool( int64_t amt = resource_user->free_pool; resource_user->free_pool = 0; resource_quota->free_pool += amt; - if (grpc_resource_quota_trace) { + rq_update_estimate(resource_quota); + if (GRPC_TRACER_ON(grpc_resource_quota_trace)) { gpr_log(GPR_DEBUG, "RQ %s %s: reclaim_from_per_user_free_pool %" PRId64 " bytes; rq_free_pool -> %" PRId64, resource_quota->name, resource_user->name, amt, @@ -339,19 +352,19 @@ static bool rq_reclaim(grpc_exec_ctx *exec_ctx, : GRPC_RULIST_RECLAIMER_BENIGN; grpc_resource_user *resource_user = rulist_pop_head(resource_quota, list); if (resource_user == NULL) return false; - if (grpc_resource_quota_trace) { + if (GRPC_TRACER_ON(grpc_resource_quota_trace)) { gpr_log(GPR_DEBUG, "RQ %s %s: initiate %s reclamation", resource_quota->name, resource_user->name, destructive ? "destructive" : "benign"); } resource_quota->reclaiming = true; - grpc_resource_quota_internal_ref(resource_quota); + grpc_resource_quota_ref_internal(resource_quota); grpc_closure *c = resource_user->reclaimers[destructive]; GPR_ASSERT(c); resource_quota->debug_only_last_reclaimer_resource_user = resource_user; resource_quota->debug_only_last_initiated_reclaimer = c; resource_user->reclaimers[destructive] = NULL; - grpc_closure_run(exec_ctx, c, GRPC_ERROR_NONE); + GRPC_CLOSURE_RUN(exec_ctx, c, GRPC_ERROR_NONE); return true; } @@ -371,30 +384,23 @@ static void ru_slice_ref(void *p) { gpr_ref(&rc->refs); } -static void ru_slice_unref(void *p) { +static void ru_slice_unref(grpc_exec_ctx *exec_ctx, void *p) { ru_slice_refcount *rc = p; if (gpr_unref(&rc->refs)) { - /* TODO(ctiller): this is dangerous, but I think safe for now: - we have no guarantee here that we're at a safe point for creating an - execution context, but we have no way of writing this code otherwise. - In the future: consider lifting grpc_slice to grpc, and offering an - internal_{ref,unref} pair that is execution context aware. - Alternatively, - make exec_ctx be thread local and 'do the right thing' (whatever that - is) - if NULL */ - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - grpc_resource_user_free(&exec_ctx, rc->resource_user, rc->size); - grpc_exec_ctx_finish(&exec_ctx); + grpc_resource_user_free(exec_ctx, rc->resource_user, rc->size); gpr_free(rc); } } +static const grpc_slice_refcount_vtable ru_slice_vtable = { + ru_slice_ref, ru_slice_unref, grpc_slice_default_eq_impl, + grpc_slice_default_hash_impl}; + static grpc_slice ru_slice_create(grpc_resource_user *resource_user, size_t size) { ru_slice_refcount *rc = gpr_malloc(sizeof(ru_slice_refcount) + size); - rc->base.ref = ru_slice_ref; - rc->base.unref = ru_slice_unref; + rc->base.vtable = &ru_slice_vtable; + rc->base.sub_refcount = &rc->base; gpr_ref_init(&rc->refs, 1); rc->resource_user = resource_user; rc->size = size; @@ -439,7 +445,7 @@ static bool ru_post_reclaimer(grpc_exec_ctx *exec_ctx, resource_user->new_reclaimers[destructive] = NULL; GPR_ASSERT(resource_user->reclaimers[destructive] == NULL); if (gpr_atm_acq_load(&resource_user->shutdown) > 0) { - grpc_exec_ctx_sched(exec_ctx, closure, GRPC_ERROR_CANCELLED, NULL); + GRPC_CLOSURE_SCHED(exec_ctx, closure, GRPC_ERROR_CANCELLED); return false; } resource_user->reclaimers[destructive] = closure; @@ -480,10 +486,10 @@ static void ru_post_destructive_reclaimer(grpc_exec_ctx *exec_ctx, void *ru, static void ru_shutdown(grpc_exec_ctx *exec_ctx, void *ru, grpc_error *error) { grpc_resource_user *resource_user = ru; - grpc_exec_ctx_sched(exec_ctx, resource_user->reclaimers[0], - GRPC_ERROR_CANCELLED, NULL); - grpc_exec_ctx_sched(exec_ctx, resource_user->reclaimers[1], - GRPC_ERROR_CANCELLED, NULL); + GRPC_CLOSURE_SCHED(exec_ctx, resource_user->reclaimers[0], + GRPC_ERROR_CANCELLED); + GRPC_CLOSURE_SCHED(exec_ctx, resource_user->reclaimers[1], + GRPC_ERROR_CANCELLED); resource_user->reclaimers[0] = NULL; resource_user->reclaimers[1] = NULL; rulist_remove(resource_user, GRPC_RULIST_RECLAIMER_BENIGN); @@ -496,15 +502,15 @@ static void ru_destroy(grpc_exec_ctx *exec_ctx, void *ru, grpc_error *error) { for (int i = 0; i < GRPC_RULIST_COUNT; i++) { rulist_remove(resource_user, (grpc_rulist)i); } - grpc_exec_ctx_sched(exec_ctx, resource_user->reclaimers[0], - GRPC_ERROR_CANCELLED, NULL); - grpc_exec_ctx_sched(exec_ctx, resource_user->reclaimers[1], - GRPC_ERROR_CANCELLED, NULL); + GRPC_CLOSURE_SCHED(exec_ctx, resource_user->reclaimers[0], + GRPC_ERROR_CANCELLED); + GRPC_CLOSURE_SCHED(exec_ctx, resource_user->reclaimers[1], + GRPC_ERROR_CANCELLED); if (resource_user->free_pool != 0) { resource_user->resource_quota->free_pool += resource_user->free_pool; rq_step_sched(exec_ctx, resource_user->resource_quota); } - grpc_resource_quota_internal_unref(exec_ctx, resource_user->resource_quota); + grpc_resource_quota_unref_internal(exec_ctx, resource_user->resource_quota); gpr_mu_destroy(&resource_user->mu); gpr_free(resource_user->name); gpr_free(resource_user); @@ -520,7 +526,7 @@ static void ru_allocated_slices(grpc_exec_ctx *exec_ctx, void *arg, slice_allocator->length)); } } - grpc_closure_run(exec_ctx, &slice_allocator->on_done, GRPC_ERROR_REF(error)); + GRPC_CLOSURE_RUN(exec_ctx, &slice_allocator->on_done, GRPC_ERROR_REF(error)); } /******************************************************************************* @@ -539,8 +545,9 @@ static void rq_resize(grpc_exec_ctx *exec_ctx, void *args, grpc_error *error) { int64_t delta = a->size - a->resource_quota->size; a->resource_quota->size += delta; a->resource_quota->free_pool += delta; + rq_update_estimate(a->resource_quota); rq_step_sched(exec_ctx, a->resource_quota); - grpc_resource_quota_internal_unref(exec_ctx, a->resource_quota); + grpc_resource_quota_unref_internal(exec_ctx, a->resource_quota); gpr_free(a); } @@ -549,7 +556,7 @@ static void rq_reclamation_done(grpc_exec_ctx *exec_ctx, void *rq, grpc_resource_quota *resource_quota = rq; resource_quota->reclaiming = false; rq_step_sched(exec_ctx, resource_quota); - grpc_resource_quota_internal_unref(exec_ctx, resource_quota); + grpc_resource_quota_unref_internal(exec_ctx, resource_quota); } /******************************************************************************* @@ -560,30 +567,34 @@ static void rq_reclamation_done(grpc_exec_ctx *exec_ctx, void *rq, grpc_resource_quota *grpc_resource_quota_create(const char *name) { grpc_resource_quota *resource_quota = gpr_malloc(sizeof(*resource_quota)); gpr_ref_init(&resource_quota->refs, 1); - resource_quota->combiner = grpc_combiner_create(NULL); + resource_quota->combiner = grpc_combiner_create(); resource_quota->free_pool = INT64_MAX; resource_quota->size = INT64_MAX; + gpr_atm_no_barrier_store(&resource_quota->last_size, GPR_ATM_MAX); resource_quota->step_scheduled = false; resource_quota->reclaiming = false; + gpr_atm_no_barrier_store(&resource_quota->memory_usage_estimation, 0); if (name != NULL) { resource_quota->name = gpr_strdup(name); } else { gpr_asprintf(&resource_quota->name, "anonymous_pool_%" PRIxPTR, (intptr_t)resource_quota); } - grpc_closure_init(&resource_quota->rq_step_closure, rq_step, resource_quota); - grpc_closure_init(&resource_quota->rq_reclamation_done_closure, - rq_reclamation_done, resource_quota); + GRPC_CLOSURE_INIT(&resource_quota->rq_step_closure, rq_step, resource_quota, + grpc_combiner_finally_scheduler(resource_quota->combiner)); + GRPC_CLOSURE_INIT(&resource_quota->rq_reclamation_done_closure, + rq_reclamation_done, resource_quota, + grpc_combiner_scheduler(resource_quota->combiner)); for (int i = 0; i < GRPC_RULIST_COUNT; i++) { resource_quota->roots[i] = NULL; } return resource_quota; } -void grpc_resource_quota_internal_unref(grpc_exec_ctx *exec_ctx, +void grpc_resource_quota_unref_internal(grpc_exec_ctx *exec_ctx, grpc_resource_quota *resource_quota) { if (gpr_unref(&resource_quota->refs)) { - grpc_combiner_destroy(exec_ctx, resource_quota->combiner); + GRPC_COMBINER_UNREF(exec_ctx, resource_quota->combiner, "resource_quota"); gpr_free(resource_quota->name); gpr_free(resource_quota); } @@ -592,11 +603,11 @@ void grpc_resource_quota_internal_unref(grpc_exec_ctx *exec_ctx, /* Public API */ void grpc_resource_quota_unref(grpc_resource_quota *resource_quota) { grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - grpc_resource_quota_internal_unref(&exec_ctx, resource_quota); + grpc_resource_quota_unref_internal(&exec_ctx, resource_quota); grpc_exec_ctx_finish(&exec_ctx); } -grpc_resource_quota *grpc_resource_quota_internal_ref( +grpc_resource_quota *grpc_resource_quota_ref_internal( grpc_resource_quota *resource_quota) { gpr_ref(&resource_quota->refs); return resource_quota; @@ -604,7 +615,14 @@ grpc_resource_quota *grpc_resource_quota_internal_ref( /* Public API */ void grpc_resource_quota_ref(grpc_resource_quota *resource_quota) { - grpc_resource_quota_internal_ref(resource_quota); + grpc_resource_quota_ref_internal(resource_quota); +} + +double grpc_resource_quota_get_memory_pressure( + grpc_resource_quota *resource_quota) { + return ((double)(gpr_atm_no_barrier_load( + &resource_quota->memory_usage_estimation))) / + ((double)MEMORY_USAGE_ESTIMATION_MAX); } /* Public API */ @@ -612,14 +630,19 @@ void grpc_resource_quota_resize(grpc_resource_quota *resource_quota, size_t size) { grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; rq_resize_args *a = gpr_malloc(sizeof(*a)); - a->resource_quota = grpc_resource_quota_internal_ref(resource_quota); + a->resource_quota = grpc_resource_quota_ref_internal(resource_quota); a->size = (int64_t)size; - grpc_closure_init(&a->closure, rq_resize, a); - grpc_combiner_execute(&exec_ctx, resource_quota->combiner, &a->closure, - GRPC_ERROR_NONE, false); + gpr_atm_no_barrier_store(&resource_quota->last_size, + (gpr_atm)GPR_MIN((size_t)GPR_ATM_MAX, size)); + GRPC_CLOSURE_INIT(&a->closure, rq_resize, a, grpc_schedule_on_exec_ctx); + GRPC_CLOSURE_SCHED(&exec_ctx, &a->closure, GRPC_ERROR_NONE); grpc_exec_ctx_finish(&exec_ctx); } +size_t grpc_resource_quota_peek_size(grpc_resource_quota *resource_quota) { + return (size_t)gpr_atm_no_barrier_load(&resource_quota->last_size); +} + /******************************************************************************* * grpc_resource_user channel args api */ @@ -629,7 +652,7 @@ grpc_resource_quota *grpc_resource_quota_from_channel_args( for (size_t i = 0; i < channel_args->num_args; i++) { if (0 == strcmp(channel_args->args[i].key, GRPC_ARG_RESOURCE_QUOTA)) { if (channel_args->args[i].type == GRPC_ARG_POINTER) { - return grpc_resource_quota_internal_ref( + return grpc_resource_quota_ref_internal( channel_args->args[i].value.pointer.p); } else { gpr_log(GPR_DEBUG, GRPC_ARG_RESOURCE_QUOTA " should be a pointer"); @@ -644,7 +667,9 @@ static void *rq_copy(void *rq) { return rq; } -static void rq_destroy(void *rq) { grpc_resource_quota_unref(rq); } +static void rq_destroy(grpc_exec_ctx *exec_ctx, void *rq) { + grpc_resource_quota_unref_internal(exec_ctx, rq); +} static int rq_cmp(void *a, void *b) { return GPR_ICMP(a, b); } @@ -661,17 +686,21 @@ grpc_resource_user *grpc_resource_user_create( grpc_resource_quota *resource_quota, const char *name) { grpc_resource_user *resource_user = gpr_malloc(sizeof(*resource_user)); resource_user->resource_quota = - grpc_resource_quota_internal_ref(resource_quota); - grpc_closure_init(&resource_user->allocate_closure, &ru_allocate, - resource_user); - grpc_closure_init(&resource_user->add_to_free_pool_closure, - &ru_add_to_free_pool, resource_user); - grpc_closure_init(&resource_user->post_reclaimer_closure[0], - &ru_post_benign_reclaimer, resource_user); - grpc_closure_init(&resource_user->post_reclaimer_closure[1], - &ru_post_destructive_reclaimer, resource_user); - grpc_closure_init(&resource_user->destroy_closure, &ru_destroy, - resource_user); + grpc_resource_quota_ref_internal(resource_quota); + GRPC_CLOSURE_INIT(&resource_user->allocate_closure, &ru_allocate, + resource_user, + grpc_combiner_scheduler(resource_quota->combiner)); + GRPC_CLOSURE_INIT(&resource_user->add_to_free_pool_closure, + &ru_add_to_free_pool, resource_user, + grpc_combiner_scheduler(resource_quota->combiner)); + GRPC_CLOSURE_INIT(&resource_user->post_reclaimer_closure[0], + &ru_post_benign_reclaimer, resource_user, + grpc_combiner_scheduler(resource_quota->combiner)); + GRPC_CLOSURE_INIT(&resource_user->post_reclaimer_closure[1], + &ru_post_destructive_reclaimer, resource_user, + grpc_combiner_scheduler(resource_quota->combiner)); + GRPC_CLOSURE_INIT(&resource_user->destroy_closure, &ru_destroy, resource_user, + grpc_combiner_scheduler(resource_quota->combiner)); gpr_mu_init(&resource_user->mu); gpr_atm_rel_store(&resource_user->refs, 1); gpr_atm_rel_store(&resource_user->shutdown, 0); @@ -695,6 +724,11 @@ grpc_resource_user *grpc_resource_user_create( return resource_user; } +grpc_resource_quota *grpc_resource_user_quota( + grpc_resource_user *resource_user) { + return resource_user->resource_quota; +} + static void ru_ref_by(grpc_resource_user *resource_user, gpr_atm amount) { GPR_ASSERT(amount > 0); GPR_ASSERT(gpr_atm_no_barrier_fetch_add(&resource_user->refs, amount) != 0); @@ -706,9 +740,8 @@ static void ru_unref_by(grpc_exec_ctx *exec_ctx, gpr_atm old = gpr_atm_full_fetch_add(&resource_user->refs, -amount); GPR_ASSERT(old >= amount); if (old == amount) { - grpc_combiner_execute(exec_ctx, resource_user->resource_quota->combiner, - &resource_user->destroy_closure, GRPC_ERROR_NONE, - false); + GRPC_CLOSURE_SCHED(exec_ctx, &resource_user->destroy_closure, + GRPC_ERROR_NONE); } } @@ -724,9 +757,12 @@ void grpc_resource_user_unref(grpc_exec_ctx *exec_ctx, void grpc_resource_user_shutdown(grpc_exec_ctx *exec_ctx, grpc_resource_user *resource_user) { if (gpr_atm_full_fetch_add(&resource_user->shutdown, 1) == 0) { - grpc_combiner_execute(exec_ctx, resource_user->resource_quota->combiner, - grpc_closure_create(ru_shutdown, resource_user), - GRPC_ERROR_NONE, false); + GRPC_CLOSURE_SCHED( + exec_ctx, + GRPC_CLOSURE_CREATE( + ru_shutdown, resource_user, + grpc_combiner_scheduler(resource_user->resource_quota->combiner)), + GRPC_ERROR_NONE); } } @@ -736,7 +772,7 @@ void grpc_resource_user_alloc(grpc_exec_ctx *exec_ctx, gpr_mu_lock(&resource_user->mu); ru_ref_by(resource_user, (gpr_atm)size); resource_user->free_pool -= (int64_t)size; - if (grpc_resource_quota_trace) { + if (GRPC_TRACER_ON(grpc_resource_quota_trace)) { gpr_log(GPR_DEBUG, "RQ %s %s: alloc %" PRIdPTR "; free_pool -> %" PRId64, resource_user->resource_quota->name, resource_user->name, size, resource_user->free_pool); @@ -746,12 +782,11 @@ void grpc_resource_user_alloc(grpc_exec_ctx *exec_ctx, GRPC_ERROR_NONE); if (!resource_user->allocating) { resource_user->allocating = true; - grpc_combiner_execute(exec_ctx, resource_user->resource_quota->combiner, - &resource_user->allocate_closure, GRPC_ERROR_NONE, - false); + GRPC_CLOSURE_SCHED(exec_ctx, &resource_user->allocate_closure, + GRPC_ERROR_NONE); } } else { - grpc_exec_ctx_sched(exec_ctx, optional_on_done, GRPC_ERROR_NONE, NULL); + GRPC_CLOSURE_SCHED(exec_ctx, optional_on_done, GRPC_ERROR_NONE); } gpr_mu_unlock(&resource_user->mu); } @@ -761,7 +796,7 @@ void grpc_resource_user_free(grpc_exec_ctx *exec_ctx, gpr_mu_lock(&resource_user->mu); bool was_zero_or_negative = resource_user->free_pool <= 0; resource_user->free_pool += (int64_t)size; - if (grpc_resource_quota_trace) { + if (GRPC_TRACER_ON(grpc_resource_quota_trace)) { gpr_log(GPR_DEBUG, "RQ %s %s: free %" PRIdPTR "; free_pool -> %" PRId64, resource_user->resource_quota->name, resource_user->name, size, resource_user->free_pool); @@ -770,9 +805,8 @@ void grpc_resource_user_free(grpc_exec_ctx *exec_ctx, if (is_bigger_than_zero && was_zero_or_negative && !resource_user->added_to_free_pool) { resource_user->added_to_free_pool = true; - grpc_combiner_execute(exec_ctx, resource_user->resource_quota->combiner, - &resource_user->add_to_free_pool_closure, - GRPC_ERROR_NONE, false); + GRPC_CLOSURE_SCHED(exec_ctx, &resource_user->add_to_free_pool_closure, + GRPC_ERROR_NONE); } gpr_mu_unlock(&resource_user->mu); ru_unref_by(exec_ctx, resource_user, (gpr_atm)size); @@ -784,29 +818,29 @@ void grpc_resource_user_post_reclaimer(grpc_exec_ctx *exec_ctx, grpc_closure *closure) { GPR_ASSERT(resource_user->new_reclaimers[destructive] == NULL); resource_user->new_reclaimers[destructive] = closure; - grpc_combiner_execute(exec_ctx, resource_user->resource_quota->combiner, - &resource_user->post_reclaimer_closure[destructive], - GRPC_ERROR_NONE, false); + GRPC_CLOSURE_SCHED(exec_ctx, + &resource_user->post_reclaimer_closure[destructive], + GRPC_ERROR_NONE); } void grpc_resource_user_finish_reclamation(grpc_exec_ctx *exec_ctx, grpc_resource_user *resource_user) { - if (grpc_resource_quota_trace) { + if (GRPC_TRACER_ON(grpc_resource_quota_trace)) { gpr_log(GPR_DEBUG, "RQ %s %s: reclamation complete", resource_user->resource_quota->name, resource_user->name); } - grpc_combiner_execute( - exec_ctx, resource_user->resource_quota->combiner, - &resource_user->resource_quota->rq_reclamation_done_closure, - GRPC_ERROR_NONE, false); + GRPC_CLOSURE_SCHED( + exec_ctx, &resource_user->resource_quota->rq_reclamation_done_closure, + GRPC_ERROR_NONE); } void grpc_resource_user_slice_allocator_init( grpc_resource_user_slice_allocator *slice_allocator, grpc_resource_user *resource_user, grpc_iomgr_cb_func cb, void *p) { - grpc_closure_init(&slice_allocator->on_allocated, ru_allocated_slices, - slice_allocator); - grpc_closure_init(&slice_allocator->on_done, cb, p); + GRPC_CLOSURE_INIT(&slice_allocator->on_allocated, ru_allocated_slices, + slice_allocator, grpc_schedule_on_exec_ctx); + GRPC_CLOSURE_INIT(&slice_allocator->on_done, cb, p, + grpc_schedule_on_exec_ctx); slice_allocator->resource_user = resource_user; } diff --git a/Sources/CgRPC/src/core/lib/iomgr/resource_quota.h b/Sources/CgRPC/src/core/lib/iomgr/resource_quota.h index 0181fd978..d66f9ae77 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/resource_quota.h +++ b/Sources/CgRPC/src/core/lib/iomgr/resource_quota.h @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -36,6 +21,7 @@ #include +#include "src/core/lib/debug/trace.h" #include "src/core/lib/iomgr/exec_ctx.h" /** \file Tracks resource usage against a pool. @@ -75,19 +61,33 @@ maintain lists of users (which users arrange to leave before they are destroyed) */ -extern int grpc_resource_quota_trace; +extern grpc_tracer_flag grpc_resource_quota_trace; -grpc_resource_quota *grpc_resource_quota_internal_ref( +grpc_resource_quota *grpc_resource_quota_ref_internal( grpc_resource_quota *resource_quota); -void grpc_resource_quota_internal_unref(grpc_exec_ctx *exec_ctx, +void grpc_resource_quota_unref_internal(grpc_exec_ctx *exec_ctx, grpc_resource_quota *resource_quota); grpc_resource_quota *grpc_resource_quota_from_channel_args( const grpc_channel_args *channel_args); +/* Return a number indicating current memory pressure: + 0.0 ==> no memory usage + 1.0 ==> maximum memory usage */ +double grpc_resource_quota_get_memory_pressure( + grpc_resource_quota *resource_quota); + +size_t grpc_resource_quota_peek_size(grpc_resource_quota *resource_quota); + typedef struct grpc_resource_user grpc_resource_user; grpc_resource_user *grpc_resource_user_create( grpc_resource_quota *resource_quota, const char *name); + +/* Returns a borrowed reference to the underlying resource quota for this + resource user. */ +grpc_resource_quota *grpc_resource_user_quota( + grpc_resource_user *resource_user); + void grpc_resource_user_ref(grpc_resource_user *resource_user); void grpc_resource_user_unref(grpc_exec_ctx *exec_ctx, grpc_resource_user *resource_user); diff --git a/Sources/CgRPC/src/core/lib/iomgr/sockaddr.h b/Sources/CgRPC/src/core/lib/iomgr/sockaddr.h index 52b504390..206d596cc 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/sockaddr.h +++ b/Sources/CgRPC/src/core/lib/iomgr/sockaddr.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/sockaddr_posix.h b/Sources/CgRPC/src/core/lib/iomgr/sockaddr_posix.h index b150de42f..22d57ca6b 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/sockaddr_posix.h +++ b/Sources/CgRPC/src/core/lib/iomgr/sockaddr_posix.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/sockaddr_utils.c b/Sources/CgRPC/src/core/lib/iomgr/sockaddr_utils.c index 44bc2f968..3f4145d10 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/sockaddr_utils.c +++ b/Sources/CgRPC/src/core/lib/iomgr/sockaddr_utils.c @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -55,7 +40,9 @@ int grpc_sockaddr_is_v4mapped(const grpc_resolved_address *resolved_addr, GPR_ASSERT(resolved_addr != resolved_addr4_out); const struct sockaddr *addr = (const struct sockaddr *)resolved_addr->addr; struct sockaddr_in *addr4_out = - (struct sockaddr_in *)resolved_addr4_out->addr; + resolved_addr4_out == NULL + ? NULL + : (struct sockaddr_in *)resolved_addr4_out->addr; if (addr->sa_family == AF_INET6) { const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)addr; if (memcmp(addr6->sin6_addr.s6_addr, kV4MappedPrefix, @@ -162,6 +149,7 @@ int grpc_sockaddr_to_string(char **out, char ntop_buf[INET6_ADDRSTRLEN]; const void *ip = NULL; int port; + uint32_t sin6_scope_id = 0; int ret; *out = NULL; @@ -177,10 +165,19 @@ int grpc_sockaddr_to_string(char **out, const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)addr; ip = &addr6->sin6_addr; port = ntohs(addr6->sin6_port); + sin6_scope_id = addr6->sin6_scope_id; } if (ip != NULL && grpc_inet_ntop(addr->sa_family, ip, ntop_buf, sizeof(ntop_buf)) != NULL) { - ret = gpr_join_host_port(out, ntop_buf, port); + if (sin6_scope_id != 0) { + char *host_with_scope; + /* Enclose sin6_scope_id with the format defined in RFC 6784 section 2. */ + gpr_asprintf(&host_with_scope, "%s%%25%" PRIu32, ntop_buf, sin6_scope_id); + ret = gpr_join_host_port(out, host_with_scope, port); + gpr_free(host_with_scope); + } else { + ret = gpr_join_host_port(out, ntop_buf, port); + } } else { ret = gpr_asprintf(out, "(sockaddr family=%d)", addr->sa_family); } @@ -190,31 +187,42 @@ int grpc_sockaddr_to_string(char **out, } char *grpc_sockaddr_to_uri(const grpc_resolved_address *resolved_addr) { - char *temp; - char *result; grpc_resolved_address addr_normalized; - const struct sockaddr *addr; - if (grpc_sockaddr_is_v4mapped(resolved_addr, &addr_normalized)) { resolved_addr = &addr_normalized; } + const char *scheme = grpc_sockaddr_get_uri_scheme(resolved_addr); + if (scheme == NULL || strcmp("unix", scheme) == 0) { + return grpc_sockaddr_to_uri_unix_if_possible(resolved_addr); + } + char *path = NULL; + char *uri_str = NULL; + if (grpc_sockaddr_to_string(&path, resolved_addr, + false /* suppress errors */) && + scheme != NULL) { + gpr_asprintf(&uri_str, "%s:%s", scheme, path); + } + gpr_free(path); + return uri_str != NULL ? uri_str : NULL; +} - addr = (const struct sockaddr *)resolved_addr->addr; - +const char *grpc_sockaddr_get_uri_scheme( + const grpc_resolved_address *resolved_addr) { + const struct sockaddr *addr = (const struct sockaddr *)resolved_addr->addr; switch (addr->sa_family) { case AF_INET: - grpc_sockaddr_to_string(&temp, resolved_addr, 0); - gpr_asprintf(&result, "ipv4:%s", temp); - gpr_free(temp); - return result; + return "ipv4"; case AF_INET6: - grpc_sockaddr_to_string(&temp, resolved_addr, 0); - gpr_asprintf(&result, "ipv6:%s", temp); - gpr_free(temp); - return result; - default: - return grpc_sockaddr_to_uri_unix_if_possible(resolved_addr); + return "ipv6"; + case AF_UNIX: + return "unix"; } + return NULL; +} + +int grpc_sockaddr_get_family(const grpc_resolved_address *resolved_addr) { + const struct sockaddr *addr = (const struct sockaddr *)resolved_addr->addr; + return addr->sa_family; } int grpc_sockaddr_get_port(const grpc_resolved_address *resolved_addr) { diff --git a/Sources/CgRPC/src/core/lib/iomgr/sockaddr_utils.h b/Sources/CgRPC/src/core/lib/iomgr/sockaddr_utils.h index 5371e360c..a589a1970 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/sockaddr_utils.h +++ b/Sources/CgRPC/src/core/lib/iomgr/sockaddr_utils.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -50,7 +35,7 @@ int grpc_sockaddr_to_v4mapped(const grpc_resolved_address *addr, grpc_resolved_address *addr6_out); /* If addr is ::, 0.0.0.0, or ::ffff:0.0.0.0, writes the port number to - *port_out (if not NULL) and returns true, otherwise returns false. */ + *port_out (if not NULL) and returns true, otherwise returns false. */ int grpc_sockaddr_is_wildcard(const grpc_resolved_address *addr, int *port_out); /* Writes 0.0.0.0:port and [::]:port to separate sockaddrs. */ @@ -84,6 +69,12 @@ int grpc_sockaddr_set_port(const grpc_resolved_address *addr, int port); int grpc_sockaddr_to_string(char **out, const grpc_resolved_address *addr, int normalize); +/* Returns the URI string corresponding to \a addr */ char *grpc_sockaddr_to_uri(const grpc_resolved_address *addr); +/* Returns the URI scheme corresponding to \a addr */ +const char *grpc_sockaddr_get_uri_scheme(const grpc_resolved_address *addr); + +int grpc_sockaddr_get_family(const grpc_resolved_address *resolved_addr); + #endif /* GRPC_CORE_LIB_IOMGR_SOCKADDR_UTILS_H */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/sockaddr_windows.h b/Sources/CgRPC/src/core/lib/iomgr/sockaddr_windows.h index 971db5b32..cf0f6b914 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/sockaddr_windows.h +++ b/Sources/CgRPC/src/core/lib/iomgr/sockaddr_windows.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/socket_factory_posix.c b/Sources/CgRPC/src/core/lib/iomgr/socket_factory_posix.c new file mode 100644 index 000000000..0f82dea57 --- /dev/null +++ b/Sources/CgRPC/src/core/lib/iomgr/socket_factory_posix.c @@ -0,0 +1,92 @@ +/* + * + * Copyright 2017 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 "src/core/lib/iomgr/port.h" + +#ifdef GRPC_POSIX_SOCKET + +#include "src/core/lib/channel/channel_args.h" +#include "src/core/lib/iomgr/socket_factory_posix.h" + +#include +#include +#include + +void grpc_socket_factory_init(grpc_socket_factory *factory, + const grpc_socket_factory_vtable *vtable) { + factory->vtable = vtable; + gpr_ref_init(&factory->refcount, 1); +} + +int grpc_socket_factory_socket(grpc_socket_factory *factory, int domain, + int type, int protocol) { + return factory->vtable->socket(factory, domain, type, protocol); +} + +int grpc_socket_factory_bind(grpc_socket_factory *factory, int sockfd, + const grpc_resolved_address *addr) { + return factory->vtable->bind(factory, sockfd, addr); +} + +int grpc_socket_factory_compare(grpc_socket_factory *a, + grpc_socket_factory *b) { + int c = GPR_ICMP(a, b); + if (c != 0) { + grpc_socket_factory *sma = a; + grpc_socket_factory *smb = b; + c = GPR_ICMP(sma->vtable, smb->vtable); + if (c == 0) { + c = sma->vtable->compare(sma, smb); + } + } + return c; +} + +grpc_socket_factory *grpc_socket_factory_ref(grpc_socket_factory *factory) { + gpr_ref(&factory->refcount); + return factory; +} + +void grpc_socket_factory_unref(grpc_socket_factory *factory) { + if (gpr_unref(&factory->refcount)) { + factory->vtable->destroy(factory); + } +} + +static void *socket_factory_arg_copy(void *p) { + return grpc_socket_factory_ref(p); +} + +static void socket_factory_arg_destroy(grpc_exec_ctx *exec_ctx, void *p) { + grpc_socket_factory_unref(p); +} + +static int socket_factory_cmp(void *a, void *b) { + return grpc_socket_factory_compare((grpc_socket_factory *)a, + (grpc_socket_factory *)b); +} + +static const grpc_arg_pointer_vtable socket_factory_arg_vtable = { + socket_factory_arg_copy, socket_factory_arg_destroy, socket_factory_cmp}; + +grpc_arg grpc_socket_factory_to_arg(grpc_socket_factory *factory) { + return grpc_channel_arg_pointer_create(GRPC_ARG_SOCKET_FACTORY, factory, + &socket_factory_arg_vtable); +} + +#endif diff --git a/Sources/CgRPC/src/core/lib/iomgr/socket_factory_posix.h b/Sources/CgRPC/src/core/lib/iomgr/socket_factory_posix.h new file mode 100644 index 000000000..a46938b06 --- /dev/null +++ b/Sources/CgRPC/src/core/lib/iomgr/socket_factory_posix.h @@ -0,0 +1,75 @@ +/* + * + * Copyright 2017 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 GRPC_CORE_LIB_IOMGR_SOCKET_FACTORY_POSIX_H +#define GRPC_CORE_LIB_IOMGR_SOCKET_FACTORY_POSIX_H + +#include +#include +#include "src/core/lib/iomgr/resolve_address.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** The virtual table of grpc_socket_factory */ +typedef struct { + /** Replacement for socket(2) */ + int (*socket)(grpc_socket_factory *factory, int domain, int type, + int protocol); + /** Replacement for bind(2) */ + int (*bind)(grpc_socket_factory *factory, int sockfd, + const grpc_resolved_address *addr); + /** Compare socket factory \a a and \a b */ + int (*compare)(grpc_socket_factory *a, grpc_socket_factory *b); + /** Destroys the socket factory instance */ + void (*destroy)(grpc_socket_factory *factory); +} grpc_socket_factory_vtable; + +/** The Socket Factory interface allows changes on socket options */ +struct grpc_socket_factory { + const grpc_socket_factory_vtable *vtable; + gpr_refcount refcount; +}; + +/** called by concrete implementations to initialize the base struct */ +void grpc_socket_factory_init(grpc_socket_factory *factory, + const grpc_socket_factory_vtable *vtable); + +/** Wrap \a factory as a grpc_arg */ +grpc_arg grpc_socket_factory_to_arg(grpc_socket_factory *factory); + +/** Perform the equivalent of a socket(2) operation using \a factory */ +int grpc_socket_factory_socket(grpc_socket_factory *factory, int domain, + int type, int protocol); + +/** Perform the equivalent of a bind(2) operation using \a factory */ +int grpc_socket_factory_bind(grpc_socket_factory *factory, int sockfd, + const grpc_resolved_address *addr); + +/** Compare if \a a and \a b are the same factory or have same settings */ +int grpc_socket_factory_compare(grpc_socket_factory *a, grpc_socket_factory *b); + +grpc_socket_factory *grpc_socket_factory_ref(grpc_socket_factory *factory); +void grpc_socket_factory_unref(grpc_socket_factory *factory); + +#ifdef __cplusplus +} +#endif + +#endif /* GRPC_CORE_LIB_IOMGR_SOCKET_FACTORY_POSIX_H */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/socket_mutator.c b/Sources/CgRPC/src/core/lib/iomgr/socket_mutator.c index 8b1efb6ba..5d6c2c400 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/socket_mutator.c +++ b/Sources/CgRPC/src/core/lib/iomgr/socket_mutator.c @@ -1,38 +1,25 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 "src/core/lib/iomgr/socket_mutator.h" +#include "src/core/lib/channel/channel_args.h" + #include #include #include @@ -76,7 +63,7 @@ static void *socket_mutator_arg_copy(void *p) { return grpc_socket_mutator_ref(p); } -static void socket_mutator_arg_destroy(void *p) { +static void socket_mutator_arg_destroy(grpc_exec_ctx *exec_ctx, void *p) { grpc_socket_mutator_unref(p); } @@ -89,10 +76,6 @@ static const grpc_arg_pointer_vtable socket_mutator_arg_vtable = { socket_mutator_arg_copy, socket_mutator_arg_destroy, socket_mutator_cmp}; grpc_arg grpc_socket_mutator_to_arg(grpc_socket_mutator *mutator) { - grpc_arg arg; - arg.type = GRPC_ARG_POINTER; - arg.key = GRPC_ARG_SOCKET_MUTATOR; - arg.value.pointer.vtable = &socket_mutator_arg_vtable; - arg.value.pointer.p = mutator; - return arg; + return grpc_channel_arg_pointer_create(GRPC_ARG_SOCKET_MUTATOR, mutator, + &socket_mutator_arg_vtable); } diff --git a/Sources/CgRPC/src/core/lib/iomgr/socket_mutator.h b/Sources/CgRPC/src/core/lib/iomgr/socket_mutator.h index 2f5b6c248..ba956e16f 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/socket_mutator.h +++ b/Sources/CgRPC/src/core/lib/iomgr/socket_mutator.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -37,6 +22,8 @@ #include #include +#include + #ifdef __cplusplus extern "C" { #endif diff --git a/Sources/CgRPC/src/core/lib/iomgr/socket_utils.h b/Sources/CgRPC/src/core/lib/iomgr/socket_utils.h index cc3ee2e30..03fe46e5e 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/socket_utils.h +++ b/Sources/CgRPC/src/core/lib/iomgr/socket_utils.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/socket_utils_common_posix.c b/Sources/CgRPC/src/core/lib/iomgr/socket_utils_common_posix.c index 88e9ade25..b8e2a0cdf 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/socket_utils_common_posix.c +++ b/Sources/CgRPC/src/core/lib/iomgr/socket_utils_common_posix.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -90,7 +75,7 @@ grpc_error *grpc_set_socket_no_sigpipe_if_possible(int fd) { return GRPC_OS_ERROR(errno, "getsockopt(SO_NOSIGPIPE)"); } if ((newval != 0) != (val != 0)) { - return GRPC_ERROR_CREATE("Failed to set SO_NOSIGPIPE"); + return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Failed to set SO_NOSIGPIPE"); } #endif return GRPC_ERROR_NONE; @@ -164,7 +149,7 @@ grpc_error *grpc_set_socket_reuse_addr(int fd, int reuse) { return GRPC_OS_ERROR(errno, "getsockopt(SO_REUSEADDR)"); } if ((newval != 0) != val) { - return GRPC_ERROR_CREATE("Failed to set SO_REUSEADDR"); + return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Failed to set SO_REUSEADDR"); } return GRPC_ERROR_NONE; @@ -173,7 +158,8 @@ grpc_error *grpc_set_socket_reuse_addr(int fd, int reuse) { /* set a socket to reuse old addresses */ grpc_error *grpc_set_socket_reuse_port(int fd, int reuse) { #ifndef SO_REUSEPORT - return GRPC_ERROR_CREATE("SO_REUSEPORT unavailable on compiling system"); + return GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "SO_REUSEPORT unavailable on compiling system"); #else int val = (reuse != 0); int newval; @@ -185,7 +171,7 @@ grpc_error *grpc_set_socket_reuse_port(int fd, int reuse) { return GRPC_OS_ERROR(errno, "getsockopt(SO_REUSEPORT)"); } if ((newval != 0) != val) { - return GRPC_ERROR_CREATE("Failed to set SO_REUSEPORT"); + return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Failed to set SO_REUSEPORT"); } return GRPC_ERROR_NONE; @@ -204,7 +190,7 @@ grpc_error *grpc_set_socket_low_latency(int fd, int low_latency) { return GRPC_OS_ERROR(errno, "getsockopt(TCP_NODELAY)"); } if ((newval != 0) != val) { - return GRPC_ERROR_CREATE("Failed to set TCP_NODELAY"); + return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Failed to set TCP_NODELAY"); } return GRPC_ERROR_NONE; } @@ -213,7 +199,7 @@ grpc_error *grpc_set_socket_low_latency(int fd, int low_latency) { grpc_error *grpc_set_socket_with_mutator(int fd, grpc_socket_mutator *mutator) { GPR_ASSERT(mutator); if (!grpc_socket_mutator_mutate_fd(mutator, fd)) { - return GRPC_ERROR_CREATE("grpc_socket_mutator failed."); + return GRPC_ERROR_CREATE_FROM_STATIC_STRING("grpc_socket_mutator failed."); } return GRPC_ERROR_NONE; } @@ -268,7 +254,8 @@ static grpc_error *error_for_fd(int fd, const grpc_resolved_address *addr) { char *addr_str; grpc_sockaddr_to_string(&addr_str, addr, 0); grpc_error *err = grpc_error_set_str(GRPC_OS_ERROR(errno, "socket"), - GRPC_ERROR_STR_TARGET_ADDRESS, addr_str); + GRPC_ERROR_STR_TARGET_ADDRESS, + grpc_slice_from_copied_string(addr_str)); gpr_free(addr_str); return err; } @@ -276,11 +263,25 @@ static grpc_error *error_for_fd(int fd, const grpc_resolved_address *addr) { grpc_error *grpc_create_dualstack_socket( const grpc_resolved_address *resolved_addr, int type, int protocol, grpc_dualstack_mode *dsmode, int *newfd) { + return grpc_create_dualstack_socket_using_factory(NULL, resolved_addr, type, + protocol, dsmode, newfd); +} + +static int create_socket(grpc_socket_factory *factory, int domain, int type, + int protocol) { + return (factory != NULL) + ? grpc_socket_factory_socket(factory, domain, type, protocol) + : socket(domain, type, protocol); +} + +grpc_error *grpc_create_dualstack_socket_using_factory( + grpc_socket_factory *factory, const grpc_resolved_address *resolved_addr, + int type, int protocol, grpc_dualstack_mode *dsmode, int *newfd) { const struct sockaddr *addr = (const struct sockaddr *)resolved_addr->addr; int family = addr->sa_family; if (family == AF_INET6) { if (grpc_ipv6_loopback_available()) { - *newfd = socket(family, type, protocol); + *newfd = create_socket(factory, family, type, protocol); } else { *newfd = -1; errno = EAFNOSUPPORT; @@ -302,7 +303,7 @@ grpc_error *grpc_create_dualstack_socket( family = AF_INET; } *dsmode = family == AF_INET ? GRPC_DSMODE_IPV4 : GRPC_DSMODE_NONE; - *newfd = socket(family, type, protocol); + *newfd = create_socket(factory, family, type, protocol); return error_for_fd(*newfd, resolved_addr); } diff --git a/Sources/CgRPC/src/core/lib/iomgr/socket_utils_linux.c b/Sources/CgRPC/src/core/lib/iomgr/socket_utils_linux.c index bf6e9e4f5..e7b094d21 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/socket_utils_linux.c +++ b/Sources/CgRPC/src/core/lib/iomgr/socket_utils_linux.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/socket_utils_posix.c b/Sources/CgRPC/src/core/lib/iomgr/socket_utils_posix.c index 9dea0c0cd..dfd1ffd1e 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/socket_utils_posix.c +++ b/Sources/CgRPC/src/core/lib/iomgr/socket_utils_posix.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/socket_utils_posix.h b/Sources/CgRPC/src/core/lib/iomgr/socket_utils_posix.h index e84d3781a..eef80b439 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/socket_utils_posix.h +++ b/Sources/CgRPC/src/core/lib/iomgr/socket_utils_posix.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -41,6 +26,7 @@ #include #include "src/core/lib/iomgr/error.h" +#include "src/core/lib/iomgr/socket_factory_posix.h" #include "src/core/lib/iomgr/socket_mutator.h" /* a wrapper for accept or accept4 */ @@ -137,4 +123,10 @@ grpc_error *grpc_create_dualstack_socket(const grpc_resolved_address *addr, grpc_dualstack_mode *dsmode, int *newfd); +/* Same as grpc_create_dualstack_socket(), but use the given socket factory (if + non-null) to create the socket, rather than calling socket() directly. */ +grpc_error *grpc_create_dualstack_socket_using_factory( + grpc_socket_factory *factory, const grpc_resolved_address *addr, int type, + int protocol, grpc_dualstack_mode *dsmode, int *newfd); + #endif /* GRPC_CORE_LIB_IOMGR_SOCKET_UTILS_POSIX_H */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/socket_utils_uv.c b/Sources/CgRPC/src/core/lib/iomgr/socket_utils_uv.c index 741bf2896..0f7de4dfa 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/socket_utils_uv.c +++ b/Sources/CgRPC/src/core/lib/iomgr/socket_utils_uv.c @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/socket_utils_windows.c b/Sources/CgRPC/src/core/lib/iomgr/socket_utils_windows.c index 628ad4a45..2732c159a 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/socket_utils_windows.c +++ b/Sources/CgRPC/src/core/lib/iomgr/socket_utils_windows.c @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -41,8 +26,12 @@ #include const char *grpc_inet_ntop(int af, const void *src, char *dst, size_t size) { +#ifdef GPR_WIN_INET_NTOP + return inet_ntop(af, src, dst, size); +#else /* Windows InetNtopA wants a mutable ip pointer */ return InetNtopA(af, (void *)src, dst, size); +#endif /* GPR_WIN_INET_NTOP */ } #endif /* GRPC_WINDOWS_SOCKETUTILS */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/socket_windows.c b/Sources/CgRPC/src/core/lib/iomgr/socket_windows.c index 54911e0e3..a0d731b94 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/socket_windows.c +++ b/Sources/CgRPC/src/core/lib/iomgr/socket_windows.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -131,7 +116,7 @@ static void socket_notify_on_iocp(grpc_exec_ctx *exec_ctx, gpr_mu_lock(&socket->state_mu); if (info->has_pending_iocp) { info->has_pending_iocp = 0; - grpc_exec_ctx_sched(exec_ctx, closure, GRPC_ERROR_NONE, NULL); + GRPC_CLOSURE_SCHED(exec_ctx, closure, GRPC_ERROR_NONE); } else { info->closure = closure; } @@ -154,7 +139,7 @@ void grpc_socket_become_ready(grpc_exec_ctx *exec_ctx, grpc_winsocket *socket, GPR_ASSERT(!info->has_pending_iocp); gpr_mu_lock(&socket->state_mu); if (info->closure) { - grpc_exec_ctx_sched(exec_ctx, info->closure, GRPC_ERROR_NONE, NULL); + GRPC_CLOSURE_SCHED(exec_ctx, info->closure, GRPC_ERROR_NONE); info->closure = NULL; } else { info->has_pending_iocp = 1; diff --git a/Sources/CgRPC/src/core/lib/iomgr/socket_windows.h b/Sources/CgRPC/src/core/lib/iomgr/socket_windows.h index a3875ce16..67dc4ca53 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/socket_windows.h +++ b/Sources/CgRPC/src/core/lib/iomgr/socket_windows.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/sys_epoll_wrapper.h b/Sources/CgRPC/src/core/lib/iomgr/sys_epoll_wrapper.h new file mode 100644 index 000000000..3fa535715 --- /dev/null +++ b/Sources/CgRPC/src/core/lib/iomgr/sys_epoll_wrapper.h @@ -0,0 +1,28 @@ +/* + * + * Copyright 2017 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 GRPC_CORE_LIB_IOMGR_SYS_EPOLL_WRAPPER_H +#define GRPC_CORE_LIB_IOMGR_SYS_EPOLL_WRAPPER_H + +#include + +#ifndef EPOLLEXCLUSIVE +#define EPOLLEXCLUSIVE (1 << 28) +#endif + +#endif /* GRPC_CORE_LIB_IOMGR_SYS_EPOLL_WRAPPER_H */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/tcp_client.h b/Sources/CgRPC/src/core/lib/iomgr/tcp_client.h index 048566131..6c9e51ae8 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/tcp_client.h +++ b/Sources/CgRPC/src/core/lib/iomgr/tcp_client.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -40,10 +25,6 @@ #include "src/core/lib/iomgr/pollset_set.h" #include "src/core/lib/iomgr/resolve_address.h" -/* Channel arg (integer) setting how large a slice to try and read from the wire - each time recvmsg (or equivalent) is called */ -#define GRPC_ARG_TCP_READ_CHUNK_SIZE "grpc.experimental.tcp_read_chunk_size" - /* Asynchronously connect to an address (specified as (addr, len)), and call cb with arg and the completed connection when done (or call cb with arg and NULL on failure). diff --git a/Sources/CgRPC/src/core/lib/iomgr/tcp_client_posix.c b/Sources/CgRPC/src/core/lib/iomgr/tcp_client_posix.c index a3a70a8ed..a25fba452 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/tcp_client_posix.c +++ b/Sources/CgRPC/src/core/lib/iomgr/tcp_client_posix.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -58,13 +43,14 @@ #include "src/core/lib/iomgr/unix_sockets_posix.h" #include "src/core/lib/support/string.h" -extern int grpc_tcp_trace; +extern grpc_tracer_flag grpc_tcp_trace; typedef struct { gpr_mu mu; grpc_fd *fd; gpr_timespec deadline; grpc_timer alarm; + grpc_closure on_alarm; int refs; grpc_closure write_closure; grpc_pollset_set *interested_parties; @@ -113,22 +99,22 @@ static grpc_error *prepare_socket(const grpc_resolved_address *addr, int fd, static void tc_on_alarm(grpc_exec_ctx *exec_ctx, void *acp, grpc_error *error) { int done; async_connect *ac = acp; - if (grpc_tcp_trace) { + if (GRPC_TRACER_ON(grpc_tcp_trace)) { const char *str = grpc_error_string(error); gpr_log(GPR_DEBUG, "CLIENT_CONNECT: %s: on_alarm: error=%s", ac->addr_str, str); - grpc_error_free_string(str); } gpr_mu_lock(&ac->mu); if (ac->fd != NULL) { - grpc_fd_shutdown(exec_ctx, ac->fd); + grpc_fd_shutdown(exec_ctx, ac->fd, GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "connect() timed out")); } done = (--ac->refs == 0); gpr_mu_unlock(&ac->mu); if (done) { gpr_mu_destroy(&ac->mu); gpr_free(ac->addr_str); - grpc_channel_args_destroy(ac->channel_args); + grpc_channel_args_destroy(exec_ctx, ac->channel_args); gpr_free(ac); } } @@ -136,29 +122,7 @@ static void tc_on_alarm(grpc_exec_ctx *exec_ctx, void *acp, grpc_error *error) { grpc_endpoint *grpc_tcp_client_create_from_fd( grpc_exec_ctx *exec_ctx, grpc_fd *fd, const grpc_channel_args *channel_args, const char *addr_str) { - size_t tcp_read_chunk_size = GRPC_TCP_DEFAULT_READ_SLICE_SIZE; - grpc_resource_quota *resource_quota = grpc_resource_quota_create(NULL); - if (channel_args != NULL) { - for (size_t i = 0; i < channel_args->num_args; i++) { - if (0 == - strcmp(channel_args->args[i].key, GRPC_ARG_TCP_READ_CHUNK_SIZE)) { - grpc_integer_options options = {(int)tcp_read_chunk_size, 1, - 8 * 1024 * 1024}; - tcp_read_chunk_size = (size_t)grpc_channel_arg_get_integer( - &channel_args->args[i], options); - } else if (0 == - strcmp(channel_args->args[i].key, GRPC_ARG_RESOURCE_QUOTA)) { - grpc_resource_quota_internal_unref(exec_ctx, resource_quota); - resource_quota = grpc_resource_quota_internal_ref( - channel_args->args[i].value.pointer.p); - } - } - } - - grpc_endpoint *ep = - grpc_tcp_create(fd, resource_quota, tcp_read_chunk_size, addr_str); - grpc_resource_quota_internal_unref(exec_ctx, resource_quota); - return ep; + return grpc_tcp_create(exec_ctx, fd, channel_args, addr_str); } static void on_writable(grpc_exec_ctx *exec_ctx, void *acp, grpc_error *error) { @@ -173,11 +137,10 @@ static void on_writable(grpc_exec_ctx *exec_ctx, void *acp, grpc_error *error) { GRPC_ERROR_REF(error); - if (grpc_tcp_trace) { + if (GRPC_TRACER_ON(grpc_tcp_trace)) { const char *str = grpc_error_string(error); gpr_log(GPR_DEBUG, "CLIENT_CONNECT: %s: on_writable: error=%s", ac->addr_str, str); - grpc_error_free_string(str); } gpr_mu_lock(&ac->mu); @@ -191,7 +154,8 @@ static void on_writable(grpc_exec_ctx *exec_ctx, void *acp, grpc_error *error) { gpr_mu_lock(&ac->mu); if (error != GRPC_ERROR_NONE) { error = - grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR, "Timeout occurred"); + grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR, + grpc_slice_from_static_string("Timeout occurred")); goto finish; } @@ -245,27 +209,33 @@ static void on_writable(grpc_exec_ctx *exec_ctx, void *acp, grpc_error *error) { finish: if (fd != NULL) { grpc_pollset_set_del_fd(exec_ctx, ac->interested_parties, fd); - grpc_fd_orphan(exec_ctx, fd, NULL, NULL, "tcp_client_orphan"); + grpc_fd_orphan(exec_ctx, fd, NULL, NULL, false /* already_closed */, + "tcp_client_orphan"); fd = NULL; } done = (--ac->refs == 0); gpr_mu_unlock(&ac->mu); if (error != GRPC_ERROR_NONE) { char *error_descr; - gpr_asprintf(&error_descr, "Failed to connect to remote host: %s", - grpc_error_get_str(error, GRPC_ERROR_STR_DESCRIPTION)); - error = grpc_error_set_str(error, GRPC_ERROR_STR_DESCRIPTION, error_descr); + grpc_slice str; + bool ret = grpc_error_get_str(error, GRPC_ERROR_STR_DESCRIPTION, &str); + GPR_ASSERT(ret); + char *desc = grpc_slice_to_c_string(str); + gpr_asprintf(&error_descr, "Failed to connect to remote host: %s", desc); + error = grpc_error_set_str(error, GRPC_ERROR_STR_DESCRIPTION, + grpc_slice_from_copied_string(error_descr)); gpr_free(error_descr); - error = - grpc_error_set_str(error, GRPC_ERROR_STR_TARGET_ADDRESS, ac->addr_str); + gpr_free(desc); + error = grpc_error_set_str(error, GRPC_ERROR_STR_TARGET_ADDRESS, + grpc_slice_from_copied_string(ac->addr_str)); } if (done) { gpr_mu_destroy(&ac->mu); gpr_free(ac->addr_str); - grpc_channel_args_destroy(ac->channel_args); + grpc_channel_args_destroy(exec_ctx, ac->channel_args); gpr_free(ac); } - grpc_exec_ctx_sched(exec_ctx, closure, error, NULL); + GRPC_CLOSURE_SCHED(exec_ctx, closure, error); } static void tcp_client_connect_impl(grpc_exec_ctx *exec_ctx, @@ -294,7 +264,7 @@ static void tcp_client_connect_impl(grpc_exec_ctx *exec_ctx, error = grpc_create_dualstack_socket(addr, SOCK_STREAM, 0, &dsmode, &fd); if (error != GRPC_ERROR_NONE) { - grpc_exec_ctx_sched(exec_ctx, closure, error, NULL); + GRPC_CLOSURE_SCHED(exec_ctx, closure, error); return; } if (dsmode == GRPC_DSMODE_IPV4) { @@ -303,7 +273,7 @@ static void tcp_client_connect_impl(grpc_exec_ctx *exec_ctx, addr = &addr4_copy; } if ((error = prepare_socket(addr, fd, channel_args)) != GRPC_ERROR_NONE) { - grpc_exec_ctx_sched(exec_ctx, closure, error, NULL); + GRPC_CLOSURE_SCHED(exec_ctx, closure, error); return; } @@ -321,14 +291,14 @@ static void tcp_client_connect_impl(grpc_exec_ctx *exec_ctx, if (err >= 0) { *ep = grpc_tcp_client_create_from_fd(exec_ctx, fdobj, channel_args, addr_str); - grpc_exec_ctx_sched(exec_ctx, closure, GRPC_ERROR_NONE, NULL); + GRPC_CLOSURE_SCHED(exec_ctx, closure, GRPC_ERROR_NONE); goto done; } if (errno != EWOULDBLOCK && errno != EINPROGRESS) { - grpc_fd_orphan(exec_ctx, fdobj, NULL, NULL, "tcp_client_connect_error"); - grpc_exec_ctx_sched(exec_ctx, closure, GRPC_OS_ERROR(errno, "connect"), - NULL); + grpc_fd_orphan(exec_ctx, fdobj, NULL, NULL, false /* already_closed */, + "tcp_client_connect_error"); + GRPC_CLOSURE_SCHED(exec_ctx, closure, GRPC_OS_ERROR(errno, "connect")); goto done; } @@ -343,19 +313,20 @@ static void tcp_client_connect_impl(grpc_exec_ctx *exec_ctx, addr_str = NULL; gpr_mu_init(&ac->mu); ac->refs = 2; - ac->write_closure.cb = on_writable; - ac->write_closure.cb_arg = ac; + GRPC_CLOSURE_INIT(&ac->write_closure, on_writable, ac, + grpc_schedule_on_exec_ctx); ac->channel_args = grpc_channel_args_copy(channel_args); - if (grpc_tcp_trace) { - gpr_log(GPR_DEBUG, "CLIENT_CONNECT: %s: asynchronously connecting", - ac->addr_str); + if (GRPC_TRACER_ON(grpc_tcp_trace)) { + gpr_log(GPR_DEBUG, "CLIENT_CONNECT: %s: asynchronously connecting fd %p", + ac->addr_str, fdobj); } gpr_mu_lock(&ac->mu); + GRPC_CLOSURE_INIT(&ac->on_alarm, tc_on_alarm, ac, grpc_schedule_on_exec_ctx); grpc_timer_init(exec_ctx, &ac->alarm, gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC), - tc_on_alarm, ac, gpr_now(GPR_CLOCK_MONOTONIC)); + &ac->on_alarm, gpr_now(GPR_CLOCK_MONOTONIC)); grpc_fd_notify_on_write(exec_ctx, ac->fd, &ac->write_closure); gpr_mu_unlock(&ac->mu); diff --git a/Sources/CgRPC/src/core/lib/iomgr/tcp_client_posix.h b/Sources/CgRPC/src/core/lib/iomgr/tcp_client_posix.h index efc5fcd5b..b5a381479 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/tcp_client_posix.h +++ b/Sources/CgRPC/src/core/lib/iomgr/tcp_client_posix.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/tcp_client_uv.c b/Sources/CgRPC/src/core/lib/iomgr/tcp_client_uv.c index b07f9ceff..786c456b7 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/tcp_client_uv.c +++ b/Sources/CgRPC/src/core/lib/iomgr/tcp_client_uv.c @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -41,14 +26,18 @@ #include #include "src/core/lib/iomgr/error.h" +#include "src/core/lib/iomgr/iomgr_uv.h" #include "src/core/lib/iomgr/sockaddr_utils.h" #include "src/core/lib/iomgr/tcp_client.h" #include "src/core/lib/iomgr/tcp_uv.h" #include "src/core/lib/iomgr/timer.h" +extern grpc_tracer_flag grpc_tcp_trace; + typedef struct grpc_uv_tcp_connect { uv_connect_t connect_req; grpc_timer alarm; + grpc_closure on_alarm; uv_tcp_t *tcp_handle; grpc_closure *closure; grpc_endpoint **endpoint; @@ -59,7 +48,8 @@ typedef struct grpc_uv_tcp_connect { static void uv_tcp_connect_cleanup(grpc_exec_ctx *exec_ctx, grpc_uv_tcp_connect *connect) { - grpc_resource_quota_internal_unref(exec_ctx, connect->resource_quota); + grpc_resource_quota_unref_internal(exec_ctx, connect->resource_quota); + gpr_free(connect->addr_name); gpr_free(connect); } @@ -69,6 +59,11 @@ static void uv_tc_on_alarm(grpc_exec_ctx *exec_ctx, void *acp, grpc_error *error) { int done; grpc_uv_tcp_connect *connect = acp; + if (GRPC_TRACER_ON(grpc_tcp_trace)) { + const char *str = grpc_error_string(error); + gpr_log(GPR_DEBUG, "CLIENT_CONNECT: %s: on_alarm: error=%s", + connect->addr_name, str); + } if (error == GRPC_ERROR_NONE) { /* error == NONE implies that the timer ran out, and wasn't cancelled. If it was cancelled, then the handler that cancelled it also should close @@ -92,25 +87,30 @@ static void uv_tc_on_connect(uv_connect_t *req, int status) { *connect->endpoint = grpc_tcp_create( connect->tcp_handle, connect->resource_quota, connect->addr_name); } else { - error = GRPC_ERROR_CREATE("Failed to connect to remote host"); + error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "Failed to connect to remote host"); error = grpc_error_set_int(error, GRPC_ERROR_INT_ERRNO, -status); error = - grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR, uv_strerror(status)); + grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR, + grpc_slice_from_static_string(uv_strerror(status))); if (status == UV_ECANCELED) { - error = grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR, - "Timeout occurred"); + error = + grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR, + grpc_slice_from_static_string("Timeout occurred")); // This should only happen if the handle is already closed } else { - error = grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR, - uv_strerror(status)); + error = grpc_error_set_str( + error, GRPC_ERROR_STR_OS_ERROR, + grpc_slice_from_static_string(uv_strerror(status))); uv_close((uv_handle_t *)connect->tcp_handle, tcp_close_callback); } } done = (--connect->refs == 0); if (done) { + grpc_exec_ctx_flush(&exec_ctx); uv_tcp_connect_cleanup(&exec_ctx, connect); } - grpc_exec_ctx_sched(&exec_ctx, closure, error, NULL); + GRPC_CLOSURE_SCHED(&exec_ctx, closure, error); grpc_exec_ctx_finish(&exec_ctx); } @@ -125,18 +125,19 @@ static void tcp_client_connect_impl(grpc_exec_ctx *exec_ctx, (void)channel_args; (void)interested_parties; + GRPC_UV_ASSERT_SAME_THREAD(); + if (channel_args != NULL) { for (size_t i = 0; i < channel_args->num_args; i++) { if (0 == strcmp(channel_args->args[i].key, GRPC_ARG_RESOURCE_QUOTA)) { - grpc_resource_quota_internal_unref(exec_ctx, resource_quota); - resource_quota = grpc_resource_quota_internal_ref( + grpc_resource_quota_unref_internal(exec_ctx, resource_quota); + resource_quota = grpc_resource_quota_ref_internal( channel_args->args[i].value.pointer.p); } } } - connect = gpr_malloc(sizeof(grpc_uv_tcp_connect)); - memset(connect, 0, sizeof(grpc_uv_tcp_connect)); + connect = gpr_zalloc(sizeof(grpc_uv_tcp_connect)); connect->closure = closure; connect->endpoint = ep; connect->tcp_handle = gpr_malloc(sizeof(uv_tcp_t)); @@ -144,13 +145,22 @@ static void tcp_client_connect_impl(grpc_exec_ctx *exec_ctx, connect->resource_quota = resource_quota; uv_tcp_init(uv_default_loop(), connect->tcp_handle); connect->connect_req.data = connect; + connect->refs = 1; + + if (GRPC_TRACER_ON(grpc_tcp_trace)) { + gpr_log(GPR_DEBUG, "CLIENT_CONNECT: %s: asynchronously connecting", + connect->addr_name); + } + // TODO(murgatroid99): figure out what the return value here means uv_tcp_connect(&connect->connect_req, connect->tcp_handle, (const struct sockaddr *)resolved_addr->addr, uv_tc_on_connect); + GRPC_CLOSURE_INIT(&connect->on_alarm, uv_tc_on_alarm, connect, + grpc_schedule_on_exec_ctx); grpc_timer_init(exec_ctx, &connect->alarm, gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC), - uv_tc_on_alarm, connect, gpr_now(GPR_CLOCK_MONOTONIC)); + &connect->on_alarm, gpr_now(GPR_CLOCK_MONOTONIC)); } // overridden by api_fuzzer.c diff --git a/Sources/CgRPC/src/core/lib/iomgr/tcp_client_windows.c b/Sources/CgRPC/src/core/lib/iomgr/tcp_client_windows.c index 1127588eb..fc62105cc 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/tcp_client_windows.c +++ b/Sources/CgRPC/src/core/lib/iomgr/tcp_client_windows.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -58,11 +43,12 @@ typedef struct { grpc_winsocket *socket; gpr_timespec deadline; grpc_timer alarm; + grpc_closure on_alarm; char *addr_name; int refs; grpc_closure on_connect; grpc_endpoint **endpoint; - grpc_resource_quota *resource_quota; + grpc_channel_args *channel_args; } async_connect; static void async_connect_unlock_and_cleanup(grpc_exec_ctx *exec_ctx, @@ -71,7 +57,7 @@ static void async_connect_unlock_and_cleanup(grpc_exec_ctx *exec_ctx, int done = (--ac->refs == 0); gpr_mu_unlock(&ac->mu); if (done) { - grpc_resource_quota_internal_unref(exec_ctx, ac->resource_quota); + grpc_channel_args_destroy(exec_ctx, ac->channel_args); gpr_mu_destroy(&ac->mu); gpr_free(ac->addr_name); gpr_free(ac); @@ -118,28 +104,27 @@ static void on_connect(grpc_exec_ctx *exec_ctx, void *acp, grpc_error *error) { if (!wsa_success) { error = GRPC_WSA_ERROR(WSAGetLastError(), "ConnectEx"); } else { - *ep = grpc_tcp_create(socket, ac->resource_quota, ac->addr_name); + *ep = + grpc_tcp_create(exec_ctx, socket, ac->channel_args, ac->addr_name); socket = NULL; } } else { - error = GRPC_ERROR_CREATE("socket is null"); + error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("socket is null"); } } async_connect_unlock_and_cleanup(exec_ctx, ac, socket); /* If the connection was aborted, the callback was already called when the deadline was met. */ - grpc_exec_ctx_sched(exec_ctx, on_done, error, NULL); + GRPC_CLOSURE_SCHED(exec_ctx, on_done, error); } /* Tries to issue one async connection, then schedules both an IOCP notification request for the connection, and one timeout alert. */ -void grpc_tcp_client_connect(grpc_exec_ctx *exec_ctx, grpc_closure *on_done, - grpc_endpoint **endpoint, - grpc_pollset_set *interested_parties, - const grpc_channel_args *channel_args, - const grpc_resolved_address *addr, - gpr_timespec deadline) { +static void tcp_client_connect_impl( + grpc_exec_ctx *exec_ctx, grpc_closure *on_done, grpc_endpoint **endpoint, + grpc_pollset_set *interested_parties, const grpc_channel_args *channel_args, + const grpc_resolved_address *addr, gpr_timespec deadline) { SOCKET sock = INVALID_SOCKET; BOOL success; int status; @@ -153,17 +138,6 @@ void grpc_tcp_client_connect(grpc_exec_ctx *exec_ctx, grpc_closure *on_done, grpc_winsocket_callback_info *info; grpc_error *error = GRPC_ERROR_NONE; - grpc_resource_quota *resource_quota = grpc_resource_quota_create(NULL); - if (channel_args != NULL) { - for (size_t i = 0; i < channel_args->num_args; i++) { - if (0 == strcmp(channel_args->args[i].key, GRPC_ARG_RESOURCE_QUOTA)) { - grpc_resource_quota_internal_unref(exec_ctx, resource_quota); - resource_quota = grpc_resource_quota_internal_ref( - channel_args->args[i].value.pointer.p); - } - } - } - *endpoint = NULL; /* Use dualstack sockets where available. */ @@ -226,10 +200,11 @@ void grpc_tcp_client_connect(grpc_exec_ctx *exec_ctx, grpc_closure *on_done, ac->refs = 2; ac->addr_name = grpc_sockaddr_to_uri(addr); ac->endpoint = endpoint; - ac->resource_quota = resource_quota; - grpc_closure_init(&ac->on_connect, on_connect, ac); + ac->channel_args = grpc_channel_args_copy(channel_args); + GRPC_CLOSURE_INIT(&ac->on_connect, on_connect, ac, grpc_schedule_on_exec_ctx); - grpc_timer_init(exec_ctx, &ac->alarm, deadline, on_alarm, ac, + GRPC_CLOSURE_INIT(&ac->on_alarm, on_alarm, ac, grpc_schedule_on_exec_ctx); + grpc_timer_init(exec_ctx, &ac->alarm, deadline, &ac->on_alarm, gpr_now(GPR_CLOCK_MONOTONIC)); grpc_socket_notify_on_write(exec_ctx, socket, &ac->on_connect); return; @@ -238,16 +213,33 @@ void grpc_tcp_client_connect(grpc_exec_ctx *exec_ctx, grpc_closure *on_done, GPR_ASSERT(error != GRPC_ERROR_NONE); char *target_uri = grpc_sockaddr_to_uri(addr); grpc_error *final_error = grpc_error_set_str( - GRPC_ERROR_CREATE_REFERENCING("Failed to connect", &error, 1), - GRPC_ERROR_STR_TARGET_ADDRESS, target_uri); + GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING("Failed to connect", + &error, 1), + GRPC_ERROR_STR_TARGET_ADDRESS, grpc_slice_from_copied_string(target_uri)); GRPC_ERROR_UNREF(error); if (socket != NULL) { grpc_winsocket_destroy(socket); } else if (sock != INVALID_SOCKET) { closesocket(sock); } - grpc_resource_quota_internal_unref(exec_ctx, resource_quota); - grpc_exec_ctx_sched(exec_ctx, on_done, final_error, NULL); + GRPC_CLOSURE_SCHED(exec_ctx, on_done, final_error); +} + +// overridden by api_fuzzer.c +void (*grpc_tcp_client_connect_impl)( + grpc_exec_ctx *exec_ctx, grpc_closure *closure, grpc_endpoint **ep, + grpc_pollset_set *interested_parties, const grpc_channel_args *channel_args, + const grpc_resolved_address *addr, + gpr_timespec deadline) = tcp_client_connect_impl; + +void grpc_tcp_client_connect(grpc_exec_ctx *exec_ctx, grpc_closure *closure, + grpc_endpoint **ep, + grpc_pollset_set *interested_parties, + const grpc_channel_args *channel_args, + const grpc_resolved_address *addr, + gpr_timespec deadline) { + grpc_tcp_client_connect_impl(exec_ctx, closure, ep, interested_parties, + channel_args, addr, deadline); } #endif /* GRPC_WINSOCK_SOCKET */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/tcp_posix.c b/Sources/CgRPC/src/core/lib/iomgr/tcp_posix.c index 540305e4f..2f543fd8a 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/tcp_posix.c +++ b/Sources/CgRPC/src/core/lib/iomgr/tcp_posix.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -52,10 +37,13 @@ #include #include #include +#include +#include "src/core/lib/channel/channel_args.h" #include "src/core/lib/debug/trace.h" #include "src/core/lib/iomgr/ev_posix.h" #include "src/core/lib/profiling/timers.h" +#include "src/core/lib/slice/slice_internal.h" #include "src/core/lib/slice/slice_string_helpers.h" #include "src/core/lib/support/string.h" @@ -71,7 +59,7 @@ typedef GRPC_MSG_IOVLEN_TYPE msg_iovlen_type; typedef size_t msg_iovlen_type; #endif -int grpc_tcp_trace = 0; +grpc_tracer_flag grpc_tcp_trace = GRPC_TRACER_INITIALIZER(false, "tcp"); typedef struct { grpc_endpoint base; @@ -79,10 +67,14 @@ typedef struct { int fd; bool finished_edge; msg_iovlen_type iov_size; /* Number of slices to allocate per read attempt */ - size_t slice_size; + double target_length; + double bytes_read_this_round; gpr_refcount refcount; gpr_atm shutdown_count; + int min_read_chunk_size; + int max_read_chunk_size; + /* garbage after the last read */ grpc_slice_buffer last_read_buffer; @@ -107,10 +99,47 @@ typedef struct { grpc_resource_user_slice_allocator slice_allocator; } grpc_tcp; +static void add_to_estimate(grpc_tcp *tcp, size_t bytes) { + tcp->bytes_read_this_round += (double)bytes; +} + +static void finish_estimate(grpc_tcp *tcp) { + /* If we read >80% of the target buffer in one read loop, increase the size + of the target buffer to either the amount read, or twice its previous + value */ + if (tcp->bytes_read_this_round > tcp->target_length * 0.8) { + tcp->target_length = + GPR_MAX(2 * tcp->target_length, tcp->bytes_read_this_round); + } else { + tcp->target_length = + 0.99 * tcp->target_length + 0.01 * tcp->bytes_read_this_round; + } + tcp->bytes_read_this_round = 0; +} + +static size_t get_target_read_size(grpc_tcp *tcp) { + grpc_resource_quota *rq = grpc_resource_user_quota(tcp->resource_user); + double pressure = grpc_resource_quota_get_memory_pressure(rq); + double target = + tcp->target_length * (pressure > 0.8 ? (1.0 - pressure) / 0.2 : 1.0); + size_t sz = (((size_t)GPR_CLAMP(target, tcp->min_read_chunk_size, + tcp->max_read_chunk_size)) + + 255) & + ~(size_t)255; + /* don't use more than 1/16th of the overall resource quota for a single read + * alloc */ + size_t rqmax = grpc_resource_quota_peek_size(rq); + if (sz > rqmax / 16 && rqmax > 1024) { + sz = rqmax / 16; + } + return sz; +} + static grpc_error *tcp_annotate_error(grpc_error *src_error, grpc_tcp *tcp) { return grpc_error_set_str( grpc_error_set_int(src_error, GRPC_ERROR_INT_FD, tcp->fd), - GRPC_ERROR_STR_TARGET_ADDRESS, tcp->peer_string); + GRPC_ERROR_STR_TARGET_ADDRESS, + grpc_slice_from_copied_string(tcp->peer_string)); } static void tcp_handle_read(grpc_exec_ctx *exec_ctx, void *arg /* grpc_tcp */, @@ -118,30 +147,34 @@ static void tcp_handle_read(grpc_exec_ctx *exec_ctx, void *arg /* grpc_tcp */, static void tcp_handle_write(grpc_exec_ctx *exec_ctx, void *arg /* grpc_tcp */, grpc_error *error); -static void tcp_shutdown(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep) { +static void tcp_shutdown(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, + grpc_error *why) { grpc_tcp *tcp = (grpc_tcp *)ep; - grpc_fd_shutdown(exec_ctx, tcp->em_fd); + grpc_fd_shutdown(exec_ctx, tcp->em_fd, why); grpc_resource_user_shutdown(exec_ctx, tcp->resource_user); } static void tcp_free(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp) { grpc_fd_orphan(exec_ctx, tcp->em_fd, tcp->release_fd_cb, tcp->release_fd, - "tcp_unref_orphan"); - grpc_slice_buffer_destroy(&tcp->last_read_buffer); + false /* already_closed */, "tcp_unref_orphan"); + grpc_slice_buffer_destroy_internal(exec_ctx, &tcp->last_read_buffer); grpc_resource_user_unref(exec_ctx, tcp->resource_user); gpr_free(tcp->peer_string); gpr_free(tcp); } -/*#define GRPC_TCP_REFCOUNT_DEBUG*/ -#ifdef GRPC_TCP_REFCOUNT_DEBUG +#ifndef NDEBUG #define TCP_UNREF(cl, tcp, reason) \ tcp_unref((cl), (tcp), (reason), __FILE__, __LINE__) #define TCP_REF(tcp, reason) tcp_ref((tcp), (reason), __FILE__, __LINE__) static void tcp_unref(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp, const char *reason, const char *file, int line) { - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "TCP unref %p : %s %d -> %d", tcp, - reason, tcp->refcount.count, tcp->refcount.count - 1); + if (GRPC_TRACER_ON(grpc_tcp_trace)) { + gpr_atm val = gpr_atm_no_barrier_load(&tcp->refcount.count); + gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, + "TCP unref %p : %s %" PRIdPTR " -> %" PRIdPTR, tcp, reason, val, + val - 1); + } if (gpr_unref(&tcp->refcount)) { tcp_free(exec_ctx, tcp); } @@ -149,8 +182,12 @@ static void tcp_unref(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp, static void tcp_ref(grpc_tcp *tcp, const char *reason, const char *file, int line) { - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "TCP ref %p : %s %d -> %d", tcp, - reason, tcp->refcount.count, tcp->refcount.count + 1); + if (GRPC_TRACER_ON(grpc_tcp_trace)) { + gpr_atm val = gpr_atm_no_barrier_load(&tcp->refcount.count); + gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, + "TCP ref %p : %s %" PRIdPTR " -> %" PRIdPTR, tcp, reason, val, + val + 1); + } gpr_ref(&tcp->refcount); } #else @@ -168,7 +205,7 @@ static void tcp_ref(grpc_tcp *tcp) { gpr_ref(&tcp->refcount); } static void tcp_destroy(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep) { grpc_network_status_unregister_endpoint(ep); grpc_tcp *tcp = (grpc_tcp *)ep; - grpc_slice_buffer_reset_and_unref(&tcp->last_read_buffer); + grpc_slice_buffer_reset_and_unref_internal(exec_ctx, &tcp->last_read_buffer); TCP_UNREF(exec_ctx, tcp, "destroy"); } @@ -176,11 +213,11 @@ static void call_read_cb(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp, grpc_error *error) { grpc_closure *cb = tcp->read_cb; - if (grpc_tcp_trace) { + if (GRPC_TRACER_ON(grpc_tcp_trace)) { size_t i; const char *str = grpc_error_string(error); gpr_log(GPR_DEBUG, "read: error=%s", str); - grpc_error_free_string(str); + for (i = 0; i < tcp->incoming_buffer->count; i++) { char *dump = grpc_dump_slice(tcp->incoming_buffer->slices[i], GPR_DUMP_HEX | GPR_DUMP_ASCII); @@ -191,7 +228,7 @@ static void call_read_cb(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp, tcp->read_cb = NULL; tcp->incoming_buffer = NULL; - grpc_closure_run(exec_ctx, cb, error); + GRPC_CLOSURE_RUN(exec_ctx, cb, error); } #define MAX_READ_IOVEC 4 @@ -229,32 +266,32 @@ static void tcp_do_read(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp) { /* NB: After calling call_read_cb a parallel call of the read handler may * be running. */ if (errno == EAGAIN) { - if (tcp->iov_size > 1) { - tcp->iov_size /= 2; - } + finish_estimate(tcp); /* We've consumed the edge, request a new one */ grpc_fd_notify_on_read(exec_ctx, tcp->em_fd, &tcp->read_closure); } else { - grpc_slice_buffer_reset_and_unref(tcp->incoming_buffer); + grpc_slice_buffer_reset_and_unref_internal(exec_ctx, + tcp->incoming_buffer); call_read_cb(exec_ctx, tcp, tcp_annotate_error(GRPC_OS_ERROR(errno, "recvmsg"), tcp)); TCP_UNREF(exec_ctx, tcp, "read"); } } else if (read_bytes == 0) { /* 0 read size ==> end of stream */ - grpc_slice_buffer_reset_and_unref(tcp->incoming_buffer); - call_read_cb(exec_ctx, tcp, - tcp_annotate_error(GRPC_ERROR_CREATE("Socket closed"), tcp)); + grpc_slice_buffer_reset_and_unref_internal(exec_ctx, tcp->incoming_buffer); + call_read_cb( + exec_ctx, tcp, + tcp_annotate_error( + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Socket closed"), tcp)); TCP_UNREF(exec_ctx, tcp, "read"); } else { + add_to_estimate(tcp, (size_t)read_bytes); GPR_ASSERT((size_t)read_bytes <= tcp->incoming_buffer->length); if ((size_t)read_bytes < tcp->incoming_buffer->length) { grpc_slice_buffer_trim_end( tcp->incoming_buffer, tcp->incoming_buffer->length - (size_t)read_bytes, &tcp->last_read_buffer); - } else if (tcp->iov_size < MAX_READ_IOVEC) { - ++tcp->iov_size; } GPR_ASSERT((size_t)read_bytes == tcp->incoming_buffer->length); call_read_cb(exec_ctx, tcp, GRPC_ERROR_NONE); @@ -268,8 +305,9 @@ static void tcp_read_allocation_done(grpc_exec_ctx *exec_ctx, void *tcpp, grpc_error *error) { grpc_tcp *tcp = tcpp; if (error != GRPC_ERROR_NONE) { - grpc_slice_buffer_reset_and_unref(tcp->incoming_buffer); - grpc_slice_buffer_reset_and_unref(&tcp->last_read_buffer); + grpc_slice_buffer_reset_and_unref_internal(exec_ctx, tcp->incoming_buffer); + grpc_slice_buffer_reset_and_unref_internal(exec_ctx, + &tcp->last_read_buffer); call_read_cb(exec_ctx, tcp, GRPC_ERROR_REF(error)); TCP_UNREF(exec_ctx, tcp, "read"); } else { @@ -278,11 +316,11 @@ static void tcp_read_allocation_done(grpc_exec_ctx *exec_ctx, void *tcpp, } static void tcp_continue_read(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp) { - if (tcp->incoming_buffer->count < (size_t)tcp->iov_size) { - grpc_resource_user_alloc_slices( - exec_ctx, &tcp->slice_allocator, tcp->slice_size, - (size_t)tcp->iov_size - tcp->incoming_buffer->count, - tcp->incoming_buffer); + size_t target_read_size = get_target_read_size(tcp); + if (tcp->incoming_buffer->length < target_read_size && + tcp->incoming_buffer->count < MAX_READ_IOVEC) { + grpc_resource_user_alloc_slices(exec_ctx, &tcp->slice_allocator, + target_read_size, 1, tcp->incoming_buffer); } else { tcp_do_read(exec_ctx, tcp); } @@ -294,8 +332,9 @@ static void tcp_handle_read(grpc_exec_ctx *exec_ctx, void *arg /* grpc_tcp */, GPR_ASSERT(!tcp->finished_edge); if (error != GRPC_ERROR_NONE) { - grpc_slice_buffer_reset_and_unref(tcp->incoming_buffer); - grpc_slice_buffer_reset_and_unref(&tcp->last_read_buffer); + grpc_slice_buffer_reset_and_unref_internal(exec_ctx, tcp->incoming_buffer); + grpc_slice_buffer_reset_and_unref_internal(exec_ctx, + &tcp->last_read_buffer); call_read_cb(exec_ctx, tcp, GRPC_ERROR_REF(error)); TCP_UNREF(exec_ctx, tcp, "read"); } else { @@ -309,14 +348,14 @@ static void tcp_read(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, GPR_ASSERT(tcp->read_cb == NULL); tcp->read_cb = cb; tcp->incoming_buffer = incoming_buffer; - grpc_slice_buffer_reset_and_unref(incoming_buffer); + grpc_slice_buffer_reset_and_unref_internal(exec_ctx, incoming_buffer); grpc_slice_buffer_swap(incoming_buffer, &tcp->last_read_buffer); TCP_REF(tcp, "read"); if (tcp->finished_edge) { tcp->finished_edge = false; grpc_fd_notify_on_read(exec_ctx, tcp->em_fd, &tcp->read_closure); } else { - grpc_exec_ctx_sched(exec_ctx, &tcp->read_closure, GRPC_ERROR_NONE, NULL); + GRPC_CLOSURE_SCHED(exec_ctx, &tcp->read_closure, GRPC_ERROR_NONE); } } @@ -421,20 +460,19 @@ static void tcp_handle_write(grpc_exec_ctx *exec_ctx, void *arg /* grpc_tcp */, } if (!tcp_flush(tcp, &error)) { - if (grpc_tcp_trace) { + if (GRPC_TRACER_ON(grpc_tcp_trace)) { gpr_log(GPR_DEBUG, "write: delayed"); } grpc_fd_notify_on_write(exec_ctx, tcp->em_fd, &tcp->write_closure); } else { cb = tcp->write_cb; tcp->write_cb = NULL; - if (grpc_tcp_trace) { + if (GRPC_TRACER_ON(grpc_tcp_trace)) { const char *str = grpc_error_string(error); gpr_log(GPR_DEBUG, "write: %s", str); - grpc_error_free_string(str); } - grpc_closure_run(exec_ctx, cb, error); + GRPC_CLOSURE_RUN(exec_ctx, cb, error); TCP_UNREF(exec_ctx, tcp, "write"); } } @@ -444,7 +482,7 @@ static void tcp_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, grpc_tcp *tcp = (grpc_tcp *)ep; grpc_error *error = GRPC_ERROR_NONE; - if (grpc_tcp_trace) { + if (GRPC_TRACER_ON(grpc_tcp_trace)) { size_t i; for (i = 0; i < buf->count; i++) { @@ -460,11 +498,12 @@ static void tcp_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, if (buf->length == 0) { GPR_TIMER_END("tcp_write", 0); - grpc_exec_ctx_sched(exec_ctx, cb, - grpc_fd_is_shutdown(tcp->em_fd) - ? tcp_annotate_error(GRPC_ERROR_CREATE("EOF"), tcp) - : GRPC_ERROR_NONE, - NULL); + GRPC_CLOSURE_SCHED( + exec_ctx, cb, + grpc_fd_is_shutdown(tcp->em_fd) + ? tcp_annotate_error(GRPC_ERROR_CREATE_FROM_STATIC_STRING("EOF"), + tcp) + : GRPC_ERROR_NONE); return; } tcp->outgoing_buffer = buf; @@ -474,17 +513,16 @@ static void tcp_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, if (!tcp_flush(tcp, &error)) { TCP_REF(tcp, "write"); tcp->write_cb = cb; - if (grpc_tcp_trace) { + if (GRPC_TRACER_ON(grpc_tcp_trace)) { gpr_log(GPR_DEBUG, "write: delayed"); } grpc_fd_notify_on_write(exec_ctx, tcp->em_fd, &tcp->write_closure); } else { - if (grpc_tcp_trace) { + if (GRPC_TRACER_ON(grpc_tcp_trace)) { const char *str = grpc_error_string(error); gpr_log(GPR_DEBUG, "write: %s", str); - grpc_error_free_string(str); } - grpc_exec_ctx_sched(exec_ctx, cb, error, NULL); + GRPC_CLOSURE_SCHED(exec_ctx, cb, error); } GPR_TIMER_END("tcp_write", 0); @@ -512,30 +550,60 @@ static int tcp_get_fd(grpc_endpoint *ep) { return tcp->fd; } -static grpc_workqueue *tcp_get_workqueue(grpc_endpoint *ep) { - grpc_tcp *tcp = (grpc_tcp *)ep; - return grpc_fd_get_workqueue(tcp->em_fd); -} - static grpc_resource_user *tcp_get_resource_user(grpc_endpoint *ep) { grpc_tcp *tcp = (grpc_tcp *)ep; return tcp->resource_user; } -static const grpc_endpoint_vtable vtable = {tcp_read, - tcp_write, - tcp_get_workqueue, - tcp_add_to_pollset, - tcp_add_to_pollset_set, - tcp_shutdown, - tcp_destroy, - tcp_get_resource_user, - tcp_get_peer, - tcp_get_fd}; - -grpc_endpoint *grpc_tcp_create(grpc_fd *em_fd, - grpc_resource_quota *resource_quota, - size_t slice_size, const char *peer_string) { +static const grpc_endpoint_vtable vtable = { + tcp_read, tcp_write, tcp_add_to_pollset, tcp_add_to_pollset_set, + tcp_shutdown, tcp_destroy, tcp_get_resource_user, tcp_get_peer, + tcp_get_fd}; + +#define MAX_CHUNK_SIZE 32 * 1024 * 1024 + +grpc_endpoint *grpc_tcp_create(grpc_exec_ctx *exec_ctx, grpc_fd *em_fd, + const grpc_channel_args *channel_args, + const char *peer_string) { + int tcp_read_chunk_size = GRPC_TCP_DEFAULT_READ_SLICE_SIZE; + int tcp_max_read_chunk_size = 4 * 1024 * 1024; + int tcp_min_read_chunk_size = 256; + grpc_resource_quota *resource_quota = grpc_resource_quota_create(NULL); + if (channel_args != NULL) { + for (size_t i = 0; i < channel_args->num_args; i++) { + if (0 == + strcmp(channel_args->args[i].key, GRPC_ARG_TCP_READ_CHUNK_SIZE)) { + grpc_integer_options options = {(int)tcp_read_chunk_size, 1, + MAX_CHUNK_SIZE}; + tcp_read_chunk_size = + grpc_channel_arg_get_integer(&channel_args->args[i], options); + } else if (0 == strcmp(channel_args->args[i].key, + GRPC_ARG_TCP_MIN_READ_CHUNK_SIZE)) { + grpc_integer_options options = {(int)tcp_read_chunk_size, 1, + MAX_CHUNK_SIZE}; + tcp_min_read_chunk_size = + grpc_channel_arg_get_integer(&channel_args->args[i], options); + } else if (0 == strcmp(channel_args->args[i].key, + GRPC_ARG_TCP_MAX_READ_CHUNK_SIZE)) { + grpc_integer_options options = {(int)tcp_read_chunk_size, 1, + MAX_CHUNK_SIZE}; + tcp_max_read_chunk_size = + grpc_channel_arg_get_integer(&channel_args->args[i], options); + } else if (0 == + strcmp(channel_args->args[i].key, GRPC_ARG_RESOURCE_QUOTA)) { + grpc_resource_quota_unref_internal(exec_ctx, resource_quota); + resource_quota = grpc_resource_quota_ref_internal( + channel_args->args[i].value.pointer.p); + } + } + } + + if (tcp_min_read_chunk_size > tcp_max_read_chunk_size) { + tcp_min_read_chunk_size = tcp_max_read_chunk_size; + } + tcp_read_chunk_size = GPR_CLAMP(tcp_read_chunk_size, tcp_min_read_chunk_size, + tcp_max_read_chunk_size); + grpc_tcp *tcp = (grpc_tcp *)gpr_malloc(sizeof(grpc_tcp)); tcp->base.vtable = &vtable; tcp->peer_string = gpr_strdup(peer_string); @@ -545,23 +613,27 @@ grpc_endpoint *grpc_tcp_create(grpc_fd *em_fd, tcp->release_fd_cb = NULL; tcp->release_fd = NULL; tcp->incoming_buffer = NULL; - tcp->slice_size = slice_size; + tcp->target_length = (double)tcp_read_chunk_size; + tcp->min_read_chunk_size = tcp_min_read_chunk_size; + tcp->max_read_chunk_size = tcp_max_read_chunk_size; + tcp->bytes_read_this_round = 0; tcp->iov_size = 1; tcp->finished_edge = true; /* paired with unref in grpc_tcp_destroy */ gpr_ref_init(&tcp->refcount, 1); gpr_atm_no_barrier_store(&tcp->shutdown_count, 0); tcp->em_fd = em_fd; - tcp->read_closure.cb = tcp_handle_read; - tcp->read_closure.cb_arg = tcp; - tcp->write_closure.cb = tcp_handle_write; - tcp->write_closure.cb_arg = tcp; + GRPC_CLOSURE_INIT(&tcp->read_closure, tcp_handle_read, tcp, + grpc_schedule_on_exec_ctx); + GRPC_CLOSURE_INIT(&tcp->write_closure, tcp_handle_write, tcp, + grpc_schedule_on_exec_ctx); grpc_slice_buffer_init(&tcp->last_read_buffer); tcp->resource_user = grpc_resource_user_create(resource_quota, peer_string); grpc_resource_user_slice_allocator_init( &tcp->slice_allocator, tcp->resource_user, tcp_read_allocation_done, tcp); /* Tell network status tracker about new endpoint */ grpc_network_status_register_endpoint(&tcp->base); + grpc_resource_quota_unref_internal(exec_ctx, resource_quota); return &tcp->base; } @@ -579,7 +651,7 @@ void grpc_tcp_destroy_and_release_fd(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, GPR_ASSERT(ep->vtable == &vtable); tcp->release_fd = fd; tcp->release_fd_cb = done; - grpc_slice_buffer_reset_and_unref(&tcp->last_read_buffer); + grpc_slice_buffer_reset_and_unref_internal(exec_ctx, &tcp->last_read_buffer); TCP_UNREF(exec_ctx, tcp, "destroy"); } diff --git a/Sources/CgRPC/src/core/lib/iomgr/tcp_posix.h b/Sources/CgRPC/src/core/lib/iomgr/tcp_posix.h index 1c0d13f96..6831a4a57 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/tcp_posix.h +++ b/Sources/CgRPC/src/core/lib/iomgr/tcp_posix.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -44,17 +29,17 @@ otherwise specified. */ +#include "src/core/lib/debug/trace.h" #include "src/core/lib/iomgr/endpoint.h" #include "src/core/lib/iomgr/ev_posix.h" -#define GRPC_TCP_DEFAULT_READ_SLICE_SIZE 8192 - -extern int grpc_tcp_trace; +extern grpc_tracer_flag grpc_tcp_trace; /* Create a tcp endpoint given a file desciptor and a read slice size. Takes ownership of fd. */ -grpc_endpoint *grpc_tcp_create(grpc_fd *fd, grpc_resource_quota *resource_quota, - size_t read_slice_size, const char *peer_string); +grpc_endpoint *grpc_tcp_create(grpc_exec_ctx *exec_ctx, grpc_fd *fd, + const grpc_channel_args *args, + const char *peer_string); /* Return the tcp endpoint's fd, or -1 if this is not available. Does not release the fd. diff --git a/Sources/CgRPC/src/core/lib/iomgr/tcp_server.h b/Sources/CgRPC/src/core/lib/iomgr/tcp_server.h index 437a94bef..8a126b6de 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/tcp_server.h +++ b/Sources/CgRPC/src/core/lib/iomgr/tcp_server.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/tcp_server_posix.c b/Sources/CgRPC/src/core/lib/iomgr/tcp_server_posix.c index 179f47ef7..0fc5c0fd8 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/tcp_server_posix.c +++ b/Sources/CgRPC/src/core/lib/iomgr/tcp_server_posix.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -44,10 +29,8 @@ #include #include -#include #include #include -#include #include #include #include @@ -61,83 +44,16 @@ #include #include +#include "src/core/lib/channel/channel_args.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_posix.h" #include "src/core/lib/iomgr/tcp_posix.h" +#include "src/core/lib/iomgr/tcp_server_utils_posix.h" #include "src/core/lib/iomgr/unix_sockets_posix.h" #include "src/core/lib/support/string.h" -#define MIN_SAFE_ACCEPT_QUEUE_SIZE 100 - -static gpr_once s_init_max_accept_queue_size; -static int s_max_accept_queue_size; - -/* one listening port */ -typedef struct grpc_tcp_listener grpc_tcp_listener; -struct grpc_tcp_listener { - int fd; - grpc_fd *emfd; - grpc_tcp_server *server; - grpc_resolved_address addr; - int port; - unsigned port_index; - unsigned fd_index; - grpc_closure read_closure; - grpc_closure destroyed_closure; - struct grpc_tcp_listener *next; - /* sibling is a linked list of all listeners for a given port. add_port and - clone_port place all new listeners in the same sibling list. A member of - the 'sibling' list is also a member of the 'next' list. The head of each - sibling list has is_sibling==0, and subsequent members of sibling lists - have is_sibling==1. is_sibling allows separate sibling lists to be - identified while iterating through 'next'. */ - struct grpc_tcp_listener *sibling; - int is_sibling; -}; - -/* the overall server */ -struct grpc_tcp_server { - gpr_refcount refs; - /* Called whenever accept() succeeds on a server port. */ - grpc_tcp_server_cb on_accept_cb; - void *on_accept_cb_arg; - - gpr_mu mu; - - /* active port count: how many ports are actually still listening */ - size_t active_ports; - /* destroyed port count: how many ports are completely destroyed */ - size_t destroyed_ports; - - /* is this server shutting down? */ - bool shutdown; - /* use SO_REUSEPORT */ - bool so_reuseport; - - /* linked list of server ports */ - grpc_tcp_listener *head; - grpc_tcp_listener *tail; - unsigned nports; - - /* List of closures passed to shutdown_starting_add(). */ - grpc_closure_list shutdown_starting; - - /* shutdown callback */ - grpc_closure *shutdown_complete; - - /* all pollsets interested in new connections */ - grpc_pollset **pollsets; - /* number of pollsets in the pollsets array */ - size_t pollset_count; - - /* next pollset to assign a channel to */ - gpr_atm next_pollset_to_assign; - - grpc_resource_quota *resource_quota; -}; - static gpr_once check_init = GPR_ONCE_INIT; static bool has_so_reuseport = false; @@ -158,30 +74,26 @@ grpc_error *grpc_tcp_server_create(grpc_exec_ctx *exec_ctx, grpc_tcp_server **server) { gpr_once_init(&check_init, init); - grpc_tcp_server *s = gpr_malloc(sizeof(grpc_tcp_server)); + grpc_tcp_server *s = gpr_zalloc(sizeof(grpc_tcp_server)); s->so_reuseport = has_so_reuseport; - s->resource_quota = grpc_resource_quota_create(NULL); + s->expand_wildcard_addrs = false; for (size_t i = 0; i < (args == NULL ? 0 : args->num_args); i++) { if (0 == strcmp(GRPC_ARG_ALLOW_REUSEPORT, args->args[i].key)) { if (args->args[i].type == GRPC_ARG_INTEGER) { s->so_reuseport = has_so_reuseport && (args->args[i].value.integer != 0); } else { - grpc_resource_quota_internal_unref(exec_ctx, s->resource_quota); gpr_free(s); - return GRPC_ERROR_CREATE(GRPC_ARG_ALLOW_REUSEPORT - " must be an integer"); + return GRPC_ERROR_CREATE_FROM_STATIC_STRING(GRPC_ARG_ALLOW_REUSEPORT + " must be an integer"); } - } else if (0 == strcmp(GRPC_ARG_RESOURCE_QUOTA, args->args[i].key)) { - if (args->args[i].type == GRPC_ARG_POINTER) { - grpc_resource_quota_internal_unref(exec_ctx, s->resource_quota); - s->resource_quota = - grpc_resource_quota_internal_ref(args->args[i].value.pointer.p); + } else if (0 == strcmp(GRPC_ARG_EXPAND_WILDCARD_ADDRS, args->args[i].key)) { + if (args->args[i].type == GRPC_ARG_INTEGER) { + s->expand_wildcard_addrs = (args->args[i].value.integer != 0); } else { - grpc_resource_quota_internal_unref(exec_ctx, s->resource_quota); gpr_free(s); - return GRPC_ERROR_CREATE(GRPC_ARG_RESOURCE_QUOTA - " must be a pointer to a buffer pool"); + return GRPC_ERROR_CREATE_FROM_STATIC_STRING( + GRPC_ARG_EXPAND_WILDCARD_ADDRS " must be an integer"); } } } @@ -198,6 +110,7 @@ grpc_error *grpc_tcp_server_create(grpc_exec_ctx *exec_ctx, s->head = NULL; s->tail = NULL; s->nports = 0; + s->channel_args = grpc_channel_args_copy(args); gpr_atm_no_barrier_store(&s->next_pollset_to_assign, 0); *server = s; return GRPC_ERROR_NONE; @@ -208,7 +121,7 @@ static void finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) { GPR_ASSERT(s->shutdown); gpr_mu_unlock(&s->mu); if (s->shutdown_complete != NULL) { - grpc_exec_ctx_sched(exec_ctx, s->shutdown_complete, GRPC_ERROR_NONE, NULL); + GRPC_CLOSURE_SCHED(exec_ctx, s->shutdown_complete, GRPC_ERROR_NONE); } gpr_mu_destroy(&s->mu); @@ -218,8 +131,7 @@ static void finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) { s->head = sp->next; gpr_free(sp); } - - grpc_resource_quota_internal_unref(exec_ctx, s->resource_quota); + grpc_channel_args_destroy(exec_ctx, s->channel_args); gpr_free(s); } @@ -245,19 +157,16 @@ static void deactivated_all_ports(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) { /* delete ALL the things */ gpr_mu_lock(&s->mu); - if (!s->shutdown) { - gpr_mu_unlock(&s->mu); - return; - } + GPR_ASSERT(s->shutdown); if (s->head) { grpc_tcp_listener *sp; for (sp = s->head; sp; sp = sp->next) { grpc_unlink_if_unix_domain_socket(&sp->addr); - sp->destroyed_closure.cb = destroyed_port; - sp->destroyed_closure.cb_arg = s; + GRPC_CLOSURE_INIT(&sp->destroyed_closure, destroyed_port, s, + grpc_schedule_on_exec_ctx); grpc_fd_orphan(exec_ctx, sp->emfd, &sp->destroyed_closure, NULL, - "tcp_listener_shutdown"); + false /* already_closed */, "tcp_listener_shutdown"); } gpr_mu_unlock(&s->mu); } else { @@ -276,7 +185,8 @@ static void tcp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) { if (s->active_ports) { grpc_tcp_listener *sp; for (sp = s->head; sp; sp = sp->next) { - grpc_fd_shutdown(exec_ctx, sp->emfd); + grpc_fd_shutdown(exec_ctx, sp->emfd, GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "Server destroyed")); } gpr_mu_unlock(&s->mu); } else { @@ -285,99 +195,6 @@ static void tcp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) { } } -/* get max listen queue size on linux */ -static void init_max_accept_queue_size(void) { - int n = SOMAXCONN; - char buf[64]; - FILE *fp = fopen("/proc/sys/net/core/somaxconn", "r"); - if (fp == NULL) { - /* 2.4 kernel. */ - s_max_accept_queue_size = SOMAXCONN; - return; - } - if (fgets(buf, sizeof buf, fp)) { - char *end; - long i = strtol(buf, &end, 10); - if (i > 0 && i <= INT_MAX && end && *end == 0) { - n = (int)i; - } - } - fclose(fp); - s_max_accept_queue_size = n; - - if (s_max_accept_queue_size < MIN_SAFE_ACCEPT_QUEUE_SIZE) { - gpr_log(GPR_INFO, - "Suspiciously small accept queue (%d) will probably lead to " - "connection drops", - s_max_accept_queue_size); - } -} - -static int get_max_accept_queue_size(void) { - gpr_once_init(&s_init_max_accept_queue_size, init_max_accept_queue_size); - return s_max_accept_queue_size; -} - -/* Prepare a recently-created socket for listening. */ -static grpc_error *prepare_socket(int fd, const grpc_resolved_address *addr, - bool so_reuseport, int *port) { - grpc_resolved_address sockname_temp; - grpc_error *err = GRPC_ERROR_NONE; - - GPR_ASSERT(fd >= 0); - - if (so_reuseport && !grpc_is_unix_socket(addr)) { - err = grpc_set_socket_reuse_port(fd, 1); - if (err != GRPC_ERROR_NONE) goto error; - } - - err = grpc_set_socket_nonblocking(fd, 1); - if (err != GRPC_ERROR_NONE) goto error; - err = grpc_set_socket_cloexec(fd, 1); - if (err != GRPC_ERROR_NONE) goto error; - if (!grpc_is_unix_socket(addr)) { - err = grpc_set_socket_low_latency(fd, 1); - if (err != GRPC_ERROR_NONE) goto error; - err = grpc_set_socket_reuse_addr(fd, 1); - if (err != GRPC_ERROR_NONE) goto error; - } - err = grpc_set_socket_no_sigpipe_if_possible(fd); - if (err != GRPC_ERROR_NONE) goto error; - - GPR_ASSERT(addr->len < ~(socklen_t)0); - if (bind(fd, (struct sockaddr *)addr->addr, (socklen_t)addr->len) < 0) { - err = GRPC_OS_ERROR(errno, "bind"); - goto error; - } - - if (listen(fd, get_max_accept_queue_size()) < 0) { - err = GRPC_OS_ERROR(errno, "listen"); - goto error; - } - - sockname_temp.len = sizeof(struct sockaddr_storage); - - if (getsockname(fd, (struct sockaddr *)sockname_temp.addr, - (socklen_t *)&sockname_temp.len) < 0) { - err = GRPC_OS_ERROR(errno, "getsockname"); - goto error; - } - - *port = grpc_sockaddr_get_port(&sockname_temp); - return GRPC_ERROR_NONE; - -error: - GPR_ASSERT(err != GRPC_ERROR_NONE); - if (fd >= 0) { - close(fd); - } - grpc_error *ret = grpc_error_set_int( - GRPC_ERROR_CREATE_REFERENCING("Unable to configure socket", &err, 1), - GRPC_ERROR_INT_FD, fd); - GRPC_ERROR_UNREF(err); - return ret; -} - /* event manager callback when reads are ready */ static void on_read(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *err) { grpc_tcp_listener *sp = arg; @@ -408,7 +225,14 @@ static void on_read(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *err) { grpc_fd_notify_on_read(exec_ctx, sp->emfd, &sp->read_closure); return; default: - gpr_log(GPR_ERROR, "Failed accept4: %s", strerror(errno)); + gpr_mu_lock(&sp->server->mu); + if (!sp->server->shutdown_listeners) { + gpr_log(GPR_ERROR, "Failed accept4: %s", strerror(errno)); + } else { + /* if we have shutdown listeners, accept4 could fail, and we + needn't notify users */ + } + gpr_mu_unlock(&sp->server->mu); goto error; } } @@ -418,17 +242,12 @@ static void on_read(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *err) { addr_str = grpc_sockaddr_to_uri(&addr); gpr_asprintf(&name, "tcp-server-connection:%s", addr_str); - if (grpc_tcp_trace) { + if (GRPC_TRACER_ON(grpc_tcp_trace)) { gpr_log(GPR_DEBUG, "SERVER_CONNECT: incoming connection: %s", addr_str); } grpc_fd *fdobj = grpc_fd_create(fd, name); - if (read_notifier_pollset == NULL) { - gpr_log(GPR_ERROR, "Read notifier pollset is not set on the fd"); - goto error; - } - grpc_pollset_add_fd(exec_ctx, read_notifier_pollset, fdobj); // Create acceptor. @@ -439,8 +258,7 @@ static void on_read(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *err) { sp->server->on_accept_cb( exec_ctx, sp->server->on_accept_cb_arg, - grpc_tcp_create(fdobj, sp->server->resource_quota, - GRPC_TCP_DEFAULT_READ_SLICE_SIZE, addr_str), + grpc_tcp_create(exec_ctx, fdobj, sp->server->channel_args, addr_str), read_notifier_pollset, acceptor); gpr_free(name); @@ -451,7 +269,7 @@ static void on_read(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *err) { error: gpr_mu_lock(&sp->server->mu); - if (0 == --sp->server->active_ports) { + if (0 == --sp->server->active_ports && sp->server->shutdown) { gpr_mu_unlock(&sp->server->mu); deactivated_all_ports(exec_ctx, sp->server); } else { @@ -459,53 +277,72 @@ static void on_read(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *err) { } } -static grpc_error *add_socket_to_server(grpc_tcp_server *s, int fd, - const grpc_resolved_address *addr, - unsigned port_index, unsigned fd_index, - grpc_tcp_listener **listener) { +/* Treat :: or 0.0.0.0 as a family-agnostic wildcard. */ +static grpc_error *add_wildcard_addrs_to_server(grpc_tcp_server *s, + unsigned port_index, + int requested_port, + int *out_port) { + grpc_resolved_address wild4; + grpc_resolved_address wild6; + unsigned fd_index = 0; + grpc_dualstack_mode dsmode; grpc_tcp_listener *sp = NULL; - int port = -1; - char *addr_str; - char *name; - - grpc_error *err = prepare_socket(fd, addr, s->so_reuseport, &port); - if (err == GRPC_ERROR_NONE) { - GPR_ASSERT(port > 0); - grpc_sockaddr_to_string(&addr_str, addr, 1); - gpr_asprintf(&name, "tcp-server-listener:%s", addr_str); - gpr_mu_lock(&s->mu); - s->nports++; - GPR_ASSERT(!s->on_accept_cb && "must add ports before starting server"); - sp = gpr_malloc(sizeof(grpc_tcp_listener)); - sp->next = NULL; - if (s->head == NULL) { - s->head = sp; - } else { - s->tail->next = sp; + grpc_tcp_listener *sp2 = NULL; + grpc_error *v6_err = GRPC_ERROR_NONE; + grpc_error *v4_err = GRPC_ERROR_NONE; + *out_port = -1; + + if (grpc_tcp_server_have_ifaddrs() && s->expand_wildcard_addrs) { + return grpc_tcp_server_add_all_local_addrs(s, port_index, requested_port, + out_port); + } + + grpc_sockaddr_make_wildcards(requested_port, &wild4, &wild6); + /* Try listening on IPv6 first. */ + if ((v6_err = grpc_tcp_server_add_addr(s, &wild6, port_index, fd_index, + &dsmode, &sp)) == GRPC_ERROR_NONE) { + ++fd_index; + requested_port = *out_port = sp->port; + if (dsmode == GRPC_DSMODE_DUALSTACK || dsmode == GRPC_DSMODE_IPV4) { + return GRPC_ERROR_NONE; } - s->tail = sp; - sp->server = s; - sp->fd = fd; - sp->emfd = grpc_fd_create(fd, name); - memcpy(&sp->addr, addr, sizeof(grpc_resolved_address)); - sp->port = port; - sp->port_index = port_index; - sp->fd_index = fd_index; - sp->is_sibling = 0; - sp->sibling = NULL; - GPR_ASSERT(sp->emfd); - gpr_mu_unlock(&s->mu); - gpr_free(addr_str); - gpr_free(name); } - - *listener = sp; - return err; + /* If we got a v6-only socket or nothing, try adding 0.0.0.0. */ + grpc_sockaddr_set_port(&wild4, requested_port); + if ((v4_err = grpc_tcp_server_add_addr(s, &wild4, port_index, fd_index, + &dsmode, &sp2)) == GRPC_ERROR_NONE) { + *out_port = sp2->port; + if (sp != NULL) { + sp2->is_sibling = 1; + sp->sibling = sp2; + } + } + if (*out_port > 0) { + if (v6_err != GRPC_ERROR_NONE) { + gpr_log(GPR_INFO, + "Failed to add :: listener, " + "the environment may not support IPv6: %s", + grpc_error_string(v6_err)); + GRPC_ERROR_UNREF(v6_err); + } + if (v4_err != GRPC_ERROR_NONE) { + gpr_log(GPR_INFO, + "Failed to add 0.0.0.0 listener, " + "the environment may not support IPv4: %s", + grpc_error_string(v4_err)); + GRPC_ERROR_UNREF(v4_err); + } + return GRPC_ERROR_NONE; + } else { + grpc_error *root_err = GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "Failed to add any wildcard listeners"); + GPR_ASSERT(v6_err != GRPC_ERROR_NONE && v4_err != GRPC_ERROR_NONE); + root_err = grpc_error_add_child(root_err, v6_err); + root_err = grpc_error_add_child(root_err, v4_err); + return root_err; + } } -/* Insert count new listeners after listener. Every new listener will have the - same listen address as listener (SO_REUSEPORT must be enabled). Every new - listener is a sibling of listener. */ static grpc_error *clone_port(grpc_tcp_listener *listener, unsigned count) { grpc_tcp_listener *sp = NULL; char *addr_str; @@ -523,7 +360,7 @@ static grpc_error *clone_port(grpc_tcp_listener *listener, unsigned count) { err = grpc_create_dualstack_socket(&listener->addr, SOCK_STREAM, 0, &dsmode, &fd); if (err != GRPC_ERROR_NONE) return err; - err = prepare_socket(fd, &listener->addr, true, &port); + err = grpc_tcp_server_prepare_socket(fd, &listener->addr, true, &port); if (err != GRPC_ERROR_NONE) return err; listener->server->nports++; grpc_sockaddr_to_string(&addr_str, &listener->addr, 1); @@ -558,19 +395,13 @@ grpc_error *grpc_tcp_server_add_port(grpc_tcp_server *s, const grpc_resolved_address *addr, int *out_port) { grpc_tcp_listener *sp; - grpc_tcp_listener *sp2 = NULL; - int fd; - grpc_dualstack_mode dsmode; - grpc_resolved_address addr6_v4mapped; - grpc_resolved_address wild4; - grpc_resolved_address wild6; - grpc_resolved_address addr4_copy; - grpc_resolved_address *allocated_addr = NULL; grpc_resolved_address sockname_temp; - int port; + grpc_resolved_address addr6_v4mapped; + int requested_port = grpc_sockaddr_get_port(addr); unsigned port_index = 0; - unsigned fd_index = 0; - grpc_error *errs[2] = {GRPC_ERROR_NONE, GRPC_ERROR_NONE}; + grpc_dualstack_mode dsmode; + grpc_error *err; + *out_port = -1; if (s->tail != NULL) { port_index = s->tail->port_index + 1; } @@ -578,85 +409,34 @@ grpc_error *grpc_tcp_server_add_port(grpc_tcp_server *s, /* Check if this is a wildcard port, and if so, try to keep the port the same as some previously created listener. */ - if (grpc_sockaddr_get_port(addr) == 0) { + if (requested_port == 0) { for (sp = s->head; sp; sp = sp->next) { sockname_temp.len = sizeof(struct sockaddr_storage); - if (0 == getsockname(sp->fd, (struct sockaddr *)sockname_temp.addr, + if (0 == getsockname(sp->fd, (struct sockaddr *)&sockname_temp.addr, (socklen_t *)&sockname_temp.len)) { - port = grpc_sockaddr_get_port(&sockname_temp); - if (port > 0) { - allocated_addr = gpr_malloc(sizeof(grpc_resolved_address)); - memcpy(allocated_addr, addr, addr->len); - grpc_sockaddr_set_port(allocated_addr, port); - addr = allocated_addr; + int used_port = grpc_sockaddr_get_port(&sockname_temp); + if (used_port > 0) { + memcpy(&sockname_temp, addr, sizeof(grpc_resolved_address)); + grpc_sockaddr_set_port(&sockname_temp, used_port); + requested_port = used_port; + addr = &sockname_temp; break; } } } } - - sp = NULL; - + if (grpc_sockaddr_is_wildcard(addr, &requested_port)) { + return add_wildcard_addrs_to_server(s, port_index, requested_port, + out_port); + } if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) { addr = &addr6_v4mapped; } - - /* Treat :: or 0.0.0.0 as a family-agnostic wildcard. */ - if (grpc_sockaddr_is_wildcard(addr, &port)) { - grpc_sockaddr_make_wildcards(port, &wild4, &wild6); - - /* Try listening on IPv6 first. */ - addr = &wild6; - errs[0] = grpc_create_dualstack_socket(addr, SOCK_STREAM, 0, &dsmode, &fd); - if (errs[0] == GRPC_ERROR_NONE) { - errs[0] = add_socket_to_server(s, fd, addr, port_index, fd_index, &sp); - if (fd >= 0 && dsmode == GRPC_DSMODE_DUALSTACK) { - goto done; - } - if (sp != NULL) { - ++fd_index; - } - /* If we didn't get a dualstack socket, also listen on 0.0.0.0. */ - if (port == 0 && sp != NULL) { - grpc_sockaddr_set_port(&wild4, sp->port); - } - } - addr = &wild4; - } - - errs[1] = grpc_create_dualstack_socket(addr, SOCK_STREAM, 0, &dsmode, &fd); - if (errs[1] == GRPC_ERROR_NONE) { - if (dsmode == GRPC_DSMODE_IPV4 && - grpc_sockaddr_is_v4mapped(addr, &addr4_copy)) { - addr = &addr4_copy; - } - sp2 = sp; - errs[1] = add_socket_to_server(s, fd, addr, port_index, fd_index, &sp); - if (sp2 != NULL && sp != NULL) { - sp2->sibling = sp; - sp->is_sibling = 1; - } - } - -done: - gpr_free(allocated_addr); - if (sp != NULL) { + if ((err = grpc_tcp_server_add_addr(s, addr, port_index, 0, &dsmode, &sp)) == + GRPC_ERROR_NONE) { *out_port = sp->port; - GRPC_ERROR_UNREF(errs[0]); - GRPC_ERROR_UNREF(errs[1]); - return GRPC_ERROR_NONE; - } else { - *out_port = -1; - char *addr_str = grpc_sockaddr_to_uri(addr); - grpc_error *err = grpc_error_set_str( - GRPC_ERROR_CREATE_REFERENCING("Failed to add port to server", errs, - GPR_ARRAY_SIZE(errs)), - GRPC_ERROR_STR_TARGET_ADDRESS, addr_str); - GRPC_ERROR_UNREF(errs[0]); - GRPC_ERROR_UNREF(errs[1]); - gpr_free(addr_str); - return err; } + return err; } /* Return listener at port_index or NULL. Should only be called with s->mu @@ -723,8 +503,8 @@ void grpc_tcp_server_start(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s, "clone_port", clone_port(sp, (unsigned)(pollset_count - 1)))); for (i = 0; i < pollset_count; i++) { grpc_pollset_add_fd(exec_ctx, pollsets[i], sp->emfd); - sp->read_closure.cb = on_read; - sp->read_closure.cb_arg = sp; + GRPC_CLOSURE_INIT(&sp->read_closure, on_read, sp, + grpc_schedule_on_exec_ctx); grpc_fd_notify_on_read(exec_ctx, sp->emfd, &sp->read_closure); s->active_ports++; sp = sp->next; @@ -733,8 +513,8 @@ void grpc_tcp_server_start(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s, for (i = 0; i < pollset_count; i++) { grpc_pollset_add_fd(exec_ctx, pollsets[i], sp->emfd); } - sp->read_closure.cb = on_read; - sp->read_closure.cb_arg = sp; + GRPC_CLOSURE_INIT(&sp->read_closure, on_read, sp, + grpc_schedule_on_exec_ctx); grpc_fd_notify_on_read(exec_ctx, sp->emfd, &sp->read_closure); s->active_ports++; sp = sp->next; @@ -760,7 +540,7 @@ void grpc_tcp_server_unref(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) { if (gpr_unref(&s->refs)) { grpc_tcp_server_shutdown_listeners(exec_ctx, s); gpr_mu_lock(&s->mu); - grpc_exec_ctx_enqueue_list(exec_ctx, &s->shutdown_starting, NULL); + GRPC_CLOSURE_LIST_SCHED(exec_ctx, &s->shutdown_starting); gpr_mu_unlock(&s->mu); tcp_server_destroy(exec_ctx, s); } @@ -769,11 +549,13 @@ void grpc_tcp_server_unref(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) { void grpc_tcp_server_shutdown_listeners(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) { gpr_mu_lock(&s->mu); + s->shutdown_listeners = true; /* shutdown all fd's */ if (s->active_ports) { grpc_tcp_listener *sp; for (sp = s->head; sp; sp = sp->next) { - grpc_fd_shutdown(exec_ctx, sp->emfd); + grpc_fd_shutdown(exec_ctx, sp->emfd, + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Server shutdown")); } } gpr_mu_unlock(&s->mu); diff --git a/Sources/CgRPC/src/core/lib/iomgr/tcp_server_utils_posix.h b/Sources/CgRPC/src/core/lib/iomgr/tcp_server_utils_posix.h new file mode 100644 index 000000000..85dea515d --- /dev/null +++ b/Sources/CgRPC/src/core/lib/iomgr/tcp_server_utils_posix.h @@ -0,0 +1,120 @@ +/* + * + * Copyright 2017 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 GRPC_CORE_LIB_IOMGR_TCP_SERVER_UTILS_POSIX_H +#define GRPC_CORE_LIB_IOMGR_TCP_SERVER_UTILS_POSIX_H + +#include "src/core/lib/iomgr/ev_posix.h" +#include "src/core/lib/iomgr/resolve_address.h" +#include "src/core/lib/iomgr/socket_utils_posix.h" +#include "src/core/lib/iomgr/tcp_server.h" + +/* one listening port */ +typedef struct grpc_tcp_listener { + int fd; + grpc_fd *emfd; + grpc_tcp_server *server; + grpc_resolved_address addr; + int port; + unsigned port_index; + unsigned fd_index; + grpc_closure read_closure; + grpc_closure destroyed_closure; + struct grpc_tcp_listener *next; + /* sibling is a linked list of all listeners for a given port. add_port and + clone_port place all new listeners in the same sibling list. A member of + the 'sibling' list is also a member of the 'next' list. The head of each + sibling list has is_sibling==0, and subsequent members of sibling lists + have is_sibling==1. is_sibling allows separate sibling lists to be + identified while iterating through 'next'. */ + struct grpc_tcp_listener *sibling; + int is_sibling; +} grpc_tcp_listener; + +/* the overall server */ +struct grpc_tcp_server { + gpr_refcount refs; + /* Called whenever accept() succeeds on a server port. */ + grpc_tcp_server_cb on_accept_cb; + void *on_accept_cb_arg; + + gpr_mu mu; + + /* active port count: how many ports are actually still listening */ + size_t active_ports; + /* destroyed port count: how many ports are completely destroyed */ + size_t destroyed_ports; + + /* is this server shutting down? */ + bool shutdown; + /* have listeners been shutdown? */ + bool shutdown_listeners; + /* use SO_REUSEPORT */ + bool so_reuseport; + /* expand wildcard addresses to a list of all local addresses */ + bool expand_wildcard_addrs; + + /* linked list of server ports */ + grpc_tcp_listener *head; + grpc_tcp_listener *tail; + unsigned nports; + + /* List of closures passed to shutdown_starting_add(). */ + grpc_closure_list shutdown_starting; + + /* shutdown callback */ + grpc_closure *shutdown_complete; + + /* all pollsets interested in new connections */ + grpc_pollset **pollsets; + /* number of pollsets in the pollsets array */ + size_t pollset_count; + + /* next pollset to assign a channel to */ + gpr_atm next_pollset_to_assign; + + /* channel args for this server */ + grpc_channel_args *channel_args; +}; + +/* If successful, add a listener to \a s for \a addr, set \a dsmode for the + socket, and return the \a listener. */ +grpc_error *grpc_tcp_server_add_addr(grpc_tcp_server *s, + const grpc_resolved_address *addr, + unsigned port_index, unsigned fd_index, + grpc_dualstack_mode *dsmode, + grpc_tcp_listener **listener); + +/* Get all addresses assigned to network interfaces on the machine and create a + listener for each. requested_port is the port to use for every listener, or 0 + to select one random port that will be used for every listener. Set *out_port + to the port selected. Return GRPC_ERROR_NONE only if all listeners were + added. */ +grpc_error *grpc_tcp_server_add_all_local_addrs(grpc_tcp_server *s, + unsigned port_index, + int requested_port, + int *out_port); + +/* Prepare a recently-created socket for listening. */ +grpc_error *grpc_tcp_server_prepare_socket(int fd, + const grpc_resolved_address *addr, + bool so_reuseport, int *port); +/* Ruturn true if the platform supports ifaddrs */ +bool grpc_tcp_server_have_ifaddrs(void); + +#endif /* GRPC_CORE_LIB_IOMGR_TCP_SERVER_UTILS_POSIX_H */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/tcp_server_utils_posix_common.c b/Sources/CgRPC/src/core/lib/iomgr/tcp_server_utils_posix_common.c new file mode 100644 index 000000000..ad535bc43 --- /dev/null +++ b/Sources/CgRPC/src/core/lib/iomgr/tcp_server_utils_posix_common.c @@ -0,0 +1,206 @@ +/* + * + * Copyright 2017 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 "src/core/lib/iomgr/port.h" + +#ifdef GRPC_POSIX_SOCKET + +#include "src/core/lib/iomgr/tcp_server_utils_posix.h" + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "src/core/lib/iomgr/error.h" +#include "src/core/lib/iomgr/sockaddr.h" +#include "src/core/lib/iomgr/sockaddr_utils.h" +#include "src/core/lib/iomgr/unix_sockets_posix.h" + +#define MIN_SAFE_ACCEPT_QUEUE_SIZE 100 + +static gpr_once s_init_max_accept_queue_size = GPR_ONCE_INIT; +static int s_max_accept_queue_size; + +/* get max listen queue size on linux */ +static void init_max_accept_queue_size(void) { + int n = SOMAXCONN; + char buf[64]; + FILE *fp = fopen("/proc/sys/net/core/somaxconn", "r"); + if (fp == NULL) { + /* 2.4 kernel. */ + s_max_accept_queue_size = SOMAXCONN; + return; + } + if (fgets(buf, sizeof buf, fp)) { + char *end; + long i = strtol(buf, &end, 10); + if (i > 0 && i <= INT_MAX && end && *end == 0) { + n = (int)i; + } + } + fclose(fp); + s_max_accept_queue_size = n; + + if (s_max_accept_queue_size < MIN_SAFE_ACCEPT_QUEUE_SIZE) { + gpr_log(GPR_INFO, + "Suspiciously small accept queue (%d) will probably lead to " + "connection drops", + s_max_accept_queue_size); + } +} + +static int get_max_accept_queue_size(void) { + gpr_once_init(&s_init_max_accept_queue_size, init_max_accept_queue_size); + return s_max_accept_queue_size; +} + +static grpc_error *add_socket_to_server(grpc_tcp_server *s, int fd, + const grpc_resolved_address *addr, + unsigned port_index, unsigned fd_index, + grpc_tcp_listener **listener) { + grpc_tcp_listener *sp = NULL; + int port = -1; + char *addr_str; + char *name; + + grpc_error *err = + grpc_tcp_server_prepare_socket(fd, addr, s->so_reuseport, &port); + if (err == GRPC_ERROR_NONE) { + GPR_ASSERT(port > 0); + grpc_sockaddr_to_string(&addr_str, addr, 1); + gpr_asprintf(&name, "tcp-server-listener:%s", addr_str); + gpr_mu_lock(&s->mu); + s->nports++; + GPR_ASSERT(!s->on_accept_cb && "must add ports before starting server"); + sp = gpr_malloc(sizeof(grpc_tcp_listener)); + sp->next = NULL; + if (s->head == NULL) { + s->head = sp; + } else { + s->tail->next = sp; + } + s->tail = sp; + sp->server = s; + sp->fd = fd; + sp->emfd = grpc_fd_create(fd, name); + memcpy(&sp->addr, addr, sizeof(grpc_resolved_address)); + sp->port = port; + sp->port_index = port_index; + sp->fd_index = fd_index; + sp->is_sibling = 0; + sp->sibling = NULL; + GPR_ASSERT(sp->emfd); + gpr_mu_unlock(&s->mu); + gpr_free(addr_str); + gpr_free(name); + } + + *listener = sp; + return err; +} + +/* If successful, add a listener to s for addr, set *dsmode for the socket, and + return the *listener. */ +grpc_error *grpc_tcp_server_add_addr(grpc_tcp_server *s, + const grpc_resolved_address *addr, + unsigned port_index, unsigned fd_index, + grpc_dualstack_mode *dsmode, + grpc_tcp_listener **listener) { + grpc_resolved_address addr4_copy; + int fd; + grpc_error *err = + grpc_create_dualstack_socket(addr, SOCK_STREAM, 0, dsmode, &fd); + if (err != GRPC_ERROR_NONE) { + return err; + } + if (*dsmode == GRPC_DSMODE_IPV4 && + grpc_sockaddr_is_v4mapped(addr, &addr4_copy)) { + addr = &addr4_copy; + } + return add_socket_to_server(s, fd, addr, port_index, fd_index, listener); +} + +/* Prepare a recently-created socket for listening. */ +grpc_error *grpc_tcp_server_prepare_socket(int fd, + const grpc_resolved_address *addr, + bool so_reuseport, int *port) { + grpc_resolved_address sockname_temp; + grpc_error *err = GRPC_ERROR_NONE; + + GPR_ASSERT(fd >= 0); + + if (so_reuseport && !grpc_is_unix_socket(addr)) { + err = grpc_set_socket_reuse_port(fd, 1); + if (err != GRPC_ERROR_NONE) goto error; + } + + err = grpc_set_socket_nonblocking(fd, 1); + if (err != GRPC_ERROR_NONE) goto error; + err = grpc_set_socket_cloexec(fd, 1); + if (err != GRPC_ERROR_NONE) goto error; + if (!grpc_is_unix_socket(addr)) { + err = grpc_set_socket_low_latency(fd, 1); + if (err != GRPC_ERROR_NONE) goto error; + err = grpc_set_socket_reuse_addr(fd, 1); + if (err != GRPC_ERROR_NONE) goto error; + } + err = grpc_set_socket_no_sigpipe_if_possible(fd); + if (err != GRPC_ERROR_NONE) goto error; + + GPR_ASSERT(addr->len < ~(socklen_t)0); + if (bind(fd, (struct sockaddr *)addr->addr, (socklen_t)addr->len) < 0) { + err = GRPC_OS_ERROR(errno, "bind"); + goto error; + } + + if (listen(fd, get_max_accept_queue_size()) < 0) { + err = GRPC_OS_ERROR(errno, "listen"); + goto error; + } + + sockname_temp.len = sizeof(struct sockaddr_storage); + + if (getsockname(fd, (struct sockaddr *)sockname_temp.addr, + (socklen_t *)&sockname_temp.len) < 0) { + err = GRPC_OS_ERROR(errno, "getsockname"); + goto error; + } + + *port = grpc_sockaddr_get_port(&sockname_temp); + return GRPC_ERROR_NONE; + +error: + GPR_ASSERT(err != GRPC_ERROR_NONE); + if (fd >= 0) { + close(fd); + } + grpc_error *ret = + grpc_error_set_int(GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( + "Unable to configure socket", &err, 1), + GRPC_ERROR_INT_FD, fd); + GRPC_ERROR_UNREF(err); + return ret; +} + +#endif /* GRPC_POSIX_SOCKET */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.c b/Sources/CgRPC/src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.c new file mode 100644 index 000000000..a243b69f3 --- /dev/null +++ b/Sources/CgRPC/src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.c @@ -0,0 +1,181 @@ +/* + * + * Copyright 2017 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 "src/core/lib/iomgr/port.h" + +#ifdef GRPC_HAVE_IFADDRS + +#include "src/core/lib/iomgr/tcp_server_utils_posix.h" + +#include +#include +#include +#include + +#include +#include +#include + +#include "src/core/lib/iomgr/error.h" +#include "src/core/lib/iomgr/sockaddr.h" +#include "src/core/lib/iomgr/sockaddr_utils.h" + +/* Return the listener in s with address addr or NULL. */ +static grpc_tcp_listener *find_listener_with_addr(grpc_tcp_server *s, + grpc_resolved_address *addr) { + grpc_tcp_listener *l; + gpr_mu_lock(&s->mu); + for (l = s->head; l != NULL; l = l->next) { + if (l->addr.len != addr->len) { + continue; + } + if (memcmp(l->addr.addr, addr->addr, addr->len) == 0) { + break; + } + } + gpr_mu_unlock(&s->mu); + return l; +} + +/* Bind to "::" to get a port number not used by any address. */ +static grpc_error *get_unused_port(int *port) { + grpc_resolved_address wild; + grpc_sockaddr_make_wildcard6(0, &wild); + grpc_dualstack_mode dsmode; + int fd; + grpc_error *err = + grpc_create_dualstack_socket(&wild, SOCK_STREAM, 0, &dsmode, &fd); + if (err != GRPC_ERROR_NONE) { + return err; + } + if (dsmode == GRPC_DSMODE_IPV4) { + grpc_sockaddr_make_wildcard4(0, &wild); + } + if (bind(fd, (const struct sockaddr *)wild.addr, (socklen_t)wild.len) != 0) { + err = GRPC_OS_ERROR(errno, "bind"); + close(fd); + return err; + } + if (getsockname(fd, (struct sockaddr *)wild.addr, (socklen_t *)&wild.len) != + 0) { + err = GRPC_OS_ERROR(errno, "getsockname"); + close(fd); + return err; + } + close(fd); + *port = grpc_sockaddr_get_port(&wild); + return *port <= 0 ? GRPC_ERROR_CREATE_FROM_STATIC_STRING("Bad port") + : GRPC_ERROR_NONE; +} + +grpc_error *grpc_tcp_server_add_all_local_addrs(grpc_tcp_server *s, + unsigned port_index, + int requested_port, + int *out_port) { + struct ifaddrs *ifa = NULL; + struct ifaddrs *ifa_it; + unsigned fd_index = 0; + grpc_tcp_listener *sp = NULL; + grpc_error *err = GRPC_ERROR_NONE; + if (requested_port == 0) { + /* Note: There could be a race where some local addrs can listen on the + selected port and some can't. The sane way to handle this would be to + retry by recreating the whole grpc_tcp_server. Backing out individual + listeners and orphaning the FDs looks like too much trouble. */ + if ((err = get_unused_port(&requested_port)) != GRPC_ERROR_NONE) { + return err; + } else if (requested_port <= 0) { + return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Bad get_unused_port()"); + } + gpr_log(GPR_DEBUG, "Picked unused port %d", requested_port); + } + if (getifaddrs(&ifa) != 0 || ifa == NULL) { + return GRPC_OS_ERROR(errno, "getifaddrs"); + } + for (ifa_it = ifa; ifa_it != NULL; ifa_it = ifa_it->ifa_next) { + grpc_resolved_address addr; + char *addr_str = NULL; + grpc_dualstack_mode dsmode; + grpc_tcp_listener *new_sp = NULL; + const char *ifa_name = (ifa_it->ifa_name ? ifa_it->ifa_name : ""); + if (ifa_it->ifa_addr == NULL) { + continue; + } else if (ifa_it->ifa_addr->sa_family == AF_INET) { + addr.len = sizeof(struct sockaddr_in); + } else if (ifa_it->ifa_addr->sa_family == AF_INET6) { + addr.len = sizeof(struct sockaddr_in6); + } else { + continue; + } + memcpy(addr.addr, ifa_it->ifa_addr, addr.len); + if (!grpc_sockaddr_set_port(&addr, requested_port)) { + /* Should never happen, because we check sa_family above. */ + err = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Failed to set port"); + break; + } + if (grpc_sockaddr_to_string(&addr_str, &addr, 0) < 0) { + addr_str = gpr_strdup(""); + } + gpr_log(GPR_DEBUG, + "Adding local addr from interface %s flags 0x%x to server: %s", + ifa_name, ifa_it->ifa_flags, addr_str); + /* We could have multiple interfaces with the same address (e.g., bonding), + so look for duplicates. */ + if (find_listener_with_addr(s, &addr) != NULL) { + gpr_log(GPR_DEBUG, "Skipping duplicate addr %s on interface %s", addr_str, + ifa_name); + gpr_free(addr_str); + continue; + } + if ((err = grpc_tcp_server_add_addr(s, &addr, port_index, fd_index, &dsmode, + &new_sp)) != GRPC_ERROR_NONE) { + char *err_str = NULL; + grpc_error *root_err; + if (gpr_asprintf(&err_str, "Failed to add listener: %s", addr_str) < 0) { + err_str = gpr_strdup("Failed to add listener"); + } + root_err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(err_str); + gpr_free(err_str); + gpr_free(addr_str); + err = grpc_error_add_child(root_err, err); + break; + } else { + GPR_ASSERT(requested_port == new_sp->port); + ++fd_index; + if (sp != NULL) { + new_sp->is_sibling = 1; + sp->sibling = new_sp; + } + sp = new_sp; + } + gpr_free(addr_str); + } + freeifaddrs(ifa); + if (err != GRPC_ERROR_NONE) { + return err; + } else if (sp == NULL) { + return GRPC_ERROR_CREATE_FROM_STATIC_STRING("No local addresses"); + } else { + *out_port = sp->port; + return GRPC_ERROR_NONE; + } +} + +bool grpc_tcp_server_have_ifaddrs(void) { return true; } + +#endif /* GRPC_HAVE_IFADDRS */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.c b/Sources/CgRPC/src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.c new file mode 100644 index 000000000..34eab20d6 --- /dev/null +++ b/Sources/CgRPC/src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.c @@ -0,0 +1,34 @@ +/* + * + * Copyright 2017 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 "src/core/lib/iomgr/port.h" + +#if defined(GRPC_POSIX_SOCKET) && !defined(GRPC_HAVE_IFADDRS) + +#include "src/core/lib/iomgr/tcp_server_utils_posix.h" + +grpc_error *grpc_tcp_server_add_all_local_addrs(grpc_tcp_server *s, + unsigned port_index, + int requested_port, + int *out_port) { + return GRPC_ERROR_CREATE_FROM_STATIC_STRING("no ifaddrs available"); +} + +bool grpc_tcp_server_have_ifaddrs(void) { return false; } + +#endif /* defined(GRPC_POSIX_SOCKET) && !defined(GRPC_HAVE_IFADDRS) */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/tcp_server_uv.c b/Sources/CgRPC/src/core/lib/iomgr/tcp_server_uv.c index e1a174cfa..3b9332321 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/tcp_server_uv.c +++ b/Sources/CgRPC/src/core/lib/iomgr/tcp_server_uv.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -35,6 +20,7 @@ #ifdef GRPC_UV +#include #include #include @@ -42,6 +28,7 @@ #include "src/core/lib/iomgr/error.h" #include "src/core/lib/iomgr/exec_ctx.h" +#include "src/core/lib/iomgr/iomgr_uv.h" #include "src/core/lib/iomgr/sockaddr.h" #include "src/core/lib/iomgr/sockaddr_utils.h" #include "src/core/lib/iomgr/tcp_server.h" @@ -56,6 +43,10 @@ struct grpc_tcp_listener { int port; /* linked list */ struct grpc_tcp_listener *next; + + bool closed; + + bool has_pending_connection; }; struct grpc_tcp_server { @@ -77,6 +68,8 @@ struct grpc_tcp_server { /* shutdown callback */ grpc_closure *shutdown_complete; + bool shutdown; + grpc_resource_quota *resource_quota; }; @@ -89,14 +82,14 @@ grpc_error *grpc_tcp_server_create(grpc_exec_ctx *exec_ctx, for (size_t i = 0; i < (args == NULL ? 0 : args->num_args); i++) { if (0 == strcmp(GRPC_ARG_RESOURCE_QUOTA, args->args[i].key)) { if (args->args[i].type == GRPC_ARG_POINTER) { - grpc_resource_quota_internal_unref(exec_ctx, s->resource_quota); + grpc_resource_quota_unref_internal(exec_ctx, s->resource_quota); s->resource_quota = - grpc_resource_quota_internal_ref(args->args[i].value.pointer.p); + grpc_resource_quota_ref_internal(args->args[i].value.pointer.p); } else { - grpc_resource_quota_internal_unref(exec_ctx, s->resource_quota); + grpc_resource_quota_unref_internal(exec_ctx, s->resource_quota); gpr_free(s); - return GRPC_ERROR_CREATE(GRPC_ARG_RESOURCE_QUOTA - " must be a pointer to a buffer pool"); + return GRPC_ERROR_CREATE_FROM_STATIC_STRING( + GRPC_ARG_RESOURCE_QUOTA " must be a pointer to a buffer pool"); } } } @@ -109,11 +102,13 @@ grpc_error *grpc_tcp_server_create(grpc_exec_ctx *exec_ctx, s->shutdown_starting.head = NULL; s->shutdown_starting.tail = NULL; s->shutdown_complete = shutdown_complete; + s->shutdown = false; *server = s; return GRPC_ERROR_NONE; } grpc_tcp_server *grpc_tcp_server_ref(grpc_tcp_server *s) { + GRPC_UV_ASSERT_SAME_THREAD(); gpr_ref(&s->refs); return s; } @@ -125,8 +120,9 @@ void grpc_tcp_server_shutdown_starting_add(grpc_tcp_server *s, } static void finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) { + GPR_ASSERT(s->shutdown); if (s->shutdown_complete != NULL) { - grpc_exec_ctx_sched(exec_ctx, s->shutdown_complete, GRPC_ERROR_NONE, NULL); + GRPC_CLOSURE_SCHED(exec_ctx, s->shutdown_complete, GRPC_ERROR_NONE); } while (s->head) { @@ -136,7 +132,7 @@ static void finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) { gpr_free(sp->handle); gpr_free(sp); } - grpc_resource_quota_internal_unref(exec_ctx, s->resource_quota); + grpc_resource_quota_unref_internal(exec_ctx, s->resource_quota); gpr_free(s); } @@ -144,21 +140,31 @@ static void handle_close_callback(uv_handle_t *handle) { grpc_tcp_listener *sp = (grpc_tcp_listener *)handle->data; grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; sp->server->open_ports--; - if (sp->server->open_ports == 0) { + if (sp->server->open_ports == 0 && sp->server->shutdown) { finish_shutdown(&exec_ctx, sp->server); } grpc_exec_ctx_finish(&exec_ctx); } +static void close_listener(grpc_tcp_listener *sp) { + if (!sp->closed) { + sp->closed = true; + uv_close((uv_handle_t *)sp->handle, handle_close_callback); + } +} + static void tcp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) { int immediately_done = 0; grpc_tcp_listener *sp; + GPR_ASSERT(!s->shutdown); + s->shutdown = true; + if (s->open_ports == 0) { immediately_done = 1; } for (sp = s->head; sp; sp = sp->next) { - uv_close((uv_handle_t *)sp->handle, handle_close_callback); + close_listener(sp); } if (immediately_done) { @@ -167,10 +173,11 @@ static void tcp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) { } void grpc_tcp_server_unref(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) { + GRPC_UV_ASSERT_SAME_THREAD(); if (gpr_unref(&s->refs)) { /* Complete shutdown_starting work before destroying. */ grpc_exec_ctx local_exec_ctx = GRPC_EXEC_CTX_INIT; - grpc_exec_ctx_enqueue_list(&local_exec_ctx, &s->shutdown_starting, NULL); + GRPC_CLOSURE_LIST_SCHED(&local_exec_ctx, &s->shutdown_starting); if (exec_ctx == NULL) { grpc_exec_ctx_flush(&local_exec_ctx); tcp_server_destroy(&local_exec_ctx, s); @@ -182,53 +189,74 @@ void grpc_tcp_server_unref(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) { } } -static void accepted_connection_close_cb(uv_handle_t *handle) { - gpr_free(handle); -} - -static void on_connect(uv_stream_t *server, int status) { - grpc_tcp_listener *sp = (grpc_tcp_listener *)server->data; +static void finish_accept(grpc_exec_ctx *exec_ctx, grpc_tcp_listener *sp) { + grpc_tcp_server_acceptor *acceptor = gpr_malloc(sizeof(*acceptor)); uv_tcp_t *client; grpc_endpoint *ep = NULL; - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_resolved_address peer_name; char *peer_name_string; int err; - - if (status < 0) { - gpr_log(GPR_INFO, "Skipping on_accept due to error: %s", - uv_strerror(status)); - return; - } + uv_tcp_t *server = sp->handle; client = gpr_malloc(sizeof(uv_tcp_t)); uv_tcp_init(uv_default_loop(), client); // UV documentation says this is guaranteed to succeed uv_accept((uv_stream_t *)server, (uv_stream_t *)client); - // If the server has not been started, we discard incoming connections - if (sp->server->on_accept_cb == NULL) { - uv_close((uv_handle_t *)client, accepted_connection_close_cb); + peer_name_string = NULL; + memset(&peer_name, 0, sizeof(grpc_resolved_address)); + peer_name.len = sizeof(struct sockaddr_storage); + err = uv_tcp_getpeername(client, (struct sockaddr *)&peer_name.addr, + (int *)&peer_name.len); + if (err == 0) { + peer_name_string = grpc_sockaddr_to_uri(&peer_name); } else { - peer_name_string = NULL; - memset(&peer_name, 0, sizeof(grpc_resolved_address)); - peer_name.len = sizeof(struct sockaddr_storage); - err = uv_tcp_getpeername(client, (struct sockaddr *)&peer_name.addr, - (int *)&peer_name.len); - if (err == 0) { - peer_name_string = grpc_sockaddr_to_uri(&peer_name); + gpr_log(GPR_INFO, "uv_tcp_getpeername error: %s", uv_strerror(err)); + } + if (GRPC_TRACER_ON(grpc_tcp_trace)) { + if (peer_name_string) { + gpr_log(GPR_DEBUG, "SERVER_CONNECT: %p accepted connection: %s", + sp->server, peer_name_string); } else { - gpr_log(GPR_INFO, "uv_tcp_getpeername error: %s", uv_strerror(status)); + gpr_log(GPR_DEBUG, "SERVER_CONNECT: %p accepted connection", sp->server); + } + } + ep = grpc_tcp_create(client, sp->server->resource_quota, peer_name_string); + acceptor->from_server = sp->server; + acceptor->port_index = sp->port_index; + acceptor->fd_index = 0; + sp->server->on_accept_cb(exec_ctx, sp->server->on_accept_cb_arg, ep, NULL, + acceptor); + gpr_free(peer_name_string); +} + +static void on_connect(uv_stream_t *server, int status) { + grpc_tcp_listener *sp = (grpc_tcp_listener *)server->data; + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + + if (status < 0) { + switch (status) { + case UV_EINTR: + case UV_EAGAIN: + return; + default: + close_listener(sp); + return; } - ep = grpc_tcp_create(client, sp->server->resource_quota, peer_name_string); - // Create acceptor. - grpc_tcp_server_acceptor *acceptor = gpr_malloc(sizeof(*acceptor)); - acceptor->from_server = sp->server; - acceptor->port_index = sp->port_index; - acceptor->fd_index = 0; - sp->server->on_accept_cb(&exec_ctx, sp->server->on_accept_cb_arg, ep, NULL, - acceptor); - grpc_exec_ctx_finish(&exec_ctx); } + + GPR_ASSERT(!sp->has_pending_connection); + + if (GRPC_TRACER_ON(grpc_tcp_trace)) { + gpr_log(GPR_DEBUG, "SERVER_CONNECT: %p incoming connection", sp->server); + } + + // Create acceptor. + if (sp->server->on_accept_cb) { + finish_accept(&exec_ctx, sp); + } else { + sp->has_pending_connection = true; + } + grpc_exec_ctx_finish(&exec_ctx); } static grpc_error *add_socket_to_server(grpc_tcp_server *s, uv_tcp_t *handle, @@ -244,17 +272,19 @@ static grpc_error *add_socket_to_server(grpc_tcp_server *s, uv_tcp_t *handle, // The last argument to uv_tcp_bind is flags status = uv_tcp_bind(handle, (struct sockaddr *)addr->addr, 0); if (status != 0) { - error = GRPC_ERROR_CREATE("Failed to bind to port"); + error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Failed to bind to port"); error = - grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR, uv_strerror(status)); + grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR, + grpc_slice_from_static_string(uv_strerror(status))); return error; } status = uv_listen((uv_stream_t *)handle, SOMAXCONN, on_connect); if (status != 0) { - error = GRPC_ERROR_CREATE("Failed to listen to port"); + error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Failed to listen to port"); error = - grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR, uv_strerror(status)); + grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR, + grpc_slice_from_static_string(uv_strerror(status))); return error; } @@ -262,9 +292,10 @@ static grpc_error *add_socket_to_server(grpc_tcp_server *s, uv_tcp_t *handle, status = uv_tcp_getsockname(handle, (struct sockaddr *)&sockname_temp.addr, (int *)&sockname_temp.len); if (status != 0) { - error = GRPC_ERROR_CREATE("getsockname failed"); + error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("getsockname failed"); error = - grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR, uv_strerror(status)); + grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR, + grpc_slice_from_static_string(uv_strerror(status))); return error; } @@ -272,7 +303,7 @@ static grpc_error *add_socket_to_server(grpc_tcp_server *s, uv_tcp_t *handle, GPR_ASSERT(port >= 0); GPR_ASSERT(!s->on_accept_cb && "must add ports before starting server"); - sp = gpr_malloc(sizeof(grpc_tcp_listener)); + sp = gpr_zalloc(sizeof(grpc_tcp_listener)); sp->next = NULL; if (s->head == NULL) { s->head = sp; @@ -284,6 +315,7 @@ static grpc_error *add_socket_to_server(grpc_tcp_server *s, uv_tcp_t *handle, sp->handle = handle; sp->port = port; sp->port_index = port_index; + sp->closed = false; handle->data = sp; s->open_ports++; GPR_ASSERT(sp->handle); @@ -305,6 +337,9 @@ grpc_error *grpc_tcp_server_add_port(grpc_tcp_server *s, unsigned port_index = 0; int status; grpc_error *error = GRPC_ERROR_NONE; + int family; + + GRPC_UV_ASSERT_SAME_THREAD(); if (s->tail != NULL) { port_index = s->tail->port_index + 1; @@ -342,19 +377,44 @@ grpc_error *grpc_tcp_server_add_port(grpc_tcp_server *s, } handle = gpr_malloc(sizeof(uv_tcp_t)); - status = uv_tcp_init(uv_default_loop(), handle); + + family = grpc_sockaddr_get_family(addr); + status = uv_tcp_init_ex(uv_default_loop(), handle, (unsigned int)family); +#if defined(GPR_LINUX) && defined(SO_REUSEPORT) + if (family == AF_INET || family == AF_INET6) { + int fd; + uv_fileno((uv_handle_t *)handle, &fd); + int enable = 1; + setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &enable, sizeof(enable)); + } +#endif /* GPR_LINUX && SO_REUSEPORT */ + if (status == 0) { error = add_socket_to_server(s, handle, addr, port_index, &sp); } else { - error = GRPC_ERROR_CREATE("Failed to initialize UV tcp handle"); + error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "Failed to initialize UV tcp handle"); error = - grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR, uv_strerror(status)); + grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR, + grpc_slice_from_static_string(uv_strerror(status))); } gpr_free(allocated_addr); + if (GRPC_TRACER_ON(grpc_tcp_trace)) { + char *port_string; + grpc_sockaddr_to_string(&port_string, addr, 0); + const char *str = grpc_error_string(error); + if (port_string) { + gpr_log(GPR_DEBUG, "SERVER %p add_port %s error=%s", s, port_string, str); + gpr_free(port_string); + } else { + gpr_log(GPR_DEBUG, "SERVER %p add_port error=%s", s, str); + } + } + if (error != GRPC_ERROR_NONE) { - grpc_error *error_out = GRPC_ERROR_CREATE_REFERENCING( + grpc_error *error_out = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( "Failed to add port to server", &error, 1); GRPC_ERROR_UNREF(error); error = error_out; @@ -372,13 +432,19 @@ void grpc_tcp_server_start(grpc_exec_ctx *exec_ctx, grpc_tcp_server *server, grpc_tcp_listener *sp; (void)pollsets; (void)pollset_count; + GRPC_UV_ASSERT_SAME_THREAD(); + if (GRPC_TRACER_ON(grpc_tcp_trace)) { + gpr_log(GPR_DEBUG, "SERVER_START %p", server); + } GPR_ASSERT(on_accept_cb); GPR_ASSERT(!server->on_accept_cb); server->on_accept_cb = on_accept_cb; server->on_accept_cb_arg = cb_arg; for (sp = server->head; sp; sp = sp->next) { - GPR_ASSERT(uv_listen((uv_stream_t *)sp->handle, SOMAXCONN, on_connect) == - 0); + if (sp->has_pending_connection) { + finish_accept(exec_ctx, sp); + sp->has_pending_connection = false; + } } } diff --git a/Sources/CgRPC/src/core/lib/iomgr/tcp_server_windows.c b/Sources/CgRPC/src/core/lib/iomgr/tcp_server_windows.c index b0c8586ba..0162afc1a 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/tcp_server_windows.c +++ b/Sources/CgRPC/src/core/lib/iomgr/tcp_server_windows.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -46,6 +31,7 @@ #include #include +#include "src/core/lib/channel/channel_args.h" #include "src/core/lib/iomgr/iocp_windows.h" #include "src/core/lib/iomgr/pollset_windows.h" #include "src/core/lib/iomgr/resolve_address.h" @@ -102,7 +88,7 @@ struct grpc_tcp_server { /* shutdown callback */ grpc_closure *shutdown_complete; - grpc_resource_quota *resource_quota; + grpc_channel_args *channel_args; }; /* Public function. Allocates the proper data structures to hold a @@ -112,21 +98,7 @@ grpc_error *grpc_tcp_server_create(grpc_exec_ctx *exec_ctx, const grpc_channel_args *args, grpc_tcp_server **server) { grpc_tcp_server *s = gpr_malloc(sizeof(grpc_tcp_server)); - s->resource_quota = grpc_resource_quota_create(NULL); - for (size_t i = 0; i < (args == NULL ? 0 : args->num_args); i++) { - if (0 == strcmp(GRPC_ARG_RESOURCE_QUOTA, args->args[i].key)) { - if (args->args[i].type == GRPC_ARG_POINTER) { - grpc_resource_quota_internal_unref(exec_ctx, s->resource_quota); - s->resource_quota = - grpc_resource_quota_internal_ref(args->args[i].value.pointer.p); - } else { - grpc_resource_quota_internal_unref(exec_ctx, s->resource_quota); - gpr_free(s); - return GRPC_ERROR_CREATE(GRPC_ARG_RESOURCE_QUOTA - " must be a pointer to a buffer pool"); - } - } - } + s->channel_args = grpc_channel_args_copy(args); gpr_ref_init(&s->refs, 1); gpr_mu_init(&s->mu); s->active_ports = 0; @@ -155,18 +127,19 @@ static void destroy_server(grpc_exec_ctx *exec_ctx, void *arg, grpc_winsocket_destroy(sp->socket); gpr_free(sp); } - grpc_resource_quota_internal_unref(exec_ctx, s->resource_quota); + grpc_channel_args_destroy(exec_ctx, s->channel_args); gpr_free(s); } static void finish_shutdown_locked(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) { if (s->shutdown_complete != NULL) { - grpc_exec_ctx_sched(exec_ctx, s->shutdown_complete, GRPC_ERROR_NONE, NULL); + GRPC_CLOSURE_SCHED(exec_ctx, s->shutdown_complete, GRPC_ERROR_NONE); } - grpc_exec_ctx_sched(exec_ctx, grpc_closure_create(destroy_server, s), - GRPC_ERROR_NONE, NULL); + GRPC_CLOSURE_SCHED(exec_ctx, GRPC_CLOSURE_CREATE(destroy_server, s, + grpc_schedule_on_exec_ctx), + GRPC_ERROR_NONE); } grpc_tcp_server *grpc_tcp_server_ref(grpc_tcp_server *s) { @@ -183,7 +156,6 @@ void grpc_tcp_server_shutdown_starting_add(grpc_tcp_server *s, } static void tcp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) { - int immediately_done = 0; grpc_tcp_listener *sp; gpr_mu_lock(&s->mu); @@ -204,7 +176,7 @@ void grpc_tcp_server_unref(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) { if (gpr_unref(&s->refs)) { grpc_tcp_server_shutdown_listeners(exec_ctx, s); gpr_mu_lock(&s->mu); - grpc_exec_ctx_enqueue_list(exec_ctx, &s->shutdown_starting, NULL); + GRPC_CLOSURE_LIST_SCHED(exec_ctx, &s->shutdown_starting); gpr_mu_unlock(&s->mu); tcp_server_destroy(exec_ctx, s); } @@ -239,7 +211,7 @@ static grpc_error *prepare_socket(SOCKET sock, error = GRPC_WSA_ERROR(WSAGetLastError(), "getsockname"); goto failure; } - sockname_temp.len = sockname_temp_len; + sockname_temp.len = (size_t)sockname_temp_len; *port = grpc_sockaddr_get_port(&sockname_temp); return GRPC_ERROR_NONE; @@ -247,10 +219,11 @@ static grpc_error *prepare_socket(SOCKET sock, failure: GPR_ASSERT(error != GRPC_ERROR_NONE); char *tgtaddr = grpc_sockaddr_to_uri(addr); - grpc_error *final_error = grpc_error_set_int( - grpc_error_set_str(GRPC_ERROR_CREATE_REFERENCING( + grpc_error_set_int( + grpc_error_set_str(GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( "Failed to prepare server socket", &error, 1), - GRPC_ERROR_STR_TARGET_ADDRESS, tgtaddr), + GRPC_ERROR_STR_TARGET_ADDRESS, + grpc_slice_from_copied_string(tgtaddr)), GRPC_ERROR_INT_FD, (intptr_t)sock); gpr_free(tgtaddr); GRPC_ERROR_UNREF(error); @@ -260,7 +233,6 @@ static grpc_error *prepare_socket(SOCKET sock, static void decrement_active_ports_and_notify_locked(grpc_exec_ctx *exec_ctx, grpc_tcp_listener *sp) { - int notify = 0; sp->shutting_down = 0; GPR_ASSERT(sp->server->active_ports > 0); if (0 == --sp->server->active_ports) { @@ -344,7 +316,7 @@ static void on_accept(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { if (error != GRPC_ERROR_NONE) { const char *msg = grpc_error_string(error); gpr_log(GPR_INFO, "Skipping on_accept due to error: %s", msg); - grpc_error_free_string(msg); + gpr_mu_unlock(&sp->server->mu); return; } @@ -374,7 +346,7 @@ static void on_accept(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { int peer_name_len = (int)peer_name.len; err = getpeername(sock, (struct sockaddr *)peer_name.addr, &peer_name_len); - peer_name.len = peer_name_len; + peer_name.len = (size_t)peer_name_len; if (!err) { peer_name_string = grpc_sockaddr_to_uri(&peer_name); } else { @@ -383,8 +355,8 @@ static void on_accept(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { gpr_free(utf8_message); } gpr_asprintf(&fd_name, "tcp_server:%s", peer_name_string); - ep = grpc_tcp_create(grpc_winsocket_create(sock, fd_name), - sp->server->resource_quota, peer_name_string); + ep = grpc_tcp_create(exec_ctx, grpc_winsocket_create(sock, fd_name), + sp->server->channel_args, peer_name_string); gpr_free(fd_name); gpr_free(peer_name_string); } else { @@ -465,7 +437,7 @@ static grpc_error *add_socket_to_server(grpc_tcp_server *s, SOCKET sock, sp->new_socket = INVALID_SOCKET; sp->port = port; sp->port_index = port_index; - grpc_closure_init(&sp->on_accept, on_accept, sp); + GRPC_CLOSURE_INIT(&sp->on_accept, on_accept, sp, grpc_schedule_on_exec_ctx); GPR_ASSERT(sp->socket); gpr_mu_unlock(&s->mu); *listener = sp; @@ -497,7 +469,7 @@ grpc_error *grpc_tcp_server_add_port(grpc_tcp_server *s, if (0 == getsockname(sp->socket->socket, (struct sockaddr *)sockname_temp.addr, &sockname_temp_len)) { - sockname_temp.len = sockname_temp_len; + sockname_temp.len = (size_t)sockname_temp_len; *port = grpc_sockaddr_get_port(&sockname_temp); if (*port > 0) { allocated_addr = gpr_malloc(sizeof(grpc_resolved_address)); @@ -534,7 +506,7 @@ grpc_error *grpc_tcp_server_add_port(grpc_tcp_server *s, gpr_free(allocated_addr); if (error != GRPC_ERROR_NONE) { - grpc_error *error_out = GRPC_ERROR_CREATE_REFERENCING( + grpc_error *error_out = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( "Failed to add port to server", &error, 1); GRPC_ERROR_UNREF(error); error = error_out; diff --git a/Sources/CgRPC/src/core/lib/iomgr/tcp_uv.c b/Sources/CgRPC/src/core/lib/iomgr/tcp_uv.c index 6e2ad1dbe..a05c19b4a 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/tcp_uv.c +++ b/Sources/CgRPC/src/core/lib/iomgr/tcp_uv.c @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -45,13 +30,15 @@ #include #include "src/core/lib/iomgr/error.h" +#include "src/core/lib/iomgr/iomgr_uv.h" #include "src/core/lib/iomgr/network_status_tracker.h" #include "src/core/lib/iomgr/resource_quota.h" #include "src/core/lib/iomgr/tcp_uv.h" +#include "src/core/lib/slice/slice_internal.h" #include "src/core/lib/slice/slice_string_helpers.h" #include "src/core/lib/support/string.h" -int grpc_tcp_trace = 0; +grpc_tracer_flag grpc_tcp_trace = GRPC_TRACER_INITIALIZER(false, "tcp"); typedef struct { grpc_endpoint base; @@ -78,23 +65,26 @@ typedef struct { grpc_pollset *pollset; } grpc_tcp; -static void uv_close_callback(uv_handle_t *handle) { gpr_free(handle); } - static void tcp_free(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp) { + grpc_slice_unref_internal(exec_ctx, tcp->read_slice); grpc_resource_user_unref(exec_ctx, tcp->resource_user); + gpr_free(tcp->handle); + gpr_free(tcp->peer_string); gpr_free(tcp); } -/*#define GRPC_TCP_REFCOUNT_DEBUG*/ -#ifdef GRPC_TCP_REFCOUNT_DEBUG +#ifndef NDEBUG #define TCP_UNREF(exec_ctx, tcp, reason) \ tcp_unref((exec_ctx), (tcp), (reason), __FILE__, __LINE__) -#define TCP_REF(tcp, reason) \ - tcp_ref((exec_ctx), (tcp), (reason), __FILE__, __LINE__) +#define TCP_REF(tcp, reason) tcp_ref((tcp), (reason), __FILE__, __LINE__) static void tcp_unref(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp, const char *reason, const char *file, int line) { - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "TCP unref %p : %s %d -> %d", tcp, - reason, tcp->refcount.count, tcp->refcount.count - 1); + if (GRPC_TRACER_ON(grpc_tcp_trace)) { + gpr_atm val = gpr_atm_no_barrier_load(&tcp->refcount.count); + gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, + "TCP unref %p : %s %" PRIdPTR " -> %" PRIdPTR, tcp, reason, val, + val - 1); + } if (gpr_unref(&tcp->refcount)) { tcp_free(exec_ctx, tcp); } @@ -102,8 +92,12 @@ static void tcp_unref(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp, static void tcp_ref(grpc_tcp *tcp, const char *reason, const char *file, int line) { - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "TCP ref %p : %s %d -> %d", tcp, - reason, tcp->refcount.count, tcp->refcount.count + 1); + if (GRPC_TRACER_ON(grpc_tcp_trace)) { + gpr_atm val = gpr_atm_no_barrier_load(&tcp->refcount.count); + gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, + "TCP ref %p : %s %" PRIdPTR " -> %" PRIdPTR, tcp, reason, val, + val + 1); + } gpr_ref(&tcp->refcount); } #else @@ -118,13 +112,24 @@ static void tcp_unref(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp) { static void tcp_ref(grpc_tcp *tcp) { gpr_ref(&tcp->refcount); } #endif +static void uv_close_callback(uv_handle_t *handle) { + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + grpc_tcp *tcp = handle->data; + TCP_UNREF(&exec_ctx, tcp, "destroy"); + grpc_exec_ctx_finish(&exec_ctx); +} + +static grpc_slice alloc_read_slice(grpc_exec_ctx *exec_ctx, + grpc_resource_user *resource_user) { + return grpc_resource_user_slice_malloc(exec_ctx, resource_user, + GRPC_TCP_DEFAULT_READ_SLICE_SIZE); +} + static void alloc_uv_buf(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) { grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_tcp *tcp = handle->data; (void)suggested_size; - tcp->read_slice = grpc_resource_user_slice_malloc( - &exec_ctx, tcp->resource_user, GRPC_TCP_DEFAULT_READ_SLICE_SIZE); buf->base = (char *)GRPC_SLICE_START_PTR(tcp->read_slice); buf->len = GRPC_SLICE_LENGTH(tcp->read_slice); grpc_exec_ctx_finish(&exec_ctx); @@ -146,17 +151,18 @@ static void read_callback(uv_stream_t *stream, ssize_t nread, // TODO(murgatroid99): figure out what the return value here means uv_read_stop(stream); if (nread == UV_EOF) { - error = GRPC_ERROR_CREATE("EOF"); + error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("EOF"); } else if (nread > 0) { // Successful read sub = grpc_slice_sub_no_ref(tcp->read_slice, 0, (size_t)nread); grpc_slice_buffer_add(tcp->read_slices, sub); + tcp->read_slice = alloc_read_slice(&exec_ctx, tcp->resource_user); error = GRPC_ERROR_NONE; - if (grpc_tcp_trace) { + if (GRPC_TRACER_ON(grpc_tcp_trace)) { size_t i; const char *str = grpc_error_string(error); gpr_log(GPR_DEBUG, "read: error=%s", str); - grpc_error_free_string(str); + 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); @@ -167,9 +173,9 @@ static void read_callback(uv_stream_t *stream, ssize_t nread, } } else { // nread < 0: Error - error = GRPC_ERROR_CREATE("TCP Read failed"); + error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("TCP Read failed"); } - grpc_exec_ctx_sched(&exec_ctx, cb, error, NULL); + GRPC_CLOSURE_SCHED(&exec_ctx, cb, error); grpc_exec_ctx_finish(&exec_ctx); } @@ -178,21 +184,23 @@ static void uv_endpoint_read(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, grpc_tcp *tcp = (grpc_tcp *)ep; int status; grpc_error *error = GRPC_ERROR_NONE; + GRPC_UV_ASSERT_SAME_THREAD(); GPR_ASSERT(tcp->read_cb == NULL); tcp->read_cb = cb; tcp->read_slices = read_slices; - grpc_slice_buffer_reset_and_unref(read_slices); + grpc_slice_buffer_reset_and_unref_internal(exec_ctx, read_slices); TCP_REF(tcp, "read"); // TODO(murgatroid99): figure out what the return value here means status = uv_read_start((uv_stream_t *)tcp->handle, alloc_uv_buf, read_callback); if (status != 0) { - error = GRPC_ERROR_CREATE("TCP Read failed at start"); + error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("TCP Read failed at start"); error = - grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR, uv_strerror(status)); - grpc_exec_ctx_sched(exec_ctx, cb, error, NULL); + grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR, + grpc_slice_from_static_string(uv_strerror(status))); + GRPC_CLOSURE_SCHED(exec_ctx, cb, error); } - if (grpc_tcp_trace) { + if (GRPC_TRACER_ON(grpc_tcp_trace)) { const char *str = grpc_error_string(error); gpr_log(GPR_DEBUG, "Initiating read on %p: error=%s", tcp, str); } @@ -208,16 +216,16 @@ static void write_callback(uv_write_t *req, int status) { if (status == 0) { error = GRPC_ERROR_NONE; } else { - error = GRPC_ERROR_CREATE("TCP Write failed"); + error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("TCP Write failed"); } - if (grpc_tcp_trace) { + if (GRPC_TRACER_ON(grpc_tcp_trace)) { const char *str = grpc_error_string(error); gpr_log(GPR_DEBUG, "write complete on %p: error=%s", tcp, str); } gpr_free(tcp->write_buffers); grpc_resource_user_free(&exec_ctx, tcp->resource_user, sizeof(uv_buf_t) * tcp->write_slices->count); - grpc_exec_ctx_sched(&exec_ctx, cb, error, NULL); + GRPC_CLOSURE_SCHED(&exec_ctx, cb, error); grpc_exec_ctx_finish(&exec_ctx); } @@ -230,8 +238,9 @@ static void uv_endpoint_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, unsigned int i; grpc_slice *slice; uv_write_t *write_req; + GRPC_UV_ASSERT_SAME_THREAD(); - if (grpc_tcp_trace) { + if (GRPC_TRACER_ON(grpc_tcp_trace)) { size_t j; for (j = 0; j < write_slices->count; j++) { @@ -243,8 +252,8 @@ static void uv_endpoint_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, } if (tcp->shutting_down) { - grpc_exec_ctx_sched(exec_ctx, cb, - GRPC_ERROR_CREATE("TCP socket is shutting down"), NULL); + GRPC_CLOSURE_SCHED(exec_ctx, cb, GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "TCP socket is shutting down")); return; } @@ -254,7 +263,7 @@ static void uv_endpoint_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, if (tcp->write_slices->count == 0) { // No slices means we don't have to do anything, // and libuv doesn't like empty writes - grpc_exec_ctx_sched(exec_ctx, cb, GRPC_ERROR_NONE, NULL); + GRPC_CLOSURE_SCHED(exec_ctx, cb, GRPC_ERROR_NONE); return; } @@ -297,20 +306,26 @@ static void uv_add_to_pollset_set(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, static void shutdown_callback(uv_shutdown_t *req, int status) {} -static void uv_endpoint_shutdown(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep) { +static void uv_endpoint_shutdown(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, + grpc_error *why) { grpc_tcp *tcp = (grpc_tcp *)ep; if (!tcp->shutting_down) { + if (GRPC_TRACER_ON(grpc_tcp_trace)) { + const char *str = grpc_error_string(why); + gpr_log(GPR_DEBUG, "TCP %p shutdown why=%s", tcp->handle, str); + } tcp->shutting_down = true; uv_shutdown_t *req = &tcp->shutdown_req; uv_shutdown(req, (uv_stream_t *)tcp->handle, shutdown_callback); + grpc_resource_user_shutdown(exec_ctx, tcp->resource_user); } + GRPC_ERROR_UNREF(why); } static void uv_destroy(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep) { grpc_network_status_unregister_endpoint(ep); grpc_tcp *tcp = (grpc_tcp *)ep; uv_close((uv_handle_t *)tcp->handle, uv_close_callback); - TCP_UNREF(exec_ctx, tcp, "destroy"); } static char *uv_get_peer(grpc_endpoint *ep) { @@ -323,22 +338,20 @@ static grpc_resource_user *uv_get_resource_user(grpc_endpoint *ep) { return tcp->resource_user; } -static grpc_workqueue *uv_get_workqueue(grpc_endpoint *ep) { return NULL; } - static int uv_get_fd(grpc_endpoint *ep) { return -1; } static grpc_endpoint_vtable vtable = { - uv_endpoint_read, uv_endpoint_write, uv_get_workqueue, - uv_add_to_pollset, uv_add_to_pollset_set, uv_endpoint_shutdown, - uv_destroy, uv_get_resource_user, uv_get_peer, - uv_get_fd}; + uv_endpoint_read, uv_endpoint_write, uv_add_to_pollset, + uv_add_to_pollset_set, uv_endpoint_shutdown, uv_destroy, + uv_get_resource_user, uv_get_peer, uv_get_fd}; grpc_endpoint *grpc_tcp_create(uv_tcp_t *handle, grpc_resource_quota *resource_quota, char *peer_string) { grpc_tcp *tcp = (grpc_tcp *)gpr_malloc(sizeof(grpc_tcp)); + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - if (grpc_tcp_trace) { + if (GRPC_TRACER_ON(grpc_tcp_trace)) { gpr_log(GPR_DEBUG, "Creating TCP endpoint %p", tcp); } @@ -353,6 +366,7 @@ grpc_endpoint *grpc_tcp_create(uv_tcp_t *handle, tcp->peer_string = gpr_strdup(peer_string); tcp->shutting_down = false; tcp->resource_user = grpc_resource_user_create(resource_quota, peer_string); + tcp->read_slice = alloc_read_slice(&exec_ctx, tcp->resource_user); /* Tell network status tracking code about the new endpoint */ grpc_network_status_register_endpoint(&tcp->base); @@ -360,6 +374,7 @@ grpc_endpoint *grpc_tcp_create(uv_tcp_t *handle, uv_unref((uv_handle_t *)handle); #endif + grpc_exec_ctx_finish(&exec_ctx); return &tcp->base; } diff --git a/Sources/CgRPC/src/core/lib/iomgr/tcp_uv.h b/Sources/CgRPC/src/core/lib/iomgr/tcp_uv.h index 970fcafe4..0e67481d3 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/tcp_uv.h +++ b/Sources/CgRPC/src/core/lib/iomgr/tcp_uv.h @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -44,11 +29,12 @@ otherwise specified. */ +#include "src/core/lib/debug/trace.h" #include "src/core/lib/iomgr/endpoint.h" #include -extern int grpc_tcp_trace; +extern grpc_tracer_flag grpc_tcp_trace; #define GRPC_TCP_DEFAULT_READ_SLICE_SIZE 8192 diff --git a/Sources/CgRPC/src/core/lib/iomgr/tcp_windows.c b/Sources/CgRPC/src/core/lib/iomgr/tcp_windows.c index d4613b674..2cbb97403 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/tcp_windows.c +++ b/Sources/CgRPC/src/core/lib/iomgr/tcp_windows.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -53,6 +38,7 @@ #include "src/core/lib/iomgr/socket_windows.h" #include "src/core/lib/iomgr/tcp_client.h" #include "src/core/lib/iomgr/timer.h" +#include "src/core/lib/slice/slice_internal.h" #if defined(__MSYS__) && defined(GPR_ARCH_64) /* Nasty workaround for nasty bug when using the 64 bits msys compiler @@ -62,6 +48,8 @@ #define GRPC_FIONBIO FIONBIO #endif +grpc_tracer_flag grpc_tcp_trace = GRPC_TRACER_INITIALIZER(false, "tcp"); + static grpc_error *set_non_block(SOCKET sock) { int status; uint32_t param = 1; @@ -115,6 +103,7 @@ typedef struct grpc_tcp { to protect ourselves when requesting a shutdown. */ gpr_mu mu; int shutting_down; + grpc_error *shutdown_error; char *peer_string; } grpc_tcp; @@ -124,18 +113,22 @@ static void tcp_free(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp) { gpr_mu_destroy(&tcp->mu); gpr_free(tcp->peer_string); grpc_resource_user_unref(exec_ctx, tcp->resource_user); + if (tcp->shutting_down) GRPC_ERROR_UNREF(tcp->shutdown_error); gpr_free(tcp); } -/*#define GRPC_TCP_REFCOUNT_DEBUG*/ -#ifdef GRPC_TCP_REFCOUNT_DEBUG +#ifndef NDEBUG #define TCP_UNREF(exec_ctx, tcp, reason) \ tcp_unref((exec_ctx), (tcp), (reason), __FILE__, __LINE__) #define TCP_REF(tcp, reason) tcp_ref((tcp), (reason), __FILE__, __LINE__) static void tcp_unref(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp, const char *reason, const char *file, int line) { - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "TCP unref %p : %s %d -> %d", tcp, - reason, tcp->refcount.count, tcp->refcount.count - 1); + if (GRPC_TRACER_ON(grpc_tcp_trace)) { + gpr_atm val = gpr_atm_no_barrier_load(&tcp->refcount.count); + gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, + "TCP unref %p : %s %" PRIdPTR " -> %" PRIdPTR, tcp, reason, val, + val - 1); + } if (gpr_unref(&tcp->refcount)) { tcp_free(exec_ctx, tcp); } @@ -143,8 +136,12 @@ static void tcp_unref(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp, static void tcp_ref(grpc_tcp *tcp, const char *reason, const char *file, int line) { - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "TCP ref %p : %s %d -> %d", tcp, - reason, tcp->refcount.count, tcp->refcount.count + 1); + if (GRPC_TRACER_ON(grpc_tcp_trace)) { + gpr_atm val = gpr_atm_no_barrier_load(&tcp->refcount.count); + gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, + "TCP ref %p : %s %" PRIdPTR " -> %" PRIdPTR, tcp, reason, val, + val + 1); + } gpr_ref(&tcp->refcount); } #else @@ -172,23 +169,26 @@ static void on_read(grpc_exec_ctx *exec_ctx, void *tcpp, grpc_error *error) { if (error == GRPC_ERROR_NONE) { if (info->wsa_error != 0 && !tcp->shutting_down) { char *utf8_message = gpr_format_message(info->wsa_error); - error = GRPC_ERROR_CREATE(utf8_message); + error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(utf8_message); gpr_free(utf8_message); - grpc_slice_unref(tcp->read_slice); + grpc_slice_unref_internal(exec_ctx, tcp->read_slice); } else { if (info->bytes_transfered != 0 && !tcp->shutting_down) { sub = grpc_slice_sub_no_ref(tcp->read_slice, 0, info->bytes_transfered); grpc_slice_buffer_add(tcp->read_slices, sub); } else { - grpc_slice_unref(tcp->read_slice); - error = GRPC_ERROR_CREATE("End of TCP stream"); + grpc_slice_unref_internal(exec_ctx, tcp->read_slice); + error = tcp->shutting_down + ? GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( + "TCP stream shutting down", &tcp->shutdown_error, 1) + : GRPC_ERROR_CREATE_FROM_STATIC_STRING("End of TCP stream"); } } } tcp->read_cb = NULL; TCP_UNREF(exec_ctx, tcp, "read"); - grpc_exec_ctx_sched(exec_ctx, cb, error, NULL); + GRPC_CLOSURE_SCHED(exec_ctx, cb, error); } static void win_read(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, @@ -202,16 +202,18 @@ static void win_read(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, WSABUF buffer; if (tcp->shutting_down) { - grpc_exec_ctx_sched(exec_ctx, cb, - GRPC_ERROR_CREATE("TCP socket is shutting down"), NULL); + GRPC_CLOSURE_SCHED( + exec_ctx, cb, + GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( + "TCP socket is shutting down", &tcp->shutdown_error, 1)); return; } tcp->read_cb = cb; tcp->read_slices = read_slices; - grpc_slice_buffer_reset_and_unref(read_slices); + grpc_slice_buffer_reset_and_unref_internal(exec_ctx, read_slices); - tcp->read_slice = grpc_slice_malloc(8192); + tcp->read_slice = GRPC_SLICE_MALLOC(8192); buffer.len = (ULONG)GRPC_SLICE_LENGTH( tcp->read_slice); // we know slice size fits in 32bit. @@ -227,7 +229,7 @@ static void win_read(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, /* Did we get data immediately ? Yay. */ if (info->wsa_error != WSAEWOULDBLOCK) { info->bytes_transfered = bytes_read; - grpc_exec_ctx_sched(exec_ctx, &tcp->on_read, GRPC_ERROR_NONE, NULL); + GRPC_CLOSURE_SCHED(exec_ctx, &tcp->on_read, GRPC_ERROR_NONE); return; } @@ -240,8 +242,8 @@ static void win_read(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, int wsa_error = WSAGetLastError(); if (wsa_error != WSA_IO_PENDING) { info->wsa_error = wsa_error; - grpc_exec_ctx_sched(exec_ctx, &tcp->on_read, - GRPC_WSA_ERROR(info->wsa_error, "WSARecv"), NULL); + GRPC_CLOSURE_SCHED(exec_ctx, &tcp->on_read, + GRPC_WSA_ERROR(info->wsa_error, "WSARecv")); return; } } @@ -272,7 +274,7 @@ static void on_write(grpc_exec_ctx *exec_ctx, void *tcpp, grpc_error *error) { } TCP_UNREF(exec_ctx, tcp, "write"); - grpc_exec_ctx_sched(exec_ctx, cb, error, NULL); + GRPC_CLOSURE_SCHED(exec_ctx, cb, error); } /* Initiates a write. */ @@ -290,8 +292,10 @@ static void win_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, size_t len; if (tcp->shutting_down) { - grpc_exec_ctx_sched(exec_ctx, cb, - GRPC_ERROR_CREATE("TCP socket is shutting down"), NULL); + GRPC_CLOSURE_SCHED( + exec_ctx, cb, + GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( + "TCP socket is shutting down", &tcp->shutdown_error, 1)); return; } @@ -322,7 +326,7 @@ static void win_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, grpc_error *error = status == 0 ? GRPC_ERROR_NONE : GRPC_WSA_ERROR(info->wsa_error, "WSASend"); - grpc_exec_ctx_sched(exec_ctx, cb, error, NULL); + GRPC_CLOSURE_SCHED(exec_ctx, cb, error); if (allocated) gpr_free(allocated); return; } @@ -340,8 +344,7 @@ static void win_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, int wsa_error = WSAGetLastError(); if (wsa_error != WSA_IO_PENDING) { TCP_UNREF(exec_ctx, tcp, "write"); - grpc_exec_ctx_sched(exec_ctx, cb, GRPC_WSA_ERROR(wsa_error, "WSASend"), - NULL); + GRPC_CLOSURE_SCHED(exec_ctx, cb, GRPC_WSA_ERROR(wsa_error, "WSASend")); return; } } @@ -373,12 +376,18 @@ static void win_add_to_pollset_set(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, we're not going to protect against these. However the IO Completion Port callback will happen from another thread, so we need to protect against concurrent access of the data structure in that regard. */ -static void win_shutdown(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep) { +static void win_shutdown(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, + grpc_error *why) { grpc_tcp *tcp = (grpc_tcp *)ep; gpr_mu_lock(&tcp->mu); /* At that point, what may happen is that we're already inside the IOCP callback. See the comments in on_read and on_write. */ - tcp->shutting_down = 1; + if (!tcp->shutting_down) { + tcp->shutting_down = 1; + tcp->shutdown_error = why; + } else { + GRPC_ERROR_UNREF(why); + } grpc_winsocket_shutdown(tcp->socket); gpr_mu_unlock(&tcp->mu); grpc_resource_user_shutdown(exec_ctx, tcp->resource_user); @@ -395,8 +404,6 @@ static char *win_get_peer(grpc_endpoint *ep) { return gpr_strdup(tcp->peer_string); } -static grpc_workqueue *win_get_workqueue(grpc_endpoint *ep) { return NULL; } - static grpc_resource_user *win_get_resource_user(grpc_endpoint *ep) { grpc_tcp *tcp = (grpc_tcp *)ep; return tcp->resource_user; @@ -404,28 +411,32 @@ static grpc_resource_user *win_get_resource_user(grpc_endpoint *ep) { static int win_get_fd(grpc_endpoint *ep) { return -1; } -static grpc_endpoint_vtable vtable = {win_read, - win_write, - win_get_workqueue, - win_add_to_pollset, - win_add_to_pollset_set, - win_shutdown, - win_destroy, - win_get_resource_user, - win_get_peer, - win_get_fd}; - -grpc_endpoint *grpc_tcp_create(grpc_winsocket *socket, - grpc_resource_quota *resource_quota, +static grpc_endpoint_vtable vtable = { + win_read, win_write, win_add_to_pollset, win_add_to_pollset_set, + win_shutdown, win_destroy, win_get_resource_user, win_get_peer, + win_get_fd}; + +grpc_endpoint *grpc_tcp_create(grpc_exec_ctx *exec_ctx, grpc_winsocket *socket, + grpc_channel_args *channel_args, char *peer_string) { + grpc_resource_quota *resource_quota = grpc_resource_quota_create(NULL); + if (channel_args != NULL) { + for (size_t i = 0; i < channel_args->num_args; i++) { + if (0 == strcmp(channel_args->args[i].key, GRPC_ARG_RESOURCE_QUOTA)) { + grpc_resource_quota_unref_internal(exec_ctx, resource_quota); + resource_quota = grpc_resource_quota_ref_internal( + channel_args->args[i].value.pointer.p); + } + } + } grpc_tcp *tcp = (grpc_tcp *)gpr_malloc(sizeof(grpc_tcp)); memset(tcp, 0, sizeof(grpc_tcp)); tcp->base.vtable = &vtable; tcp->socket = socket; gpr_mu_init(&tcp->mu); gpr_ref_init(&tcp->refcount, 1); - grpc_closure_init(&tcp->on_read, on_read, tcp); - grpc_closure_init(&tcp->on_write, on_write, tcp); + 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); tcp->resource_user = grpc_resource_user_create(resource_quota, peer_string); /* Tell network status tracking code about the new endpoint */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/tcp_windows.h b/Sources/CgRPC/src/core/lib/iomgr/tcp_windows.h index 4402de1c3..864184ce8 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/tcp_windows.h +++ b/Sources/CgRPC/src/core/lib/iomgr/tcp_windows.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -50,8 +35,8 @@ /* Create a tcp endpoint given a winsock handle. * Takes ownership of the handle. */ -grpc_endpoint *grpc_tcp_create(grpc_winsocket *socket, - grpc_resource_quota *resource_quota, +grpc_endpoint *grpc_tcp_create(grpc_exec_ctx *exec_ctx, grpc_winsocket *socket, + grpc_channel_args *channel_args, char *peer_string); grpc_error *grpc_tcp_prepare_socket(SOCKET sock); diff --git a/Sources/CgRPC/src/core/lib/iomgr/time_averaged_stats.c b/Sources/CgRPC/src/core/lib/iomgr/time_averaged_stats.c index da9cae6f2..3bddec04d 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/time_averaged_stats.c +++ b/Sources/CgRPC/src/core/lib/iomgr/time_averaged_stats.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/time_averaged_stats.h b/Sources/CgRPC/src/core/lib/iomgr/time_averaged_stats.h index 284b31f94..8745f7fa1 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/time_averaged_stats.h +++ b/Sources/CgRPC/src/core/lib/iomgr/time_averaged_stats.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/timer.h b/Sources/CgRPC/src/core/lib/iomgr/timer.h index 20fe98c4a..b92b8fb8b 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/timer.h +++ b/Sources/CgRPC/src/core/lib/iomgr/timer.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -49,15 +34,15 @@ typedef struct grpc_timer grpc_timer; -/* Initialize *timer. When expired or canceled, timer_cb will be called with - *timer_cb_arg and error set to indicate if it expired (GRPC_ERROR_NONE) or - was canceled (GRPC_ERROR_CANCELLED). timer_cb is guaranteed to be called - exactly once, and application code should check the error to determine - how it was invoked. The application callback is also responsible for - maintaining information about when to free up any user-level state. */ +/* Initialize *timer. When expired or canceled, closure will be called with + error set to indicate if it expired (GRPC_ERROR_NONE) or was canceled + (GRPC_ERROR_CANCELLED). timer_cb is guaranteed to be called exactly once, and + application code should check the error to determine how it was invoked. The + application callback is also responsible for maintaining information about + when to free up any user-level state. */ void grpc_timer_init(grpc_exec_ctx *exec_ctx, grpc_timer *timer, - gpr_timespec deadline, grpc_iomgr_cb_func timer_cb, - void *timer_cb_arg, gpr_timespec now); + gpr_timespec deadline, grpc_closure *closure, + gpr_timespec now); /* Note that there is no timer destroy function. This is because the timer is a one-time occurrence with a guarantee that the callback will @@ -89,6 +74,12 @@ void grpc_timer_cancel(grpc_exec_ctx *exec_ctx, grpc_timer *timer); /* iomgr internal api for dealing with timers */ +typedef enum { + GRPC_TIMERS_NOT_CHECKED, + GRPC_TIMERS_CHECKED_AND_EMPTY, + GRPC_TIMERS_FIRED, +} grpc_timer_check_result; + /* Check for timers to be run, and run them. Return true if timer callbacks were executed. If next is non-null, TRY to update *next with the next running timer @@ -96,11 +87,14 @@ void grpc_timer_cancel(grpc_exec_ctx *exec_ctx, grpc_timer *timer); *next is never guaranteed to be updated on any given execution; however, with high probability at least one thread in the system will see an update at any time slice. */ -bool grpc_timer_check(grpc_exec_ctx *exec_ctx, gpr_timespec now, - gpr_timespec *next); +grpc_timer_check_result grpc_timer_check(grpc_exec_ctx *exec_ctx, + gpr_timespec now, gpr_timespec *next); void grpc_timer_list_init(gpr_timespec now); void grpc_timer_list_shutdown(grpc_exec_ctx *exec_ctx); +/* Consume a kick issued by grpc_kick_poller */ +void grpc_timer_consume_kick(void); + /* the following must be implemented by each iomgr implementation */ void grpc_kick_poller(void); diff --git a/Sources/CgRPC/src/core/lib/iomgr/timer_generic.c b/Sources/CgRPC/src/core/lib/iomgr/timer_generic.c index 00058f9d8..12efce241 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/timer_generic.c +++ b/Sources/CgRPC/src/core/lib/iomgr/timer_generic.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -37,11 +22,16 @@ #include "src/core/lib/iomgr/timer.h" +#include #include +#include #include +#include #include +#include "src/core/lib/debug/trace.h" #include "src/core/lib/iomgr/time_averaged_stats.h" #include "src/core/lib/iomgr/timer_heap.h" +#include "src/core/lib/support/spinlock.h" #define INVALID_HEAP_INDEX 0xffffffffu @@ -51,54 +41,135 @@ #define MIN_QUEUE_WINDOW_DURATION 0.01 #define MAX_QUEUE_WINDOW_DURATION 1 +grpc_tracer_flag grpc_timer_trace = GRPC_TRACER_INITIALIZER(false, "timer"); +grpc_tracer_flag grpc_timer_check_trace = + GRPC_TRACER_INITIALIZER(false, "timer_check"); + +/* A "timer shard". Contains a 'heap' and a 'list' of timers. All timers with + * deadlines earlier than 'queue_deadline" cap are maintained in the heap and + * others are maintained in the list (unordered). This helps to keep the number + * of elements in the heap low. + * + * The 'queue_deadline_cap' gets recomputed periodically based on the timer + * stats maintained in 'stats' and the relevant timers are then moved from the + * 'list' to 'heap' + */ typedef struct { gpr_mu mu; grpc_time_averaged_stats stats; /* All and only timers with deadlines <= this will be in the heap. */ - gpr_timespec queue_deadline_cap; - gpr_timespec min_deadline; - /* Index in the g_shard_queue */ + gpr_atm queue_deadline_cap; + /* The deadline of the next timer due in this shard */ + gpr_atm min_deadline; + /* Index of this timer_shard in the g_shard_queue */ uint32_t shard_queue_index; /* This holds all timers with deadlines < queue_deadline_cap. Timers in this list have the top bit of their deadline set to 0. */ grpc_timer_heap heap; /* This holds timers whose deadline is >= queue_deadline_cap. */ grpc_timer list; -} shard_type; +} timer_shard; + +/* Array of timer shards. Whenever a timer (grpc_timer *) is added, its address + * is hashed to select the timer shard to add the timer to */ +static timer_shard g_shards[NUM_SHARDS]; + +/* Maintains a sorted list of timer shards (sorted by their min_deadline, i.e + * the deadline of the next timer in each shard). + * Access to this is protected by g_shared_mutables.mu */ +static timer_shard *g_shard_queue[NUM_SHARDS]; + +/* Thread local variable that stores the deadline of the next timer the thread + * has last-seen. This is an optimization to prevent the thread from checking + * shared_mutables.min_timer (which requires acquiring shared_mutables.mu lock, + * an expensive operation) */ +GPR_TLS_DECL(g_last_seen_min_timer); + +struct shared_mutables { + /* The deadline of the next timer due across all timer shards */ + gpr_atm min_timer; + /* Allow only one run_some_expired_timers at once */ + gpr_spinlock checker_mu; + bool initialized; + /* Protects g_shard_queue (and the shared_mutables struct itself) */ + gpr_mu mu; +} GPR_ALIGN_STRUCT(GPR_CACHELINE_SIZE); + +static struct shared_mutables g_shared_mutables = { + .checker_mu = GPR_SPINLOCK_STATIC_INITIALIZER, .initialized = false, +}; -/* Protects g_shard_queue */ -static gpr_mu g_mu; -/* Allow only one run_some_expired_timers at once */ -static gpr_mu g_checker_mu; static gpr_clock_type g_clock_type; -static shard_type g_shards[NUM_SHARDS]; -/* Protected by g_mu */ -static shard_type *g_shard_queue[NUM_SHARDS]; -static bool g_initialized = false; +static gpr_timespec g_start_time; + +static gpr_atm saturating_add(gpr_atm a, gpr_atm b) { + if (a > GPR_ATM_MAX - b) { + return GPR_ATM_MAX; + } + return a + b; +} + +static grpc_timer_check_result run_some_expired_timers(grpc_exec_ctx *exec_ctx, + gpr_atm now, + gpr_atm *next, + grpc_error *error); -static int run_some_expired_timers(grpc_exec_ctx *exec_ctx, gpr_timespec now, - gpr_timespec *next, grpc_error *error); +static gpr_timespec dbl_to_ts(double d) { + gpr_timespec ts; + ts.tv_sec = (int64_t)d; + ts.tv_nsec = (int32_t)(1e9 * (d - (double)ts.tv_sec)); + ts.clock_type = GPR_TIMESPAN; + return ts; +} + +static gpr_atm timespec_to_atm_round_up(gpr_timespec ts) { + ts = gpr_time_sub(ts, g_start_time); + double x = GPR_MS_PER_SEC * (double)ts.tv_sec + + (double)ts.tv_nsec / GPR_NS_PER_MS + + (double)(GPR_NS_PER_SEC - 1) / (double)GPR_NS_PER_SEC; + if (x < 0) return 0; + if (x > GPR_ATM_MAX) return GPR_ATM_MAX; + return (gpr_atm)x; +} -static gpr_timespec compute_min_deadline(shard_type *shard) { +static gpr_atm timespec_to_atm_round_down(gpr_timespec ts) { + ts = gpr_time_sub(ts, g_start_time); + double x = + GPR_MS_PER_SEC * (double)ts.tv_sec + (double)ts.tv_nsec / GPR_NS_PER_MS; + if (x < 0) return 0; + if (x > GPR_ATM_MAX) return GPR_ATM_MAX; + return (gpr_atm)x; +} + +static gpr_timespec atm_to_timespec(gpr_atm x) { + return gpr_time_add(g_start_time, dbl_to_ts((double)x / 1000.0)); +} + +static gpr_atm compute_min_deadline(timer_shard *shard) { return grpc_timer_heap_is_empty(&shard->heap) - ? shard->queue_deadline_cap + ? saturating_add(shard->queue_deadline_cap, 1) : grpc_timer_heap_top(&shard->heap)->deadline; } void grpc_timer_list_init(gpr_timespec now) { uint32_t i; - g_initialized = true; - gpr_mu_init(&g_mu); - gpr_mu_init(&g_checker_mu); + g_shared_mutables.initialized = true; + gpr_mu_init(&g_shared_mutables.mu); g_clock_type = now.clock_type; + g_start_time = now; + g_shared_mutables.min_timer = timespec_to_atm_round_down(now); + gpr_tls_init(&g_last_seen_min_timer); + gpr_tls_set(&g_last_seen_min_timer, 0); + grpc_register_tracer(&grpc_timer_trace); + grpc_register_tracer(&grpc_timer_check_trace); for (i = 0; i < NUM_SHARDS; i++) { - shard_type *shard = &g_shards[i]; + timer_shard *shard = &g_shards[i]; gpr_mu_init(&shard->mu); grpc_time_averaged_stats_init(&shard->stats, 1.0 / ADD_DEADLINE_SCALE, 0.1, 0.5); - shard->queue_deadline_cap = now; + shard->queue_deadline_cap = g_shared_mutables.min_timer; shard->shard_queue_index = i; grpc_timer_heap_init(&shard->heap); shard->list.next = shard->list.prev = &shard->list; @@ -109,36 +180,24 @@ void grpc_timer_list_init(gpr_timespec now) { void grpc_timer_list_shutdown(grpc_exec_ctx *exec_ctx) { int i; - run_some_expired_timers(exec_ctx, gpr_inf_future(g_clock_type), NULL, - GRPC_ERROR_CREATE("Timer list shutdown")); + run_some_expired_timers( + exec_ctx, GPR_ATM_MAX, NULL, + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Timer list shutdown")); for (i = 0; i < NUM_SHARDS; i++) { - shard_type *shard = &g_shards[i]; + timer_shard *shard = &g_shards[i]; gpr_mu_destroy(&shard->mu); grpc_timer_heap_destroy(&shard->heap); } - gpr_mu_destroy(&g_mu); - gpr_mu_destroy(&g_checker_mu); - g_initialized = false; -} - -/* This is a cheap, but good enough, pointer hash for sharding the tasks: */ -static size_t shard_idx(const grpc_timer *info) { - size_t x = (size_t)info; - return ((x >> 4) ^ (x >> 9) ^ (x >> 14)) & (NUM_SHARDS - 1); + gpr_mu_destroy(&g_shared_mutables.mu); + gpr_tls_destroy(&g_last_seen_min_timer); + g_shared_mutables.initialized = false; } static double ts_to_dbl(gpr_timespec ts) { return (double)ts.tv_sec + 1e-9 * ts.tv_nsec; } -static gpr_timespec dbl_to_ts(double d) { - gpr_timespec ts; - ts.tv_sec = (int64_t)d; - ts.tv_nsec = (int32_t)(1e9 * (d - (double)ts.tv_sec)); - ts.clock_type = GPR_TIMESPAN; - return ts; -} - +/* returns true if the first element in the list */ static void list_join(grpc_timer *head, grpc_timer *timer) { timer->next = head; timer->prev = head->prev; @@ -151,7 +210,7 @@ static void list_remove(grpc_timer *timer) { } static void swap_adjacent_shards_in_queue(uint32_t first_shard_queue_index) { - shard_type *temp; + timer_shard *temp; temp = g_shard_queue[first_shard_queue_index]; g_shard_queue[first_shard_queue_index] = g_shard_queue[first_shard_queue_index + 1]; @@ -162,58 +221,68 @@ static void swap_adjacent_shards_in_queue(uint32_t first_shard_queue_index) { first_shard_queue_index + 1; } -static void note_deadline_change(shard_type *shard) { +static void note_deadline_change(timer_shard *shard) { while (shard->shard_queue_index > 0 && - gpr_time_cmp( - shard->min_deadline, - g_shard_queue[shard->shard_queue_index - 1]->min_deadline) < 0) { + shard->min_deadline < + g_shard_queue[shard->shard_queue_index - 1]->min_deadline) { swap_adjacent_shards_in_queue(shard->shard_queue_index - 1); } while (shard->shard_queue_index < NUM_SHARDS - 1 && - gpr_time_cmp( - shard->min_deadline, - g_shard_queue[shard->shard_queue_index + 1]->min_deadline) > 0) { + shard->min_deadline > + g_shard_queue[shard->shard_queue_index + 1]->min_deadline) { swap_adjacent_shards_in_queue(shard->shard_queue_index); } } void grpc_timer_init(grpc_exec_ctx *exec_ctx, grpc_timer *timer, - gpr_timespec deadline, grpc_iomgr_cb_func timer_cb, - void *timer_cb_arg, gpr_timespec now) { + gpr_timespec deadline, grpc_closure *closure, + gpr_timespec now) { int is_first_timer = 0; - shard_type *shard = &g_shards[shard_idx(timer)]; + timer_shard *shard = &g_shards[GPR_HASH_POINTER(timer, NUM_SHARDS)]; GPR_ASSERT(deadline.clock_type == g_clock_type); GPR_ASSERT(now.clock_type == g_clock_type); - grpc_closure_init(&timer->closure, timer_cb, timer_cb_arg); - timer->deadline = deadline; - timer->triggered = 0; - - if (!g_initialized) { - timer->triggered = 1; - grpc_exec_ctx_sched( - exec_ctx, &timer->closure, - GRPC_ERROR_CREATE("Attempt to create timer before initialization"), - NULL); + timer->closure = closure; + gpr_atm deadline_atm = timer->deadline = timespec_to_atm_round_up(deadline); + + if (GRPC_TRACER_ON(grpc_timer_trace)) { + gpr_log(GPR_DEBUG, "TIMER %p: SET %" PRId64 ".%09d [%" PRIdPTR + "] now %" PRId64 ".%09d [%" PRIdPTR "] call %p[%p]", + timer, deadline.tv_sec, deadline.tv_nsec, deadline_atm, now.tv_sec, + now.tv_nsec, timespec_to_atm_round_down(now), closure, closure->cb); + } + + if (!g_shared_mutables.initialized) { + timer->pending = false; + GRPC_CLOSURE_SCHED(exec_ctx, timer->closure, + GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "Attempt to create timer before initialization")); return; } + gpr_mu_lock(&shard->mu); + timer->pending = true; if (gpr_time_cmp(deadline, now) <= 0) { - timer->triggered = 1; - grpc_exec_ctx_sched(exec_ctx, &timer->closure, GRPC_ERROR_NONE, NULL); + timer->pending = false; + GRPC_CLOSURE_SCHED(exec_ctx, timer->closure, GRPC_ERROR_NONE); + gpr_mu_unlock(&shard->mu); + /* early out */ return; } - /* TODO(ctiller): check deadline expired */ - - gpr_mu_lock(&shard->mu); grpc_time_averaged_stats_add_sample(&shard->stats, ts_to_dbl(gpr_time_sub(deadline, now))); - if (gpr_time_cmp(deadline, shard->queue_deadline_cap) < 0) { + if (deadline_atm < shard->queue_deadline_cap) { is_first_timer = grpc_timer_heap_add(&shard->heap, timer); } else { timer->heap_index = INVALID_HEAP_INDEX; list_join(&shard->list, timer); } + if (GRPC_TRACER_ON(grpc_timer_trace)) { + gpr_log(GPR_DEBUG, " .. add to shard %d with queue_deadline_cap=%" PRIdPTR + " => is_first_timer=%s", + (int)(shard - g_shards), shard->queue_deadline_cap, + is_first_timer ? "true" : "false"); + } gpr_mu_unlock(&shard->mu); /* Deadline may have decreased, we need to adjust the master queue. Note @@ -228,31 +297,44 @@ void grpc_timer_init(grpc_exec_ctx *exec_ctx, grpc_timer *timer, In that case, the timer will simply have to wait for the next grpc_timer_check. */ if (is_first_timer) { - gpr_mu_lock(&g_mu); - if (gpr_time_cmp(deadline, shard->min_deadline) < 0) { - gpr_timespec old_min_deadline = g_shard_queue[0]->min_deadline; - shard->min_deadline = deadline; + gpr_mu_lock(&g_shared_mutables.mu); + if (GRPC_TRACER_ON(grpc_timer_trace)) { + gpr_log(GPR_DEBUG, " .. old shard min_deadline=%" PRIdPTR, + shard->min_deadline); + } + if (deadline_atm < shard->min_deadline) { + gpr_atm old_min_deadline = g_shard_queue[0]->min_deadline; + shard->min_deadline = deadline_atm; note_deadline_change(shard); - if (shard->shard_queue_index == 0 && - gpr_time_cmp(deadline, old_min_deadline) < 0) { + if (shard->shard_queue_index == 0 && deadline_atm < old_min_deadline) { + gpr_atm_no_barrier_store(&g_shared_mutables.min_timer, deadline_atm); grpc_kick_poller(); } } - gpr_mu_unlock(&g_mu); + gpr_mu_unlock(&g_shared_mutables.mu); } } +void grpc_timer_consume_kick(void) { + /* force re-evaluation of last seeen min */ + gpr_tls_set(&g_last_seen_min_timer, 0); +} + void grpc_timer_cancel(grpc_exec_ctx *exec_ctx, grpc_timer *timer) { - if (!g_initialized) { + if (!g_shared_mutables.initialized) { /* must have already been cancelled, also the shard mutex is invalid */ return; } - shard_type *shard = &g_shards[shard_idx(timer)]; + timer_shard *shard = &g_shards[GPR_HASH_POINTER(timer, NUM_SHARDS)]; gpr_mu_lock(&shard->mu); - if (!timer->triggered) { - grpc_exec_ctx_sched(exec_ctx, &timer->closure, GRPC_ERROR_CANCELLED, NULL); - timer->triggered = 1; + if (GRPC_TRACER_ON(grpc_timer_trace)) { + gpr_log(GPR_DEBUG, "TIMER %p: CANCEL pending=%s", timer, + timer->pending ? "true" : "false"); + } + if (timer->pending) { + GRPC_CLOSURE_SCHED(exec_ctx, timer->closure, GRPC_ERROR_CANCELLED); + timer->pending = false; if (timer->heap_index == INVALID_HEAP_INDEX) { list_remove(timer); } else { @@ -262,12 +344,12 @@ void grpc_timer_cancel(grpc_exec_ctx *exec_ctx, grpc_timer *timer) { gpr_mu_unlock(&shard->mu); } -/* This is called when the queue is empty and "now" has reached the - queue_deadline_cap. We compute a new queue deadline and then scan the map - for timers that fall at or under it. Returns true if the queue is no - longer empty. +/* Rebalances the timer shard by computing a new 'queue_deadline_cap' and moving + all relevant timers in shard->list (i.e timers with deadlines earlier than + 'queue_deadline_cap') into into shard->heap. + Returns 'true' if shard->heap has atleast ONE element REQUIRES: shard->mu locked */ -static int refill_queue(shard_type *shard, gpr_timespec now) { +static int refill_heap(timer_shard *shard, gpr_atm now) { /* Compute the new queue window width and bound by the limits: */ double computed_deadline_delta = grpc_time_averaged_stats_update_average(&shard->stats) * @@ -278,12 +360,22 @@ static int refill_queue(shard_type *shard, gpr_timespec now) { grpc_timer *timer, *next; /* Compute the new cap and put all timers under it into the queue: */ - shard->queue_deadline_cap = gpr_time_add( - gpr_time_max(now, shard->queue_deadline_cap), dbl_to_ts(deadline_delta)); + shard->queue_deadline_cap = + saturating_add(GPR_MAX(now, shard->queue_deadline_cap), + (gpr_atm)(deadline_delta * 1000.0)); + + if (GRPC_TRACER_ON(grpc_timer_check_trace)) { + gpr_log(GPR_DEBUG, " .. shard[%d]->queue_deadline_cap --> %" PRIdPTR, + (int)(shard - g_shards), shard->queue_deadline_cap); + } for (timer = shard->list.next; timer != &shard->list; timer = next) { next = timer->next; - if (gpr_time_cmp(timer->deadline, shard->queue_deadline_cap) < 0) { + if (timer->deadline < shard->queue_deadline_cap) { + if (GRPC_TRACER_ON(grpc_timer_check_trace)) { + gpr_log(GPR_DEBUG, " .. add timer with deadline %" PRIdPTR " to heap", + timer->deadline); + } list_remove(timer); grpc_timer_heap_add(&shard->heap, timer); } @@ -294,30 +386,44 @@ static int refill_queue(shard_type *shard, gpr_timespec now) { /* This pops the next non-cancelled timer with deadline <= now from the queue, or returns NULL if there isn't one. REQUIRES: shard->mu locked */ -static grpc_timer *pop_one(shard_type *shard, gpr_timespec now) { +static grpc_timer *pop_one(timer_shard *shard, gpr_atm now) { grpc_timer *timer; for (;;) { + if (GRPC_TRACER_ON(grpc_timer_check_trace)) { + gpr_log(GPR_DEBUG, " .. shard[%d]: heap_empty=%s", + (int)(shard - g_shards), + grpc_timer_heap_is_empty(&shard->heap) ? "true" : "false"); + } if (grpc_timer_heap_is_empty(&shard->heap)) { - if (gpr_time_cmp(now, shard->queue_deadline_cap) < 0) return NULL; - if (!refill_queue(shard, now)) return NULL; + if (now < shard->queue_deadline_cap) return NULL; + if (!refill_heap(shard, now)) return NULL; } timer = grpc_timer_heap_top(&shard->heap); - if (gpr_time_cmp(timer->deadline, now) > 0) return NULL; - timer->triggered = 1; + if (GRPC_TRACER_ON(grpc_timer_check_trace)) { + gpr_log(GPR_DEBUG, + " .. check top timer deadline=%" PRIdPTR " now=%" PRIdPTR, + timer->deadline, now); + } + if (timer->deadline > now) return NULL; + if (GRPC_TRACER_ON(grpc_timer_trace)) { + gpr_log(GPR_DEBUG, "TIMER %p: FIRE %" PRIdPTR "ms late", timer, + now - timer->deadline); + } + timer->pending = false; grpc_timer_heap_pop(&shard->heap); return timer; } } /* REQUIRES: shard->mu unlocked */ -static size_t pop_timers(grpc_exec_ctx *exec_ctx, shard_type *shard, - gpr_timespec now, gpr_timespec *new_min_deadline, +static size_t pop_timers(grpc_exec_ctx *exec_ctx, timer_shard *shard, + gpr_atm now, gpr_atm *new_min_deadline, grpc_error *error) { size_t n = 0; grpc_timer *timer; gpr_mu_lock(&shard->mu); while ((timer = pop_one(shard, now))) { - grpc_exec_ctx_sched(exec_ctx, &timer->closure, GRPC_ERROR_REF(error), NULL); + GRPC_CLOSURE_SCHED(exec_ctx, timer->closure, GRPC_ERROR_REF(error)); n++; } *new_min_deadline = compute_min_deadline(shard); @@ -325,23 +431,49 @@ static size_t pop_timers(grpc_exec_ctx *exec_ctx, shard_type *shard, return n; } -static int run_some_expired_timers(grpc_exec_ctx *exec_ctx, gpr_timespec now, - gpr_timespec *next, grpc_error *error) { - size_t n = 0; +static grpc_timer_check_result run_some_expired_timers(grpc_exec_ctx *exec_ctx, + gpr_atm now, + gpr_atm *next, + grpc_error *error) { + grpc_timer_check_result result = GRPC_TIMERS_NOT_CHECKED; + + gpr_atm min_timer = gpr_atm_no_barrier_load(&g_shared_mutables.min_timer); + gpr_tls_set(&g_last_seen_min_timer, min_timer); + if (now < min_timer) { + if (next != NULL) *next = GPR_MIN(*next, min_timer); + return GRPC_TIMERS_CHECKED_AND_EMPTY; + } - /* TODO(ctiller): verify that there are any timers (atomically) here */ + if (gpr_spinlock_trylock(&g_shared_mutables.checker_mu)) { + gpr_mu_lock(&g_shared_mutables.mu); + result = GRPC_TIMERS_CHECKED_AND_EMPTY; - if (gpr_mu_trylock(&g_checker_mu)) { - gpr_mu_lock(&g_mu); + if (GRPC_TRACER_ON(grpc_timer_check_trace)) { + gpr_log(GPR_DEBUG, " .. shard[%d]->min_deadline = %" PRIdPTR, + (int)(g_shard_queue[0] - g_shards), + g_shard_queue[0]->min_deadline); + } - while (gpr_time_cmp(g_shard_queue[0]->min_deadline, now) < 0) { - gpr_timespec new_min_deadline; + while (g_shard_queue[0]->min_deadline < now || + (now != GPR_ATM_MAX && g_shard_queue[0]->min_deadline == now)) { + gpr_atm new_min_deadline; /* For efficiency, we pop as many available timers as we can from the shard. This may violate perfect timer deadline ordering, but that shouldn't be a big deal because we don't make ordering guarantees. */ - n += - pop_timers(exec_ctx, g_shard_queue[0], now, &new_min_deadline, error); + if (pop_timers(exec_ctx, g_shard_queue[0], now, &new_min_deadline, + error) > 0) { + result = GRPC_TIMERS_FIRED; + } + + if (GRPC_TRACER_ON(grpc_timer_check_trace)) { + gpr_log(GPR_DEBUG, + " .. result --> %d" + ", shard[%d]->min_deadline %" PRIdPTR " --> %" PRIdPTR + ", now=%" PRIdPTR, + result, (int)(g_shard_queue[0] - g_shards), + g_shard_queue[0]->min_deadline, new_min_deadline, now); + } /* An grpc_timer_init() on the shard could intervene here, adding a new timer that is earlier than new_min_deadline. However, @@ -353,38 +485,86 @@ static int run_some_expired_timers(grpc_exec_ctx *exec_ctx, gpr_timespec now, } if (next) { - *next = gpr_time_min(*next, g_shard_queue[0]->min_deadline); + *next = GPR_MIN(*next, g_shard_queue[0]->min_deadline); } - gpr_mu_unlock(&g_mu); - gpr_mu_unlock(&g_checker_mu); - } else if (next != NULL) { - /* TODO(ctiller): this forces calling code to do an short poll, and - then retry the timer check (because this time through the timer list was - contended). - - We could reduce the cost here dramatically by keeping a count of how many - currently active pollers got through the uncontended case above - successfully, and waking up other pollers IFF that count drops to zero. - - Once that count is in place, this entire else branch could disappear. */ - *next = gpr_time_min( - *next, gpr_time_add(now, gpr_time_from_millis(1, GPR_TIMESPAN))); + gpr_atm_no_barrier_store(&g_shared_mutables.min_timer, + g_shard_queue[0]->min_deadline); + gpr_mu_unlock(&g_shared_mutables.mu); + gpr_spinlock_unlock(&g_shared_mutables.checker_mu); } GRPC_ERROR_UNREF(error); - return (int)n; + return result; } -bool grpc_timer_check(grpc_exec_ctx *exec_ctx, gpr_timespec now, - gpr_timespec *next) { +grpc_timer_check_result grpc_timer_check(grpc_exec_ctx *exec_ctx, + gpr_timespec now, gpr_timespec *next) { + // prelude GPR_ASSERT(now.clock_type == g_clock_type); - return run_some_expired_timers( - exec_ctx, now, next, + gpr_atm now_atm = timespec_to_atm_round_down(now); + + /* fetch from a thread-local first: this avoids contention on a globally + mutable cacheline in the common case */ + gpr_atm min_timer = gpr_tls_get(&g_last_seen_min_timer); + if (now_atm < min_timer) { + if (next != NULL) { + *next = + atm_to_timespec(GPR_MIN(timespec_to_atm_round_up(*next), min_timer)); + } + if (GRPC_TRACER_ON(grpc_timer_check_trace)) { + gpr_log(GPR_DEBUG, + "TIMER CHECK SKIP: now_atm=%" PRIdPTR " min_timer=%" PRIdPTR, + now_atm, min_timer); + } + return GRPC_TIMERS_CHECKED_AND_EMPTY; + } + + grpc_error *shutdown_error = gpr_time_cmp(now, gpr_inf_future(now.clock_type)) != 0 ? GRPC_ERROR_NONE - : GRPC_ERROR_CREATE("Shutting down timer system")); + : GRPC_ERROR_CREATE_FROM_STATIC_STRING("Shutting down timer system"); + + // tracing + if (GRPC_TRACER_ON(grpc_timer_check_trace)) { + char *next_str; + if (next == NULL) { + next_str = gpr_strdup("NULL"); + } else { + gpr_asprintf(&next_str, "%" PRId64 ".%09d [%" PRIdPTR "]", next->tv_sec, + next->tv_nsec, timespec_to_atm_round_down(*next)); + } + gpr_log(GPR_DEBUG, "TIMER CHECK BEGIN: now=%" PRId64 ".%09d [%" PRIdPTR + "] next=%s tls_min=%" PRIdPTR " glob_min=%" PRIdPTR, + now.tv_sec, now.tv_nsec, now_atm, next_str, + gpr_tls_get(&g_last_seen_min_timer), + gpr_atm_no_barrier_load(&g_shared_mutables.min_timer)); + gpr_free(next_str); + } + // actual code + grpc_timer_check_result r; + gpr_atm next_atm; + if (next == NULL) { + r = run_some_expired_timers(exec_ctx, now_atm, NULL, shutdown_error); + } else { + next_atm = timespec_to_atm_round_down(*next); + r = run_some_expired_timers(exec_ctx, now_atm, &next_atm, shutdown_error); + *next = atm_to_timespec(next_atm); + } + // tracing + if (GRPC_TRACER_ON(grpc_timer_check_trace)) { + char *next_str; + if (next == NULL) { + next_str = gpr_strdup("NULL"); + } else { + gpr_asprintf(&next_str, "%" PRId64 ".%09d [%" PRIdPTR "]", next->tv_sec, + next->tv_nsec, next_atm); + } + gpr_log(GPR_DEBUG, "TIMER CHECK END: r=%d; next=%s", r, next_str); + gpr_free(next_str); + } + return r; } #endif /* GRPC_TIMER_USE_GENERIC */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/timer_generic.h b/Sources/CgRPC/src/core/lib/iomgr/timer_generic.h index e4494adb5..72a4ac1f1 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/timer_generic.h +++ b/Sources/CgRPC/src/core/lib/iomgr/timer_generic.h @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -38,12 +23,12 @@ #include "src/core/lib/iomgr/exec_ctx.h" struct grpc_timer { - gpr_timespec deadline; + gpr_atm deadline; uint32_t heap_index; /* INVALID_HEAP_INDEX if not in heap */ - int triggered; + bool pending; struct grpc_timer *next; struct grpc_timer *prev; - grpc_closure closure; + grpc_closure *closure; }; #endif /* GRPC_CORE_LIB_IOMGR_TIMER_GENERIC_H */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/timer_heap.c b/Sources/CgRPC/src/core/lib/iomgr/timer_heap.c index f736d335e..a70e3942b 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/timer_heap.c +++ b/Sources/CgRPC/src/core/lib/iomgr/timer_heap.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -50,7 +35,7 @@ static void adjust_upwards(grpc_timer **first, uint32_t i, grpc_timer *t) { while (i > 0) { uint32_t parent = (uint32_t)(((int)i - 1) / 2); - if (gpr_time_cmp(first[parent]->deadline, t->deadline) <= 0) break; + if (first[parent]->deadline <= t->deadline) break; first[i] = first[parent]; first[i]->heap_index = i; i = parent; @@ -68,12 +53,12 @@ static void adjust_downwards(grpc_timer **first, uint32_t i, uint32_t length, uint32_t left_child = 1u + 2u * i; if (left_child >= length) break; uint32_t right_child = left_child + 1; - uint32_t next_i = right_child < length && - gpr_time_cmp(first[left_child]->deadline, - first[right_child]->deadline) > 0 - ? right_child - : left_child; - if (gpr_time_cmp(t->deadline, first[next_i]->deadline) <= 0) break; + uint32_t next_i = + right_child < length && + first[left_child]->deadline > first[right_child]->deadline + ? right_child + : left_child; + if (t->deadline <= first[next_i]->deadline) break; first[i] = first[next_i]; first[i]->heap_index = i; i = next_i; @@ -97,7 +82,7 @@ static void maybe_shrink(grpc_timer_heap *heap) { static void note_changed_priority(grpc_timer_heap *heap, grpc_timer *timer) { uint32_t i = timer->heap_index; uint32_t parent = (uint32_t)(((int)i - 1) / 2); - if (gpr_time_cmp(heap->timers[parent]->deadline, timer->deadline) > 0) { + if (heap->timers[parent]->deadline > timer->deadline) { adjust_upwards(heap->timers, i, timer); } else { adjust_downwards(heap->timers, i, heap->timer_count, timer); diff --git a/Sources/CgRPC/src/core/lib/iomgr/timer_heap.h b/Sources/CgRPC/src/core/lib/iomgr/timer_heap.h index 576c20e09..0d64199ab 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/timer_heap.h +++ b/Sources/CgRPC/src/core/lib/iomgr/timer_heap.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/timer_manager.c b/Sources/CgRPC/src/core/lib/iomgr/timer_manager.c new file mode 100644 index 000000000..631f7935d --- /dev/null +++ b/Sources/CgRPC/src/core/lib/iomgr/timer_manager.c @@ -0,0 +1,354 @@ +/* + * + * Copyright 2017 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 "src/core/lib/iomgr/timer_manager.h" + +#include +#include +#include + +#include "src/core/lib/debug/trace.h" +#include "src/core/lib/iomgr/timer.h" + +typedef struct completed_thread { + gpr_thd_id t; + struct completed_thread *next; +} completed_thread; + +extern grpc_tracer_flag grpc_timer_check_trace; + +// global mutex +static gpr_mu g_mu; +// are we multi-threaded +static bool g_threaded; +// cv to wait until a thread is needed +static gpr_cv g_cv_wait; +// cv for notification when threading ends +static gpr_cv g_cv_shutdown; +// number of threads in the system +static int g_thread_count; +// number of threads sitting around waiting +static int g_waiter_count; +// linked list of threads that have completed (and need joining) +static completed_thread *g_completed_threads; +// was the manager kicked by the timer system +static bool g_kicked; +// is there a thread waiting until the next timer should fire? +static bool g_has_timed_waiter; +// the deadline of the current timed waiter thread (only relevant if +// g_has_timed_waiter is true) +static gpr_timespec g_timed_waiter_deadline; +// generation counter to track which thread is waiting for the next timer +static uint64_t g_timed_waiter_generation; + +static void timer_thread(void *completed_thread_ptr); + +static void gc_completed_threads(void) { + if (g_completed_threads != NULL) { + completed_thread *to_gc = g_completed_threads; + g_completed_threads = NULL; + gpr_mu_unlock(&g_mu); + while (to_gc != NULL) { + gpr_thd_join(to_gc->t); + completed_thread *next = to_gc->next; + gpr_free(to_gc); + to_gc = next; + } + gpr_mu_lock(&g_mu); + } +} + +static void start_timer_thread_and_unlock(void) { + GPR_ASSERT(g_threaded); + ++g_waiter_count; + ++g_thread_count; + gpr_mu_unlock(&g_mu); + if (GRPC_TRACER_ON(grpc_timer_check_trace)) { + gpr_log(GPR_DEBUG, "Spawn timer thread"); + } + gpr_thd_options opt = gpr_thd_options_default(); + gpr_thd_options_set_joinable(&opt); + completed_thread *ct = gpr_malloc(sizeof(*ct)); + // The call to gpr_thd_new() has to be under the same lock used by + // gc_completed_threads(), particularly due to ct->t, which is written here + // (internally by gpr_thd_new) and read there. Otherwise it's possible for ct + // to leak through g_completed_threads and be freed in gc_completed_threads() + // before "&ct->t" is written to, causing a use-after-free. + gpr_mu_lock(&g_mu); + gpr_thd_new(&ct->t, timer_thread, ct, &opt); + gpr_mu_unlock(&g_mu); +} + +void grpc_timer_manager_tick() { + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + gpr_timespec next = gpr_inf_future(GPR_CLOCK_MONOTONIC); + gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC); + grpc_timer_check(&exec_ctx, now, &next); + grpc_exec_ctx_finish(&exec_ctx); +} + +static void run_some_timers(grpc_exec_ctx *exec_ctx) { + // if there's something to execute... + gpr_mu_lock(&g_mu); + // remove a waiter from the pool, and start another thread if necessary + --g_waiter_count; + if (g_waiter_count == 0 && g_threaded) { + start_timer_thread_and_unlock(); + } else { + // if there's no thread waiting with a timeout, kick an existing + // waiter so that the next deadline is not missed + if (!g_has_timed_waiter) { + if (GRPC_TRACER_ON(grpc_timer_check_trace)) { + gpr_log(GPR_DEBUG, "kick untimed waiter"); + } + gpr_cv_signal(&g_cv_wait); + } + gpr_mu_unlock(&g_mu); + } + // without our lock, flush the exec_ctx + grpc_exec_ctx_flush(exec_ctx); + gpr_mu_lock(&g_mu); + // garbage collect any threads hanging out that are dead + gc_completed_threads(); + // get ready to wait again + ++g_waiter_count; + gpr_mu_unlock(&g_mu); +} + +// wait until 'next' (or forever if there is already a timed waiter in the pool) +// returns true if the thread should continue executing (false if it should +// shutdown) +static bool wait_until(gpr_timespec next) { + const gpr_timespec inf_future = gpr_inf_future(GPR_CLOCK_MONOTONIC); + gpr_mu_lock(&g_mu); + // if we're not threaded anymore, leave + if (!g_threaded) { + gpr_mu_unlock(&g_mu); + return false; + } + + // If g_kicked is true at this point, it means there was a kick from the timer + // system that the timer-manager threads here missed. We cannot trust 'next' + // here any longer (since there might be an earlier deadline). So if g_kicked + // is true at this point, we should quickly exit this and get the next + // deadline from the timer system + + if (!g_kicked) { + // if there's no timed waiter, we should become one: that waiter waits + // only until the next timer should expire. All other timers wait forever + // + // 'g_timed_waiter_generation' is a global generation counter. The idea here + // is that the thread becoming a timed-waiter increments and stores this + // global counter locally in 'my_timed_waiter_generation' before going to + // sleep. After waking up, if my_timed_waiter_generation == + // g_timed_waiter_generation, it can be sure that it was the timed_waiter + // thread (and that no other thread took over while this was asleep) + // + // Initialize my_timed_waiter_generation to some value that is NOT equal to + // g_timed_waiter_generation + uint64_t my_timed_waiter_generation = g_timed_waiter_generation - 1; + + /* If there's no timed waiter, we should become one: that waiter waits only + until the next timer should expire. All other timer threads wait forever + unless their 'next' is earlier than the current timed-waiter's deadline + (in which case the thread with earlier 'next' takes over as the new timed + waiter) */ + if (gpr_time_cmp(next, inf_future) != 0) { + if (!g_has_timed_waiter || + (gpr_time_cmp(next, g_timed_waiter_deadline) < 0)) { + my_timed_waiter_generation = ++g_timed_waiter_generation; + g_has_timed_waiter = true; + g_timed_waiter_deadline = next; + + if (GRPC_TRACER_ON(grpc_timer_check_trace)) { + gpr_timespec wait_time = + gpr_time_sub(next, gpr_now(GPR_CLOCK_MONOTONIC)); + gpr_log(GPR_DEBUG, "sleep for a %" PRId64 ".%09d seconds", + wait_time.tv_sec, wait_time.tv_nsec); + } + } else { // g_timed_waiter == true && next >= g_timed_waiter_deadline + next = inf_future; + } + } + + if (GRPC_TRACER_ON(grpc_timer_check_trace) && + gpr_time_cmp(next, inf_future) == 0) { + gpr_log(GPR_DEBUG, "sleep until kicked"); + } + + gpr_cv_wait(&g_cv_wait, &g_mu, next); + + if (GRPC_TRACER_ON(grpc_timer_check_trace)) { + gpr_log(GPR_DEBUG, "wait ended: was_timed:%d kicked:%d", + my_timed_waiter_generation == g_timed_waiter_generation, + g_kicked); + } + // if this was the timed waiter, then we need to check timers, and flag + // that there's now no timed waiter... we'll look for a replacement if + // there's work to do after checking timers (code above) + if (my_timed_waiter_generation == g_timed_waiter_generation) { + g_has_timed_waiter = false; + g_timed_waiter_deadline = gpr_inf_future(GPR_CLOCK_MONOTONIC); + } + } + + // if this was a kick from the timer system, consume it (and don't stop + // this thread yet) + if (g_kicked) { + grpc_timer_consume_kick(); + g_kicked = false; + } + + gpr_mu_unlock(&g_mu); + return true; +} + +static void timer_main_loop(grpc_exec_ctx *exec_ctx) { + const gpr_timespec inf_future = gpr_inf_future(GPR_CLOCK_MONOTONIC); + for (;;) { + gpr_timespec next = inf_future; + gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC); + // check timer state, updates next to the next time to run a check + switch (grpc_timer_check(exec_ctx, now, &next)) { + case GRPC_TIMERS_FIRED: + run_some_timers(exec_ctx); + break; + case GRPC_TIMERS_NOT_CHECKED: + /* This case only happens under contention, meaning more than one timer + manager thread checked timers concurrently. + + If that happens, we're guaranteed that some other thread has just + checked timers, and this will avalanche into some other thread seeing + empty timers and doing a timed sleep. + + Consequently, we can just sleep forever here and be happy at some + saved wakeup cycles. */ + if (GRPC_TRACER_ON(grpc_timer_check_trace)) { + gpr_log(GPR_DEBUG, "timers not checked: expect another thread to"); + } + next = inf_future; + /* fall through */ + case GRPC_TIMERS_CHECKED_AND_EMPTY: + if (!wait_until(next)) { + return; + } + break; + } + } +} + +static void timer_thread_cleanup(completed_thread *ct) { + gpr_mu_lock(&g_mu); + // terminate the thread: drop the waiter count, thread count, and let whomever + // stopped the threading stuff know that we're done + --g_waiter_count; + --g_thread_count; + if (0 == g_thread_count) { + gpr_cv_signal(&g_cv_shutdown); + } + ct->next = g_completed_threads; + g_completed_threads = ct; + gpr_mu_unlock(&g_mu); + if (GRPC_TRACER_ON(grpc_timer_check_trace)) { + gpr_log(GPR_DEBUG, "End timer thread"); + } +} + +static void timer_thread(void *completed_thread_ptr) { + // this threads exec_ctx: we try to run things through to completion here + // since it's easy to spin up new threads + grpc_exec_ctx exec_ctx = + GRPC_EXEC_CTX_INITIALIZER(0, grpc_never_ready_to_finish, NULL); + timer_main_loop(&exec_ctx); + grpc_exec_ctx_finish(&exec_ctx); + timer_thread_cleanup(completed_thread_ptr); +} + +static void start_threads(void) { + gpr_mu_lock(&g_mu); + if (!g_threaded) { + g_threaded = true; + start_timer_thread_and_unlock(); + } else { + g_threaded = false; + gpr_mu_unlock(&g_mu); + } +} + +void grpc_timer_manager_init(void) { + gpr_mu_init(&g_mu); + gpr_cv_init(&g_cv_wait); + gpr_cv_init(&g_cv_shutdown); + g_threaded = false; + g_thread_count = 0; + g_waiter_count = 0; + g_completed_threads = NULL; + + g_has_timed_waiter = false; + g_timed_waiter_deadline = gpr_inf_future(GPR_CLOCK_MONOTONIC); + + start_threads(); +} + +static void stop_threads(void) { + gpr_mu_lock(&g_mu); + if (GRPC_TRACER_ON(grpc_timer_check_trace)) { + gpr_log(GPR_DEBUG, "stop timer threads: threaded=%d", g_threaded); + } + if (g_threaded) { + g_threaded = false; + gpr_cv_broadcast(&g_cv_wait); + if (GRPC_TRACER_ON(grpc_timer_check_trace)) { + gpr_log(GPR_DEBUG, "num timer threads: %d", g_thread_count); + } + while (g_thread_count > 0) { + gpr_cv_wait(&g_cv_shutdown, &g_mu, gpr_inf_future(GPR_CLOCK_REALTIME)); + if (GRPC_TRACER_ON(grpc_timer_check_trace)) { + gpr_log(GPR_DEBUG, "num timer threads: %d", g_thread_count); + } + gc_completed_threads(); + } + } + gpr_mu_unlock(&g_mu); +} + +void grpc_timer_manager_shutdown(void) { + stop_threads(); + + gpr_mu_destroy(&g_mu); + gpr_cv_destroy(&g_cv_wait); + gpr_cv_destroy(&g_cv_shutdown); +} + +void grpc_timer_manager_set_threading(bool threaded) { + if (threaded) { + start_threads(); + } else { + stop_threads(); + } +} + +void grpc_kick_poller(void) { + gpr_mu_lock(&g_mu); + g_kicked = true; + g_has_timed_waiter = false; + g_timed_waiter_deadline = gpr_inf_future(GPR_CLOCK_MONOTONIC); + ++g_timed_waiter_generation; + gpr_cv_signal(&g_cv_wait); + gpr_mu_unlock(&g_mu); +} diff --git a/Sources/CgRPC/src/core/lib/iomgr/timer_manager.h b/Sources/CgRPC/src/core/lib/iomgr/timer_manager.h new file mode 100644 index 000000000..0ba502928 --- /dev/null +++ b/Sources/CgRPC/src/core/lib/iomgr/timer_manager.h @@ -0,0 +1,37 @@ +/* + * + * Copyright 2017 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 GRPC_CORE_LIB_IOMGR_TIMER_MANAGER_H +#define GRPC_CORE_LIB_IOMGR_TIMER_MANAGER_H + +#include + +/* Timer Manager tries to keep one thread waiting for the next timeout at all + times */ + +void grpc_timer_manager_init(void); +void grpc_timer_manager_shutdown(void); + +/* enable/disable threading - must be called after grpc_timer_manager_init and + * before grpc_timer_manager_shutdown */ +void grpc_timer_manager_set_threading(bool enabled); +/* explicitly perform one tick of the timer system - for when threading is + * disabled */ +void grpc_timer_manager_tick(void); + +#endif /* GRPC_CORE_LIB_IOMGR_TIMER_MANAGER_H */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/timer_uv.c b/Sources/CgRPC/src/core/lib/iomgr/timer_uv.c index cfcb89268..70f49bcbe 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/timer_uv.c +++ b/Sources/CgRPC/src/core/lib/iomgr/timer_uv.c @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -38,10 +23,16 @@ #include #include +#include "src/core/lib/debug/trace.h" +#include "src/core/lib/iomgr/iomgr_uv.h" #include "src/core/lib/iomgr/timer.h" #include +grpc_tracer_flag grpc_timer_trace = GRPC_TRACER_INITIALIZER(false, "timer"); +grpc_tracer_flag grpc_timer_check_trace = + GRPC_TRACER_INITIALIZER(false, "timer_check"); + static void timer_close_callback(uv_handle_t *handle) { gpr_free(handle); } static void stop_uv_timer(uv_timer_t *handle) { @@ -53,47 +44,56 @@ static void stop_uv_timer(uv_timer_t *handle) { void run_expired_timer(uv_timer_t *handle) { grpc_timer *timer = (grpc_timer *)handle->data; grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - GPR_ASSERT(!timer->triggered); - timer->triggered = 1; - grpc_exec_ctx_sched(&exec_ctx, &timer->closure, GRPC_ERROR_NONE, NULL); + GRPC_UV_ASSERT_SAME_THREAD(); + GPR_ASSERT(timer->pending); + timer->pending = 0; + GRPC_CLOSURE_SCHED(&exec_ctx, timer->closure, GRPC_ERROR_NONE); stop_uv_timer(handle); grpc_exec_ctx_finish(&exec_ctx); } void grpc_timer_init(grpc_exec_ctx *exec_ctx, grpc_timer *timer, - gpr_timespec deadline, grpc_iomgr_cb_func timer_cb, - void *timer_cb_arg, gpr_timespec now) { + gpr_timespec deadline, grpc_closure *closure, + gpr_timespec now) { uint64_t timeout; uv_timer_t *uv_timer; - grpc_closure_init(&timer->closure, timer_cb, timer_cb_arg); + GRPC_UV_ASSERT_SAME_THREAD(); + timer->closure = closure; if (gpr_time_cmp(deadline, now) <= 0) { - timer->triggered = 1; - grpc_exec_ctx_sched(exec_ctx, &timer->closure, GRPC_ERROR_NONE, NULL); + timer->pending = 0; + GRPC_CLOSURE_SCHED(exec_ctx, timer->closure, GRPC_ERROR_NONE); return; } - timer->triggered = 0; + timer->pending = 1; timeout = (uint64_t)gpr_time_to_millis(gpr_time_sub(deadline, now)); uv_timer = gpr_malloc(sizeof(uv_timer_t)); uv_timer_init(uv_default_loop(), uv_timer); uv_timer->data = timer; timer->uv_timer = uv_timer; uv_timer_start(uv_timer, run_expired_timer, timeout, 0); + /* We assume that gRPC timers are only used alongside other active gRPC + objects, and that there will therefore always be something else keeping + the uv loop alive whenever there is a timer */ + uv_unref((uv_handle_t *)uv_timer); } void grpc_timer_cancel(grpc_exec_ctx *exec_ctx, grpc_timer *timer) { - if (!timer->triggered) { - timer->triggered = 1; - grpc_exec_ctx_sched(exec_ctx, &timer->closure, GRPC_ERROR_CANCELLED, NULL); + GRPC_UV_ASSERT_SAME_THREAD(); + if (timer->pending) { + timer->pending = 0; + GRPC_CLOSURE_SCHED(exec_ctx, timer->closure, GRPC_ERROR_CANCELLED); stop_uv_timer((uv_timer_t *)timer->uv_timer); } } -bool grpc_timer_check(grpc_exec_ctx *exec_ctx, gpr_timespec now, - gpr_timespec *next) { - return false; +grpc_timer_check_result grpc_timer_check(grpc_exec_ctx *exec_ctx, + gpr_timespec now, gpr_timespec *next) { + return GRPC_TIMERS_NOT_CHECKED; } void grpc_timer_list_init(gpr_timespec now) {} void grpc_timer_list_shutdown(grpc_exec_ctx *exec_ctx) {} +void grpc_timer_consume_kick(void) {} + #endif /* GRPC_UV */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/timer_uv.h b/Sources/CgRPC/src/core/lib/iomgr/timer_uv.h index 3de383ebd..8a4c17c84 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/timer_uv.h +++ b/Sources/CgRPC/src/core/lib/iomgr/timer_uv.h @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -37,11 +22,11 @@ #include "src/core/lib/iomgr/exec_ctx.h" struct grpc_timer { - grpc_closure closure; + grpc_closure *closure; /* This is actually a uv_timer_t*, but we want to keep platform-specific types out of headers */ void *uv_timer; - int triggered; + int pending; }; #endif /* GRPC_CORE_LIB_IOMGR_TIMER_UV_H */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/udp_server.c b/Sources/CgRPC/src/core/lib/iomgr/udp_server.c index 3c24ea9af..88fa34cb7 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/udp_server.c +++ b/Sources/CgRPC/src/core/lib/iomgr/udp_server.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -59,11 +44,13 @@ #include #include #include +#include "src/core/lib/channel/channel_args.h" #include "src/core/lib/iomgr/error.h" #include "src/core/lib/iomgr/ev_posix.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_factory_posix.h" #include "src/core/lib/iomgr/socket_utils_posix.h" #include "src/core/lib/iomgr/unix_sockets_posix.h" #include "src/core/lib/support/string.h" @@ -76,17 +63,32 @@ struct grpc_udp_listener { grpc_udp_server *server; grpc_resolved_address addr; grpc_closure read_closure; + grpc_closure write_closure; + // To be called when corresponding QuicGrpcServer closes all active + // connections. + grpc_closure orphan_fd_closure; grpc_closure destroyed_closure; grpc_udp_server_read_cb read_cb; + grpc_udp_server_write_cb write_cb; grpc_udp_server_orphan_cb orphan_cb; + // True if orphan_cb is trigered. + bool orphan_notified; struct grpc_udp_listener *next; }; +struct shutdown_fd_args { + grpc_fd *fd; + gpr_mu *server_mu; +}; + /* the overall server */ struct grpc_udp_server { gpr_mu mu; + /* factory to use for creating and binding sockets, or NULL */ + grpc_socket_factory *socket_factory; + /* active port count: how many ports are actually still listening */ size_t active_ports; /* destroyed port count: how many ports are completely destroyed */ @@ -107,13 +109,28 @@ struct grpc_udp_server { grpc_pollset **pollsets; /* number of pollsets in the pollsets array */ size_t pollset_count; - /* The parent grpc server */ - grpc_server *grpc_server; + /* opaque object to pass to callbacks */ + void *user_data; }; -grpc_udp_server *grpc_udp_server_create(void) { +static grpc_socket_factory *get_socket_factory(const grpc_channel_args *args) { + if (args) { + const grpc_arg *arg = grpc_channel_args_find(args, GRPC_ARG_SOCKET_FACTORY); + if (arg) { + GPR_ASSERT(arg->type == GRPC_ARG_POINTER); + return arg->value.pointer.p; + } + } + return NULL; +} + +grpc_udp_server *grpc_udp_server_create(const grpc_channel_args *args) { grpc_udp_server *s = gpr_malloc(sizeof(grpc_udp_server)); gpr_mu_init(&s->mu); + s->socket_factory = get_socket_factory(args); + if (s->socket_factory) { + grpc_socket_factory_ref(s->socket_factory); + } s->active_ports = 0; s->destroyed_ports = 0; s->shutdown = 0; @@ -124,9 +141,22 @@ grpc_udp_server *grpc_udp_server_create(void) { return s; } +static void shutdown_fd(grpc_exec_ctx *exec_ctx, void *args, + grpc_error *error) { + struct shutdown_fd_args *shutdown_args = (struct shutdown_fd_args *)args; + gpr_mu_lock(shutdown_args->server_mu); + grpc_fd_shutdown(exec_ctx, shutdown_args->fd, GRPC_ERROR_REF(error)); + gpr_mu_unlock(shutdown_args->server_mu); + gpr_free(shutdown_args); +} + +static void dummy_cb(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { + // No-op. +} + static void finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_udp_server *s) { if (s->shutdown_complete != NULL) { - grpc_exec_ctx_sched(exec_ctx, s->shutdown_complete, GRPC_ERROR_NONE, NULL); + GRPC_CLOSURE_SCHED(exec_ctx, s->shutdown_complete, GRPC_ERROR_NONE); } gpr_mu_destroy(&s->mu); @@ -137,6 +167,10 @@ static void finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_udp_server *s) { gpr_free(sp); } + if (s->socket_factory) { + grpc_socket_factory_unref(s->socket_factory); + } + gpr_free(s); } @@ -160,26 +194,27 @@ static void deactivated_all_ports(grpc_exec_ctx *exec_ctx, grpc_udp_server *s) { /* delete ALL the things */ gpr_mu_lock(&s->mu); - if (!s->shutdown) { - gpr_mu_unlock(&s->mu); - return; - } + GPR_ASSERT(s->shutdown); if (s->head) { grpc_udp_listener *sp; for (sp = s->head; sp; sp = sp->next) { grpc_unlink_if_unix_domain_socket(&sp->addr); - sp->destroyed_closure.cb = destroyed_port; - sp->destroyed_closure.cb_arg = s; - - /* Call the orphan_cb to signal that the FD is about to be closed and - * should no longer be used. */ - GPR_ASSERT(sp->orphan_cb); - sp->orphan_cb(sp->emfd); - + GRPC_CLOSURE_INIT(&sp->destroyed_closure, destroyed_port, s, + grpc_schedule_on_exec_ctx); + if (!sp->orphan_notified) { + /* Call the orphan_cb to signal that the FD is about to be closed and + * should no longer be used. Because at this point, all listening ports + * have been shutdown already, no need to shutdown again.*/ + GRPC_CLOSURE_INIT(&sp->orphan_fd_closure, dummy_cb, sp->emfd, + grpc_schedule_on_exec_ctx); + GPR_ASSERT(sp->orphan_cb); + sp->orphan_cb(exec_ctx, sp->emfd, &sp->orphan_fd_closure, + sp->server->user_data); + } grpc_fd_orphan(exec_ctx, sp->emfd, &sp->destroyed_closure, NULL, - "udp_listener_shutdown"); + false /* already_closed */, "udp_listener_shutdown"); } gpr_mu_unlock(&s->mu); } else { @@ -202,8 +237,14 @@ void grpc_udp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_udp_server *s, if (s->active_ports) { for (sp = s->head; sp; sp = sp->next) { GPR_ASSERT(sp->orphan_cb); - sp->orphan_cb(sp->emfd); - grpc_fd_shutdown(exec_ctx, sp->emfd); + struct shutdown_fd_args *args = gpr_malloc(sizeof(*args)); + args->fd = sp->emfd; + args->server_mu = &s->mu; + GRPC_CLOSURE_INIT(&sp->orphan_fd_closure, shutdown_fd, args, + grpc_schedule_on_exec_ctx); + sp->orphan_cb(exec_ctx, sp->emfd, &sp->orphan_fd_closure, + sp->server->user_data); + sp->orphan_notified = true; } gpr_mu_unlock(&s->mu); } else { @@ -212,8 +253,17 @@ void grpc_udp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_udp_server *s, } } +static int bind_socket(grpc_socket_factory *socket_factory, int sockfd, + const grpc_resolved_address *addr) { + return (socket_factory != NULL) + ? grpc_socket_factory_bind(socket_factory, sockfd, addr) + : bind(sockfd, (struct sockaddr *)addr->addr, + (socklen_t)addr->len); +} + /* Prepare a recently-created socket for listening. */ -static int prepare_socket(int fd, const grpc_resolved_address *addr) { +static int prepare_socket(grpc_socket_factory *socket_factory, int fd, + const grpc_resolved_address *addr) { grpc_resolved_address sockname_temp; struct sockaddr *addr_ptr = (struct sockaddr *)addr->addr; /* Set send/receive socket buffers to 1 MB */ @@ -243,7 +293,7 @@ static int prepare_socket(int fd, const grpc_resolved_address *addr) { } GPR_ASSERT(addr->len < ~(socklen_t)0); - if (bind(fd, (struct sockaddr *)addr, (socklen_t)addr->len) < 0) { + if (bind_socket(socket_factory, fd, addr) < 0) { char *addr_str; grpc_sockaddr_to_string(&addr_str, addr, 0); gpr_log(GPR_ERROR, "bind addr=%s: %s", addr_str, strerror(errno)); @@ -285,7 +335,7 @@ static void on_read(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { gpr_mu_lock(&sp->server->mu); if (error != GRPC_ERROR_NONE) { - if (0 == --sp->server->active_ports) { + if (0 == --sp->server->active_ports && sp->server->shutdown) { gpr_mu_unlock(&sp->server->mu); deactivated_all_ports(exec_ctx, sp->server); } else { @@ -296,23 +346,47 @@ static void on_read(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { /* Tell the registered callback that data is available to read. */ GPR_ASSERT(sp->read_cb); - sp->read_cb(exec_ctx, sp->emfd, sp->server->grpc_server); + sp->read_cb(exec_ctx, sp->emfd, sp->server->user_data); /* Re-arm the notification event so we get another chance to read. */ grpc_fd_notify_on_read(exec_ctx, sp->emfd, &sp->read_closure); gpr_mu_unlock(&sp->server->mu); } +static void on_write(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { + grpc_udp_listener *sp = arg; + + gpr_mu_lock(&(sp->server->mu)); + if (error != GRPC_ERROR_NONE) { + if (0 == --sp->server->active_ports && sp->server->shutdown) { + gpr_mu_unlock(&sp->server->mu); + deactivated_all_ports(exec_ctx, sp->server); + } else { + gpr_mu_unlock(&sp->server->mu); + } + return; + } + + /* Tell the registered callback that the socket is writeable. */ + GPR_ASSERT(sp->write_cb); + sp->write_cb(exec_ctx, sp->emfd, sp->server->user_data); + + /* Re-arm the notification event so we get another chance to write. */ + grpc_fd_notify_on_write(exec_ctx, sp->emfd, &sp->write_closure); + gpr_mu_unlock(&sp->server->mu); +} + static int add_socket_to_server(grpc_udp_server *s, int fd, const grpc_resolved_address *addr, grpc_udp_server_read_cb read_cb, + grpc_udp_server_write_cb write_cb, grpc_udp_server_orphan_cb orphan_cb) { grpc_udp_listener *sp; int port; char *addr_str; char *name; - port = prepare_socket(fd, addr); + port = prepare_socket(s->socket_factory, fd, addr); if (port >= 0) { grpc_sockaddr_to_string(&addr_str, addr, 1); gpr_asprintf(&name, "udp-server-listener:%s", addr_str); @@ -332,7 +406,9 @@ static int add_socket_to_server(grpc_udp_server *s, int fd, sp->emfd = grpc_fd_create(fd, name); memcpy(&sp->addr, addr, sizeof(grpc_resolved_address)); sp->read_cb = read_cb; + sp->write_cb = write_cb; sp->orphan_cb = orphan_cb; + sp->orphan_notified = false; GPR_ASSERT(sp->emfd); gpr_mu_unlock(&s->mu); gpr_free(name); @@ -344,6 +420,7 @@ static int add_socket_to_server(grpc_udp_server *s, int fd, int grpc_udp_server_add_port(grpc_udp_server *s, const grpc_resolved_address *addr, grpc_udp_server_read_cb read_cb, + grpc_udp_server_write_cb write_cb, grpc_udp_server_orphan_cb orphan_cb) { grpc_udp_listener *sp; int allocated_port1 = -1; @@ -388,9 +465,10 @@ int grpc_udp_server_add_port(grpc_udp_server *s, /* Try listening on IPv6 first. */ addr = &wild6; // TODO(rjshade): Test and propagate the returned grpc_error*: - GRPC_ERROR_UNREF(grpc_create_dualstack_socket(addr, SOCK_DGRAM, IPPROTO_UDP, - &dsmode, &fd)); - allocated_port1 = add_socket_to_server(s, fd, addr, read_cb, orphan_cb); + GRPC_ERROR_UNREF(grpc_create_dualstack_socket_using_factory( + s->socket_factory, addr, SOCK_DGRAM, IPPROTO_UDP, &dsmode, &fd)); + allocated_port1 = + add_socket_to_server(s, fd, addr, read_cb, write_cb, orphan_cb); if (fd >= 0 && dsmode == GRPC_DSMODE_DUALSTACK) { goto done; } @@ -403,8 +481,8 @@ int grpc_udp_server_add_port(grpc_udp_server *s, } // TODO(rjshade): Test and propagate the returned grpc_error*: - GRPC_ERROR_UNREF(grpc_create_dualstack_socket(addr, SOCK_DGRAM, IPPROTO_UDP, - &dsmode, &fd)); + GRPC_ERROR_UNREF(grpc_create_dualstack_socket_using_factory( + s->socket_factory, addr, SOCK_DGRAM, IPPROTO_UDP, &dsmode, &fd)); if (fd < 0) { gpr_log(GPR_ERROR, "Unable to create socket: %s", strerror(errno)); } @@ -412,7 +490,8 @@ int grpc_udp_server_add_port(grpc_udp_server *s, grpc_sockaddr_is_v4mapped(addr, &addr4_copy)) { addr = &addr4_copy; } - allocated_port2 = add_socket_to_server(s, fd, addr, read_cb, orphan_cb); + allocated_port2 = + add_socket_to_server(s, fd, addr, read_cb, write_cb, orphan_cb); done: gpr_free(allocated_addr); @@ -433,24 +512,32 @@ int grpc_udp_server_get_fd(grpc_udp_server *s, unsigned port_index) { void grpc_udp_server_start(grpc_exec_ctx *exec_ctx, grpc_udp_server *s, grpc_pollset **pollsets, size_t pollset_count, - grpc_server *server) { + void *user_data) { size_t i; gpr_mu_lock(&s->mu); grpc_udp_listener *sp; GPR_ASSERT(s->active_ports == 0); s->pollsets = pollsets; - s->grpc_server = server; + s->user_data = user_data; sp = s->head; while (sp != NULL) { for (i = 0; i < pollset_count; i++) { grpc_pollset_add_fd(exec_ctx, pollsets[i], sp->emfd); } - sp->read_closure.cb = on_read; - sp->read_closure.cb_arg = sp; + GRPC_CLOSURE_INIT(&sp->read_closure, on_read, sp, + grpc_schedule_on_exec_ctx); grpc_fd_notify_on_read(exec_ctx, sp->emfd, &sp->read_closure); - s->active_ports++; + GRPC_CLOSURE_INIT(&sp->write_closure, on_write, sp, + grpc_schedule_on_exec_ctx); + grpc_fd_notify_on_write(exec_ctx, sp->emfd, &sp->write_closure); + + /* Registered for both read and write callbacks: increment active_ports + * twice to account for this, and delay free-ing of memory until both + * on_read and on_write have fired. */ + s->active_ports += 2; + sp = sp->next; } diff --git a/Sources/CgRPC/src/core/lib/iomgr/udp_server.h b/Sources/CgRPC/src/core/lib/iomgr/udp_server.h index f3c466a03..881468ea2 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/udp_server.h +++ b/Sources/CgRPC/src/core/lib/iomgr/udp_server.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -47,18 +32,25 @@ typedef struct grpc_udp_server grpc_udp_server; /* Called when data is available to read from the socket. */ typedef void (*grpc_udp_server_read_cb)(grpc_exec_ctx *exec_ctx, grpc_fd *emfd, - struct grpc_server *server); + void *user_data); + +/* Called when the socket is writeable. */ +typedef void (*grpc_udp_server_write_cb)(grpc_exec_ctx *exec_ctx, grpc_fd *emfd, + void *user_data); /* Called when the grpc_fd is about to be orphaned (and the FD closed). */ -typedef void (*grpc_udp_server_orphan_cb)(grpc_fd *emfd); +typedef void (*grpc_udp_server_orphan_cb)(grpc_exec_ctx *exec_ctx, + grpc_fd *emfd, + grpc_closure *shutdown_fd_callback, + void *user_data); /* Create a server, initially not bound to any ports */ -grpc_udp_server *grpc_udp_server_create(void); +grpc_udp_server *grpc_udp_server_create(const grpc_channel_args *args); -/* Start listening to bound ports */ +/* Start listening to bound ports. user_data is passed to callbacks. */ void grpc_udp_server_start(grpc_exec_ctx *exec_ctx, grpc_udp_server *udp_server, grpc_pollset **pollsets, size_t pollset_count, - struct grpc_server *server); + void *user_data); int grpc_udp_server_get_fd(grpc_udp_server *s, unsigned port_index); @@ -75,6 +67,7 @@ int grpc_udp_server_get_fd(grpc_udp_server *s, unsigned port_index); int grpc_udp_server_add_port(grpc_udp_server *s, const grpc_resolved_address *addr, grpc_udp_server_read_cb read_cb, + grpc_udp_server_write_cb write_cb, grpc_udp_server_orphan_cb orphan_cb); void grpc_udp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_udp_server *server, diff --git a/Sources/CgRPC/src/core/lib/iomgr/unix_sockets_posix.c b/Sources/CgRPC/src/core/lib/iomgr/unix_sockets_posix.c index 030acd981..0c8627c8c 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/unix_sockets_posix.c +++ b/Sources/CgRPC/src/core/lib/iomgr/unix_sockets_posix.c @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 "src/core/lib/iomgr/port.h" @@ -45,6 +30,7 @@ #include #include +#include void grpc_create_socketpair_if_unix(int sv[2]) { GPR_ASSERT(socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == 0); @@ -53,7 +39,16 @@ void grpc_create_socketpair_if_unix(int sv[2]) { grpc_error *grpc_resolve_unix_domain_address(const char *name, grpc_resolved_addresses **addrs) { struct sockaddr_un *un; - + if (strlen(name) > GPR_ARRAY_SIZE(((struct sockaddr_un *)0)->sun_path) - 1) { + char *err_msg; + grpc_error *err; + gpr_asprintf(&err_msg, + "Path name should not have more than %" PRIuPTR " characters.", + GPR_ARRAY_SIZE(un->sun_path) - 1); + err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(err_msg); + gpr_free(err_msg); + return err; + } *addrs = gpr_malloc(sizeof(grpc_resolved_addresses)); (*addrs)->naddrs = 1; (*addrs)->addrs = gpr_malloc(sizeof(grpc_resolved_address)); diff --git a/Sources/CgRPC/src/core/lib/iomgr/unix_sockets_posix.h b/Sources/CgRPC/src/core/lib/iomgr/unix_sockets_posix.h index 21afd3aa1..25b64b3ee 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/unix_sockets_posix.h +++ b/Sources/CgRPC/src/core/lib/iomgr/unix_sockets_posix.h @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/unix_sockets_posix_noop.c b/Sources/CgRPC/src/core/lib/iomgr/unix_sockets_posix_noop.c index 1daf5152c..e46b1c003 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/unix_sockets_posix_noop.c +++ b/Sources/CgRPC/src/core/lib/iomgr/unix_sockets_posix_noop.c @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -47,7 +32,8 @@ void grpc_create_socketpair_if_unix(int sv[2]) { grpc_error *grpc_resolve_unix_domain_address( const char *name, grpc_resolved_addresses **addresses) { *addresses = NULL; - return GRPC_ERROR_CREATE("Unix domain sockets are not supported on Windows"); + return GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "Unix domain sockets are not supported on Windows"); } int grpc_is_unix_socket(const grpc_resolved_address *addr) { return false; } diff --git a/Sources/CgRPC/src/core/lib/iomgr/wakeup_fd_cv.c b/Sources/CgRPC/src/core/lib/iomgr/wakeup_fd_cv.c index da4c2870c..075a0b642 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/wakeup_fd_cv.c +++ b/Sources/CgRPC/src/core/lib/iomgr/wakeup_fd_cv.c @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/wakeup_fd_cv.h b/Sources/CgRPC/src/core/lib/iomgr/wakeup_fd_cv.h index ac16be175..46e84f584 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/wakeup_fd_cv.h +++ b/Sources/CgRPC/src/core/lib/iomgr/wakeup_fd_cv.h @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -58,6 +43,7 @@ typedef struct cv_node { gpr_cv* cv; struct cv_node* next; + struct cv_node* prev; } cv_node; typedef struct fd_node { @@ -68,9 +54,8 @@ typedef struct fd_node { typedef struct cv_fd_table { gpr_mu mu; - int pollcount; - int shutdown; - gpr_cv shutdown_complete; + gpr_refcount pollcount; + gpr_cv shutdown_cv; fd_node* cvfds; fd_node* free_fds; unsigned int size; diff --git a/Sources/CgRPC/src/core/lib/iomgr/wakeup_fd_eventfd.c b/Sources/CgRPC/src/core/lib/iomgr/wakeup_fd_eventfd.c index 373e21d3e..81cb7ee28 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/wakeup_fd_eventfd.c +++ b/Sources/CgRPC/src/core/lib/iomgr/wakeup_fd_eventfd.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/wakeup_fd_nospecial.c b/Sources/CgRPC/src/core/lib/iomgr/wakeup_fd_nospecial.c index 611bced02..4c20b8c1b 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/wakeup_fd_nospecial.c +++ b/Sources/CgRPC/src/core/lib/iomgr/wakeup_fd_nospecial.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/wakeup_fd_pipe.c b/Sources/CgRPC/src/core/lib/iomgr/wakeup_fd_pipe.c index e186d6368..4189488f8 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/wakeup_fd_pipe.c +++ b/Sources/CgRPC/src/core/lib/iomgr/wakeup_fd_pipe.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/wakeup_fd_pipe.h b/Sources/CgRPC/src/core/lib/iomgr/wakeup_fd_pipe.h index 8972efc27..f860406bd 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/wakeup_fd_pipe.h +++ b/Sources/CgRPC/src/core/lib/iomgr/wakeup_fd_pipe.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/wakeup_fd_posix.c b/Sources/CgRPC/src/core/lib/iomgr/wakeup_fd_posix.c index 85526402b..25daa7d3f 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/wakeup_fd_posix.c +++ b/Sources/CgRPC/src/core/lib/iomgr/wakeup_fd_posix.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/wakeup_fd_posix.h b/Sources/CgRPC/src/core/lib/iomgr/wakeup_fd_posix.h index 71d32d97b..a9584d0d4 100644 --- a/Sources/CgRPC/src/core/lib/iomgr/wakeup_fd_posix.h +++ b/Sources/CgRPC/src/core/lib/iomgr/wakeup_fd_posix.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -46,7 +31,7 @@ * * Setup: * 1. Before calling anything, call global_init() at least once. - * 1. Call grpc_wakeup_fd_create() to get a wakeup_fd. + * 1. Call grpc_wakeup_fd_init() to set up a wakeup_fd. * 2. Add the result of GRPC_WAKEUP_FD_FD to the set of monitored file * descriptors for the poll() style API you are using. Monitor the file * descriptor for readability. diff --git a/Sources/CgRPC/src/core/lib/iomgr/workqueue.h b/Sources/CgRPC/src/core/lib/iomgr/workqueue.h deleted file mode 100644 index 73d984984..000000000 --- a/Sources/CgRPC/src/core/lib/iomgr/workqueue.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#ifndef GRPC_CORE_LIB_IOMGR_WORKQUEUE_H -#define GRPC_CORE_LIB_IOMGR_WORKQUEUE_H - -#include "src/core/lib/iomgr/closure.h" -#include "src/core/lib/iomgr/exec_ctx.h" -#include "src/core/lib/iomgr/iomgr.h" -#include "src/core/lib/iomgr/pollset.h" -#include "src/core/lib/iomgr/pollset_set.h" -#include "src/core/lib/iomgr/port.h" - -#ifdef GPR_WINDOWS -#include "src/core/lib/iomgr/workqueue_windows.h" -#endif - -/* grpc_workqueue is forward declared in exec_ctx.h */ - -/* Reference counting functions. Use the macro's always - (GRPC_WORKQUEUE_{REF,UNREF}). - - Pass in a descriptive reason string for reffing/unreffing as the last - argument to each macro. When GRPC_WORKQUEUE_REFCOUNT_DEBUG is defined, that - string will be printed alongside the refcount. When it is not defined, the - string will be discarded at compilation time. */ - -/*#define GRPC_WORKQUEUE_REFCOUNT_DEBUG*/ -#ifdef GRPC_WORKQUEUE_REFCOUNT_DEBUG -#define GRPC_WORKQUEUE_REF(p, r) \ - grpc_workqueue_ref((p), __FILE__, __LINE__, (r)) -#define GRPC_WORKQUEUE_UNREF(exec_ctx, p, r) \ - grpc_workqueue_unref((exec_ctx), (p), __FILE__, __LINE__, (r)) -grpc_workqueue *grpc_workqueue_ref(grpc_workqueue *workqueue, const char *file, - int line, const char *reason); -void grpc_workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue, - const char *file, int line, const char *reason); -#else -#define GRPC_WORKQUEUE_REF(p, r) grpc_workqueue_ref((p)) -#define GRPC_WORKQUEUE_UNREF(cl, p, r) grpc_workqueue_unref((cl), (p)) -grpc_workqueue *grpc_workqueue_ref(grpc_workqueue *workqueue); -void grpc_workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue); -#endif - -/** Add a work item to a workqueue. Items added to a work queue will be started - in approximately the order they were enqueued, on some thread that may or - may not be the current thread. Successive closures enqueued onto a workqueue - MAY be executed concurrently. - - It is generally more expensive to add a closure to a workqueue than to the - execution context, both in terms of CPU work and in execution latency. - - Use work queues when it's important that other threads be given a chance to - tackle some workload. */ -void grpc_workqueue_enqueue(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue, - grpc_closure *closure, grpc_error *error); - -#endif /* GRPC_CORE_LIB_IOMGR_WORKQUEUE_H */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/workqueue_uv.c b/Sources/CgRPC/src/core/lib/iomgr/workqueue_uv.c deleted file mode 100644 index e58ca476c..000000000 --- a/Sources/CgRPC/src/core/lib/iomgr/workqueue_uv.c +++ /dev/null @@ -1,66 +0,0 @@ -/* - * - * Copyright 2016, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include "src/core/lib/iomgr/port.h" - -#ifdef GRPC_UV - -#include "src/core/lib/iomgr/workqueue.h" - -// Minimal implementation of grpc_workqueue for libuv -// Works by directly enqueuing workqueue items onto the current execution -// context, which is at least correct, if not performant or in the spirit of -// workqueues. - -void grpc_workqueue_flush(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue) {} - -#ifdef GRPC_WORKQUEUE_REFCOUNT_DEBUG -grpc_workqueue *grpc_workqueue_ref(grpc_workqueue *workqueue, const char *file, - int line, const char *reason) { - return workqueue; -} -void grpc_workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue, - const char *file, int line, const char *reason) {} -#else -grpc_workqueue *grpc_workqueue_ref(grpc_workqueue *workqueue) { - return workqueue; -} -void grpc_workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue) {} -#endif - -void grpc_workqueue_enqueue(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue, - grpc_closure *closure, grpc_error *error) { - grpc_exec_ctx_sched(exec_ctx, closure, error, NULL); -} - -#endif /* GPR_UV */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/workqueue_uv.h b/Sources/CgRPC/src/core/lib/iomgr/workqueue_uv.h deleted file mode 100644 index be3f8e4d9..000000000 --- a/Sources/CgRPC/src/core/lib/iomgr/workqueue_uv.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * - * Copyright 2016, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#ifndef GRPC_CORE_LIB_IOMGR_WORKQUEUE_UV_H -#define GRPC_CORE_LIB_IOMGR_WORKQUEUE_UV_H - -#endif /* GRPC_CORE_LIB_IOMGR_WORKQUEUE_UV_H */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/workqueue_windows.c b/Sources/CgRPC/src/core/lib/iomgr/workqueue_windows.c deleted file mode 100644 index 5c93d3c59..000000000 --- a/Sources/CgRPC/src/core/lib/iomgr/workqueue_windows.c +++ /dev/null @@ -1,64 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include - -#ifdef GPR_WINDOWS - -#include "src/core/lib/iomgr/workqueue.h" - -// Minimal implementation of grpc_workqueue for Windows -// Works by directly enqueuing workqueue items onto the current execution -// context, which is at least correct, if not performant or in the spirit of -// workqueues. - -#ifdef GRPC_WORKQUEUE_REFCOUNT_DEBUG -grpc_workqueue *grpc_workqueue_ref(grpc_workqueue *workqueue, const char *file, - int line, const char *reason) { - return workqueue; -} -void grpc_workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue, - const char *file, int line, const char *reason) {} -#else -grpc_workqueue *grpc_workqueue_ref(grpc_workqueue *workqueue) { - return workqueue; -} -void grpc_workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue) {} -#endif - -void grpc_workqueue_enqueue(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue, - grpc_closure *closure, grpc_error *error) { - grpc_exec_ctx_sched(exec_ctx, closure, error, NULL); -} - -#endif /* GPR_WINDOWS */ diff --git a/Sources/CgRPC/src/core/lib/iomgr/workqueue_windows.h b/Sources/CgRPC/src/core/lib/iomgr/workqueue_windows.h deleted file mode 100644 index e5d59130b..000000000 --- a/Sources/CgRPC/src/core/lib/iomgr/workqueue_windows.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#ifndef GRPC_CORE_LIB_IOMGR_WORKQUEUE_WINDOWS_H -#define GRPC_CORE_LIB_IOMGR_WORKQUEUE_WINDOWS_H - -#endif /* GRPC_CORE_LIB_IOMGR_WORKQUEUE_WINDOWS_H */ diff --git a/Sources/CgRPC/src/core/lib/json/json.c b/Sources/CgRPC/src/core/lib/json/json.c index 48b13686d..25eee0553 100644 --- a/Sources/CgRPC/src/core/lib/json/json.c +++ b/Sources/CgRPC/src/core/lib/json/json.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -38,8 +23,7 @@ #include "src/core/lib/json/json.h" grpc_json* grpc_json_create(grpc_json_type type) { - grpc_json* json = gpr_malloc(sizeof(*json)); - memset(json, 0, sizeof(*json)); + grpc_json* json = gpr_zalloc(sizeof(*json)); json->type = type; return json; diff --git a/Sources/CgRPC/src/core/lib/json/json.h b/Sources/CgRPC/src/core/lib/json/json.h index 7111db0b5..bbd43025e 100644 --- a/Sources/CgRPC/src/core/lib/json/json.h +++ b/Sources/CgRPC/src/core/lib/json/json.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/json/json_common.h b/Sources/CgRPC/src/core/lib/json/json_common.h index fa13088be..bfa2ba32b 100644 --- a/Sources/CgRPC/src/core/lib/json/json_common.h +++ b/Sources/CgRPC/src/core/lib/json/json_common.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/json/json_reader.c b/Sources/CgRPC/src/core/lib/json/json_reader.c index 5b42ca53f..094a35176 100644 --- a/Sources/CgRPC/src/core/lib/json/json_reader.c +++ b/Sources/CgRPC/src/core/lib/json/json_reader.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015-2016, Google Inc. - * All rights reserved. + * Copyright 2015-2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -193,6 +178,7 @@ grpc_json_reader_status grpc_json_reader_run(grpc_json_reader *reader) { json_reader_string_clear(reader); reader->state = GRPC_JSON_STATE_VALUE_END; /* The missing break here is intentional. */ + /* fallthrough */ case GRPC_JSON_STATE_VALUE_END: case GRPC_JSON_STATE_OBJECT_KEY_BEGIN: diff --git a/Sources/CgRPC/src/core/lib/json/json_reader.h b/Sources/CgRPC/src/core/lib/json/json_reader.h index e0322c550..577fbbbaf 100644 --- a/Sources/CgRPC/src/core/lib/json/json_reader.h +++ b/Sources/CgRPC/src/core/lib/json/json_reader.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/json/json_string.c b/Sources/CgRPC/src/core/lib/json/json_string.c index 4af7ee717..65b5f0f48 100644 --- a/Sources/CgRPC/src/core/lib/json/json_string.c +++ b/Sources/CgRPC/src/core/lib/json/json_string.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/json/json_writer.c b/Sources/CgRPC/src/core/lib/json/json_writer.c index b6a17f41e..eab1bff7a 100644 --- a/Sources/CgRPC/src/core/lib/json/json_writer.c +++ b/Sources/CgRPC/src/core/lib/json/json_writer.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/json/json_writer.h b/Sources/CgRPC/src/core/lib/json/json_writer.h index faeb41d03..8779039d4 100644 --- a/Sources/CgRPC/src/core/lib/json/json_writer.h +++ b/Sources/CgRPC/src/core/lib/json/json_writer.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/profiling/basic_timers.c b/Sources/CgRPC/src/core/lib/profiling/basic_timers.c index bdf9af233..c7645b74f 100644 --- a/Sources/CgRPC/src/core/lib/profiling/basic_timers.c +++ b/Sources/CgRPC/src/core/lib/profiling/basic_timers.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -43,6 +28,9 @@ #include #include #include +#include + +#include "src/core/lib/support/env.h" typedef enum { BEGIN = '{', END = '}', MARK = '.' } marker_type; @@ -74,7 +62,7 @@ typedef struct gpr_timer_log_list { static __thread gpr_timer_log *g_thread_log; static gpr_once g_once_init = GPR_ONCE_INIT; static FILE *output_file; -static const char *output_filename = "latency_trace.txt"; +static const char *output_filename_or_null = NULL; static pthread_mutex_t g_mu; static pthread_cond_t g_cv; static gpr_timer_log_list g_in_progress_logs; @@ -85,6 +73,17 @@ static __thread int g_thread_id; static int g_next_thread_id; static int g_writing_enabled = 1; +static const char *output_filename() { + if (output_filename_or_null == NULL) { + output_filename_or_null = gpr_getenv("LATENCY_TRACE"); + if (output_filename_or_null == NULL || + strlen(output_filename_or_null) == 0) { + output_filename_or_null = "latency_trace.txt"; + } + } + return output_filename_or_null; +} + static int timer_log_push_back(gpr_timer_log_list *list, gpr_timer_log *log) { if (list->head == NULL) { list->head = list->tail = log; @@ -134,7 +133,7 @@ static void timer_log_remove(gpr_timer_log_list *list, gpr_timer_log *log) { static void write_log(gpr_timer_log *log) { size_t i; if (output_file == NULL) { - output_file = fopen(output_filename, "w"); + output_file = fopen(output_filename(), "w"); } for (i = 0; i < log->num_entries; i++) { gpr_timer_entry *entry = &(log->log[i]); @@ -198,13 +197,13 @@ static void finish_writing(void) { } void gpr_timers_set_log_filename(const char *filename) { - output_filename = filename; + output_filename_or_null = filename; } static void init_output() { gpr_thd_options options = gpr_thd_options_default(); gpr_thd_options_set_joinable(&options); - gpr_thd_new(&g_writing_thread, writing_thread, NULL, &options); + GPR_ASSERT(gpr_thd_new(&g_writing_thread, writing_thread, NULL, &options)); atexit(finish_writing); } diff --git a/Sources/CgRPC/src/core/lib/profiling/stap_timers.c b/Sources/CgRPC/src/core/lib/profiling/stap_timers.c index 25e38e6d9..c86d74f05 100644 --- a/Sources/CgRPC/src/core/lib/profiling/stap_timers.c +++ b/Sources/CgRPC/src/core/lib/profiling/stap_timers.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/profiling/timers.h b/Sources/CgRPC/src/core/lib/profiling/timers.h index 621cdbf65..58e6659e6 100644 --- a/Sources/CgRPC/src/core/lib/profiling/timers.h +++ b/Sources/CgRPC/src/core/lib/profiling/timers.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/security/context/security_context.c b/Sources/CgRPC/src/core/lib/security/context/security_context.c index 2204fadf5..8fff2c92c 100644 --- a/Sources/CgRPC/src/core/lib/security/context/security_context.c +++ b/Sources/CgRPC/src/core/lib/security/context/security_context.c @@ -1,38 +1,24 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 +#include "src/core/lib/channel/channel_args.h" #include "src/core/lib/security/context/security_context.h" #include "src/core/lib/support/string.h" #include "src/core/lib/surface/api_trace.h" @@ -43,10 +29,16 @@ #include #include +#ifndef NDEBUG +grpc_tracer_flag grpc_trace_auth_context_refcount = + GRPC_TRACER_INITIALIZER(false, "auth_context_refcount"); +#endif + /* --- grpc_call --- */ grpc_call_error grpc_call_set_credentials(grpc_call *call, grpc_call_credentials *creds) { + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_client_security_context *ctx = NULL; GRPC_API_TRACE("grpc_call_set_credentials(call=%p, creds=%p)", 2, (call, creds)); @@ -62,9 +54,10 @@ grpc_call_error grpc_call_set_credentials(grpc_call *call, grpc_call_context_set(call, GRPC_CONTEXT_SECURITY, ctx, grpc_client_security_context_destroy); } else { - grpc_call_credentials_unref(ctx->creds); + grpc_call_credentials_unref(&exec_ctx, ctx->creds); ctx->creds = grpc_call_credentials_ref(creds); } + grpc_exec_ctx_finish(&exec_ctx); return GRPC_CALL_OK; } @@ -89,29 +82,25 @@ void grpc_auth_context_release(grpc_auth_context *context) { /* --- grpc_client_security_context --- */ grpc_client_security_context *grpc_client_security_context_create(void) { - grpc_client_security_context *ctx = - gpr_malloc(sizeof(grpc_client_security_context)); - memset(ctx, 0, sizeof(grpc_client_security_context)); - return ctx; + return gpr_zalloc(sizeof(grpc_client_security_context)); } void grpc_client_security_context_destroy(void *ctx) { + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_client_security_context *c = (grpc_client_security_context *)ctx; - grpc_call_credentials_unref(c->creds); + grpc_call_credentials_unref(&exec_ctx, c->creds); GRPC_AUTH_CONTEXT_UNREF(c->auth_context, "client_security_context"); if (c->extension.instance != NULL && c->extension.destroy != NULL) { c->extension.destroy(c->extension.instance); } gpr_free(ctx); + grpc_exec_ctx_finish(&exec_ctx); } /* --- grpc_server_security_context --- */ grpc_server_security_context *grpc_server_security_context_create(void) { - grpc_server_security_context *ctx = - gpr_malloc(sizeof(grpc_server_security_context)); - memset(ctx, 0, sizeof(grpc_server_security_context)); - return ctx; + return gpr_zalloc(sizeof(grpc_server_security_context)); } void grpc_server_security_context_destroy(void *ctx) { @@ -128,8 +117,7 @@ void grpc_server_security_context_destroy(void *ctx) { static grpc_auth_property_iterator empty_iterator = {NULL, 0, NULL}; grpc_auth_context *grpc_auth_context_create(grpc_auth_context *chained) { - grpc_auth_context *ctx = gpr_malloc(sizeof(grpc_auth_context)); - memset(ctx, 0, sizeof(grpc_auth_context)); + grpc_auth_context *ctx = gpr_zalloc(sizeof(grpc_auth_context)); gpr_ref_init(&ctx->refcount, 1); if (chained != NULL) { ctx->chained = GRPC_AUTH_CONTEXT_REF(chained, "chained"); @@ -139,14 +127,17 @@ grpc_auth_context *grpc_auth_context_create(grpc_auth_context *chained) { return ctx; } -#ifdef GRPC_AUTH_CONTEXT_REFCOUNT_DEBUG +#ifndef NDEBUG grpc_auth_context *grpc_auth_context_ref(grpc_auth_context *ctx, const char *file, int line, const char *reason) { if (ctx == NULL) return NULL; - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, - "AUTH_CONTEXT:%p ref %d -> %d %s", ctx, (int)ctx->refcount.count, - (int)ctx->refcount.count + 1, reason); + if (GRPC_TRACER_ON(grpc_trace_auth_context_refcount)) { + 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 == NULL) return NULL; @@ -155,13 +146,16 @@ grpc_auth_context *grpc_auth_context_ref(grpc_auth_context *ctx) { return ctx; } -#ifdef GRPC_AUTH_CONTEXT_REFCOUNT_DEBUG +#ifndef NDEBUG void grpc_auth_context_unref(grpc_auth_context *ctx, const char *file, int line, const char *reason) { if (ctx == NULL) return; - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, - "AUTH_CONTEXT:%p unref %d -> %d %s", ctx, (int)ctx->refcount.count, - (int)ctx->refcount.count - 1, reason); + if (GRPC_TRACER_ON(grpc_trace_auth_context_refcount)) { + 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 == NULL) return; @@ -307,7 +301,7 @@ void grpc_auth_property_reset(grpc_auth_property *property) { memset(property, 0, sizeof(grpc_auth_property)); } -static void auth_context_pointer_arg_destroy(void *p) { +static void auth_context_pointer_arg_destroy(grpc_exec_ctx *exec_ctx, void *p) { GRPC_AUTH_CONTEXT_UNREF(p, "auth_context_pointer_arg"); } @@ -322,13 +316,8 @@ static const grpc_arg_pointer_vtable auth_context_pointer_vtable = { auth_context_pointer_cmp}; grpc_arg grpc_auth_context_to_arg(grpc_auth_context *p) { - grpc_arg arg; - memset(&arg, 0, sizeof(grpc_arg)); - arg.type = GRPC_ARG_POINTER; - arg.key = GRPC_AUTH_CONTEXT_ARG; - arg.value.pointer.p = p; - arg.value.pointer.vtable = &auth_context_pointer_vtable; - return arg; + return grpc_channel_arg_pointer_create(GRPC_AUTH_CONTEXT_ARG, p, + &auth_context_pointer_vtable); } grpc_auth_context *grpc_auth_context_from_arg(const grpc_arg *arg) { diff --git a/Sources/CgRPC/src/core/lib/security/context/security_context.h b/Sources/CgRPC/src/core/lib/security/context/security_context.h index 1e131a0c2..0df39257a 100644 --- a/Sources/CgRPC/src/core/lib/security/context/security_context.h +++ b/Sources/CgRPC/src/core/lib/security/context/security_context.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -37,6 +22,10 @@ #include "src/core/lib/iomgr/pollset.h" #include "src/core/lib/security/credentials/credentials.h" +#ifndef NDEBUG +extern grpc_tracer_flag grpc_trace_auth_context_refcount; +#endif + #ifdef __cplusplus extern "C" { #endif @@ -65,7 +54,7 @@ struct grpc_auth_context { grpc_auth_context *grpc_auth_context_create(grpc_auth_context *chained); /* Refcounting. */ -#ifdef GRPC_AUTH_CONTEXT_REFCOUNT_DEBUG +#ifndef NDEBUG #define GRPC_AUTH_CONTEXT_REF(p, r) \ grpc_auth_context_ref((p), __FILE__, __LINE__, (r)) #define GRPC_AUTH_CONTEXT_UNREF(p, r) \ diff --git a/Sources/CgRPC/src/core/lib/security/credentials/composite/composite_credentials.c b/Sources/CgRPC/src/core/lib/security/credentials/composite/composite_credentials.c index d55d00b7b..09fd60a12 100644 --- a/Sources/CgRPC/src/core/lib/security/credentials/composite/composite_credentials.c +++ b/Sources/CgRPC/src/core/lib/security/credentials/composite/composite_credentials.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015-2016, Google Inc. - * All rights reserved. + * Copyright 2015-2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -47,87 +32,98 @@ typedef struct { grpc_composite_call_credentials *composite_creds; size_t creds_index; - grpc_credentials_md_store *md_elems; - grpc_auth_metadata_context auth_md_context; - void *user_data; grpc_polling_entity *pollent; - grpc_credentials_metadata_cb cb; + 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) { +static void composite_call_destruct(grpc_exec_ctx *exec_ctx, + grpc_call_credentials *creds) { grpc_composite_call_credentials *c = (grpc_composite_call_credentials *)creds; - size_t i; - for (i = 0; i < c->inner.num_creds; i++) { - grpc_call_credentials_unref(c->inner.creds_array[i]); + for (size_t i = 0; i < c->inner.num_creds; i++) { + grpc_call_credentials_unref(exec_ctx, c->inner.creds_array[i]); } gpr_free(c->inner.creds_array); } -static void composite_call_md_context_destroy( - grpc_composite_call_credentials_metadata_context *ctx) { - grpc_credentials_md_store_unref(ctx->md_elems); - gpr_free(ctx); -} - -static void composite_call_metadata_cb(grpc_exec_ctx *exec_ctx, void *user_data, - grpc_credentials_md *md_elems, - size_t num_md, - grpc_credentials_status status, - const char *error_details) { +static void composite_call_metadata_cb(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error) { grpc_composite_call_credentials_metadata_context *ctx = - (grpc_composite_call_credentials_metadata_context *)user_data; - if (status != GRPC_CREDENTIALS_OK) { - ctx->cb(exec_ctx, ctx->user_data, NULL, 0, status, error_details); - return; - } - - /* Copy the metadata in the context. */ - if (num_md > 0) { - size_t i; - for (i = 0; i < num_md; i++) { - grpc_credentials_md_store_add(ctx->md_elems, md_elems[i].key, - md_elems[i].value); + (grpc_composite_call_credentials_metadata_context *)arg; + if (error == GRPC_ERROR_NONE) { + /* 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( + exec_ctx, inner_creds, 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(exec_ctx, arg, error); + GRPC_ERROR_UNREF(error); + } + return; } + // We're done! } - - /* 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++]; - grpc_call_credentials_get_request_metadata( - exec_ctx, inner_creds, ctx->pollent, ctx->auth_md_context, - composite_call_metadata_cb, ctx); - return; - } - - /* We're done!. */ - ctx->cb(exec_ctx, ctx->user_data, ctx->md_elems->entries, - ctx->md_elems->num_entries, GRPC_CREDENTIALS_OK, NULL); - composite_call_md_context_destroy(ctx); + GRPC_CLOSURE_SCHED(exec_ctx, ctx->on_request_metadata, GRPC_ERROR_REF(error)); + gpr_free(ctx); } -static void composite_call_get_request_metadata( +static bool composite_call_get_request_metadata( grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds, grpc_polling_entity *pollent, grpc_auth_metadata_context auth_md_context, - grpc_credentials_metadata_cb cb, void *user_data) { + grpc_credentials_mdelem_array *md_array, grpc_closure *on_request_metadata, + grpc_error **error) { grpc_composite_call_credentials *c = (grpc_composite_call_credentials *)creds; grpc_composite_call_credentials_metadata_context *ctx; - - ctx = gpr_malloc(sizeof(grpc_composite_call_credentials_metadata_context)); - memset(ctx, 0, sizeof(grpc_composite_call_credentials_metadata_context)); - ctx->auth_md_context = auth_md_context; - ctx->user_data = user_data; - ctx->cb = cb; + ctx = gpr_zalloc(sizeof(grpc_composite_call_credentials_metadata_context)); ctx->composite_creds = c; ctx->pollent = pollent; - ctx->md_elems = grpc_credentials_md_store_create(c->inner.num_creds); - grpc_call_credentials_get_request_metadata( - exec_ctx, c->inner.creds_array[ctx->creds_index++], ctx->pollent, - auth_md_context, composite_call_metadata_cb, ctx); + 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); + 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( + exec_ctx, inner_creds, ctx->pollent, ctx->auth_md_context, + ctx->md_array, &ctx->internal_on_request_metadata, error)) { + if (*error != GRPC_ERROR_NONE) break; + } else { + break; + } + } + // If we got through all creds synchronously or we got a synchronous + // error on one of them, return synchronously. + if (ctx->creds_index == ctx->composite_creds->inner.num_creds || + *error != GRPC_ERROR_NONE) { + gpr_free(ctx); + return true; + } + // At least one inner cred is returning asynchronously, so we'll + // return asynchronously as well. + return false; +} + +static void composite_call_cancel_get_request_metadata( + grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds, + grpc_credentials_mdelem_array *md_array, grpc_error *error) { + grpc_composite_call_credentials *c = (grpc_composite_call_credentials *)creds; + for (size_t i = 0; i < c->inner.num_creds; ++i) { + grpc_call_credentials_cancel_get_request_metadata( + exec_ctx, c->inner.creds_array[i], 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_destruct, composite_call_get_request_metadata, + composite_call_cancel_get_request_metadata}; static grpc_call_credentials_array get_creds_array( grpc_call_credentials **creds_addr) { @@ -156,8 +152,7 @@ grpc_call_credentials *grpc_composite_call_credentials_create( GPR_ASSERT(reserved == NULL); GPR_ASSERT(creds1 != NULL); GPR_ASSERT(creds2 != NULL); - c = gpr_malloc(sizeof(grpc_composite_call_credentials)); - memset(c, 0, sizeof(grpc_composite_call_credentials)); + c = 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); @@ -165,8 +160,7 @@ grpc_call_credentials *grpc_composite_call_credentials_create( 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 = gpr_malloc(creds_array_byte_size); - memset(c->inner.creds_array, 0, creds_array_byte_size); + c->inner.creds_array = 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); @@ -209,17 +203,19 @@ grpc_call_credentials *grpc_credentials_contains_type( /* -- Composite channel credentials. -- */ -static void composite_channel_destruct(grpc_channel_credentials *creds) { +static void composite_channel_destruct(grpc_exec_ctx *exec_ctx, + grpc_channel_credentials *creds) { grpc_composite_channel_credentials *c = (grpc_composite_channel_credentials *)creds; - grpc_channel_credentials_unref(c->inner_creds); - grpc_call_credentials_unref(c->call_creds); + grpc_channel_credentials_unref(exec_ctx, c->inner_creds); + grpc_call_credentials_unref(exec_ctx, c->call_creds); } static grpc_security_status composite_channel_create_security_connector( - grpc_channel_credentials *creds, grpc_call_credentials *call_creds, - const char *target, const grpc_channel_args *args, - grpc_channel_security_connector **sc, grpc_channel_args **new_args) { + grpc_exec_ctx *exec_ctx, grpc_channel_credentials *creds, + 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 = (grpc_composite_channel_credentials *)creds; grpc_security_status status = GRPC_SECURITY_ERROR; @@ -233,11 +229,12 @@ static grpc_security_status composite_channel_create_security_connector( grpc_call_credentials *composite_call_creds = grpc_composite_call_credentials_create(c->call_creds, call_creds, NULL); 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); + exec_ctx, c->inner_creds, composite_call_creds, target, args, sc, + new_args); + grpc_call_credentials_unref(exec_ctx, composite_call_creds); } else { status = c->inner_creds->vtable->create_security_connector( - c->inner_creds, c->call_creds, target, args, sc, new_args); + exec_ctx, c->inner_creds, c->call_creds, target, args, sc, new_args); } return status; } @@ -257,8 +254,7 @@ static grpc_channel_credentials_vtable composite_channel_credentials_vtable = { 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 = gpr_malloc(sizeof(*c)); - memset(c, 0, sizeof(*c)); + grpc_composite_channel_credentials *c = gpr_zalloc(sizeof(*c)); GPR_ASSERT(channel_creds != NULL && call_creds != NULL && reserved == NULL); GRPC_API_TRACE( "grpc_composite_channel_credentials_create(channel_creds=%p, " diff --git a/Sources/CgRPC/src/core/lib/security/credentials/composite/composite_credentials.h b/Sources/CgRPC/src/core/lib/security/credentials/composite/composite_credentials.h index f8425c2b7..3076afcb7 100644 --- a/Sources/CgRPC/src/core/lib/security/credentials/composite/composite_credentials.h +++ b/Sources/CgRPC/src/core/lib/security/credentials/composite/composite_credentials.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/security/credentials/credentials.c b/Sources/CgRPC/src/core/lib/security/credentials/credentials.c index 1149e5c2e..8a67c9865 100644 --- a/Sources/CgRPC/src/core/lib/security/credentials/credentials.c +++ b/Sources/CgRPC/src/core/lib/security/credentials/credentials.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -37,7 +22,6 @@ #include #include "src/core/lib/channel/channel_args.h" -#include "src/core/lib/channel/http_client_filter.h" #include "src/core/lib/http/httpcli.h" #include "src/core/lib/http/parser.h" #include "src/core/lib/iomgr/executor.h" @@ -54,20 +38,16 @@ /* -- Common. -- */ grpc_credentials_metadata_request *grpc_credentials_metadata_request_create( - grpc_call_credentials *creds, grpc_credentials_metadata_cb cb, - void *user_data) { + grpc_call_credentials *creds) { grpc_credentials_metadata_request *r = - gpr_malloc(sizeof(grpc_credentials_metadata_request)); - memset(&r->response, 0, sizeof(r->response)); + gpr_zalloc(sizeof(grpc_credentials_metadata_request)); r->creds = grpc_call_credentials_ref(creds); - r->cb = cb; - r->user_data = user_data; return r; } void grpc_credentials_metadata_request_destroy( - grpc_credentials_metadata_request *r) { - grpc_call_credentials_unref(r->creds); + grpc_exec_ctx *exec_ctx, grpc_credentials_metadata_request *r) { + grpc_call_credentials_unref(exec_ctx, r->creds); grpc_http_response_destroy(&r->response); gpr_free(r); } @@ -79,17 +59,22 @@ grpc_channel_credentials *grpc_channel_credentials_ref( return creds; } -void grpc_channel_credentials_unref(grpc_channel_credentials *creds) { +void grpc_channel_credentials_unref(grpc_exec_ctx *exec_ctx, + grpc_channel_credentials *creds) { if (creds == NULL) return; if (gpr_unref(&creds->refcount)) { - if (creds->vtable->destruct != NULL) creds->vtable->destruct(creds); + if (creds->vtable->destruct != NULL) { + creds->vtable->destruct(exec_ctx, 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_channel_credentials_unref(creds); + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + grpc_channel_credentials_unref(&exec_ctx, creds); + grpc_exec_ctx_finish(&exec_ctx); } grpc_call_credentials *grpc_call_credentials_ref(grpc_call_credentials *creds) { @@ -98,44 +83,56 @@ grpc_call_credentials *grpc_call_credentials_ref(grpc_call_credentials *creds) { return creds; } -void grpc_call_credentials_unref(grpc_call_credentials *creds) { +void grpc_call_credentials_unref(grpc_exec_ctx *exec_ctx, + grpc_call_credentials *creds) { if (creds == NULL) return; if (gpr_unref(&creds->refcount)) { - if (creds->vtable->destruct != NULL) creds->vtable->destruct(creds); + if (creds->vtable->destruct != NULL) { + creds->vtable->destruct(exec_ctx, creds); + } gpr_free(creds); } } void grpc_call_credentials_release(grpc_call_credentials *creds) { GRPC_API_TRACE("grpc_call_credentials_release(creds=%p)", 1, (creds)); - grpc_call_credentials_unref(creds); + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + grpc_call_credentials_unref(&exec_ctx, creds); + grpc_exec_ctx_finish(&exec_ctx); } -void grpc_call_credentials_get_request_metadata( +bool grpc_call_credentials_get_request_metadata( grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds, grpc_polling_entity *pollent, grpc_auth_metadata_context context, - grpc_credentials_metadata_cb cb, void *user_data) { + grpc_credentials_mdelem_array *md_array, grpc_closure *on_request_metadata, + grpc_error **error) { if (creds == NULL || creds->vtable->get_request_metadata == NULL) { - if (cb != NULL) { - cb(exec_ctx, user_data, NULL, 0, GRPC_CREDENTIALS_OK, NULL); - } + return true; + } + return creds->vtable->get_request_metadata( + exec_ctx, creds, pollent, context, md_array, on_request_metadata, error); +} + +void grpc_call_credentials_cancel_get_request_metadata( + grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds, + grpc_credentials_mdelem_array *md_array, grpc_error *error) { + if (creds == NULL || creds->vtable->cancel_get_request_metadata == NULL) { return; } - creds->vtable->get_request_metadata(exec_ctx, creds, pollent, context, cb, - user_data); + creds->vtable->cancel_get_request_metadata(exec_ctx, 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) { + grpc_exec_ctx *exec_ctx, 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 = NULL; if (channel_creds == NULL) { return GRPC_SECURITY_ERROR; } GPR_ASSERT(channel_creds->vtable->create_security_connector != NULL); return channel_creds->vtable->create_security_connector( - channel_creds, NULL, target, args, sc, new_args); + exec_ctx, channel_creds, NULL, target, args, sc, new_args); } grpc_channel_credentials * @@ -150,6 +147,49 @@ grpc_channel_credentials_duplicate_without_call_credentials( } } +static void credentials_pointer_arg_destroy(grpc_exec_ctx *exec_ctx, void *p) { + grpc_channel_credentials_unref(exec_ctx, p); +} + +static void *credentials_pointer_arg_copy(void *p) { + return grpc_channel_credentials_ref(p); +} + +static int credentials_pointer_cmp(void *a, void *b) { return GPR_ICMP(a, b); } + +static const grpc_arg_pointer_vtable credentials_pointer_vtable = { + credentials_pointer_arg_copy, credentials_pointer_arg_destroy, + credentials_pointer_cmp}; + +grpc_arg grpc_channel_credentials_to_arg( + grpc_channel_credentials *credentials) { + return grpc_channel_arg_pointer_create( + GRPC_ARG_CHANNEL_CREDENTIALS, credentials, &credentials_pointer_vtable); +} + +grpc_channel_credentials *grpc_channel_credentials_from_arg( + const grpc_arg *arg) { + if (strcmp(arg->key, GRPC_ARG_CHANNEL_CREDENTIALS)) return NULL; + if (arg->type != GRPC_ARG_POINTER) { + gpr_log(GPR_ERROR, "Invalid type %d for arg %s", arg->type, + GRPC_ARG_CHANNEL_CREDENTIALS); + return NULL; + } + return arg->value.pointer.p; +} + +grpc_channel_credentials *grpc_channel_credentials_find_in_args( + const grpc_channel_args *args) { + size_t i; + if (args == NULL) return NULL; + for (i = 0; i < args->num_args; i++) { + grpc_channel_credentials *credentials = + grpc_channel_credentials_from_arg(&args->args[i]); + if (credentials != NULL) return credentials; + } + return NULL; +} + grpc_server_credentials *grpc_server_credentials_ref( grpc_server_credentials *creds) { if (creds == NULL) return NULL; @@ -157,10 +197,13 @@ grpc_server_credentials *grpc_server_credentials_ref( return creds; } -void grpc_server_credentials_unref(grpc_server_credentials *creds) { +void grpc_server_credentials_unref(grpc_exec_ctx *exec_ctx, + grpc_server_credentials *creds) { if (creds == NULL) return; if (gpr_unref(&creds->refcount)) { - if (creds->vtable->destruct != NULL) creds->vtable->destruct(creds); + if (creds->vtable->destruct != NULL) { + creds->vtable->destruct(exec_ctx, creds); + } if (creds->processor.destroy != NULL && creds->processor.state != NULL) { creds->processor.destroy(creds->processor.state); } @@ -170,16 +213,19 @@ void grpc_server_credentials_unref(grpc_server_credentials *creds) { void grpc_server_credentials_release(grpc_server_credentials *creds) { GRPC_API_TRACE("grpc_server_credentials_release(creds=%p)", 1, (creds)); - grpc_server_credentials_unref(creds); + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + grpc_server_credentials_unref(&exec_ctx, creds); + grpc_exec_ctx_finish(&exec_ctx); } grpc_security_status grpc_server_credentials_create_security_connector( - grpc_server_credentials *creds, grpc_server_security_connector **sc) { + grpc_exec_ctx *exec_ctx, grpc_server_credentials *creds, + grpc_server_security_connector **sc) { if (creds == NULL || creds->vtable->create_security_connector == NULL) { gpr_log(GPR_ERROR, "Server credentials cannot create security context."); return GRPC_SECURITY_ERROR; } - return creds->vtable->create_security_connector(creds, sc); + return creds->vtable->create_security_connector(exec_ctx, creds, sc); } void grpc_server_credentials_set_auth_metadata_processor( @@ -196,8 +242,9 @@ void grpc_server_credentials_set_auth_metadata_processor( creds->processor = processor; } -static void server_credentials_pointer_arg_destroy(void *p) { - grpc_server_credentials_unref(p); +static void server_credentials_pointer_arg_destroy(grpc_exec_ctx *exec_ctx, + void *p) { + grpc_server_credentials_unref(exec_ctx, p); } static void *server_credentials_pointer_arg_copy(void *p) { @@ -213,13 +260,8 @@ static const grpc_arg_pointer_vtable cred_ptr_vtable = { server_credentials_pointer_cmp}; grpc_arg grpc_server_credentials_to_arg(grpc_server_credentials *p) { - grpc_arg arg; - memset(&arg, 0, sizeof(grpc_arg)); - arg.type = GRPC_ARG_POINTER; - arg.key = GRPC_SERVER_CREDENTIALS_ARG; - arg.value.pointer.p = p; - arg.value.pointer.vtable = &cred_ptr_vtable; - return arg; + return grpc_channel_arg_pointer_create(GRPC_SERVER_CREDENTIALS_ARG, p, + &cred_ptr_vtable); } grpc_server_credentials *grpc_server_credentials_from_arg(const grpc_arg *arg) { diff --git a/Sources/CgRPC/src/core/lib/security/credentials/credentials.h b/Sources/CgRPC/src/core/lib/security/credentials/credentials.h index 85b3bc535..04a54b0ca 100644 --- a/Sources/CgRPC/src/core/lib/security/credentials/credentials.h +++ b/Sources/CgRPC/src/core/lib/security/credentials/credentials.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -71,7 +56,7 @@ typedef enum { #define GRPC_SECURE_TOKEN_REFRESH_THRESHOLD_SECS 60 -#define GRPC_COMPUTE_ENGINE_METADATA_HOST "metadata" +#define GRPC_COMPUTE_ENGINE_METADATA_HOST "metadata.google.internal" #define GRPC_COMPUTE_ENGINE_METADATA_TOKEN_PATH \ "/computeMetadata/v1/instance/service-accounts/default/token" @@ -100,13 +85,16 @@ void grpc_override_well_known_credentials_path_getter( /* --- grpc_channel_credentials. --- */ +#define GRPC_ARG_CHANNEL_CREDENTIALS "grpc.channel_credentials" + typedef struct { - void (*destruct)(grpc_channel_credentials *c); + void (*destruct)(grpc_exec_ctx *exec_ctx, grpc_channel_credentials *c); grpc_security_status (*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); + grpc_exec_ctx *exec_ctx, 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); grpc_channel_credentials *(*duplicate_without_call_credentials)( grpc_channel_credentials *c); @@ -120,16 +108,17 @@ struct grpc_channel_credentials { grpc_channel_credentials *grpc_channel_credentials_ref( grpc_channel_credentials *creds); -void grpc_channel_credentials_unref(grpc_channel_credentials *creds); +void grpc_channel_credentials_unref(grpc_exec_ctx *exec_ctx, + 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); + grpc_exec_ctx *exec_ctx, 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 @@ -138,47 +127,50 @@ grpc_channel_credentials * grpc_channel_credentials_duplicate_without_call_credentials( grpc_channel_credentials *creds); -/* --- grpc_credentials_md. --- */ +/* Util to encapsulate the channel credentials in a channel arg. */ +grpc_arg grpc_channel_credentials_to_arg(grpc_channel_credentials *credentials); -typedef struct { - grpc_slice key; - grpc_slice value; -} grpc_credentials_md; +/* Util to get the channel credentials from a channel arg. */ +grpc_channel_credentials *grpc_channel_credentials_from_arg( + const grpc_arg *arg); + +/* Util to find the channel credentials from channel args. */ +grpc_channel_credentials *grpc_channel_credentials_find_in_args( + const grpc_channel_args *args); + +/* --- grpc_credentials_mdelem_array. --- */ typedef struct { - grpc_credentials_md *entries; - size_t num_entries; - size_t allocated; - gpr_refcount refcount; -} grpc_credentials_md_store; + grpc_mdelem *md; + size_t size; +} grpc_credentials_mdelem_array; -grpc_credentials_md_store *grpc_credentials_md_store_create( - size_t initial_capacity); +/// Takes a new ref to \a md. +void grpc_credentials_mdelem_array_add(grpc_credentials_mdelem_array *list, + grpc_mdelem md); -/* Will ref key and value. */ -void grpc_credentials_md_store_add(grpc_credentials_md_store *store, - grpc_slice key, grpc_slice value); -void grpc_credentials_md_store_add_cstrings(grpc_credentials_md_store *store, - const char *key, const char *value); -grpc_credentials_md_store *grpc_credentials_md_store_ref( - grpc_credentials_md_store *store); -void grpc_credentials_md_store_unref(grpc_credentials_md_store *store); +/// Appends all elements from \a src to \a dst, taking a new ref to each one. +void grpc_credentials_mdelem_array_append(grpc_credentials_mdelem_array *dst, + grpc_credentials_mdelem_array *src); -/* --- grpc_call_credentials. --- */ +void grpc_credentials_mdelem_array_destroy(grpc_exec_ctx *exec_ctx, + grpc_credentials_mdelem_array *list); -/* error_details must be NULL if status is GRPC_CREDENTIALS_OK. */ -typedef void (*grpc_credentials_metadata_cb)( - grpc_exec_ctx *exec_ctx, void *user_data, grpc_credentials_md *md_elems, - size_t num_md, grpc_credentials_status status, const char *error_details); +/* --- grpc_call_credentials. --- */ typedef struct { - void (*destruct)(grpc_call_credentials *c); - void (*get_request_metadata)(grpc_exec_ctx *exec_ctx, + void (*destruct)(grpc_exec_ctx *exec_ctx, grpc_call_credentials *c); + bool (*get_request_metadata)(grpc_exec_ctx *exec_ctx, grpc_call_credentials *c, grpc_polling_entity *pollent, grpc_auth_metadata_context context, - grpc_credentials_metadata_cb cb, - void *user_data); + grpc_credentials_mdelem_array *md_array, + grpc_closure *on_request_metadata, + grpc_error **error); + void (*cancel_get_request_metadata)(grpc_exec_ctx *exec_ctx, + grpc_call_credentials *c, + grpc_credentials_mdelem_array *md_array, + grpc_error *error); } grpc_call_credentials_vtable; struct grpc_call_credentials { @@ -188,23 +180,39 @@ struct grpc_call_credentials { }; grpc_call_credentials *grpc_call_credentials_ref(grpc_call_credentials *creds); -void grpc_call_credentials_unref(grpc_call_credentials *creds); -void grpc_call_credentials_get_request_metadata( +void grpc_call_credentials_unref(grpc_exec_ctx *exec_ctx, + 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_exec_ctx *exec_ctx, grpc_call_credentials *creds, grpc_polling_entity *pollent, grpc_auth_metadata_context context, - grpc_credentials_metadata_cb cb, void *user_data); + 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_exec_ctx *exec_ctx, 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( - const char *md_key, const char *md_value, int is_async); + grpc_exec_ctx *exec_ctx, const char *md_key, const char *md_value, + bool is_async); /* --- grpc_server_credentials. --- */ typedef struct { - void (*destruct)(grpc_server_credentials *c); + void (*destruct)(grpc_exec_ctx *exec_ctx, grpc_server_credentials *c); grpc_security_status (*create_security_connector)( - grpc_server_credentials *c, grpc_server_security_connector **sc); + grpc_exec_ctx *exec_ctx, grpc_server_credentials *c, + grpc_server_security_connector **sc); } grpc_server_credentials_vtable; struct grpc_server_credentials { @@ -215,12 +223,14 @@ struct grpc_server_credentials { }; grpc_security_status grpc_server_credentials_create_security_connector( - grpc_server_credentials *creds, grpc_server_security_connector **sc); + grpc_exec_ctx *exec_ctx, grpc_server_credentials *creds, + grpc_server_security_connector **sc); grpc_server_credentials *grpc_server_credentials_ref( grpc_server_credentials *creds); -void grpc_server_credentials_unref(grpc_server_credentials *creds); +void grpc_server_credentials_unref(grpc_exec_ctx *exec_ctx, + grpc_server_credentials *creds); #define GRPC_SERVER_CREDENTIALS_ARG "grpc.server_credentials" @@ -233,16 +243,13 @@ grpc_server_credentials *grpc_find_server_credentials_in_args( typedef struct { grpc_call_credentials *creds; - grpc_credentials_metadata_cb cb; grpc_http_response response; - void *user_data; } grpc_credentials_metadata_request; grpc_credentials_metadata_request *grpc_credentials_metadata_request_create( - grpc_call_credentials *creds, grpc_credentials_metadata_cb cb, - void *user_data); + grpc_call_credentials *creds); void grpc_credentials_metadata_request_destroy( - grpc_credentials_metadata_request *r); + grpc_exec_ctx *exec_ctx, grpc_credentials_metadata_request *r); #endif /* GRPC_CORE_LIB_SECURITY_CREDENTIALS_CREDENTIALS_H */ diff --git a/Sources/CgRPC/src/core/lib/security/credentials/credentials_metadata.c b/Sources/CgRPC/src/core/lib/security/credentials/credentials_metadata.c index e6cb56773..ccd39e610 100644 --- a/Sources/CgRPC/src/core/lib/security/credentials/credentials_metadata.c +++ b/Sources/CgRPC/src/core/lib/security/credentials/credentials_metadata.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -37,65 +22,38 @@ #include -static void store_ensure_capacity(grpc_credentials_md_store *store) { - if (store->num_entries == store->allocated) { - store->allocated = (store->allocated == 0) ? 1 : store->allocated * 2; - store->entries = gpr_realloc( - store->entries, store->allocated * sizeof(grpc_credentials_md)); - } -} +#include "src/core/lib/slice/slice_internal.h" -grpc_credentials_md_store *grpc_credentials_md_store_create( - size_t initial_capacity) { - grpc_credentials_md_store *store = - gpr_malloc(sizeof(grpc_credentials_md_store)); - memset(store, 0, sizeof(grpc_credentials_md_store)); - if (initial_capacity > 0) { - store->entries = gpr_malloc(initial_capacity * sizeof(grpc_credentials_md)); - store->allocated = initial_capacity; +static void mdelem_list_ensure_capacity(grpc_credentials_mdelem_array *list, + size_t additional_space_needed) { + size_t target_size = list->size + additional_space_needed; + // Find the next power of two greater than the target size (i.e., + // whenever we add more space, we double what we already have). + size_t new_size = 2; + while (new_size < target_size) { + new_size *= 2; } - gpr_ref_init(&store->refcount, 1); - return store; + list->md = gpr_realloc(list->md, sizeof(grpc_mdelem) * new_size); } -void grpc_credentials_md_store_add(grpc_credentials_md_store *store, - grpc_slice key, grpc_slice value) { - if (store == NULL) return; - store_ensure_capacity(store); - store->entries[store->num_entries].key = grpc_slice_ref(key); - store->entries[store->num_entries].value = grpc_slice_ref(value); - store->num_entries++; +void grpc_credentials_mdelem_array_add(grpc_credentials_mdelem_array *list, + grpc_mdelem md) { + mdelem_list_ensure_capacity(list, 1); + list->md[list->size++] = GRPC_MDELEM_REF(md); } -void grpc_credentials_md_store_add_cstrings(grpc_credentials_md_store *store, - const char *key, - const char *value) { - if (store == NULL) return; - store_ensure_capacity(store); - store->entries[store->num_entries].key = grpc_slice_from_copied_string(key); - store->entries[store->num_entries].value = - grpc_slice_from_copied_string(value); - store->num_entries++; -} - -grpc_credentials_md_store *grpc_credentials_md_store_ref( - grpc_credentials_md_store *store) { - if (store == NULL) return NULL; - gpr_ref(&store->refcount); - return store; +void grpc_credentials_mdelem_array_append(grpc_credentials_mdelem_array *dst, + grpc_credentials_mdelem_array *src) { + mdelem_list_ensure_capacity(dst, src->size); + for (size_t i = 0; i < src->size; ++i) { + dst->md[dst->size++] = GRPC_MDELEM_REF(src->md[i]); + } } -void grpc_credentials_md_store_unref(grpc_credentials_md_store *store) { - if (store == NULL) return; - if (gpr_unref(&store->refcount)) { - if (store->entries != NULL) { - size_t i; - for (i = 0; i < store->num_entries; i++) { - grpc_slice_unref(store->entries[i].key); - grpc_slice_unref(store->entries[i].value); - } - gpr_free(store->entries); - } - gpr_free(store); +void grpc_credentials_mdelem_array_destroy( + grpc_exec_ctx *exec_ctx, grpc_credentials_mdelem_array *list) { + for (size_t i = 0; i < list->size; ++i) { + GRPC_MDELEM_UNREF(exec_ctx, list->md[i]); } + gpr_free(list->md); } diff --git a/Sources/CgRPC/src/core/lib/security/credentials/fake/fake_credentials.c b/Sources/CgRPC/src/core/lib/security/credentials/fake/fake_credentials.c index ea4cb76fb..ac9017850 100644 --- a/Sources/CgRPC/src/core/lib/security/credentials/fake/fake_credentials.c +++ b/Sources/CgRPC/src/core/lib/security/credentials/fake/fake_credentials.c @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -35,26 +20,32 @@ #include -#include "src/core/lib/channel/channel_args.h" -#include "src/core/lib/iomgr/executor.h" - #include #include #include +#include "src/core/lib/channel/channel_args.h" +#include "src/core/lib/iomgr/executor.h" +#include "src/core/lib/support/string.h" + /* -- Fake transport security credentials. -- */ +#define GRPC_ARG_FAKE_SECURITY_EXPECTED_TARGETS \ + "grpc.fake_security.expected_targets" + 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(call_creds); + grpc_exec_ctx *exec_ctx, 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(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) { + grpc_exec_ctx *exec_ctx, grpc_server_credentials *c, + grpc_server_security_connector **sc) { *sc = grpc_fake_server_security_connector_create(); return GRPC_SECURITY_OK; } @@ -69,8 +60,7 @@ static grpc_server_credentials_vtable grpc_channel_credentials *grpc_fake_transport_security_credentials_create( void) { - grpc_channel_credentials *c = gpr_malloc(sizeof(grpc_channel_credentials)); - memset(c, 0, sizeof(grpc_channel_credentials)); + grpc_channel_credentials *c = 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); @@ -87,53 +77,65 @@ grpc_server_credentials *grpc_fake_transport_security_server_credentials_create( return c; } -/* -- Metadata-only test credentials. -- */ +grpc_arg grpc_fake_transport_expected_targets_arg(char *expected_targets) { + return grpc_channel_arg_string_create(GRPC_ARG_FAKE_SECURITY_EXPECTED_TARGETS, + expected_targets); +} -static void md_only_test_destruct(grpc_call_credentials *creds) { - grpc_md_only_test_credentials *c = (grpc_md_only_test_credentials *)creds; - grpc_credentials_md_store_unref(c->md_store); +const char *grpc_fake_transport_get_expected_targets( + const grpc_channel_args *args) { + const grpc_arg *expected_target_arg = + grpc_channel_args_find(args, GRPC_ARG_FAKE_SECURITY_EXPECTED_TARGETS); + if (expected_target_arg != NULL && + expected_target_arg->type == GRPC_ARG_STRING) { + return expected_target_arg->value.string; + } + return NULL; } -static void on_simulated_token_fetch_done(grpc_exec_ctx *exec_ctx, - void *user_data, grpc_error *error) { - grpc_credentials_metadata_request *r = - (grpc_credentials_metadata_request *)user_data; - grpc_md_only_test_credentials *c = (grpc_md_only_test_credentials *)r->creds; - r->cb(exec_ctx, r->user_data, c->md_store->entries, c->md_store->num_entries, - GRPC_CREDENTIALS_OK, NULL); - grpc_credentials_metadata_request_destroy(r); +/* -- Metadata-only test credentials. -- */ + +static void md_only_test_destruct(grpc_exec_ctx *exec_ctx, + grpc_call_credentials *creds) { + grpc_md_only_test_credentials *c = (grpc_md_only_test_credentials *)creds; + GRPC_MDELEM_UNREF(exec_ctx, c->md); } -static void md_only_test_get_request_metadata( +static bool md_only_test_get_request_metadata( grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds, grpc_polling_entity *pollent, grpc_auth_metadata_context context, - grpc_credentials_metadata_cb cb, void *user_data) { + grpc_credentials_mdelem_array *md_array, grpc_closure *on_request_metadata, + grpc_error **error) { grpc_md_only_test_credentials *c = (grpc_md_only_test_credentials *)creds; - + grpc_credentials_mdelem_array_add(md_array, c->md); if (c->is_async) { - grpc_credentials_metadata_request *cb_arg = - grpc_credentials_metadata_request_create(creds, cb, user_data); - grpc_executor_push( - grpc_closure_create(on_simulated_token_fetch_done, cb_arg), - GRPC_ERROR_NONE); - } else { - cb(exec_ctx, user_data, c->md_store->entries, 1, GRPC_CREDENTIALS_OK, NULL); + GRPC_CLOSURE_SCHED(exec_ctx, on_request_metadata, GRPC_ERROR_NONE); + return false; } + return true; +} + +static void md_only_test_cancel_get_request_metadata( + grpc_exec_ctx *exec_ctx, grpc_call_credentials *c, + 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_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, int is_async) { + grpc_exec_ctx *exec_ctx, const char *md_key, const char *md_value, + bool is_async) { grpc_md_only_test_credentials *c = - gpr_malloc(sizeof(grpc_md_only_test_credentials)); - memset(c, 0, sizeof(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_store = grpc_credentials_md_store_create(1); - grpc_credentials_md_store_add_cstrings(c->md_store, md_key, md_value); + c->md = + grpc_mdelem_from_slices(exec_ctx, grpc_slice_from_copied_string(md_key), + grpc_slice_from_copied_string(md_value)); c->is_async = is_async; return &c->base; } diff --git a/Sources/CgRPC/src/core/lib/security/credentials/fake/fake_credentials.h b/Sources/CgRPC/src/core/lib/security/credentials/fake/fake_credentials.h index 9cf38084a..aa0f3b6e2 100644 --- a/Sources/CgRPC/src/core/lib/security/credentials/fake/fake_credentials.h +++ b/Sources/CgRPC/src/core/lib/security/credentials/fake/fake_credentials.h @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -45,12 +30,30 @@ grpc_channel_credentials *grpc_fake_transport_security_credentials_create(void); grpc_server_credentials *grpc_fake_transport_security_server_credentials_create( void); +/* Used to verify the target names given to the fake transport security + * connector. + * + * The syntax of \a expected_targets by example: + * For LB channels: + * "backend_target_1,backend_target_2,...;lb_target_1,lb_target_2,..." + * For regular channels: + * "backend_taget_1,backend_target_2,..." + * + * That is to say, LB channels have a heading list of LB targets separated from + * the list of backend targets by a semicolon. For non-LB channels, only the + * latter is present. */ +grpc_arg grpc_fake_transport_expected_targets_arg(char *expected_targets); + +/* Return the value associated with the expected targets channel arg or NULL */ +const char *grpc_fake_transport_get_expected_targets( + const grpc_channel_args *args); + /* -- Metadata-only Test credentials. -- */ typedef struct { grpc_call_credentials base; - grpc_credentials_md_store *md_store; - int is_async; + grpc_mdelem md; + bool is_async; } grpc_md_only_test_credentials; #endif /* GRPC_CORE_LIB_SECURITY_CREDENTIALS_FAKE_FAKE_CREDENTIALS_H */ diff --git a/Sources/CgRPC/src/core/lib/security/credentials/google_default/credentials_generic.c b/Sources/CgRPC/src/core/lib/security/credentials/google_default/credentials_generic.c index d13d8c520..4f79718f3 100644 --- a/Sources/CgRPC/src/core/lib/security/credentials/google_default/credentials_generic.c +++ b/Sources/CgRPC/src/core/lib/security/credentials/google_default/credentials_generic.c @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/security/credentials/google_default/google_default_credentials.c b/Sources/CgRPC/src/core/lib/security/credentials/google_default/google_default_credentials.c index afe0e3d35..a2a8e289e 100644 --- a/Sources/CgRPC/src/core/lib/security/credentials/google_default/google_default_credentials.c +++ b/Sources/CgRPC/src/core/lib/security/credentials/google_default/google_default_credentials.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -45,6 +30,7 @@ #include "src/core/lib/iomgr/polling_entity.h" #include "src/core/lib/security/credentials/jwt/jwt_credentials.h" #include "src/core/lib/security/credentials/oauth2/oauth2_credentials.h" +#include "src/core/lib/slice/slice_internal.h" #include "src/core/lib/slice/slice_string_helpers.h" #include "src/core/lib/support/env.h" #include "src/core/lib/support/string.h" @@ -98,21 +84,20 @@ static void on_compute_engine_detection_http_response(grpc_exec_ctx *exec_ctx, } static void destroy_pollset(grpc_exec_ctx *exec_ctx, void *p, grpc_error *e) { - grpc_pollset_destroy(p); + grpc_pollset_destroy(exec_ctx, p); } -static int is_stack_running_on_compute_engine(void) { +static int is_stack_running_on_compute_engine(grpc_exec_ctx *exec_ctx) { compute_engine_detector detector; grpc_httpcli_request request; grpc_httpcli_context context; - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_closure destroy_closure; /* The http call is local. If it takes more than one sec, it is for sure not on compute engine. */ gpr_timespec max_detection_delay = gpr_time_from_seconds(1, GPR_TIMESPAN); - grpc_pollset *pollset = gpr_malloc(grpc_pollset_size()); + grpc_pollset *pollset = gpr_zalloc(grpc_pollset_size()); grpc_pollset_init(pollset, &g_polling_mu); detector.pollent = grpc_polling_entity_create_from_pollset(pollset); detector.is_done = 0; @@ -128,13 +113,14 @@ static int is_stack_running_on_compute_engine(void) { grpc_resource_quota *resource_quota = grpc_resource_quota_create("google_default_credentials"); grpc_httpcli_get( - &exec_ctx, &context, &detector.pollent, resource_quota, &request, + exec_ctx, &context, &detector.pollent, resource_quota, &request, gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), max_detection_delay), - grpc_closure_create(on_compute_engine_detection_http_response, &detector), + GRPC_CLOSURE_CREATE(on_compute_engine_detection_http_response, &detector, + grpc_schedule_on_exec_ctx), &detector.response); - grpc_resource_quota_internal_unref(&exec_ctx, resource_quota); + grpc_resource_quota_unref_internal(exec_ctx, resource_quota); - grpc_exec_ctx_flush(&exec_ctx); + grpc_exec_ctx_flush(exec_ctx); /* Block until we get the response. This is not ideal but this should only be called once for the lifetime of the process by the default credentials. */ @@ -143,7 +129,7 @@ static int is_stack_running_on_compute_engine(void) { grpc_pollset_worker *worker = NULL; if (!GRPC_LOG_IF_ERROR( "pollset_work", - grpc_pollset_work(&exec_ctx, + grpc_pollset_work(exec_ctx, grpc_polling_entity_pollset(&detector.pollent), &worker, gpr_now(GPR_CLOCK_MONOTONIC), gpr_inf_future(GPR_CLOCK_MONOTONIC)))) { @@ -153,14 +139,15 @@ static int is_stack_running_on_compute_engine(void) { } gpr_mu_unlock(g_polling_mu); - grpc_httpcli_context_destroy(&context); - grpc_closure_init(&destroy_closure, destroy_pollset, - grpc_polling_entity_pollset(&detector.pollent)); - grpc_pollset_shutdown(&exec_ctx, + grpc_httpcli_context_destroy(exec_ctx, &context); + GRPC_CLOSURE_INIT(&destroy_closure, destroy_pollset, + grpc_polling_entity_pollset(&detector.pollent), + grpc_schedule_on_exec_ctx); + grpc_pollset_shutdown(exec_ctx, grpc_polling_entity_pollset(&detector.pollent), &destroy_closure); - grpc_exec_ctx_finish(&exec_ctx); g_polling_mu = NULL; + grpc_exec_ctx_flush(exec_ctx); gpr_free(grpc_polling_entity_pollset(&detector.pollent)); grpc_http_response_destroy(&detector.response); @@ -170,15 +157,15 @@ static int is_stack_running_on_compute_engine(void) { /* Takes ownership of creds_path if not NULL. */ static grpc_error *create_default_creds_from_path( - char *creds_path, grpc_call_credentials **creds) { + grpc_exec_ctx *exec_ctx, char *creds_path, grpc_call_credentials **creds) { grpc_json *json = NULL; grpc_auth_json_key key; grpc_auth_refresh_token token; grpc_call_credentials *result = NULL; - grpc_slice creds_data = gpr_empty_slice(); + grpc_slice creds_data = grpc_empty_slice(); grpc_error *error = GRPC_ERROR_NONE; if (creds_path == NULL) { - error = GRPC_ERROR_CREATE("creds_path unset"); + error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("creds_path unset"); goto end; } error = grpc_load_file(creds_path, 0, &creds_data); @@ -188,10 +175,9 @@ static grpc_error *create_default_creds_from_path( json = grpc_json_parse_string_with_len( (char *)GRPC_SLICE_START_PTR(creds_data), GRPC_SLICE_LENGTH(creds_data)); if (json == NULL) { - char *dump = grpc_dump_slice(creds_data, GPR_DUMP_HEX | GPR_DUMP_ASCII); - error = grpc_error_set_str(GRPC_ERROR_CREATE("Failed to parse JSON"), - GRPC_ERROR_STR_RAW_BYTES, dump); - gpr_free(dump); + error = grpc_error_set_str( + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Failed to parse JSON"), + GRPC_ERROR_STR_RAW_BYTES, grpc_slice_ref_internal(creds_data)); goto end; } @@ -200,9 +186,9 @@ static grpc_error *create_default_creds_from_path( if (grpc_auth_json_key_is_valid(&key)) { result = grpc_service_account_jwt_access_credentials_create_from_auth_json_key( - key, grpc_max_auth_token_lifetime()); + exec_ctx, key, grpc_max_auth_token_lifetime()); if (result == NULL) { - error = GRPC_ERROR_CREATE( + error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( "grpc_service_account_jwt_access_credentials_create_from_auth_json_" "key failed"); } @@ -215,7 +201,7 @@ static grpc_error *create_default_creds_from_path( result = grpc_refresh_token_credentials_create_from_auth_refresh_token(token); if (result == NULL) { - error = GRPC_ERROR_CREATE( + error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( "grpc_refresh_token_credentials_create_from_auth_refresh_token " "failed"); } @@ -225,7 +211,7 @@ static grpc_error *create_default_creds_from_path( end: GPR_ASSERT((result == NULL) + (error == GRPC_ERROR_NONE) == 1); if (creds_path != NULL) gpr_free(creds_path); - grpc_slice_unref(creds_data); + grpc_slice_unref_internal(exec_ctx, creds_data); if (json != NULL) grpc_json_destroy(json); *creds = result; return error; @@ -234,8 +220,10 @@ static grpc_error *create_default_creds_from_path( grpc_channel_credentials *grpc_google_default_credentials_create(void) { grpc_channel_credentials *result = NULL; grpc_call_credentials *call_creds = NULL; - grpc_error *error = GRPC_ERROR_CREATE("Failed to create Google credentials"); + grpc_error *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "Failed to create Google credentials"); grpc_error *err; + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; GRPC_API_TRACE("grpc_google_default_credentials_create(void)", 0, ()); @@ -250,26 +238,29 @@ grpc_channel_credentials *grpc_google_default_credentials_create(void) { /* First, try the environment variable. */ err = create_default_creds_from_path( - gpr_getenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR), &call_creds); + &exec_ctx, gpr_getenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR), &call_creds); if (err == GRPC_ERROR_NONE) goto end; error = grpc_error_add_child(error, err); /* Then the well-known file. */ err = create_default_creds_from_path( - grpc_get_well_known_google_credentials_file_path(), &call_creds); + &exec_ctx, grpc_get_well_known_google_credentials_file_path(), + &call_creds); if (err == GRPC_ERROR_NONE) goto end; error = grpc_error_add_child(error, err); /* At last try to see if we're on compute engine (do the detection only once since it requires a network test). */ if (!compute_engine_detection_done) { - int need_compute_engine_creds = is_stack_running_on_compute_engine(); + int need_compute_engine_creds = + is_stack_running_on_compute_engine(&exec_ctx); compute_engine_detection_done = 1; if (need_compute_engine_creds) { call_creds = grpc_google_compute_engine_credentials_create(NULL); if (call_creds == NULL) { error = grpc_error_add_child( - error, GRPC_ERROR_CREATE("Failed to get credentials from network")); + error, GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "Failed to get credentials from network")); } } } @@ -286,8 +277,8 @@ grpc_channel_credentials *grpc_google_default_credentials_create(void) { grpc_composite_channel_credentials_create(ssl_creds, call_creds, NULL)); GPR_ASSERT(default_credentials != NULL); - grpc_channel_credentials_unref(ssl_creds); - grpc_call_credentials_unref(call_creds); + grpc_channel_credentials_unref(&exec_ctx, ssl_creds); + grpc_call_credentials_unref(&exec_ctx, call_creds); result = default_credentials; } else { gpr_log(GPR_ERROR, "Could not create google default credentials."); @@ -299,18 +290,21 @@ grpc_channel_credentials *grpc_google_default_credentials_create(void) { } else { GRPC_ERROR_UNREF(error); } + grpc_exec_ctx_finish(&exec_ctx); return result; } void grpc_flush_cached_google_default_credentials(void) { + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; gpr_once_init(&g_once, init_default_credentials); gpr_mu_lock(&g_state_mu); if (default_credentials != NULL) { - grpc_channel_credentials_unref(default_credentials); + grpc_channel_credentials_unref(&exec_ctx, default_credentials); default_credentials = NULL; } compute_engine_detection_done = 0; gpr_mu_unlock(&g_state_mu); + grpc_exec_ctx_finish(&exec_ctx); } /* -- Well known credentials path. -- */ diff --git a/Sources/CgRPC/src/core/lib/security/credentials/google_default/google_default_credentials.h b/Sources/CgRPC/src/core/lib/security/credentials/google_default/google_default_credentials.h index b55546ded..c3755e01a 100644 --- a/Sources/CgRPC/src/core/lib/security/credentials/google_default/google_default_credentials.h +++ b/Sources/CgRPC/src/core/lib/security/credentials/google_default/google_default_credentials.h @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/security/credentials/iam/iam_credentials.c b/Sources/CgRPC/src/core/lib/security/credentials/iam/iam_credentials.c index 370a384d0..3de8319d9 100644 --- a/Sources/CgRPC/src/core/lib/security/credentials/iam/iam_credentials.c +++ b/Sources/CgRPC/src/core/lib/security/credentials/iam/iam_credentials.c @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -42,28 +27,36 @@ #include #include -static void iam_destruct(grpc_call_credentials *creds) { +static void iam_destruct(grpc_exec_ctx *exec_ctx, + grpc_call_credentials *creds) { grpc_google_iam_credentials *c = (grpc_google_iam_credentials *)creds; - grpc_credentials_md_store_unref(c->iam_md); + grpc_credentials_mdelem_array_destroy(exec_ctx, &c->md_array); } -static void iam_get_request_metadata(grpc_exec_ctx *exec_ctx, +static bool iam_get_request_metadata(grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds, grpc_polling_entity *pollent, grpc_auth_metadata_context context, - grpc_credentials_metadata_cb cb, - void *user_data) { + grpc_credentials_mdelem_array *md_array, + grpc_closure *on_request_metadata, + grpc_error **error) { grpc_google_iam_credentials *c = (grpc_google_iam_credentials *)creds; - cb(exec_ctx, user_data, c->iam_md->entries, c->iam_md->num_entries, - GRPC_CREDENTIALS_OK, NULL); + grpc_credentials_mdelem_array_append(md_array, &c->md_array); + return true; } -static grpc_call_credentials_vtable iam_vtable = {iam_destruct, - iam_get_request_metadata}; +static void iam_cancel_get_request_metadata( + grpc_exec_ctx *exec_ctx, grpc_call_credentials *c, + 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_call_credentials *grpc_google_iam_credentials_create( const char *token, const char *authority_selector, void *reserved) { - grpc_google_iam_credentials *c; + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; GRPC_API_TRACE( "grpc_iam_credentials_create(token=%s, authority_selector=%s, " "reserved=%p)", @@ -71,15 +64,22 @@ grpc_call_credentials *grpc_google_iam_credentials_create( GPR_ASSERT(reserved == NULL); GPR_ASSERT(token != NULL); GPR_ASSERT(authority_selector != NULL); - c = gpr_malloc(sizeof(grpc_google_iam_credentials)); - memset(c, 0, sizeof(grpc_google_iam_credentials)); + grpc_google_iam_credentials *c = gpr_zalloc(sizeof(*c)); c->base.type = GRPC_CALL_CREDENTIALS_TYPE_IAM; c->base.vtable = &iam_vtable; gpr_ref_init(&c->base.refcount, 1); - c->iam_md = grpc_credentials_md_store_create(2); - grpc_credentials_md_store_add_cstrings( - c->iam_md, GRPC_IAM_AUTHORIZATION_TOKEN_METADATA_KEY, token); - grpc_credentials_md_store_add_cstrings( - c->iam_md, GRPC_IAM_AUTHORITY_SELECTOR_METADATA_KEY, authority_selector); + grpc_mdelem md = grpc_mdelem_from_slices( + &exec_ctx, + 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(&exec_ctx, md); + md = grpc_mdelem_from_slices( + &exec_ctx, + 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(&exec_ctx, md); + grpc_exec_ctx_finish(&exec_ctx); return &c->base; } diff --git a/Sources/CgRPC/src/core/lib/security/credentials/iam/iam_credentials.h b/Sources/CgRPC/src/core/lib/security/credentials/iam/iam_credentials.h index af54faa58..5e3cf65ba 100644 --- a/Sources/CgRPC/src/core/lib/security/credentials/iam/iam_credentials.h +++ b/Sources/CgRPC/src/core/lib/security/credentials/iam/iam_credentials.h @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -38,7 +23,7 @@ typedef struct { grpc_call_credentials base; - grpc_credentials_md_store *iam_md; + grpc_credentials_mdelem_array md_array; } grpc_google_iam_credentials; #endif /* GRPC_CORE_LIB_SECURITY_CREDENTIALS_IAM_IAM_CREDENTIALS_H */ diff --git a/Sources/CgRPC/src/core/lib/security/credentials/jwt/json_token.c b/Sources/CgRPC/src/core/lib/security/credentials/jwt/json_token.c index 192a5f47e..fff71255a 100644 --- a/Sources/CgRPC/src/core/lib/security/credentials/jwt/json_token.c +++ b/Sources/CgRPC/src/core/lib/security/credentials/jwt/json_token.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -40,8 +25,8 @@ #include #include -#include "src/core/lib/security/util/b64.h" #include "src/core/lib/security/util/json_util.h" +#include "src/core/lib/slice/b64.h" #include "src/core/lib/support/string.h" #include diff --git a/Sources/CgRPC/src/core/lib/security/credentials/jwt/json_token.h b/Sources/CgRPC/src/core/lib/security/credentials/jwt/json_token.h index c13eb5580..e50790ef2 100644 --- a/Sources/CgRPC/src/core/lib/security/credentials/jwt/json_token.h +++ b/Sources/CgRPC/src/core/lib/security/credentials/jwt/json_token.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/security/credentials/jwt/jwt_credentials.c b/Sources/CgRPC/src/core/lib/security/credentials/jwt/jwt_credentials.c index 3daf0f4ef..02c82e99b 100644 --- a/Sources/CgRPC/src/core/lib/security/credentials/jwt/jwt_credentials.c +++ b/Sources/CgRPC/src/core/lib/security/credentials/jwt/jwt_credentials.c @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -42,11 +27,10 @@ #include #include -static void jwt_reset_cache(grpc_service_account_jwt_access_credentials *c) { - if (c->cached.jwt_md != NULL) { - grpc_credentials_md_store_unref(c->cached.jwt_md); - c->cached.jwt_md = NULL; - } +static void jwt_reset_cache(grpc_exec_ctx *exec_ctx, + grpc_service_account_jwt_access_credentials *c) { + GRPC_MDELEM_UNREF(exec_ctx, c->cached.jwt_md); + c->cached.jwt_md = GRPC_MDNULL; if (c->cached.service_url != NULL) { gpr_free(c->cached.service_url); c->cached.service_url = NULL; @@ -54,45 +38,47 @@ static void jwt_reset_cache(grpc_service_account_jwt_access_credentials *c) { c->cached.jwt_expiration = gpr_inf_past(GPR_CLOCK_REALTIME); } -static void jwt_destruct(grpc_call_credentials *creds) { +static void jwt_destruct(grpc_exec_ctx *exec_ctx, + grpc_call_credentials *creds) { grpc_service_account_jwt_access_credentials *c = (grpc_service_account_jwt_access_credentials *)creds; grpc_auth_json_key_destruct(&c->key); - jwt_reset_cache(c); + jwt_reset_cache(exec_ctx, c); gpr_mu_destroy(&c->cache_mu); } -static void jwt_get_request_metadata(grpc_exec_ctx *exec_ctx, +static bool jwt_get_request_metadata(grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds, grpc_polling_entity *pollent, grpc_auth_metadata_context context, - grpc_credentials_metadata_cb cb, - void *user_data) { + grpc_credentials_mdelem_array *md_array, + grpc_closure *on_request_metadata, + grpc_error **error) { grpc_service_account_jwt_access_credentials *c = (grpc_service_account_jwt_access_credentials *)creds; 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_credentials_md_store *jwt_md = NULL; + grpc_mdelem jwt_md = GRPC_MDNULL; { gpr_mu_lock(&c->cache_mu); if (c->cached.service_url != NULL && strcmp(c->cached.service_url, context.service_url) == 0 && - c->cached.jwt_md != NULL && + !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_credentials_md_store_ref(c->cached.jwt_md); + jwt_md = GRPC_MDELEM_REF(c->cached.jwt_md); } gpr_mu_unlock(&c->cache_mu); } - if (jwt_md == NULL) { + if (GRPC_MDISNULL(jwt_md)) { char *jwt = NULL; /* Generate a new jwt. */ gpr_mu_lock(&c->cache_mu); - jwt_reset_cache(c); + jwt_reset_cache(exec_ctx, c); jwt = grpc_jwt_encode_and_sign(&c->key, context.service_url, c->jwt_lifetime, NULL); if (jwt != NULL) { @@ -102,45 +88,58 @@ static void jwt_get_request_metadata(grpc_exec_ctx *exec_ctx, 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_credentials_md_store_create(1); - grpc_credentials_md_store_add_cstrings( - c->cached.jwt_md, GRPC_AUTHORIZATION_METADATA_KEY, md_value); + c->cached.jwt_md = grpc_mdelem_from_slices( + exec_ctx, + grpc_slice_from_static_string(GRPC_AUTHORIZATION_METADATA_KEY), + grpc_slice_from_copied_string(md_value)); gpr_free(md_value); - jwt_md = grpc_credentials_md_store_ref(c->cached.jwt_md); + jwt_md = GRPC_MDELEM_REF(c->cached.jwt_md); } gpr_mu_unlock(&c->cache_mu); } - if (jwt_md != NULL) { - cb(exec_ctx, user_data, jwt_md->entries, jwt_md->num_entries, - GRPC_CREDENTIALS_OK, NULL); - grpc_credentials_md_store_unref(jwt_md); + if (!GRPC_MDISNULL(jwt_md)) { + grpc_credentials_mdelem_array_add(md_array, jwt_md); + GRPC_MDELEM_UNREF(exec_ctx, jwt_md); } else { - cb(exec_ctx, user_data, NULL, 0, GRPC_CREDENTIALS_ERROR, - "Could not generate JWT."); + *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Could not generate JWT."); } + return true; +} + +static void jwt_cancel_get_request_metadata( + grpc_exec_ctx *exec_ctx, grpc_call_credentials *c, + 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}; +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_exec_ctx *exec_ctx, 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 NULL; } - c = gpr_malloc(sizeof(grpc_service_account_jwt_access_credentials)); - memset(c, 0, sizeof(grpc_service_account_jwt_access_credentials)); + c = 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; + gpr_timespec max_token_lifetime = grpc_max_auth_token_lifetime(); + if (gpr_time_cmp(token_lifetime, max_token_lifetime) > 0) { + gpr_log(GPR_INFO, + "Cropping token lifetime to maximum allowed value (%d secs).", + (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); + jwt_reset_cache(exec_ctx, c); return &c->base; } @@ -169,7 +168,7 @@ static char *redact_private_key(const char *json_key) { grpc_call_credentials *grpc_service_account_jwt_access_credentials_create( const char *json_key, gpr_timespec token_lifetime, void *reserved) { - if (grpc_api_trace) { + if (GRPC_TRACER_ON(grpc_api_trace)) { char *clean_json = redact_private_key(json_key); gpr_log(GPR_INFO, "grpc_service_account_jwt_access_credentials_create(" @@ -183,6 +182,11 @@ grpc_call_credentials *grpc_service_account_jwt_access_credentials_create( gpr_free(clean_json); } GPR_ASSERT(reserved == NULL); - return grpc_service_account_jwt_access_credentials_create_from_auth_json_key( - grpc_auth_json_key_create_from_string(json_key), token_lifetime); + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + grpc_call_credentials *creds = + grpc_service_account_jwt_access_credentials_create_from_auth_json_key( + &exec_ctx, grpc_auth_json_key_create_from_string(json_key), + token_lifetime); + grpc_exec_ctx_finish(&exec_ctx); + return creds; } diff --git a/Sources/CgRPC/src/core/lib/security/credentials/jwt/jwt_credentials.h b/Sources/CgRPC/src/core/lib/security/credentials/jwt/jwt_credentials.h index d57260617..07f402266 100644 --- a/Sources/CgRPC/src/core/lib/security/credentials/jwt/jwt_credentials.h +++ b/Sources/CgRPC/src/core/lib/security/credentials/jwt/jwt_credentials.h @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -44,7 +29,7 @@ typedef struct { // the service_url for a more sophisticated one. gpr_mu cache_mu; struct { - grpc_credentials_md_store *jwt_md; + grpc_mdelem jwt_md; char *service_url; gpr_timespec jwt_expiration; } cached; @@ -57,6 +42,7 @@ typedef struct { // Takes ownership of the key. grpc_call_credentials * grpc_service_account_jwt_access_credentials_create_from_auth_json_key( - grpc_auth_json_key key, gpr_timespec token_lifetime); + grpc_exec_ctx *exec_ctx, grpc_auth_json_key key, + gpr_timespec token_lifetime); #endif /* GRPC_CORE_LIB_SECURITY_CREDENTIALS_JWT_JWT_CREDENTIALS_H */ diff --git a/Sources/CgRPC/src/core/lib/security/credentials/jwt/jwt_verifier.c b/Sources/CgRPC/src/core/lib/security/credentials/jwt/jwt_verifier.c index 42bd89dd0..a27284bc5 100644 --- a/Sources/CgRPC/src/core/lib/security/credentials/jwt/jwt_verifier.c +++ b/Sources/CgRPC/src/core/lib/security/credentials/jwt/jwt_verifier.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -36,11 +21,6 @@ #include #include -#include "src/core/lib/http/httpcli.h" -#include "src/core/lib/iomgr/polling_entity.h" -#include "src/core/lib/security/util/b64.h" -#include "src/core/lib/tsi/ssl_types.h" - #include #include #include @@ -48,6 +28,13 @@ #include #include +#include "src/core/lib/http/httpcli.h" +#include "src/core/lib/iomgr/polling_entity.h" +#include "src/core/lib/slice/b64.h" +#include "src/core/lib/slice/slice_internal.h" +#include "src/core/lib/support/string.h" +#include "src/core/tsi/ssl_types.h" + /* --- Utils. --- */ const char *grpc_jwt_verifier_status_to_string( @@ -84,11 +71,12 @@ static const EVP_MD *evp_md_from_alg(const char *alg) { } } -static grpc_json *parse_json_part_from_jwt(const char *str, size_t len, +static grpc_json *parse_json_part_from_jwt(grpc_exec_ctx *exec_ctx, + const char *str, size_t len, grpc_slice *buffer) { grpc_json *json; - *buffer = grpc_base64_decode_with_len(str, len, 1); + *buffer = grpc_base64_decode_with_len(exec_ctx, str, len, 1); if (GRPC_SLICE_IS_EMPTY(*buffer)) { gpr_log(GPR_ERROR, "Invalid base64."); return NULL; @@ -96,7 +84,7 @@ static grpc_json *parse_json_part_from_jwt(const char *str, size_t len, json = grpc_json_parse_string_with_len((char *)GRPC_SLICE_START_PTR(*buffer), GRPC_SLICE_LENGTH(*buffer)); if (json == NULL) { - grpc_slice_unref(*buffer); + grpc_slice_unref_internal(exec_ctx, *buffer); gpr_log(GPR_ERROR, "JSON parsing error."); } return json; @@ -132,16 +120,16 @@ typedef struct { grpc_slice buffer; } jose_header; -static void jose_header_destroy(jose_header *h) { - grpc_slice_unref(h->buffer); +static void jose_header_destroy(grpc_exec_ctx *exec_ctx, jose_header *h) { + grpc_slice_unref_internal(exec_ctx, h->buffer); gpr_free(h); } /* Takes ownership of json and buffer. */ -static jose_header *jose_header_from_json(grpc_json *json, grpc_slice buffer) { +static jose_header *jose_header_from_json(grpc_exec_ctx *exec_ctx, + grpc_json *json, grpc_slice buffer) { grpc_json *cur; - jose_header *h = gpr_malloc(sizeof(jose_header)); - memset(h, 0, sizeof(jose_header)); + jose_header *h = gpr_zalloc(sizeof(jose_header)); h->buffer = buffer; for (cur = json->child; cur != NULL; cur = cur->next) { if (strcmp(cur->key, "alg") == 0) { @@ -173,7 +161,7 @@ static jose_header *jose_header_from_json(grpc_json *json, grpc_slice buffer) { error: grpc_json_destroy(json); - jose_header_destroy(h); + jose_header_destroy(exec_ctx, h); return NULL; } @@ -193,9 +181,9 @@ struct grpc_jwt_claims { grpc_slice buffer; }; -void grpc_jwt_claims_destroy(grpc_jwt_claims *claims) { +void grpc_jwt_claims_destroy(grpc_exec_ctx *exec_ctx, grpc_jwt_claims *claims) { grpc_json_destroy(claims->json); - grpc_slice_unref(claims->buffer); + grpc_slice_unref_internal(exec_ctx, claims->buffer); gpr_free(claims); } @@ -240,7 +228,8 @@ gpr_timespec grpc_jwt_claims_not_before(const grpc_jwt_claims *claims) { } /* Takes ownership of json and buffer even in case of failure. */ -grpc_jwt_claims *grpc_jwt_claims_from_json(grpc_json *json, grpc_slice buffer) { +grpc_jwt_claims *grpc_jwt_claims_from_json(grpc_exec_ctx *exec_ctx, + grpc_json *json, grpc_slice buffer) { grpc_json *cur; grpc_jwt_claims *claims = gpr_malloc(sizeof(grpc_jwt_claims)); memset(claims, 0, sizeof(grpc_jwt_claims)); @@ -281,7 +270,7 @@ grpc_jwt_claims *grpc_jwt_claims_from_json(grpc_json *json, grpc_slice buffer) { return claims; error: - grpc_jwt_claims_destroy(claims); + grpc_jwt_claims_destroy(exec_ctx, claims); return NULL; } @@ -305,6 +294,17 @@ grpc_jwt_verifier_status grpc_jwt_claims_check(const grpc_jwt_claims *claims, return GRPC_JWT_VERIFIER_TIME_CONSTRAINT_FAILURE; } + /* This should be probably up to the upper layer to decide but let's harcode + the 99% use case here for email issuers, where the JWT must be self + issued. */ + if (grpc_jwt_issuer_email_domain(claims->iss) != NULL && + claims->sub != NULL && strcmp(claims->iss, claims->sub) != 0) { + gpr_log(GPR_ERROR, + "Email issuer (%s) cannot assert another subject (%s) than itself.", + claims->iss, claims->sub); + return GRPC_JWT_VERIFIER_BAD_SUBJECT; + } + if (audience == NULL) { audience_ok = claims->aud == NULL; } else { @@ -347,8 +347,7 @@ static verifier_cb_ctx *verifier_cb_ctx_create( const char *signed_jwt, size_t signed_jwt_len, void *user_data, grpc_jwt_verification_done_cb cb) { grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - verifier_cb_ctx *ctx = gpr_malloc(sizeof(verifier_cb_ctx)); - memset(ctx, 0, sizeof(verifier_cb_ctx)); + verifier_cb_ctx *ctx = gpr_zalloc(sizeof(verifier_cb_ctx)); ctx->verifier = verifier; ctx->pollent = grpc_polling_entity_create_from_pollset(pollset); ctx->header = header; @@ -362,12 +361,12 @@ static verifier_cb_ctx *verifier_cb_ctx_create( return ctx; } -void verifier_cb_ctx_destroy(verifier_cb_ctx *ctx) { +void verifier_cb_ctx_destroy(grpc_exec_ctx *exec_ctx, verifier_cb_ctx *ctx) { if (ctx->audience != NULL) gpr_free(ctx->audience); - if (ctx->claims != NULL) grpc_jwt_claims_destroy(ctx->claims); - grpc_slice_unref(ctx->signature); - grpc_slice_unref(ctx->signed_data); - jose_header_destroy(ctx->header); + if (ctx->claims != NULL) grpc_jwt_claims_destroy(exec_ctx, ctx->claims); + grpc_slice_unref_internal(exec_ctx, ctx->signature); + grpc_slice_unref_internal(exec_ctx, ctx->signed_data); + jose_header_destroy(exec_ctx, ctx->header); for (size_t i = 0; i < HTTP_RESPONSE_COUNT; i++) { grpc_http_response_destroy(&ctx->responses[i]); } @@ -443,30 +442,62 @@ static EVP_PKEY *extract_pkey_from_x509(const char *x509_str) { end: BIO_free(bio); - if (x509 != NULL) X509_free(x509); + X509_free(x509); return result; } -static BIGNUM *bignum_from_base64(const char *b64) { +static BIGNUM *bignum_from_base64(grpc_exec_ctx *exec_ctx, const char *b64) { BIGNUM *result = NULL; grpc_slice bin; if (b64 == NULL) return NULL; - bin = grpc_base64_decode(b64, 1); + bin = grpc_base64_decode(exec_ctx, b64, 1); if (GRPC_SLICE_IS_EMPTY(bin)) { gpr_log(GPR_ERROR, "Invalid base64 for big num."); return NULL; } result = BN_bin2bn(GRPC_SLICE_START_PTR(bin), TSI_SIZE_AS_SIZE(GRPC_SLICE_LENGTH(bin)), NULL); - grpc_slice_unref(bin); + grpc_slice_unref_internal(exec_ctx, bin); return result; } -static EVP_PKEY *pkey_from_jwk(const grpc_json *json, const char *kty) { +#if OPENSSL_VERSION_NUMBER < 0x10100000L + +// Provide compatibility across OpenSSL 1.02 and 1.1. +static int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d) { + /* If the fields n and e in r are NULL, the corresponding input + * parameters MUST be non-NULL for n and e. d may be + * left NULL (in case only the public key is used). + */ + if ((r->n == NULL && n == NULL) || (r->e == NULL && e == NULL)) { + return 0; + } + + if (n != NULL) { + BN_free(r->n); + r->n = n; + } + if (e != NULL) { + BN_free(r->e); + r->e = e; + } + if (d != NULL) { + BN_free(r->d); + r->d = d; + } + + return 1; +} +#endif // OPENSSL_VERSION_NUMBER < 0x10100000L + +static EVP_PKEY *pkey_from_jwk(grpc_exec_ctx *exec_ctx, const grpc_json *json, + const char *kty) { const grpc_json *key_prop; RSA *rsa = NULL; EVP_PKEY *result = NULL; + BIGNUM *tmp_n = NULL; + BIGNUM *tmp_e = NULL; GPR_ASSERT(kty != NULL && json != NULL); if (strcmp(kty, "RSA") != 0) { @@ -480,26 +511,38 @@ static EVP_PKEY *pkey_from_jwk(const grpc_json *json, const char *kty) { } for (key_prop = json->child; key_prop != NULL; key_prop = key_prop->next) { if (strcmp(key_prop->key, "n") == 0) { - rsa->n = bignum_from_base64(validate_string_field(key_prop, "n")); - if (rsa->n == NULL) goto end; + tmp_n = + bignum_from_base64(exec_ctx, validate_string_field(key_prop, "n")); + if (tmp_n == NULL) goto end; } else if (strcmp(key_prop->key, "e") == 0) { - rsa->e = bignum_from_base64(validate_string_field(key_prop, "e")); - if (rsa->e == NULL) goto end; + tmp_e = + bignum_from_base64(exec_ctx, validate_string_field(key_prop, "e")); + if (tmp_e == NULL) goto end; } } - if (rsa->e == NULL || rsa->n == NULL) { + if (tmp_e == NULL || tmp_n == NULL) { gpr_log(GPR_ERROR, "Missing RSA public key field."); goto end; } + if (!RSA_set0_key(rsa, tmp_n, tmp_e, NULL)) { + gpr_log(GPR_ERROR, "Cannot set RSA key from inputs."); + goto end; + } + /* RSA_set0_key takes ownership on success. */ + tmp_n = NULL; + tmp_e = NULL; result = EVP_PKEY_new(); EVP_PKEY_set1_RSA(result, rsa); /* uprefs rsa. */ end: - if (rsa != NULL) RSA_free(rsa); + RSA_free(rsa); + BN_free(tmp_n); + BN_free(tmp_e); return result; } -static EVP_PKEY *find_verification_key(const grpc_json *json, +static EVP_PKEY *find_verification_key(grpc_exec_ctx *exec_ctx, + const grpc_json *json, const char *header_alg, const char *header_kid) { const grpc_json *jkey; @@ -543,7 +586,7 @@ static EVP_PKEY *find_verification_key(const grpc_json *json, } if (alg != NULL && kid != NULL && kty != NULL && strcmp(kid, header_kid) == 0 && strcmp(alg, header_alg) == 0) { - return pkey_from_jwk(jkey, kty); + return pkey_from_jwk(exec_ctx, jkey, kty); } } gpr_log(GPR_ERROR, @@ -580,7 +623,7 @@ static int verify_jwt_signature(EVP_PKEY *key, const char *alg, result = 1; end: - if (md_ctx != NULL) EVP_MD_CTX_destroy(md_ctx); + EVP_MD_CTX_destroy(md_ctx); return result; } @@ -597,7 +640,7 @@ static void on_keys_retrieved(grpc_exec_ctx *exec_ctx, void *user_data, goto end; } verification_key = - find_verification_key(json, ctx->header->alg, ctx->header->kid); + find_verification_key(exec_ctx, json, ctx->header->alg, ctx->header->kid); if (verification_key == NULL) { gpr_log(GPR_ERROR, "Could not find verification key with kid %s.", ctx->header->kid); @@ -620,9 +663,9 @@ static void on_keys_retrieved(grpc_exec_ctx *exec_ctx, void *user_data, end: if (json != NULL) grpc_json_destroy(json); - if (verification_key != NULL) EVP_PKEY_free(verification_key); - ctx->user_cb(ctx->user_data, status, claims); - verifier_cb_ctx_destroy(ctx); + EVP_PKEY_free(verification_key); + ctx->user_cb(exec_ctx, ctx->user_data, status, claims); + verifier_cb_ctx_destroy(exec_ctx, ctx); } static void on_openid_config_retrieved(grpc_exec_ctx *exec_ctx, void *user_data, @@ -665,17 +708,18 @@ static void on_openid_config_retrieved(grpc_exec_ctx *exec_ctx, void *user_data, grpc_httpcli_get( exec_ctx, &ctx->verifier->http_ctx, &ctx->pollent, resource_quota, &req, gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), grpc_jwt_verifier_max_delay), - grpc_closure_create(on_keys_retrieved, ctx), + GRPC_CLOSURE_CREATE(on_keys_retrieved, ctx, grpc_schedule_on_exec_ctx), &ctx->responses[HTTP_RESPONSE_KEYS]); - grpc_resource_quota_internal_unref(exec_ctx, resource_quota); + grpc_resource_quota_unref_internal(exec_ctx, resource_quota); grpc_json_destroy(json); gpr_free(req.host); return; error: if (json != NULL) grpc_json_destroy(json); - ctx->user_cb(ctx->user_data, GRPC_JWT_VERIFIER_KEY_RETRIEVAL_ERROR, NULL); - verifier_cb_ctx_destroy(ctx); + ctx->user_cb(exec_ctx, ctx->user_data, GRPC_JWT_VERIFIER_KEY_RETRIEVAL_ERROR, + NULL); + verifier_cb_ctx_destroy(exec_ctx, ctx); } static email_key_mapping *verifier_get_mapping(grpc_jwt_verifier *v, @@ -705,10 +749,26 @@ static void verifier_put_mapping(grpc_jwt_verifier *v, const char *email_domain, GPR_ASSERT(v->num_mappings <= v->allocated_mappings); } +/* Very non-sophisticated way to detect an email address. Should be good + enough for now... */ +const char *grpc_jwt_issuer_email_domain(const char *issuer) { + const char *at_sign = strchr(issuer, '@'); + if (at_sign == NULL) return NULL; + const char *email_domain = at_sign + 1; + if (*email_domain == '\0') return NULL; + const char *dot = strrchr(email_domain, '.'); + if (dot == NULL || dot == email_domain) return email_domain; + GPR_ASSERT(dot > email_domain); + /* There may be a subdomain, we just want the domain. */ + dot = gpr_memrchr(email_domain, '.', (size_t)(dot - email_domain)); + if (dot == NULL) return email_domain; + return dot + 1; +} + /* Takes ownership of ctx. */ static void retrieve_key_and_verify(grpc_exec_ctx *exec_ctx, verifier_cb_ctx *ctx) { - const char *at_sign; + const char *email_domain; grpc_closure *http_cb; char *path_prefix = NULL; const char *iss; @@ -733,13 +793,9 @@ static void retrieve_key_and_verify(grpc_exec_ctx *exec_ctx, Nobody seems to implement the account/email/webfinger part 2. of the spec so we will rely instead on email/url mappings if we detect such an issuer. Part 4, on the other hand is implemented by both google and salesforce. */ - - /* Very non-sophisticated way to detect an email address. Should be good - enough for now... */ - at_sign = strchr(iss, '@'); - if (at_sign != NULL) { + email_domain = grpc_jwt_issuer_email_domain(iss); + if (email_domain != NULL) { email_key_mapping *mapping; - const char *email_domain = at_sign + 1; GPR_ASSERT(ctx->verifier != NULL); mapping = verifier_get_mapping(ctx->verifier, email_domain); if (mapping == NULL) { @@ -754,7 +810,8 @@ static void retrieve_key_and_verify(grpc_exec_ctx *exec_ctx, *(path_prefix++) = '\0'; gpr_asprintf(&req.http.path, "/%s/%s", path_prefix, iss); } - http_cb = grpc_closure_create(on_keys_retrieved, ctx); + http_cb = + GRPC_CLOSURE_CREATE(on_keys_retrieved, ctx, grpc_schedule_on_exec_ctx); rsp_idx = HTTP_RESPONSE_KEYS; } else { req.host = gpr_strdup(strstr(iss, "https://") == iss ? iss + 8 : iss); @@ -766,7 +823,8 @@ static void retrieve_key_and_verify(grpc_exec_ctx *exec_ctx, gpr_asprintf(&req.http.path, "/%s%s", path_prefix, GRPC_OPENID_CONFIG_URL_SUFFIX); } - http_cb = grpc_closure_create(on_openid_config_retrieved, ctx); + http_cb = GRPC_CLOSURE_CREATE(on_openid_config_retrieved, ctx, + grpc_schedule_on_exec_ctx); rsp_idx = HTTP_RESPONSE_OPENID; } @@ -779,14 +837,15 @@ static void retrieve_key_and_verify(grpc_exec_ctx *exec_ctx, exec_ctx, &ctx->verifier->http_ctx, &ctx->pollent, resource_quota, &req, gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), grpc_jwt_verifier_max_delay), http_cb, &ctx->responses[rsp_idx]); - grpc_resource_quota_internal_unref(exec_ctx, resource_quota); + grpc_resource_quota_unref_internal(exec_ctx, resource_quota); gpr_free(req.host); gpr_free(req.http.path); return; error: - ctx->user_cb(ctx->user_data, GRPC_JWT_VERIFIER_KEY_RETRIEVAL_ERROR, NULL); - verifier_cb_ctx_destroy(ctx); + ctx->user_cb(exec_ctx, ctx->user_data, GRPC_JWT_VERIFIER_KEY_RETRIEVAL_ERROR, + NULL); + verifier_cb_ctx_destroy(exec_ctx, ctx); } void grpc_jwt_verifier_verify(grpc_exec_ctx *exec_ctx, @@ -808,22 +867,24 @@ void grpc_jwt_verifier_verify(grpc_exec_ctx *exec_ctx, GPR_ASSERT(verifier != NULL && jwt != NULL && audience != NULL && cb != NULL); dot = strchr(cur, '.'); if (dot == NULL) goto error; - json = parse_json_part_from_jwt(cur, (size_t)(dot - cur), &header_buffer); + json = parse_json_part_from_jwt(exec_ctx, cur, (size_t)(dot - cur), + &header_buffer); if (json == NULL) goto error; - header = jose_header_from_json(json, header_buffer); + header = jose_header_from_json(exec_ctx, json, header_buffer); if (header == NULL) goto error; cur = dot + 1; dot = strchr(cur, '.'); if (dot == NULL) goto error; - json = parse_json_part_from_jwt(cur, (size_t)(dot - cur), &claims_buffer); + json = parse_json_part_from_jwt(exec_ctx, cur, (size_t)(dot - cur), + &claims_buffer); if (json == NULL) goto error; - claims = grpc_jwt_claims_from_json(json, claims_buffer); + claims = grpc_jwt_claims_from_json(exec_ctx, json, claims_buffer); if (claims == NULL) goto error; signed_jwt_len = (size_t)(dot - jwt); cur = dot + 1; - signature = grpc_base64_decode(cur, 1); + signature = grpc_base64_decode(exec_ctx, cur, 1); if (GRPC_SLICE_IS_EMPTY(signature)) goto error; retrieve_key_and_verify( exec_ctx, @@ -832,16 +893,15 @@ void grpc_jwt_verifier_verify(grpc_exec_ctx *exec_ctx, return; error: - if (header != NULL) jose_header_destroy(header); - if (claims != NULL) grpc_jwt_claims_destroy(claims); - cb(user_data, GRPC_JWT_VERIFIER_BAD_FORMAT, NULL); + if (header != NULL) jose_header_destroy(exec_ctx, header); + if (claims != NULL) grpc_jwt_claims_destroy(exec_ctx, claims); + cb(exec_ctx, user_data, GRPC_JWT_VERIFIER_BAD_FORMAT, NULL); } grpc_jwt_verifier *grpc_jwt_verifier_create( const grpc_jwt_verifier_email_domain_key_url_mapping *mappings, size_t num_mappings) { - grpc_jwt_verifier *v = gpr_malloc(sizeof(grpc_jwt_verifier)); - memset(v, 0, sizeof(grpc_jwt_verifier)); + grpc_jwt_verifier *v = gpr_zalloc(sizeof(grpc_jwt_verifier)); grpc_httpcli_context_init(&v->http_ctx); /* We know at least of one mapping. */ @@ -860,10 +920,10 @@ grpc_jwt_verifier *grpc_jwt_verifier_create( return v; } -void grpc_jwt_verifier_destroy(grpc_jwt_verifier *v) { +void grpc_jwt_verifier_destroy(grpc_exec_ctx *exec_ctx, grpc_jwt_verifier *v) { size_t i; if (v == NULL) return; - grpc_httpcli_context_destroy(&v->http_ctx); + grpc_httpcli_context_destroy(exec_ctx, &v->http_ctx); if (v->mappings != NULL) { for (i = 0; i < v->num_mappings; i++) { gpr_free(v->mappings[i].email_domain); diff --git a/Sources/CgRPC/src/core/lib/security/credentials/jwt/jwt_verifier.h b/Sources/CgRPC/src/core/lib/security/credentials/jwt/jwt_verifier.h index f09f9d5d4..8fac452d4 100644 --- a/Sources/CgRPC/src/core/lib/security/credentials/jwt/jwt_verifier.h +++ b/Sources/CgRPC/src/core/lib/security/credentials/jwt/jwt_verifier.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -43,8 +28,7 @@ /* --- Constants. --- */ #define GRPC_OPENID_CONFIG_URL_SUFFIX "/.well-known/openid-configuration" -#define GRPC_GOOGLE_SERVICE_ACCOUNTS_EMAIL_DOMAIN \ - "developer.gserviceaccount.com" +#define GRPC_GOOGLE_SERVICE_ACCOUNTS_EMAIL_DOMAIN "gserviceaccount.com" #define GRPC_GOOGLE_SERVICE_ACCOUNTS_KEY_URL_PREFIX \ "www.googleapis.com/robot/v1/metadata/x509" @@ -57,6 +41,7 @@ typedef enum { GRPC_JWT_VERIFIER_BAD_AUDIENCE, GRPC_JWT_VERIFIER_KEY_RETRIEVAL_ERROR, GRPC_JWT_VERIFIER_TIME_CONSTRAINT_FAILURE, + GRPC_JWT_VERIFIER_BAD_SUBJECT, GRPC_JWT_VERIFIER_GENERIC_ERROR } grpc_jwt_verifier_status; @@ -66,7 +51,7 @@ const char *grpc_jwt_verifier_status_to_string(grpc_jwt_verifier_status status); typedef struct grpc_jwt_claims grpc_jwt_claims; -void grpc_jwt_claims_destroy(grpc_jwt_claims *claims); +void grpc_jwt_claims_destroy(grpc_exec_ctx *exec_ctx, grpc_jwt_claims *claims); /* Returns the whole JSON tree of the claims. */ const grpc_json *grpc_jwt_claims_json(const grpc_jwt_claims *claims); @@ -109,13 +94,15 @@ grpc_jwt_verifier *grpc_jwt_verifier_create( size_t num_mappings); /*The verifier must not be destroyed if there are still outstanding callbacks.*/ -void grpc_jwt_verifier_destroy(grpc_jwt_verifier *verifier); +void grpc_jwt_verifier_destroy(grpc_exec_ctx *exec_ctx, + grpc_jwt_verifier *verifier); /* User provided callback that will be called when the verification of the JWT is done (maybe in another thread). It is the responsibility of the callee to call grpc_jwt_claims_destroy on the claims. */ -typedef void (*grpc_jwt_verification_done_cb)(void *user_data, +typedef void (*grpc_jwt_verification_done_cb)(grpc_exec_ctx *exec_ctx, + void *user_data, grpc_jwt_verifier_status status, grpc_jwt_claims *claims); @@ -129,8 +116,10 @@ void grpc_jwt_verifier_verify(grpc_exec_ctx *exec_ctx, /* --- TESTING ONLY exposed functions. --- */ -grpc_jwt_claims *grpc_jwt_claims_from_json(grpc_json *json, grpc_slice buffer); +grpc_jwt_claims *grpc_jwt_claims_from_json(grpc_exec_ctx *exec_ctx, + grpc_json *json, grpc_slice buffer); grpc_jwt_verifier_status grpc_jwt_claims_check(const grpc_jwt_claims *claims, const char *audience); +const char *grpc_jwt_issuer_email_domain(const char *issuer); #endif /* GRPC_CORE_LIB_SECURITY_CREDENTIALS_JWT_JWT_VERIFIER_H */ diff --git a/Sources/CgRPC/src/core/lib/security/credentials/oauth2/oauth2_credentials.c b/Sources/CgRPC/src/core/lib/security/credentials/oauth2/oauth2_credentials.c index b3625b22c..10b270c49 100644 --- a/Sources/CgRPC/src/core/lib/security/credentials/oauth2/oauth2_credentials.c +++ b/Sources/CgRPC/src/core/lib/security/credentials/oauth2/oauth2_credentials.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -118,18 +103,21 @@ 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) { +static void oauth2_token_fetcher_destruct(grpc_exec_ctx *exec_ctx, + grpc_call_credentials *creds) { grpc_oauth2_token_fetcher_credentials *c = (grpc_oauth2_token_fetcher_credentials *)creds; - grpc_credentials_md_store_unref(c->access_token_md); + GRPC_MDELEM_UNREF(exec_ctx, c->access_token_md); gpr_mu_destroy(&c->mu); - grpc_httpcli_context_destroy(&c->httpcli_context); + grpc_pollset_set_destroy(exec_ctx, + grpc_polling_entity_pollset_set(&c->pollent)); + grpc_httpcli_context_destroy(exec_ctx, &c->httpcli_context); } grpc_credentials_status grpc_oauth2_token_fetcher_credentials_parse_server_response( - const grpc_http_response *response, grpc_credentials_md_store **token_md, - gpr_timespec *token_lifetime) { + grpc_exec_ctx *exec_ctx, const grpc_http_response *response, + grpc_mdelem *token_md, gpr_timespec *token_lifetime) { char *null_terminated_body = NULL; char *new_access_token = NULL; grpc_credentials_status status = GRPC_CREDENTIALS_OK; @@ -198,17 +186,18 @@ grpc_oauth2_token_fetcher_credentials_parse_server_response( token_lifetime->tv_sec = strtol(expires_in->value, NULL, 10); token_lifetime->tv_nsec = 0; token_lifetime->clock_type = GPR_TIMESPAN; - if (*token_md != NULL) grpc_credentials_md_store_unref(*token_md); - *token_md = grpc_credentials_md_store_create(1); - grpc_credentials_md_store_add_cstrings( - *token_md, GRPC_AUTHORIZATION_METADATA_KEY, new_access_token); + if (!GRPC_MDISNULL(*token_md)) GRPC_MDELEM_UNREF(exec_ctx, *token_md); + *token_md = grpc_mdelem_from_slices( + exec_ctx, + grpc_slice_from_static_string(GRPC_AUTHORIZATION_METADATA_KEY), + grpc_slice_from_copied_string(new_access_token)); status = GRPC_CREDENTIALS_OK; } end: - if (status != GRPC_CREDENTIALS_OK && (*token_md != NULL)) { - grpc_credentials_md_store_unref(*token_md); - *token_md = NULL; + if (status != GRPC_CREDENTIALS_OK && !GRPC_MDISNULL(*token_md)) { + GRPC_MDELEM_UNREF(exec_ctx, *token_md); + *token_md = GRPC_MDNULL; } if (null_terminated_body != NULL) gpr_free(null_terminated_body); if (new_access_token != NULL) gpr_free(new_access_token); @@ -219,63 +208,130 @@ grpc_oauth2_token_fetcher_credentials_parse_server_response( static void on_oauth2_token_fetcher_http_response(grpc_exec_ctx *exec_ctx, void *user_data, grpc_error *error) { + GRPC_LOG_IF_ERROR("oauth_fetch", GRPC_ERROR_REF(error)); grpc_credentials_metadata_request *r = (grpc_credentials_metadata_request *)user_data; grpc_oauth2_token_fetcher_credentials *c = (grpc_oauth2_token_fetcher_credentials *)r->creds; + grpc_mdelem access_token_md = GRPC_MDNULL; gpr_timespec token_lifetime; - grpc_credentials_status status; - - GRPC_LOG_IF_ERROR("oauth_fetch", GRPC_ERROR_REF(error)); - + grpc_credentials_status status = + grpc_oauth2_token_fetcher_credentials_parse_server_response( + exec_ctx, &r->response, &access_token_md, &token_lifetime); + // Update cache and grab list of pending requests. gpr_mu_lock(&c->mu); - status = grpc_oauth2_token_fetcher_credentials_parse_server_response( - &r->response, &c->access_token_md, &token_lifetime); - if (status == GRPC_CREDENTIALS_OK) { - c->token_expiration = - gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), token_lifetime); - r->cb(exec_ctx, r->user_data, c->access_token_md->entries, - c->access_token_md->num_entries, GRPC_CREDENTIALS_OK, NULL); - } else { - c->token_expiration = gpr_inf_past(GPR_CLOCK_REALTIME); - r->cb(exec_ctx, r->user_data, NULL, 0, status, - "Error occured when fetching oauth2 token."); - } + c->token_fetch_pending = false; + c->access_token_md = GRPC_MDELEM_REF(access_token_md); + c->token_expiration = + status == GRPC_CREDENTIALS_OK + ? gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), token_lifetime) + : gpr_inf_past(GPR_CLOCK_REALTIME); + grpc_oauth2_pending_get_request_metadata *pending_request = + c->pending_requests; + c->pending_requests = NULL; gpr_mu_unlock(&c->mu); - grpc_credentials_metadata_request_destroy(r); + // Invoke callbacks for all pending requests. + while (pending_request != NULL) { + if (status == GRPC_CREDENTIALS_OK) { + grpc_credentials_mdelem_array_add(pending_request->md_array, + access_token_md); + } else { + error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( + "Error occured when fetching oauth2 token.", &error, 1); + } + GRPC_CLOSURE_SCHED(exec_ctx, pending_request->on_request_metadata, error); + grpc_polling_entity_del_from_pollset_set( + exec_ctx, pending_request->pollent, + grpc_polling_entity_pollset_set(&c->pollent)); + grpc_oauth2_pending_get_request_metadata *prev = pending_request; + pending_request = pending_request->next; + gpr_free(prev); + } + GRPC_MDELEM_UNREF(exec_ctx, access_token_md); + grpc_call_credentials_unref(exec_ctx, r->creds); + grpc_credentials_metadata_request_destroy(exec_ctx, r); } -static void oauth2_token_fetcher_get_request_metadata( +static bool oauth2_token_fetcher_get_request_metadata( grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds, grpc_polling_entity *pollent, grpc_auth_metadata_context context, - grpc_credentials_metadata_cb cb, void *user_data) { + grpc_credentials_mdelem_array *md_array, grpc_closure *on_request_metadata, + grpc_error **error) { grpc_oauth2_token_fetcher_credentials *c = (grpc_oauth2_token_fetcher_credentials *)creds; + // Check if we can use the cached token. gpr_timespec refresh_threshold = gpr_time_from_seconds( GRPC_SECURE_TOKEN_REFRESH_THRESHOLD_SECS, GPR_TIMESPAN); - grpc_credentials_md_store *cached_access_token_md = NULL; - { - gpr_mu_lock(&c->mu); - if (c->access_token_md != NULL && - (gpr_time_cmp( - gpr_time_sub(c->token_expiration, gpr_now(GPR_CLOCK_REALTIME)), - refresh_threshold) > 0)) { - cached_access_token_md = - grpc_credentials_md_store_ref(c->access_token_md); - } + grpc_mdelem cached_access_token_md = GRPC_MDNULL; + gpr_mu_lock(&c->mu); + if (!GRPC_MDISNULL(c->access_token_md) && + (gpr_time_cmp( + gpr_time_sub(c->token_expiration, gpr_now(GPR_CLOCK_REALTIME)), + refresh_threshold) > 0)) { + cached_access_token_md = GRPC_MDELEM_REF(c->access_token_md); + } + if (!GRPC_MDISNULL(cached_access_token_md)) { gpr_mu_unlock(&c->mu); + grpc_credentials_mdelem_array_add(md_array, cached_access_token_md); + GRPC_MDELEM_UNREF(exec_ctx, cached_access_token_md); + return true; } - if (cached_access_token_md != NULL) { - cb(exec_ctx, user_data, cached_access_token_md->entries, - cached_access_token_md->num_entries, GRPC_CREDENTIALS_OK, NULL); - grpc_credentials_md_store_unref(cached_access_token_md); - } else { + // Couldn't get the token from the cache. + // Add request to c->pending_requests and start a new fetch if needed. + grpc_oauth2_pending_get_request_metadata *pending_request = + (grpc_oauth2_pending_get_request_metadata *)gpr_malloc( + sizeof(*pending_request)); + pending_request->md_array = md_array; + pending_request->on_request_metadata = on_request_metadata; + pending_request->pollent = pollent; + grpc_polling_entity_add_to_pollset_set( + exec_ctx, pollent, grpc_polling_entity_pollset_set(&c->pollent)); + pending_request->next = c->pending_requests; + c->pending_requests = pending_request; + bool start_fetch = false; + if (!c->token_fetch_pending) { + c->token_fetch_pending = true; + start_fetch = true; + } + gpr_mu_unlock(&c->mu); + if (start_fetch) { + grpc_call_credentials_ref(creds); c->fetch_func( - exec_ctx, - grpc_credentials_metadata_request_create(creds, cb, user_data), - &c->httpcli_context, pollent, on_oauth2_token_fetcher_http_response, - gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), refresh_threshold)); + exec_ctx, grpc_credentials_metadata_request_create(creds), + &c->httpcli_context, &c->pollent, on_oauth2_token_fetcher_http_response, + gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), refresh_threshold)); } + return false; +} + +static void oauth2_token_fetcher_cancel_get_request_metadata( + grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds, + grpc_credentials_mdelem_array *md_array, grpc_error *error) { + grpc_oauth2_token_fetcher_credentials *c = + (grpc_oauth2_token_fetcher_credentials *)creds; + gpr_mu_lock(&c->mu); + grpc_oauth2_pending_get_request_metadata *prev = NULL; + grpc_oauth2_pending_get_request_metadata *pending_request = + c->pending_requests; + while (pending_request != NULL) { + if (pending_request->md_array == md_array) { + // Remove matching pending request from the list. + if (prev != NULL) { + prev->next = pending_request->next; + } else { + c->pending_requests = pending_request->next; + } + // Invoke the callback immediately with an error. + GRPC_CLOSURE_SCHED(exec_ctx, pending_request->on_request_metadata, + GRPC_ERROR_REF(error)); + gpr_free(pending_request); + break; + } + prev = pending_request; + pending_request = pending_request->next; + } + gpr_mu_unlock(&c->mu); + GRPC_ERROR_UNREF(error); } static void init_oauth2_token_fetcher(grpc_oauth2_token_fetcher_credentials *c, @@ -286,6 +342,8 @@ static void init_oauth2_token_fetcher(grpc_oauth2_token_fetcher_credentials *c, gpr_mu_init(&c->mu); c->token_expiration = gpr_inf_past(GPR_CLOCK_REALTIME); 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); } @@ -294,7 +352,8 @@ static void init_oauth2_token_fetcher(grpc_oauth2_token_fetcher_credentials *c, // static grpc_call_credentials_vtable compute_engine_vtable = { - oauth2_token_fetcher_destruct, oauth2_token_fetcher_get_request_metadata}; + oauth2_token_fetcher_destruct, oauth2_token_fetcher_get_request_metadata, + oauth2_token_fetcher_cancel_get_request_metadata}; static void compute_engine_fetch_oauth2( grpc_exec_ctx *exec_ctx, grpc_credentials_metadata_request *metadata_req, @@ -312,10 +371,11 @@ static void compute_engine_fetch_oauth2( extreme memory pressure. */ grpc_resource_quota *resource_quota = grpc_resource_quota_create("oauth2_credentials"); - grpc_httpcli_get(exec_ctx, httpcli_context, pollent, resource_quota, &request, - deadline, grpc_closure_create(response_cb, metadata_req), - &metadata_req->response); - grpc_resource_quota_internal_unref(exec_ctx, resource_quota); + grpc_httpcli_get( + exec_ctx, 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(exec_ctx, resource_quota); } grpc_call_credentials *grpc_google_compute_engine_credentials_create( @@ -334,15 +394,17 @@ grpc_call_credentials *grpc_google_compute_engine_credentials_create( // Google Refresh Token credentials. // -static void refresh_token_destruct(grpc_call_credentials *creds) { +static void refresh_token_destruct(grpc_exec_ctx *exec_ctx, + grpc_call_credentials *creds) { grpc_google_refresh_token_credentials *c = (grpc_google_refresh_token_credentials *)creds; grpc_auth_refresh_token_destruct(&c->refresh_token); - oauth2_token_fetcher_destruct(&c->base.base); + oauth2_token_fetcher_destruct(exec_ctx, &c->base.base); } static grpc_call_credentials_vtable refresh_token_vtable = { - refresh_token_destruct, oauth2_token_fetcher_get_request_metadata}; + refresh_token_destruct, oauth2_token_fetcher_get_request_metadata, + oauth2_token_fetcher_cancel_get_request_metadata}; static void refresh_token_fetch_oauth2( grpc_exec_ctx *exec_ctx, grpc_credentials_metadata_request *metadata_req, @@ -368,11 +430,12 @@ static void refresh_token_fetch_oauth2( extreme memory pressure. */ grpc_resource_quota *resource_quota = grpc_resource_quota_create("oauth2_credentials_refresh"); - grpc_httpcli_post(exec_ctx, httpcli_context, pollent, resource_quota, - &request, body, strlen(body), deadline, - grpc_closure_create(response_cb, metadata_req), - &metadata_req->response); - grpc_resource_quota_internal_unref(exec_ctx, resource_quota); + grpc_httpcli_post( + exec_ctx, httpcli_context, pollent, resource_quota, &request, body, + strlen(body), deadline, + GRPC_CLOSURE_CREATE(response_cb, metadata_req, grpc_schedule_on_exec_ctx), + &metadata_req->response); + grpc_resource_quota_unref_internal(exec_ctx, resource_quota); gpr_free(body); } @@ -384,8 +447,7 @@ grpc_refresh_token_credentials_create_from_auth_refresh_token( gpr_log(GPR_ERROR, "Invalid input for refresh token credentials creation"); return NULL; } - c = gpr_malloc(sizeof(grpc_google_refresh_token_credentials)); - memset(c, 0, sizeof(grpc_google_refresh_token_credentials)); + c = 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; @@ -408,7 +470,7 @@ grpc_call_credentials *grpc_google_refresh_token_credentials_create( const char *json_refresh_token, void *reserved) { grpc_auth_refresh_token token = grpc_auth_refresh_token_create_from_string(json_refresh_token); - if (grpc_api_trace) { + if (GRPC_TRACER_ON(grpc_api_trace)) { char *loggable_token = create_loggable_refresh_token(&token); gpr_log(GPR_INFO, "grpc_refresh_token_credentials_create(json_refresh_token=%s, " @@ -424,41 +486,51 @@ grpc_call_credentials *grpc_google_refresh_token_credentials_create( // Oauth2 Access Token credentials. // -static void access_token_destruct(grpc_call_credentials *creds) { +static void access_token_destruct(grpc_exec_ctx *exec_ctx, + grpc_call_credentials *creds) { grpc_access_token_credentials *c = (grpc_access_token_credentials *)creds; - grpc_credentials_md_store_unref(c->access_token_md); + GRPC_MDELEM_UNREF(exec_ctx, c->access_token_md); } -static void access_token_get_request_metadata( +static bool access_token_get_request_metadata( grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds, grpc_polling_entity *pollent, grpc_auth_metadata_context context, - grpc_credentials_metadata_cb cb, void *user_data) { + grpc_credentials_mdelem_array *md_array, grpc_closure *on_request_metadata, + grpc_error **error) { grpc_access_token_credentials *c = (grpc_access_token_credentials *)creds; - cb(exec_ctx, user_data, c->access_token_md->entries, 1, GRPC_CREDENTIALS_OK, - NULL); + grpc_credentials_mdelem_array_add(md_array, c->access_token_md); + return true; +} + +static void access_token_cancel_get_request_metadata( + grpc_exec_ctx *exec_ctx, grpc_call_credentials *c, + 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_destruct, access_token_get_request_metadata, + access_token_cancel_get_request_metadata}; grpc_call_credentials *grpc_access_token_credentials_create( const char *access_token, void *reserved) { grpc_access_token_credentials *c = - gpr_malloc(sizeof(grpc_access_token_credentials)); - char *token_md_value; + gpr_zalloc(sizeof(grpc_access_token_credentials)); GRPC_API_TRACE( "grpc_access_token_credentials_create(access_token=, " "reserved=%p)", 1, (reserved)); GPR_ASSERT(reserved == NULL); - memset(c, 0, sizeof(grpc_access_token_credentials)); c->base.type = GRPC_CALL_CREDENTIALS_TYPE_OAUTH2; c->base.vtable = &access_token_vtable; gpr_ref_init(&c->base.refcount, 1); - c->access_token_md = grpc_credentials_md_store_create(1); + char *token_md_value; gpr_asprintf(&token_md_value, "Bearer %s", access_token); - grpc_credentials_md_store_add_cstrings( - c->access_token_md, GRPC_AUTHORIZATION_METADATA_KEY, token_md_value); + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + c->access_token_md = grpc_mdelem_from_slices( + &exec_ctx, grpc_slice_from_static_string(GRPC_AUTHORIZATION_METADATA_KEY), + grpc_slice_from_copied_string(token_md_value)); + grpc_exec_ctx_finish(&exec_ctx); gpr_free(token_md_value); return &c->base; } diff --git a/Sources/CgRPC/src/core/lib/security/credentials/oauth2/oauth2_credentials.h b/Sources/CgRPC/src/core/lib/security/credentials/oauth2/oauth2_credentials.h index 7f6f205c2..d9ad6691b 100644 --- a/Sources/CgRPC/src/core/lib/security/credentials/oauth2/oauth2_credentials.h +++ b/Sources/CgRPC/src/core/lib/security/credentials/oauth2/oauth2_credentials.h @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -73,13 +58,24 @@ typedef void (*grpc_fetch_oauth2_func)(grpc_exec_ctx *exec_ctx, grpc_polling_entity *pollent, grpc_iomgr_cb_func cb, gpr_timespec deadline); + +typedef 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_credentials_md_store *access_token_md; + 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; // Google refresh token credentials. @@ -91,7 +87,7 @@ typedef struct { // Access token credentials. typedef struct { grpc_call_credentials base; - grpc_credentials_md_store *access_token_md; + grpc_mdelem access_token_md; } grpc_access_token_credentials; // Private constructor for refresh token credentials from an already parsed @@ -103,7 +99,7 @@ grpc_refresh_token_credentials_create_from_auth_refresh_token( // Exposed for testing only. grpc_credentials_status grpc_oauth2_token_fetcher_credentials_parse_server_response( - const struct grpc_http_response *response, - grpc_credentials_md_store **token_md, gpr_timespec *token_lifetime); + grpc_exec_ctx *exec_ctx, const struct grpc_http_response *response, + grpc_mdelem *token_md, gpr_timespec *token_lifetime); #endif /* GRPC_CORE_LIB_SECURITY_CREDENTIALS_OAUTH2_OAUTH2_CREDENTIALS_H */ diff --git a/Sources/CgRPC/src/core/lib/security/credentials/plugin/plugin_credentials.c b/Sources/CgRPC/src/core/lib/security/credentials/plugin/plugin_credentials.c index 5d950098a..73e0c23e0 100644 --- a/Sources/CgRPC/src/core/lib/security/credentials/plugin/plugin_credentials.c +++ b/Sources/CgRPC/src/core/lib/security/credentials/plugin/plugin_credentials.c @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -35,115 +20,170 @@ #include -#include "src/core/lib/surface/api_trace.h" - #include #include #include #include #include -typedef struct { - void *user_data; - grpc_credentials_metadata_cb cb; -} grpc_metadata_plugin_request; +#include "src/core/lib/slice/slice_internal.h" +#include "src/core/lib/slice/slice_string_helpers.h" +#include "src/core/lib/surface/api_trace.h" +#include "src/core/lib/surface/validate_metadata.h" -static void plugin_destruct(grpc_call_credentials *creds) { +static void plugin_destruct(grpc_exec_ctx *exec_ctx, + grpc_call_credentials *creds) { grpc_plugin_credentials *c = (grpc_plugin_credentials *)creds; + gpr_mu_destroy(&c->mu); if (c->plugin.state != NULL && c->plugin.destroy != NULL) { c->plugin.destroy(c->plugin.state); } } +static void pending_request_remove_locked( + grpc_plugin_credentials *c, + grpc_plugin_credentials_pending_request *pending_request) { + if (pending_request->prev == NULL) { + c->pending_requests = pending_request->next; + } else { + pending_request->prev->next = pending_request->next; + } + if (pending_request->next != NULL) { + pending_request->next->prev = pending_request->prev; + } +} + static void plugin_md_request_metadata_ready(void *request, const grpc_metadata *md, size_t num_md, grpc_status_code status, const char *error_details) { /* called from application code */ - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - grpc_metadata_plugin_request *r = (grpc_metadata_plugin_request *)request; - if (status != GRPC_STATUS_OK) { - if (error_details != NULL) { - gpr_log(GPR_ERROR, "Getting metadata from plugin failed with error: %s", - error_details); - } - r->cb(&exec_ctx, r->user_data, NULL, 0, GRPC_CREDENTIALS_ERROR, - error_details); - } else { - size_t i; - bool seen_illegal_header = false; - grpc_credentials_md *md_array = NULL; - for (i = 0; i < num_md; i++) { - if (!grpc_header_key_is_legal(md[i].key, strlen(md[i].key))) { - gpr_log(GPR_ERROR, "Plugin added invalid metadata key: %s", md[i].key); - seen_illegal_header = true; - break; - } else if (!grpc_is_binary_header(md[i].key, strlen(md[i].key)) && - !grpc_header_nonbin_value_is_legal(md[i].value, - md[i].value_length)) { - gpr_log(GPR_ERROR, "Plugin added invalid metadata value."); - seen_illegal_header = true; - break; + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INITIALIZER( + GRPC_EXEC_CTX_FLAG_IS_FINISHED | GRPC_EXEC_CTX_FLAG_THREAD_RESOURCE_LOOP, + NULL, NULL); + grpc_plugin_credentials_pending_request *r = + (grpc_plugin_credentials_pending_request *)request; + // Check if the request has been cancelled. + // If not, remove it from the pending list, so that it cannot be + // cancelled out from under us. + gpr_mu_lock(&r->creds->mu); + if (!r->cancelled) pending_request_remove_locked(r->creds, r); + gpr_mu_unlock(&r->creds->mu); + grpc_call_credentials_unref(&exec_ctx, &r->creds->base); + // If it has not been cancelled, process it. + if (!r->cancelled) { + if (status != GRPC_STATUS_OK) { + char *msg; + gpr_asprintf(&msg, "Getting metadata from plugin failed with error: %s", + error_details); + GRPC_CLOSURE_SCHED(&exec_ctx, r->on_request_metadata, + GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg)); + gpr_free(msg); + } else { + bool seen_illegal_header = false; + for (size_t i = 0; i < num_md; ++i) { + if (!GRPC_LOG_IF_ERROR("validate_metadata_from_plugin", + grpc_validate_header_key_is_legal(md[i].key))) { + seen_illegal_header = true; + break; + } else if (!grpc_is_binary_header(md[i].key) && + !GRPC_LOG_IF_ERROR( + "validate_metadata_from_plugin", + grpc_validate_header_nonbin_value_is_legal( + md[i].value))) { + gpr_log(GPR_ERROR, "Plugin added invalid metadata value."); + seen_illegal_header = true; + break; + } } - } - if (seen_illegal_header) { - r->cb(&exec_ctx, r->user_data, NULL, 0, GRPC_CREDENTIALS_ERROR, - "Illegal metadata"); - } else if (num_md > 0) { - md_array = gpr_malloc(num_md * sizeof(grpc_credentials_md)); - for (i = 0; i < num_md; i++) { - md_array[i].key = grpc_slice_from_copied_string(md[i].key); - md_array[i].value = - grpc_slice_from_copied_buffer(md[i].value, md[i].value_length); - } - r->cb(&exec_ctx, r->user_data, md_array, num_md, GRPC_CREDENTIALS_OK, - NULL); - for (i = 0; i < num_md; i++) { - grpc_slice_unref(md_array[i].key); - grpc_slice_unref(md_array[i].value); + if (seen_illegal_header) { + GRPC_CLOSURE_SCHED( + &exec_ctx, r->on_request_metadata, + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Illegal metadata")); + } else { + for (size_t i = 0; i < num_md; ++i) { + grpc_mdelem mdelem = grpc_mdelem_from_slices( + &exec_ctx, grpc_slice_ref_internal(md[i].key), + grpc_slice_ref_internal(md[i].value)); + grpc_credentials_mdelem_array_add(r->md_array, mdelem); + GRPC_MDELEM_UNREF(&exec_ctx, mdelem); + } + GRPC_CLOSURE_SCHED(&exec_ctx, r->on_request_metadata, GRPC_ERROR_NONE); } - gpr_free(md_array); - } else if (num_md == 0) { - r->cb(&exec_ctx, r->user_data, NULL, 0, GRPC_CREDENTIALS_OK, NULL); } } gpr_free(r); grpc_exec_ctx_finish(&exec_ctx); } -static void plugin_get_request_metadata(grpc_exec_ctx *exec_ctx, +static bool plugin_get_request_metadata(grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds, grpc_polling_entity *pollent, grpc_auth_metadata_context context, - grpc_credentials_metadata_cb cb, - void *user_data) { + grpc_credentials_mdelem_array *md_array, + grpc_closure *on_request_metadata, + grpc_error **error) { grpc_plugin_credentials *c = (grpc_plugin_credentials *)creds; if (c->plugin.get_metadata != NULL) { - grpc_metadata_plugin_request *request = gpr_malloc(sizeof(*request)); - memset(request, 0, sizeof(*request)); - request->user_data = user_data; - request->cb = cb; + // Create pending_request object. + grpc_plugin_credentials_pending_request *pending_request = + (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; + // Add it to the pending list. + gpr_mu_lock(&c->mu); + if (c->pending_requests != NULL) { + c->pending_requests->prev = pending_request; + } + pending_request->next = c->pending_requests; + c->pending_requests = pending_request; + gpr_mu_unlock(&c->mu); + // Invoke the plugin. The callback holds a ref to us. + grpc_call_credentials_ref(creds); c->plugin.get_metadata(c->plugin.state, context, - plugin_md_request_metadata_ready, request); - } else { - cb(exec_ctx, user_data, NULL, 0, GRPC_CREDENTIALS_OK, NULL); + plugin_md_request_metadata_ready, pending_request); + return false; + } + return true; +} + +static void plugin_cancel_get_request_metadata( + grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds, + grpc_credentials_mdelem_array *md_array, grpc_error *error) { + grpc_plugin_credentials *c = (grpc_plugin_credentials *)creds; + gpr_mu_lock(&c->mu); + for (grpc_plugin_credentials_pending_request *pending_request = + c->pending_requests; + pending_request != NULL; pending_request = pending_request->next) { + if (pending_request->md_array == md_array) { + pending_request->cancelled = true; + GRPC_CLOSURE_SCHED(exec_ctx, pending_request->on_request_metadata, + GRPC_ERROR_REF(error)); + pending_request_remove_locked(c, pending_request); + break; + } } + gpr_mu_unlock(&c->mu); + GRPC_ERROR_UNREF(error); } static grpc_call_credentials_vtable plugin_vtable = { - plugin_destruct, plugin_get_request_metadata}; + plugin_destruct, plugin_get_request_metadata, + plugin_cancel_get_request_metadata}; grpc_call_credentials *grpc_metadata_credentials_create_from_plugin( grpc_metadata_credentials_plugin plugin, void *reserved) { - grpc_plugin_credentials *c = gpr_malloc(sizeof(*c)); + grpc_plugin_credentials *c = gpr_zalloc(sizeof(*c)); GRPC_API_TRACE("grpc_metadata_credentials_create_from_plugin(reserved=%p)", 1, (reserved)); GPR_ASSERT(reserved == NULL); - memset(c, 0, sizeof(*c)); 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; } diff --git a/Sources/CgRPC/src/core/lib/security/credentials/plugin/plugin_credentials.h b/Sources/CgRPC/src/core/lib/security/credentials/plugin/plugin_credentials.h index 89073cb3d..57266d589 100644 --- a/Sources/CgRPC/src/core/lib/security/credentials/plugin/plugin_credentials.h +++ b/Sources/CgRPC/src/core/lib/security/credentials/plugin/plugin_credentials.h @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -36,10 +21,22 @@ #include "src/core/lib/security/credentials/credentials.h" -typedef struct { +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; - grpc_credentials_md_store *plugin_md; + gpr_mu mu; + grpc_plugin_credentials_pending_request *pending_requests; } grpc_plugin_credentials; #endif /* GRPC_CORE_LIB_SECURITY_CREDENTIALS_PLUGIN_PLUGIN_CREDENTIALS_H */ diff --git a/Sources/CgRPC/src/core/lib/security/credentials/ssl/ssl_credentials.c b/Sources/CgRPC/src/core/lib/security/credentials/ssl/ssl_credentials.c index 0dc1fccec..006db1ec7 100644 --- a/Sources/CgRPC/src/core/lib/security/credentials/ssl/ssl_credentials.c +++ b/Sources/CgRPC/src/core/lib/security/credentials/ssl/ssl_credentials.c @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -36,45 +21,39 @@ #include #include "src/core/lib/channel/channel_args.h" -#include "src/core/lib/channel/http_client_filter.h" #include "src/core/lib/surface/api_trace.h" #include #include +#include // -// Utils +// SSL Channel Credentials. // -static void ssl_copy_key_material(const char *input, unsigned char **output, - size_t *output_size) { - *output_size = strlen(input); - *output = gpr_malloc(*output_size); - memcpy(*output, input, *output_size); +static void ssl_config_pem_key_cert_pair_destroy( + tsi_ssl_pem_key_cert_pair *kp) { + if (kp == NULL) return; + gpr_free((void *)kp->private_key); + gpr_free((void *)kp->cert_chain); } -// -// SSL Channel Credentials. -// - -static void ssl_destruct(grpc_channel_credentials *creds) { +static void ssl_destruct(grpc_exec_ctx *exec_ctx, + grpc_channel_credentials *creds) { grpc_ssl_credentials *c = (grpc_ssl_credentials *)creds; - if (c->config.pem_root_certs != NULL) gpr_free(c->config.pem_root_certs); - if (c->config.pem_private_key != NULL) gpr_free(c->config.pem_private_key); - if (c->config.pem_cert_chain != NULL) gpr_free(c->config.pem_cert_chain); + gpr_free(c->config.pem_root_certs); + ssl_config_pem_key_cert_pair_destroy(&c->config.pem_key_cert_pair); } static grpc_security_status ssl_create_security_connector( - grpc_channel_credentials *creds, grpc_call_credentials *call_creds, - const char *target, const grpc_channel_args *args, - grpc_channel_security_connector **sc, grpc_channel_args **new_args) { + grpc_exec_ctx *exec_ctx, grpc_channel_credentials *creds, + 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 = (grpc_ssl_credentials *)creds; grpc_security_status status = GRPC_SECURITY_OK; - size_t i = 0; const char *overridden_target_name = NULL; - grpc_arg new_arg; - - for (i = 0; args && i < args->num_args; i++) { + for (size_t i = 0; args && i < args->num_args; i++) { grpc_arg *arg = &args->args[i]; if (strcmp(arg->key, GRPC_SSL_TARGET_NAME_OVERRIDE_ARG) == 0 && arg->type == GRPC_ARG_STRING) { @@ -83,13 +62,12 @@ static grpc_security_status ssl_create_security_connector( } } status = grpc_ssl_channel_security_connector_create( - call_creds, &c->config, target, overridden_target_name, sc); + exec_ctx, call_creds, &c->config, target, overridden_target_name, sc); if (status != GRPC_SECURITY_OK) { return status; } - new_arg.type = GRPC_ARG_STRING; - new_arg.key = GRPC_ARG_HTTP2_SCHEME; - new_arg.value.string = "https"; + grpc_arg new_arg = + grpc_channel_arg_string_create(GRPC_ARG_HTTP2_SCHEME, "https"); *new_args = grpc_channel_args_copy_and_add(args, &new_arg, 1); return status; } @@ -101,32 +79,28 @@ static void ssl_build_config(const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pair, grpc_ssl_config *config) { if (pem_root_certs != NULL) { - ssl_copy_key_material(pem_root_certs, &config->pem_root_certs, - &config->pem_root_certs_size); + config->pem_root_certs = gpr_strdup(pem_root_certs); } if (pem_key_cert_pair != NULL) { GPR_ASSERT(pem_key_cert_pair->private_key != NULL); GPR_ASSERT(pem_key_cert_pair->cert_chain != NULL); - ssl_copy_key_material(pem_key_cert_pair->private_key, - &config->pem_private_key, - &config->pem_private_key_size); - ssl_copy_key_material(pem_key_cert_pair->cert_chain, - &config->pem_cert_chain, - &config->pem_cert_chain_size); + config->pem_key_cert_pair.cert_chain = + gpr_strdup(pem_key_cert_pair->cert_chain); + config->pem_key_cert_pair.private_key = + gpr_strdup(pem_key_cert_pair->private_key); } } grpc_channel_credentials *grpc_ssl_credentials_create( const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pair, void *reserved) { - grpc_ssl_credentials *c = gpr_malloc(sizeof(grpc_ssl_credentials)); + grpc_ssl_credentials *c = gpr_zalloc(sizeof(grpc_ssl_credentials)); GRPC_API_TRACE( "grpc_ssl_credentials_create(pem_root_certs=%s, " "pem_key_cert_pair=%p, " "reserved=%p)", 3, (pem_root_certs, pem_key_cert_pair, reserved)); GPR_ASSERT(reserved == NULL); - memset(c, 0, sizeof(grpc_ssl_credentials)); c->base.type = GRPC_CHANNEL_CREDENTIALS_TYPE_SSL; c->base.vtable = &ssl_vtable; gpr_ref_init(&c->base.refcount, 1); @@ -138,32 +112,22 @@ grpc_channel_credentials *grpc_ssl_credentials_create( // SSL Server Credentials. // -static void ssl_server_destruct(grpc_server_credentials *creds) { +static void ssl_server_destruct(grpc_exec_ctx *exec_ctx, + grpc_server_credentials *creds) { grpc_ssl_server_credentials *c = (grpc_ssl_server_credentials *)creds; size_t i; for (i = 0; i < c->config.num_key_cert_pairs; i++) { - if (c->config.pem_private_keys[i] != NULL) { - gpr_free(c->config.pem_private_keys[i]); - } - if (c->config.pem_cert_chains[i] != NULL) { - gpr_free(c->config.pem_cert_chains[i]); - } - } - if (c->config.pem_private_keys != NULL) gpr_free(c->config.pem_private_keys); - if (c->config.pem_private_keys_sizes != NULL) { - gpr_free(c->config.pem_private_keys_sizes); - } - if (c->config.pem_cert_chains != NULL) gpr_free(c->config.pem_cert_chains); - if (c->config.pem_cert_chains_sizes != NULL) { - gpr_free(c->config.pem_cert_chains_sizes); + ssl_config_pem_key_cert_pair_destroy(&c->config.pem_key_cert_pairs[i]); } - if (c->config.pem_root_certs != NULL) gpr_free(c->config.pem_root_certs); + gpr_free(c->config.pem_key_cert_pairs); + gpr_free(c->config.pem_root_certs); } static grpc_security_status ssl_server_create_security_connector( - grpc_server_credentials *creds, grpc_server_security_connector **sc) { + grpc_exec_ctx *exec_ctx, grpc_server_credentials *creds, + grpc_server_security_connector **sc) { grpc_ssl_server_credentials *c = (grpc_ssl_server_credentials *)creds; - return grpc_ssl_server_security_connector_create(&c->config, sc); + return grpc_ssl_server_security_connector_create(exec_ctx, &c->config, sc); } static grpc_server_credentials_vtable ssl_server_vtable = { @@ -177,30 +141,21 @@ static void ssl_build_server_config( size_t i; config->client_certificate_request = client_certificate_request; if (pem_root_certs != NULL) { - ssl_copy_key_material(pem_root_certs, &config->pem_root_certs, - &config->pem_root_certs_size); + config->pem_root_certs = gpr_strdup(pem_root_certs); } if (num_key_cert_pairs > 0) { GPR_ASSERT(pem_key_cert_pairs != NULL); - config->pem_private_keys = - gpr_malloc(num_key_cert_pairs * sizeof(unsigned char *)); - config->pem_cert_chains = - gpr_malloc(num_key_cert_pairs * sizeof(unsigned char *)); - config->pem_private_keys_sizes = - gpr_malloc(num_key_cert_pairs * sizeof(size_t)); - config->pem_cert_chains_sizes = - gpr_malloc(num_key_cert_pairs * sizeof(size_t)); + config->pem_key_cert_pairs = + gpr_zalloc(num_key_cert_pairs * sizeof(tsi_ssl_pem_key_cert_pair)); } config->num_key_cert_pairs = num_key_cert_pairs; for (i = 0; i < num_key_cert_pairs; i++) { GPR_ASSERT(pem_key_cert_pairs[i].private_key != NULL); GPR_ASSERT(pem_key_cert_pairs[i].cert_chain != NULL); - ssl_copy_key_material(pem_key_cert_pairs[i].private_key, - &config->pem_private_keys[i], - &config->pem_private_keys_sizes[i]); - ssl_copy_key_material(pem_key_cert_pairs[i].cert_chain, - &config->pem_cert_chains[i], - &config->pem_cert_chains_sizes[i]); + config->pem_key_cert_pairs[i].cert_chain = + gpr_strdup(pem_key_cert_pairs[i].cert_chain); + config->pem_key_cert_pairs[i].private_key = + gpr_strdup(pem_key_cert_pairs[i].private_key); } } @@ -221,7 +176,7 @@ grpc_server_credentials *grpc_ssl_server_credentials_create_ex( grpc_ssl_client_certificate_request_type client_certificate_request, void *reserved) { grpc_ssl_server_credentials *c = - gpr_malloc(sizeof(grpc_ssl_server_credentials)); + gpr_zalloc(sizeof(grpc_ssl_server_credentials)); GRPC_API_TRACE( "grpc_ssl_server_credentials_create_ex(" "pem_root_certs=%s, pem_key_cert_pairs=%p, num_key_cert_pairs=%lu, " @@ -229,7 +184,6 @@ grpc_server_credentials *grpc_ssl_server_credentials_create_ex( 5, (pem_root_certs, pem_key_cert_pairs, (unsigned long)num_key_cert_pairs, client_certificate_request, reserved)); GPR_ASSERT(reserved == NULL); - memset(c, 0, 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; diff --git a/Sources/CgRPC/src/core/lib/security/credentials/ssl/ssl_credentials.h b/Sources/CgRPC/src/core/lib/security/credentials/ssl/ssl_credentials.h index f23dbdbe4..b43c656cd 100644 --- a/Sources/CgRPC/src/core/lib/security/credentials/ssl/ssl_credentials.h +++ b/Sources/CgRPC/src/core/lib/security/credentials/ssl/ssl_credentials.h @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 GRPC_CORE_LIB_SECURITY_CREDENTIALS_SSL_SSL_CREDENTIALS_H diff --git a/Sources/CgRPC/src/core/lib/security/transport/auth_filters.h b/Sources/CgRPC/src/core/lib/security/transport/auth_filters.h index f688d4ed2..bd5902a12 100644 --- a/Sources/CgRPC/src/core/lib/security/transport/auth_filters.h +++ b/Sources/CgRPC/src/core/lib/security/transport/auth_filters.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/security/transport/client_auth_filter.c b/Sources/CgRPC/src/core/lib/security/transport/client_auth_filter.c index da897296e..531a88434 100644 --- a/Sources/CgRPC/src/core/lib/security/transport/client_auth_filter.c +++ b/Sources/CgRPC/src/core/lib/security/transport/client_auth_filter.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -44,6 +29,8 @@ #include "src/core/lib/security/context/security_context.h" #include "src/core/lib/security/credentials/credentials.h" #include "src/core/lib/security/transport/security_connector.h" +#include "src/core/lib/slice/slice_internal.h" +#include "src/core/lib/slice/slice_string_helpers.h" #include "src/core/lib/support/string.h" #include "src/core/lib/surface/call.h" #include "src/core/lib/transport/static_metadata.h" @@ -53,17 +40,26 @@ /* We can have a per-call credentials. */ typedef struct { grpc_call_credentials *creds; - grpc_mdstr *host; - grpc_mdstr *method; + bool have_host; + bool have_method; + grpc_slice host; + grpc_slice method; /* pollset{_set} bound to this call; if we need to make external network requests, they should be done under a pollset added to this pollset_set so that work can progress when this call wants work to progress */ grpc_polling_entity *pollent; - grpc_transport_stream_op op; - uint8_t security_context_set; + gpr_atm security_context_set; + gpr_mu security_context_mu; + grpc_credentials_mdelem_array md_array; grpc_linked_mdelem md_links[MAX_CREDENTIALS_METADATA_COUNT]; grpc_auth_metadata_context auth_md_context; + grpc_closure closure; + // Either 0 (no cancellation and no async operation in flight), + // a grpc_closure* (if the lowest bit is 0), + // or a grpc_error* (if the lowest bit is 1). + gpr_atm cancellation_state; + grpc_closure cancel_closure; } call_data; /* We can have a per-channel credentials. */ @@ -72,6 +68,43 @@ typedef struct { grpc_auth_context *auth_context; } channel_data; +static void decode_cancel_state(gpr_atm cancel_state, grpc_closure **func, + grpc_error **error) { + // If the lowest bit is 1, the value is a grpc_error*. + // Otherwise, if non-zdero, the value is a grpc_closure*. + if (cancel_state & 1) { + *error = (grpc_error *)(cancel_state & ~(gpr_atm)1); + } else if (cancel_state != 0) { + *func = (grpc_closure *)cancel_state; + } +} + +static gpr_atm encode_cancel_state_error(grpc_error *error) { + // Set the lowest bit to 1 to indicate that it's an error. + return (gpr_atm)1 | (gpr_atm)error; +} + +// Returns an error if the call has been cancelled. Otherwise, sets the +// cancellation function to be called upon cancellation. +static grpc_error *set_cancel_func(grpc_call_element *elem, + grpc_iomgr_cb_func func) { + call_data *calld = (call_data *)elem->call_data; + // Decode original state. + gpr_atm original_state = gpr_atm_acq_load(&calld->cancellation_state); + grpc_error *original_error = GRPC_ERROR_NONE; + grpc_closure *original_func = NULL; + decode_cancel_state(original_state, &original_func, &original_error); + // If error is set, return it. + if (original_error != GRPC_ERROR_NONE) return GRPC_ERROR_REF(original_error); + // Otherwise, store func. + GRPC_CLOSURE_INIT(&calld->cancel_closure, func, elem, + grpc_schedule_on_exec_ctx); + GPR_ASSERT(((gpr_atm)&calld->cancel_closure & (gpr_atm)1) == 0); + gpr_atm_rel_store(&calld->cancellation_state, + (gpr_atm)&calld->cancel_closure); + return GRPC_ERROR_NONE; +} + static void reset_auth_metadata_context( grpc_auth_metadata_context *auth_md_context) { if (auth_md_context->service_url != NULL) { @@ -88,49 +121,46 @@ static void reset_auth_metadata_context( auth_md_context->channel_auth_context = NULL; } -static void bubble_up_error(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, - grpc_status_code status, const char *error_msg) { - call_data *calld = elem->call_data; - gpr_log(GPR_ERROR, "Client side authentication failure: %s", error_msg); - grpc_slice error_slice = grpc_slice_from_copied_string(error_msg); - grpc_transport_stream_op_add_close(&calld->op, status, &error_slice); - grpc_call_next_op(exec_ctx, elem, &calld->op); +static void add_error(grpc_error **combined, grpc_error *error) { + if (error == GRPC_ERROR_NONE) return; + if (*combined == GRPC_ERROR_NONE) { + *combined = GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "Client auth metadata plugin error"); + } + *combined = grpc_error_add_child(*combined, error); } -static void on_credentials_metadata(grpc_exec_ctx *exec_ctx, void *user_data, - grpc_credentials_md *md_elems, - size_t num_md, - grpc_credentials_status status, - const char *error_details) { - grpc_call_element *elem = (grpc_call_element *)user_data; +static void on_credentials_metadata(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *input_error) { + grpc_transport_stream_op_batch *batch = (grpc_transport_stream_op_batch *)arg; + grpc_call_element *elem = batch->handler_private.extra_arg; call_data *calld = elem->call_data; - grpc_transport_stream_op *op = &calld->op; - grpc_metadata_batch *mdb; - size_t i; reset_auth_metadata_context(&calld->auth_md_context); - if (status != GRPC_CREDENTIALS_OK) { - bubble_up_error(exec_ctx, elem, GRPC_STATUS_UNAUTHENTICATED, - (error_details != NULL && strlen(error_details) > 0) - ? error_details - : "Credentials failed to get metadata."); - return; + grpc_error *error = GRPC_ERROR_REF(input_error); + if (error == GRPC_ERROR_NONE) { + GPR_ASSERT(calld->md_array.size <= MAX_CREDENTIALS_METADATA_COUNT); + GPR_ASSERT(batch->send_initial_metadata); + grpc_metadata_batch *mdb = + batch->payload->send_initial_metadata.send_initial_metadata; + for (size_t i = 0; i < calld->md_array.size; ++i) { + add_error(&error, grpc_metadata_batch_add_tail( + exec_ctx, mdb, &calld->md_links[i], + GRPC_MDELEM_REF(calld->md_array.md[i]))); + } } - GPR_ASSERT(num_md <= MAX_CREDENTIALS_METADATA_COUNT); - GPR_ASSERT(op->send_initial_metadata != NULL); - mdb = op->send_initial_metadata; - for (i = 0; i < num_md; i++) { - grpc_metadata_batch_add_tail( - mdb, &calld->md_links[i], - grpc_mdelem_from_slices(grpc_slice_ref(md_elems[i].key), - grpc_slice_ref(md_elems[i].value))); + if (error == GRPC_ERROR_NONE) { + grpc_call_next_op(exec_ctx, elem, batch); + } else { + error = grpc_error_set_int(error, GRPC_ERROR_INT_GRPC_STATUS, + GRPC_STATUS_UNAUTHENTICATED); + grpc_transport_stream_op_batch_finish_with_failure(exec_ctx, batch, error); } - grpc_call_next_op(exec_ctx, elem, op); } void build_auth_metadata_context(grpc_security_connector *sc, grpc_auth_context *auth_context, call_data *calld) { - char *service = gpr_strdup(grpc_mdstr_as_c_string(calld->method)); + char *service = grpc_slice_to_c_string(calld->method); char *last_slash = strrchr(service, '/'); char *method_name = NULL; char *service_url = NULL; @@ -146,30 +176,41 @@ void build_auth_metadata_context(grpc_security_connector *sc, method_name = gpr_strdup(last_slash + 1); } if (method_name == NULL) method_name = gpr_strdup(""); + char *host = grpc_slice_to_c_string(calld->host); gpr_asprintf(&service_url, "%s://%s%s", - sc->url_scheme == NULL ? "" : sc->url_scheme, - grpc_mdstr_as_c_string(calld->host), service); + sc->url_scheme == NULL ? "" : sc->url_scheme, host, service); calld->auth_md_context.service_url = service_url; calld->auth_md_context.method_name = method_name; calld->auth_md_context.channel_auth_context = GRPC_AUTH_CONTEXT_REF(auth_context, "grpc_auth_metadata_context"); gpr_free(service); + gpr_free(host); +} + +static void cancel_get_request_metadata(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error) { + grpc_call_element *elem = (grpc_call_element *)arg; + call_data *calld = (call_data *)elem->call_data; + grpc_call_credentials_cancel_get_request_metadata( + exec_ctx, calld->creds, &calld->md_array, GRPC_ERROR_REF(error)); } static void send_security_metadata(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, - grpc_transport_stream_op *op) { + grpc_transport_stream_op_batch *batch) { call_data *calld = elem->call_data; channel_data *chand = elem->channel_data; grpc_client_security_context *ctx = - (grpc_client_security_context *)op->context[GRPC_CONTEXT_SECURITY].value; + (grpc_client_security_context *)batch->payload + ->context[GRPC_CONTEXT_SECURITY] + .value; grpc_call_credentials *channel_call_creds = chand->security_connector->request_metadata_creds; int call_creds_has_md = (ctx != NULL) && (ctx->creds != NULL); if (channel_call_creds == NULL && !call_creds_has_md) { /* Skip sending metadata altogether. */ - grpc_call_next_op(exec_ctx, elem, op); + grpc_call_next_op(exec_ctx, elem, batch); return; } @@ -177,8 +218,12 @@ static void send_security_metadata(grpc_exec_ctx *exec_ctx, calld->creds = grpc_composite_call_credentials_create(channel_call_creds, ctx->creds, NULL); if (calld->creds == NULL) { - bubble_up_error(exec_ctx, elem, GRPC_STATUS_UNAUTHENTICATED, - "Incompatible credentials set on channel and call."); + grpc_transport_stream_op_batch_finish_with_failure( + exec_ctx, batch, + grpc_error_set_int( + GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "Incompatible credentials set on channel and call."), + GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAUTHENTICATED)); return; } } else { @@ -188,95 +233,175 @@ static void send_security_metadata(grpc_exec_ctx *exec_ctx, build_auth_metadata_context(&chand->security_connector->base, chand->auth_context, calld); - calld->op = *op; /* Copy op (originates from the caller's stack). */ + + grpc_error *cancel_error = set_cancel_func(elem, cancel_get_request_metadata); + if (cancel_error != GRPC_ERROR_NONE) { + grpc_transport_stream_op_batch_finish_with_failure(exec_ctx, batch, + cancel_error); + return; + } GPR_ASSERT(calld->pollent != NULL); - grpc_call_credentials_get_request_metadata( - exec_ctx, calld->creds, calld->pollent, calld->auth_md_context, - on_credentials_metadata, elem); + GRPC_CLOSURE_INIT(&calld->closure, on_credentials_metadata, batch, + grpc_schedule_on_exec_ctx); + grpc_error *error = GRPC_ERROR_NONE; + if (grpc_call_credentials_get_request_metadata( + exec_ctx, calld->creds, calld->pollent, calld->auth_md_context, + &calld->md_array, &calld->closure, &error)) { + // Synchronous return; invoke on_credentials_metadata() directly. + on_credentials_metadata(exec_ctx, batch, error); + GRPC_ERROR_UNREF(error); + } } -static void on_host_checked(grpc_exec_ctx *exec_ctx, void *user_data, - grpc_security_status status) { - grpc_call_element *elem = (grpc_call_element *)user_data; +static void on_host_checked(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error) { + grpc_transport_stream_op_batch *batch = (grpc_transport_stream_op_batch *)arg; + grpc_call_element *elem = batch->handler_private.extra_arg; call_data *calld = elem->call_data; - if (status == GRPC_SECURITY_OK) { - send_security_metadata(exec_ctx, elem, &calld->op); + if (error == GRPC_ERROR_NONE) { + send_security_metadata(exec_ctx, elem, batch); } else { char *error_msg; + char *host = grpc_slice_to_c_string(calld->host); gpr_asprintf(&error_msg, "Invalid host %s set in :authority metadata.", - grpc_mdstr_as_c_string(calld->host)); - bubble_up_error(exec_ctx, elem, GRPC_STATUS_UNAUTHENTICATED, error_msg); + host); + gpr_free(host); + grpc_transport_stream_op_batch_finish_with_failure( + exec_ctx, batch, + grpc_error_set_int(GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_msg), + GRPC_ERROR_INT_GRPC_STATUS, + GRPC_STATUS_UNAUTHENTICATED)); gpr_free(error_msg); } } -/* Called either: - - in response to an API call (or similar) from above, to send something - - a network event (or similar) from below, to receive something - op contains type and call direction information, in addition to the data - that is being sent or received. */ -static void auth_start_transport_op(grpc_exec_ctx *exec_ctx, - grpc_call_element *elem, - grpc_transport_stream_op *op) { - GPR_TIMER_BEGIN("auth_start_transport_op", 0); +static void cancel_check_call_host(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error) { + grpc_call_element *elem = (grpc_call_element *)arg; + call_data *calld = (call_data *)elem->call_data; + channel_data *chand = (channel_data *)elem->channel_data; + grpc_channel_security_connector_cancel_check_call_host( + exec_ctx, chand->security_connector, &calld->closure, + GRPC_ERROR_REF(error)); +} + +static void auth_start_transport_stream_op_batch( + grpc_exec_ctx *exec_ctx, grpc_call_element *elem, + grpc_transport_stream_op_batch *batch) { + GPR_TIMER_BEGIN("auth_start_transport_stream_op_batch", 0); /* grab pointers to our data from the call element */ call_data *calld = elem->call_data; channel_data *chand = elem->channel_data; - grpc_linked_mdelem *l; - grpc_client_security_context *sec_ctx = NULL; - - if (calld->security_context_set == 0 && op->cancel_error == GRPC_ERROR_NONE) { - calld->security_context_set = 1; - GPR_ASSERT(op->context); - if (op->context[GRPC_CONTEXT_SECURITY].value == NULL) { - op->context[GRPC_CONTEXT_SECURITY].value = - grpc_client_security_context_create(); - op->context[GRPC_CONTEXT_SECURITY].destroy = - grpc_client_security_context_destroy; + + if (batch->cancel_stream) { + while (true) { + // Decode the original cancellation state. + gpr_atm original_state = gpr_atm_acq_load(&calld->cancellation_state); + grpc_error *cancel_error = GRPC_ERROR_NONE; + grpc_closure *func = NULL; + decode_cancel_state(original_state, &func, &cancel_error); + // If we had already set a cancellation error, there's nothing + // more to do. + if (cancel_error != GRPC_ERROR_NONE) break; + // If there's a cancel func, call it. + // Note that even if the cancel func has been changed by some + // other thread between when we decoded it and now, it will just + // be a no-op. + cancel_error = GRPC_ERROR_REF(batch->payload->cancel_stream.cancel_error); + if (func != NULL) { + GRPC_CLOSURE_SCHED(exec_ctx, func, GRPC_ERROR_REF(cancel_error)); + } + // Encode the new error into cancellation state. + if (gpr_atm_full_cas(&calld->cancellation_state, original_state, + encode_cancel_state_error(cancel_error))) { + break; // Success. + } + // The cas failed, so try again. + } + } else { + /* double checked lock over security context to ensure it's set once */ + if (gpr_atm_acq_load(&calld->security_context_set) == 0) { + gpr_mu_lock(&calld->security_context_mu); + if (gpr_atm_acq_load(&calld->security_context_set) == 0) { + GPR_ASSERT(batch->payload->context != NULL); + if (batch->payload->context[GRPC_CONTEXT_SECURITY].value == NULL) { + batch->payload->context[GRPC_CONTEXT_SECURITY].value = + grpc_client_security_context_create(); + batch->payload->context[GRPC_CONTEXT_SECURITY].destroy = + grpc_client_security_context_destroy; + } + grpc_client_security_context *sec_ctx = + batch->payload->context[GRPC_CONTEXT_SECURITY].value; + GRPC_AUTH_CONTEXT_UNREF(sec_ctx->auth_context, "client auth filter"); + sec_ctx->auth_context = + GRPC_AUTH_CONTEXT_REF(chand->auth_context, "client_auth_filter"); + gpr_atm_rel_store(&calld->security_context_set, 1); + } + gpr_mu_unlock(&calld->security_context_mu); } - sec_ctx = op->context[GRPC_CONTEXT_SECURITY].value; - GRPC_AUTH_CONTEXT_UNREF(sec_ctx->auth_context, "client auth filter"); - sec_ctx->auth_context = - GRPC_AUTH_CONTEXT_REF(chand->auth_context, "client_auth_filter"); } - if (op->send_initial_metadata != NULL) { - for (l = op->send_initial_metadata->list.head; l != NULL; l = l->next) { - grpc_mdelem *md = l->md; + if (batch->send_initial_metadata) { + for (grpc_linked_mdelem *l = batch->payload->send_initial_metadata + .send_initial_metadata->list.head; + l != NULL; l = l->next) { + grpc_mdelem md = l->md; /* Pointer comparison is OK for md_elems created from the same context. */ - if (md->key == GRPC_MDSTR_AUTHORITY) { - if (calld->host != NULL) GRPC_MDSTR_UNREF(calld->host); - calld->host = GRPC_MDSTR_REF(md->value); - } else if (md->key == GRPC_MDSTR_PATH) { - if (calld->method != NULL) GRPC_MDSTR_UNREF(calld->method); - calld->method = GRPC_MDSTR_REF(md->value); + if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_AUTHORITY)) { + if (calld->have_host) { + grpc_slice_unref_internal(exec_ctx, calld->host); + } + calld->host = grpc_slice_ref_internal(GRPC_MDVALUE(md)); + calld->have_host = true; + } else if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_PATH)) { + if (calld->have_method) { + grpc_slice_unref_internal(exec_ctx, calld->method); + } + calld->method = grpc_slice_ref_internal(GRPC_MDVALUE(md)); + calld->have_method = true; } } - if (calld->host != NULL) { - const char *call_host = grpc_mdstr_as_c_string(calld->host); - calld->op = *op; /* Copy op (originates from the caller's stack). */ - grpc_channel_security_connector_check_call_host( - exec_ctx, chand->security_connector, call_host, chand->auth_context, - on_host_checked, elem); - GPR_TIMER_END("auth_start_transport_op", 0); + if (calld->have_host) { + grpc_error *cancel_error = set_cancel_func(elem, cancel_check_call_host); + if (cancel_error != GRPC_ERROR_NONE) { + grpc_transport_stream_op_batch_finish_with_failure(exec_ctx, batch, + cancel_error); + } else { + char *call_host = grpc_slice_to_c_string(calld->host); + batch->handler_private.extra_arg = elem; + grpc_error *error = GRPC_ERROR_NONE; + if (grpc_channel_security_connector_check_call_host( + exec_ctx, chand->security_connector, call_host, + chand->auth_context, + GRPC_CLOSURE_INIT(&calld->closure, on_host_checked, batch, + grpc_schedule_on_exec_ctx), + &error)) { + // Synchronous return; invoke on_host_checked() directly. + on_host_checked(exec_ctx, batch, error); + GRPC_ERROR_UNREF(error); + } + gpr_free(call_host); + } + GPR_TIMER_END("auth_start_transport_stream_op_batch", 0); return; /* early exit */ } } /* pass control down the stack */ - grpc_call_next_op(exec_ctx, elem, op); - GPR_TIMER_END("auth_start_transport_op", 0); + grpc_call_next_op(exec_ctx, elem, batch); + GPR_TIMER_END("auth_start_transport_stream_op_batch", 0); } /* Constructor for call_data */ static grpc_error *init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, - grpc_call_element_args *args) { + const grpc_call_element_args *args) { call_data *calld = elem->call_data; memset(calld, 0, sizeof(*calld)); + gpr_mu_init(&calld->security_context_mu); return GRPC_ERROR_NONE; } @@ -290,16 +415,23 @@ static void set_pollset_or_pollset_set(grpc_exec_ctx *exec_ctx, /* Destructor for call_data */ static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, const grpc_call_final_info *final_info, - void *ignored) { + grpc_closure *ignored) { call_data *calld = elem->call_data; - grpc_call_credentials_unref(calld->creds); - if (calld->host != NULL) { - GRPC_MDSTR_UNREF(calld->host); + grpc_credentials_mdelem_array_destroy(exec_ctx, &calld->md_array); + grpc_call_credentials_unref(exec_ctx, calld->creds); + if (calld->have_host) { + grpc_slice_unref_internal(exec_ctx, calld->host); } - if (calld->method != NULL) { - GRPC_MDSTR_UNREF(calld->method); + if (calld->have_method) { + grpc_slice_unref_internal(exec_ctx, calld->method); } reset_auth_metadata_context(&calld->auth_md_context); + gpr_mu_destroy(&calld->security_context_mu); + gpr_atm cancel_state = gpr_atm_acq_load(&calld->cancellation_state); + grpc_error *cancel_error = GRPC_ERROR_NONE; + grpc_closure *cancel_func = NULL; + decode_cancel_state(cancel_state, &cancel_func, &cancel_error); + GRPC_ERROR_UNREF(cancel_error); } /* Constructor for channel_data */ @@ -307,9 +439,17 @@ static grpc_error *init_channel_elem(grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, grpc_channel_element_args *args) { grpc_security_connector *sc = - grpc_find_security_connector_in_args(args->channel_args); + grpc_security_connector_find_in_args(args->channel_args); + if (sc == NULL) { + return GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "Security connector missing from client auth filter args"); + } grpc_auth_context *auth_context = grpc_find_auth_context_in_args(args->channel_args); + if (auth_context == NULL) { + 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 = elem->channel_data; @@ -318,8 +458,6 @@ static grpc_error *init_channel_elem(grpc_exec_ctx *exec_ctx, handle the case that there's no 'next' filter to call on the up or down path */ GPR_ASSERT(!args->is_last); - GPR_ASSERT(sc != NULL); - GPR_ASSERT(auth_context != NULL); /* initialize members */ chand->security_connector = @@ -337,13 +475,21 @@ static void destroy_channel_elem(grpc_exec_ctx *exec_ctx, channel_data *chand = elem->channel_data; grpc_channel_security_connector *sc = chand->security_connector; if (sc != NULL) { - GRPC_SECURITY_CONNECTOR_UNREF(&sc->base, "client_auth_filter"); + GRPC_SECURITY_CONNECTOR_UNREF(exec_ctx, &sc->base, "client_auth_filter"); } GRPC_AUTH_CONTEXT_UNREF(chand->auth_context, "client_auth_filter"); } const grpc_channel_filter grpc_client_auth_filter = { - auth_start_transport_op, grpc_channel_next_op, sizeof(call_data), - init_call_elem, set_pollset_or_pollset_set, destroy_call_elem, - sizeof(channel_data), init_channel_elem, destroy_channel_elem, - grpc_call_next_get_peer, grpc_channel_next_get_info, "client-auth"}; + auth_start_transport_stream_op_batch, + grpc_channel_next_op, + sizeof(call_data), + init_call_elem, + set_pollset_or_pollset_set, + destroy_call_elem, + sizeof(channel_data), + init_channel_elem, + destroy_channel_elem, + grpc_call_next_get_peer, + grpc_channel_next_get_info, + "client-auth"}; diff --git a/Sources/CgRPC/src/core/lib/security/transport/lb_targets_info.c b/Sources/CgRPC/src/core/lib/security/transport/lb_targets_info.c new file mode 100644 index 000000000..5583a4e0f --- /dev/null +++ b/Sources/CgRPC/src/core/lib/security/transport/lb_targets_info.c @@ -0,0 +1,54 @@ +/* + * + * Copyright 2017 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 + +#include "src/core/lib/channel/channel_args.h" +#include "src/core/lib/security/transport/lb_targets_info.h" + +/* Channel arg key for the mapping of LB server addresses to their names for + * secure naming purposes. */ +#define GRPC_ARG_LB_SECURE_NAMING_MAP "grpc.lb_secure_naming_map" + +static void *targets_info_copy(void *p) { return grpc_slice_hash_table_ref(p); } +static void targets_info_destroy(grpc_exec_ctx *exec_ctx, void *p) { + grpc_slice_hash_table_unref(exec_ctx, p); +} +static int targets_info_cmp(void *a, void *b) { + return grpc_slice_hash_table_cmp(a, b); +} +static const grpc_arg_pointer_vtable server_to_balancer_names_vtable = { + targets_info_copy, targets_info_destroy, targets_info_cmp}; + +grpc_arg grpc_lb_targets_info_create_channel_arg( + grpc_slice_hash_table *targets_info) { + return grpc_channel_arg_pointer_create(GRPC_ARG_LB_SECURE_NAMING_MAP, + targets_info, + &server_to_balancer_names_vtable); +} + +grpc_slice_hash_table *grpc_lb_targets_info_find_in_args( + const grpc_channel_args *args) { + const grpc_arg *targets_info_arg = + grpc_channel_args_find(args, GRPC_ARG_LB_SECURE_NAMING_MAP); + if (targets_info_arg != NULL) { + GPR_ASSERT(targets_info_arg->type == GRPC_ARG_POINTER); + return targets_info_arg->value.pointer.p; + } + return NULL; +} diff --git a/Sources/CgRPC/src/core/lib/security/transport/lb_targets_info.h b/Sources/CgRPC/src/core/lib/security/transport/lb_targets_info.h new file mode 100644 index 000000000..c3d685df5 --- /dev/null +++ b/Sources/CgRPC/src/core/lib/security/transport/lb_targets_info.h @@ -0,0 +1,32 @@ +/* + * + * Copyright 2017 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 GRPC_CORE_LIB_SECURITY_TRANSPORT_LB_TARGETS_INFO_H +#define GRPC_CORE_LIB_SECURITY_TRANSPORT_LB_TARGETS_INFO_H + +#include "src/core/lib/slice/slice_hash_table.h" + +/** Return a channel argument containing \a targets_info. */ +grpc_arg grpc_lb_targets_info_create_channel_arg( + grpc_slice_hash_table *targets_info); + +/** Return the instance of targets info in \a args or NULL */ +grpc_slice_hash_table *grpc_lb_targets_info_find_in_args( + const grpc_channel_args *args); + +#endif /* GRPC_CORE_LIB_SECURITY_TRANSPORT_LB_TARGETS_INFO_H */ diff --git a/Sources/CgRPC/src/core/lib/security/transport/secure_endpoint.c b/Sources/CgRPC/src/core/lib/security/transport/secure_endpoint.c index 331a8f183..5e41b94ff 100644 --- a/Sources/CgRPC/src/core/lib/security/transport/secure_endpoint.c +++ b/Sources/CgRPC/src/core/lib/security/transport/secure_endpoint.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -46,9 +31,10 @@ #include "src/core/lib/profiling/timers.h" #include "src/core/lib/security/transport/secure_endpoint.h" #include "src/core/lib/security/transport/tsi_error.h" +#include "src/core/lib/slice/slice_internal.h" #include "src/core/lib/slice/slice_string_helpers.h" #include "src/core/lib/support/string.h" -#include "src/core/lib/tsi/transport_security_interface.h" +#include "src/core/tsi/transport_security_interface.h" #define STAGING_BUFFER_SIZE 8192 @@ -74,33 +60,36 @@ typedef struct { gpr_refcount ref; } secure_endpoint; -int grpc_trace_secure_endpoint = 0; +grpc_tracer_flag grpc_trace_secure_endpoint = + GRPC_TRACER_INITIALIZER(false, "secure_endpoint"); static void destroy(grpc_exec_ctx *exec_ctx, secure_endpoint *secure_ep) { secure_endpoint *ep = secure_ep; grpc_endpoint_destroy(exec_ctx, ep->wrapped_ep); tsi_frame_protector_destroy(ep->protector); - grpc_slice_buffer_destroy(&ep->leftover_bytes); - grpc_slice_unref(ep->read_staging_buffer); - grpc_slice_unref(ep->write_staging_buffer); - grpc_slice_buffer_destroy(&ep->output_buffer); - grpc_slice_buffer_destroy(&ep->source_buffer); + grpc_slice_buffer_destroy_internal(exec_ctx, &ep->leftover_bytes); + grpc_slice_unref_internal(exec_ctx, ep->read_staging_buffer); + grpc_slice_unref_internal(exec_ctx, ep->write_staging_buffer); + grpc_slice_buffer_destroy_internal(exec_ctx, &ep->output_buffer); + grpc_slice_buffer_destroy_internal(exec_ctx, &ep->source_buffer); gpr_mu_destroy(&ep->protector_mu); gpr_free(ep); } -/*#define GRPC_SECURE_ENDPOINT_REFCOUNT_DEBUG*/ -#ifdef GRPC_SECURE_ENDPOINT_REFCOUNT_DEBUG +#ifndef NDEBUG #define SECURE_ENDPOINT_UNREF(exec_ctx, ep, reason) \ secure_endpoint_unref((exec_ctx), (ep), (reason), __FILE__, __LINE__) #define SECURE_ENDPOINT_REF(ep, reason) \ secure_endpoint_ref((ep), (reason), __FILE__, __LINE__) -static void secure_endpoint_unref(secure_endpoint *ep, - grpc_closure_list *closure_list, +static void secure_endpoint_unref(grpc_exec_ctx *exec_ctx, secure_endpoint *ep, const char *reason, const char *file, int line) { - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "SECENDP unref %p : %s %d -> %d", - ep, reason, ep->ref.count, ep->ref.count - 1); + if (GRPC_TRACER_ON(grpc_trace_secure_endpoint)) { + gpr_atm val = gpr_atm_no_barrier_load(&ep->ref.count); + gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, + "SECENDP unref %p : %s %" PRIdPTR " -> %" PRIdPTR, ep, reason, val, + val - 1); + } if (gpr_unref(&ep->ref)) { destroy(exec_ctx, ep); } @@ -108,8 +97,12 @@ static void secure_endpoint_unref(secure_endpoint *ep, static void secure_endpoint_ref(secure_endpoint *ep, const char *reason, const char *file, int line) { - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "SECENDP ref %p : %s %d -> %d", - ep, reason, ep->ref.count, ep->ref.count + 1); + if (GRPC_TRACER_ON(grpc_trace_secure_endpoint)) { + gpr_atm val = gpr_atm_no_barrier_load(&ep->ref.count); + gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, + "SECENDP ref %p : %s %" PRIdPTR " -> %" PRIdPTR, ep, reason, val, + val + 1); + } gpr_ref(&ep->ref); } #else @@ -129,14 +122,14 @@ static void secure_endpoint_ref(secure_endpoint *ep) { gpr_ref(&ep->ref); } static void flush_read_staging_buffer(secure_endpoint *ep, uint8_t **cur, uint8_t **end) { grpc_slice_buffer_add(ep->read_buffer, ep->read_staging_buffer); - ep->read_staging_buffer = grpc_slice_malloc(STAGING_BUFFER_SIZE); + ep->read_staging_buffer = GRPC_SLICE_MALLOC(STAGING_BUFFER_SIZE); *cur = GRPC_SLICE_START_PTR(ep->read_staging_buffer); *end = GRPC_SLICE_END_PTR(ep->read_staging_buffer); } static void call_read_cb(grpc_exec_ctx *exec_ctx, secure_endpoint *ep, grpc_error *error) { - if (grpc_trace_secure_endpoint) { + if (GRPC_TRACER_ON(grpc_trace_secure_endpoint)) { size_t i; for (i = 0; i < ep->read_buffer->count; i++) { char *data = grpc_dump_slice(ep->read_buffer->slices[i], @@ -146,7 +139,7 @@ static void call_read_cb(grpc_exec_ctx *exec_ctx, secure_endpoint *ep, } } ep->read_buffer = NULL; - grpc_exec_ctx_sched(exec_ctx, ep->read_cb, error, NULL); + GRPC_CLOSURE_SCHED(exec_ctx, ep->read_cb, error); SECURE_ENDPOINT_UNREF(exec_ctx, ep, "read"); } @@ -160,8 +153,8 @@ static void on_read(grpc_exec_ctx *exec_ctx, void *user_data, uint8_t *end = GRPC_SLICE_END_PTR(ep->read_staging_buffer); if (error != GRPC_ERROR_NONE) { - grpc_slice_buffer_reset_and_unref(ep->read_buffer); - call_read_cb(exec_ctx, ep, GRPC_ERROR_CREATE_REFERENCING( + grpc_slice_buffer_reset_and_unref_internal(exec_ctx, ep->read_buffer); + call_read_cb(exec_ctx, ep, GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( "Secure read failed", &error, 1)); return; } @@ -215,12 +208,14 @@ static void on_read(grpc_exec_ctx *exec_ctx, void *user_data, /* TODO(yangg) experiment with moving this block after read_cb to see if it helps latency */ - grpc_slice_buffer_reset_and_unref(&ep->source_buffer); + grpc_slice_buffer_reset_and_unref_internal(exec_ctx, &ep->source_buffer); if (result != TSI_OK) { - grpc_slice_buffer_reset_and_unref(ep->read_buffer); - call_read_cb(exec_ctx, ep, grpc_set_tsi_error_result( - GRPC_ERROR_CREATE("Unwrap failed"), result)); + grpc_slice_buffer_reset_and_unref_internal(exec_ctx, ep->read_buffer); + call_read_cb( + exec_ctx, ep, + grpc_set_tsi_error_result( + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Unwrap failed"), result)); return; } @@ -232,7 +227,7 @@ static void endpoint_read(grpc_exec_ctx *exec_ctx, grpc_endpoint *secure_ep, secure_endpoint *ep = (secure_endpoint *)secure_ep; ep->read_cb = cb; ep->read_buffer = slices; - grpc_slice_buffer_reset_and_unref(ep->read_buffer); + grpc_slice_buffer_reset_and_unref_internal(exec_ctx, ep->read_buffer); SECURE_ENDPOINT_REF(ep, "read"); if (ep->leftover_bytes.count) { @@ -249,7 +244,7 @@ static void endpoint_read(grpc_exec_ctx *exec_ctx, grpc_endpoint *secure_ep, static void flush_write_staging_buffer(secure_endpoint *ep, uint8_t **cur, uint8_t **end) { grpc_slice_buffer_add(&ep->output_buffer, ep->write_staging_buffer); - ep->write_staging_buffer = grpc_slice_malloc(STAGING_BUFFER_SIZE); + ep->write_staging_buffer = GRPC_SLICE_MALLOC(STAGING_BUFFER_SIZE); *cur = GRPC_SLICE_START_PTR(ep->write_staging_buffer); *end = GRPC_SLICE_END_PTR(ep->write_staging_buffer); } @@ -264,9 +259,9 @@ static void endpoint_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *secure_ep, uint8_t *cur = GRPC_SLICE_START_PTR(ep->write_staging_buffer); uint8_t *end = GRPC_SLICE_END_PTR(ep->write_staging_buffer); - grpc_slice_buffer_reset_and_unref(&ep->output_buffer); + grpc_slice_buffer_reset_and_unref_internal(exec_ctx, &ep->output_buffer); - if (grpc_trace_secure_endpoint) { + if (GRPC_TRACER_ON(grpc_trace_secure_endpoint)) { for (i = 0; i < slices->count; i++) { char *data = grpc_dump_slice(slices->slices[i], GPR_DUMP_HEX | GPR_DUMP_ASCII); @@ -328,11 +323,11 @@ static void endpoint_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *secure_ep, if (result != TSI_OK) { /* TODO(yangg) do different things according to the error type? */ - grpc_slice_buffer_reset_and_unref(&ep->output_buffer); - grpc_exec_ctx_sched( + grpc_slice_buffer_reset_and_unref_internal(exec_ctx, &ep->output_buffer); + GRPC_CLOSURE_SCHED( exec_ctx, cb, - grpc_set_tsi_error_result(GRPC_ERROR_CREATE("Wrap failed"), result), - NULL); + grpc_set_tsi_error_result( + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Wrap failed"), result)); GPR_TIMER_END("secure_endpoint.endpoint_write", 0); return; } @@ -341,10 +336,10 @@ static void endpoint_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *secure_ep, GPR_TIMER_END("secure_endpoint.endpoint_write", 0); } -static void endpoint_shutdown(grpc_exec_ctx *exec_ctx, - grpc_endpoint *secure_ep) { +static void endpoint_shutdown(grpc_exec_ctx *exec_ctx, grpc_endpoint *secure_ep, + grpc_error *why) { secure_endpoint *ep = (secure_endpoint *)secure_ep; - grpc_endpoint_shutdown(exec_ctx, ep->wrapped_ep); + grpc_endpoint_shutdown(exec_ctx, ep->wrapped_ep, why); } static void endpoint_destroy(grpc_exec_ctx *exec_ctx, @@ -377,11 +372,6 @@ static int endpoint_get_fd(grpc_endpoint *secure_ep) { return grpc_endpoint_get_fd(ep->wrapped_ep); } -static grpc_workqueue *endpoint_get_workqueue(grpc_endpoint *secure_ep) { - secure_endpoint *ep = (secure_endpoint *)secure_ep; - return grpc_endpoint_get_workqueue(ep->wrapped_ep); -} - static grpc_resource_user *endpoint_get_resource_user( grpc_endpoint *secure_ep) { secure_endpoint *ep = (secure_endpoint *)secure_ep; @@ -390,7 +380,6 @@ static grpc_resource_user *endpoint_get_resource_user( static const grpc_endpoint_vtable vtable = {endpoint_read, endpoint_write, - endpoint_get_workqueue, endpoint_add_to_pollset, endpoint_add_to_pollset_set, endpoint_shutdown, @@ -410,14 +399,14 @@ grpc_endpoint *grpc_secure_endpoint_create( grpc_slice_buffer_init(&ep->leftover_bytes); for (i = 0; i < leftover_nslices; i++) { grpc_slice_buffer_add(&ep->leftover_bytes, - grpc_slice_ref(leftover_slices[i])); + grpc_slice_ref_internal(leftover_slices[i])); } - ep->write_staging_buffer = grpc_slice_malloc(STAGING_BUFFER_SIZE); - ep->read_staging_buffer = grpc_slice_malloc(STAGING_BUFFER_SIZE); + ep->write_staging_buffer = GRPC_SLICE_MALLOC(STAGING_BUFFER_SIZE); + ep->read_staging_buffer = GRPC_SLICE_MALLOC(STAGING_BUFFER_SIZE); grpc_slice_buffer_init(&ep->output_buffer); grpc_slice_buffer_init(&ep->source_buffer); ep->read_buffer = NULL; - grpc_closure_init(&ep->on_read, on_read, ep); + GRPC_CLOSURE_INIT(&ep->on_read, on_read, ep, grpc_schedule_on_exec_ctx); gpr_mu_init(&ep->protector_mu); gpr_ref_init(&ep->ref, 1); return &ep->base; diff --git a/Sources/CgRPC/src/core/lib/security/transport/secure_endpoint.h b/Sources/CgRPC/src/core/lib/security/transport/secure_endpoint.h index a61f40a4f..1c5555f3d 100644 --- a/Sources/CgRPC/src/core/lib/security/transport/secure_endpoint.h +++ b/Sources/CgRPC/src/core/lib/security/transport/secure_endpoint.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -39,7 +24,7 @@ struct tsi_frame_protector; -extern int grpc_trace_secure_endpoint; +extern grpc_tracer_flag grpc_trace_secure_endpoint; /* Takes ownership of protector and to_wrap, and refs leftover_slices. */ grpc_endpoint *grpc_secure_endpoint_create( diff --git a/Sources/CgRPC/src/core/lib/security/transport/security_connector.c b/Sources/CgRPC/src/core/lib/security/transport/security_connector.c index 5b088aa58..a7568b995 100644 --- a/Sources/CgRPC/src/core/lib/security/transport/security_connector.c +++ b/Sources/CgRPC/src/core/lib/security/transport/security_connector.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -43,16 +28,25 @@ #include #include "src/core/ext/transport/chttp2/alpn/alpn.h" +#include "src/core/lib/channel/channel_args.h" #include "src/core/lib/channel/handshaker.h" #include "src/core/lib/iomgr/load_file.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" +#include "src/core/lib/security/transport/lb_targets_info.h" #include "src/core/lib/security/transport/secure_endpoint.h" #include "src/core/lib/security/transport/security_handshaker.h" #include "src/core/lib/support/env.h" #include "src/core/lib/support/string.h" -#include "src/core/lib/tsi/fake_transport_security.h" -#include "src/core/lib/tsi/ssl_transport_security.h" +#include "src/core/tsi/fake_transport_security.h" +#include "src/core/tsi/ssl_transport_security.h" +#include "src/core/tsi/transport_security_adapter.h" + +#ifndef NDEBUG +grpc_tracer_flag grpc_trace_security_connector_refcount = + GRPC_TRACER_INITIALIZER(false, "security_connector_refcount"); +#endif /* -- Constants. -- */ @@ -75,9 +69,8 @@ void grpc_set_ssl_roots_override_callback(grpc_ssl_roots_override_callback cb) { /* Defines the cipher suites that we accept by default. All these cipher suites are compliant with HTTP2. */ -#define GRPC_SSL_CIPHER_SUITES \ - "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-" \ - "SHA384:ECDHE-RSA-AES256-GCM-SHA384" +#define GRPC_SSL_CIPHER_SUITES \ + "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384" static gpr_once cipher_suites_once = GPR_ONCE_INIT; static const char *cipher_suites = NULL; @@ -134,34 +127,49 @@ void grpc_security_connector_check_peer(grpc_exec_ctx *exec_ctx, grpc_auth_context **auth_context, grpc_closure *on_peer_checked) { if (sc == NULL) { - grpc_exec_ctx_sched( - exec_ctx, on_peer_checked, - GRPC_ERROR_CREATE("cannot check peer -- no security connector"), NULL); + GRPC_CLOSURE_SCHED(exec_ctx, on_peer_checked, + GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "cannot check peer -- no security connector")); tsi_peer_destruct(&peer); } else { sc->vtable->check_peer(exec_ctx, sc, peer, auth_context, on_peer_checked); } } -void grpc_channel_security_connector_check_call_host( +bool grpc_channel_security_connector_check_call_host( grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *sc, const char *host, grpc_auth_context *auth_context, - grpc_security_call_host_check_cb cb, void *user_data) { + grpc_closure *on_call_host_checked, grpc_error **error) { if (sc == NULL || sc->check_call_host == NULL) { - cb(exec_ctx, user_data, GRPC_SECURITY_ERROR); - } else { - sc->check_call_host(exec_ctx, sc, host, auth_context, cb, user_data); + *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "cannot check call host -- no security connector"); + return true; } + return sc->check_call_host(exec_ctx, sc, host, auth_context, + on_call_host_checked, error); } -#ifdef GRPC_SECURITY_CONNECTOR_REFCOUNT_DEBUG +void grpc_channel_security_connector_cancel_check_call_host( + grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *sc, + grpc_closure *on_call_host_checked, grpc_error *error) { + if (sc == NULL || sc->cancel_check_call_host == NULL) { + GRPC_ERROR_UNREF(error); + return; + } + sc->cancel_check_call_host(exec_ctx, 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 == NULL) return NULL; - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, - "SECURITY_CONNECTOR:%p ref %d -> %d %s", sc, - (int)sc->refcount.count, (int)sc->refcount.count + 1, reason); + if (GRPC_TRACER_ON(grpc_trace_security_connector_refcount)) { + 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) { @@ -171,23 +179,28 @@ grpc_security_connector *grpc_security_connector_ref( return sc; } -#ifdef GRPC_SECURITY_CONNECTOR_REFCOUNT_DEBUG -void grpc_security_connector_unref(grpc_security_connector *sc, +#ifndef NDEBUG +void grpc_security_connector_unref(grpc_exec_ctx *exec_ctx, + grpc_security_connector *sc, const char *file, int line, const char *reason) { if (sc == NULL) return; - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, - "SECURITY_CONNECTOR:%p unref %d -> %d %s", sc, - (int)sc->refcount.count, (int)sc->refcount.count - 1, reason); + if (GRPC_TRACER_ON(grpc_trace_security_connector_refcount)) { + 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) { +void grpc_security_connector_unref(grpc_exec_ctx *exec_ctx, + grpc_security_connector *sc) { if (sc == NULL) return; #endif - if (gpr_unref(&sc->refcount)) sc->vtable->destroy(sc); + if (gpr_unref(&sc->refcount)) sc->vtable->destroy(exec_ctx, sc); } -static void connector_pointer_arg_destroy(void *p) { - GRPC_SECURITY_CONNECTOR_UNREF(p, "connector_pointer_arg_destroy"); +static void connector_pointer_arg_destroy(grpc_exec_ctx *exec_ctx, void *p) { + GRPC_SECURITY_CONNECTOR_UNREF(exec_ctx, p, "connector_pointer_arg_destroy"); } static void *connector_pointer_arg_copy(void *p) { @@ -201,25 +214,21 @@ static const grpc_arg_pointer_vtable connector_pointer_vtable = { connector_pointer_cmp}; grpc_arg grpc_security_connector_to_arg(grpc_security_connector *sc) { - grpc_arg result; - result.type = GRPC_ARG_POINTER; - result.key = GRPC_SECURITY_CONNECTOR_ARG; - result.value.pointer.vtable = &connector_pointer_vtable; - result.value.pointer.p = sc; - return result; + return grpc_channel_arg_pointer_create(GRPC_ARG_SECURITY_CONNECTOR, sc, + &connector_pointer_vtable); } grpc_security_connector *grpc_security_connector_from_arg(const grpc_arg *arg) { - if (strcmp(arg->key, GRPC_SECURITY_CONNECTOR_ARG)) return NULL; + if (strcmp(arg->key, GRPC_ARG_SECURITY_CONNECTOR)) return NULL; if (arg->type != GRPC_ARG_POINTER) { gpr_log(GPR_ERROR, "Invalid type %d for arg %s", arg->type, - GRPC_SECURITY_CONNECTOR_ARG); + GRPC_ARG_SECURITY_CONNECTOR); return NULL; } return arg->value.pointer.p; } -grpc_security_connector *grpc_find_security_connector_in_args( +grpc_security_connector *grpc_security_connector_find_in_args( const grpc_channel_args *args) { size_t i; if (args == NULL) return NULL; @@ -233,13 +242,89 @@ grpc_security_connector *grpc_find_security_connector_in_args( /* -- Fake implementation. -- */ -static void fake_channel_destroy(grpc_security_connector *sc) { - grpc_channel_security_connector *c = (grpc_channel_security_connector *)sc; - grpc_call_credentials_unref(c->request_metadata_creds); +typedef struct { + grpc_channel_security_connector base; + char *target; + char *expected_targets; + bool is_lb_channel; +} grpc_fake_channel_security_connector; + +static void fake_channel_destroy(grpc_exec_ctx *exec_ctx, + grpc_security_connector *sc) { + grpc_fake_channel_security_connector *c = + (grpc_fake_channel_security_connector *)sc; + grpc_call_credentials_unref(exec_ctx, c->base.request_metadata_creds); + gpr_free(c->target); + gpr_free(c->expected_targets); + gpr_free(c); +} + +static void fake_server_destroy(grpc_exec_ctx *exec_ctx, + grpc_security_connector *sc) { gpr_free(sc); } -static void fake_server_destroy(grpc_security_connector *sc) { gpr_free(sc); } +static bool fake_check_target(const char *target_type, const char *target, + const char *set_str) { + GPR_ASSERT(target_type != NULL); + GPR_ASSERT(target != NULL); + char **set = NULL; + 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] != NULL && strcmp(target, set[i]) == 0) found = true; + } + for (size_t i = 0; i < set_size; ++i) { + gpr_free(set[i]); + } + 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 == NULL) return; + char **lbs_and_backends = NULL; + 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; + } + 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(); +} static void fake_check_peer(grpc_exec_ctx *exec_ctx, grpc_security_connector *sc, tsi_peer peer, @@ -249,7 +334,8 @@ static void fake_check_peer(grpc_exec_ctx *exec_ctx, grpc_error *error = GRPC_ERROR_NONE; *auth_context = NULL; if (peer.property_count != 1) { - error = GRPC_ERROR_CREATE("Fake peers should only have 1 property."); + error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "Fake peers should only have 1 property."); goto end; } prop_name = peer.properties[0].name; @@ -258,32 +344,55 @@ static void fake_check_peer(grpc_exec_ctx *exec_ctx, char *msg; gpr_asprintf(&msg, "Unexpected property in fake peer: %s.", prop_name == NULL ? "" : prop_name); - error = GRPC_ERROR_CREATE(msg); + error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg); gpr_free(msg); goto end; } if (strncmp(peer.properties[0].value.data, TSI_FAKE_CERTIFICATE_TYPE, peer.properties[0].value.length)) { - error = GRPC_ERROR_CREATE("Invalid value for cert type property."); + error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "Invalid value for cert type property."); goto end; } *auth_context = grpc_auth_context_create(NULL); grpc_auth_context_add_cstring_property( *auth_context, GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME, GRPC_FAKE_TRANSPORT_SECURITY_TYPE); - end: - grpc_exec_ctx_sched(exec_ctx, on_peer_checked, error, NULL); + GRPC_CLOSURE_SCHED(exec_ctx, on_peer_checked, error); tsi_peer_destruct(&peer); } -static void fake_channel_check_call_host(grpc_exec_ctx *exec_ctx, +static void fake_channel_check_peer(grpc_exec_ctx *exec_ctx, + grpc_security_connector *sc, tsi_peer peer, + grpc_auth_context **auth_context, + grpc_closure *on_peer_checked) { + fake_check_peer(exec_ctx, sc, peer, auth_context, on_peer_checked); + grpc_fake_channel_security_connector *c = + (grpc_fake_channel_security_connector *)sc; + fake_secure_name_check(c->target, c->expected_targets, c->is_lb_channel); +} + +static void fake_server_check_peer(grpc_exec_ctx *exec_ctx, + grpc_security_connector *sc, tsi_peer peer, + grpc_auth_context **auth_context, + grpc_closure *on_peer_checked) { + fake_check_peer(exec_ctx, sc, peer, auth_context, on_peer_checked); +} + +static bool fake_channel_check_call_host(grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *sc, const char *host, grpc_auth_context *auth_context, - grpc_security_call_host_check_cb cb, - void *user_data) { - cb(exec_ctx, user_data, GRPC_SECURITY_OK); + grpc_closure *on_call_host_checked, + grpc_error **error) { + return true; +} + +static void fake_channel_cancel_check_call_host( + grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *sc, + grpc_closure *on_call_host_checked, grpc_error *error) { + GRPC_ERROR_UNREF(error); } static void fake_channel_add_handshakers( @@ -307,29 +416,34 @@ static void fake_server_add_handshakers(grpc_exec_ctx *exec_ctx, } static grpc_security_connector_vtable fake_channel_vtable = { - fake_channel_destroy, fake_check_peer}; + fake_channel_destroy, fake_channel_check_peer}; -static grpc_security_connector_vtable fake_server_vtable = {fake_server_destroy, - fake_check_peer}; +static grpc_security_connector_vtable fake_server_vtable = { + fake_server_destroy, fake_server_check_peer}; grpc_channel_security_connector *grpc_fake_channel_security_connector_create( - grpc_call_credentials *request_metadata_creds) { - grpc_channel_security_connector *c = gpr_malloc(sizeof(*c)); - memset(c, 0, sizeof(*c)); - gpr_ref_init(&c->base.refcount, 1); - c->base.url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME; - c->base.vtable = &fake_channel_vtable; - c->request_metadata_creds = grpc_call_credentials_ref(request_metadata_creds); - c->check_call_host = fake_channel_check_call_host; - c->add_handshakers = fake_channel_add_handshakers; - return c; + grpc_call_credentials *request_metadata_creds, const char *target, + const grpc_channel_args *args) { + grpc_fake_channel_security_connector *c = 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.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_lb_targets_info_find_in_args(args) != NULL); + return &c->base; } grpc_server_security_connector *grpc_fake_server_security_connector_create( void) { grpc_server_security_connector *c = - gpr_malloc(sizeof(grpc_server_security_connector)); - memset(c, 0, sizeof(*c)); + 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; @@ -341,52 +455,39 @@ grpc_server_security_connector *grpc_fake_server_security_connector_create( typedef struct { grpc_channel_security_connector base; - tsi_ssl_handshaker_factory *handshaker_factory; + tsi_ssl_client_handshaker_factory *handshaker_factory; char *target_name; char *overridden_target_name; } grpc_ssl_channel_security_connector; typedef struct { grpc_server_security_connector base; - tsi_ssl_handshaker_factory *handshaker_factory; + tsi_ssl_server_handshaker_factory *handshaker_factory; } grpc_ssl_server_security_connector; -static void ssl_channel_destroy(grpc_security_connector *sc) { +static void ssl_channel_destroy(grpc_exec_ctx *exec_ctx, + grpc_security_connector *sc) { grpc_ssl_channel_security_connector *c = (grpc_ssl_channel_security_connector *)sc; - grpc_call_credentials_unref(c->base.request_metadata_creds); + grpc_call_credentials_unref(exec_ctx, c->base.request_metadata_creds); if (c->handshaker_factory != NULL) { - tsi_ssl_handshaker_factory_destroy(c->handshaker_factory); + tsi_ssl_client_handshaker_factory_destroy(c->handshaker_factory); } if (c->target_name != NULL) gpr_free(c->target_name); if (c->overridden_target_name != NULL) gpr_free(c->overridden_target_name); gpr_free(sc); } -static void ssl_server_destroy(grpc_security_connector *sc) { +static void ssl_server_destroy(grpc_exec_ctx *exec_ctx, + grpc_security_connector *sc) { grpc_ssl_server_security_connector *c = (grpc_ssl_server_security_connector *)sc; if (c->handshaker_factory != NULL) { - tsi_ssl_handshaker_factory_destroy(c->handshaker_factory); + tsi_ssl_server_handshaker_factory_destroy(c->handshaker_factory); } gpr_free(sc); } -static grpc_security_status ssl_create_handshaker( - tsi_ssl_handshaker_factory *handshaker_factory, bool is_client, - const char *peer_name, tsi_handshaker **handshaker) { - tsi_result result = TSI_OK; - if (handshaker_factory == NULL) return GRPC_SECURITY_ERROR; - result = tsi_ssl_handshaker_factory_create_handshaker( - handshaker_factory, is_client ? peer_name : NULL, handshaker); - if (result != TSI_OK) { - gpr_log(GPR_ERROR, "Handshaker creation failed with error %s.", - tsi_result_to_string(result)); - return GRPC_SECURITY_ERROR; - } - return GRPC_SECURITY_OK; -} - static void ssl_channel_add_handshakers(grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *sc, grpc_handshake_manager *handshake_mgr) { @@ -394,14 +495,22 @@ static void ssl_channel_add_handshakers(grpc_exec_ctx *exec_ctx, (grpc_ssl_channel_security_connector *)sc; // Instantiate TSI handshaker. tsi_handshaker *tsi_hs = NULL; - ssl_create_handshaker(c->handshaker_factory, true /* is_client */, - c->overridden_target_name != NULL - ? c->overridden_target_name - : c->target_name, - &tsi_hs); + tsi_result result = tsi_ssl_client_handshaker_factory_create_handshaker( + c->handshaker_factory, + c->overridden_target_name != NULL ? 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( - exec_ctx, tsi_hs, &sc->base)); + grpc_handshake_manager_add( + handshake_mgr, + grpc_security_handshaker_create( + exec_ctx, tsi_create_adapter_handshaker(tsi_hs), &sc->base)); } static void ssl_server_add_handshakers(grpc_exec_ctx *exec_ctx, @@ -411,11 +520,19 @@ static void ssl_server_add_handshakers(grpc_exec_ctx *exec_ctx, (grpc_ssl_server_security_connector *)sc; // Instantiate TSI handshaker. tsi_handshaker *tsi_hs = NULL; - ssl_create_handshaker(c->handshaker_factory, false /* is_client */, - NULL /* peer_name */, &tsi_hs); + tsi_result result = tsi_ssl_server_handshaker_factory_create_handshaker( + c->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( - exec_ctx, tsi_hs, &sc->base)); + grpc_handshake_manager_add( + handshake_mgr, + grpc_security_handshaker_create( + exec_ctx, tsi_create_adapter_handshaker(tsi_hs), &sc->base)); } static int ssl_host_matches_name(const tsi_peer *peer, const char *peer_name) { @@ -479,18 +596,19 @@ static grpc_error *ssl_check_peer(grpc_security_connector *sc, const tsi_peer_property *p = tsi_peer_get_property_by_name(peer, TSI_SSL_ALPN_SELECTED_PROTOCOL); if (p == NULL) { - return GRPC_ERROR_CREATE( + return GRPC_ERROR_CREATE_FROM_STATIC_STRING( "Cannot check peer: missing selected ALPN property."); } if (!grpc_chttp2_is_alpn_version_supported(p->value.data, p->value.length)) { - return GRPC_ERROR_CREATE("Cannot check peer: invalid ALPN value."); + return GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "Cannot check peer: invalid ALPN value."); } /* Check the peer name if specified. */ if (peer_name != NULL && !ssl_host_matches_name(peer, peer_name)) { char *msg; gpr_asprintf(&msg, "Peer name %s is not in peer certificate", peer_name); - grpc_error *error = GRPC_ERROR_CREATE(msg); + grpc_error *error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg); gpr_free(msg); return error; } @@ -508,7 +626,7 @@ static void ssl_channel_check_peer(grpc_exec_ctx *exec_ctx, ? c->overridden_target_name : c->target_name, &peer, auth_context); - grpc_exec_ctx_sched(exec_ctx, on_peer_checked, error, NULL); + GRPC_CLOSURE_SCHED(exec_ctx, on_peer_checked, error); tsi_peer_destruct(&peer); } @@ -518,7 +636,7 @@ static void ssl_server_check_peer(grpc_exec_ctx *exec_ctx, grpc_closure *on_peer_checked) { grpc_error *error = ssl_check_peer(sc, NULL, &peer, auth_context); tsi_peer_destruct(&peer); - grpc_exec_ctx_sched(exec_ctx, on_peer_checked, error, NULL); + GRPC_CLOSURE_SCHED(exec_ctx, on_peer_checked, error); } static void add_shallow_auth_property_to_peer(tsi_peer *peer, @@ -564,26 +682,35 @@ void tsi_shallow_peer_destruct(tsi_peer *peer) { if (peer->properties != NULL) gpr_free(peer->properties); } -static void ssl_channel_check_call_host(grpc_exec_ctx *exec_ctx, +static bool ssl_channel_check_call_host(grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *sc, const char *host, grpc_auth_context *auth_context, - grpc_security_call_host_check_cb cb, - void *user_data) { + grpc_closure *on_call_host_checked, + grpc_error **error) { grpc_ssl_channel_security_connector *c = (grpc_ssl_channel_security_connector *)sc; grpc_security_status status = GRPC_SECURITY_ERROR; tsi_peer peer = tsi_shallow_peer_from_ssl_auth_context(auth_context); if (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 != NULL && strcmp(host, c->target_name) == 0) { status = GRPC_SECURITY_OK; } - cb(exec_ctx, user_data, status); + if (status != GRPC_SECURITY_OK) { + *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "call host does not match SSL server name"); + } tsi_shallow_peer_destruct(&peer); + return true; +} + +static void ssl_channel_cancel_check_call_host( + grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *sc, + grpc_closure *on_call_host_checked, grpc_error *error) { + GRPC_ERROR_UNREF(error); } static grpc_security_connector_vtable ssl_channel_vtable = { @@ -592,15 +719,16 @@ static grpc_security_connector_vtable ssl_channel_vtable = { static grpc_security_connector_vtable ssl_server_vtable = { ssl_server_destroy, ssl_server_check_peer}; +/* returns a NULL terminated slice. */ static grpc_slice compute_default_pem_root_certs_once(void) { - grpc_slice result = gpr_empty_slice(); + grpc_slice result = grpc_empty_slice(); /* First try to load the roots from the environment. */ char *default_root_certs_path = gpr_getenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR); if (default_root_certs_path != NULL) { GRPC_LOG_IF_ERROR("load_file", - grpc_load_file(default_root_certs_path, 0, &result)); + grpc_load_file(default_root_certs_path, 1, &result)); gpr_free(default_root_certs_path); } @@ -611,15 +739,18 @@ static grpc_slice compute_default_pem_root_certs_once(void) { ovrd_res = ssl_roots_override_cb(&pem_root_certs); if (ovrd_res == GRPC_SSL_ROOTS_OVERRIDE_OK) { GPR_ASSERT(pem_root_certs != NULL); - result = grpc_slice_new(pem_root_certs, strlen(pem_root_certs), gpr_free); + result = grpc_slice_from_copied_buffer( + pem_root_certs, + strlen(pem_root_certs) + 1); // NULL terminator. } + gpr_free(pem_root_certs); } /* Fall back to installed certs if needed. */ if (GRPC_SLICE_IS_EMPTY(result) && ovrd_res != GRPC_SSL_ROOTS_OVERRIDE_FAIL_PERMANENTLY) { GRPC_LOG_IF_ERROR("load_file", - grpc_load_file(installed_roots_path, 0, &result)); + grpc_load_file(installed_roots_path, 1, &result)); } return result; } @@ -659,36 +790,31 @@ get_tsi_client_certificate_request_type( } } -size_t grpc_get_default_ssl_roots(const unsigned char **pem_root_certs) { +const char *grpc_get_default_ssl_roots(void) { /* TODO(jboeuf@google.com): Maybe revisit the approach which consists in loading all the roots once for the lifetime of the process. */ static gpr_once once = GPR_ONCE_INIT; gpr_once_init(&once, init_default_pem_root_certs); - *pem_root_certs = GRPC_SLICE_START_PTR(default_pem_root_certs); - return GRPC_SLICE_LENGTH(default_pem_root_certs); + return GRPC_SLICE_IS_EMPTY(default_pem_root_certs) + ? NULL + : (const char *)GRPC_SLICE_START_PTR(default_pem_root_certs); } grpc_security_status grpc_ssl_channel_security_connector_create( - grpc_call_credentials *request_metadata_creds, + grpc_exec_ctx *exec_ctx, grpc_call_credentials *request_metadata_creds, const grpc_ssl_config *config, const char *target_name, const char *overridden_target_name, grpc_channel_security_connector **sc) { size_t num_alpn_protocols = grpc_chttp2_num_alpn_versions(); - const unsigned char **alpn_protocol_strings = + const char **alpn_protocol_strings = gpr_malloc(sizeof(const char *) * num_alpn_protocols); - unsigned char *alpn_protocol_string_lengths = - gpr_malloc(sizeof(unsigned char) * num_alpn_protocols); tsi_result result = TSI_OK; grpc_ssl_channel_security_connector *c; size_t i; - const unsigned char *pem_root_certs; - size_t pem_root_certs_size; + const char *pem_root_certs; char *port; for (i = 0; i < num_alpn_protocols; i++) { - alpn_protocol_strings[i] = - (const unsigned char *)grpc_chttp2_get_alpn_version_index(i); - alpn_protocol_string_lengths[i] = - (unsigned char)strlen(grpc_chttp2_get_alpn_version_index(i)); + alpn_protocol_strings[i] = grpc_chttp2_get_alpn_version_index(i); } if (config == NULL || target_name == NULL) { @@ -696,18 +822,16 @@ grpc_security_status grpc_ssl_channel_security_connector_create( goto error; } if (config->pem_root_certs == NULL) { - pem_root_certs_size = grpc_get_default_ssl_roots(&pem_root_certs); - if (pem_root_certs == NULL || pem_root_certs_size == 0) { + pem_root_certs = grpc_get_default_ssl_roots(); + if (pem_root_certs == NULL) { gpr_log(GPR_ERROR, "Could not get default pem root certs."); goto error; } } else { pem_root_certs = config->pem_root_certs; - pem_root_certs_size = config->pem_root_certs_size; } - c = gpr_malloc(sizeof(grpc_ssl_channel_security_connector)); - memset(c, 0, sizeof(grpc_ssl_channel_security_connector)); + c = gpr_zalloc(sizeof(grpc_ssl_channel_security_connector)); gpr_ref_init(&c->base.base.refcount, 1); c->base.base.vtable = &ssl_channel_vtable; @@ -715,89 +839,78 @@ grpc_security_status grpc_ssl_channel_security_connector_create( 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 != NULL) { c->overridden_target_name = gpr_strdup(overridden_target_name); } + + bool has_key_cert_pair = config->pem_key_cert_pair.private_key != NULL && + config->pem_key_cert_pair.cert_chain != NULL; result = tsi_create_ssl_client_handshaker_factory( - config->pem_private_key, config->pem_private_key_size, - config->pem_cert_chain, config->pem_cert_chain_size, pem_root_certs, - pem_root_certs_size, ssl_cipher_suites(), alpn_protocol_strings, - alpn_protocol_string_lengths, (uint16_t)num_alpn_protocols, + has_key_cert_pair ? &config->pem_key_cert_pair : NULL, pem_root_certs, + ssl_cipher_suites(), alpn_protocol_strings, (uint16_t)num_alpn_protocols, &c->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); + ssl_channel_destroy(exec_ctx, &c->base.base); *sc = NULL; goto error; } *sc = &c->base; gpr_free((void *)alpn_protocol_strings); - gpr_free(alpn_protocol_string_lengths); return GRPC_SECURITY_OK; error: gpr_free((void *)alpn_protocol_strings); - gpr_free(alpn_protocol_string_lengths); return GRPC_SECURITY_ERROR; } grpc_security_status grpc_ssl_server_security_connector_create( - const grpc_ssl_server_config *config, grpc_server_security_connector **sc) { + grpc_exec_ctx *exec_ctx, const grpc_ssl_server_config *config, + grpc_server_security_connector **sc) { size_t num_alpn_protocols = grpc_chttp2_num_alpn_versions(); - const unsigned char **alpn_protocol_strings = + const char **alpn_protocol_strings = gpr_malloc(sizeof(const char *) * num_alpn_protocols); - unsigned char *alpn_protocol_string_lengths = - gpr_malloc(sizeof(unsigned char) * num_alpn_protocols); tsi_result result = TSI_OK; grpc_ssl_server_security_connector *c; size_t i; for (i = 0; i < num_alpn_protocols; i++) { - alpn_protocol_strings[i] = - (const unsigned char *)grpc_chttp2_get_alpn_version_index(i); - alpn_protocol_string_lengths[i] = - (unsigned char)strlen(grpc_chttp2_get_alpn_version_index(i)); + alpn_protocol_strings[i] = grpc_chttp2_get_alpn_version_index(i); } if (config == NULL || config->num_key_cert_pairs == 0) { gpr_log(GPR_ERROR, "An SSL server needs a key and a cert."); goto error; } - c = gpr_malloc(sizeof(grpc_ssl_server_security_connector)); - memset(c, 0, sizeof(grpc_ssl_server_security_connector)); + c = 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; result = tsi_create_ssl_server_handshaker_factory_ex( - (const unsigned char **)config->pem_private_keys, - config->pem_private_keys_sizes, - (const unsigned char **)config->pem_cert_chains, - config->pem_cert_chains_sizes, config->num_key_cert_pairs, - config->pem_root_certs, config->pem_root_certs_size, - get_tsi_client_certificate_request_type( - config->client_certificate_request), - ssl_cipher_suites(), alpn_protocol_strings, alpn_protocol_string_lengths, - (uint16_t)num_alpn_protocols, &c->handshaker_factory); + config->pem_key_cert_pairs, config->num_key_cert_pairs, + config->pem_root_certs, get_tsi_client_certificate_request_type( + config->client_certificate_request), + ssl_cipher_suites(), alpn_protocol_strings, (uint16_t)num_alpn_protocols, + &c->handshaker_factory); if (result != TSI_OK) { gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.", tsi_result_to_string(result)); - ssl_server_destroy(&c->base.base); + ssl_server_destroy(exec_ctx, &c->base.base); *sc = NULL; goto error; } c->base.add_handshakers = ssl_server_add_handshakers; *sc = &c->base; gpr_free((void *)alpn_protocol_strings); - gpr_free(alpn_protocol_string_lengths); return GRPC_SECURITY_OK; error: gpr_free((void *)alpn_protocol_strings); - gpr_free(alpn_protocol_string_lengths); return GRPC_SECURITY_ERROR; } diff --git a/Sources/CgRPC/src/core/lib/security/transport/security_connector.h b/Sources/CgRPC/src/core/lib/security/transport/security_connector.h index a84b35905..4f9b63ad2 100644 --- a/Sources/CgRPC/src/core/lib/security/transport/security_connector.h +++ b/Sources/CgRPC/src/core/lib/security/transport/security_connector.h @@ -1,45 +1,37 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 GRPC_CORE_LIB_SECURITY_TRANSPORT_SECURITY_CONNECTOR_H #define GRPC_CORE_LIB_SECURITY_TRANSPORT_SECURITY_CONNECTOR_H +#include + #include #include "src/core/lib/channel/handshaker.h" #include "src/core/lib/iomgr/endpoint.h" #include "src/core/lib/iomgr/tcp_server.h" -#include "src/core/lib/tsi/transport_security_interface.h" +#include "src/core/tsi/ssl_transport_security.h" +#include "src/core/tsi/transport_security_interface.h" + +#ifndef NDEBUG +extern grpc_tracer_flag grpc_trace_security_connector_refcount; +#endif /* --- status enum. --- */ @@ -57,10 +49,10 @@ typedef enum { GRPC_SECURITY_OK = 0, GRPC_SECURITY_ERROR } grpc_security_status; typedef struct grpc_security_connector grpc_security_connector; -#define GRPC_SECURITY_CONNECTOR_ARG "grpc.security_connector" +#define GRPC_ARG_SECURITY_CONNECTOR "grpc.security_connector" typedef struct { - void (*destroy)(grpc_security_connector *sc); + void (*destroy)(grpc_exec_ctx *exec_ctx, grpc_security_connector *sc); void (*check_peer)(grpc_exec_ctx *exec_ctx, grpc_security_connector *sc, tsi_peer peer, grpc_auth_context **auth_context, grpc_closure *on_peer_checked); @@ -78,23 +70,26 @@ struct grpc_security_connector { }; /* Refcounting. */ -#ifdef GRPC_SECURITY_CONNECTOR_REFCOUNT_DEBUG +#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)) +#define GRPC_SECURITY_CONNECTOR_UNREF(exec_ctx, p, r) \ + grpc_security_connector_unref((exec_ctx), (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, +void grpc_security_connector_unref(grpc_exec_ctx *exec_ctx, + 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)) +#define GRPC_SECURITY_CONNECTOR_UNREF(exec_ctx, p, r) \ + grpc_security_connector_unref((exec_ctx), (p)) grpc_security_connector *grpc_security_connector_ref( grpc_security_connector *policy); -void grpc_security_connector_unref(grpc_security_connector *policy); +void grpc_security_connector_unref(grpc_exec_ctx *exec_ctx, + grpc_security_connector *policy); #endif /* Check the peer. Callee takes ownership of the peer object. @@ -112,7 +107,7 @@ grpc_arg grpc_security_connector_to_arg(grpc_security_connector *sc); grpc_security_connector *grpc_security_connector_from_arg(const grpc_arg *arg); /* Util to find the connector from channel args. */ -grpc_security_connector *grpc_find_security_connector_in_args( +grpc_security_connector *grpc_security_connector_find_in_args( const grpc_channel_args *args); /* --- channel_security_connector object. --- @@ -122,27 +117,38 @@ grpc_security_connector *grpc_find_security_connector_in_args( typedef struct grpc_channel_security_connector grpc_channel_security_connector; -typedef void (*grpc_security_call_host_check_cb)(grpc_exec_ctx *exec_ctx, - void *user_data, - grpc_security_status status); - struct grpc_channel_security_connector { grpc_security_connector base; grpc_call_credentials *request_metadata_creds; - void (*check_call_host)(grpc_exec_ctx *exec_ctx, + bool (*check_call_host)(grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *sc, const char *host, grpc_auth_context *auth_context, - grpc_security_call_host_check_cb cb, void *user_data); + grpc_closure *on_call_host_checked, + grpc_error **error); + void (*cancel_check_call_host)(grpc_exec_ctx *exec_ctx, + grpc_channel_security_connector *sc, + grpc_closure *on_call_host_checked, + grpc_error *error); void (*add_handshakers)(grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *sc, grpc_handshake_manager *handshake_mgr); }; -/* Checks that the host that will be set for a call is acceptable. */ -void grpc_channel_security_connector_check_call_host( +/// 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_exec_ctx *exec_ctx, grpc_channel_security_connector *sc, const char *host, grpc_auth_context *auth_context, - grpc_security_call_host_check_cb cb, void *user_data); + 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_exec_ctx *exec_ctx, 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( @@ -172,7 +178,8 @@ void grpc_server_security_connector_add_handshakers( /* For TESTING ONLY! Creates a fake connector that emulates real channel security. */ grpc_channel_security_connector *grpc_fake_channel_security_connector_create( - grpc_call_credentials *request_metadata_creds); + grpc_call_credentials *request_metadata_creds, const char *target, + const grpc_channel_args *args); /* For TESTING ONLY! Creates a fake connector that emulates real server security. */ @@ -180,13 +187,10 @@ grpc_server_security_connector *grpc_fake_server_security_connector_create( void); /* Config for ssl clients. */ + typedef struct { - unsigned char *pem_private_key; - size_t pem_private_key_size; - unsigned char *pem_cert_chain; - size_t pem_cert_chain_size; - unsigned char *pem_root_certs; - size_t pem_root_certs_size; + tsi_ssl_pem_key_cert_pair pem_key_cert_pair; + char *pem_root_certs; } grpc_ssl_config; /* Creates an SSL channel_security_connector. @@ -203,25 +207,21 @@ typedef struct { specific error code otherwise. */ grpc_security_status grpc_ssl_channel_security_connector_create( - grpc_call_credentials *request_metadata_creds, + grpc_exec_ctx *exec_ctx, grpc_call_credentials *request_metadata_creds, const grpc_ssl_config *config, const char *target_name, const char *overridden_target_name, grpc_channel_security_connector **sc); -/* Gets the default ssl roots. */ -size_t grpc_get_default_ssl_roots(const unsigned char **pem_root_certs); +/* Gets the default ssl roots. Returns NULL if not found. */ +const char *grpc_get_default_ssl_roots(void); /* Exposed for TESTING ONLY!. */ grpc_slice grpc_get_default_ssl_roots_for_testing(void); /* Config for ssl servers. */ typedef struct { - unsigned char **pem_private_keys; - size_t *pem_private_keys_sizes; - unsigned char **pem_cert_chains; - size_t *pem_cert_chains_sizes; + tsi_ssl_pem_key_cert_pair *pem_key_cert_pairs; size_t num_key_cert_pairs; - unsigned char *pem_root_certs; - size_t pem_root_certs_size; + char *pem_root_certs; grpc_ssl_client_certificate_request_type client_certificate_request; } grpc_ssl_server_config; @@ -232,7 +232,8 @@ typedef struct { specific error code otherwise. */ grpc_security_status grpc_ssl_server_security_connector_create( - const grpc_ssl_server_config *config, grpc_server_security_connector **sc); + grpc_exec_ctx *exec_ctx, const grpc_ssl_server_config *config, + grpc_server_security_connector **sc); /* Util. */ const tsi_peer_property *tsi_peer_get_property_by_name(const tsi_peer *peer, diff --git a/Sources/CgRPC/src/core/lib/security/transport/security_handshaker.c b/Sources/CgRPC/src/core/lib/security/transport/security_handshaker.c index 41a775db8..fc9c9f980 100644 --- a/Sources/CgRPC/src/core/lib/security/transport/security_handshaker.c +++ b/Sources/CgRPC/src/core/lib/security/transport/security_handshaker.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -42,9 +27,11 @@ #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/security/context/security_context.h" #include "src/core/lib/security/transport/secure_endpoint.h" #include "src/core/lib/security/transport/tsi_error.h" +#include "src/core/lib/slice/slice_internal.h" #define GRPC_INITIAL_HANDSHAKE_BUFFER_SIZE 256 @@ -69,12 +56,12 @@ typedef struct { unsigned char *handshake_buffer; size_t handshake_buffer_size; - grpc_slice_buffer left_overs; 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; static void security_handshaker_unref(grpc_exec_ctx *exec_ctx, @@ -82,30 +69,31 @@ static void security_handshaker_unref(grpc_exec_ctx *exec_ctx, 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 != NULL) { grpc_endpoint_destroy(exec_ctx, h->endpoint_to_destroy); } if (h->read_buffer_to_destroy != NULL) { - grpc_slice_buffer_destroy(h->read_buffer_to_destroy); + grpc_slice_buffer_destroy_internal(exec_ctx, h->read_buffer_to_destroy); gpr_free(h->read_buffer_to_destroy); } gpr_free(h->handshake_buffer); - grpc_slice_buffer_destroy(&h->left_overs); - grpc_slice_buffer_destroy(&h->outgoing); + grpc_slice_buffer_destroy_internal(exec_ctx, &h->outgoing); GRPC_AUTH_CONTEXT_UNREF(h->auth_context, "handshake"); - GRPC_SECURITY_CONNECTOR_UNREF(h->connector, "handshake"); + GRPC_SECURITY_CONNECTOR_UNREF(exec_ctx, 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) { +static void cleanup_args_for_failure_locked(grpc_exec_ctx *exec_ctx, + security_handshaker *h) { h->endpoint_to_destroy = h->args->endpoint; h->args->endpoint = NULL; h->read_buffer_to_destroy = h->args->read_buffer; h->args->read_buffer = NULL; - grpc_channel_args_destroy(h->args->args); + grpc_channel_args_destroy(exec_ctx, h->args->args); h->args->args = NULL; } @@ -117,26 +105,26 @@ static void security_handshake_failed_locked(grpc_exec_ctx *exec_ctx, if (error == GRPC_ERROR_NONE) { // If we were shut down after the handshake succeeded but before an // endpoint callback was invoked, we need to generate our own error. - error = GRPC_ERROR_CREATE("Handshaker shutdown"); + error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Handshaker shutdown"); } const char *msg = grpc_error_string(error); gpr_log(GPR_DEBUG, "Security handshake failed: %s", msg); - grpc_error_free_string(msg); + if (!h->shutdown) { // TODO(ctiller): It is currently necessary to shutdown endpoints // before destroying them, even if we know that there are no // pending read/write callbacks. This should be fixed, at which // point this can be removed. - grpc_endpoint_shutdown(exec_ctx, h->args->endpoint); + grpc_endpoint_shutdown(exec_ctx, h->args->endpoint, GRPC_ERROR_REF(error)); // Not shutting down, so the write failed. Clean up before // invoking the callback. - cleanup_args_for_failure_locked(h); + cleanup_args_for_failure_locked(exec_ctx, h); // Set shutdown to true so that subsequent calls to // security_handshaker_shutdown() do nothing. h->shutdown = true; } // Invoke callback. - grpc_exec_ctx_sched(exec_ctx, h->on_handshake_done, error, NULL); + GRPC_CLOSURE_SCHED(exec_ctx, h->on_handshake_done, error); } static void on_peer_checked(grpc_exec_ctx *exec_ctx, void *arg, @@ -147,33 +135,45 @@ static void on_peer_checked(grpc_exec_ctx *exec_ctx, void *arg, security_handshake_failed_locked(exec_ctx, h, GRPC_ERROR_REF(error)); goto done; } - // Get frame protector. + // Create frame protector. tsi_frame_protector *protector; - tsi_result result = - tsi_handshaker_create_frame_protector(h->handshaker, NULL, &protector); + tsi_result result = tsi_handshaker_result_create_frame_protector( + h->handshaker_result, NULL, &protector); if (result != TSI_OK) { error = grpc_set_tsi_error_result( - GRPC_ERROR_CREATE("Frame protector creation failed"), result); + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Frame protector creation failed"), + result); security_handshake_failed_locked(exec_ctx, h, error); goto done; } - // Success. + // Get unused bytes. + const unsigned char *unused_bytes = NULL; + size_t unused_bytes_size = 0; + result = tsi_handshaker_result_get_unused_bytes( + h->handshaker_result, &unused_bytes, &unused_bytes_size); // Create secure endpoint. - h->args->endpoint = grpc_secure_endpoint_create( - protector, h->args->endpoint, h->left_overs.slices, h->left_overs.count); - h->left_overs.count = 0; - h->left_overs.length = 0; - // Clear out the read buffer before it gets passed to the transport, - // since any excess bytes were already copied to h->left_overs. - grpc_slice_buffer_reset_and_unref(h->args->read_buffer); + if (unused_bytes_size > 0) { + grpc_slice slice = + grpc_slice_from_copied_buffer((char *)unused_bytes, unused_bytes_size); + h->args->endpoint = + grpc_secure_endpoint_create(protector, h->args->endpoint, &slice, 1); + grpc_slice_unref_internal(exec_ctx, slice); + } else { + h->args->endpoint = + grpc_secure_endpoint_create(protector, h->args->endpoint, NULL, 0); + } + tsi_handshaker_result_destroy(h->handshaker_result); + h->handshaker_result = NULL; + // Clear out the read buffer before it gets passed to the transport. + grpc_slice_buffer_reset_and_unref_internal(exec_ctx, h->args->read_buffer); // Add auth context to channel args. grpc_arg auth_context_arg = grpc_auth_context_to_arg(h->auth_context); grpc_channel_args *tmp_args = h->args->args; h->args->args = grpc_channel_args_copy_and_add(tmp_args, &auth_context_arg, 1); - grpc_channel_args_destroy(tmp_args); + grpc_channel_args_destroy(exec_ctx, tmp_args); // Invoke callback. - grpc_exec_ctx_sched(exec_ctx, h->on_handshake_done, GRPC_ERROR_NONE, NULL); + GRPC_CLOSURE_SCHED(exec_ctx, h->on_handshake_done, GRPC_ERROR_NONE); // Set shutdown to true so that subsequent calls to // security_handshaker_shutdown() do nothing. h->shutdown = true; @@ -185,44 +185,98 @@ static void on_peer_checked(grpc_exec_ctx *exec_ctx, void *arg, static grpc_error *check_peer_locked(grpc_exec_ctx *exec_ctx, security_handshaker *h) { tsi_peer peer; - tsi_result result = tsi_handshaker_extract_peer(h->handshaker, &peer); + tsi_result result = + tsi_handshaker_result_extract_peer(h->handshaker_result, &peer); if (result != TSI_OK) { return grpc_set_tsi_error_result( - GRPC_ERROR_CREATE("Peer extraction failed"), result); + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Peer extraction failed"), result); } grpc_security_connector_check_peer(exec_ctx, h->connector, peer, &h->auth_context, &h->on_peer_checked); return GRPC_ERROR_NONE; } -static grpc_error *send_handshake_bytes_to_peer_locked(grpc_exec_ctx *exec_ctx, - security_handshaker *h) { - // Get data to send. - tsi_result result = TSI_OK; - size_t offset = 0; - do { - size_t to_send_size = h->handshake_buffer_size - offset; - result = tsi_handshaker_get_bytes_to_send_to_peer( - h->handshaker, h->handshake_buffer + offset, &to_send_size); - offset += to_send_size; - if (result == TSI_INCOMPLETE_DATA) { - h->handshake_buffer_size *= 2; - h->handshake_buffer = - gpr_realloc(h->handshake_buffer, h->handshake_buffer_size); - } - } while (result == TSI_INCOMPLETE_DATA); +static grpc_error *on_handshake_next_done_locked( + grpc_exec_ctx *exec_ctx, security_handshaker *h, tsi_result result, + const unsigned char *bytes_to_send, size_t bytes_to_send_size, + tsi_handshaker_result *handshaker_result) { + grpc_error *error = GRPC_ERROR_NONE; + // Read more if we need to. + if (result == TSI_INCOMPLETE_DATA) { + GPR_ASSERT(bytes_to_send_size == 0); + grpc_endpoint_read(exec_ctx, h->args->endpoint, h->args->read_buffer, + &h->on_handshake_data_received_from_peer); + return error; + } if (result != TSI_OK) { - return grpc_set_tsi_error_result(GRPC_ERROR_CREATE("Handshake failed"), - result); + return grpc_set_tsi_error_result( + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Handshake failed"), result); } - // Send data. - grpc_slice to_send = - grpc_slice_from_copied_buffer((const char *)h->handshake_buffer, offset); - grpc_slice_buffer_reset_and_unref(&h->outgoing); - grpc_slice_buffer_add(&h->outgoing, to_send); - grpc_endpoint_write(exec_ctx, h->args->endpoint, &h->outgoing, - &h->on_handshake_data_sent_to_peer); - return GRPC_ERROR_NONE; + // Update handshaker result. + if (handshaker_result != NULL) { + GPR_ASSERT(h->handshaker_result == NULL); + h->handshaker_result = handshaker_result; + } + if (bytes_to_send_size > 0) { + // Send data to peer, if needed. + grpc_slice to_send = grpc_slice_from_copied_buffer( + (const char *)bytes_to_send, bytes_to_send_size); + grpc_slice_buffer_reset_and_unref_internal(exec_ctx, &h->outgoing); + grpc_slice_buffer_add(&h->outgoing, to_send); + grpc_endpoint_write(exec_ctx, h->args->endpoint, &h->outgoing, + &h->on_handshake_data_sent_to_peer); + } else if (handshaker_result == NULL) { + // There is nothing to send, but need to read from peer. + grpc_endpoint_read(exec_ctx, h->args->endpoint, h->args->read_buffer, + &h->on_handshake_data_received_from_peer); + } else { + // Handshake has finished, check peer and so on. + error = check_peer_locked(exec_ctx, h); + } + return error; +} + +static void on_handshake_next_done_grpc_wrapper( + tsi_result result, void *user_data, const unsigned char *bytes_to_send, + size_t bytes_to_send_size, tsi_handshaker_result *handshaker_result) { + security_handshaker *h = user_data; + // This callback will be invoked by TSI in a non-grpc thread, so it's + // safe to create our own exec_ctx here. + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + gpr_mu_lock(&h->mu); + grpc_error *error = + on_handshake_next_done_locked(&exec_ctx, h, result, bytes_to_send, + bytes_to_send_size, handshaker_result); + if (error != GRPC_ERROR_NONE) { + security_handshake_failed_locked(&exec_ctx, h, error); + gpr_mu_unlock(&h->mu); + security_handshaker_unref(&exec_ctx, h); + } else { + gpr_mu_unlock(&h->mu); + } + grpc_exec_ctx_finish(&exec_ctx); +} + +static grpc_error *do_handshaker_next_locked( + grpc_exec_ctx *exec_ctx, security_handshaker *h, + const unsigned char *bytes_received, size_t bytes_received_size) { + // Invoke TSI handshaker. + const unsigned char *bytes_to_send = NULL; + size_t bytes_to_send_size = 0; + tsi_handshaker_result *handshaker_result = NULL; + tsi_result result = tsi_handshaker_next( + h->handshaker, bytes_received, bytes_received_size, &bytes_to_send, + &bytes_to_send_size, &handshaker_result, + &on_handshake_next_done_grpc_wrapper, h); + if (result == TSI_ASYNC) { + // Handshaker operating asynchronously. Nothing else to do here; + // callback will be invoked in a TSI thread. + return GRPC_ERROR_NONE; + } + // Handshaker returned synchronously. Invoke callback directly in + // this thread with our existing exec_ctx. + return on_handshake_next_done_locked(exec_ctx, h, result, bytes_to_send, + bytes_to_send_size, handshaker_result); } static void on_handshake_data_received_from_peer(grpc_exec_ctx *exec_ctx, @@ -231,78 +285,40 @@ static void on_handshake_data_received_from_peer(grpc_exec_ctx *exec_ctx, gpr_mu_lock(&h->mu); if (error != GRPC_ERROR_NONE || h->shutdown) { security_handshake_failed_locked( - exec_ctx, h, - GRPC_ERROR_CREATE_REFERENCING("Handshake read failed", &error, 1)); + exec_ctx, h, GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( + "Handshake read failed", &error, 1)); gpr_mu_unlock(&h->mu); security_handshaker_unref(exec_ctx, h); return; } - // Process received data. - tsi_result result = TSI_OK; - size_t consumed_slice_size = 0; + // Copy all slices received. size_t i; + size_t bytes_received_size = 0; for (i = 0; i < h->args->read_buffer->count; i++) { - consumed_slice_size = GRPC_SLICE_LENGTH(h->args->read_buffer->slices[i]); - result = tsi_handshaker_process_bytes_from_peer( - h->handshaker, GRPC_SLICE_START_PTR(h->args->read_buffer->slices[i]), - &consumed_slice_size); - if (!tsi_handshaker_is_in_progress(h->handshaker)) break; + bytes_received_size += GRPC_SLICE_LENGTH(h->args->read_buffer->slices[i]); } - if (tsi_handshaker_is_in_progress(h->handshaker)) { - /* We may need more data. */ - if (result == TSI_INCOMPLETE_DATA) { - grpc_endpoint_read(exec_ctx, h->args->endpoint, h->args->read_buffer, - &h->on_handshake_data_received_from_peer); - goto done; - } else { - error = send_handshake_bytes_to_peer_locked(exec_ctx, h); - if (error != GRPC_ERROR_NONE) { - security_handshake_failed_locked(exec_ctx, h, error); - gpr_mu_unlock(&h->mu); - security_handshaker_unref(exec_ctx, h); - return; - } - goto done; - } + if (bytes_received_size > h->handshake_buffer_size) { + h->handshake_buffer = gpr_realloc(h->handshake_buffer, bytes_received_size); + h->handshake_buffer_size = bytes_received_size; } - if (result != TSI_OK) { - security_handshake_failed_locked( - exec_ctx, h, grpc_set_tsi_error_result( - GRPC_ERROR_CREATE("Handshake failed"), result)); - gpr_mu_unlock(&h->mu); - security_handshaker_unref(exec_ctx, h); - return; - } - /* Handshake is done and successful this point. */ - bool has_left_overs_in_current_slice = - (consumed_slice_size < - GRPC_SLICE_LENGTH(h->args->read_buffer->slices[i])); - size_t num_left_overs = (has_left_overs_in_current_slice ? 1 : 0) + - h->args->read_buffer->count - i - 1; - if (num_left_overs > 0) { - /* Put the leftovers in our buffer (ownership transfered). */ - if (has_left_overs_in_current_slice) { - grpc_slice_buffer_add( - &h->left_overs, - grpc_slice_split_tail(&h->args->read_buffer->slices[i], - consumed_slice_size)); - /* split_tail above increments refcount. */ - grpc_slice_unref(h->args->read_buffer->slices[i]); - } - grpc_slice_buffer_addn( - &h->left_overs, &h->args->read_buffer->slices[i + 1], - num_left_overs - (size_t)has_left_overs_in_current_slice); + size_t offset = 0; + for (i = 0; i < h->args->read_buffer->count; i++) { + size_t slice_size = GPR_SLICE_LENGTH(h->args->read_buffer->slices[i]); + memcpy(h->handshake_buffer + offset, + GRPC_SLICE_START_PTR(h->args->read_buffer->slices[i]), slice_size); + offset += slice_size; } - // Check peer. - error = check_peer_locked(exec_ctx, h); + // Call TSI handshaker. + error = do_handshaker_next_locked(exec_ctx, h, h->handshake_buffer, + bytes_received_size); + if (error != GRPC_ERROR_NONE) { security_handshake_failed_locked(exec_ctx, h, error); gpr_mu_unlock(&h->mu); security_handshaker_unref(exec_ctx, h); - return; + } else { + gpr_mu_unlock(&h->mu); } -done: - gpr_mu_unlock(&h->mu); } static void on_handshake_data_sent_to_peer(grpc_exec_ctx *exec_ctx, void *arg, @@ -311,14 +327,14 @@ static void on_handshake_data_sent_to_peer(grpc_exec_ctx *exec_ctx, void *arg, gpr_mu_lock(&h->mu); if (error != GRPC_ERROR_NONE || h->shutdown) { security_handshake_failed_locked( - exec_ctx, h, - GRPC_ERROR_CREATE_REFERENCING("Handshake write failed", &error, 1)); + exec_ctx, h, GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( + "Handshake write failed", &error, 1)); gpr_mu_unlock(&h->mu); security_handshaker_unref(exec_ctx, h); return; } - /* We may be done. */ - if (tsi_handshaker_is_in_progress(h->handshaker)) { + // We may be done. + if (h->handshaker_result == NULL) { grpc_endpoint_read(exec_ctx, h->args->endpoint, h->args->read_buffer, &h->on_handshake_data_received_from_peer); } else { @@ -344,15 +360,17 @@ static void security_handshaker_destroy(grpc_exec_ctx *exec_ctx, } static void security_handshaker_shutdown(grpc_exec_ctx *exec_ctx, - grpc_handshaker *handshaker) { + grpc_handshaker *handshaker, + grpc_error *why) { security_handshaker *h = (security_handshaker *)handshaker; gpr_mu_lock(&h->mu); if (!h->shutdown) { h->shutdown = true; - grpc_endpoint_shutdown(exec_ctx, h->args->endpoint); - cleanup_args_for_failure_locked(h); + grpc_endpoint_shutdown(exec_ctx, h->args->endpoint, GRPC_ERROR_REF(why)); + cleanup_args_for_failure_locked(exec_ctx, h); } gpr_mu_unlock(&h->mu); + GRPC_ERROR_UNREF(why); } static void security_handshaker_do_handshake(grpc_exec_ctx *exec_ctx, @@ -365,7 +383,7 @@ static void security_handshaker_do_handshake(grpc_exec_ctx *exec_ctx, h->args = args; h->on_handshake_done = on_handshake_done; gpr_ref(&h->refs); - grpc_error *error = send_handshake_bytes_to_peer_locked(exec_ctx, h); + grpc_error *error = do_handshaker_next_locked(exec_ctx, h, NULL, 0); if (error != GRPC_ERROR_NONE) { security_handshake_failed_locked(exec_ctx, h, error); gpr_mu_unlock(&h->mu); @@ -382,8 +400,7 @@ static const grpc_handshaker_vtable security_handshaker_vtable = { static grpc_handshaker *security_handshaker_create( grpc_exec_ctx *exec_ctx, tsi_handshaker *handshaker, grpc_security_connector *connector) { - security_handshaker *h = gpr_malloc(sizeof(security_handshaker)); - memset(h, 0, sizeof(security_handshaker)); + security_handshaker *h = gpr_zalloc(sizeof(security_handshaker)); grpc_handshaker_init(&security_handshaker_vtable, &h->base); h->handshaker = handshaker; h->connector = GRPC_SECURITY_CONNECTOR_REF(connector, "handshake"); @@ -391,12 +408,14 @@ static grpc_handshaker *security_handshaker_create( gpr_ref_init(&h->refs, 1); h->handshake_buffer_size = GRPC_INITIAL_HANDSHAKE_BUFFER_SIZE; h->handshake_buffer = gpr_malloc(h->handshake_buffer_size); - grpc_closure_init(&h->on_handshake_data_sent_to_peer, - on_handshake_data_sent_to_peer, h); - grpc_closure_init(&h->on_handshake_data_received_from_peer, - on_handshake_data_received_from_peer, h); - grpc_closure_init(&h->on_peer_checked, on_peer_checked, h); - grpc_slice_buffer_init(&h->left_overs); + GRPC_CLOSURE_INIT(&h->on_handshake_data_sent_to_peer, + on_handshake_data_sent_to_peer, h, + grpc_schedule_on_exec_ctx); + GRPC_CLOSURE_INIT(&h->on_handshake_data_received_from_peer, + on_handshake_data_received_from_peer, h, + grpc_schedule_on_exec_ctx); + GRPC_CLOSURE_INIT(&h->on_peer_checked, on_peer_checked, h, + grpc_schedule_on_exec_ctx); grpc_slice_buffer_init(&h->outgoing); return &h->base; } @@ -411,16 +430,19 @@ static void fail_handshaker_destroy(grpc_exec_ctx *exec_ctx, } static void fail_handshaker_shutdown(grpc_exec_ctx *exec_ctx, - grpc_handshaker *handshaker) {} + grpc_handshaker *handshaker, + grpc_error *why) { + GRPC_ERROR_UNREF(why); +} static void fail_handshaker_do_handshake(grpc_exec_ctx *exec_ctx, grpc_handshaker *handshaker, grpc_tcp_server_acceptor *acceptor, grpc_closure *on_handshake_done, grpc_handshaker_args *args) { - grpc_exec_ctx_sched(exec_ctx, on_handshake_done, - GRPC_ERROR_CREATE("Failed to create security handshaker"), - NULL); + GRPC_CLOSURE_SCHED(exec_ctx, on_handshake_done, + GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "Failed to create security handshaker")); } static const grpc_handshaker_vtable fail_handshaker_vtable = { @@ -433,6 +455,45 @@ static grpc_handshaker *fail_handshaker_create() { return h; } +// +// handshaker factories +// + +static void client_handshaker_factory_add_handshakers( + grpc_exec_ctx *exec_ctx, grpc_handshaker_factory *handshaker_factory, + const grpc_channel_args *args, grpc_handshake_manager *handshake_mgr) { + grpc_channel_security_connector *security_connector = + (grpc_channel_security_connector *)grpc_security_connector_find_in_args( + args); + grpc_channel_security_connector_add_handshakers(exec_ctx, security_connector, + handshake_mgr); +} + +static void server_handshaker_factory_add_handshakers( + grpc_exec_ctx *exec_ctx, grpc_handshaker_factory *hf, + const grpc_channel_args *args, grpc_handshake_manager *handshake_mgr) { + grpc_server_security_connector *security_connector = + (grpc_server_security_connector *)grpc_security_connector_find_in_args( + args); + grpc_server_security_connector_add_handshakers(exec_ctx, security_connector, + handshake_mgr); +} + +static void handshaker_factory_destroy( + grpc_exec_ctx *exec_ctx, grpc_handshaker_factory *handshaker_factory) {} + +static const grpc_handshaker_factory_vtable client_handshaker_factory_vtable = { + client_handshaker_factory_add_handshakers, handshaker_factory_destroy}; + +static grpc_handshaker_factory client_handshaker_factory = { + &client_handshaker_factory_vtable}; + +static const grpc_handshaker_factory_vtable server_handshaker_factory_vtable = { + server_handshaker_factory_add_handshakers, handshaker_factory_destroy}; + +static grpc_handshaker_factory server_handshaker_factory = { + &server_handshaker_factory_vtable}; + // // exported functions // @@ -448,3 +509,10 @@ grpc_handshaker *grpc_security_handshaker_create( return security_handshaker_create(exec_ctx, handshaker, connector); } } + +void grpc_security_register_handshaker_factories() { + grpc_handshaker_factory_register(false /* at_start */, HANDSHAKER_CLIENT, + &client_handshaker_factory); + grpc_handshaker_factory_register(false /* at_start */, HANDSHAKER_SERVER, + &server_handshaker_factory); +} diff --git a/Sources/CgRPC/src/core/lib/security/transport/security_handshaker.h b/Sources/CgRPC/src/core/lib/security/transport/security_handshaker.h index 5ddbf4b45..95bf127fc 100644 --- a/Sources/CgRPC/src/core/lib/security/transport/security_handshaker.h +++ b/Sources/CgRPC/src/core/lib/security/transport/security_handshaker.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -43,4 +28,7 @@ grpc_handshaker *grpc_security_handshaker_create( grpc_exec_ctx *exec_ctx, tsi_handshaker *handshaker, grpc_security_connector *connector); +/// Registers security handshaker factories. +void grpc_security_register_handshaker_factories(); + #endif /* GRPC_CORE_LIB_SECURITY_TRANSPORT_SECURITY_HANDSHAKER_H */ diff --git a/Sources/CgRPC/src/core/lib/security/transport/server_auth_filter.c b/Sources/CgRPC/src/core/lib/security/transport/server_auth_filter.c index e6a242e68..9bf3f0ca0 100644 --- a/Sources/CgRPC/src/core/lib/security/transport/server_auth_filter.c +++ b/Sources/CgRPC/src/core/lib/security/transport/server_auth_filter.c @@ -1,54 +1,35 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 +#include +#include + #include "src/core/lib/security/context/security_context.h" #include "src/core/lib/security/credentials/credentials.h" #include "src/core/lib/security/transport/auth_filters.h" - -#include -#include +#include "src/core/lib/slice/slice_internal.h" typedef struct call_data { - grpc_metadata_batch *recv_initial_metadata; - /* Closure to call when finished with the auth_on_recv hook. */ - grpc_closure *on_done_recv; - /* Receive closures are chained: we inject this closure as the on_done_recv - up-call on transport_op, and remember to call our on_done_recv member after - handling it. */ - grpc_closure auth_on_recv; - grpc_transport_stream_op *transport_op; + grpc_transport_stream_op_batch *recv_initial_metadata_batch; + grpc_closure *original_recv_initial_metadata_ready; + grpc_closure recv_initial_metadata_ready; grpc_metadata_array md; const grpc_metadata *consumed_md; size_t num_consumed_md; @@ -67,47 +48,34 @@ static grpc_metadata_array metadata_batch_to_md_array( grpc_metadata_array_init(&result); for (l = batch->list.head; l != NULL; l = l->next) { grpc_metadata *usr_md = NULL; - grpc_mdelem *md = l->md; - grpc_mdstr *key = md->key; - grpc_mdstr *value = md->value; + grpc_mdelem md = l->md; + grpc_slice key = GRPC_MDKEY(md); + grpc_slice value = GRPC_MDVALUE(md); if (result.count == result.capacity) { result.capacity = GPR_MAX(result.capacity + 8, result.capacity * 2); result.metadata = gpr_realloc(result.metadata, result.capacity * sizeof(grpc_metadata)); } usr_md = &result.metadata[result.count++]; - usr_md->key = grpc_mdstr_as_c_string(key); - usr_md->value = grpc_mdstr_as_c_string(value); - usr_md->value_length = GRPC_SLICE_LENGTH(value->slice); + usr_md->key = grpc_slice_ref_internal(key); + usr_md->value = grpc_slice_ref_internal(value); } return result; } -static grpc_mdelem *remove_consumed_md(void *user_data, grpc_mdelem *md) { +static grpc_filtered_mdelem remove_consumed_md(grpc_exec_ctx *exec_ctx, + void *user_data, + grpc_mdelem md) { grpc_call_element *elem = user_data; call_data *calld = elem->call_data; size_t i; for (i = 0; i < calld->num_consumed_md; i++) { const grpc_metadata *consumed_md = &calld->consumed_md[i]; - /* Maybe we could do a pointer comparison but we do not have any guarantee - that the metadata processor used the same pointers for consumed_md in the - callback. */ - if (GRPC_SLICE_LENGTH(md->key->slice) != strlen(consumed_md->key) || - GRPC_SLICE_LENGTH(md->value->slice) != consumed_md->value_length) { - continue; - } - if (memcmp(GRPC_SLICE_START_PTR(md->key->slice), consumed_md->key, - GRPC_SLICE_LENGTH(md->key->slice)) == 0 && - memcmp(GRPC_SLICE_START_PTR(md->value->slice), consumed_md->value, - GRPC_SLICE_LENGTH(md->value->slice)) == 0) { - return NULL; /* Delete. */ - } + if (grpc_slice_eq(GRPC_MDKEY(md), consumed_md->key) && + grpc_slice_eq(GRPC_MDVALUE(md), consumed_md->value)) + return GRPC_FILTERED_REMOVE(); } - return md; -} - -static void destroy_op(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { - gpr_free(arg); + return GRPC_FILTERED_MDELEM(md); } /* called from application code */ @@ -117,144 +85,117 @@ static void on_md_processing_done( grpc_status_code status, const char *error_details) { grpc_call_element *elem = user_data; call_data *calld = elem->call_data; + grpc_transport_stream_op_batch *batch = calld->recv_initial_metadata_batch; grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - /* TODO(jboeuf): Implement support for response_md. */ if (response_md != NULL && num_response_md > 0) { gpr_log(GPR_INFO, "response_md in auth metadata processing not supported for now. " "Ignoring..."); } - + grpc_error *error = GRPC_ERROR_NONE; if (status == GRPC_STATUS_OK) { calld->consumed_md = consumed_md; calld->num_consumed_md = num_consumed_md; - grpc_metadata_batch_filter(calld->recv_initial_metadata, remove_consumed_md, - elem); - grpc_metadata_array_destroy(&calld->md); - grpc_exec_ctx_sched(&exec_ctx, calld->on_done_recv, GRPC_ERROR_NONE, NULL); + error = grpc_metadata_batch_filter( + &exec_ctx, batch->payload->recv_initial_metadata.recv_initial_metadata, + remove_consumed_md, elem, "Response metadata filtering error"); } else { - grpc_slice message; - grpc_transport_stream_op *close_op = gpr_malloc(sizeof(*close_op)); - memset(close_op, 0, sizeof(*close_op)); - grpc_metadata_array_destroy(&calld->md); - error_details = error_details != NULL - ? error_details - : "Authentication metadata processing failed."; - message = grpc_slice_from_copied_string(error_details); - calld->transport_op->send_initial_metadata = NULL; - if (calld->transport_op->send_message != NULL) { - grpc_byte_stream_destroy(&exec_ctx, calld->transport_op->send_message); - calld->transport_op->send_message = NULL; + if (error_details == NULL) { + error_details = "Authentication metadata processing failed."; } - calld->transport_op->send_trailing_metadata = NULL; - close_op->on_complete = grpc_closure_create(destroy_op, close_op); - grpc_transport_stream_op_add_close(close_op, status, &message); - grpc_call_next_op(&exec_ctx, elem, close_op); - grpc_exec_ctx_sched(&exec_ctx, calld->on_done_recv, - grpc_error_set_int(GRPC_ERROR_CREATE(error_details), - GRPC_ERROR_INT_GRPC_STATUS, status), - NULL); + error = + grpc_error_set_int(GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_details), + GRPC_ERROR_INT_GRPC_STATUS, status); } - + for (size_t i = 0; i < calld->md.count; i++) { + grpc_slice_unref_internal(&exec_ctx, calld->md.metadata[i].key); + grpc_slice_unref_internal(&exec_ctx, calld->md.metadata[i].value); + } + grpc_metadata_array_destroy(&calld->md); + GRPC_CLOSURE_SCHED(&exec_ctx, calld->original_recv_initial_metadata_ready, + error); grpc_exec_ctx_finish(&exec_ctx); } -static void auth_on_recv(grpc_exec_ctx *exec_ctx, void *user_data, - grpc_error *error) { - grpc_call_element *elem = user_data; - call_data *calld = elem->call_data; +static void recv_initial_metadata_ready(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error) { + grpc_call_element *elem = arg; channel_data *chand = elem->channel_data; + call_data *calld = elem->call_data; + grpc_transport_stream_op_batch *batch = calld->recv_initial_metadata_batch; if (error == GRPC_ERROR_NONE) { - if (chand->creds->processor.process != NULL) { - calld->md = metadata_batch_to_md_array(calld->recv_initial_metadata); + if (chand->creds != NULL && chand->creds->processor.process != NULL) { + calld->md = metadata_batch_to_md_array( + batch->payload->recv_initial_metadata.recv_initial_metadata); chand->creds->processor.process( chand->creds->processor.state, calld->auth_context, calld->md.metadata, calld->md.count, on_md_processing_done, elem); return; } } - grpc_exec_ctx_sched(exec_ctx, calld->on_done_recv, GRPC_ERROR_REF(error), - NULL); + GRPC_CLOSURE_RUN(exec_ctx, calld->original_recv_initial_metadata_ready, + GRPC_ERROR_REF(error)); } -static void set_recv_ops_md_callbacks(grpc_call_element *elem, - grpc_transport_stream_op *op) { +static void auth_start_transport_stream_op_batch( + grpc_exec_ctx *exec_ctx, grpc_call_element *elem, + grpc_transport_stream_op_batch *batch) { call_data *calld = elem->call_data; - - if (op->recv_initial_metadata != NULL) { - /* substitute our callback for the higher callback */ - calld->recv_initial_metadata = op->recv_initial_metadata; - calld->on_done_recv = op->recv_initial_metadata_ready; - op->recv_initial_metadata_ready = &calld->auth_on_recv; - calld->transport_op = op; + if (batch->recv_initial_metadata) { + // Inject our callback. + calld->recv_initial_metadata_batch = batch; + calld->original_recv_initial_metadata_ready = + batch->payload->recv_initial_metadata.recv_initial_metadata_ready; + batch->payload->recv_initial_metadata.recv_initial_metadata_ready = + &calld->recv_initial_metadata_ready; } -} - -/* Called either: - - in response to an API call (or similar) from above, to send something - - a network event (or similar) from below, to receive something - op contains type and call direction information, in addition to the data - that is being sent or received. */ -static void auth_start_transport_op(grpc_exec_ctx *exec_ctx, - grpc_call_element *elem, - grpc_transport_stream_op *op) { - set_recv_ops_md_callbacks(elem, op); - grpc_call_next_op(exec_ctx, elem, op); + grpc_call_next_op(exec_ctx, elem, batch); } /* Constructor for call_data */ static grpc_error *init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, - grpc_call_element_args *args) { - /* grab pointers to our data from the call element */ + const grpc_call_element_args *args) { call_data *calld = elem->call_data; channel_data *chand = elem->channel_data; - grpc_server_security_context *server_ctx = NULL; - - /* initialize members */ - memset(calld, 0, sizeof(*calld)); - grpc_closure_init(&calld->auth_on_recv, auth_on_recv, elem); - + GRPC_CLOSURE_INIT(&calld->recv_initial_metadata_ready, + recv_initial_metadata_ready, elem, + grpc_schedule_on_exec_ctx); + // Create server security context. Set its auth context from channel + // data and save it in the call context. + grpc_server_security_context *server_ctx = + grpc_server_security_context_create(); + server_ctx->auth_context = grpc_auth_context_create(chand->auth_context); + calld->auth_context = server_ctx->auth_context; if (args->context[GRPC_CONTEXT_SECURITY].value != NULL) { args->context[GRPC_CONTEXT_SECURITY].destroy( args->context[GRPC_CONTEXT_SECURITY].value); } - - server_ctx = grpc_server_security_context_create(); - server_ctx->auth_context = grpc_auth_context_create(chand->auth_context); - calld->auth_context = server_ctx->auth_context; - args->context[GRPC_CONTEXT_SECURITY].value = server_ctx; args->context[GRPC_CONTEXT_SECURITY].destroy = grpc_server_security_context_destroy; - return GRPC_ERROR_NONE; } /* Destructor for call_data */ static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, const grpc_call_final_info *final_info, - void *ignored) {} + grpc_closure *ignored) {} /* Constructor for channel_data */ static grpc_error *init_channel_elem(grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, grpc_channel_element_args *args) { + GPR_ASSERT(!args->is_last); + channel_data *chand = elem->channel_data; grpc_auth_context *auth_context = grpc_find_auth_context_in_args(args->channel_args); - grpc_server_credentials *creds = - grpc_find_server_credentials_in_args(args->channel_args); - /* grab pointers to our data from the channel element */ - channel_data *chand = elem->channel_data; - - GPR_ASSERT(!args->is_last); GPR_ASSERT(auth_context != NULL); - GPR_ASSERT(creds != NULL); - - /* initialize members */ 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); return GRPC_ERROR_NONE; } @@ -262,14 +203,13 @@ static grpc_error *init_channel_elem(grpc_exec_ctx *exec_ctx, /* Destructor for channel data */ static void destroy_channel_elem(grpc_exec_ctx *exec_ctx, grpc_channel_element *elem) { - /* grab pointers to our data from the channel element */ channel_data *chand = elem->channel_data; GRPC_AUTH_CONTEXT_UNREF(chand->auth_context, "server_auth_filter"); - grpc_server_credentials_unref(chand->creds); + grpc_server_credentials_unref(exec_ctx, chand->creds); } const grpc_channel_filter grpc_server_auth_filter = { - auth_start_transport_op, + auth_start_transport_stream_op_batch, grpc_channel_next_op, sizeof(call_data), init_call_elem, diff --git a/Sources/CgRPC/src/core/lib/security/transport/tsi_error.c b/Sources/CgRPC/src/core/lib/security/transport/tsi_error.c index afc173356..72f9600e8 100644 --- a/Sources/CgRPC/src/core/lib/security/transport/tsi_error.c +++ b/Sources/CgRPC/src/core/lib/security/transport/tsi_error.c @@ -1,40 +1,27 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 "src/core/lib/security/transport/tsi_error.h" grpc_error *grpc_set_tsi_error_result(grpc_error *error, tsi_result result) { - return grpc_error_set_int(grpc_error_set_str(error, GRPC_ERROR_STR_TSI_ERROR, - tsi_result_to_string(result)), - GRPC_ERROR_INT_TSI_CODE, result); + return grpc_error_set_int( + grpc_error_set_str( + error, GRPC_ERROR_STR_TSI_ERROR, + grpc_slice_from_static_string(tsi_result_to_string(result))), + GRPC_ERROR_INT_TSI_CODE, result); } diff --git a/Sources/CgRPC/src/core/lib/security/transport/tsi_error.h b/Sources/CgRPC/src/core/lib/security/transport/tsi_error.h index 636fbb89c..87a63a8a7 100644 --- a/Sources/CgRPC/src/core/lib/security/transport/tsi_error.h +++ b/Sources/CgRPC/src/core/lib/security/transport/tsi_error.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -35,7 +20,7 @@ #define GRPC_CORE_LIB_SECURITY_TRANSPORT_TSI_ERROR_H #include "src/core/lib/iomgr/error.h" -#include "src/core/lib/tsi/transport_security_interface.h" +#include "src/core/tsi/transport_security_interface.h" grpc_error *grpc_set_tsi_error_result(grpc_error *error, tsi_result result); diff --git a/Sources/CgRPC/src/core/lib/security/util/b64.h b/Sources/CgRPC/src/core/lib/security/util/b64.h deleted file mode 100644 index 6ea0b5365..000000000 --- a/Sources/CgRPC/src/core/lib/security/util/b64.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#ifndef GRPC_CORE_LIB_SECURITY_UTIL_B64_H -#define GRPC_CORE_LIB_SECURITY_UTIL_B64_H - -#include - -/* Encodes data using base64. It is the caller's responsability to free - the returned char * using gpr_free. Returns NULL on NULL input. */ -char *grpc_base64_encode(const void *data, size_t data_size, int url_safe, - int multiline); - -/* Decodes data according to the base64 specification. Returns an empty - slice in case of failure. */ -grpc_slice grpc_base64_decode(const char *b64, int url_safe); - -/* Same as above except that the length is provided by the caller. */ -grpc_slice grpc_base64_decode_with_len(const char *b64, size_t b64_len, - int url_safe); - -#endif /* GRPC_CORE_LIB_SECURITY_UTIL_B64_H */ diff --git a/Sources/CgRPC/src/core/lib/security/util/json_util.c b/Sources/CgRPC/src/core/lib/security/util/json_util.c index 7eed039ba..d847addef 100644 --- a/Sources/CgRPC/src/core/lib/security/util/json_util.c +++ b/Sources/CgRPC/src/core/lib/security/util/json_util.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/security/util/json_util.h b/Sources/CgRPC/src/core/lib/security/util/json_util.h index 137900593..5ea831e27 100644 --- a/Sources/CgRPC/src/core/lib/security/util/json_util.h +++ b/Sources/CgRPC/src/core/lib/security/util/json_util.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/security/util/b64.c b/Sources/CgRPC/src/core/lib/slice/b64.c similarity index 76% rename from Sources/CgRPC/src/core/lib/security/util/b64.c rename to Sources/CgRPC/src/core/lib/slice/b64.c index 4892e8e62..d02f303bd 100644 --- a/Sources/CgRPC/src/core/lib/security/util/b64.c +++ b/Sources/CgRPC/src/core/lib/slice/b64.c @@ -1,37 +1,22 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 "src/core/lib/security/util/b64.h" +#include "src/core/lib/slice/b64.h" #include #include @@ -40,6 +25,8 @@ #include #include +#include "src/core/lib/slice/slice_internal.h" + /* --- Constants. --- */ static const int8_t base64_bytes[] = { @@ -69,15 +56,31 @@ static const char base64_url_safe_chars[] = char *grpc_base64_encode(const void *vdata, size_t data_size, int url_safe, int multiline) { - const unsigned char *data = vdata; - const char *base64_chars = - url_safe ? base64_url_safe_chars : base64_url_unsafe_chars; + size_t result_projected_size = + grpc_base64_estimate_encoded_size(data_size, url_safe, multiline); + char *result = gpr_malloc(result_projected_size); + grpc_base64_encode_core(result, vdata, data_size, url_safe, multiline); + return result; +} + +size_t grpc_base64_estimate_encoded_size(size_t data_size, int url_safe, + int multiline) { size_t result_projected_size = 4 * ((data_size + 3) / 3) + 2 * (multiline ? (data_size / (3 * GRPC_BASE64_MULTILINE_NUM_BLOCKS)) : 0) + 1; - char *result = gpr_malloc(result_projected_size); + return result_projected_size; +} + +void grpc_base64_encode_core(char *result, const void *vdata, size_t data_size, + int url_safe, int multiline) { + const unsigned char *data = vdata; + const char *base64_chars = + url_safe ? base64_url_safe_chars : base64_url_unsafe_chars; + const size_t result_projected_size = + grpc_base64_estimate_encoded_size(data_size, url_safe, multiline); + char *current = result; size_t num_blocks = 0; size_t i = 0; @@ -117,11 +120,11 @@ char *grpc_base64_encode(const void *vdata, size_t data_size, int url_safe, GPR_ASSERT(current >= result); GPR_ASSERT((uintptr_t)(current - result) < result_projected_size); result[current - result] = '\0'; - return result; } -grpc_slice grpc_base64_decode(const char *b64, int url_safe) { - return grpc_base64_decode_with_len(b64, strlen(b64), url_safe); +grpc_slice grpc_base64_decode(grpc_exec_ctx *exec_ctx, const char *b64, + int url_safe) { + return grpc_base64_decode_with_len(exec_ctx, b64, strlen(b64), url_safe); } static void decode_one_char(const unsigned char *codes, unsigned char *result, @@ -182,9 +185,9 @@ static int decode_group(const unsigned char *codes, size_t num_codes, return 1; } -grpc_slice grpc_base64_decode_with_len(const char *b64, size_t b64_len, - int url_safe) { - grpc_slice result = grpc_slice_malloc(b64_len); +grpc_slice grpc_base64_decode_with_len(grpc_exec_ctx *exec_ctx, const char *b64, + size_t b64_len, int url_safe) { + grpc_slice result = GRPC_SLICE_MALLOC(b64_len); unsigned char *current = GRPC_SLICE_START_PTR(result); size_t result_size = 0; unsigned char codes[4]; @@ -228,6 +231,6 @@ grpc_slice grpc_base64_decode_with_len(const char *b64, size_t b64_len, return result; fail: - grpc_slice_unref(result); - return gpr_empty_slice(); + grpc_slice_unref_internal(exec_ctx, result); + return grpc_empty_slice(); } diff --git a/Sources/CgRPC/src/core/lib/slice/b64.h b/Sources/CgRPC/src/core/lib/slice/b64.h new file mode 100644 index 000000000..3fd15febe --- /dev/null +++ b/Sources/CgRPC/src/core/lib/slice/b64.h @@ -0,0 +1,50 @@ +/* + * + * 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 GRPC_CORE_LIB_SLICE_B64_H +#define GRPC_CORE_LIB_SLICE_B64_H + +#include + +/* Encodes data using base64. It is the caller's responsability to free + the returned char * using gpr_free. Returns NULL on NULL input. + TODO(makdharma) : change the flags to bool from int */ +char *grpc_base64_encode(const void *data, size_t data_size, int url_safe, + int multiline); + +/* estimate the upper bound on size of base64 encoded data. The actual size + * is guaranteed to be less than or equal to the size returned here. */ +size_t grpc_base64_estimate_encoded_size(size_t data_size, int url_safe, + int multiline); + +/* Encodes data using base64 and write it to memory pointed to by result. It is + * the caller's responsiblity to allocate enough memory in |result| to fit the + * encoded data. */ +void grpc_base64_encode_core(char *result, const void *vdata, size_t data_size, + int url_safe, int multiline); + +/* Decodes data according to the base64 specification. Returns an empty + slice in case of failure. */ +grpc_slice grpc_base64_decode(grpc_exec_ctx *exec_ctx, const char *b64, + int url_safe); + +/* Same as above except that the length is provided by the caller. */ +grpc_slice grpc_base64_decode_with_len(grpc_exec_ctx *exec_ctx, const char *b64, + size_t b64_len, int url_safe); + +#endif /* GRPC_CORE_LIB_SLICE_B64_H */ diff --git a/Sources/CgRPC/src/core/lib/slice/percent_encoding.c b/Sources/CgRPC/src/core/lib/slice/percent_encoding.c index b9e35f1c7..effc8d7ad 100644 --- a/Sources/CgRPC/src/core/lib/slice/percent_encoding.c +++ b/Sources/CgRPC/src/core/lib/slice/percent_encoding.c @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -35,6 +20,8 @@ #include +#include "src/core/lib/slice/slice_internal.h" + const uint8_t grpc_url_percent_encoding_unreserved_bytes[256 / 8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0xff, 0x03, 0xfe, 0xff, 0xff, 0x87, 0xfe, 0xff, 0xff, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -66,10 +53,10 @@ grpc_slice grpc_percent_encode_slice(grpc_slice slice, } // no unreserved bytes: return the string unmodified if (!any_reserved_bytes) { - return grpc_slice_ref(slice); + return grpc_slice_ref_internal(slice); } // second pass: actually encode - grpc_slice out = grpc_slice_malloc(output_length); + grpc_slice out = GRPC_SLICE_MALLOC(output_length); uint8_t *q = GRPC_SLICE_START_PTR(out); for (p = slice_start; p < slice_end; p++) { if (is_unreserved_character(*p, unreserved_bytes)) { @@ -119,11 +106,11 @@ bool grpc_strict_percent_decode_slice(grpc_slice slice_in, } } if (!any_percent_encoded_stuff) { - *slice_out = grpc_slice_ref(slice_in); + *slice_out = grpc_slice_ref_internal(slice_in); return true; } p = GRPC_SLICE_START_PTR(slice_in); - *slice_out = grpc_slice_malloc(out_length); + *slice_out = GRPC_SLICE_MALLOC(out_length); uint8_t *q = GRPC_SLICE_START_PTR(*slice_out); while (p != in_end) { if (*p == '%') { @@ -158,10 +145,10 @@ grpc_slice grpc_permissive_percent_decode_slice(grpc_slice slice_in) { } } if (!any_percent_encoded_stuff) { - return grpc_slice_ref(slice_in); + return grpc_slice_ref_internal(slice_in); } p = GRPC_SLICE_START_PTR(slice_in); - grpc_slice out = grpc_slice_malloc(out_length); + grpc_slice out = GRPC_SLICE_MALLOC(out_length); uint8_t *q = GRPC_SLICE_START_PTR(out); while (p != in_end) { if (*p == '%') { diff --git a/Sources/CgRPC/src/core/lib/slice/percent_encoding.h b/Sources/CgRPC/src/core/lib/slice/percent_encoding.h index 189bdbe31..faae26a68 100644 --- a/Sources/CgRPC/src/core/lib/slice/percent_encoding.h +++ b/Sources/CgRPC/src/core/lib/slice/percent_encoding.h @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/slice/slice.c b/Sources/CgRPC/src/core/lib/slice/slice.c index 52977e6d9..8a8087805 100644 --- a/Sources/CgRPC/src/core/lib/slice/slice.c +++ b/Sources/CgRPC/src/core/lib/slice/slice.c @@ -1,77 +1,100 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 "src/core/lib/slice/slice_internal.h" + #include #include #include #include -grpc_slice gpr_empty_slice(void) { +#include "src/core/lib/iomgr/exec_ctx.h" + +char *grpc_slice_to_c_string(grpc_slice slice) { + char *out = gpr_malloc(GRPC_SLICE_LENGTH(slice) + 1); + memcpy(out, GRPC_SLICE_START_PTR(slice), GRPC_SLICE_LENGTH(slice)); + out[GRPC_SLICE_LENGTH(slice)] = 0; + return out; +} + +grpc_slice grpc_empty_slice(void) { grpc_slice out; - out.refcount = 0; + out.refcount = NULL; out.data.inlined.length = 0; return out; } -grpc_slice grpc_slice_ref(grpc_slice slice) { +grpc_slice grpc_slice_copy(grpc_slice s) { + grpc_slice out = GRPC_SLICE_MALLOC(GRPC_SLICE_LENGTH(s)); + memcpy(GRPC_SLICE_START_PTR(out), GRPC_SLICE_START_PTR(s), + GRPC_SLICE_LENGTH(s)); + return out; +} + +grpc_slice grpc_slice_ref_internal(grpc_slice slice) { if (slice.refcount) { - slice.refcount->ref(slice.refcount); + slice.refcount->vtable->ref(slice.refcount); } return slice; } -void grpc_slice_unref(grpc_slice slice) { +void grpc_slice_unref_internal(grpc_exec_ctx *exec_ctx, grpc_slice slice) { if (slice.refcount) { - slice.refcount->unref(slice.refcount); + slice.refcount->vtable->unref(exec_ctx, slice.refcount); } } +/* Public API */ +grpc_slice grpc_slice_ref(grpc_slice slice) { + return grpc_slice_ref_internal(slice); +} + +/* Public API */ +void grpc_slice_unref(grpc_slice slice) { + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + grpc_slice_unref_internal(&exec_ctx, slice); + grpc_exec_ctx_finish(&exec_ctx); +} + /* grpc_slice_from_static_string support structure - a refcount that does nothing */ -static void noop_ref_or_unref(void *unused) {} +static void noop_ref(void *unused) {} +static void noop_unref(grpc_exec_ctx *exec_ctx, void *unused) {} -static grpc_slice_refcount noop_refcount = {noop_ref_or_unref, - noop_ref_or_unref}; +static const grpc_slice_refcount_vtable noop_refcount_vtable = { + noop_ref, noop_unref, grpc_slice_default_eq_impl, + grpc_slice_default_hash_impl}; +static grpc_slice_refcount noop_refcount = {&noop_refcount_vtable, + &noop_refcount}; -grpc_slice grpc_slice_from_static_string(const char *s) { +grpc_slice grpc_slice_from_static_buffer(const void *s, size_t len) { grpc_slice slice; slice.refcount = &noop_refcount; slice.data.refcounted.bytes = (uint8_t *)s; - slice.data.refcounted.length = strlen(s); + slice.data.refcounted.length = len; return slice; } +grpc_slice grpc_slice_from_static_string(const char *s) { + return grpc_slice_from_static_buffer(s, strlen(s)); +} + /* grpc_slice_new support structures - we create a refcount object extended with the user provided data pointer & destroy function */ typedef struct new_slice_refcount { @@ -86,7 +109,7 @@ static void new_slice_ref(void *p) { gpr_ref(&r->refs); } -static void new_slice_unref(void *p) { +static void new_slice_unref(grpc_exec_ctx *exec_ctx, void *p) { new_slice_refcount *r = p; if (gpr_unref(&r->refs)) { r->user_destroy(r->user_data); @@ -94,14 +117,18 @@ static void new_slice_unref(void *p) { } } +static const grpc_slice_refcount_vtable new_slice_vtable = { + new_slice_ref, new_slice_unref, grpc_slice_default_eq_impl, + grpc_slice_default_hash_impl}; + grpc_slice grpc_slice_new_with_user_data(void *p, size_t len, void (*destroy)(void *), void *user_data) { grpc_slice slice; new_slice_refcount *rc = gpr_malloc(sizeof(new_slice_refcount)); gpr_ref_init(&rc->refs, 1); - rc->rc.ref = new_slice_ref; - rc->rc.unref = new_slice_unref; + rc->rc.vtable = &new_slice_vtable; + rc->rc.sub_refcount = &rc->rc; rc->user_destroy = destroy; rc->user_data = user_data; @@ -131,7 +158,7 @@ static void new_with_len_ref(void *p) { gpr_ref(&r->refs); } -static void new_with_len_unref(void *p) { +static void new_with_len_unref(grpc_exec_ctx *exec_ctx, void *p) { new_with_len_slice_refcount *r = p; if (gpr_unref(&r->refs)) { r->user_destroy(r->user_data, r->user_length); @@ -139,14 +166,18 @@ static void new_with_len_unref(void *p) { } } +static const grpc_slice_refcount_vtable new_with_len_vtable = { + new_with_len_ref, new_with_len_unref, grpc_slice_default_eq_impl, + grpc_slice_default_hash_impl}; + grpc_slice grpc_slice_new_with_len(void *p, size_t len, void (*destroy)(void *, size_t)) { grpc_slice slice; new_with_len_slice_refcount *rc = gpr_malloc(sizeof(new_with_len_slice_refcount)); gpr_ref_init(&rc->refs, 1); - rc->rc.ref = new_with_len_ref; - rc->rc.unref = new_with_len_unref; + rc->rc.vtable = &new_with_len_vtable; + rc->rc.sub_refcount = &rc->rc; rc->user_destroy = destroy; rc->user_data = p; rc->user_length = len; @@ -158,7 +189,8 @@ grpc_slice grpc_slice_new_with_len(void *p, size_t len, } grpc_slice grpc_slice_from_copied_buffer(const char *source, size_t length) { - grpc_slice slice = grpc_slice_malloc(length); + if (length == 0) return grpc_empty_slice(); + grpc_slice slice = GRPC_SLICE_MALLOC(length); memcpy(GRPC_SLICE_START_PTR(slice), source, length); return slice; } @@ -177,42 +209,53 @@ static void malloc_ref(void *p) { gpr_ref(&r->refs); } -static void malloc_unref(void *p) { +static void malloc_unref(grpc_exec_ctx *exec_ctx, void *p) { malloc_refcount *r = p; if (gpr_unref(&r->refs)) { gpr_free(r); } } +static const grpc_slice_refcount_vtable malloc_vtable = { + malloc_ref, malloc_unref, grpc_slice_default_eq_impl, + grpc_slice_default_hash_impl}; + +grpc_slice grpc_slice_malloc_large(size_t length) { + grpc_slice slice; + + /* Memory layout used by the slice created here: + + +-----------+----------------------------------------------------------+ + | refcount | bytes | + +-----------+----------------------------------------------------------+ + + refcount is a malloc_refcount + bytes is an array of bytes of the requested length + Both parts are placed in the same allocation returned from gpr_malloc */ + malloc_refcount *rc = gpr_malloc(sizeof(malloc_refcount) + length); + + /* Initial refcount on rc is 1 - and it's up to the caller to release + this reference. */ + gpr_ref_init(&rc->refs, 1); + + rc->base.vtable = &malloc_vtable; + rc->base.sub_refcount = &rc->base; + + /* Build up the slice to be returned. */ + /* The slices refcount points back to the allocated block. */ + slice.refcount = &rc->base; + /* The data bytes are placed immediately after the refcount struct */ + slice.data.refcounted.bytes = (uint8_t *)(rc + 1); + /* And the length of the block is set to the requested length */ + slice.data.refcounted.length = length; + return slice; +} + grpc_slice grpc_slice_malloc(size_t length) { grpc_slice slice; if (length > sizeof(slice.data.inlined.bytes)) { - /* Memory layout used by the slice created here: - - +-----------+----------------------------------------------------------+ - | refcount | bytes | - +-----------+----------------------------------------------------------+ - - refcount is a malloc_refcount - bytes is an array of bytes of the requested length - Both parts are placed in the same allocation returned from gpr_malloc */ - malloc_refcount *rc = gpr_malloc(sizeof(malloc_refcount) + length); - - /* Initial refcount on rc is 1 - and it's up to the caller to release - this reference. */ - gpr_ref_init(&rc->refs, 1); - - rc->base.ref = malloc_ref; - rc->base.unref = malloc_unref; - - /* Build up the slice to be returned. */ - /* The slices refcount points back to the allocated block. */ - slice.refcount = &rc->base; - /* The data bytes are placed immediately after the refcount struct */ - slice.data.refcounted.bytes = (uint8_t *)(rc + 1); - /* And the length of the block is set to the requested length */ - slice.data.refcounted.length = length; + return grpc_slice_malloc_large(length); } else { /* small slice: just inline the data */ slice.refcount = NULL; @@ -231,7 +274,7 @@ grpc_slice grpc_slice_sub_no_ref(grpc_slice source, size_t begin, size_t end) { GPR_ASSERT(source.data.refcounted.length >= end); /* Build the result */ - subset.refcount = source.refcount; + subset.refcount = source.refcount->sub_refcount; /* Point into the source array */ subset.data.refcounted.bytes = source.data.refcounted.bytes + begin; subset.data.refcounted.length = end - begin; @@ -257,12 +300,13 @@ grpc_slice grpc_slice_sub(grpc_slice source, size_t begin, size_t end) { } else { subset = grpc_slice_sub_no_ref(source, begin, end); /* Bump the refcount */ - subset.refcount->ref(subset.refcount); + subset.refcount->vtable->ref(subset.refcount); } return subset; } -grpc_slice grpc_slice_split_tail(grpc_slice *source, size_t split) { +grpc_slice grpc_slice_split_tail_maybe_ref(grpc_slice *source, size_t split, + grpc_slice_ref_whom ref_whom) { grpc_slice tail; if (source->refcount == NULL) { @@ -276,17 +320,32 @@ grpc_slice grpc_slice_split_tail(grpc_slice *source, size_t split) { } else { size_t tail_length = source->data.refcounted.length - split; GPR_ASSERT(source->data.refcounted.length >= split); - if (tail_length < sizeof(tail.data.inlined.bytes)) { + if (tail_length < sizeof(tail.data.inlined.bytes) && + ref_whom != GRPC_SLICE_REF_TAIL) { /* Copy out the bytes - it'll be cheaper than refcounting */ tail.refcount = NULL; tail.data.inlined.length = (uint8_t)tail_length; memcpy(tail.data.inlined.bytes, source->data.refcounted.bytes + split, tail_length); + source->refcount = source->refcount->sub_refcount; } else { /* Build the result */ - tail.refcount = source->refcount; - /* Bump the refcount */ - tail.refcount->ref(tail.refcount); + switch (ref_whom) { + case GRPC_SLICE_REF_TAIL: + tail.refcount = source->refcount->sub_refcount; + source->refcount = &noop_refcount; + break; + case GRPC_SLICE_REF_HEAD: + tail.refcount = &noop_refcount; + source->refcount = source->refcount->sub_refcount; + break; + case GRPC_SLICE_REF_BOTH: + tail.refcount = source->refcount->sub_refcount; + source->refcount = source->refcount->sub_refcount; + /* Bump the refcount */ + tail.refcount->vtable->ref(tail.refcount); + break; + } /* Point into the source array */ tail.data.refcounted.bytes = source->data.refcounted.bytes + split; tail.data.refcounted.length = tail_length; @@ -297,6 +356,10 @@ grpc_slice grpc_slice_split_tail(grpc_slice *source, size_t split) { return tail; } +grpc_slice grpc_slice_split_tail(grpc_slice *source, size_t split) { + return grpc_slice_split_tail_maybe_ref(source, split, GRPC_SLICE_REF_BOTH); +} + grpc_slice grpc_slice_split_head(grpc_slice *source, size_t split) { grpc_slice head; @@ -316,18 +379,20 @@ grpc_slice grpc_slice_split_head(grpc_slice *source, size_t split) { head.refcount = NULL; head.data.inlined.length = (uint8_t)split; memcpy(head.data.inlined.bytes, source->data.refcounted.bytes, split); + source->refcount = source->refcount->sub_refcount; source->data.refcounted.bytes += split; source->data.refcounted.length -= split; } else { GPR_ASSERT(source->data.refcounted.length >= split); /* Build the result */ - head.refcount = source->refcount; + head.refcount = source->refcount->sub_refcount; /* Bump the refcount */ - head.refcount->ref(head.refcount); + head.refcount->vtable->ref(head.refcount); /* Point into the source array */ head.data.refcounted.bytes = source->data.refcounted.bytes; head.data.refcounted.length = split; + source->refcount = source->refcount->sub_refcount; source->data.refcounted.bytes += split; source->data.refcounted.length -= split; } @@ -335,6 +400,20 @@ grpc_slice grpc_slice_split_head(grpc_slice *source, size_t split) { return head; } +int grpc_slice_default_eq_impl(grpc_slice a, grpc_slice b) { + if (GRPC_SLICE_LENGTH(a) != GRPC_SLICE_LENGTH(b)) return false; + if (GRPC_SLICE_LENGTH(a) == 0) return true; + return 0 == memcmp(GRPC_SLICE_START_PTR(a), GRPC_SLICE_START_PTR(b), + GRPC_SLICE_LENGTH(a)); +} + +int grpc_slice_eq(grpc_slice a, grpc_slice b) { + if (a.refcount && b.refcount && a.refcount->vtable == b.refcount->vtable) { + return a.refcount->vtable->eq(a, b); + } + return grpc_slice_default_eq_impl(a, b); +} + int grpc_slice_cmp(grpc_slice a, grpc_slice b) { int d = (int)(GRPC_SLICE_LENGTH(a) - GRPC_SLICE_LENGTH(b)); if (d != 0) return d; @@ -351,8 +430,55 @@ int grpc_slice_str_cmp(grpc_slice a, const char *b) { int grpc_slice_is_equivalent(grpc_slice a, grpc_slice b) { if (a.refcount == NULL || b.refcount == NULL) { - return grpc_slice_cmp(a, b) == 0; + return grpc_slice_eq(a, b); } return a.data.refcounted.length == b.data.refcounted.length && a.data.refcounted.bytes == b.data.refcounted.bytes; } + +int grpc_slice_buf_start_eq(grpc_slice a, const void *b, size_t len) { + if (GRPC_SLICE_LENGTH(a) < len) return 0; + return 0 == memcmp(GRPC_SLICE_START_PTR(a), b, len); +} + +int grpc_slice_rchr(grpc_slice s, char c) { + const char *b = (const char *)GRPC_SLICE_START_PTR(s); + int i; + for (i = (int)GRPC_SLICE_LENGTH(s) - 1; i != -1 && b[i] != c; i--) + ; + return i; +} + +int grpc_slice_chr(grpc_slice s, char c) { + const char *b = (const char *)GRPC_SLICE_START_PTR(s); + const char *p = memchr(b, c, GRPC_SLICE_LENGTH(s)); + return p == NULL ? -1 : (int)(p - b); +} + +int grpc_slice_slice(grpc_slice haystack, grpc_slice needle) { + size_t haystack_len = GRPC_SLICE_LENGTH(haystack); + const uint8_t *haystack_bytes = GRPC_SLICE_START_PTR(haystack); + size_t needle_len = GRPC_SLICE_LENGTH(needle); + const uint8_t *needle_bytes = GRPC_SLICE_START_PTR(needle); + + if (haystack_len == 0 || needle_len == 0) return -1; + if (haystack_len < needle_len) return -1; + if (haystack_len == needle_len) + return grpc_slice_eq(haystack, needle) ? 0 : -1; + if (needle_len == 1) return grpc_slice_chr(haystack, (char)*needle_bytes); + + const uint8_t *last = haystack_bytes + haystack_len - needle_len; + for (const uint8_t *cur = haystack_bytes; cur != last; ++cur) { + if (0 == memcmp(cur, needle_bytes, needle_len)) { + return (int)(cur - haystack_bytes); + } + } + return -1; +} + +grpc_slice grpc_slice_dup(grpc_slice a) { + grpc_slice copy = GRPC_SLICE_MALLOC(GRPC_SLICE_LENGTH(a)); + memcpy(GRPC_SLICE_START_PTR(copy), GRPC_SLICE_START_PTR(a), + GRPC_SLICE_LENGTH(a)); + return copy; +} diff --git a/Sources/CgRPC/src/core/lib/slice/slice_buffer.c b/Sources/CgRPC/src/core/lib/slice/slice_buffer.c index 990ef128b..a54a997a0 100644 --- a/Sources/CgRPC/src/core/lib/slice/slice_buffer.c +++ b/Sources/CgRPC/src/core/lib/slice/slice_buffer.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -40,18 +25,34 @@ #include #include +#include "src/core/lib/slice/slice_internal.h" + /* grow a buffer; requires GRPC_SLICE_BUFFER_INLINE_ELEMENTS > 1 */ #define GROW(x) (3 * (x) / 2) static void maybe_embiggen(grpc_slice_buffer *sb) { - if (sb->count == sb->capacity) { - sb->capacity = GROW(sb->capacity); - GPR_ASSERT(sb->capacity > sb->count); - if (sb->slices == sb->inlined) { - sb->slices = gpr_malloc(sb->capacity * sizeof(grpc_slice)); - memcpy(sb->slices, sb->inlined, sb->count * sizeof(grpc_slice)); + /* How far away from sb->base_slices is sb->slices pointer */ + size_t slice_offset = (size_t)(sb->slices - sb->base_slices); + size_t slice_count = sb->count + slice_offset; + + if (slice_count == sb->capacity) { + if (sb->base_slices != sb->slices) { + /* Make room by moving elements if there's still space unused */ + memmove(sb->base_slices, sb->slices, sb->count * sizeof(grpc_slice)); + sb->slices = sb->base_slices; } else { - sb->slices = gpr_realloc(sb->slices, sb->capacity * sizeof(grpc_slice)); + /* Allocate more memory if no more space is available */ + sb->capacity = GROW(sb->capacity); + GPR_ASSERT(sb->capacity > slice_count); + if (sb->base_slices == sb->inlined) { + sb->base_slices = gpr_malloc(sb->capacity * sizeof(grpc_slice)); + memcpy(sb->base_slices, sb->inlined, slice_count * sizeof(grpc_slice)); + } else { + sb->base_slices = + gpr_realloc(sb->base_slices, sb->capacity * sizeof(grpc_slice)); + } + + sb->slices = sb->base_slices + slice_offset; } } } @@ -60,16 +61,23 @@ void grpc_slice_buffer_init(grpc_slice_buffer *sb) { sb->count = 0; sb->length = 0; sb->capacity = GRPC_SLICE_BUFFER_INLINE_ELEMENTS; - sb->slices = sb->inlined; + sb->base_slices = sb->slices = sb->inlined; } -void grpc_slice_buffer_destroy(grpc_slice_buffer *sb) { - grpc_slice_buffer_reset_and_unref(sb); - if (sb->slices != sb->inlined) { - gpr_free(sb->slices); +void grpc_slice_buffer_destroy_internal(grpc_exec_ctx *exec_ctx, + grpc_slice_buffer *sb) { + grpc_slice_buffer_reset_and_unref_internal(exec_ctx, sb); + if (sb->base_slices != sb->inlined) { + gpr_free(sb->base_slices); } } +void grpc_slice_buffer_destroy(grpc_slice_buffer *sb) { + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + grpc_slice_buffer_destroy_internal(&exec_ctx, sb); + grpc_exec_ctx_finish(&exec_ctx); +} + uint8_t *grpc_slice_buffer_tiny_add(grpc_slice_buffer *sb, size_t n) { grpc_slice *back; uint8_t *out; @@ -154,44 +162,63 @@ void grpc_slice_buffer_pop(grpc_slice_buffer *sb) { } } -void grpc_slice_buffer_reset_and_unref(grpc_slice_buffer *sb) { +void grpc_slice_buffer_reset_and_unref_internal(grpc_exec_ctx *exec_ctx, + grpc_slice_buffer *sb) { size_t i; - for (i = 0; i < sb->count; i++) { - grpc_slice_unref(sb->slices[i]); + grpc_slice_unref_internal(exec_ctx, sb->slices[i]); } sb->count = 0; sb->length = 0; } +void grpc_slice_buffer_reset_and_unref(grpc_slice_buffer *sb) { + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + grpc_slice_buffer_reset_and_unref_internal(&exec_ctx, sb); + grpc_exec_ctx_finish(&exec_ctx); +} + void grpc_slice_buffer_swap(grpc_slice_buffer *a, grpc_slice_buffer *b) { - GPR_SWAP(size_t, a->count, b->count); - GPR_SWAP(size_t, a->capacity, b->capacity); - GPR_SWAP(size_t, a->length, b->length); + size_t a_offset = (size_t)(a->slices - a->base_slices); + size_t b_offset = (size_t)(b->slices - b->base_slices); + + size_t a_count = a->count + a_offset; + size_t b_count = b->count + b_offset; - if (a->slices == a->inlined) { - if (b->slices == b->inlined) { + if (a->base_slices == a->inlined) { + if (b->base_slices == b->inlined) { /* swap contents of inlined buffer */ grpc_slice temp[GRPC_SLICE_BUFFER_INLINE_ELEMENTS]; - memcpy(temp, a->slices, b->count * sizeof(grpc_slice)); - memcpy(a->slices, b->slices, a->count * sizeof(grpc_slice)); - memcpy(b->slices, temp, b->count * sizeof(grpc_slice)); + memcpy(temp, a->base_slices, a_count * sizeof(grpc_slice)); + memcpy(a->base_slices, b->base_slices, b_count * sizeof(grpc_slice)); + memcpy(b->base_slices, temp, a_count * sizeof(grpc_slice)); } else { /* a is inlined, b is not - copy a inlined into b, fix pointers */ - a->slices = b->slices; - b->slices = b->inlined; - memcpy(b->slices, a->inlined, b->count * sizeof(grpc_slice)); + a->base_slices = b->base_slices; + b->base_slices = b->inlined; + memcpy(b->base_slices, a->inlined, a_count * sizeof(grpc_slice)); } - } else if (b->slices == b->inlined) { + } else if (b->base_slices == b->inlined) { /* b is inlined, a is not - copy b inlined int a, fix pointers */ - b->slices = a->slices; - a->slices = a->inlined; - memcpy(a->slices, b->inlined, a->count * sizeof(grpc_slice)); + b->base_slices = a->base_slices; + a->base_slices = a->inlined; + memcpy(a->base_slices, b->inlined, b_count * sizeof(grpc_slice)); } else { /* no inlining: easy swap */ - GPR_SWAP(grpc_slice *, a->slices, b->slices); + GPR_SWAP(grpc_slice *, a->base_slices, b->base_slices); } + + /* Update the slices pointers (cannot do a GPR_SWAP on slices fields here). + * Also note that since the base_slices pointers are already swapped we need + * use 'b_offset' for 'a->base_slices' and vice versa */ + a->slices = a->base_slices + b_offset; + b->slices = b->base_slices + a_offset; + + /* base_slices and slices fields are correctly set. Swap all other fields */ + GPR_SWAP(size_t, a->count, b->count); + GPR_SWAP(size_t, a->capacity, b->capacity); + GPR_SWAP(size_t, a->length, b->length); } void grpc_slice_buffer_move_into(grpc_slice_buffer *src, @@ -211,44 +238,83 @@ void grpc_slice_buffer_move_into(grpc_slice_buffer *src, src->length = 0; } -void grpc_slice_buffer_move_first(grpc_slice_buffer *src, size_t n, - grpc_slice_buffer *dst) { - size_t src_idx; - size_t output_len = dst->length + n; - size_t new_input_len = src->length - n; +static void slice_buffer_move_first_maybe_ref(grpc_slice_buffer *src, size_t n, + grpc_slice_buffer *dst, + bool incref) { GPR_ASSERT(src->length >= n); if (src->length == n) { grpc_slice_buffer_move_into(src, dst); return; } - src_idx = 0; - while (src_idx < src->capacity) { - grpc_slice slice = src->slices[src_idx]; + + size_t output_len = dst->length + n; + size_t new_input_len = src->length - n; + + while (src->count > 0) { + grpc_slice slice = grpc_slice_buffer_take_first(src); size_t slice_len = GRPC_SLICE_LENGTH(slice); if (n > slice_len) { grpc_slice_buffer_add(dst, slice); n -= slice_len; - src_idx++; } else if (n == slice_len) { grpc_slice_buffer_add(dst, slice); - src_idx++; break; - } else { /* n < slice_len */ - src->slices[src_idx] = grpc_slice_split_tail(&slice, n); + } else if (incref) { /* n < slice_len */ + grpc_slice_buffer_undo_take_first( + src, grpc_slice_split_tail_maybe_ref(&slice, n, GRPC_SLICE_REF_BOTH)); GPR_ASSERT(GRPC_SLICE_LENGTH(slice) == n); - GPR_ASSERT(GRPC_SLICE_LENGTH(src->slices[src_idx]) == slice_len - n); grpc_slice_buffer_add(dst, slice); break; + } else { /* n < slice_len */ + grpc_slice_buffer_undo_take_first( + src, grpc_slice_split_tail_maybe_ref(&slice, n, GRPC_SLICE_REF_TAIL)); + GPR_ASSERT(GRPC_SLICE_LENGTH(slice) == n); + grpc_slice_buffer_add_indexed(dst, slice); + break; } } GPR_ASSERT(dst->length == output_len); - memmove(src->slices, src->slices + src_idx, - sizeof(grpc_slice) * (src->count - src_idx)); - src->count -= src_idx; - src->length = new_input_len; + GPR_ASSERT(src->length == new_input_len); GPR_ASSERT(src->count > 0); } +void grpc_slice_buffer_move_first(grpc_slice_buffer *src, size_t n, + grpc_slice_buffer *dst) { + slice_buffer_move_first_maybe_ref(src, n, dst, true); +} + +void grpc_slice_buffer_move_first_no_ref(grpc_slice_buffer *src, size_t n, + grpc_slice_buffer *dst) { + slice_buffer_move_first_maybe_ref(src, n, dst, false); +} + +void grpc_slice_buffer_move_first_into_buffer(grpc_exec_ctx *exec_ctx, + grpc_slice_buffer *src, size_t n, + void *dst) { + char *dstp = dst; + GPR_ASSERT(src->length >= n); + + while (n > 0) { + grpc_slice slice = grpc_slice_buffer_take_first(src); + size_t slice_len = GRPC_SLICE_LENGTH(slice); + if (slice_len > n) { + memcpy(dstp, GRPC_SLICE_START_PTR(slice), n); + grpc_slice_buffer_undo_take_first( + src, grpc_slice_sub_no_ref(slice, n, slice_len)); + n = 0; + } else if (slice_len == n) { + memcpy(dstp, GRPC_SLICE_START_PTR(slice), n); + grpc_slice_unref_internal(exec_ctx, slice); + n = 0; + } else { + memcpy(dstp, GRPC_SLICE_START_PTR(slice), slice_len); + dstp += slice_len; + n -= slice_len; + grpc_slice_unref_internal(exec_ctx, slice); + } + } +} + void grpc_slice_buffer_trim_end(grpc_slice_buffer *sb, size_t n, grpc_slice_buffer *garbage) { GPR_ASSERT(n <= sb->length); @@ -277,8 +343,17 @@ grpc_slice grpc_slice_buffer_take_first(grpc_slice_buffer *sb) { grpc_slice slice; GPR_ASSERT(sb->count > 0); slice = sb->slices[0]; - memmove(&sb->slices[0], &sb->slices[1], (sb->count - 1) * sizeof(grpc_slice)); + sb->slices++; sb->count--; sb->length -= GRPC_SLICE_LENGTH(slice); + return slice; } + +void grpc_slice_buffer_undo_take_first(grpc_slice_buffer *sb, + grpc_slice slice) { + sb->slices--; + sb->slices[0] = slice; + sb->count++; + sb->length += GRPC_SLICE_LENGTH(slice); +} diff --git a/Sources/CgRPC/src/core/lib/slice/slice_hash_table.c b/Sources/CgRPC/src/core/lib/slice/slice_hash_table.c new file mode 100644 index 000000000..1866ed25a --- /dev/null +++ b/Sources/CgRPC/src/core/lib/slice/slice_hash_table.c @@ -0,0 +1,145 @@ +// +// Copyright 2016 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 "src/core/lib/slice/slice_hash_table.h" + +#include +#include + +#include +#include + +#include "src/core/lib/slice/slice_internal.h" +#include "src/core/lib/transport/metadata.h" + +struct grpc_slice_hash_table { + gpr_refcount refs; + void (*destroy_value)(grpc_exec_ctx* exec_ctx, void* value); + int (*value_cmp)(void* a, void* b); + size_t size; + size_t max_num_probes; + grpc_slice_hash_table_entry* entries; +}; + +static bool is_empty(grpc_slice_hash_table_entry* entry) { + return entry->value == NULL; +} + +static void grpc_slice_hash_table_add(grpc_slice_hash_table* table, + grpc_slice key, void* value) { + GPR_ASSERT(value != NULL); + const size_t hash = grpc_slice_hash(key); + for (size_t offset = 0; offset < table->size; ++offset) { + const size_t idx = (hash + offset) % table->size; + if (is_empty(&table->entries[idx])) { + table->entries[idx].key = key; + table->entries[idx].value = value; + // Keep track of the maximum number of probes needed, since this + // provides an upper bound for lookups. + if (offset > table->max_num_probes) table->max_num_probes = offset; + return; + } + } + GPR_ASSERT(false); // Table should never be full. +} + +grpc_slice_hash_table* grpc_slice_hash_table_create( + size_t num_entries, grpc_slice_hash_table_entry* entries, + void (*destroy_value)(grpc_exec_ctx* exec_ctx, void* value), + int (*value_cmp)(void* a, void* b)) { + grpc_slice_hash_table* table = gpr_zalloc(sizeof(*table)); + gpr_ref_init(&table->refs, 1); + table->destroy_value = destroy_value; + table->value_cmp = value_cmp; + // Keep load factor low to improve performance of lookups. + table->size = num_entries * 2; + const size_t entry_size = sizeof(grpc_slice_hash_table_entry) * table->size; + table->entries = gpr_zalloc(entry_size); + for (size_t i = 0; i < num_entries; ++i) { + grpc_slice_hash_table_entry* entry = &entries[i]; + grpc_slice_hash_table_add(table, entry->key, entry->value); + } + return table; +} + +grpc_slice_hash_table* grpc_slice_hash_table_ref(grpc_slice_hash_table* table) { + if (table != NULL) gpr_ref(&table->refs); + return table; +} + +void grpc_slice_hash_table_unref(grpc_exec_ctx* exec_ctx, + grpc_slice_hash_table* table) { + if (table != NULL && gpr_unref(&table->refs)) { + for (size_t i = 0; i < table->size; ++i) { + grpc_slice_hash_table_entry* entry = &table->entries[i]; + if (!is_empty(entry)) { + grpc_slice_unref_internal(exec_ctx, entry->key); + table->destroy_value(exec_ctx, entry->value); + } + } + gpr_free(table->entries); + gpr_free(table); + } +} + +void* grpc_slice_hash_table_get(const grpc_slice_hash_table* table, + const grpc_slice key) { + const size_t hash = grpc_slice_hash(key); + // We cap the number of probes at the max number recorded when + // populating the table. + for (size_t offset = 0; offset <= table->max_num_probes; ++offset) { + const size_t idx = (hash + offset) % table->size; + if (is_empty(&table->entries[idx])) break; + if (grpc_slice_eq(table->entries[idx].key, key)) { + return table->entries[idx].value; + } + } + return NULL; // Not found. +} + +static int pointer_cmp(void* a, void* b) { return GPR_ICMP(a, b); } +int grpc_slice_hash_table_cmp(const grpc_slice_hash_table* a, + const grpc_slice_hash_table* b) { + int (*const value_cmp_fn_a)(void* a, void* b) = + a->value_cmp != NULL ? a->value_cmp : pointer_cmp; + int (*const value_cmp_fn_b)(void* a, void* b) = + b->value_cmp != NULL ? b->value_cmp : pointer_cmp; + // Compare value_fns + const int value_fns_cmp = + GPR_ICMP((void*)value_cmp_fn_a, (void*)value_cmp_fn_b); + if (value_fns_cmp != 0) return value_fns_cmp; + // Compare sizes + if (a->size < b->size) return -1; + if (a->size > b->size) return 1; + // Compare rows. + for (size_t i = 0; i < a->size; ++i) { + if (is_empty(&a->entries[i])) { + if (!is_empty(&b->entries[i])) { + return -1; // a empty but b non-empty + } + continue; // both empty, no need to check key or value + } else if (is_empty(&b->entries[i])) { + return 1; // a non-empty but b empty + } + // neither entry is empty + const int key_cmp = grpc_slice_cmp(a->entries[i].key, b->entries[i].key); + if (key_cmp != 0) return key_cmp; + const int value_cmp = + value_cmp_fn_a(a->entries[i].value, b->entries[i].value); + if (value_cmp != 0) return value_cmp; + } + return 0; +} diff --git a/Sources/CgRPC/src/core/lib/slice/slice_hash_table.h b/Sources/CgRPC/src/core/lib/slice/slice_hash_table.h new file mode 100644 index 000000000..339078fef --- /dev/null +++ b/Sources/CgRPC/src/core/lib/slice/slice_hash_table.h @@ -0,0 +1,70 @@ +/* + * Copyright 2016 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 GRPC_CORE_LIB_SLICE_SLICE_HASH_TABLE_H +#define GRPC_CORE_LIB_SLICE_SLICE_HASH_TABLE_H + +#include "src/core/lib/transport/metadata.h" + +/** Hash table implementation. + * + * This implementation uses open addressing + * (https://en.wikipedia.org/wiki/Open_addressing) with linear + * probing (https://en.wikipedia.org/wiki/Linear_probing). + * + * The keys are \a grpc_slice objects. The values are arbitrary pointers + * with a common destroy function. + * + * Hash tables are intentionally immutable, to avoid the need for locking. + */ + +typedef struct grpc_slice_hash_table grpc_slice_hash_table; + +typedef struct grpc_slice_hash_table_entry { + grpc_slice key; + void *value; /* Must not be NULL. */ +} grpc_slice_hash_table_entry; + +/** Creates a new hash table of containing \a entries, which is an array + of length \a num_entries. Takes ownership of all keys and values in \a + entries. Values will be cleaned up via \a destroy_value(). If not NULL, \a + value_cmp will be used to compare values in the context of \a + grpc_slice_hash_table_cmp. If NULL, raw pointer (\a GPR_ICMP) comparison + will be used. */ +grpc_slice_hash_table *grpc_slice_hash_table_create( + size_t num_entries, grpc_slice_hash_table_entry *entries, + void (*destroy_value)(grpc_exec_ctx *exec_ctx, void *value), + int (*value_cmp)(void *a, void *b)); + +grpc_slice_hash_table *grpc_slice_hash_table_ref(grpc_slice_hash_table *table); +void grpc_slice_hash_table_unref(grpc_exec_ctx *exec_ctx, + grpc_slice_hash_table *table); + +/** Returns the value from \a table associated with \a key. + Returns NULL if \a key is not found. */ +void *grpc_slice_hash_table_get(const grpc_slice_hash_table *table, + const grpc_slice key); + +/** Compares \a a vs. \a b. + * A table is considered "smaller" (resp. "greater") if: + * - GPR_ICMP(a->value_cmp, b->value_cmp) < 1 (resp. > 1), + * - else, it contains fewer (resp. more) entries, + * - else, if strcmp(a_key, b_key) < 1 (resp. > 1), + * - else, if value_cmp(a_value, b_value) < 1 (resp. > 1). */ +int grpc_slice_hash_table_cmp(const grpc_slice_hash_table *a, + const grpc_slice_hash_table *b); + +#endif /* GRPC_CORE_LIB_SLICE_SLICE_HASH_TABLE_H */ diff --git a/Sources/CgRPC/src/core/lib/slice/slice_intern.c b/Sources/CgRPC/src/core/lib/slice/slice_intern.c new file mode 100644 index 000000000..a6d22c1e1 --- /dev/null +++ b/Sources/CgRPC/src/core/lib/slice/slice_intern.c @@ -0,0 +1,331 @@ +/* + * + * Copyright 2016 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 "src/core/lib/slice/slice_internal.h" + +#include + +#include +#include + +#include "src/core/lib/iomgr/iomgr_internal.h" /* for iomgr_abort_on_leaks() */ +#include "src/core/lib/profiling/timers.h" +#include "src/core/lib/slice/slice_string_helpers.h" +#include "src/core/lib/support/murmur_hash.h" +#include "src/core/lib/transport/static_metadata.h" + +#define LOG2_SHARD_COUNT 5 +#define SHARD_COUNT (1 << LOG2_SHARD_COUNT) +#define INITIAL_SHARD_CAPACITY 8 + +#define TABLE_IDX(hash, capacity) (((hash) >> LOG2_SHARD_COUNT) % (capacity)) +#define SHARD_IDX(hash) ((hash) & ((1 << LOG2_SHARD_COUNT) - 1)) + +typedef struct interned_slice_refcount { + grpc_slice_refcount base; + grpc_slice_refcount sub; + size_t length; + gpr_atm refcnt; + uint32_t hash; + struct interned_slice_refcount *bucket_next; +} interned_slice_refcount; + +typedef struct slice_shard { + gpr_mu mu; + interned_slice_refcount **strs; + size_t count; + size_t capacity; +} slice_shard; + +/* hash seed: decided at initialization time */ +static uint32_t g_hash_seed; +static int g_forced_hash_seed = 0; + +static slice_shard g_shards[SHARD_COUNT]; + +typedef struct { + uint32_t hash; + uint32_t idx; +} static_metadata_hash_ent; + +static static_metadata_hash_ent + static_metadata_hash[4 * GRPC_STATIC_MDSTR_COUNT]; +static uint32_t max_static_metadata_hash_probe; +static uint32_t static_metadata_hash_values[GRPC_STATIC_MDSTR_COUNT]; + +static void interned_slice_ref(void *p) { + interned_slice_refcount *s = p; + GPR_ASSERT(gpr_atm_no_barrier_fetch_add(&s->refcnt, 1) > 0); +} + +static void interned_slice_destroy(interned_slice_refcount *s) { + slice_shard *shard = &g_shards[SHARD_IDX(s->hash)]; + gpr_mu_lock(&shard->mu); + GPR_ASSERT(0 == gpr_atm_no_barrier_load(&s->refcnt)); + interned_slice_refcount **prev_next; + interned_slice_refcount *cur; + for (prev_next = &shard->strs[TABLE_IDX(s->hash, shard->capacity)], + cur = *prev_next; + cur != s; prev_next = &cur->bucket_next, cur = cur->bucket_next) + ; + *prev_next = cur->bucket_next; + shard->count--; + gpr_free(s); + gpr_mu_unlock(&shard->mu); +} + +static void interned_slice_unref(grpc_exec_ctx *exec_ctx, void *p) { + interned_slice_refcount *s = p; + if (1 == gpr_atm_full_fetch_add(&s->refcnt, -1)) { + interned_slice_destroy(s); + } +} + +static void interned_slice_sub_ref(void *p) { + interned_slice_ref(((char *)p) - offsetof(interned_slice_refcount, sub)); +} + +static void interned_slice_sub_unref(grpc_exec_ctx *exec_ctx, void *p) { + interned_slice_unref(exec_ctx, + ((char *)p) - offsetof(interned_slice_refcount, sub)); +} + +static uint32_t interned_slice_hash(grpc_slice slice) { + interned_slice_refcount *s = (interned_slice_refcount *)slice.refcount; + return s->hash; +} + +static int interned_slice_eq(grpc_slice a, grpc_slice b) { + return a.refcount == b.refcount; +} + +static const grpc_slice_refcount_vtable interned_slice_vtable = { + interned_slice_ref, interned_slice_unref, interned_slice_eq, + interned_slice_hash}; +static const grpc_slice_refcount_vtable interned_slice_sub_vtable = { + interned_slice_sub_ref, interned_slice_sub_unref, + grpc_slice_default_eq_impl, grpc_slice_default_hash_impl}; + +static void grow_shard(slice_shard *shard) { + size_t capacity = shard->capacity * 2; + size_t i; + interned_slice_refcount **strtab; + interned_slice_refcount *s, *next; + + GPR_TIMER_BEGIN("grow_strtab", 0); + + strtab = gpr_zalloc(sizeof(interned_slice_refcount *) * capacity); + + for (i = 0; i < shard->capacity; i++) { + for (s = shard->strs[i]; s; s = next) { + size_t idx = TABLE_IDX(s->hash, capacity); + next = s->bucket_next; + s->bucket_next = strtab[idx]; + strtab[idx] = s; + } + } + + gpr_free(shard->strs); + shard->strs = strtab; + shard->capacity = capacity; + + GPR_TIMER_END("grow_strtab", 0); +} + +static grpc_slice materialize(interned_slice_refcount *s) { + grpc_slice slice; + slice.refcount = &s->base; + slice.data.refcounted.bytes = (uint8_t *)(s + 1); + slice.data.refcounted.length = s->length; + return slice; +} + +uint32_t grpc_slice_default_hash_impl(grpc_slice s) { + return gpr_murmur_hash3(GRPC_SLICE_START_PTR(s), GRPC_SLICE_LENGTH(s), + g_hash_seed); +} + +uint32_t grpc_static_slice_hash(grpc_slice s) { + return static_metadata_hash_values[GRPC_STATIC_METADATA_INDEX(s)]; +} + +int grpc_static_slice_eq(grpc_slice a, grpc_slice b) { + return GRPC_STATIC_METADATA_INDEX(a) == GRPC_STATIC_METADATA_INDEX(b); +} + +uint32_t grpc_slice_hash(grpc_slice s) { + return s.refcount == NULL ? grpc_slice_default_hash_impl(s) + : s.refcount->vtable->hash(s); +} + +grpc_slice grpc_slice_maybe_static_intern(grpc_slice slice, + bool *returned_slice_is_different) { + if (GRPC_IS_STATIC_METADATA_STRING(slice)) { + return slice; + } + + uint32_t hash = grpc_slice_hash(slice); + for (uint32_t i = 0; i <= max_static_metadata_hash_probe; i++) { + static_metadata_hash_ent ent = + static_metadata_hash[(hash + i) % GPR_ARRAY_SIZE(static_metadata_hash)]; + if (ent.hash == hash && ent.idx < GRPC_STATIC_MDSTR_COUNT && + grpc_slice_eq(grpc_static_slice_table[ent.idx], slice)) { + *returned_slice_is_different = true; + return grpc_static_slice_table[ent.idx]; + } + } + + return slice; +} + +bool grpc_slice_is_interned(grpc_slice slice) { + return (slice.refcount && slice.refcount->vtable == &interned_slice_vtable) || + GRPC_IS_STATIC_METADATA_STRING(slice); +} + +grpc_slice grpc_slice_intern(grpc_slice slice) { + GPR_TIMER_BEGIN("grpc_slice_intern", 0); + if (GRPC_IS_STATIC_METADATA_STRING(slice)) { + GPR_TIMER_END("grpc_slice_intern", 0); + return slice; + } + + uint32_t hash = grpc_slice_hash(slice); + for (uint32_t i = 0; i <= max_static_metadata_hash_probe; i++) { + static_metadata_hash_ent ent = + static_metadata_hash[(hash + i) % GPR_ARRAY_SIZE(static_metadata_hash)]; + if (ent.hash == hash && ent.idx < GRPC_STATIC_MDSTR_COUNT && + grpc_slice_eq(grpc_static_slice_table[ent.idx], slice)) { + GPR_TIMER_END("grpc_slice_intern", 0); + return grpc_static_slice_table[ent.idx]; + } + } + + interned_slice_refcount *s; + slice_shard *shard = &g_shards[SHARD_IDX(hash)]; + + gpr_mu_lock(&shard->mu); + + /* search for an existing string */ + size_t idx = TABLE_IDX(hash, shard->capacity); + for (s = shard->strs[idx]; s; s = s->bucket_next) { + if (s->hash == hash && grpc_slice_eq(slice, materialize(s))) { + if (gpr_atm_no_barrier_fetch_add(&s->refcnt, 1) == 0) { + /* If we get here, we've added a ref to something that was about to + * die - drop it immediately. + * The *only* possible path here (given the shard mutex) should be to + * drop from one ref back to zero - assert that with a CAS */ + GPR_ASSERT(gpr_atm_rel_cas(&s->refcnt, 1, 0)); + /* and treat this as if we were never here... sshhh */ + } else { + gpr_mu_unlock(&shard->mu); + GPR_TIMER_END("grpc_slice_intern", 0); + return materialize(s); + } + } + } + + /* not found: create a new string */ + /* string data goes after the internal_string header */ + s = gpr_malloc(sizeof(*s) + GRPC_SLICE_LENGTH(slice)); + gpr_atm_rel_store(&s->refcnt, 1); + s->length = GRPC_SLICE_LENGTH(slice); + s->hash = hash; + s->base.vtable = &interned_slice_vtable; + s->base.sub_refcount = &s->sub; + s->sub.vtable = &interned_slice_sub_vtable; + s->sub.sub_refcount = &s->sub; + s->bucket_next = shard->strs[idx]; + shard->strs[idx] = s; + memcpy(s + 1, GRPC_SLICE_START_PTR(slice), GRPC_SLICE_LENGTH(slice)); + + shard->count++; + + if (shard->count > shard->capacity * 2) { + grow_shard(shard); + } + + gpr_mu_unlock(&shard->mu); + + GPR_TIMER_END("grpc_slice_intern", 0); + return materialize(s); +} + +void grpc_test_only_set_slice_hash_seed(uint32_t seed) { + g_hash_seed = seed; + g_forced_hash_seed = 1; +} + +void grpc_slice_intern_init(void) { + if (!g_forced_hash_seed) { + g_hash_seed = (uint32_t)gpr_now(GPR_CLOCK_REALTIME).tv_nsec; + } + for (size_t i = 0; i < SHARD_COUNT; i++) { + slice_shard *shard = &g_shards[i]; + gpr_mu_init(&shard->mu); + shard->count = 0; + shard->capacity = INITIAL_SHARD_CAPACITY; + shard->strs = gpr_zalloc(sizeof(*shard->strs) * shard->capacity); + } + for (size_t i = 0; i < GPR_ARRAY_SIZE(static_metadata_hash); i++) { + static_metadata_hash[i].hash = 0; + static_metadata_hash[i].idx = GRPC_STATIC_MDSTR_COUNT; + } + max_static_metadata_hash_probe = 0; + for (size_t i = 0; i < GRPC_STATIC_MDSTR_COUNT; i++) { + static_metadata_hash_values[i] = + grpc_slice_default_hash_impl(grpc_static_slice_table[i]); + for (size_t j = 0; j < GPR_ARRAY_SIZE(static_metadata_hash); j++) { + size_t slot = (static_metadata_hash_values[i] + j) % + GPR_ARRAY_SIZE(static_metadata_hash); + if (static_metadata_hash[slot].idx == GRPC_STATIC_MDSTR_COUNT) { + static_metadata_hash[slot].hash = static_metadata_hash_values[i]; + static_metadata_hash[slot].idx = (uint32_t)i; + if (j > max_static_metadata_hash_probe) { + max_static_metadata_hash_probe = (uint32_t)j; + } + break; + } + } + } +} + +void grpc_slice_intern_shutdown(void) { + for (size_t i = 0; i < SHARD_COUNT; i++) { + slice_shard *shard = &g_shards[i]; + gpr_mu_destroy(&shard->mu); + /* TODO(ctiller): GPR_ASSERT(shard->count == 0); */ + if (shard->count != 0) { + gpr_log(GPR_DEBUG, "WARNING: %" PRIuPTR " metadata strings were leaked", + shard->count); + for (size_t j = 0; j < shard->capacity; j++) { + for (interned_slice_refcount *s = shard->strs[j]; s; + s = s->bucket_next) { + char *text = + grpc_dump_slice(materialize(s), GPR_DUMP_HEX | GPR_DUMP_ASCII); + gpr_log(GPR_DEBUG, "LEAKED: %s", text); + gpr_free(text); + } + } + if (grpc_iomgr_abort_on_leaks()) { + abort(); + } + } + gpr_free(shard->strs); + } +} diff --git a/Sources/CgRPC/src/core/lib/slice/slice_internal.h b/Sources/CgRPC/src/core/lib/slice/slice_internal.h new file mode 100644 index 000000000..6df0b4b50 --- /dev/null +++ b/Sources/CgRPC/src/core/lib/slice/slice_internal.h @@ -0,0 +1,49 @@ +/* + * + * Copyright 2016 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 GRPC_CORE_LIB_SLICE_SLICE_INTERNAL_H +#define GRPC_CORE_LIB_SLICE_SLICE_INTERNAL_H + +#include +#include + +#include "src/core/lib/iomgr/exec_ctx.h" + +grpc_slice grpc_slice_ref_internal(grpc_slice slice); +void grpc_slice_unref_internal(grpc_exec_ctx *exec_ctx, grpc_slice slice); +void grpc_slice_buffer_reset_and_unref_internal(grpc_exec_ctx *exec_ctx, + grpc_slice_buffer *sb); +void grpc_slice_buffer_destroy_internal(grpc_exec_ctx *exec_ctx, + grpc_slice_buffer *sb); + +/* Check if a slice is interned */ +bool grpc_slice_is_interned(grpc_slice slice); + +void grpc_slice_intern_init(void); +void grpc_slice_intern_shutdown(void); +void grpc_test_only_set_slice_hash_seed(uint32_t key); +// if slice matches a static slice, returns the static slice +// otherwise returns the passed in slice (without reffing it) +// used for surface boundaries where we might receive an un-interned static +// string +grpc_slice grpc_slice_maybe_static_intern(grpc_slice slice, + bool *returned_slice_is_different); +uint32_t grpc_static_slice_hash(grpc_slice s); +int grpc_static_slice_eq(grpc_slice a, grpc_slice b); + +#endif /* GRPC_CORE_LIB_SLICE_SLICE_INTERNAL_H */ diff --git a/Sources/CgRPC/src/core/lib/slice/slice_string_helpers.c b/Sources/CgRPC/src/core/lib/slice/slice_string_helpers.c index 4731762ec..d461c474d 100644 --- a/Sources/CgRPC/src/core/lib/slice/slice_string_helpers.c +++ b/Sources/CgRPC/src/core/lib/slice/slice_string_helpers.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -37,6 +22,7 @@ #include +#include "src/core/lib/slice/slice_internal.h" #include "src/core/lib/support/string.h" char *grpc_dump_slice(grpc_slice s, uint32_t flags) { @@ -84,6 +70,11 @@ void grpc_slice_split(grpc_slice str, const char *sep, grpc_slice_buffer *dst) { grpc_slice_buffer_add_indexed( dst, grpc_slice_sub(str, end + sep_len, GRPC_SLICE_LENGTH(str))); } else { /* no sep found, add whole input */ - grpc_slice_buffer_add_indexed(dst, grpc_slice_ref(str)); + grpc_slice_buffer_add_indexed(dst, grpc_slice_ref_internal(str)); } } + +bool grpc_parse_slice_to_uint32(grpc_slice str, uint32_t *result) { + return gpr_parse_bytes_to_uint32((const char *)GRPC_SLICE_START_PTR(str), + GRPC_SLICE_LENGTH(str), result) != 0; +} diff --git a/Sources/CgRPC/src/core/lib/slice/slice_string_helpers.h b/Sources/CgRPC/src/core/lib/slice/slice_string_helpers.h index 151c72077..bcfb33bfb 100644 --- a/Sources/CgRPC/src/core/lib/slice/slice_string_helpers.h +++ b/Sources/CgRPC/src/core/lib/slice/slice_string_helpers.h @@ -1,45 +1,33 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 GRPC_CORE_LIB_SLICE_SLICE_STRING_HELPERS_H #define GRPC_CORE_LIB_SLICE_SLICE_STRING_HELPERS_H +#include #include #include #include #include +#include "src/core/lib/support/string.h" + #ifdef __cplusplus extern "C" { #endif @@ -51,6 +39,8 @@ char *grpc_dump_slice(grpc_slice slice, uint32_t flags); * should be a properly initialized instance. */ void grpc_slice_split(grpc_slice str, const char *sep, grpc_slice_buffer *dst); +bool grpc_parse_slice_to_uint32(grpc_slice str, uint32_t *result); + #ifdef __cplusplus } #endif diff --git a/Sources/CgRPC/src/core/lib/support/alloc.c b/Sources/CgRPC/src/core/lib/support/alloc.c index 618c3f6ac..886d69d64 100644 --- a/Sources/CgRPC/src/core/lib/support/alloc.c +++ b/Sources/CgRPC/src/core/lib/support/alloc.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -36,9 +21,19 @@ #include #include #include +#include #include "src/core/lib/profiling/timers.h" -static gpr_allocation_functions g_alloc_functions = {malloc, realloc, free}; +static void *zalloc_with_calloc(size_t sz) { return calloc(sz, 1); } + +static void *zalloc_with_gpr_malloc(size_t sz) { + void *p = gpr_malloc(sz); + memset(p, 0, sz); + return p; +} + +static gpr_allocation_functions g_alloc_functions = {malloc, zalloc_with_calloc, + realloc, free}; gpr_allocation_functions gpr_get_allocation_functions() { return g_alloc_functions; @@ -48,6 +43,9 @@ void gpr_set_allocation_functions(gpr_allocation_functions functions) { GPR_ASSERT(functions.malloc_fn != NULL); GPR_ASSERT(functions.realloc_fn != NULL); GPR_ASSERT(functions.free_fn != NULL); + if (functions.zalloc_fn == NULL) { + functions.zalloc_fn = zalloc_with_gpr_malloc; + } g_alloc_functions = functions; } @@ -63,6 +61,18 @@ void *gpr_malloc(size_t size) { return p; } +void *gpr_zalloc(size_t size) { + void *p; + if (size == 0) return NULL; + GPR_TIMER_BEGIN("gpr_zalloc", 0); + p = g_alloc_functions.zalloc_fn(size); + if (!p) { + abort(); + } + GPR_TIMER_END("gpr_zalloc", 0); + return p; +} + void gpr_free(void *p) { GPR_TIMER_BEGIN("gpr_free", 0); g_alloc_functions.free_fn(p); diff --git a/Sources/CgRPC/src/core/lib/support/arena.c b/Sources/CgRPC/src/core/lib/support/arena.c new file mode 100644 index 000000000..9e0f73ae3 --- /dev/null +++ b/Sources/CgRPC/src/core/lib/support/arena.c @@ -0,0 +1,83 @@ +/* + * + * Copyright 2017 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 "src/core/lib/support/arena.h" +#include +#include +#include +#include + +#define ROUND_UP_TO_ALIGNMENT_SIZE(x) \ + (((x) + GPR_MAX_ALIGNMENT - 1u) & ~(GPR_MAX_ALIGNMENT - 1u)) + +typedef struct zone { + size_t size_begin; + size_t size_end; + gpr_atm next_atm; +} zone; + +struct gpr_arena { + gpr_atm size_so_far; + zone initial_zone; +}; + +gpr_arena *gpr_arena_create(size_t initial_size) { + initial_size = ROUND_UP_TO_ALIGNMENT_SIZE(initial_size); + gpr_arena *a = (gpr_arena *)gpr_zalloc(sizeof(gpr_arena) + initial_size); + a->initial_zone.size_end = initial_size; + return a; +} + +size_t gpr_arena_destroy(gpr_arena *arena) { + gpr_atm size = gpr_atm_no_barrier_load(&arena->size_so_far); + zone *z = (zone *)gpr_atm_no_barrier_load(&arena->initial_zone.next_atm); + gpr_free(arena); + while (z) { + zone *next_z = (zone *)gpr_atm_no_barrier_load(&z->next_atm); + gpr_free(z); + z = next_z; + } + return (size_t)size; +} + +void *gpr_arena_alloc(gpr_arena *arena, size_t size) { + size = ROUND_UP_TO_ALIGNMENT_SIZE(size); + size_t start = + (size_t)gpr_atm_no_barrier_fetch_add(&arena->size_so_far, size); + zone *z = &arena->initial_zone; + while (start > z->size_end) { + zone *next_z = (zone *)gpr_atm_acq_load(&z->next_atm); + if (next_z == NULL) { + size_t next_z_size = (size_t)gpr_atm_no_barrier_load(&arena->size_so_far); + next_z = (zone *)gpr_zalloc(sizeof(zone) + next_z_size); + next_z->size_begin = z->size_end; + next_z->size_end = z->size_end + next_z_size; + if (!gpr_atm_rel_cas(&z->next_atm, (gpr_atm)NULL, (gpr_atm)next_z)) { + gpr_free(next_z); + next_z = (zone *)gpr_atm_acq_load(&z->next_atm); + } + } + z = next_z; + } + if (start + size > z->size_end) { + return gpr_arena_alloc(arena, size); + } + GPR_ASSERT(start >= z->size_begin); + GPR_ASSERT(start + size <= z->size_end); + return ((char *)(z + 1)) + start - z->size_begin; +} diff --git a/Sources/CgRPC/src/core/lib/support/arena.h b/Sources/CgRPC/src/core/lib/support/arena.h new file mode 100644 index 000000000..47f0e4d16 --- /dev/null +++ b/Sources/CgRPC/src/core/lib/support/arena.h @@ -0,0 +1,39 @@ +/* + * + * Copyright 2017 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. + * + */ + +// \file Arena based allocator +// Allows very fast allocation of memory, but that memory cannot be freed until +// the arena as a whole is freed +// Tracks the total memory allocated against it, so that future arenas can +// pre-allocate the right amount of memory + +#ifndef GRPC_CORE_LIB_SUPPORT_ARENA_H +#define GRPC_CORE_LIB_SUPPORT_ARENA_H + +#include + +typedef struct gpr_arena gpr_arena; + +// Create an arena, with \a initial_size bytes in the first allocated buffer +gpr_arena *gpr_arena_create(size_t initial_size); +// Allocate \a size bytes from the arena +void *gpr_arena_alloc(gpr_arena *arena, size_t size); +// Destroy an arena, returning the total number of bytes allocated +size_t gpr_arena_destroy(gpr_arena *arena); + +#endif /* GRPC_CORE_LIB_SUPPORT_ARENA_H */ diff --git a/Sources/CgRPC/src/core/lib/support/atm.c b/Sources/CgRPC/src/core/lib/support/atm.c new file mode 100644 index 000000000..2f37d62f7 --- /dev/null +++ b/Sources/CgRPC/src/core/lib/support/atm.c @@ -0,0 +1,32 @@ +/* + * + * Copyright 2017 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 +#include + +gpr_atm gpr_atm_no_barrier_clamped_add(gpr_atm *value, gpr_atm delta, + gpr_atm min, gpr_atm max) { + gpr_atm current_value; + gpr_atm new_value; + do { + current_value = gpr_atm_no_barrier_load(value); + new_value = GPR_CLAMP(current_value + delta, min, max); + if (new_value == current_value) break; + } while (!gpr_atm_no_barrier_cas(value, current_value, new_value)); + return new_value; +} diff --git a/Sources/CgRPC/src/core/lib/support/atomic.h b/Sources/CgRPC/src/core/lib/support/atomic.h new file mode 100644 index 000000000..73c59ae3c --- /dev/null +++ b/Sources/CgRPC/src/core/lib/support/atomic.h @@ -0,0 +1,30 @@ +/* + * + * Copyright 2017 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 GRPC_CORE_LIB_SUPPORT_ATOMIC_H +#define GRPC_CORE_LIB_SUPPORT_ATOMIC_H + +#include + +#ifdef GPR_HAS_CXX11_ATOMIC +#include "src/core/lib/support/atomic_with_std.h" +#else +#include "src/core/lib/support/atomic_with_atm.h" +#endif + +#endif /* GRPC_CORE_LIB_SUPPORT_ATOMIC_H */ diff --git a/Sources/CgRPC/src/core/lib/support/atomic_with_atm.h b/Sources/CgRPC/src/core/lib/support/atomic_with_atm.h new file mode 100644 index 000000000..fe00e9b5b --- /dev/null +++ b/Sources/CgRPC/src/core/lib/support/atomic_with_atm.h @@ -0,0 +1,55 @@ +/* + * + * Copyright 2017 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 GRPC_CORE_LIB_SUPPORT_ATOMIC_WITH_ATM_H +#define GRPC_CORE_LIB_SUPPORT_ATOMIC_WITH_ATM_H + +#include + +namespace grpc_core { + +enum MemoryOrderRelaxed { memory_order_relaxed }; + +template +class atomic; + +template <> +class atomic { + public: + atomic() { gpr_atm_no_barrier_store(&x_, static_cast(false)); } + explicit atomic(bool x) { + gpr_atm_no_barrier_store(&x_, static_cast(x)); + } + + bool compare_exchange_strong(bool& expected, bool update, MemoryOrderRelaxed, + MemoryOrderRelaxed) { + if (!gpr_atm_no_barrier_cas(&x_, static_cast(expected), + static_cast(update))) { + expected = gpr_atm_no_barrier_load(&x_) != 0; + return false; + } + return true; + } + + private: + gpr_atm x_; +}; + +} // namespace grpc_core + +#endif /* GRPC_CORE_LIB_SUPPORT_ATOMIC_WITH_ATM_H */ diff --git a/Sources/CgRPC/src/core/lib/support/atomic_with_std.h b/Sources/CgRPC/src/core/lib/support/atomic_with_std.h new file mode 100644 index 000000000..c7a92f701 --- /dev/null +++ b/Sources/CgRPC/src/core/lib/support/atomic_with_std.h @@ -0,0 +1,33 @@ +/* + * + * Copyright 2017 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 GRPC_CORE_LIB_SUPPORT_ATOMIC_WITH_STD_H +#define GRPC_CORE_LIB_SUPPORT_ATOMIC_WITH_STD_H + +#include + +namespace grpc_core { + +template +using atomic = std::atomic; + +typedef std::memory_order memory_order; + +} // namespace grpc_core + +#endif /* GRPC_CORE_LIB_SUPPORT_ATOMIC_WITH_STD_H */ diff --git a/Sources/CgRPC/src/core/lib/support/avl.c b/Sources/CgRPC/src/core/lib/support/avl.c index acf8fd5a5..0e28b24c9 100644 --- a/Sources/CgRPC/src/core/lib/support/avl.c +++ b/Sources/CgRPC/src/core/lib/support/avl.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -54,15 +39,16 @@ static gpr_avl_node *ref_node(gpr_avl_node *node) { return node; } -static void unref_node(const gpr_avl_vtable *vtable, gpr_avl_node *node) { +static void unref_node(const gpr_avl_vtable *vtable, gpr_avl_node *node, + void *user_data) { if (node == NULL) { return; } if (gpr_unref(&node->refs)) { - vtable->destroy_key(node->key); - vtable->destroy_value(node->value); - unref_node(vtable, node->left); - unref_node(vtable, node->right); + vtable->destroy_key(node->key, user_data); + vtable->destroy_value(node->value, user_data); + unref_node(vtable, node->left, user_data); + unref_node(vtable, node->right, user_data); gpr_free(node); } } @@ -91,7 +77,7 @@ static gpr_avl_node *assert_invariants(gpr_avl_node *n) { return n; } gpr_avl_node *new_node(void *key, void *value, gpr_avl_node *left, gpr_avl_node *right) { - gpr_avl_node *node = gpr_malloc(sizeof(*node)); + gpr_avl_node *node = (gpr_avl_node *)gpr_malloc(sizeof(*node)); gpr_ref_init(&node->refs, 1); node->key = key; node->value = value; @@ -102,30 +88,30 @@ gpr_avl_node *new_node(void *key, void *value, gpr_avl_node *left, } static gpr_avl_node *get(const gpr_avl_vtable *vtable, gpr_avl_node *node, - void *key) { + void *key, void *user_data) { long cmp; if (node == NULL) { return NULL; } - cmp = vtable->compare_keys(node->key, key); + cmp = vtable->compare_keys(node->key, key, user_data); if (cmp == 0) { return node; } else if (cmp > 0) { - return get(vtable, node->left, key); + return get(vtable, node->left, key, user_data); } else { - return get(vtable, node->right, key); + return get(vtable, node->right, key, user_data); } } -void *gpr_avl_get(gpr_avl avl, void *key) { - gpr_avl_node *node = get(avl.vtable, avl.root, key); +void *gpr_avl_get(gpr_avl avl, void *key, void *user_data) { + gpr_avl_node *node = get(avl.vtable, avl.root, key, user_data); return node ? node->value : NULL; } -int gpr_avl_maybe_get(gpr_avl avl, void *key, void **value) { - gpr_avl_node *node = get(avl.vtable, avl.root, key); +int gpr_avl_maybe_get(gpr_avl avl, void *key, void **value, void *user_data) { + gpr_avl_node *node = get(avl.vtable, avl.root, key, user_data); if (node != NULL) { *value = node->value; return 1; @@ -135,101 +121,108 @@ int gpr_avl_maybe_get(gpr_avl avl, void *key, void **value) { static gpr_avl_node *rotate_left(const gpr_avl_vtable *vtable, void *key, void *value, gpr_avl_node *left, - gpr_avl_node *right) { - gpr_avl_node *n = - new_node(vtable->copy_key(right->key), vtable->copy_value(right->value), - new_node(key, value, left, ref_node(right->left)), - ref_node(right->right)); - unref_node(vtable, right); + gpr_avl_node *right, void *user_data) { + gpr_avl_node *n = new_node(vtable->copy_key(right->key, user_data), + vtable->copy_value(right->value, user_data), + new_node(key, value, left, ref_node(right->left)), + ref_node(right->right)); + unref_node(vtable, right, user_data); return n; } static gpr_avl_node *rotate_right(const gpr_avl_vtable *vtable, void *key, void *value, gpr_avl_node *left, - gpr_avl_node *right) { - gpr_avl_node *n = new_node( - vtable->copy_key(left->key), vtable->copy_value(left->value), - ref_node(left->left), new_node(key, value, ref_node(left->right), right)); - unref_node(vtable, left); + gpr_avl_node *right, void *user_data) { + gpr_avl_node *n = + new_node(vtable->copy_key(left->key, user_data), + vtable->copy_value(left->value, user_data), ref_node(left->left), + new_node(key, value, ref_node(left->right), right)); + unref_node(vtable, left, user_data); return n; } static gpr_avl_node *rotate_left_right(const gpr_avl_vtable *vtable, void *key, void *value, gpr_avl_node *left, - gpr_avl_node *right) { + gpr_avl_node *right, void *user_data) { /* rotate_right(..., rotate_left(left), right) */ - gpr_avl_node *n = new_node( - vtable->copy_key(left->right->key), - vtable->copy_value(left->right->value), - new_node(vtable->copy_key(left->key), vtable->copy_value(left->value), - ref_node(left->left), ref_node(left->right->left)), - new_node(key, value, ref_node(left->right->right), right)); - unref_node(vtable, left); + gpr_avl_node *n = + new_node(vtable->copy_key(left->right->key, user_data), + vtable->copy_value(left->right->value, user_data), + new_node(vtable->copy_key(left->key, user_data), + vtable->copy_value(left->value, user_data), + ref_node(left->left), ref_node(left->right->left)), + new_node(key, value, ref_node(left->right->right), right)); + unref_node(vtable, left, user_data); return n; } static gpr_avl_node *rotate_right_left(const gpr_avl_vtable *vtable, void *key, void *value, gpr_avl_node *left, - gpr_avl_node *right) { + gpr_avl_node *right, void *user_data) { /* rotate_left(..., left, rotate_right(right)) */ - gpr_avl_node *n = new_node( - vtable->copy_key(right->left->key), - vtable->copy_value(right->left->value), - new_node(key, value, left, ref_node(right->left->left)), - new_node(vtable->copy_key(right->key), vtable->copy_value(right->value), - ref_node(right->left->right), ref_node(right->right))); - unref_node(vtable, right); + gpr_avl_node *n = + new_node(vtable->copy_key(right->left->key, user_data), + vtable->copy_value(right->left->value, user_data), + new_node(key, value, left, ref_node(right->left->left)), + new_node(vtable->copy_key(right->key, user_data), + vtable->copy_value(right->value, user_data), + ref_node(right->left->right), ref_node(right->right))); + unref_node(vtable, right, user_data); return n; } static gpr_avl_node *rebalance(const gpr_avl_vtable *vtable, void *key, void *value, gpr_avl_node *left, - gpr_avl_node *right) { + gpr_avl_node *right, void *user_data) { switch (node_height(left) - node_height(right)) { case 2: if (node_height(left->left) - node_height(left->right) == -1) { return assert_invariants( - rotate_left_right(vtable, key, value, left, right)); + rotate_left_right(vtable, key, value, left, right, user_data)); } else { - return assert_invariants(rotate_right(vtable, key, value, left, right)); + return assert_invariants( + rotate_right(vtable, key, value, left, right, user_data)); } case -2: if (node_height(right->left) - node_height(right->right) == 1) { return assert_invariants( - rotate_right_left(vtable, key, value, left, right)); + rotate_right_left(vtable, key, value, left, right, user_data)); } else { - return assert_invariants(rotate_left(vtable, key, value, left, right)); + return assert_invariants( + rotate_left(vtable, key, value, left, right, user_data)); } default: return assert_invariants(new_node(key, value, left, right)); } } -static gpr_avl_node *add(const gpr_avl_vtable *vtable, gpr_avl_node *node, - void *key, void *value) { +static gpr_avl_node *add_key(const gpr_avl_vtable *vtable, gpr_avl_node *node, + void *key, void *value, void *user_data) { long cmp; if (node == NULL) { return new_node(key, value, NULL, NULL); } - cmp = vtable->compare_keys(node->key, key); + cmp = vtable->compare_keys(node->key, key, user_data); if (cmp == 0) { return new_node(key, value, ref_node(node->left), ref_node(node->right)); } else if (cmp > 0) { - return rebalance( - vtable, vtable->copy_key(node->key), vtable->copy_value(node->value), - add(vtable, node->left, key, value), ref_node(node->right)); + return rebalance(vtable, vtable->copy_key(node->key, user_data), + vtable->copy_value(node->value, user_data), + add_key(vtable, node->left, key, value, user_data), + ref_node(node->right), user_data); } else { - return rebalance(vtable, vtable->copy_key(node->key), - vtable->copy_value(node->value), ref_node(node->left), - add(vtable, node->right, key, value)); + return rebalance( + vtable, vtable->copy_key(node->key, user_data), + vtable->copy_value(node->value, user_data), ref_node(node->left), + add_key(vtable, node->right, key, value, user_data), user_data); } } -gpr_avl gpr_avl_add(gpr_avl avl, void *key, void *value) { +gpr_avl gpr_avl_add(gpr_avl avl, void *key, void *value, void *user_data) { gpr_avl_node *old_root = avl.root; - avl.root = add(avl.vtable, avl.root, key, value); + avl.root = add_key(avl.vtable, avl.root, key, value, user_data); assert_invariants(avl.root); - unref_node(avl.vtable, old_root); + unref_node(avl.vtable, old_root, user_data); return avl; } @@ -247,13 +240,14 @@ static gpr_avl_node *in_order_tail(gpr_avl_node *node) { return node; } -static gpr_avl_node *remove(const gpr_avl_vtable *vtable, gpr_avl_node *node, - void *key) { +static gpr_avl_node *remove_key(const gpr_avl_vtable *vtable, + gpr_avl_node *node, void *key, + void *user_data) { long cmp; if (node == NULL) { return NULL; } - cmp = vtable->compare_keys(node->key, key); + cmp = vtable->compare_keys(node->key, key, user_data); if (cmp == 0) { if (node->left == NULL) { return ref_node(node->right); @@ -261,39 +255,45 @@ static gpr_avl_node *remove(const gpr_avl_vtable *vtable, gpr_avl_node *node, return ref_node(node->left); } else if (node->left->height < node->right->height) { gpr_avl_node *h = in_order_head(node->right); - return rebalance(vtable, vtable->copy_key(h->key), - vtable->copy_value(h->value), ref_node(node->left), - remove(vtable, node->right, h->key)); + return rebalance( + vtable, vtable->copy_key(h->key, user_data), + vtable->copy_value(h->value, user_data), ref_node(node->left), + remove_key(vtable, node->right, h->key, user_data), user_data); } else { gpr_avl_node *h = in_order_tail(node->left); - return rebalance( - vtable, vtable->copy_key(h->key), vtable->copy_value(h->value), - remove(vtable, node->left, h->key), ref_node(node->right)); + return rebalance(vtable, vtable->copy_key(h->key, user_data), + vtable->copy_value(h->value, user_data), + remove_key(vtable, node->left, h->key, user_data), + ref_node(node->right), user_data); } } else if (cmp > 0) { - return rebalance(vtable, vtable->copy_key(node->key), - vtable->copy_value(node->value), - remove(vtable, node->left, key), ref_node(node->right)); + return rebalance(vtable, vtable->copy_key(node->key, user_data), + vtable->copy_value(node->value, user_data), + remove_key(vtable, node->left, key, user_data), + ref_node(node->right), user_data); } else { - return rebalance(vtable, vtable->copy_key(node->key), - vtable->copy_value(node->value), ref_node(node->left), - remove(vtable, node->right, key)); + return rebalance( + vtable, vtable->copy_key(node->key, user_data), + vtable->copy_value(node->value, user_data), ref_node(node->left), + remove_key(vtable, node->right, key, user_data), user_data); } } -gpr_avl gpr_avl_remove(gpr_avl avl, void *key) { +gpr_avl gpr_avl_remove(gpr_avl avl, void *key, void *user_data) { gpr_avl_node *old_root = avl.root; - avl.root = remove(avl.vtable, avl.root, key); + avl.root = remove_key(avl.vtable, avl.root, key, user_data); assert_invariants(avl.root); - unref_node(avl.vtable, old_root); + unref_node(avl.vtable, old_root, user_data); return avl; } -gpr_avl gpr_avl_ref(gpr_avl avl) { +gpr_avl gpr_avl_ref(gpr_avl avl, void *user_data) { ref_node(avl.root); return avl; } -void gpr_avl_unref(gpr_avl avl) { unref_node(avl.vtable, avl.root); } +void gpr_avl_unref(gpr_avl avl, void *user_data) { + unref_node(avl.vtable, avl.root, user_data); +} int gpr_avl_is_empty(gpr_avl avl) { return avl.root == NULL; } diff --git a/Sources/CgRPC/src/core/lib/support/backoff.c b/Sources/CgRPC/src/core/lib/support/backoff.c index 061247271..6dc0df473 100644 --- a/Sources/CgRPC/src/core/lib/support/backoff.c +++ b/Sources/CgRPC/src/core/lib/support/backoff.c @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/support/backoff.h b/Sources/CgRPC/src/core/lib/support/backoff.h index 5e9b74082..6e0cc3a4b 100644 --- a/Sources/CgRPC/src/core/lib/support/backoff.h +++ b/Sources/CgRPC/src/core/lib/support/backoff.h @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/support/block_annotate.h b/Sources/CgRPC/src/core/lib/support/block_annotate.h index 8fb380241..0a2cb4501 100644 --- a/Sources/CgRPC/src/core/lib/support/block_annotate.h +++ b/Sources/CgRPC/src/core/lib/support/block_annotate.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/support/cmdline.c b/Sources/CgRPC/src/core/lib/support/cmdline.c index d47498676..9fb80d446 100644 --- a/Sources/CgRPC/src/core/lib/support/cmdline.c +++ b/Sources/CgRPC/src/core/lib/support/cmdline.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -71,8 +56,7 @@ struct gpr_cmdline { static int normal_state(gpr_cmdline *cl, char *arg); gpr_cmdline *gpr_cmdline_create(const char *description) { - gpr_cmdline *cl = gpr_malloc(sizeof(gpr_cmdline)); - memset(cl, 0, sizeof(gpr_cmdline)); + gpr_cmdline *cl = (gpr_cmdline *)gpr_zalloc(sizeof(gpr_cmdline)); cl->description = description; cl->state = normal_state; @@ -101,8 +85,7 @@ static void add_arg(gpr_cmdline *cl, const char *name, const char *help, GPR_ASSERT(0 != strcmp(a->name, name)); } - a = gpr_malloc(sizeof(arg)); - memset(a, 0, sizeof(arg)); + a = (arg *)gpr_zalloc(sizeof(arg)); a->name = name; a->help = help; a->type = type; @@ -304,7 +287,7 @@ static int normal_state(gpr_cmdline *cl, char *str) { eq = strchr(str, '='); if (eq != NULL) { /* copy the string into a temp buffer and extract the name */ - tmp = arg_name = gpr_malloc((size_t)(eq - str + 1)); + tmp = arg_name = (char *)gpr_malloc((size_t)(eq - str + 1)); memcpy(arg_name, str, (size_t)(eq - str)); arg_name[eq - str] = 0; } else { diff --git a/Sources/CgRPC/src/core/lib/support/cpu_iphone.c b/Sources/CgRPC/src/core/lib/support/cpu_iphone.c index 82b49b47b..dfd69b9fd 100644 --- a/Sources/CgRPC/src/core/lib/support/cpu_iphone.c +++ b/Sources/CgRPC/src/core/lib/support/cpu_iphone.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/support/cpu_linux.c b/Sources/CgRPC/src/core/lib/support/cpu_linux.c index d6f7e7d3d..228066844 100644 --- a/Sources/CgRPC/src/core/lib/support/cpu_linux.c +++ b/Sources/CgRPC/src/core/lib/support/cpu_linux.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -67,12 +52,17 @@ unsigned gpr_cpu_num_cores(void) { } unsigned gpr_cpu_current_cpu(void) { +#ifdef GPR_MUSL_LIBC_COMPAT + // sched_getcpu() is undefined on musl + return 0; +#else int cpu = sched_getcpu(); if (cpu < 0) { gpr_log(GPR_ERROR, "Error determining current CPU: %s\n", strerror(errno)); return 0; } return (unsigned)cpu; +#endif } #endif /* GPR_CPU_LINUX */ diff --git a/Sources/CgRPC/src/core/lib/support/cpu_posix.c b/Sources/CgRPC/src/core/lib/support/cpu_posix.c index 667bde7ca..a1ba8202a 100644 --- a/Sources/CgRPC/src/core/lib/support/cpu_posix.c +++ b/Sources/CgRPC/src/core/lib/support/cpu_posix.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -41,6 +26,7 @@ #include #include +#include static __thread char magic_thread_local; @@ -60,18 +46,12 @@ unsigned gpr_cpu_num_cores(void) { return (unsigned)ncpus; } -/* This is a cheap, but good enough, pointer hash for sharding things: */ -static size_t shard_ptr(const void *info) { - size_t x = (size_t)info; - return ((x >> 4) ^ (x >> 9) ^ (x >> 14)) % gpr_cpu_num_cores(); -} - unsigned gpr_cpu_current_cpu(void) { /* NOTE: there's no way I know to return the actual cpu index portably... most code that's using this is using it to shard across work queues though, so here we use thread identity instead to achieve a similar though not identical effect */ - return (unsigned)shard_ptr(&magic_thread_local); + return (unsigned)GPR_HASH_POINTER(&magic_thread_local, gpr_cpu_num_cores()); } #endif /* GPR_CPU_POSIX */ diff --git a/Sources/CgRPC/src/core/lib/support/cpu_windows.c b/Sources/CgRPC/src/core/lib/support/cpu_windows.c index 34d006bfc..af26ff367 100644 --- a/Sources/CgRPC/src/core/lib/support/cpu_windows.c +++ b/Sources/CgRPC/src/core/lib/support/cpu_windows.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/support/env.h b/Sources/CgRPC/src/core/lib/support/env.h index 6ada5d939..e2c012a72 100644 --- a/Sources/CgRPC/src/core/lib/support/env.h +++ b/Sources/CgRPC/src/core/lib/support/env.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -51,6 +36,12 @@ char *gpr_getenv(const char *name); /* Sets the the environment with the specified name to the specified value. */ void gpr_setenv(const char *name, const char *value); +/* This is a version of gpr_getenv that does not produce any output if it has to + use an insecure version of the function. It is ONLY to be used to solve the + problem in which we need to check an env variable to configure the verbosity + level of logging. So DO NOT USE THIS. */ +const char *gpr_getenv_silent(const char *name, char **dst); + #ifdef __cplusplus } #endif diff --git a/Sources/CgRPC/src/core/lib/support/env_linux.c b/Sources/CgRPC/src/core/lib/support/env_linux.c index 2436eb20b..4c45a977c 100644 --- a/Sources/CgRPC/src/core/lib/support/env_linux.c +++ b/Sources/CgRPC/src/core/lib/support/env_linux.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -53,7 +38,9 @@ #include "src/core/lib/support/string.h" -char *gpr_getenv(const char *name) { +const char *gpr_getenv_silent(const char *name, char **dst) { + const char *insecure_func_used = NULL; + char *result = NULL; #if defined(GPR_BACKWARDS_COMPATIBILITY_MODE) typedef char *(*getenv_type)(const char *); static getenv_type getenv_func = NULL; @@ -63,22 +50,28 @@ char *gpr_getenv(const char *name) { for (size_t i = 0; getenv_func == NULL && i < GPR_ARRAY_SIZE(names); i++) { getenv_func = (getenv_type)dlsym(RTLD_DEFAULT, names[i]); if (getenv_func != NULL && strstr(names[i], "secure") == NULL) { - gpr_log(GPR_DEBUG, - "Warning: insecure environment read function '%s' used", - names[i]); + insecure_func_used = names[i]; } } - char *result = getenv_func(name); - return result == NULL ? result : gpr_strdup(result); + result = getenv_func(name); #elif __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 17) - char *result = secure_getenv(name); - return result == NULL ? result : gpr_strdup(result); + result = secure_getenv(name); #else - gpr_log(GPR_DEBUG, "Warning: insecure environment read function '%s' used", - "getenv"); - char *result = getenv(name); - return result == NULL ? result : gpr_strdup(result); + result = getenv(name); + insecure_func_used = "getenv"; #endif + *dst = result == NULL ? result : gpr_strdup(result); + return insecure_func_used; +} + +char *gpr_getenv(const char *name) { + char *result = NULL; + const char *insecure_func_used = gpr_getenv_silent(name, &result); + if (insecure_func_used != NULL) { + gpr_log(GPR_DEBUG, "Warning: insecure environment read function '%s' used", + insecure_func_used); + } + return result; } void gpr_setenv(const char *name, const char *value) { diff --git a/Sources/CgRPC/src/core/lib/support/env_posix.c b/Sources/CgRPC/src/core/lib/support/env_posix.c index ff4763044..b88822ca0 100644 --- a/Sources/CgRPC/src/core/lib/support/env_posix.c +++ b/Sources/CgRPC/src/core/lib/support/env_posix.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -44,6 +29,11 @@ #include #include "src/core/lib/support/string.h" +const char *gpr_getenv_silent(const char *name, char **dst) { + *dst = gpr_getenv(name); + return NULL; +} + char *gpr_getenv(const char *name) { char *result = getenv(name); return result == NULL ? result : gpr_strdup(result); diff --git a/Sources/CgRPC/src/core/lib/support/env_windows.c b/Sources/CgRPC/src/core/lib/support/env_windows.c index 911695944..652eeb61c 100644 --- a/Sources/CgRPC/src/core/lib/support/env_windows.c +++ b/Sources/CgRPC/src/core/lib/support/env_windows.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -45,6 +30,11 @@ #include #include +const char *gpr_getenv_silent(const char *name, char **dst) { + *dst = gpr_getenv(name); + return NULL; +} + char *gpr_getenv(const char *name) { char *result = NULL; DWORD size; diff --git a/Sources/CgRPC/src/core/lib/support/histogram.c b/Sources/CgRPC/src/core/lib/support/histogram.c index 7b016bbc7..6d5ead9aa 100644 --- a/Sources/CgRPC/src/core/lib/support/histogram.c +++ b/Sources/CgRPC/src/core/lib/support/histogram.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -88,7 +73,7 @@ static double bucket_start(gpr_histogram *h, double x) { gpr_histogram *gpr_histogram_create(double resolution, double max_bucket_start) { - gpr_histogram *h = gpr_malloc(sizeof(gpr_histogram)); + gpr_histogram *h = (gpr_histogram *)gpr_malloc(sizeof(gpr_histogram)); GPR_ASSERT(resolution > 0.0); GPR_ASSERT(max_bucket_start > resolution); h->sum = 0.0; @@ -102,8 +87,7 @@ gpr_histogram *gpr_histogram_create(double resolution, h->num_buckets = bucket_for_unchecked(h, max_bucket_start) + 1; GPR_ASSERT(h->num_buckets > 1); GPR_ASSERT(h->num_buckets < 100000000); - h->buckets = gpr_malloc(sizeof(uint32_t) * h->num_buckets); - memset(h->buckets, 0, sizeof(uint32_t) * h->num_buckets); + h->buckets = (uint32_t *)gpr_zalloc(sizeof(uint32_t) * h->num_buckets); return h; } diff --git a/Sources/CgRPC/src/core/lib/support/host_port.c b/Sources/CgRPC/src/core/lib/support/host_port.c index f19bdbc83..3302e574a 100644 --- a/Sources/CgRPC/src/core/lib/support/host_port.c +++ b/Sources/CgRPC/src/core/lib/support/host_port.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -98,7 +83,7 @@ int gpr_split_host_port(const char *name, char **host, char **port) { } /* Allocate return values. */ - *host = gpr_malloc(host_len + 1); + *host = (char *)gpr_malloc(host_len + 1); memcpy(*host, host_start, host_len); (*host)[host_len] = '\0'; diff --git a/Sources/CgRPC/src/core/lib/support/log.c b/Sources/CgRPC/src/core/lib/support/log.c index af1651dae..fadb4d9a2 100644 --- a/Sources/CgRPC/src/core/lib/support/log.c +++ b/Sources/CgRPC/src/core/lib/support/log.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -43,7 +28,7 @@ #include extern void gpr_default_log(gpr_log_func_args *args); -static gpr_log_func g_log_func = gpr_default_log; +static gpr_atm g_log_func = (gpr_atm)gpr_default_log; static gpr_atm g_min_severity_to_print = GPR_LOG_VERBOSITY_UNSET; const char *gpr_log_severity_string(gpr_log_severity severity) { @@ -70,7 +55,7 @@ void gpr_log_message(const char *file, int line, gpr_log_severity severity, lfargs.line = line; lfargs.severity = severity; lfargs.message = message; - g_log_func(&lfargs); + ((gpr_log_func)gpr_atm_no_barrier_load(&g_log_func))(&lfargs); } void gpr_set_log_verbosity(gpr_log_severity min_severity_to_print) { @@ -79,7 +64,8 @@ void gpr_set_log_verbosity(gpr_log_severity min_severity_to_print) { } void gpr_log_verbosity_init() { - char *verbosity = gpr_getenv("GRPC_VERBOSITY"); + char *verbosity = NULL; + const char *insecure_getenv = gpr_getenv_silent("GRPC_VERBOSITY", &verbosity); gpr_atm min_severity_to_print = GPR_LOG_SEVERITY_ERROR; if (verbosity != NULL) { @@ -96,8 +82,13 @@ void gpr_log_verbosity_init() { GPR_LOG_VERBOSITY_UNSET) { gpr_atm_no_barrier_store(&g_min_severity_to_print, min_severity_to_print); } + + if (insecure_getenv != NULL) { + gpr_log(GPR_DEBUG, "Warning: insecure environment read function '%s' used", + insecure_getenv); + } } void gpr_set_log_function(gpr_log_func f) { - g_log_func = f ? f : gpr_default_log; + gpr_atm_no_barrier_store(&g_log_func, (gpr_atm)(f ? f : gpr_default_log)); } diff --git a/Sources/CgRPC/src/core/lib/support/log_android.c b/Sources/CgRPC/src/core/lib/support/log_android.c index 94c8100fd..6f1cec51f 100644 --- a/Sources/CgRPC/src/core/lib/support/log_android.c +++ b/Sources/CgRPC/src/core/lib/support/log_android.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/support/log_linux.c b/Sources/CgRPC/src/core/lib/support/log_linux.c index 299b37737..61d234642 100644 --- a/Sources/CgRPC/src/core/lib/support/log_linux.c +++ b/Sources/CgRPC/src/core/lib/support/log_linux.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -79,6 +64,8 @@ void gpr_default_log(gpr_log_func_args *args) { time_t timer; gpr_timespec now = gpr_now(GPR_CLOCK_REALTIME); struct tm tm; + static __thread long tid = 0; + if (tid == 0) tid = gettid(); timer = (time_t)now.tv_sec; final_slash = strrchr(args->file, '/'); @@ -96,7 +83,7 @@ void gpr_default_log(gpr_log_func_args *args) { gpr_asprintf(&prefix, "%s%s.%09" PRId32 " %7ld %s:%d]", gpr_log_severity_string(args->severity), time_buffer, - now.tv_nsec, gettid(), display_file, args->line); + now.tv_nsec, tid, display_file, args->line); fprintf(stderr, "%-60s %s\n", prefix, args->message); gpr_free(prefix); diff --git a/Sources/CgRPC/src/core/lib/support/log_posix.c b/Sources/CgRPC/src/core/lib/support/log_posix.c index f972da088..8b376fce4 100644 --- a/Sources/CgRPC/src/core/lib/support/log_posix.c +++ b/Sources/CgRPC/src/core/lib/support/log_posix.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -37,6 +22,7 @@ #include #include +#include #include #include #include @@ -93,10 +79,13 @@ void gpr_default_log(gpr_log_func_args *args) { strcpy(time_buffer, "error:strftime"); } - fprintf(stderr, "%s%s.%09d %7tu %s:%d] %s\n", - gpr_log_severity_string(args->severity), time_buffer, - (int)(now.tv_nsec), gettid(), display_file, args->line, - args->message); + char *prefix; + gpr_asprintf(&prefix, "%s%s.%09d %7tu %s:%d]", + gpr_log_severity_string(args->severity), time_buffer, + (int)(now.tv_nsec), gettid(), display_file, args->line); + + fprintf(stderr, "%-70s %s\n", prefix, args->message); + gpr_free(prefix); } #endif /* defined(GPR_POSIX_LOG) */ diff --git a/Sources/CgRPC/src/core/lib/support/log_windows.c b/Sources/CgRPC/src/core/lib/support/log_windows.c index ea898c359..0fdab79ae 100644 --- a/Sources/CgRPC/src/core/lib/support/log_windows.c +++ b/Sources/CgRPC/src/core/lib/support/log_windows.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/support/memory.h b/Sources/CgRPC/src/core/lib/support/memory.h new file mode 100644 index 000000000..dc3d32e1c --- /dev/null +++ b/Sources/CgRPC/src/core/lib/support/memory.h @@ -0,0 +1,59 @@ +/* + * + * Copyright 2017 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 GRPC_CORE_LIB_SUPPORT_MEMORY_H +#define GRPC_CORE_LIB_SUPPORT_MEMORY_H + +#include + +#include +#include + +namespace grpc_core { + +// Alternative to new, since we cannot use it (for fear of libstdc++) +template +inline T* New(Args&&... args) { + void* p = gpr_malloc(sizeof(T)); + return new (p) T(std::forward(args)...); +} + +// Alternative to delete, since we cannot use it (for fear of libstdc++) +template +inline void Delete(T* p) { + p->~T(); + gpr_free(p); +} + +template +class DefaultDelete { + public: + void operator()(T* p) { Delete(p); } +}; + +template > +using UniquePtr = std::unique_ptr; + +template +inline UniquePtr MakeUnique(Args&&... args) { + return UniquePtr(New(std::forward(args)...)); +} + +} // namespace grpc_core + +#endif /* GRPC_CORE_LIB_SUPPORT_MEMORY_H */ diff --git a/Sources/CgRPC/src/core/lib/support/mpscq.c b/Sources/CgRPC/src/core/lib/support/mpscq.c index 5b9323275..e9f893988 100644 --- a/Sources/CgRPC/src/core/lib/support/mpscq.c +++ b/Sources/CgRPC/src/core/lib/support/mpscq.c @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -54,21 +39,31 @@ void gpr_mpscq_push(gpr_mpscq *q, gpr_mpscq_node *n) { } gpr_mpscq_node *gpr_mpscq_pop(gpr_mpscq *q) { + bool empty; + return gpr_mpscq_pop_and_check_end(q, &empty); +} + +gpr_mpscq_node *gpr_mpscq_pop_and_check_end(gpr_mpscq *q, bool *empty) { gpr_mpscq_node *tail = q->tail; gpr_mpscq_node *next = (gpr_mpscq_node *)gpr_atm_acq_load(&tail->next); if (tail == &q->stub) { // indicates the list is actually (ephemerally) empty - if (next == NULL) return NULL; + if (next == NULL) { + *empty = true; + return NULL; + } q->tail = next; tail = next; next = (gpr_mpscq_node *)gpr_atm_acq_load(&tail->next); } if (next != NULL) { + *empty = false; q->tail = next; return tail; } gpr_mpscq_node *head = (gpr_mpscq_node *)gpr_atm_acq_load(&q->head); if (tail != head) { + *empty = false; // indicates a retry is in order: we're still adding return NULL; } @@ -79,5 +74,6 @@ gpr_mpscq_node *gpr_mpscq_pop(gpr_mpscq *q) { return tail; } // indicates a retry is in order: we're still adding + *empty = false; return NULL; } diff --git a/Sources/CgRPC/src/core/lib/support/mpscq.h b/Sources/CgRPC/src/core/lib/support/mpscq.h index 977a11795..daa51768f 100644 --- a/Sources/CgRPC/src/core/lib/support/mpscq.h +++ b/Sources/CgRPC/src/core/lib/support/mpscq.h @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -35,6 +20,7 @@ #define GRPC_CORE_LIB_SUPPORT_MPSCQ_H #include +#include #include // Multiple-producer single-consumer lock free queue, based upon the @@ -61,5 +47,7 @@ void gpr_mpscq_push(gpr_mpscq *q, gpr_mpscq_node *n); // Pop a node (returns NULL if no node is ready - which doesn't indicate that // the queue is empty!!) gpr_mpscq_node *gpr_mpscq_pop(gpr_mpscq *q); +// Pop a node; sets *empty to true if the queue is empty, or false if it is not +gpr_mpscq_node *gpr_mpscq_pop_and_check_end(gpr_mpscq *q, bool *empty); #endif /* GRPC_CORE_LIB_SUPPORT_MPSCQ_H */ diff --git a/Sources/CgRPC/src/core/lib/support/murmur_hash.c b/Sources/CgRPC/src/core/lib/support/murmur_hash.c index 7137c1f31..f06b970de 100644 --- a/Sources/CgRPC/src/core/lib/support/murmur_hash.c +++ b/Sources/CgRPC/src/core/lib/support/murmur_hash.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -77,8 +62,10 @@ uint32_t gpr_murmur_hash3(const void *key, size_t len, uint32_t seed) { switch (len & 3) { case 3: k1 ^= ((uint32_t)tail[2]) << 16; + /* fallthrough */ case 2: k1 ^= ((uint32_t)tail[1]) << 8; + /* fallthrough */ case 1: k1 ^= tail[0]; k1 *= c1; diff --git a/Sources/CgRPC/src/core/lib/support/murmur_hash.h b/Sources/CgRPC/src/core/lib/support/murmur_hash.h index 6d282ff35..7510b4d09 100644 --- a/Sources/CgRPC/src/core/lib/support/murmur_hash.h +++ b/Sources/CgRPC/src/core/lib/support/murmur_hash.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/support/spinlock.h b/Sources/CgRPC/src/core/lib/support/spinlock.h new file mode 100644 index 000000000..37adda11b --- /dev/null +++ b/Sources/CgRPC/src/core/lib/support/spinlock.h @@ -0,0 +1,37 @@ +/* + * + * 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 GRPC_CORE_LIB_SUPPORT_SPINLOCK_H +#define GRPC_CORE_LIB_SUPPORT_SPINLOCK_H + +#include + +/* Simple spinlock. No backoff strategy, gpr_spinlock_lock is almost always + a concurrency code smell. */ +typedef struct { gpr_atm atm; } gpr_spinlock; + +#define GPR_SPINLOCK_INITIALIZER ((gpr_spinlock){0}) +#define GPR_SPINLOCK_STATIC_INITIALIZER \ + { 0 } +#define gpr_spinlock_trylock(lock) (gpr_atm_acq_cas(&(lock)->atm, 0, 1)) +#define gpr_spinlock_unlock(lock) (gpr_atm_rel_store(&(lock)->atm, 0)) +#define gpr_spinlock_lock(lock) \ + do { \ + } while (!gpr_spinlock_trylock((lock))) + +#endif /* GRPC_CORE_LIB_SUPPORT_SPINLOCK_H */ diff --git a/Sources/CgRPC/src/core/lib/support/stack_lockfree.c b/Sources/CgRPC/src/core/lib/support/stack_lockfree.c index 9d7c9e5a3..0fb64ed00 100644 --- a/Sources/CgRPC/src/core/lib/support/stack_lockfree.c +++ b/Sources/CgRPC/src/core/lib/support/stack_lockfree.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -72,28 +57,20 @@ typedef union lockfree_node { struct gpr_stack_lockfree { lockfree_node *entries; lockfree_node head; /* An atomic entry describing curr head */ - -#ifndef NDEBUG - /* Bitmap of pushed entries to check for double-push or pop */ - gpr_atm pushed[(INVALID_ENTRY_INDEX + 1) / (8 * sizeof(gpr_atm))]; -#endif }; gpr_stack_lockfree *gpr_stack_lockfree_create(size_t entries) { gpr_stack_lockfree *stack; - stack = gpr_malloc(sizeof(*stack)); + stack = (gpr_stack_lockfree *)gpr_malloc(sizeof(*stack)); /* Since we only allocate 16 bits to represent an entry number, * make sure that we are within the desired range */ /* Reserve the highest entry number as a dummy */ GPR_ASSERT(entries < INVALID_ENTRY_INDEX); - stack->entries = gpr_malloc_aligned(entries * sizeof(stack->entries[0]), - ENTRY_ALIGNMENT_BITS); + stack->entries = (lockfree_node *)gpr_malloc_aligned( + entries * sizeof(stack->entries[0]), ENTRY_ALIGNMENT_BITS); /* Clear out all entries */ memset(stack->entries, 0, entries * sizeof(stack->entries[0])); memset(&stack->head, 0, sizeof(stack->head)); -#ifndef NDEBUG - memset(&stack->pushed, 0, sizeof(stack->pushed)); -#endif GPR_ASSERT(sizeof(stack->entries->atm) == sizeof(stack->entries->contents)); @@ -130,19 +107,6 @@ int gpr_stack_lockfree_push(gpr_stack_lockfree *stack, int entry) { newhead.contents.aba_ctr = ++curent.contents.aba_ctr; gpr_atm_no_barrier_store(&stack->entries[entry].atm, curent.atm); -#ifndef NDEBUG - /* Check for double push */ - { - int pushed_index = entry / (int)(8 * sizeof(gpr_atm)); - int pushed_bit = entry % (int)(8 * sizeof(gpr_atm)); - gpr_atm old_val; - - old_val = gpr_atm_no_barrier_fetch_add(&stack->pushed[pushed_index], - ((gpr_atm)1 << pushed_bit)); - GPR_ASSERT((old_val & (((gpr_atm)1) << pushed_bit)) == 0); - } -#endif - do { /* Atomically get the existing head value for use */ head.atm = gpr_atm_no_barrier_load(&(stack->head.atm)); @@ -168,18 +132,6 @@ int gpr_stack_lockfree_pop(gpr_stack_lockfree *stack) { gpr_atm_no_barrier_load(&(stack->entries[head.contents.index].atm)); } while (!gpr_atm_no_barrier_cas(&(stack->head.atm), head.atm, newhead.atm)); -#ifndef NDEBUG - /* Check for valid pop */ - { - int pushed_index = head.contents.index / (8 * sizeof(gpr_atm)); - int pushed_bit = head.contents.index % (8 * sizeof(gpr_atm)); - gpr_atm old_val; - - old_val = gpr_atm_no_barrier_fetch_add(&stack->pushed[pushed_index], - -((gpr_atm)1 << pushed_bit)); - GPR_ASSERT((old_val & (((gpr_atm)1) << pushed_bit)) != 0); - } -#endif return head.contents.index; } diff --git a/Sources/CgRPC/src/core/lib/support/stack_lockfree.h b/Sources/CgRPC/src/core/lib/support/stack_lockfree.h index 35ef7c295..6324211b7 100644 --- a/Sources/CgRPC/src/core/lib/support/stack_lockfree.h +++ b/Sources/CgRPC/src/core/lib/support/stack_lockfree.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/support/string.c b/Sources/CgRPC/src/core/lib/support/string.c index f10a30f0f..b65009754 100644 --- a/Sources/CgRPC/src/core/lib/support/string.c +++ b/Sources/CgRPC/src/core/lib/support/string.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -53,7 +38,7 @@ char *gpr_strdup(const char *src) { } len = strlen(src) + 1; - dst = gpr_malloc(len); + dst = (char *)gpr_malloc(len); memcpy(dst, src, len); @@ -74,13 +59,13 @@ static dump_out dump_out_create(void) { static void dump_out_append(dump_out *out, char c) { if (out->length == out->capacity) { out->capacity = GPR_MAX(8, 2 * out->capacity); - out->data = gpr_realloc(out->data, out->capacity); + out->data = (char *)gpr_realloc(out->data, out->capacity); } out->data[out->length++] = c; } static void hexdump(dump_out *out, const char *buf, size_t len) { - static const char hex[16] = "0123456789abcdef"; + static const char *hex = "0123456789abcdef"; const uint8_t *const beg = (const uint8_t *)buf; const uint8_t *const end = beg + len; @@ -124,16 +109,16 @@ char *gpr_dump(const char *buf, size_t len, uint32_t flags) { int gpr_parse_bytes_to_uint32(const char *buf, size_t len, uint32_t *result) { uint32_t out = 0; - uint32_t new; + uint32_t new_val; size_t i; if (len == 0) return 0; /* must have some bytes */ for (i = 0; i < len; i++) { if (buf[i] < '0' || buf[i] > '9') return 0; /* bad char */ - new = 10 * out + (uint32_t)(buf[i] - '0'); - if (new < out) return 0; /* overflow */ - out = new; + new_val = 10 * out + (uint32_t)(buf[i] - '0'); + if (new_val < out) return 0; /* overflow */ + out = new_val; } *result = out; @@ -201,7 +186,7 @@ int gpr_parse_nonnegative_int(const char *value) { char *gpr_leftpad(const char *str, char flag, size_t length) { const size_t str_length = strlen(str); const size_t out_length = str_length > length ? str_length : length; - char *out = gpr_malloc(out_length + 1); + char *out = (char *)gpr_malloc(out_length + 1); memset(out, flag, out_length - str_length); memcpy(out + out_length - str_length, str, str_length); out[out_length] = 0; @@ -225,7 +210,7 @@ char *gpr_strjoin_sep(const char **strs, size_t nstrs, const char *sep, if (nstrs > 0) { out_length += sep_len * (nstrs - 1); /* separators */ } - out = gpr_malloc(out_length); + out = (char *)gpr_malloc(out_length); out_length = 0; for (i = 0; i < nstrs; i++) { const size_t slen = strlen(strs[i]); @@ -256,7 +241,7 @@ void gpr_strvec_destroy(gpr_strvec *sv) { void gpr_strvec_add(gpr_strvec *sv, char *str) { if (sv->count == sv->capacity) { sv->capacity = GPR_MAX(sv->capacity + 8, sv->capacity * 2); - sv->strs = gpr_realloc(sv->strs, sizeof(char *) * sv->capacity); + sv->strs = (char **)gpr_realloc(sv->strs, sizeof(char *) * sv->capacity); } sv->strs[sv->count++] = str; } @@ -275,3 +260,41 @@ int gpr_stricmp(const char *a, const char *b) { } while (ca == cb && ca && cb); return ca - cb; } + +static void add_string_to_split(const char *beg, const char *end, char ***strs, + size_t *nstrs, size_t *capstrs) { + char *out = (char *)gpr_malloc((size_t)(end - beg) + 1); + memcpy(out, beg, (size_t)(end - beg)); + out[end - beg] = 0; + if (*nstrs == *capstrs) { + *capstrs = GPR_MAX(8, 2 * *capstrs); + *strs = (char **)gpr_realloc(*strs, sizeof(*strs) * *capstrs); + } + (*strs)[*nstrs] = out; + ++*nstrs; +} + +void gpr_string_split(const char *input, const char *sep, char ***strs, + size_t *nstrs) { + char *next; + *strs = NULL; + *nstrs = 0; + size_t capstrs = 0; + while ((next = strstr(input, sep))) { + add_string_to_split(input, next, strs, nstrs, &capstrs); + input = next + strlen(sep); + } + add_string_to_split(input, input + strlen(input), strs, nstrs, &capstrs); +} + +void *gpr_memrchr(const void *s, int c, size_t n) { + if (s == NULL) return NULL; + char *b = (char *)s; + size_t i; + for (i = 0; i < n; i++) { + if (b[n - i - 1] == c) { + return &b[n - i - 1]; + } + } + return NULL; +} diff --git a/Sources/CgRPC/src/core/lib/support/string.h b/Sources/CgRPC/src/core/lib/support/string.h index e933e2eb4..e11df8439 100644 --- a/Sources/CgRPC/src/core/lib/support/string.h +++ b/Sources/CgRPC/src/core/lib/support/string.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -36,8 +21,6 @@ #include -#include -#include #include #ifdef __cplusplus @@ -98,6 +81,9 @@ char *gpr_strjoin(const char **strs, size_t nstrs, size_t *total_length); char *gpr_strjoin_sep(const char **strs, size_t nstrs, const char *sep, size_t *total_length); +void gpr_string_split(const char *input, const char *sep, char ***strs, + size_t *nstrs); + /* A vector of strings... for building up a final string one piece at a time */ typedef struct { char **strs; @@ -118,6 +104,8 @@ char *gpr_strvec_flatten(gpr_strvec *strs, size_t *total_length); lower(a)==lower(b), >0 if lower(a)>lower(b) */ int gpr_stricmp(const char *a, const char *b); +void *gpr_memrchr(const void *s, int c, size_t n); + #ifdef __cplusplus } #endif diff --git a/Sources/CgRPC/src/core/lib/support/string_posix.c b/Sources/CgRPC/src/core/lib/support/string_posix.c index c804ed5de..e768faf73 100644 --- a/Sources/CgRPC/src/core/lib/support/string_posix.c +++ b/Sources/CgRPC/src/core/lib/support/string_posix.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -58,7 +43,7 @@ int gpr_asprintf(char **strp, const char *format, ...) { /* Allocate a new buffer, with space for the NUL terminator. */ strp_buflen = (size_t)ret + 1; - if ((*strp = gpr_malloc(strp_buflen)) == NULL) { + if ((*strp = (char *)gpr_malloc(strp_buflen)) == NULL) { /* This shouldn't happen, because gpr_malloc() calls abort(). */ return -1; } diff --git a/Sources/CgRPC/src/core/lib/support/string_util_windows.c b/Sources/CgRPC/src/core/lib/support/string_util_windows.c index 049c9a8c0..2a0340444 100644 --- a/Sources/CgRPC/src/core/lib/support/string_util_windows.c +++ b/Sources/CgRPC/src/core/lib/support/string_util_windows.c @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/support/string_windows.c b/Sources/CgRPC/src/core/lib/support/string_windows.c index ecc2a3a4e..50278d955 100644 --- a/Sources/CgRPC/src/core/lib/support/string_windows.c +++ b/Sources/CgRPC/src/core/lib/support/string_windows.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/support/string_windows.h b/Sources/CgRPC/src/core/lib/support/string_windows.h index 899563b72..7c7f31e7a 100644 --- a/Sources/CgRPC/src/core/lib/support/string_windows.h +++ b/Sources/CgRPC/src/core/lib/support/string_windows.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/support/subprocess_posix.c b/Sources/CgRPC/src/core/lib/support/subprocess_posix.c index 4247a1c12..af75162ee 100644 --- a/Sources/CgRPC/src/core/lib/support/subprocess_posix.c +++ b/Sources/CgRPC/src/core/lib/support/subprocess_posix.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -67,7 +52,7 @@ gpr_subprocess *gpr_subprocess_create(int argc, const char **argv) { if (pid == -1) { return NULL; } else if (pid == 0) { - exec_args = gpr_malloc(((size_t)argc + 1) * sizeof(char *)); + exec_args = (char **)gpr_malloc(((size_t)argc + 1) * sizeof(char *)); memcpy(exec_args, argv, (size_t)argc * sizeof(char *)); exec_args[argc] = NULL; execv(exec_args[0], exec_args); @@ -76,8 +61,7 @@ gpr_subprocess *gpr_subprocess_create(int argc, const char **argv) { _exit(1); return NULL; } else { - r = gpr_malloc(sizeof(gpr_subprocess)); - memset(r, 0, sizeof(*r)); + r = (gpr_subprocess *)gpr_zalloc(sizeof(gpr_subprocess)); r->pid = pid; return r; } diff --git a/Sources/CgRPC/src/core/lib/support/subprocess_windows.c b/Sources/CgRPC/src/core/lib/support/subprocess_windows.c index dee8c44ac..7412f8d34 100644 --- a/Sources/CgRPC/src/core/lib/support/subprocess_windows.c +++ b/Sources/CgRPC/src/core/lib/support/subprocess_windows.c @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/support/sync.c b/Sources/CgRPC/src/core/lib/support/sync.c index 44b83f817..994dcb0e1 100644 --- a/Sources/CgRPC/src/core/lib/support/sync.c +++ b/Sources/CgRPC/src/core/lib/support/sync.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -37,6 +22,8 @@ #include #include +#include + /* Number of mutexes to allocate for events, to avoid lock contention. Should be a prime. */ enum { event_sync_partitions = 31 }; @@ -99,8 +86,12 @@ void gpr_ref_init(gpr_refcount *r, int n) { gpr_atm_rel_store(&r->count, n); } void gpr_ref(gpr_refcount *r) { gpr_atm_no_barrier_fetch_add(&r->count, 1); } void gpr_ref_non_zero(gpr_refcount *r) { +#ifndef NDEBUG gpr_atm prior = gpr_atm_no_barrier_fetch_add(&r->count, 1); - GPR_ASSERT(prior > 0); + assert(prior > 0); +#else + gpr_ref(r); +#endif } void gpr_refn(gpr_refcount *r, int n) { @@ -113,6 +104,10 @@ int gpr_unref(gpr_refcount *r) { return prior == 1; } +int gpr_ref_is_unique(gpr_refcount *r) { + return gpr_atm_acq_load(&r->count) == 1; +} + void gpr_stats_init(gpr_stats_counter *c, intptr_t n) { gpr_atm_rel_store(&c->value, n); } diff --git a/Sources/CgRPC/src/core/lib/support/sync_posix.c b/Sources/CgRPC/src/core/lib/support/sync_posix.c index dcb0969a4..62d800b18 100644 --- a/Sources/CgRPC/src/core/lib/support/sync_posix.c +++ b/Sources/CgRPC/src/core/lib/support/sync_posix.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -42,11 +27,20 @@ #include #include "src/core/lib/profiling/timers.h" +#ifdef GPR_LOW_LEVEL_COUNTERS +gpr_atm gpr_mu_locks = 0; +gpr_atm gpr_counter_atm_cas = 0; +gpr_atm gpr_counter_atm_add = 0; +#endif + void gpr_mu_init(gpr_mu* mu) { GPR_ASSERT(pthread_mutex_init(mu, NULL) == 0); } void gpr_mu_destroy(gpr_mu* mu) { GPR_ASSERT(pthread_mutex_destroy(mu) == 0); } void gpr_mu_lock(gpr_mu* mu) { +#ifdef GPR_LOW_LEVEL_COUNTERS + GPR_ATM_INC_COUNTER(gpr_mu_locks); +#endif GPR_TIMER_BEGIN("gpr_mu_lock", 0); GPR_ASSERT(pthread_mutex_lock(mu) == 0); GPR_TIMER_END("gpr_mu_lock", 0); diff --git a/Sources/CgRPC/src/core/lib/support/sync_windows.c b/Sources/CgRPC/src/core/lib/support/sync_windows.c index 8f0e8ff69..008c5aecb 100644 --- a/Sources/CgRPC/src/core/lib/support/sync_windows.c +++ b/Sources/CgRPC/src/core/lib/support/sync_windows.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/support/thd.c b/Sources/CgRPC/src/core/lib/support/thd.c index 40f53a18e..ca62615d6 100644 --- a/Sources/CgRPC/src/core/lib/support/thd.c +++ b/Sources/CgRPC/src/core/lib/support/thd.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/support/thd_internal.h b/Sources/CgRPC/src/core/lib/support/thd_internal.h index 975d5537c..cc468c784 100644 --- a/Sources/CgRPC/src/core/lib/support/thd_internal.h +++ b/Sources/CgRPC/src/core/lib/support/thd_internal.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/support/thd_posix.c b/Sources/CgRPC/src/core/lib/support/thd_posix.c index 2fc23bffa..98afd10df 100644 --- a/Sources/CgRPC/src/core/lib/support/thd_posix.c +++ b/Sources/CgRPC/src/core/lib/support/thd_posix.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -65,7 +50,7 @@ int gpr_thd_new(gpr_thd_id *t, void (*thd_body)(void *arg), void *arg, pthread_t p; /* don't use gpr_malloc as we may cause an infinite recursion with * the profiling code */ - struct thd_arg *a = malloc(sizeof(*a)); + struct thd_arg *a = (struct thd_arg *)malloc(sizeof(*a)); GPR_ASSERT(a != NULL); a->body = thd_body; a->arg = arg; diff --git a/Sources/CgRPC/src/core/lib/support/thd_windows.c b/Sources/CgRPC/src/core/lib/support/thd_windows.c index 74d2250df..54533e941 100644 --- a/Sources/CgRPC/src/core/lib/support/thd_windows.c +++ b/Sources/CgRPC/src/core/lib/support/thd_windows.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/support/time.c b/Sources/CgRPC/src/core/lib/support/time.c index 5a7d043ae..6903674d7 100644 --- a/Sources/CgRPC/src/core/lib/support/time.c +++ b/Sources/CgRPC/src/core/lib/support/time.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -42,7 +27,7 @@ int gpr_time_cmp(gpr_timespec a, gpr_timespec b) { int cmp = (a.tv_sec > b.tv_sec) - (a.tv_sec < b.tv_sec); GPR_ASSERT(a.clock_type == b.clock_type); - if (cmp == 0) { + if (cmp == 0 && a.tv_sec != INT64_MAX && a.tv_sec != INT64_MIN) { cmp = (a.tv_nsec > b.tv_nsec) - (a.tv_nsec < b.tv_nsec); } return cmp; @@ -244,15 +229,9 @@ gpr_timespec gpr_convert_clock_type(gpr_timespec t, gpr_clock_type clock_type) { return t; } - if (t.tv_nsec == 0) { - if (t.tv_sec == INT64_MAX) { - t.clock_type = clock_type; - return t; - } - if (t.tv_sec == INT64_MIN) { - t.clock_type = clock_type; - return t; - } + if (t.tv_sec == INT64_MAX || t.tv_sec == INT64_MIN) { + t.clock_type = clock_type; + return t; } if (clock_type == GPR_TIMESPAN) { diff --git a/Sources/CgRPC/src/core/lib/support/time_posix.c b/Sources/CgRPC/src/core/lib/support/time_posix.c index a69c501e9..3ead40d80 100644 --- a/Sources/CgRPC/src/core/lib/support/time_posix.c +++ b/Sources/CgRPC/src/core/lib/support/time_posix.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -42,6 +27,7 @@ #ifdef __linux__ #include #endif +#include #include #include #include "src/core/lib/support/block_annotate.h" @@ -144,7 +130,14 @@ static gpr_timespec now_impl(gpr_clock_type clock) { gpr_timespec (*gpr_now_impl)(gpr_clock_type clock_type) = now_impl; +#ifdef GPR_LOW_LEVEL_COUNTERS +gpr_atm gpr_now_call_count; +#endif + gpr_timespec gpr_now(gpr_clock_type clock_type) { +#ifdef GPR_LOW_LEVEL_COUNTERS + __atomic_fetch_add(&gpr_now_call_count, 1, __ATOMIC_RELAXED); +#endif return gpr_now_impl(clock_type); } diff --git a/Sources/CgRPC/src/core/lib/support/time_precise.c b/Sources/CgRPC/src/core/lib/support/time_precise.c index a2cf74bc8..6ce19e53c 100644 --- a/Sources/CgRPC/src/core/lib/support/time_precise.c +++ b/Sources/CgRPC/src/core/lib/support/time_precise.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -37,26 +22,26 @@ #ifdef GRPC_TIMERS_RDTSC #if defined(__i386__) -static void gpr_get_cycle_counter(long long int *clk) { - long long int ret; +static void gpr_get_cycle_counter(int64_t int *clk) { + int64_t int ret; __asm__ volatile("rdtsc" : "=A"(ret)); *clk = ret; } // ---------------------------------------------------------------- #elif defined(__x86_64__) || defined(__amd64__) -static void gpr_get_cycle_counter(long long int *clk) { - unsigned long long low, high; +static void gpr_get_cycle_counter(int64_t *clk) { + uint64_t low, high; __asm__ volatile("rdtsc" : "=a"(low), "=d"(high)); - *clk = (long long)(high << 32) | (long long)low; + *clk = (int64_t)(high << 32) | (int64_t)low; } #endif static double cycles_per_second = 0; -static long long int start_cycle; +static int64_t start_cycle; void gpr_precise_clock_init(void) { time_t start; - long long end_cycle; + int64_t end_cycle; gpr_log(GPR_DEBUG, "Calibrating timers"); start = time(NULL); while (time(NULL) == start) @@ -70,7 +55,7 @@ void gpr_precise_clock_init(void) { } void gpr_precise_clock_now(gpr_timespec *clk) { - long long int counter; + int64_t counter; double secs; gpr_get_cycle_counter(&counter); secs = (double)(counter - start_cycle) / cycles_per_second; diff --git a/Sources/CgRPC/src/core/lib/support/time_precise.h b/Sources/CgRPC/src/core/lib/support/time_precise.h index 30818d04b..aa28d6d7c 100644 --- a/Sources/CgRPC/src/core/lib/support/time_precise.h +++ b/Sources/CgRPC/src/core/lib/support/time_precise.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/support/time_windows.c b/Sources/CgRPC/src/core/lib/support/time_windows.c index 645973287..40df3761c 100644 --- a/Sources/CgRPC/src/core/lib/support/time_windows.c +++ b/Sources/CgRPC/src/core/lib/support/time_windows.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -56,7 +41,7 @@ void gpr_time_init(void) { g_time_scale = 1.0 / (double)frequency.QuadPart; } -gpr_timespec gpr_now(gpr_clock_type clock) { +static gpr_timespec now_impl(gpr_clock_type clock) { gpr_timespec now_tv; LONGLONG diff; struct _timeb now_tb; @@ -84,6 +69,12 @@ gpr_timespec gpr_now(gpr_clock_type clock) { return now_tv; } +gpr_timespec (*gpr_now_impl)(gpr_clock_type clock_type) = now_impl; + +gpr_timespec gpr_now(gpr_clock_type clock_type) { + return gpr_now_impl(clock_type); +} + void gpr_sleep_until(gpr_timespec until) { gpr_timespec now; gpr_timespec delta; diff --git a/Sources/CgRPC/src/core/lib/support/tls_pthread.c b/Sources/CgRPC/src/core/lib/support/tls_pthread.c index 9683a6e54..9ebee577f 100644 --- a/Sources/CgRPC/src/core/lib/support/tls_pthread.c +++ b/Sources/CgRPC/src/core/lib/support/tls_pthread.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/support/tmpfile.h b/Sources/CgRPC/src/core/lib/support/tmpfile.h index 8952e5ec3..caa1d0f4d 100644 --- a/Sources/CgRPC/src/core/lib/support/tmpfile.h +++ b/Sources/CgRPC/src/core/lib/support/tmpfile.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -36,8 +21,6 @@ #include -#include - #ifdef __cplusplus extern "C" { #endif diff --git a/Sources/CgRPC/src/core/lib/support/tmpfile_msys.c b/Sources/CgRPC/src/core/lib/support/tmpfile_msys.c index 4f566c4c2..614c0a4a1 100644 --- a/Sources/CgRPC/src/core/lib/support/tmpfile_msys.c +++ b/Sources/CgRPC/src/core/lib/support/tmpfile_msys.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/support/tmpfile_posix.c b/Sources/CgRPC/src/core/lib/support/tmpfile_posix.c index 0cd4bb6fc..7ad3af0a5 100644 --- a/Sources/CgRPC/src/core/lib/support/tmpfile_posix.c +++ b/Sources/CgRPC/src/core/lib/support/tmpfile_posix.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -50,34 +35,34 @@ FILE *gpr_tmpfile(const char *prefix, char **tmp_filename) { FILE *result = NULL; - char *template; + char *filename_template; int fd; if (tmp_filename != NULL) *tmp_filename = NULL; - gpr_asprintf(&template, "/tmp/%s_XXXXXX", prefix); - GPR_ASSERT(template != NULL); + gpr_asprintf(&filename_template, "/tmp/%s_XXXXXX", prefix); + GPR_ASSERT(filename_template != NULL); - fd = mkstemp(template); + fd = mkstemp(filename_template); if (fd == -1) { - gpr_log(GPR_ERROR, "mkstemp failed for template %s with error %s.", - template, strerror(errno)); + gpr_log(GPR_ERROR, "mkstemp failed for filename_template %s with error %s.", + filename_template, strerror(errno)); goto end; } result = fdopen(fd, "w+"); if (result == NULL) { gpr_log(GPR_ERROR, "Could not open file %s from fd %d (error = %s).", - template, fd, strerror(errno)); - unlink(template); + filename_template, fd, strerror(errno)); + unlink(filename_template); close(fd); goto end; } end: if (result != NULL && tmp_filename != NULL) { - *tmp_filename = template; + *tmp_filename = filename_template; } else { - gpr_free(template); + gpr_free(filename_template); } return result; } diff --git a/Sources/CgRPC/src/core/lib/support/tmpfile_windows.c b/Sources/CgRPC/src/core/lib/support/tmpfile_windows.c index 542f53e58..47b4510a7 100644 --- a/Sources/CgRPC/src/core/lib/support/tmpfile_windows.c +++ b/Sources/CgRPC/src/core/lib/support/tmpfile_windows.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/support/wrap_memcpy.c b/Sources/CgRPC/src/core/lib/support/wrap_memcpy.c index 15c289f7b..cff056dc3 100644 --- a/Sources/CgRPC/src/core/lib/support/wrap_memcpy.c +++ b/Sources/CgRPC/src/core/lib/support/wrap_memcpy.c @@ -1,36 +1,23 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 + #include /* Provide a wrapped memcpy for targets that need to be backwards @@ -40,7 +27,7 @@ */ #ifdef __linux__ -#ifdef __x86_64__ +#if defined(__x86_64__) && !defined(GPR_MUSL_LIBC_COMPAT) __asm__(".symver memcpy,memcpy@GLIBC_2.2.5"); void *__wrap_memcpy(void *destination, const void *source, size_t num) { return memcpy(destination, source, num); diff --git a/Sources/CgRPC/src/core/lib/surface/alarm.c b/Sources/CgRPC/src/core/lib/surface/alarm.c index aa9d60ee6..7d60b1de1 100644 --- a/Sources/CgRPC/src/core/lib/surface/alarm.c +++ b/Sources/CgRPC/src/core/lib/surface/alarm.c @@ -1,43 +1,37 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 "src/core/lib/surface/alarm_internal.h" #include #include +#include #include "src/core/lib/iomgr/timer.h" #include "src/core/lib/surface/completion_queue.h" +#ifndef NDEBUG +grpc_tracer_flag grpc_trace_alarm_refcount = + GRPC_TRACER_INITIALIZER(false, "alarm_refcount"); +#endif + struct grpc_alarm { + gpr_refcount refs; grpc_timer alarm; + grpc_closure on_alarm; grpc_cq_completion completion; /** completion queue where events about this alarm will be posted */ grpc_completion_queue *cq; @@ -45,13 +39,58 @@ struct grpc_alarm { void *tag; }; -static void do_nothing_end_completion(grpc_exec_ctx *exec_ctx, void *arg, - grpc_cq_completion *c) {} +static void alarm_ref(grpc_alarm *alarm) { gpr_ref(&alarm->refs); } + +static void alarm_unref(grpc_alarm *alarm) { + if (gpr_unref(&alarm->refs)) { + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + GRPC_CQ_INTERNAL_UNREF(&exec_ctx, alarm->cq, "alarm"); + grpc_exec_ctx_finish(&exec_ctx); + gpr_free(alarm); + } +} + +#ifndef NDEBUG +static void alarm_ref_dbg(grpc_alarm *alarm, const char *reason, + const char *file, int line) { + if (GRPC_TRACER_ON(grpc_trace_alarm_refcount)) { + gpr_atm val = gpr_atm_no_barrier_load(&alarm->refs.count); + gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, + "Alarm:%p ref %" PRIdPTR " -> %" PRIdPTR " %s", alarm, val, + val + 1, reason); + } + + alarm_ref(alarm); +} + +static void alarm_unref_dbg(grpc_alarm *alarm, const char *reason, + const char *file, int line) { + if (GRPC_TRACER_ON(grpc_trace_alarm_refcount)) { + gpr_atm val = gpr_atm_no_barrier_load(&alarm->refs.count); + gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, + "Alarm:%p Unref %" PRIdPTR " -> %" PRIdPTR " %s", alarm, val, + val - 1, reason); + } + + alarm_unref(alarm); +} +#endif + +static void alarm_end_completion(grpc_exec_ctx *exec_ctx, void *arg, + grpc_cq_completion *c) { + grpc_alarm *alarm = arg; + GRPC_ALARM_UNREF(alarm, "dequeue-end-op"); +} static void alarm_cb(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { grpc_alarm *alarm = arg; - grpc_cq_end_op(exec_ctx, alarm->cq, alarm->tag, error, - do_nothing_end_completion, NULL, &alarm->completion); + + /* We are queuing an op on completion queue. This means, the alarm's structure + cannot be destroyed until the op is dequeued. Adding an extra ref + here and unref'ing when the op is dequeued will achieve this */ + GRPC_ALARM_REF(alarm, "queue-end-op"); + grpc_cq_end_op(exec_ctx, alarm->cq, alarm->tag, error, alarm_end_completion, + (void *)alarm, &alarm->completion); } grpc_alarm *grpc_alarm_create(grpc_completion_queue *cq, gpr_timespec deadline, @@ -59,14 +98,24 @@ grpc_alarm *grpc_alarm_create(grpc_completion_queue *cq, gpr_timespec deadline, grpc_alarm *alarm = gpr_malloc(sizeof(grpc_alarm)); grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + gpr_ref_init(&alarm->refs, 1); + +#ifndef NDEBUG + if (GRPC_TRACER_ON(grpc_trace_alarm_refcount)) { + gpr_log(GPR_DEBUG, "Alarm:%p created (ref: 1)", alarm); + } +#endif + GRPC_CQ_INTERNAL_REF(cq, "alarm"); alarm->cq = cq; alarm->tag = tag; - grpc_cq_begin_op(cq, tag); + GPR_ASSERT(grpc_cq_begin_op(cq, tag)); + GRPC_CLOSURE_INIT(&alarm->on_alarm, alarm_cb, alarm, + grpc_schedule_on_exec_ctx); grpc_timer_init(&exec_ctx, &alarm->alarm, gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC), - alarm_cb, alarm, gpr_now(GPR_CLOCK_MONOTONIC)); + &alarm->on_alarm, gpr_now(GPR_CLOCK_MONOTONIC)); grpc_exec_ctx_finish(&exec_ctx); return alarm; } @@ -79,6 +128,5 @@ void grpc_alarm_cancel(grpc_alarm *alarm) { void grpc_alarm_destroy(grpc_alarm *alarm) { grpc_alarm_cancel(alarm); - GRPC_CQ_INTERNAL_UNREF(alarm->cq, "alarm"); - gpr_free(alarm); + GRPC_ALARM_UNREF(alarm, "alarm_destroy"); } diff --git a/Sources/CgRPC/src/core/lib/surface/alarm_internal.h b/Sources/CgRPC/src/core/lib/surface/alarm_internal.h new file mode 100644 index 000000000..7f2126c5c --- /dev/null +++ b/Sources/CgRPC/src/core/lib/surface/alarm_internal.h @@ -0,0 +1,40 @@ +/* + * + * Copyright 2015-2017 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 GRPC_CORE_LIB_SURFACE_ALARM_INTERNAL_H +#define GRPC_CORE_LIB_SURFACE_ALARM_INTERNAL_H + +#include +#include "src/core/lib/debug/trace.h" + +#ifndef NDEBUG + +extern grpc_tracer_flag grpc_trace_alarm_refcount; + +#define GRPC_ALARM_REF(a, reason) alarm_ref_dbg(a, reason, __FILE__, __LINE__) +#define GRPC_ALARM_UNREF(a, reason) \ + alarm_unref_dbg(a, reason, __FILE__, __LINE__) + +#else /* !defined(NDEBUG) */ + +#define GRPC_ALARM_REF(a, reason) alarm_ref(a) +#define GRPC_ALARM_UNREF(a, reason) alarm_unref(a) + +#endif /* defined(NDEBUG) */ + +#endif /* GRPC_CORE_LIB_SURFACE_ALARM_INTERNAL_H */ diff --git a/Sources/CgRPC/src/core/lib/surface/api_trace.c b/Sources/CgRPC/src/core/lib/surface/api_trace.c index 79e3e5ca9..56973303d 100644 --- a/Sources/CgRPC/src/core/lib/surface/api_trace.c +++ b/Sources/CgRPC/src/core/lib/surface/api_trace.c @@ -1,36 +1,22 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 "src/core/lib/surface/api_trace.h" +#include "src/core/lib/debug/trace.h" -int grpc_api_trace = 0; +grpc_tracer_flag grpc_api_trace = GRPC_TRACER_INITIALIZER(false, "api"); diff --git a/Sources/CgRPC/src/core/lib/surface/api_trace.h b/Sources/CgRPC/src/core/lib/surface/api_trace.h index c60aaba5e..849cbaaef 100644 --- a/Sources/CgRPC/src/core/lib/surface/api_trace.h +++ b/Sources/CgRPC/src/core/lib/surface/api_trace.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -37,7 +22,7 @@ #include #include "src/core/lib/debug/trace.h" -extern int grpc_api_trace; +extern grpc_tracer_flag grpc_api_trace; /* Provide unwrapping macros because we're in C89 and variadic macros weren't introduced until C99... */ @@ -58,7 +43,7 @@ extern int grpc_api_trace; /* Due to the limitations of C89's preprocessor, the arity of the var-arg list 'nargs' must be specified. */ #define GRPC_API_TRACE(fmt, nargs, args) \ - if (grpc_api_trace) { \ + if (GRPC_TRACER_ON(grpc_api_trace)) { \ gpr_log(GPR_INFO, fmt GRPC_API_TRACE_UNWRAP##nargs args); \ } diff --git a/Sources/CgRPC/src/core/lib/surface/byte_buffer.c b/Sources/CgRPC/src/core/lib/surface/byte_buffer.c index d646591a6..0bc990d48 100644 --- a/Sources/CgRPC/src/core/lib/surface/byte_buffer.c +++ b/Sources/CgRPC/src/core/lib/surface/byte_buffer.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -35,6 +20,8 @@ #include #include +#include "src/core/lib/slice/slice_internal.h" + grpc_byte_buffer *grpc_raw_byte_buffer_create(grpc_slice *slices, size_t nslices) { return grpc_raw_compressed_byte_buffer_create(slices, nslices, @@ -50,7 +37,7 @@ grpc_byte_buffer *grpc_raw_compressed_byte_buffer_create( bb->data.raw.compression = compression; grpc_slice_buffer_init(&bb->data.raw.slice_buffer); for (i = 0; i < nslices; i++) { - grpc_slice_ref(slices[i]); + grpc_slice_ref_internal(slices[i]); grpc_slice_buffer_add(&bb->data.raw.slice_buffer, slices[i]); } return bb; @@ -82,12 +69,14 @@ grpc_byte_buffer *grpc_byte_buffer_copy(grpc_byte_buffer *bb) { void grpc_byte_buffer_destroy(grpc_byte_buffer *bb) { if (!bb) return; + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; switch (bb->type) { case GRPC_BB_RAW: - grpc_slice_buffer_destroy(&bb->data.raw.slice_buffer); + grpc_slice_buffer_destroy_internal(&exec_ctx, &bb->data.raw.slice_buffer); break; } gpr_free(bb); + grpc_exec_ctx_finish(&exec_ctx); } size_t grpc_byte_buffer_length(grpc_byte_buffer *bb) { diff --git a/Sources/CgRPC/src/core/lib/surface/byte_buffer_reader.c b/Sources/CgRPC/src/core/lib/surface/byte_buffer_reader.c index 0089959fb..87bd3239c 100644 --- a/Sources/CgRPC/src/core/lib/surface/byte_buffer_reader.c +++ b/Sources/CgRPC/src/core/lib/surface/byte_buffer_reader.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -42,6 +27,7 @@ #include #include "src/core/lib/compression/message_compress.h" +#include "src/core/lib/slice/slice_internal.h" static int is_compressed(grpc_byte_buffer *buffer) { switch (buffer->type) { @@ -56,13 +42,15 @@ static int is_compressed(grpc_byte_buffer *buffer) { int grpc_byte_buffer_reader_init(grpc_byte_buffer_reader *reader, grpc_byte_buffer *buffer) { + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_slice_buffer decompressed_slices_buffer; reader->buffer_in = buffer; switch (reader->buffer_in->type) { case GRPC_BB_RAW: grpc_slice_buffer_init(&decompressed_slices_buffer); if (is_compressed(reader->buffer_in)) { - if (grpc_msg_decompress(reader->buffer_in->data.raw.compression, + if (grpc_msg_decompress(&exec_ctx, + reader->buffer_in->data.raw.compression, &reader->buffer_in->data.raw.slice_buffer, &decompressed_slices_buffer) == 0) { gpr_log(GPR_ERROR, @@ -76,13 +64,15 @@ int grpc_byte_buffer_reader_init(grpc_byte_buffer_reader *reader, grpc_raw_byte_buffer_create(decompressed_slices_buffer.slices, decompressed_slices_buffer.count); } - grpc_slice_buffer_destroy(&decompressed_slices_buffer); + grpc_slice_buffer_destroy_internal(&exec_ctx, + &decompressed_slices_buffer); } else { /* not compressed, use the input buffer as output */ reader->buffer_out = reader->buffer_in; } reader->current.index = 0; break; } + grpc_exec_ctx_finish(&exec_ctx); return 1; } @@ -104,7 +94,8 @@ int grpc_byte_buffer_reader_next(grpc_byte_buffer_reader *reader, grpc_slice_buffer *slice_buffer; slice_buffer = &reader->buffer_out->data.raw.slice_buffer; if (reader->current.index < slice_buffer->count) { - *slice = grpc_slice_ref(slice_buffer->slices[reader->current.index]); + *slice = grpc_slice_ref_internal( + slice_buffer->slices[reader->current.index]); reader->current.index += 1; return 1; } @@ -118,15 +109,17 @@ grpc_slice grpc_byte_buffer_reader_readall(grpc_byte_buffer_reader *reader) { grpc_slice in_slice; size_t bytes_read = 0; const size_t input_size = grpc_byte_buffer_length(reader->buffer_out); - grpc_slice out_slice = grpc_slice_malloc(input_size); + grpc_slice out_slice = GRPC_SLICE_MALLOC(input_size); uint8_t *const outbuf = GRPC_SLICE_START_PTR(out_slice); /* just an alias */ + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; while (grpc_byte_buffer_reader_next(reader, &in_slice) != 0) { const size_t slice_length = GRPC_SLICE_LENGTH(in_slice); memcpy(&(outbuf[bytes_read]), GRPC_SLICE_START_PTR(in_slice), slice_length); bytes_read += slice_length; - grpc_slice_unref(in_slice); + grpc_slice_unref_internal(&exec_ctx, in_slice); GPR_ASSERT(bytes_read <= input_size); } + grpc_exec_ctx_finish(&exec_ctx); return out_slice; } diff --git a/Sources/CgRPC/src/core/lib/surface/call.c b/Sources/CgRPC/src/core/lib/surface/call.c index 8ca3cab9d..00ec9c7c9 100644 --- a/Sources/CgRPC/src/core/lib/surface/call.c +++ b/Sources/CgRPC/src/core/lib/surface/call.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -49,19 +34,23 @@ #include "src/core/lib/compression/algorithm_metadata.h" #include "src/core/lib/iomgr/timer.h" #include "src/core/lib/profiling/timers.h" +#include "src/core/lib/slice/slice_internal.h" #include "src/core/lib/slice/slice_string_helpers.h" +#include "src/core/lib/support/arena.h" #include "src/core/lib/support/string.h" #include "src/core/lib/surface/api_trace.h" #include "src/core/lib/surface/call.h" #include "src/core/lib/surface/channel.h" #include "src/core/lib/surface/completion_queue.h" +#include "src/core/lib/surface/validate_metadata.h" +#include "src/core/lib/transport/error_utils.h" #include "src/core/lib/transport/metadata.h" #include "src/core/lib/transport/static_metadata.h" #include "src/core/lib/transport/transport.h" /** The maximum number of concurrent batches possible. Based upon the maximum number of individually queueable ops in the batch - api: + api: - initial metadata send - message send - status/close send (depending on client/server) @@ -83,58 +72,94 @@ typedef enum { /* Status came from 'the wire' - or somewhere below the surface layer */ STATUS_FROM_WIRE, - /* Status was created by some internal channel stack operation */ + /* Status was created by some internal channel stack operation: must come via + add_batch_error */ STATUS_FROM_CORE, + /* Status was created by some surface error */ + STATUS_FROM_SURFACE, /* Status came from the server sending status */ STATUS_FROM_SERVER_STATUS, STATUS_SOURCE_COUNT } status_source; typedef struct { - uint8_t is_set; - grpc_status_code code; - grpc_mdstr *details; + bool is_set; + grpc_error *error; } received_status; +static gpr_atm pack_received_status(received_status r) { + return r.is_set ? (1 | (gpr_atm)r.error) : 0; +} + +static received_status unpack_received_status(gpr_atm atm) { + return (atm & 1) == 0 + ? (received_status){.is_set = false, .error = GRPC_ERROR_NONE} + : (received_status){.is_set = true, + .error = (grpc_error *)(atm & ~(gpr_atm)1)}; +} + +#define MAX_ERRORS_PER_BATCH 4 + typedef struct batch_control { grpc_call *call; - grpc_cq_completion cq_completion; + /* Share memory for cq_completion and notify_tag as they are never needed + simultaneously. Each byte used in this data structure count as six bytes + per call, so any savings we can make are worthwhile, + + We use notify_tag to determine whether or not to send notification to the + completion queue. Once we've made that determination, we can reuse the + memory for cq_completion. */ + union { + grpc_cq_completion cq_completion; + struct { + /* Any given op indicates completion by either (a) calling a closure or + (b) sending a notification on the call's completion queue. If + \a is_closure is true, \a tag indicates a closure to be invoked; + otherwise, \a tag indicates the tag to be used in the notification to + be sent to the completion queue. */ + void *tag; + bool is_closure; + } notify_tag; + } completion_data; grpc_closure finish_batch; - void *notify_tag; gpr_refcount steps_to_complete; - grpc_error *error; - uint8_t send_initial_metadata; - uint8_t send_message; - uint8_t send_final_op; - uint8_t recv_initial_metadata; - uint8_t recv_message; - uint8_t recv_final_op; - uint8_t is_notify_tag_closure; - - /* TODO(ctiller): now that this is inlined, figure out how much of the above - state can be eliminated */ - grpc_transport_stream_op op; + grpc_error *errors[MAX_ERRORS_PER_BATCH]; + gpr_atm num_errors; + + grpc_transport_stream_op_batch op; } batch_control; +typedef struct { + gpr_mu child_list_mu; + grpc_call *first_child; +} parent_call; + +typedef struct { + grpc_call *parent; + /** siblings: children of the same parent form a list, and this list is + protected under + parent->mu */ + grpc_call *sibling_next; + grpc_call *sibling_prev; +} child_call; + struct grpc_call { + gpr_refcount ext_ref; + gpr_arena *arena; grpc_completion_queue *cq; grpc_polling_entity pollent; grpc_channel *channel; - grpc_call *parent; - grpc_call *first_child; gpr_timespec start_time; - /* TODO(ctiller): share with cq if possible? */ - gpr_mu mu; + /* parent_call* */ gpr_atm parent_call_atm; + child_call *child_call; /* client or server call */ bool is_client; - /** has grpc_call_destroy been called */ + /** has grpc_call_unref been called */ bool destroy_called; /** flag indicating that cancellation is inherited */ bool cancellation_is_inherited; - /** bitmask of live batches */ - uint8_t used_batches; /** which ops are in-flight */ bool sent_initial_metadata; bool sending_message; @@ -142,12 +167,14 @@ struct grpc_call { bool received_initial_metadata; bool receiving_message; bool requested_final_op; - bool received_final_op; + gpr_atm any_ops_sent_atm; + gpr_atm received_final_op_atm; /* have we received initial metadata */ bool has_initial_md_been_received; - batch_control active_batches[MAX_CONCURRENT_BATCHES]; + batch_control *active_batches[MAX_CONCURRENT_BATCHES]; + grpc_transport_stream_op_batch_payload stream_op_payload; /* first idx: is_receiving, second idx: is_trailing */ grpc_metadata_batch metadata_batch[2][2]; @@ -156,8 +183,8 @@ struct grpc_call { Element 0 is initial metadata, element 1 is trailing metadata. */ grpc_metadata_array *buffered_metadata[2]; - /* Received call statuses from various sources */ - received_status status[STATUS_SOURCE_COUNT]; + /* Packed received call statuses from various sources */ + gpr_atm status[STATUS_SOURCE_COUNT]; /* Call data useful used for reporting. Only valid after the call has * completed */ @@ -177,13 +204,8 @@ struct grpc_call { int send_extra_metadata_count; gpr_timespec send_deadline; - /** siblings: children of the same parent form a list, and this list is - protected under - parent->mu */ - grpc_call *sibling_next; - grpc_call *sibling_prev; - grpc_slice_buffer_stream sending_stream; + grpc_byte_stream *receiving_stream; grpc_byte_buffer **receiving_buffer; grpc_slice receiving_slice; @@ -192,11 +214,12 @@ struct grpc_call { grpc_closure receiving_initial_metadata_ready; uint32_t test_only_last_message_flags; + grpc_closure release_call; + union { struct { grpc_status_code *status; - char **status_details; - size_t *status_details_capacity; + grpc_slice *status_details; } client; struct { int *cancelled; @@ -206,6 +229,11 @@ struct grpc_call { void *saved_receiving_stream_ready_bctlp; }; +grpc_tracer_flag grpc_call_error_trace = + GRPC_TRACER_INITIALIZER(false, "call_error"); +grpc_tracer_flag grpc_compression_trace = + GRPC_TRACER_INITIALIZER(false, "compression"); + #define CALL_STACK_FROM_CALL(call) ((grpc_call_stack *)((call) + 1)) #define CALL_FROM_CALL_STACK(call_stack) (((grpc_call *)(call_stack)) - 1) #define CALL_ELEM_FROM_CALL(call, idx) \ @@ -214,45 +242,89 @@ struct grpc_call { CALL_FROM_CALL_STACK(grpc_call_stack_from_top_element(top_elem)) static void execute_op(grpc_exec_ctx *exec_ctx, grpc_call *call, - grpc_transport_stream_op *op); -static grpc_call_error cancel_with_status(grpc_exec_ctx *exec_ctx, grpc_call *c, - grpc_status_code status, - const char *description); -static grpc_call_error close_with_status(grpc_exec_ctx *exec_ctx, grpc_call *c, - grpc_status_code status, - const char *description); + grpc_transport_stream_op_batch *op); +static void cancel_with_status(grpc_exec_ctx *exec_ctx, grpc_call *c, + status_source source, grpc_status_code status, + const char *description); +static void cancel_with_error(grpc_exec_ctx *exec_ctx, grpc_call *c, + status_source source, grpc_error *error); static void destroy_call(grpc_exec_ctx *exec_ctx, void *call_stack, grpc_error *error); static void receiving_slice_ready(grpc_exec_ctx *exec_ctx, void *bctlp, grpc_error *error); +static void get_final_status(grpc_call *call, + void (*set_value)(grpc_status_code code, + void *user_data), + void *set_value_user_data, grpc_slice *details); +static void set_status_value_directly(grpc_status_code status, void *dest); +static void set_status_from_error(grpc_exec_ctx *exec_ctx, grpc_call *call, + status_source source, grpc_error *error); +static void process_data_after_md(grpc_exec_ctx *exec_ctx, batch_control *bctl); +static void post_batch_completion(grpc_exec_ctx *exec_ctx, batch_control *bctl); +static void add_batch_error(grpc_exec_ctx *exec_ctx, batch_control *bctl, + grpc_error *error, bool has_cancelled); + +static void add_init_error(grpc_error **composite, grpc_error *new) { + if (new == GRPC_ERROR_NONE) return; + if (*composite == GRPC_ERROR_NONE) + *composite = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Call creation failed"); + *composite = grpc_error_add_child(*composite, new); +} -grpc_error *grpc_call_create(const grpc_call_create_args *args, +void *grpc_call_arena_alloc(grpc_call *call, size_t size) { + return gpr_arena_alloc(call->arena, size); +} + +static parent_call *get_or_create_parent_call(grpc_call *call) { + parent_call *p = (parent_call *)gpr_atm_acq_load(&call->parent_call_atm); + if (p == NULL) { + p = gpr_arena_alloc(call->arena, sizeof(*p)); + gpr_mu_init(&p->child_list_mu); + if (!gpr_atm_rel_cas(&call->parent_call_atm, (gpr_atm)NULL, (gpr_atm)p)) { + gpr_mu_destroy(&p->child_list_mu); + p = (parent_call *)gpr_atm_acq_load(&call->parent_call_atm); + } + } + return p; +} + +static parent_call *get_parent_call(grpc_call *call) { + return (parent_call *)gpr_atm_acq_load(&call->parent_call_atm); +} + +grpc_error *grpc_call_create(grpc_exec_ctx *exec_ctx, + const grpc_call_create_args *args, grpc_call **out_call) { size_t i, j; + grpc_error *error = GRPC_ERROR_NONE; grpc_channel_stack *channel_stack = grpc_channel_get_channel_stack(args->channel); - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_call *call; GPR_TIMER_BEGIN("grpc_call_create", 0); - call = gpr_malloc(sizeof(grpc_call) + channel_stack->call_stack_size); + gpr_arena *arena = + gpr_arena_create(grpc_channel_get_call_size_estimate(args->channel)); + call = gpr_arena_alloc(arena, + sizeof(grpc_call) + channel_stack->call_stack_size); + gpr_ref_init(&call->ext_ref, 1); + call->arena = arena; *out_call = call; - memset(call, 0, sizeof(grpc_call)); - gpr_mu_init(&call->mu); call->channel = args->channel; call->cq = args->cq; - call->parent = args->parent_call; call->start_time = gpr_now(GPR_CLOCK_MONOTONIC); /* Always support no compression */ GPR_BITSET(&call->encodings_accepted_by_peer, GRPC_COMPRESS_NONE); call->is_client = args->server_transport_data == NULL; - grpc_mdstr *path = NULL; + call->stream_op_payload.context = call->context; + grpc_slice path = grpc_empty_slice(); if (call->is_client) { GPR_ASSERT(args->add_initial_metadata_count < MAX_SEND_EXTRA_METADATA_COUNT); for (i = 0; i < args->add_initial_metadata_count; i++) { call->send_extra_metadata[i].md = args->add_initial_metadata[i]; - if (args->add_initial_metadata[i]->key == GRPC_MDSTR_PATH) { - path = GRPC_MDSTR_REF(args->add_initial_metadata[i]->value); + if (grpc_slice_eq(GRPC_MDKEY(args->add_initial_metadata[i]), + GRPC_MDSTR_PATH)) { + path = grpc_slice_ref_internal( + GRPC_MDVALUE(args->add_initial_metadata[i])); } } call->send_extra_metadata_count = (int)args->add_initial_metadata_count; @@ -268,12 +340,20 @@ grpc_error *grpc_call_create(const grpc_call_create_args *args, gpr_timespec send_deadline = gpr_convert_clock_type(args->send_deadline, GPR_CLOCK_MONOTONIC); + bool immediately_cancel = false; + if (args->parent_call != NULL) { + child_call *cc = call->child_call = + gpr_arena_alloc(arena, sizeof(child_call)); + call->child_call->parent = args->parent_call; + GRPC_CALL_INTERNAL_REF(args->parent_call, "child"); GPR_ASSERT(call->is_client); GPR_ASSERT(!args->parent_call->is_client); - gpr_mu_lock(&args->parent_call->mu); + parent_call *pc = get_or_create_parent_call(args->parent_call); + + gpr_mu_lock(&pc->child_list_mu); if (args->propagation_mask & GRPC_PROPAGATE_DEADLINE) { send_deadline = gpr_time_min( @@ -286,43 +366,60 @@ grpc_error *grpc_call_create(const grpc_call_create_args *args, /* TODO(ctiller): This should change to use the appropriate census start_op * call. */ if (args->propagation_mask & GRPC_PROPAGATE_CENSUS_TRACING_CONTEXT) { - GPR_ASSERT(args->propagation_mask & GRPC_PROPAGATE_CENSUS_STATS_CONTEXT); + if (0 == (args->propagation_mask & GRPC_PROPAGATE_CENSUS_STATS_CONTEXT)) { + add_init_error(&error, GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "Census tracing propagation requested " + "without Census context propagation")); + } grpc_call_context_set( call, GRPC_CONTEXT_TRACING, args->parent_call->context[GRPC_CONTEXT_TRACING].value, NULL); - } else { - GPR_ASSERT(args->propagation_mask & GRPC_PROPAGATE_CENSUS_STATS_CONTEXT); + } else if (args->propagation_mask & GRPC_PROPAGATE_CENSUS_STATS_CONTEXT) { + add_init_error(&error, GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "Census context propagation requested " + "without Census tracing propagation")); } if (args->propagation_mask & GRPC_PROPAGATE_CANCELLATION) { call->cancellation_is_inherited = 1; + if (gpr_atm_acq_load(&args->parent_call->received_final_op_atm)) { + immediately_cancel = true; + } } - if (args->parent_call->first_child == NULL) { - args->parent_call->first_child = call; - call->sibling_next = call->sibling_prev = call; + if (pc->first_child == NULL) { + pc->first_child = call; + cc->sibling_next = cc->sibling_prev = call; } else { - call->sibling_next = args->parent_call->first_child; - call->sibling_prev = args->parent_call->first_child->sibling_prev; - call->sibling_next->sibling_prev = call->sibling_prev->sibling_next = - call; + cc->sibling_next = pc->first_child; + cc->sibling_prev = pc->first_child->child_call->sibling_prev; + cc->sibling_next->child_call->sibling_prev = + cc->sibling_prev->child_call->sibling_next = call; } - gpr_mu_unlock(&args->parent_call->mu); + gpr_mu_unlock(&pc->child_list_mu); } call->send_deadline = send_deadline; GRPC_CHANNEL_INTERNAL_REF(args->channel, "call"); - /* initial refcount dropped by grpc_call_destroy */ - grpc_error *error = grpc_call_stack_init( - &exec_ctx, channel_stack, 1, destroy_call, call, call->context, - args->server_transport_data, path, call->start_time, send_deadline, - CALL_STACK_FROM_CALL(call)); + /* initial refcount dropped by grpc_call_unref */ + grpc_call_element_args call_args = { + .call_stack = CALL_STACK_FROM_CALL(call), + .server_transport_data = args->server_transport_data, + .context = call->context, + .path = path, + .start_time = call->start_time, + .deadline = send_deadline, + .arena = call->arena}; + add_init_error(&error, grpc_call_stack_init(exec_ctx, channel_stack, 1, + destroy_call, call, &call_args)); if (error != GRPC_ERROR_NONE) { - grpc_status_code status; - const char *error_str; - grpc_error_get_status(error, &status, &error_str); - close_with_status(&exec_ctx, call, status, error_str); + cancel_with_error(exec_ctx, call, STATUS_FROM_SURFACE, + GRPC_ERROR_REF(error)); + } + if (immediately_cancel) { + cancel_with_error(exec_ctx, call, STATUS_FROM_API_OVERRIDE, + GRPC_ERROR_CANCELLED); } if (args->cq != NULL) { GPR_ASSERT( @@ -338,12 +435,11 @@ grpc_error *grpc_call_create(const grpc_call_create_args *args, } if (!grpc_polling_entity_is_empty(&call->pollent)) { grpc_call_stack_set_pollset_or_pollset_set( - &exec_ctx, CALL_STACK_FROM_CALL(call), &call->pollent); + exec_ctx, CALL_STACK_FROM_CALL(call), &call->pollent); } - if (path != NULL) GRPC_MDSTR_UNREF(path); + grpc_slice_unref_internal(exec_ctx, path); - grpc_exec_ctx_finish(&exec_ctx); GPR_TIMER_END("grpc_call_create", 0); return error; } @@ -363,7 +459,7 @@ void grpc_call_set_completion_queue(grpc_exec_ctx *exec_ctx, grpc_call *call, exec_ctx, CALL_STACK_FROM_CALL(call), &call->pollent); } -#ifdef GRPC_STREAM_REFCOUNT_DEBUG +#ifndef NDEBUG #define REF_REASON reason #define REF_ARG , const char *reason #else @@ -377,22 +473,12 @@ void grpc_call_internal_unref(grpc_exec_ctx *exec_ctx, grpc_call *c REF_ARG) { GRPC_CALL_STACK_UNREF(exec_ctx, CALL_STACK_FROM_CALL(c), REF_REASON); } -static void get_final_status(grpc_call *call, - void (*set_value)(grpc_status_code code, - void *user_data), - void *set_value_user_data) { - int i; - for (i = 0; i < STATUS_SOURCE_COUNT; i++) { - if (call->status[i].is_set) { - set_value(call->status[i].code, set_value_user_data); - return; - } - } - if (call->is_client) { - set_value(GRPC_STATUS_UNKNOWN, set_value_user_data); - } else { - set_value(GRPC_STATUS_OK, set_value_user_data); - } +static void release_call(grpc_exec_ctx *exec_ctx, void *call, + grpc_error *error) { + grpc_call *c = call; + grpc_channel *channel = c->channel; + grpc_channel_update_call_size_estimate(channel, gpr_arena_destroy(c->arena)); + GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, channel, "call"); } static void set_status_value_directly(grpc_status_code status, void *dest); @@ -404,19 +490,17 @@ static void destroy_call(grpc_exec_ctx *exec_ctx, void *call, GPR_TIMER_BEGIN("destroy_call", 0); for (i = 0; i < 2; i++) { grpc_metadata_batch_destroy( - &c->metadata_batch[1 /* is_receiving */][i /* is_initial */]); + exec_ctx, &c->metadata_batch[1 /* is_receiving */][i /* is_initial */]); } if (c->receiving_stream != NULL) { grpc_byte_stream_destroy(exec_ctx, c->receiving_stream); } - gpr_mu_destroy(&c->mu); - for (i = 0; i < STATUS_SOURCE_COUNT; i++) { - if (c->status[i].details) { - GRPC_MDSTR_UNREF(c->status[i].details); - } + parent_call *pc = get_parent_call(c); + if (pc != NULL) { + gpr_mu_destroy(&pc->child_list_mu); } for (ii = 0; ii < c->send_extra_metadata_count; ii++) { - GRPC_MDELEM_UNREF(c->send_extra_metadata[ii].md); + GRPC_MDELEM_UNREF(exec_ctx, c->send_extra_metadata[ii].md); } for (i = 0; i < GRPC_CONTEXT_COUNT; i++) { if (c->context[i].destroy) { @@ -424,46 +508,244 @@ static void destroy_call(grpc_exec_ctx *exec_ctx, void *call, } } if (c->cq) { - GRPC_CQ_INTERNAL_UNREF(c->cq, "bind"); + GRPC_CQ_INTERNAL_UNREF(exec_ctx, c->cq, "bind"); } - grpc_channel *channel = c->channel; - get_final_status(call, set_status_value_directly, - &c->final_info.final_status); + get_final_status(call, set_status_value_directly, &c->final_info.final_status, + NULL); c->final_info.stats.latency = gpr_time_sub(gpr_now(GPR_CLOCK_MONOTONIC), c->start_time); - grpc_call_stack_destroy(exec_ctx, CALL_STACK_FROM_CALL(c), &c->final_info, c); - GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, channel, "call"); + for (i = 0; i < STATUS_SOURCE_COUNT; i++) { + GRPC_ERROR_UNREF( + unpack_received_status(gpr_atm_acq_load(&c->status[i])).error); + } + + grpc_call_stack_destroy(exec_ctx, CALL_STACK_FROM_CALL(c), &c->final_info, + GRPC_CLOSURE_INIT(&c->release_call, release_call, c, + grpc_schedule_on_exec_ctx)); GPR_TIMER_END("destroy_call", 0); } -static void set_status_code(grpc_call *call, status_source source, - uint32_t status) { - if (call->status[source].is_set) return; +void grpc_call_ref(grpc_call *c) { gpr_ref(&c->ext_ref); } + +void grpc_call_unref(grpc_call *c) { + if (!gpr_unref(&c->ext_ref)) return; + + child_call *cc = c->child_call; + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + + GPR_TIMER_BEGIN("grpc_call_unref", 0); + GRPC_API_TRACE("grpc_call_unref(c=%p)", 1, (c)); + + if (cc) { + parent_call *pc = get_parent_call(cc->parent); + gpr_mu_lock(&pc->child_list_mu); + if (c == pc->first_child) { + pc->first_child = cc->sibling_next; + if (c == pc->first_child) { + pc->first_child = NULL; + } + } + cc->sibling_prev->child_call->sibling_next = cc->sibling_next; + cc->sibling_next->child_call->sibling_prev = cc->sibling_prev; + gpr_mu_unlock(&pc->child_list_mu); + GRPC_CALL_INTERNAL_UNREF(&exec_ctx, cc->parent, "child"); + } + + GPR_ASSERT(!c->destroy_called); + c->destroy_called = 1; + bool cancel = gpr_atm_acq_load(&c->any_ops_sent_atm) != 0 && + gpr_atm_acq_load(&c->received_final_op_atm) == 0; + if (cancel) { + cancel_with_error(&exec_ctx, c, STATUS_FROM_API_OVERRIDE, + GRPC_ERROR_CANCELLED); + } + GRPC_CALL_INTERNAL_UNREF(&exec_ctx, c, "destroy"); + grpc_exec_ctx_finish(&exec_ctx); + GPR_TIMER_END("grpc_call_unref", 0); +} + +grpc_call_error grpc_call_cancel(grpc_call *call, void *reserved) { + GRPC_API_TRACE("grpc_call_cancel(call=%p, reserved=%p)", 2, (call, reserved)); + GPR_ASSERT(!reserved); + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + cancel_with_error(&exec_ctx, call, STATUS_FROM_API_OVERRIDE, + GRPC_ERROR_CANCELLED); + grpc_exec_ctx_finish(&exec_ctx); + return GRPC_CALL_OK; +} + +static void execute_op(grpc_exec_ctx *exec_ctx, grpc_call *call, + grpc_transport_stream_op_batch *op) { + grpc_call_element *elem; + + GPR_TIMER_BEGIN("execute_op", 0); + elem = CALL_ELEM_FROM_CALL(call, 0); + elem->filter->start_transport_stream_op_batch(exec_ctx, elem, op); + GPR_TIMER_END("execute_op", 0); +} + +char *grpc_call_get_peer(grpc_call *call) { + grpc_call_element *elem = CALL_ELEM_FROM_CALL(call, 0); + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + char *result; + GRPC_API_TRACE("grpc_call_get_peer(%p)", 1, (call)); + result = elem->filter->get_peer(&exec_ctx, elem); + if (result == NULL) { + result = grpc_channel_get_target(call->channel); + } + if (result == NULL) { + result = gpr_strdup("unknown"); + } + grpc_exec_ctx_finish(&exec_ctx); + return result; +} + +grpc_call *grpc_call_from_top_element(grpc_call_element *elem) { + return CALL_FROM_TOP_ELEM(elem); +} + +/******************************************************************************* + * CANCELLATION + */ + +grpc_call_error grpc_call_cancel_with_status(grpc_call *c, + grpc_status_code status, + const char *description, + void *reserved) { + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + GRPC_API_TRACE( + "grpc_call_cancel_with_status(" + "c=%p, status=%d, description=%s, reserved=%p)", + 4, (c, (int)status, description, reserved)); + GPR_ASSERT(reserved == NULL); + cancel_with_status(&exec_ctx, c, STATUS_FROM_API_OVERRIDE, status, + description); + grpc_exec_ctx_finish(&exec_ctx); + return GRPC_CALL_OK; +} + +static void done_termination(grpc_exec_ctx *exec_ctx, void *call, + grpc_error *error) { + GRPC_CALL_INTERNAL_UNREF(exec_ctx, call, "termination"); +} + +static void cancel_with_error(grpc_exec_ctx *exec_ctx, grpc_call *c, + status_source source, grpc_error *error) { + GRPC_CALL_INTERNAL_REF(c, "termination"); + set_status_from_error(exec_ctx, c, source, GRPC_ERROR_REF(error)); + grpc_transport_stream_op_batch *op = grpc_make_transport_stream_op( + GRPC_CLOSURE_CREATE(done_termination, c, grpc_schedule_on_exec_ctx)); + op->cancel_stream = true; + op->payload->cancel_stream.cancel_error = error; + execute_op(exec_ctx, c, op); +} + +static grpc_error *error_from_status(grpc_status_code status, + const char *description) { + // copying 'description' is needed to ensure the grpc_call_cancel_with_status + // guarantee that can be short-lived. + return grpc_error_set_int( + grpc_error_set_str(GRPC_ERROR_CREATE_FROM_COPIED_STRING(description), + GRPC_ERROR_STR_GRPC_MESSAGE, + grpc_slice_from_copied_string(description)), + GRPC_ERROR_INT_GRPC_STATUS, status); +} + +static void cancel_with_status(grpc_exec_ctx *exec_ctx, grpc_call *c, + status_source source, grpc_status_code status, + const char *description) { + cancel_with_error(exec_ctx, c, source, + error_from_status(status, description)); +} + +/******************************************************************************* + * FINAL STATUS CODE MANIPULATION + */ + +static bool get_final_status_from( + grpc_call *call, grpc_error *error, bool allow_ok_status, + void (*set_value)(grpc_status_code code, void *user_data), + void *set_value_user_data, grpc_slice *details) { + grpc_status_code code; + grpc_slice slice = grpc_empty_slice(); + grpc_error_get_status(error, call->send_deadline, &code, &slice, NULL); + if (code == GRPC_STATUS_OK && !allow_ok_status) { + return false; + } - call->status[source].is_set = 1; - call->status[source].code = (grpc_status_code)status; + set_value(code, set_value_user_data); + if (details != NULL) { + *details = grpc_slice_ref_internal(slice); + } + return true; } -static void set_status_details(grpc_call *call, status_source source, - grpc_mdstr *status) { - if (call->status[source].details != NULL) { - GRPC_MDSTR_UNREF(status); +static void get_final_status(grpc_call *call, + void (*set_value)(grpc_status_code code, + void *user_data), + void *set_value_user_data, grpc_slice *details) { + int i; + received_status status[STATUS_SOURCE_COUNT]; + for (i = 0; i < STATUS_SOURCE_COUNT; i++) { + status[i] = unpack_received_status(gpr_atm_acq_load(&call->status[i])); + } + if (GRPC_TRACER_ON(grpc_call_error_trace)) { + gpr_log(GPR_DEBUG, "get_final_status %s", call->is_client ? "CLI" : "SVR"); + for (i = 0; i < STATUS_SOURCE_COUNT; i++) { + if (status[i].is_set) { + gpr_log(GPR_DEBUG, " %d: %s", i, grpc_error_string(status[i].error)); + } + } + } + /* first search through ignoring "OK" statuses: if something went wrong, + * ensure we report it */ + for (int allow_ok_status = 0; allow_ok_status < 2; allow_ok_status++) { + /* search for the best status we can present: ideally the error we use has a + clearly defined grpc-status, and we'll prefer that. */ + for (i = 0; i < STATUS_SOURCE_COUNT; i++) { + if (status[i].is_set && + grpc_error_has_clear_grpc_status(status[i].error)) { + if (get_final_status_from(call, status[i].error, allow_ok_status != 0, + set_value, set_value_user_data, details)) { + return; + } + } + } + /* If no clearly defined status exists, search for 'anything' */ + for (i = 0; i < STATUS_SOURCE_COUNT; i++) { + if (status[i].is_set) { + if (get_final_status_from(call, status[i].error, allow_ok_status != 0, + set_value, set_value_user_data, details)) { + return; + } + } + } + } + /* If nothing exists, set some default */ + if (call->is_client) { + set_value(GRPC_STATUS_UNKNOWN, set_value_user_data); } else { - call->status[source].details = status; + set_value(GRPC_STATUS_OK, set_value_user_data); } } -static void set_status_from_error(grpc_call *call, status_source source, - grpc_error *error) { - grpc_status_code status; - const char *msg; - grpc_error_get_status(error, &status, &msg); - set_status_code(call, source, (uint32_t)status); - set_status_details(call, source, grpc_mdstr_from_string(msg)); +static void set_status_from_error(grpc_exec_ctx *exec_ctx, grpc_call *call, + status_source source, grpc_error *error) { + if (!gpr_atm_rel_cas(&call->status[source], + pack_received_status((received_status){ + .is_set = false, .error = GRPC_ERROR_NONE}), + pack_received_status((received_status){ + .is_set = true, .error = error}))) { + GRPC_ERROR_UNREF(error); + } } +/******************************************************************************* + * COMPRESSION + */ + static void set_incoming_compression_algorithm( grpc_call *call, grpc_compression_algorithm algo) { GPR_ASSERT(algo < GRPC_COMPRESS_ALGORITHMS_COUNT); @@ -473,9 +755,7 @@ static void set_incoming_compression_algorithm( grpc_compression_algorithm grpc_call_test_only_get_compression_algorithm( grpc_call *call) { grpc_compression_algorithm algorithm; - gpr_mu_lock(&call->mu); algorithm = call->incoming_compression_algorithm; - gpr_mu_unlock(&call->mu); return algorithm; } @@ -487,15 +767,14 @@ static grpc_compression_algorithm compression_algorithm_for_level_locked( uint32_t grpc_call_test_only_get_message_flags(grpc_call *call) { uint32_t flags; - gpr_mu_lock(&call->mu); flags = call->test_only_last_message_flags; - gpr_mu_unlock(&call->mu); return flags; } static void destroy_encodings_accepted_by_peer(void *p) { return; } -static void set_encodings_accepted_by_peer(grpc_call *call, grpc_mdelem *mdel) { +static void set_encodings_accepted_by_peer(grpc_exec_ctx *exec_ctx, + grpc_call *call, grpc_mdelem mdel) { size_t i; grpc_compression_algorithm algorithm; grpc_slice_buffer accept_encoding_parts; @@ -510,7 +789,7 @@ static void set_encodings_accepted_by_peer(grpc_call *call, grpc_mdelem *mdel) { return; } - accept_encoding_slice = mdel->value->slice; + accept_encoding_slice = GRPC_MDVALUE(mdel); grpc_slice_buffer_init(&accept_encoding_parts); grpc_slice_split(accept_encoding_slice, ",", &accept_encoding_parts); @@ -519,15 +798,13 @@ static void set_encodings_accepted_by_peer(grpc_call *call, grpc_mdelem *mdel) { /* Always support no compression */ GPR_BITSET(&call->encodings_accepted_by_peer, GRPC_COMPRESS_NONE); for (i = 0; i < accept_encoding_parts.count; i++) { - const grpc_slice *accept_encoding_entry_slice = - &accept_encoding_parts.slices[i]; - if (grpc_compression_algorithm_parse( - (const char *)GRPC_SLICE_START_PTR(*accept_encoding_entry_slice), - GRPC_SLICE_LENGTH(*accept_encoding_entry_slice), &algorithm)) { + grpc_slice accept_encoding_entry_slice = accept_encoding_parts.slices[i]; + if (grpc_compression_algorithm_parse(accept_encoding_entry_slice, + &algorithm)) { GPR_BITSET(&call->encodings_accepted_by_peer, algorithm); } else { char *accept_encoding_entry_str = - grpc_dump_slice(*accept_encoding_entry_slice, GPR_DUMP_ASCII); + grpc_slice_to_c_string(accept_encoding_entry_slice); gpr_log(GPR_ERROR, "Invalid entry in accept encoding metadata: '%s'. Ignoring.", accept_encoding_entry_str); @@ -535,7 +812,7 @@ static void set_encodings_accepted_by_peer(grpc_call *call, grpc_mdelem *mdel) { } } - grpc_slice_buffer_destroy(&accept_encoding_parts); + grpc_slice_buffer_destroy_internal(exec_ctx, &accept_encoding_parts); grpc_mdelem_set_user_data( mdel, destroy_encodings_accepted_by_peer, @@ -544,43 +821,11 @@ static void set_encodings_accepted_by_peer(grpc_call *call, grpc_mdelem *mdel) { uint32_t grpc_call_test_only_get_encodings_accepted_by_peer(grpc_call *call) { uint32_t encodings_accepted_by_peer; - gpr_mu_lock(&call->mu); encodings_accepted_by_peer = call->encodings_accepted_by_peer; - gpr_mu_unlock(&call->mu); return encodings_accepted_by_peer; } -static void get_final_details(grpc_call *call, char **out_details, - size_t *out_details_capacity) { - int i; - for (i = 0; i < STATUS_SOURCE_COUNT; i++) { - if (call->status[i].is_set) { - if (call->status[i].details) { - grpc_slice details = call->status[i].details->slice; - size_t len = GRPC_SLICE_LENGTH(details); - if (len + 1 > *out_details_capacity) { - *out_details_capacity = - GPR_MAX(len + 1, *out_details_capacity * 3 / 2); - *out_details = gpr_realloc(*out_details, *out_details_capacity); - } - memcpy(*out_details, GRPC_SLICE_START_PTR(details), len); - (*out_details)[len] = 0; - } else { - goto no_details; - } - return; - } - } - -no_details: - if (0 == *out_details_capacity) { - *out_details_capacity = 8; - *out_details = gpr_malloc(*out_details_capacity); - } - **out_details = 0; -} - -static grpc_linked_mdelem *linked_from_md(grpc_metadata *md) { +static grpc_linked_mdelem *linked_from_md(const grpc_metadata *md) { return (grpc_linked_mdelem *)&md->internal_data; } @@ -593,12 +838,10 @@ static grpc_metadata *get_md_elem(grpc_metadata *metadata, return res; } -static int prepare_application_metadata(grpc_call *call, int count, - grpc_metadata *metadata, - int is_trailing, - int prepend_extra_metadata, - grpc_metadata *additional_metadata, - int additional_metadata_count) { +static int prepare_application_metadata( + grpc_exec_ctx *exec_ctx, grpc_call *call, int count, + grpc_metadata *metadata, int is_trailing, int prepend_extra_metadata, + grpc_metadata *additional_metadata, int additional_metadata_count) { int total_count = count + additional_metadata_count; int i; grpc_metadata_batch *batch = @@ -606,30 +849,25 @@ static int prepare_application_metadata(grpc_call *call, int count, for (i = 0; i < total_count; i++) { const grpc_metadata *md = get_md_elem(metadata, additional_metadata, i, count); - grpc_linked_mdelem *l = (grpc_linked_mdelem *)&md->internal_data; + grpc_linked_mdelem *l = linked_from_md(md); GPR_ASSERT(sizeof(grpc_linked_mdelem) == sizeof(md->internal_data)); - l->md = grpc_mdelem_from_string_and_buffer( - md->key, (const uint8_t *)md->value, md->value_length); - if (!grpc_header_key_is_legal(grpc_mdstr_as_c_string(l->md->key), - GRPC_MDSTR_LENGTH(l->md->key))) { - gpr_log(GPR_ERROR, "attempt to send invalid metadata key: %s", - grpc_mdstr_as_c_string(l->md->key)); + if (!GRPC_LOG_IF_ERROR("validate_metadata", + grpc_validate_header_key_is_legal(md->key))) { break; - } else if (!grpc_is_binary_header(grpc_mdstr_as_c_string(l->md->key), - GRPC_MDSTR_LENGTH(l->md->key)) && - !grpc_header_nonbin_value_is_legal( - grpc_mdstr_as_c_string(l->md->value), - GRPC_MDSTR_LENGTH(l->md->value))) { - gpr_log(GPR_ERROR, "attempt to send invalid metadata value"); + } else if (!grpc_is_binary_header(md->key) && + !GRPC_LOG_IF_ERROR( + "validate_metadata", + grpc_validate_header_nonbin_value_is_legal(md->value))) { break; } + l->md = grpc_mdelem_from_grpc_metadata(exec_ctx, (grpc_metadata *)md); } if (i != total_count) { - for (int j = 0; j <= i; j++) { + for (int j = 0; j < i; j++) { const grpc_metadata *md = get_md_elem(metadata, additional_metadata, j, count); - grpc_linked_mdelem *l = (grpc_linked_mdelem *)&md->internal_data; - GRPC_MDELEM_UNREF(l->md); + grpc_linked_mdelem *l = linked_from_md(md); + GRPC_MDELEM_UNREF(exec_ctx, l->md); } return 0; } @@ -637,275 +875,44 @@ static int prepare_application_metadata(grpc_call *call, int count, if (call->send_extra_metadata_count == 0) { prepend_extra_metadata = 0; } else { - for (i = 1; i < call->send_extra_metadata_count; i++) { - call->send_extra_metadata[i].prev = &call->send_extra_metadata[i - 1]; - } - for (i = 0; i < call->send_extra_metadata_count - 1; i++) { - call->send_extra_metadata[i].next = &call->send_extra_metadata[i + 1]; + for (i = 0; i < call->send_extra_metadata_count; i++) { + GRPC_LOG_IF_ERROR("prepare_application_metadata", + grpc_metadata_batch_link_tail( + exec_ctx, batch, &call->send_extra_metadata[i])); } } } - for (i = 1; i < total_count; i++) { - grpc_metadata *md = get_md_elem(metadata, additional_metadata, i, count); - grpc_metadata *prev_md = - get_md_elem(metadata, additional_metadata, i - 1, count); - linked_from_md(md)->prev = linked_from_md(prev_md); - } - for (i = 0; i < total_count - 1; i++) { + for (i = 0; i < total_count; i++) { grpc_metadata *md = get_md_elem(metadata, additional_metadata, i, count); - grpc_metadata *next_md = - get_md_elem(metadata, additional_metadata, i + 1, count); - linked_from_md(md)->next = linked_from_md(next_md); - } - - switch (prepend_extra_metadata * 2 + (total_count != 0)) { - case 0: - /* no prepend, no metadata => nothing to do */ - batch->list.head = batch->list.tail = NULL; - break; - case 1: { - /* metadata, but no prepend */ - grpc_metadata *first_md = - get_md_elem(metadata, additional_metadata, 0, count); - grpc_metadata *last_md = - get_md_elem(metadata, additional_metadata, total_count - 1, count); - batch->list.head = linked_from_md(first_md); - batch->list.tail = linked_from_md(last_md); - batch->list.head->prev = NULL; - batch->list.tail->next = NULL; - break; - } - case 2: - /* prepend, but no md */ - batch->list.head = &call->send_extra_metadata[0]; - batch->list.tail = - &call->send_extra_metadata[call->send_extra_metadata_count - 1]; - batch->list.head->prev = NULL; - batch->list.tail->next = NULL; - call->send_extra_metadata_count = 0; - break; - case 3: { - /* prepend AND md */ - grpc_metadata *first_md = - get_md_elem(metadata, additional_metadata, 0, count); - grpc_metadata *last_md = - get_md_elem(metadata, additional_metadata, total_count - 1, count); - batch->list.head = &call->send_extra_metadata[0]; - call->send_extra_metadata[call->send_extra_metadata_count - 1].next = - linked_from_md(first_md); - linked_from_md(first_md)->prev = - &call->send_extra_metadata[call->send_extra_metadata_count - 1]; - batch->list.tail = linked_from_md(last_md); - batch->list.head->prev = NULL; - batch->list.tail->next = NULL; - call->send_extra_metadata_count = 0; - break; + grpc_linked_mdelem *l = linked_from_md(md); + grpc_error *error = grpc_metadata_batch_link_tail(exec_ctx, batch, l); + if (error != GRPC_ERROR_NONE) { + GRPC_MDELEM_UNREF(exec_ctx, l->md); } - default: - GPR_UNREACHABLE_CODE(return 0); + GRPC_LOG_IF_ERROR("prepare_application_metadata", error); } + call->send_extra_metadata_count = 0; return 1; } -void grpc_call_destroy(grpc_call *c) { - int cancel; - grpc_call *parent = c->parent; - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - - GPR_TIMER_BEGIN("grpc_call_destroy", 0); - GRPC_API_TRACE("grpc_call_destroy(c=%p)", 1, (c)); - - if (parent) { - gpr_mu_lock(&parent->mu); - if (c == parent->first_child) { - parent->first_child = c->sibling_next; - if (c == parent->first_child) { - parent->first_child = NULL; - } - c->sibling_prev->sibling_next = c->sibling_next; - c->sibling_next->sibling_prev = c->sibling_prev; - } - gpr_mu_unlock(&parent->mu); - GRPC_CALL_INTERNAL_UNREF(&exec_ctx, parent, "child"); - } - - gpr_mu_lock(&c->mu); - GPR_ASSERT(!c->destroy_called); - c->destroy_called = 1; - cancel = !c->received_final_op; - gpr_mu_unlock(&c->mu); - if (cancel) grpc_call_cancel(c, NULL); - GRPC_CALL_INTERNAL_UNREF(&exec_ctx, c, "destroy"); - grpc_exec_ctx_finish(&exec_ctx); - GPR_TIMER_END("grpc_call_destroy", 0); -} - -grpc_call_error grpc_call_cancel(grpc_call *call, void *reserved) { - GRPC_API_TRACE("grpc_call_cancel(call=%p, reserved=%p)", 2, (call, reserved)); - GPR_ASSERT(!reserved); - return grpc_call_cancel_with_status(call, GRPC_STATUS_CANCELLED, "Cancelled", - NULL); -} - -grpc_call_error grpc_call_cancel_with_status(grpc_call *c, - grpc_status_code status, - const char *description, - void *reserved) { - grpc_call_error r; - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - GRPC_API_TRACE( - "grpc_call_cancel_with_status(" - "c=%p, status=%d, description=%s, reserved=%p)", - 4, (c, (int)status, description, reserved)); - GPR_ASSERT(reserved == NULL); - gpr_mu_lock(&c->mu); - r = cancel_with_status(&exec_ctx, c, status, description); - gpr_mu_unlock(&c->mu); - grpc_exec_ctx_finish(&exec_ctx); - return r; -} - -typedef struct termination_closure { - grpc_closure closure; - grpc_call *call; - grpc_error *error; - enum { TC_CANCEL, TC_CLOSE } type; - grpc_transport_stream_op op; -} termination_closure; - -static void done_termination(grpc_exec_ctx *exec_ctx, void *tcp, - grpc_error *error) { - termination_closure *tc = tcp; - switch (tc->type) { - case TC_CANCEL: - GRPC_CALL_INTERNAL_UNREF(exec_ctx, tc->call, "cancel"); - break; - case TC_CLOSE: - GRPC_CALL_INTERNAL_UNREF(exec_ctx, tc->call, "close"); - break; - } - GRPC_ERROR_UNREF(tc->error); - gpr_free(tc); -} - -static void send_cancel(grpc_exec_ctx *exec_ctx, void *tcp, grpc_error *error) { - termination_closure *tc = tcp; - memset(&tc->op, 0, sizeof(tc->op)); - tc->op.cancel_error = tc->error; - /* reuse closure to catch completion */ - grpc_closure_init(&tc->closure, done_termination, tc); - tc->op.on_complete = &tc->closure; - execute_op(exec_ctx, tc->call, &tc->op); -} - -static void send_close(grpc_exec_ctx *exec_ctx, void *tcp, grpc_error *error) { - termination_closure *tc = tcp; - memset(&tc->op, 0, sizeof(tc->op)); - tc->op.close_error = tc->error; - /* reuse closure to catch completion */ - grpc_closure_init(&tc->closure, done_termination, tc); - tc->op.on_complete = &tc->closure; - execute_op(exec_ctx, tc->call, &tc->op); -} - -static grpc_call_error terminate_with_status(grpc_exec_ctx *exec_ctx, - termination_closure *tc) { - set_status_from_error(tc->call, STATUS_FROM_API_OVERRIDE, tc->error); - - if (tc->type == TC_CANCEL) { - grpc_closure_init(&tc->closure, send_cancel, tc); - GRPC_CALL_INTERNAL_REF(tc->call, "cancel"); - } else if (tc->type == TC_CLOSE) { - grpc_closure_init(&tc->closure, send_close, tc); - GRPC_CALL_INTERNAL_REF(tc->call, "close"); - } - grpc_exec_ctx_sched(exec_ctx, &tc->closure, GRPC_ERROR_NONE, NULL); - return GRPC_CALL_OK; -} - -static grpc_call_error cancel_with_status(grpc_exec_ctx *exec_ctx, grpc_call *c, - grpc_status_code status, - const char *description) { - GPR_ASSERT(status != GRPC_STATUS_OK); - termination_closure *tc = gpr_malloc(sizeof(*tc)); - memset(tc, 0, sizeof(termination_closure)); - tc->type = TC_CANCEL; - tc->call = c; - tc->error = grpc_error_set_int( - grpc_error_set_str(GRPC_ERROR_CREATE(description), - GRPC_ERROR_STR_GRPC_MESSAGE, description), - GRPC_ERROR_INT_GRPC_STATUS, status); - - return terminate_with_status(exec_ctx, tc); -} - -static grpc_call_error close_with_status(grpc_exec_ctx *exec_ctx, grpc_call *c, - grpc_status_code status, - const char *description) { - GPR_ASSERT(status != GRPC_STATUS_OK); - termination_closure *tc = gpr_malloc(sizeof(*tc)); - memset(tc, 0, sizeof(termination_closure)); - tc->type = TC_CLOSE; - tc->call = c; - tc->error = grpc_error_set_int( - grpc_error_set_str(GRPC_ERROR_CREATE(description), - GRPC_ERROR_STR_GRPC_MESSAGE, description), - GRPC_ERROR_INT_GRPC_STATUS, status); - - return terminate_with_status(exec_ctx, tc); -} - -static void execute_op(grpc_exec_ctx *exec_ctx, grpc_call *call, - grpc_transport_stream_op *op) { - grpc_call_element *elem; - - GPR_TIMER_BEGIN("execute_op", 0); - elem = CALL_ELEM_FROM_CALL(call, 0); - op->context = call->context; - elem->filter->start_transport_stream_op(exec_ctx, elem, op); - GPR_TIMER_END("execute_op", 0); -} - -char *grpc_call_get_peer(grpc_call *call) { - grpc_call_element *elem = CALL_ELEM_FROM_CALL(call, 0); - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - char *result; - GRPC_API_TRACE("grpc_call_get_peer(%p)", 1, (call)); - result = elem->filter->get_peer(&exec_ctx, elem); - if (result == NULL) { - result = grpc_channel_get_target(call->channel); - } - if (result == NULL) { - result = gpr_strdup("unknown"); - } - grpc_exec_ctx_finish(&exec_ctx); - return result; -} - -grpc_call *grpc_call_from_top_element(grpc_call_element *elem) { - return CALL_FROM_TOP_ELEM(elem); -} - /* we offset status by a small amount when storing it into transport metadata as metadata cannot store a 0 value (which is used as OK for grpc_status_codes */ #define STATUS_OFFSET 1 static void destroy_status(void *ignored) {} -static uint32_t decode_status(grpc_mdelem *md) { +static uint32_t decode_status(grpc_mdelem md) { uint32_t status; void *user_data; - if (md == GRPC_MDELEM_GRPC_STATUS_0) return 0; - if (md == GRPC_MDELEM_GRPC_STATUS_1) return 1; - if (md == GRPC_MDELEM_GRPC_STATUS_2) return 2; + if (grpc_mdelem_eq(md, GRPC_MDELEM_GRPC_STATUS_0)) return 0; + if (grpc_mdelem_eq(md, GRPC_MDELEM_GRPC_STATUS_1)) return 1; + if (grpc_mdelem_eq(md, GRPC_MDELEM_GRPC_STATUS_2)) return 2; user_data = grpc_mdelem_get_user_data(md, destroy_status); if (user_data != NULL) { status = ((uint32_t)(intptr_t)user_data) - STATUS_OFFSET; } else { - if (!gpr_parse_bytes_to_uint32(grpc_mdstr_as_c_string(md->value), - GRPC_SLICE_LENGTH(md->value->slice), - &status)) { + if (!grpc_parse_slice_to_uint32(GRPC_MDVALUE(md), &status)) { status = GRPC_STATUS_UNKNOWN; /* could not parse status code */ } grpc_mdelem_set_user_data(md, destroy_status, @@ -914,89 +921,94 @@ static uint32_t decode_status(grpc_mdelem *md) { return status; } -static grpc_compression_algorithm decode_compression(grpc_mdelem *md) { +static grpc_compression_algorithm decode_compression(grpc_mdelem md) { grpc_compression_algorithm algorithm = - grpc_compression_algorithm_from_mdstr(md->value); + grpc_compression_algorithm_from_slice(GRPC_MDVALUE(md)); if (algorithm == GRPC_COMPRESS_ALGORITHMS_COUNT) { - const char *md_c_str = grpc_mdstr_as_c_string(md->value); + char *md_c_str = grpc_slice_to_c_string(GRPC_MDVALUE(md)); gpr_log(GPR_ERROR, "Invalid incoming compression algorithm: '%s'. Interpreting " "incoming data as uncompressed.", md_c_str); + gpr_free(md_c_str); return GRPC_COMPRESS_NONE; } return algorithm; } -static grpc_mdelem *recv_common_filter(grpc_call *call, grpc_mdelem *elem) { - if (elem->key == GRPC_MDSTR_GRPC_STATUS) { - GPR_TIMER_BEGIN("status", 0); - set_status_code(call, STATUS_FROM_WIRE, decode_status(elem)); - GPR_TIMER_END("status", 0); - return NULL; - } else if (elem->key == GRPC_MDSTR_GRPC_MESSAGE) { - GPR_TIMER_BEGIN("status-details", 0); - set_status_details(call, STATUS_FROM_WIRE, GRPC_MDSTR_REF(elem->value)); - GPR_TIMER_END("status-details", 0); - return NULL; - } - return elem; -} - -static grpc_mdelem *publish_app_metadata(grpc_call *call, grpc_mdelem *elem, - int is_trailing) { +static void publish_app_metadata(grpc_call *call, grpc_metadata_batch *b, + int is_trailing) { + if (b->list.count == 0) return; + GPR_TIMER_BEGIN("publish_app_metadata", 0); grpc_metadata_array *dest; grpc_metadata *mdusr; - GPR_TIMER_BEGIN("publish_app_metadata", 0); dest = call->buffered_metadata[is_trailing]; - if (dest->count == dest->capacity) { - dest->capacity = GPR_MAX(dest->capacity + 8, dest->capacity * 2); + if (dest->count + b->list.count > dest->capacity) { + dest->capacity = + GPR_MAX(dest->capacity + b->list.count, dest->capacity * 3 / 2); dest->metadata = gpr_realloc(dest->metadata, sizeof(grpc_metadata) * dest->capacity); } - mdusr = &dest->metadata[dest->count++]; - mdusr->key = grpc_mdstr_as_c_string(elem->key); - mdusr->value = grpc_mdstr_as_c_string(elem->value); - mdusr->value_length = GRPC_SLICE_LENGTH(elem->value->slice); + for (grpc_linked_mdelem *l = b->list.head; l != NULL; l = l->next) { + mdusr = &dest->metadata[dest->count++]; + /* we pass back borrowed slices that are valid whilst the call is valid */ + mdusr->key = GRPC_MDKEY(l->md); + mdusr->value = GRPC_MDVALUE(l->md); + } GPR_TIMER_END("publish_app_metadata", 0); - return elem; } -static grpc_mdelem *recv_initial_filter(void *callp, grpc_mdelem *elem) { - grpc_call *call = callp; - elem = recv_common_filter(call, elem); - if (elem == NULL) { - return NULL; - } else if (elem->key == GRPC_MDSTR_GRPC_ENCODING) { +static void recv_initial_filter(grpc_exec_ctx *exec_ctx, grpc_call *call, + grpc_metadata_batch *b) { + if (b->idx.named.grpc_encoding != NULL) { GPR_TIMER_BEGIN("incoming_compression_algorithm", 0); - set_incoming_compression_algorithm(call, decode_compression(elem)); + set_incoming_compression_algorithm( + call, decode_compression(b->idx.named.grpc_encoding->md)); GPR_TIMER_END("incoming_compression_algorithm", 0); - return NULL; - } else if (elem->key == GRPC_MDSTR_GRPC_ACCEPT_ENCODING) { + grpc_metadata_batch_remove(exec_ctx, b, b->idx.named.grpc_encoding); + } + if (b->idx.named.grpc_accept_encoding != NULL) { GPR_TIMER_BEGIN("encodings_accepted_by_peer", 0); - set_encodings_accepted_by_peer(call, elem); + set_encodings_accepted_by_peer(exec_ctx, call, + b->idx.named.grpc_accept_encoding->md); + grpc_metadata_batch_remove(exec_ctx, b, b->idx.named.grpc_accept_encoding); GPR_TIMER_END("encodings_accepted_by_peer", 0); - return NULL; - } else { - return publish_app_metadata(call, elem, 0); } + publish_app_metadata(call, b, false); } -static grpc_mdelem *recv_trailing_filter(void *callp, grpc_mdelem *elem) { - grpc_call *call = callp; - elem = recv_common_filter(call, elem); - if (elem == NULL) { - return NULL; - } else { - return publish_app_metadata(call, elem, 1); +static void recv_trailing_filter(grpc_exec_ctx *exec_ctx, void *args, + grpc_metadata_batch *b) { + grpc_call *call = args; + if (b->idx.named.grpc_status != NULL) { + uint32_t status_code = decode_status(b->idx.named.grpc_status->md); + grpc_error *error = + status_code == GRPC_STATUS_OK + ? GRPC_ERROR_NONE + : grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "Error received from peer"), + GRPC_ERROR_INT_GRPC_STATUS, + (intptr_t)status_code); + if (b->idx.named.grpc_message != NULL) { + error = grpc_error_set_str( + error, GRPC_ERROR_STR_GRPC_MESSAGE, + grpc_slice_ref_internal(GRPC_MDVALUE(b->idx.named.grpc_message->md))); + grpc_metadata_batch_remove(exec_ctx, b, b->idx.named.grpc_message); + } else if (error != GRPC_ERROR_NONE) { + error = grpc_error_set_str(error, GRPC_ERROR_STR_GRPC_MESSAGE, + grpc_empty_slice()); + } + set_status_from_error(exec_ctx, call, STATUS_FROM_WIRE, error); + grpc_metadata_batch_remove(exec_ctx, b, b->idx.named.grpc_status); } + publish_app_metadata(call, b, true); } grpc_call_stack *grpc_call_get_call_stack(grpc_call *call) { return CALL_STACK_FROM_CALL(call); } -/* +/******************************************************************************* * BATCH API IMPLEMENTATION */ @@ -1025,54 +1037,154 @@ static bool are_initial_metadata_flags_valid(uint32_t flags, bool is_client) { return !(flags & invalid_positions); } -static batch_control *allocate_batch_control(grpc_call *call) { - size_t i; - for (i = 0; i < MAX_CONCURRENT_BATCHES; i++) { - if ((call->used_batches & (1 << i)) == 0) { - call->used_batches = (uint8_t)(call->used_batches | (uint8_t)(1 << i)); - return &call->active_batches[i]; - } +static int batch_slot_for_op(grpc_op_type type) { + switch (type) { + case GRPC_OP_SEND_INITIAL_METADATA: + return 0; + case GRPC_OP_SEND_MESSAGE: + return 1; + case GRPC_OP_SEND_CLOSE_FROM_CLIENT: + case GRPC_OP_SEND_STATUS_FROM_SERVER: + return 2; + case GRPC_OP_RECV_INITIAL_METADATA: + return 3; + case GRPC_OP_RECV_MESSAGE: + return 4; + case GRPC_OP_RECV_CLOSE_ON_SERVER: + case GRPC_OP_RECV_STATUS_ON_CLIENT: + return 5; + } + GPR_UNREACHABLE_CODE(return 123456789); +} + +static batch_control *allocate_batch_control(grpc_call *call, + const grpc_op *ops, + size_t num_ops) { + int slot = batch_slot_for_op(ops[0].op); + batch_control **pslot = &call->active_batches[slot]; + if (*pslot == NULL) { + *pslot = gpr_arena_alloc(call->arena, sizeof(batch_control)); + } + batch_control *bctl = *pslot; + if (bctl->call != NULL) { + return NULL; } - return NULL; + memset(bctl, 0, sizeof(*bctl)); + bctl->call = call; + bctl->op.payload = &call->stream_op_payload; + return bctl; } static void finish_batch_completion(grpc_exec_ctx *exec_ctx, void *user_data, grpc_cq_completion *storage) { batch_control *bctl = user_data; grpc_call *call = bctl->call; - gpr_mu_lock(&call->mu); - call->used_batches = (uint8_t)( - call->used_batches & ~(uint8_t)(1 << (bctl - call->active_batches))); - gpr_mu_unlock(&call->mu); + bctl->call = NULL; GRPC_CALL_INTERNAL_UNREF(exec_ctx, call, "completion"); } +static grpc_error *consolidate_batch_errors(batch_control *bctl) { + size_t n = (size_t)gpr_atm_acq_load(&bctl->num_errors); + if (n == 0) { + return GRPC_ERROR_NONE; + } else if (n == 1) { + /* Skip creating a composite error in the case that only one error was + logged */ + grpc_error *e = bctl->errors[0]; + bctl->errors[0] = NULL; + return e; + } else { + grpc_error *error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( + "Call batch failed", bctl->errors, n); + for (size_t i = 0; i < n; i++) { + GRPC_ERROR_UNREF(bctl->errors[i]); + bctl->errors[i] = NULL; + } + return error; + } +} + static void post_batch_completion(grpc_exec_ctx *exec_ctx, batch_control *bctl) { + grpc_call *next_child_call; grpc_call *call = bctl->call; - grpc_error *error = bctl->error; - if (bctl->recv_final_op) { + grpc_error *error = consolidate_batch_errors(bctl); + + if (bctl->op.send_initial_metadata) { + grpc_metadata_batch_destroy( + exec_ctx, + &call->metadata_batch[0 /* is_receiving */][0 /* is_trailing */]); + } + if (bctl->op.send_message) { + call->sending_message = false; + } + if (bctl->op.send_trailing_metadata) { + grpc_metadata_batch_destroy( + exec_ctx, + &call->metadata_batch[0 /* is_receiving */][1 /* is_trailing */]); + } + if (bctl->op.recv_trailing_metadata) { + grpc_metadata_batch *md = + &call->metadata_batch[1 /* is_receiving */][1 /* is_trailing */]; + recv_trailing_filter(exec_ctx, call, md); + + /* propagate cancellation to any interested children */ + gpr_atm_rel_store(&call->received_final_op_atm, 1); + parent_call *pc = get_parent_call(call); + if (pc != NULL) { + grpc_call *child; + gpr_mu_lock(&pc->child_list_mu); + child = pc->first_child; + if (child != NULL) { + do { + next_child_call = child->child_call->sibling_next; + if (child->cancellation_is_inherited) { + GRPC_CALL_INTERNAL_REF(child, "propagate_cancel"); + cancel_with_error(exec_ctx, child, STATUS_FROM_API_OVERRIDE, + GRPC_ERROR_CANCELLED); + GRPC_CALL_INTERNAL_UNREF(exec_ctx, child, "propagate_cancel"); + } + child = next_child_call; + } while (child != pc->first_child); + } + gpr_mu_unlock(&pc->child_list_mu); + } + + if (call->is_client) { + get_final_status(call, set_status_value_directly, + call->final_op.client.status, + call->final_op.client.status_details); + } else { + get_final_status(call, set_cancelled_value, + call->final_op.server.cancelled, NULL); + } + GRPC_ERROR_UNREF(error); error = GRPC_ERROR_NONE; } - if (bctl->is_notify_tag_closure) { + + if (bctl->completion_data.notify_tag.is_closure) { /* unrefs bctl->error */ - grpc_closure_run(exec_ctx, bctl->notify_tag, error); - gpr_mu_lock(&call->mu); - bctl->call->used_batches = - (uint8_t)(bctl->call->used_batches & - ~(uint8_t)(1 << (bctl - bctl->call->active_batches))); - gpr_mu_unlock(&call->mu); + bctl->call = NULL; + GRPC_CLOSURE_RUN(exec_ctx, bctl->completion_data.notify_tag.tag, error); GRPC_CALL_INTERNAL_UNREF(exec_ctx, call, "completion"); } else { /* unrefs bctl->error */ - grpc_cq_end_op(exec_ctx, bctl->call->cq, bctl->notify_tag, error, - finish_batch_completion, bctl, &bctl->cq_completion); + grpc_cq_end_op( + exec_ctx, bctl->call->cq, bctl->completion_data.notify_tag.tag, error, + finish_batch_completion, bctl, &bctl->completion_data.cq_completion); + } +} + +static void finish_batch_step(grpc_exec_ctx *exec_ctx, batch_control *bctl) { + if (gpr_unref(&bctl->steps_to_complete)) { + post_batch_completion(exec_ctx, bctl); } } static void continue_receiving_slices(grpc_exec_ctx *exec_ctx, batch_control *bctl) { + grpc_error *error; grpc_call *call = bctl->call; for (;;) { size_t remaining = call->receiving_stream->length - @@ -1081,16 +1193,25 @@ static void continue_receiving_slices(grpc_exec_ctx *exec_ctx, call->receiving_message = 0; grpc_byte_stream_destroy(exec_ctx, call->receiving_stream); call->receiving_stream = NULL; - if (gpr_unref(&bctl->steps_to_complete)) { - post_batch_completion(exec_ctx, bctl); - } + finish_batch_step(exec_ctx, bctl); return; } - if (grpc_byte_stream_next(exec_ctx, call->receiving_stream, - &call->receiving_slice, remaining, + if (grpc_byte_stream_next(exec_ctx, call->receiving_stream, remaining, &call->receiving_slice_ready)) { - grpc_slice_buffer_add(&(*call->receiving_buffer)->data.raw.slice_buffer, - call->receiving_slice); + error = grpc_byte_stream_pull(exec_ctx, call->receiving_stream, + &call->receiving_slice); + if (error == GRPC_ERROR_NONE) { + grpc_slice_buffer_add(&(*call->receiving_buffer)->data.raw.slice_buffer, + call->receiving_slice); + } else { + grpc_byte_stream_destroy(exec_ctx, call->receiving_stream); + call->receiving_stream = NULL; + grpc_byte_buffer_destroy(*call->receiving_buffer); + *call->receiving_buffer = NULL; + call->receiving_message = 0; + finish_batch_step(exec_ctx, bctl); + return; + } } else { return; } @@ -1101,21 +1222,35 @@ static void receiving_slice_ready(grpc_exec_ctx *exec_ctx, void *bctlp, grpc_error *error) { batch_control *bctl = bctlp; grpc_call *call = bctl->call; + grpc_byte_stream *bs = call->receiving_stream; + bool release_error = false; if (error == GRPC_ERROR_NONE) { - grpc_slice_buffer_add(&(*call->receiving_buffer)->data.raw.slice_buffer, - call->receiving_slice); - continue_receiving_slices(exec_ctx, bctl); - } else { - if (grpc_trace_operation_failures) { + grpc_slice slice; + error = grpc_byte_stream_pull(exec_ctx, bs, &slice); + if (error == GRPC_ERROR_NONE) { + grpc_slice_buffer_add(&(*call->receiving_buffer)->data.raw.slice_buffer, + slice); + continue_receiving_slices(exec_ctx, bctl); + } else { + /* Error returned by grpc_byte_stream_pull needs to be released manually + */ + release_error = true; + } + } + + if (error != GRPC_ERROR_NONE) { + if (GRPC_TRACER_ON(grpc_trace_operation_failures)) { GRPC_LOG_IF_ERROR("receiving_slice_ready", GRPC_ERROR_REF(error)); } grpc_byte_stream_destroy(exec_ctx, call->receiving_stream); call->receiving_stream = NULL; grpc_byte_buffer_destroy(*call->receiving_buffer); *call->receiving_buffer = NULL; - if (gpr_unref(&bctl->steps_to_complete)) { - post_batch_completion(exec_ctx, bctl); + call->receiving_message = 0; + finish_batch_step(exec_ctx, bctl); + if (release_error) { + GRPC_ERROR_UNREF(error); } } } @@ -1126,9 +1261,7 @@ static void process_data_after_md(grpc_exec_ctx *exec_ctx, if (call->receiving_stream == NULL) { *call->receiving_buffer = NULL; call->receiving_message = 0; - if (gpr_unref(&bctl->steps_to_complete)) { - post_batch_completion(exec_ctx, bctl); - } + finish_batch_step(exec_ctx, bctl); } else { call->test_only_last_message_flags = call->receiving_stream->flags; if ((call->receiving_stream->flags & GRPC_WRITE_INTERNAL_COMPRESS) && @@ -1138,8 +1271,8 @@ static void process_data_after_md(grpc_exec_ctx *exec_ctx, } else { *call->receiving_buffer = grpc_raw_byte_buffer_create(NULL, 0); } - grpc_closure_init(&call->receiving_slice_ready, receiving_slice_ready, - bctl); + GRPC_CLOSURE_INIT(&call->receiving_slice_ready, receiving_slice_ready, bctl, + grpc_schedule_on_exec_ctx); continue_receiving_slices(exec_ctx, bctl); } } @@ -1149,19 +1282,19 @@ static void receiving_stream_ready(grpc_exec_ctx *exec_ctx, void *bctlp, batch_control *bctl = bctlp; grpc_call *call = bctl->call; if (error != GRPC_ERROR_NONE) { - grpc_status_code status; - const char *msg; - grpc_error_get_status(error, &status, &msg); - close_with_status(exec_ctx, call, status, msg); + if (call->receiving_stream != NULL) { + grpc_byte_stream_destroy(exec_ctx, call->receiving_stream); + call->receiving_stream = NULL; + } + add_batch_error(exec_ctx, bctl, GRPC_ERROR_REF(error), true); + cancel_with_error(exec_ctx, call, STATUS_FROM_SURFACE, + GRPC_ERROR_REF(error)); } - gpr_mu_lock(&bctl->call->mu); - if (bctl->call->has_initial_md_been_received || error != GRPC_ERROR_NONE || + if (call->has_initial_md_been_received || error != GRPC_ERROR_NONE || call->receiving_stream == NULL) { - gpr_mu_unlock(&bctl->call->mu); process_data_after_md(exec_ctx, bctlp); } else { call->saved_receiving_stream_ready_bctlp = bctlp; - gpr_mu_unlock(&bctl->call->mu); } } @@ -1180,7 +1313,8 @@ static void validate_filtered_metadata(grpc_exec_ctx *exec_ctx, gpr_asprintf(&error_msg, "Invalid compression algorithm value '%d'.", algo); gpr_log(GPR_ERROR, "%s", error_msg); - close_with_status(exec_ctx, call, GRPC_STATUS_UNIMPLEMENTED, error_msg); + cancel_with_status(exec_ctx, call, STATUS_FROM_SURFACE, + GRPC_STATUS_UNIMPLEMENTED, error_msg); } else if (grpc_compression_options_is_algorithm_enabled( &compression_options, algo) == 0) { /* check if algorithm is supported by current channel config */ @@ -1189,7 +1323,8 @@ static void validate_filtered_metadata(grpc_exec_ctx *exec_ctx, gpr_asprintf(&error_msg, "Compression algorithm '%s' is disabled.", algo_name); gpr_log(GPR_ERROR, "%s", error_msg); - close_with_status(exec_ctx, call, GRPC_STATUS_UNIMPLEMENTED, error_msg); + cancel_with_status(exec_ctx, call, STATUS_FROM_SURFACE, + GRPC_STATUS_UNIMPLEMENTED, error_msg); } else { call->incoming_compression_algorithm = algo; } @@ -1201,8 +1336,7 @@ static void validate_filtered_metadata(grpc_exec_ctx *exec_ctx, GPR_ASSERT(call->encodings_accepted_by_peer != 0); if (!GPR_BITGET(call->encodings_accepted_by_peer, call->incoming_compression_algorithm)) { - extern int grpc_compression_trace; - if (grpc_compression_trace) { + if (GRPC_TRACER_ON(grpc_compression_trace)) { char *algo_name = NULL; grpc_compression_algorithm_name(call->incoming_compression_algorithm, &algo_name); @@ -1215,12 +1349,15 @@ static void validate_filtered_metadata(grpc_exec_ctx *exec_ctx, } } -static void add_batch_error(batch_control *bctl, grpc_error *error) { +static void add_batch_error(grpc_exec_ctx *exec_ctx, batch_control *bctl, + grpc_error *error, bool has_cancelled) { if (error == GRPC_ERROR_NONE) return; - if (bctl->error == GRPC_ERROR_NONE) { - bctl->error = GRPC_ERROR_CREATE("Call batch operation failed"); + int idx = (int)gpr_atm_full_fetch_add(&bctl->num_errors, 1); + if (idx == 0 && !has_cancelled) { + cancel_with_error(exec_ctx, bctl->call, STATUS_FROM_CORE, + GRPC_ERROR_REF(error)); } - bctl->error = grpc_error_add_child(bctl->error, error); + bctl->errors[idx] = error; } static void receiving_initial_metadata_ready(grpc_exec_ctx *exec_ctx, @@ -1228,14 +1365,13 @@ static void receiving_initial_metadata_ready(grpc_exec_ctx *exec_ctx, batch_control *bctl = bctlp; grpc_call *call = bctl->call; - gpr_mu_lock(&call->mu); - - add_batch_error(bctl, GRPC_ERROR_REF(error)); + add_batch_error(exec_ctx, bctl, GRPC_ERROR_REF(error), false); if (error == GRPC_ERROR_NONE) { grpc_metadata_batch *md = &call->metadata_batch[1 /* is_receiving */][0 /* is_trailing */]; - grpc_metadata_batch_filter(md, recv_initial_filter, call); + recv_initial_filter(exec_ctx, call, md); + /* TODO(ctiller): this could be moved into recv_initial_filter now */ GPR_TIMER_BEGIN("validate_filtered_metadata", 0); validate_filtered_metadata(exec_ctx, bctl); GPR_TIMER_END("validate_filtered_metadata", 0); @@ -1250,91 +1386,27 @@ static void receiving_initial_metadata_ready(grpc_exec_ctx *exec_ctx, call->has_initial_md_been_received = true; if (call->saved_receiving_stream_ready_bctlp != NULL) { - grpc_closure *saved_rsr_closure = grpc_closure_create( - receiving_stream_ready, call->saved_receiving_stream_ready_bctlp); + grpc_closure *saved_rsr_closure = GRPC_CLOSURE_CREATE( + receiving_stream_ready, call->saved_receiving_stream_ready_bctlp, + grpc_schedule_on_exec_ctx); call->saved_receiving_stream_ready_bctlp = NULL; - grpc_exec_ctx_sched(exec_ctx, saved_rsr_closure, error, NULL); + GRPC_CLOSURE_RUN(exec_ctx, saved_rsr_closure, GRPC_ERROR_REF(error)); } - gpr_mu_unlock(&call->mu); - - if (gpr_unref(&bctl->steps_to_complete)) { - post_batch_completion(exec_ctx, bctl); - } + finish_batch_step(exec_ctx, bctl); } static void finish_batch(grpc_exec_ctx *exec_ctx, void *bctlp, grpc_error *error) { batch_control *bctl = bctlp; - grpc_call *call = bctl->call; - grpc_call *child_call; - grpc_call *next_child_call; - - GRPC_ERROR_REF(error); - - gpr_mu_lock(&call->mu); - - // If the error has an associated status code, set the call's status. - intptr_t status; - if (error != GRPC_ERROR_NONE && - grpc_error_get_int(error, GRPC_ERROR_INT_GRPC_STATUS, &status)) { - set_status_from_error(call, STATUS_FROM_CORE, error); - } - - if (bctl->send_initial_metadata) { - if (error != GRPC_ERROR_NONE) { - set_status_from_error(call, STATUS_FROM_CORE, error); - } - grpc_metadata_batch_destroy( - &call->metadata_batch[0 /* is_receiving */][0 /* is_trailing */]); - } - if (bctl->send_message) { - call->sending_message = 0; - } - if (bctl->send_final_op) { - grpc_metadata_batch_destroy( - &call->metadata_batch[0 /* is_receiving */][1 /* is_trailing */]); - } - if (bctl->recv_final_op) { - grpc_metadata_batch *md = - &call->metadata_batch[1 /* is_receiving */][1 /* is_trailing */]; - grpc_metadata_batch_filter(md, recv_trailing_filter, call); - - call->received_final_op = true; - /* propagate cancellation to any interested children */ - child_call = call->first_child; - if (child_call != NULL) { - do { - next_child_call = child_call->sibling_next; - if (child_call->cancellation_is_inherited) { - GRPC_CALL_INTERNAL_REF(child_call, "propagate_cancel"); - grpc_call_cancel(child_call, NULL); - GRPC_CALL_INTERNAL_UNREF(exec_ctx, child_call, "propagate_cancel"); - } - child_call = next_child_call; - } while (child_call != call->first_child); - } - - if (call->is_client) { - get_final_status(call, set_status_value_directly, - call->final_op.client.status); - get_final_details(call, call->final_op.client.status_details, - call->final_op.client.status_details_capacity); - } else { - get_final_status(call, set_cancelled_value, - call->final_op.server.cancelled); - } - GRPC_ERROR_UNREF(error); - error = GRPC_ERROR_NONE; - } - add_batch_error(bctl, GRPC_ERROR_REF(error)); - gpr_mu_unlock(&call->mu); - if (gpr_unref(&bctl->steps_to_complete)) { - post_batch_completion(exec_ctx, bctl); - } + add_batch_error(exec_ctx, bctl, GRPC_ERROR_REF(error), false); + finish_batch_step(exec_ctx, bctl); +} - GRPC_ERROR_UNREF(error); +static void free_no_op_completion(grpc_exec_ctx *exec_ctx, void *p, + grpc_cq_completion *completion) { + gpr_free(completion); } static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx, @@ -1351,33 +1423,33 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx, grpc_metadata compression_md; GPR_TIMER_BEGIN("grpc_call_start_batch", 0); - GRPC_CALL_LOG_BATCH(GPR_INFO, call, ops, nops, notify_tag); - /* TODO(ctiller): this feels like it could be made lock-free */ - gpr_mu_lock(&call->mu); - bctl = allocate_batch_control(call); - memset(bctl, 0, sizeof(*bctl)); - bctl->call = call; - bctl->notify_tag = notify_tag; - bctl->is_notify_tag_closure = (uint8_t)(is_notify_tag_closure != 0); - - grpc_transport_stream_op *stream_op = &bctl->op; - memset(stream_op, 0, sizeof(*stream_op)); - stream_op->covered_by_poller = true; - if (nops == 0) { - GRPC_CALL_INTERNAL_REF(call, "completion"); - bctl->error = GRPC_ERROR_NONE; if (!is_notify_tag_closure) { - grpc_cq_begin_op(call->cq, notify_tag); + GPR_ASSERT(grpc_cq_begin_op(call->cq, notify_tag)); + grpc_cq_end_op(exec_ctx, call->cq, notify_tag, GRPC_ERROR_NONE, + free_no_op_completion, NULL, + gpr_malloc(sizeof(grpc_cq_completion))); + } else { + GRPC_CLOSURE_SCHED(exec_ctx, notify_tag, GRPC_ERROR_NONE); } - gpr_mu_unlock(&call->mu); - post_batch_completion(exec_ctx, bctl); error = GRPC_CALL_OK; goto done; } + bctl = allocate_batch_control(call, ops, nops); + if (bctl == NULL) { + return GRPC_CALL_ERROR_TOO_MANY_OPERATIONS; + } + bctl->completion_data.notify_tag.tag = notify_tag; + bctl->completion_data.notify_tag.is_closure = + (uint8_t)(is_notify_tag_closure != 0); + + grpc_transport_stream_op_batch *stream_op = &bctl->op; + grpc_transport_stream_op_batch_payload *stream_op_payload = + &call->stream_op_payload; + /* rewrite batch ops into a transport op */ for (i = 0; i < nops; i++) { op = &ops[i]; @@ -1417,13 +1489,10 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx, const grpc_compression_algorithm calgo = compression_algorithm_for_level_locked( call, effective_compression_level); - char *calgo_name = NULL; - grpc_compression_algorithm_name(calgo, &calgo_name); // the following will be picked up by the compress filter and used as // the call's compression algorithm. - compression_md.key = GRPC_COMPRESSION_REQUEST_ALGORITHM_MD_KEY; - compression_md.value = calgo_name; - compression_md.value_length = strlen(calgo_name); + compression_md.key = GRPC_MDSTR_GRPC_INTERNAL_ENCODING_REQUEST; + compression_md.value = grpc_compression_algorithm_slice(calgo); additional_metadata_count++; } @@ -1432,27 +1501,30 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx, error = GRPC_CALL_ERROR_INVALID_METADATA; goto done_with_error; } - bctl->send_initial_metadata = 1; - call->sent_initial_metadata = 1; + stream_op->send_initial_metadata = true; + call->sent_initial_metadata = true; if (!prepare_application_metadata( - call, (int)op->data.send_initial_metadata.count, + exec_ctx, call, (int)op->data.send_initial_metadata.count, op->data.send_initial_metadata.metadata, 0, call->is_client, &compression_md, (int)additional_metadata_count)) { error = GRPC_CALL_ERROR_INVALID_METADATA; goto done_with_error; } /* TODO(ctiller): just make these the same variable? */ - call->metadata_batch[0][0].deadline = call->send_deadline; - stream_op->send_initial_metadata = + if (call->is_client) { + call->metadata_batch[0][0].deadline = call->send_deadline; + } + stream_op_payload->send_initial_metadata.send_initial_metadata = &call->metadata_batch[0 /* is_receiving */][0 /* is_trailing */]; - stream_op->send_initial_metadata_flags = op->flags; + stream_op_payload->send_initial_metadata.send_initial_metadata_flags = + op->flags; break; case GRPC_OP_SEND_MESSAGE: if (!are_write_flags_valid(op->flags)) { error = GRPC_CALL_ERROR_INVALID_FLAGS; goto done_with_error; } - if (op->data.send_message == NULL) { + if (op->data.send_message.send_message == NULL) { error = GRPC_CALL_ERROR_INVALID_MESSAGE; goto done_with_error; } @@ -1460,18 +1532,21 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx, error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS; goto done_with_error; } - bctl->send_message = 1; - call->sending_message = 1; + stream_op->send_message = true; + call->sending_message = true; grpc_slice_buffer_stream_init( &call->sending_stream, - &op->data.send_message->data.raw.slice_buffer, op->flags); + &op->data.send_message.send_message->data.raw.slice_buffer, + op->flags); /* If the outgoing buffer is already compressed, mark it as so in the flags. These will be picked up by the compression filter and further (wasteful) attempts at compression skipped. */ - if (op->data.send_message->data.raw.compression > GRPC_COMPRESS_NONE) { + if (op->data.send_message.send_message->data.raw.compression > + GRPC_COMPRESS_NONE) { call->sending_stream.base.flags |= GRPC_WRITE_INTERNAL_COMPRESS; } - stream_op->send_message = &call->sending_stream.base; + stream_op_payload->send_message.send_message = + &call->sending_stream.base; break; case GRPC_OP_SEND_CLOSE_FROM_CLIENT: /* Flag validation: currently allow no flags */ @@ -1487,9 +1562,9 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx, error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS; goto done_with_error; } - bctl->send_final_op = 1; - call->sent_final_op = 1; - stream_op->send_trailing_metadata = + stream_op->send_trailing_metadata = true; + call->sent_final_op = true; + stream_op_payload->send_trailing_metadata.send_trailing_metadata = &call->metadata_batch[0 /* is_receiving */][1 /* is_trailing */]; break; case GRPC_OP_SEND_STATUS_FROM_SERVER: @@ -1511,34 +1586,47 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx, error = GRPC_CALL_ERROR_INVALID_METADATA; goto done_with_error; } - bctl->send_final_op = 1; - call->sent_final_op = 1; + stream_op->send_trailing_metadata = true; + call->sent_final_op = true; + GPR_ASSERT(call->send_extra_metadata_count == 0); call->send_extra_metadata_count = 1; call->send_extra_metadata[0].md = grpc_channel_get_reffed_status_elem( - call->channel, op->data.send_status_from_server.status); - if (op->data.send_status_from_server.status_details != NULL) { - call->send_extra_metadata[1].md = grpc_mdelem_from_metadata_strings( - GRPC_MDSTR_GRPC_MESSAGE, - grpc_mdstr_from_string( - op->data.send_status_from_server.status_details)); - call->send_extra_metadata_count++; - set_status_details( - call, STATUS_FROM_API_OVERRIDE, - GRPC_MDSTR_REF(call->send_extra_metadata[1].md->value)); - } - if (op->data.send_status_from_server.status != GRPC_STATUS_OK) { - set_status_code(call, STATUS_FROM_API_OVERRIDE, - (uint32_t)op->data.send_status_from_server.status); + exec_ctx, call->channel, op->data.send_status_from_server.status); + { + grpc_error *override_error = GRPC_ERROR_NONE; + if (op->data.send_status_from_server.status != GRPC_STATUS_OK) { + override_error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "Error from server send status"); + } + if (op->data.send_status_from_server.status_details != NULL) { + call->send_extra_metadata[1].md = grpc_mdelem_from_slices( + exec_ctx, GRPC_MDSTR_GRPC_MESSAGE, + grpc_slice_ref_internal( + *op->data.send_status_from_server.status_details)); + call->send_extra_metadata_count++; + char *msg = grpc_slice_to_c_string( + GRPC_MDVALUE(call->send_extra_metadata[1].md)); + override_error = + grpc_error_set_str(override_error, GRPC_ERROR_STR_GRPC_MESSAGE, + grpc_slice_from_copied_string(msg)); + gpr_free(msg); + } + set_status_from_error(exec_ctx, call, STATUS_FROM_API_OVERRIDE, + override_error); } if (!prepare_application_metadata( - call, + exec_ctx, call, (int)op->data.send_status_from_server.trailing_metadata_count, op->data.send_status_from_server.trailing_metadata, 1, 1, NULL, 0)) { + for (int n = 0; n < call->send_extra_metadata_count; n++) { + GRPC_MDELEM_UNREF(exec_ctx, call->send_extra_metadata[n].md); + } + call->send_extra_metadata_count = 0; error = GRPC_CALL_ERROR_INVALID_METADATA; goto done_with_error; } - stream_op->send_trailing_metadata = + stream_op_payload->send_trailing_metadata.send_trailing_metadata = &call->metadata_batch[0 /* is_receiving */][1 /* is_trailing */]; break; case GRPC_OP_RECV_INITIAL_METADATA: @@ -1551,18 +1639,16 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx, error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS; goto done_with_error; } - /* IF this is a server, then GRPC_OP_RECV_INITIAL_METADATA *must* come - from server.c. In that case, it's coming from accept_stream, and in - that case we're not necessarily covered by a poller. */ - stream_op->covered_by_poller = call->is_client; - call->received_initial_metadata = 1; - call->buffered_metadata[0] = op->data.recv_initial_metadata; - grpc_closure_init(&call->receiving_initial_metadata_ready, - receiving_initial_metadata_ready, bctl); - bctl->recv_initial_metadata = 1; - stream_op->recv_initial_metadata = + call->received_initial_metadata = true; + call->buffered_metadata[0] = + op->data.recv_initial_metadata.recv_initial_metadata; + GRPC_CLOSURE_INIT(&call->receiving_initial_metadata_ready, + receiving_initial_metadata_ready, bctl, + grpc_schedule_on_exec_ctx); + stream_op->recv_initial_metadata = true; + stream_op_payload->recv_initial_metadata.recv_initial_metadata = &call->metadata_batch[1 /* is_receiving */][0 /* is_trailing */]; - stream_op->recv_initial_metadata_ready = + stream_op_payload->recv_initial_metadata.recv_initial_metadata_ready = &call->receiving_initial_metadata_ready; num_completion_callbacks_needed++; break; @@ -1576,13 +1662,14 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx, error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS; goto done_with_error; } - call->receiving_message = 1; - bctl->recv_message = 1; - call->receiving_buffer = op->data.recv_message; - stream_op->recv_message = &call->receiving_stream; - grpc_closure_init(&call->receiving_stream_ready, receiving_stream_ready, - bctl); - stream_op->recv_message_ready = &call->receiving_stream_ready; + call->receiving_message = true; + stream_op->recv_message = true; + call->receiving_buffer = op->data.recv_message.recv_message; + stream_op_payload->recv_message.recv_message = &call->receiving_stream; + GRPC_CLOSURE_INIT(&call->receiving_stream_ready, receiving_stream_ready, + bctl, grpc_schedule_on_exec_ctx); + stream_op_payload->recv_message.recv_message_ready = + &call->receiving_stream_ready; num_completion_callbacks_needed++; break; case GRPC_OP_RECV_STATUS_ON_CLIENT: @@ -1599,18 +1686,17 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx, error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS; goto done_with_error; } - call->requested_final_op = 1; + call->requested_final_op = true; call->buffered_metadata[1] = op->data.recv_status_on_client.trailing_metadata; call->final_op.client.status = op->data.recv_status_on_client.status; call->final_op.client.status_details = op->data.recv_status_on_client.status_details; - call->final_op.client.status_details_capacity = - op->data.recv_status_on_client.status_details_capacity; - bctl->recv_final_op = 1; - stream_op->recv_trailing_metadata = + stream_op->recv_trailing_metadata = true; + stream_op->collect_stats = true; + stream_op_payload->recv_trailing_metadata.recv_trailing_metadata = &call->metadata_batch[1 /* is_receiving */][1 /* is_trailing */]; - stream_op->collect_stats = + stream_op_payload->collect_stats.collect_stats = &call->final_info.stats.transport_stream_stats; break; case GRPC_OP_RECV_CLOSE_ON_SERVER: @@ -1627,13 +1713,14 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx, error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS; goto done_with_error; } - call->requested_final_op = 1; + call->requested_final_op = true; call->final_op.server.cancelled = op->data.recv_close_on_server.cancelled; - bctl->recv_final_op = 1; - stream_op->recv_trailing_metadata = + stream_op->recv_trailing_metadata = true; + stream_op->collect_stats = true; + stream_op_payload->recv_trailing_metadata.recv_trailing_metadata = &call->metadata_batch[1 /* is_receiving */][1 /* is_trailing */]; - stream_op->collect_stats = + stream_op_payload->collect_stats.collect_stats = &call->final_info.stats.transport_stream_stats; break; } @@ -1641,14 +1728,14 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx, GRPC_CALL_INTERNAL_REF(call, "completion"); if (!is_notify_tag_closure) { - grpc_cq_begin_op(call->cq, notify_tag); + GPR_ASSERT(grpc_cq_begin_op(call->cq, notify_tag)); } gpr_ref_init(&bctl->steps_to_complete, num_completion_callbacks_needed); - stream_op->context = call->context; - grpc_closure_init(&bctl->finish_batch, finish_batch, bctl); + GRPC_CLOSURE_INIT(&bctl->finish_batch, finish_batch, bctl, + grpc_schedule_on_exec_ctx); stream_op->on_complete = &bctl->finish_batch; - gpr_mu_unlock(&call->mu); + gpr_atm_rel_store(&call->any_ops_sent_atm, 1); execute_op(exec_ctx, call, stream_op); @@ -1658,28 +1745,27 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx, done_with_error: /* reverse any mutations that occured */ - if (bctl->send_initial_metadata) { - call->sent_initial_metadata = 0; - grpc_metadata_batch_clear(&call->metadata_batch[0][0]); + if (stream_op->send_initial_metadata) { + call->sent_initial_metadata = false; + grpc_metadata_batch_clear(exec_ctx, &call->metadata_batch[0][0]); } - if (bctl->send_message) { - call->sending_message = 0; + if (stream_op->send_message) { + call->sending_message = false; grpc_byte_stream_destroy(exec_ctx, &call->sending_stream.base); } - if (bctl->send_final_op) { - call->sent_final_op = 0; - grpc_metadata_batch_clear(&call->metadata_batch[0][1]); + if (stream_op->send_trailing_metadata) { + call->sent_final_op = false; + grpc_metadata_batch_clear(exec_ctx, &call->metadata_batch[0][1]); } - if (bctl->recv_initial_metadata) { - call->received_initial_metadata = 0; + if (stream_op->recv_initial_metadata) { + call->received_initial_metadata = false; } - if (bctl->recv_message) { - call->receiving_message = 0; + if (stream_op->recv_message) { + call->receiving_message = false; } - if (bctl->recv_final_op) { - call->requested_final_op = 0; + if (stream_op->recv_trailing_metadata) { + call->requested_final_op = false; } - gpr_mu_unlock(&call->mu); goto done; } @@ -1728,10 +1814,8 @@ uint8_t grpc_call_is_client(grpc_call *call) { return call->is_client; } grpc_compression_algorithm grpc_call_compression_for_level( grpc_call *call, grpc_compression_level level) { - gpr_mu_lock(&call->mu); grpc_compression_algorithm algo = compression_algorithm_for_level_locked(call, level); - gpr_mu_unlock(&call->mu); return algo; } @@ -1765,6 +1849,8 @@ const char *grpc_call_error_to_string(grpc_call_error error) { return "GRPC_CALL_ERROR_PAYLOAD_TYPE_MISMATCH"; case GRPC_CALL_ERROR_TOO_MANY_OPERATIONS: return "GRPC_CALL_ERROR_TOO_MANY_OPERATIONS"; + case GRPC_CALL_ERROR_COMPLETION_QUEUE_SHUTDOWN: + return "GRPC_CALL_ERROR_COMPLETION_QUEUE_SHUTDOWN"; case GRPC_CALL_OK: return "GRPC_CALL_OK"; } diff --git a/Sources/CgRPC/src/core/lib/surface/call.h b/Sources/CgRPC/src/core/lib/surface/call.h index 18af41b7f..185bfccb7 100644 --- a/Sources/CgRPC/src/core/lib/surface/call.h +++ b/Sources/CgRPC/src/core/lib/surface/call.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -61,7 +46,7 @@ typedef struct grpc_call_create_args { const void *server_transport_data; - grpc_mdelem **add_initial_metadata; + grpc_mdelem *add_initial_metadata; size_t add_initial_metadata_count; gpr_timespec send_deadline; @@ -70,13 +55,14 @@ typedef struct grpc_call_create_args { /* Create a new call based on \a args. Regardless of success or failure, always returns a valid new call into *call */ -grpc_error *grpc_call_create(const grpc_call_create_args *args, +grpc_error *grpc_call_create(grpc_exec_ctx *exec_ctx, + const grpc_call_create_args *args, grpc_call **call); void grpc_call_set_completion_queue(grpc_exec_ctx *exec_ctx, grpc_call *call, grpc_completion_queue *cq); -#ifdef GRPC_STREAM_REFCOUNT_DEBUG +#ifndef NDEBUG void grpc_call_internal_ref(grpc_call *call, const char *reason); void grpc_call_internal_unref(grpc_exec_ctx *exec_ctx, grpc_call *call, const char *reason); @@ -109,13 +95,15 @@ void grpc_call_log_batch(char *file, int line, gpr_log_severity severity, /* Set a context pointer. No thread safety guarantees are made wrt this value. */ +/* TODO(#9731): add exec_ctx to destroy */ void grpc_call_context_set(grpc_call *call, grpc_context_index elem, void *value, void (*destroy)(void *value)); /* Get a context pointer. */ void *grpc_call_context_get(grpc_call *call, grpc_context_index elem); #define GRPC_CALL_LOG_BATCH(sev, call, ops, nops, tag) \ - if (grpc_api_trace) grpc_call_log_batch(sev, call, ops, nops, tag) + if (GRPC_TRACER_ON(grpc_api_trace)) \ + grpc_call_log_batch(sev, call, ops, nops, tag) uint8_t grpc_call_is_client(grpc_call *call); @@ -124,6 +112,9 @@ uint8_t grpc_call_is_client(grpc_call *call); grpc_compression_algorithm grpc_call_compression_for_level( grpc_call *call, grpc_compression_level level); +extern grpc_tracer_flag grpc_call_error_trace; +extern grpc_tracer_flag grpc_compression_trace; + #ifdef __cplusplus } #endif diff --git a/Sources/CgRPC/src/core/lib/surface/call_details.c b/Sources/CgRPC/src/core/lib/surface/call_details.c index fe73da3f5..ea9208c7e 100644 --- a/Sources/CgRPC/src/core/lib/surface/call_details.c +++ b/Sources/CgRPC/src/core/lib/surface/call_details.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -36,15 +21,21 @@ #include +#include "src/core/lib/iomgr/exec_ctx.h" +#include "src/core/lib/slice/slice_internal.h" #include "src/core/lib/surface/api_trace.h" void grpc_call_details_init(grpc_call_details* cd) { GRPC_API_TRACE("grpc_call_details_init(cd=%p)", 1, (cd)); memset(cd, 0, sizeof(*cd)); + cd->method = grpc_empty_slice(); + cd->host = grpc_empty_slice(); } void grpc_call_details_destroy(grpc_call_details* cd) { GRPC_API_TRACE("grpc_call_details_destroy(cd=%p)", 1, (cd)); - gpr_free(cd->method); - gpr_free(cd->host); + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + grpc_slice_unref_internal(&exec_ctx, cd->method); + grpc_slice_unref_internal(&exec_ctx, cd->host); + grpc_exec_ctx_finish(&exec_ctx); } diff --git a/Sources/CgRPC/src/core/lib/surface/call_log_batch.c b/Sources/CgRPC/src/core/lib/surface/call_log_batch.c index 31c074f15..4443aba58 100644 --- a/Sources/CgRPC/src/core/lib/surface/call_log_batch.c +++ b/Sources/CgRPC/src/core/lib/surface/call_log_batch.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -35,17 +20,22 @@ #include #include +#include "src/core/lib/slice/slice_string_helpers.h" #include "src/core/lib/support/string.h" static void add_metadata(gpr_strvec *b, const grpc_metadata *md, size_t count) { size_t i; + if (md == NULL) { + gpr_strvec_add(b, gpr_strdup("(nil)")); + return; + } for (i = 0; i < count; i++) { gpr_strvec_add(b, gpr_strdup("\nkey=")); - gpr_strvec_add(b, gpr_strdup(md[i].key)); + gpr_strvec_add(b, grpc_slice_to_c_string(md[i].key)); gpr_strvec_add(b, gpr_strdup(" value=")); - gpr_strvec_add(b, gpr_dump(md[i].value, md[i].value_length, - GPR_DUMP_HEX | GPR_DUMP_ASCII)); + gpr_strvec_add(b, + grpc_dump_slice(md[i].value, GPR_DUMP_HEX | GPR_DUMP_ASCII)); } } @@ -63,27 +53,35 @@ char *grpc_op_string(const grpc_op *op) { op->data.send_initial_metadata.count); break; case GRPC_OP_SEND_MESSAGE: - gpr_asprintf(&tmp, "SEND_MESSAGE ptr=%p", op->data.send_message); + gpr_asprintf(&tmp, "SEND_MESSAGE ptr=%p", + op->data.send_message.send_message); gpr_strvec_add(&b, tmp); break; case GRPC_OP_SEND_CLOSE_FROM_CLIENT: gpr_strvec_add(&b, gpr_strdup("SEND_CLOSE_FROM_CLIENT")); break; case GRPC_OP_SEND_STATUS_FROM_SERVER: - gpr_asprintf(&tmp, "SEND_STATUS_FROM_SERVER status=%d details=%s", - op->data.send_status_from_server.status, - op->data.send_status_from_server.status_details); + gpr_asprintf(&tmp, "SEND_STATUS_FROM_SERVER status=%d details=", + op->data.send_status_from_server.status); gpr_strvec_add(&b, tmp); + if (op->data.send_status_from_server.status_details != NULL) { + gpr_strvec_add(&b, grpc_dump_slice( + *op->data.send_status_from_server.status_details, + GPR_DUMP_ASCII)); + } else { + gpr_strvec_add(&b, gpr_strdup("(null)")); + } add_metadata(&b, op->data.send_status_from_server.trailing_metadata, op->data.send_status_from_server.trailing_metadata_count); break; case GRPC_OP_RECV_INITIAL_METADATA: gpr_asprintf(&tmp, "RECV_INITIAL_METADATA ptr=%p", - op->data.recv_initial_metadata); + op->data.recv_initial_metadata.recv_initial_metadata); gpr_strvec_add(&b, tmp); break; case GRPC_OP_RECV_MESSAGE: - gpr_asprintf(&tmp, "RECV_MESSAGE ptr=%p", op->data.recv_message); + gpr_asprintf(&tmp, "RECV_MESSAGE ptr=%p", + op->data.recv_message.recv_message); gpr_strvec_add(&b, tmp); break; case GRPC_OP_RECV_STATUS_ON_CLIENT: diff --git a/Sources/CgRPC/src/core/lib/surface/call_test_only.h b/Sources/CgRPC/src/core/lib/surface/call_test_only.h index 47088991d..2f1b80bfd 100644 --- a/Sources/CgRPC/src/core/lib/surface/call_test_only.h +++ b/Sources/CgRPC/src/core/lib/surface/call_test_only.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/surface/channel.c b/Sources/CgRPC/src/core/lib/surface/channel.c index 9405015c5..5780a18ce 100644 --- a/Sources/CgRPC/src/core/lib/surface/channel.c +++ b/Sources/CgRPC/src/core/lib/surface/channel.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -43,6 +28,7 @@ #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/iomgr/iomgr.h" +#include "src/core/lib/slice/slice_internal.h" #include "src/core/lib/support/string.h" #include "src/core/lib/surface/api_trace.h" #include "src/core/lib/surface/call.h" @@ -57,15 +43,17 @@ #define NUM_CACHED_STATUS_ELEMS 3 typedef struct registered_call { - grpc_mdelem *path; - grpc_mdelem *authority; + grpc_mdelem path; + grpc_mdelem authority; struct registered_call *next; } registered_call; struct grpc_channel { int is_client; grpc_compression_options compression_options; - grpc_mdelem *default_authority; + grpc_mdelem default_authority; + + gpr_atm call_size_estimate; gpr_mu registered_call_mu; registered_call *registered_calls; @@ -82,18 +70,10 @@ struct grpc_channel { static void destroy_channel(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error); -grpc_channel *grpc_channel_create(grpc_exec_ctx *exec_ctx, const char *target, - const grpc_channel_args *input_args, - grpc_channel_stack_type channel_stack_type, - grpc_transport *optional_transport) { - grpc_channel_stack_builder *builder = grpc_channel_stack_builder_create(); - grpc_channel_stack_builder_set_channel_arguments(builder, input_args); - grpc_channel_stack_builder_set_target(builder, target); - grpc_channel_stack_builder_set_transport(builder, optional_transport); - if (!grpc_channel_init_create_stack(exec_ctx, builder, channel_stack_type)) { - grpc_channel_stack_builder_destroy(builder); - return NULL; - } +grpc_channel *grpc_channel_create_with_builder( + grpc_exec_ctx *exec_ctx, grpc_channel_stack_builder *builder, + grpc_channel_stack_type channel_stack_type) { + char *target = gpr_strdup(grpc_channel_stack_builder_get_target(builder)); grpc_channel_args *args = grpc_channel_args_copy( grpc_channel_stack_builder_get_channel_arguments(builder)); grpc_channel *channel; @@ -101,33 +81,38 @@ grpc_channel *grpc_channel_create(grpc_exec_ctx *exec_ctx, const char *target, exec_ctx, builder, sizeof(grpc_channel), 1, destroy_channel, NULL, (void **)&channel); if (error != GRPC_ERROR_NONE) { - const char *msg = grpc_error_string(error); - gpr_log(GPR_ERROR, "channel stack builder failed: %s", msg); - grpc_error_free_string(msg); + gpr_log(GPR_ERROR, "channel stack builder failed: %s", + grpc_error_string(error)); GRPC_ERROR_UNREF(error); + gpr_free(target); goto done; } memset(channel, 0, sizeof(*channel)); - channel->target = gpr_strdup(target); + channel->target = target; channel->is_client = grpc_channel_stack_type_is_client(channel_stack_type); gpr_mu_init(&channel->registered_call_mu); channel->registered_calls = NULL; - grpc_compression_options_init(&channel->compression_options); + gpr_atm_no_barrier_store( + &channel->call_size_estimate, + (gpr_atm)CHANNEL_STACK_FROM_CHANNEL(channel)->call_stack_size); + grpc_compression_options_init(&channel->compression_options); for (size_t i = 0; i < args->num_args; i++) { if (0 == strcmp(args->args[i].key, GRPC_ARG_DEFAULT_AUTHORITY)) { if (args->args[i].type != GRPC_ARG_STRING) { gpr_log(GPR_ERROR, "%s ignored: it must be a string", GRPC_ARG_DEFAULT_AUTHORITY); } else { - if (channel->default_authority) { + if (!GRPC_MDISNULL(channel->default_authority)) { /* setting this takes precedence over anything else */ - GRPC_MDELEM_UNREF(channel->default_authority); + GRPC_MDELEM_UNREF(exec_ctx, channel->default_authority); } - channel->default_authority = - grpc_mdelem_from_strings(":authority", args->args[i].value.string); + channel->default_authority = grpc_mdelem_from_slices( + exec_ctx, GRPC_MDSTR_AUTHORITY, + grpc_slice_intern( + grpc_slice_from_static_string(args->args[i].value.string))); } } else if (0 == strcmp(args->args[i].key, GRPC_SSL_TARGET_NAME_OVERRIDE_ARG)) { @@ -135,30 +120,35 @@ grpc_channel *grpc_channel_create(grpc_exec_ctx *exec_ctx, const char *target, gpr_log(GPR_ERROR, "%s ignored: it must be a string", GRPC_SSL_TARGET_NAME_OVERRIDE_ARG); } else { - if (channel->default_authority) { + if (!GRPC_MDISNULL(channel->default_authority)) { /* other ways of setting this (notably ssl) take precedence */ gpr_log(GPR_ERROR, "%s ignored: default host already set some other way", GRPC_SSL_TARGET_NAME_OVERRIDE_ARG); } else { - channel->default_authority = grpc_mdelem_from_strings( - ":authority", args->args[i].value.string); + channel->default_authority = grpc_mdelem_from_slices( + exec_ctx, GRPC_MDSTR_AUTHORITY, + grpc_slice_intern( + grpc_slice_from_static_string(args->args[i].value.string))); } } } else if (0 == strcmp(args->args[i].key, GRPC_COMPRESSION_CHANNEL_DEFAULT_LEVEL)) { channel->compression_options.default_level.is_set = true; - GPR_ASSERT(args->args[i].value.integer >= 0 && - args->args[i].value.integer < GRPC_COMPRESS_LEVEL_COUNT); channel->compression_options.default_level.level = - (grpc_compression_level)args->args[i].value.integer; + (grpc_compression_level)grpc_channel_arg_get_integer( + &args->args[i], + (grpc_integer_options){GRPC_COMPRESS_LEVEL_NONE, + GRPC_COMPRESS_LEVEL_NONE, + GRPC_COMPRESS_LEVEL_COUNT - 1}); } else if (0 == strcmp(args->args[i].key, GRPC_COMPRESSION_CHANNEL_DEFAULT_ALGORITHM)) { channel->compression_options.default_algorithm.is_set = true; - GPR_ASSERT(args->args[i].value.integer >= 0 && - args->args[i].value.integer < GRPC_COMPRESS_ALGORITHMS_COUNT); channel->compression_options.default_algorithm.algorithm = - (grpc_compression_algorithm)args->args[i].value.integer; + (grpc_compression_algorithm)grpc_channel_arg_get_integer( + &args->args[i], + (grpc_integer_options){GRPC_COMPRESS_NONE, GRPC_COMPRESS_NONE, + GRPC_COMPRESS_ALGORITHMS_COUNT - 1}); } else if (0 == strcmp(args->args[i].key, GRPC_COMPRESSION_CHANNEL_ENABLED_ALGORITHMS_BITSET)) { @@ -169,10 +159,59 @@ grpc_channel *grpc_channel_create(grpc_exec_ctx *exec_ctx, const char *target, } done: - grpc_channel_args_destroy(args); + grpc_channel_args_destroy(exec_ctx, args); return channel; } +grpc_channel *grpc_channel_create(grpc_exec_ctx *exec_ctx, const char *target, + const grpc_channel_args *input_args, + grpc_channel_stack_type channel_stack_type, + grpc_transport *optional_transport) { + grpc_channel_stack_builder *builder = grpc_channel_stack_builder_create(); + grpc_channel_stack_builder_set_channel_arguments(exec_ctx, builder, + input_args); + grpc_channel_stack_builder_set_target(builder, target); + grpc_channel_stack_builder_set_transport(builder, optional_transport); + if (!grpc_channel_init_create_stack(exec_ctx, builder, channel_stack_type)) { + grpc_channel_stack_builder_destroy(exec_ctx, builder); + return NULL; + } + return grpc_channel_create_with_builder(exec_ctx, builder, + channel_stack_type); +} + +size_t grpc_channel_get_call_size_estimate(grpc_channel *channel) { +#define ROUND_UP_SIZE 256 + /* We round up our current estimate to the NEXT value of ROUND_UP_SIZE. + This ensures: + 1. a consistent size allocation when our estimate is drifting slowly + (which is common) - which tends to help most allocators reuse memory + 2. a small amount of allowed growth over the estimate without hitting + the arena size doubling case, reducing overall memory usage */ + return ((size_t)gpr_atm_no_barrier_load(&channel->call_size_estimate) + + 2 * ROUND_UP_SIZE) & + ~(size_t)(ROUND_UP_SIZE - 1); +} + +void grpc_channel_update_call_size_estimate(grpc_channel *channel, + size_t size) { + size_t cur = (size_t)gpr_atm_no_barrier_load(&channel->call_size_estimate); + if (cur < size) { + /* size grew: update estimate */ + gpr_atm_no_barrier_cas(&channel->call_size_estimate, (gpr_atm)cur, + (gpr_atm)size); + /* if we lose: never mind, something else will likely update soon enough */ + } else if (cur == size) { + /* no change: holding pattern */ + } else if (cur > 0) { + /* size shrank: decrease estimate */ + gpr_atm_no_barrier_cas( + &channel->call_size_estimate, (gpr_atm)cur, + (gpr_atm)(GPR_MIN(cur - 1, (255 * cur + size) / 256))); + /* if we lose: never mind, something else will likely update soon enough */ + } +} + char *grpc_channel_get_target(grpc_channel *channel) { GRPC_API_TRACE("grpc_channel_get_target(channel=%p)", 1, (channel)); return gpr_strdup(channel->target); @@ -188,20 +227,20 @@ void grpc_channel_get_info(grpc_channel *channel, } static grpc_call *grpc_channel_create_call_internal( - grpc_channel *channel, grpc_call *parent_call, uint32_t propagation_mask, - grpc_completion_queue *cq, grpc_pollset_set *pollset_set_alternative, - grpc_mdelem *path_mdelem, grpc_mdelem *authority_mdelem, - gpr_timespec deadline) { - grpc_mdelem *send_metadata[2]; + grpc_exec_ctx *exec_ctx, grpc_channel *channel, grpc_call *parent_call, + uint32_t propagation_mask, grpc_completion_queue *cq, + grpc_pollset_set *pollset_set_alternative, grpc_mdelem path_mdelem, + grpc_mdelem authority_mdelem, gpr_timespec deadline) { + grpc_mdelem send_metadata[2]; size_t num_metadata = 0; GPR_ASSERT(channel->is_client); GPR_ASSERT(!(cq != NULL && pollset_set_alternative != NULL)); send_metadata[num_metadata++] = path_mdelem; - if (authority_mdelem != NULL) { + if (!GRPC_MDISNULL(authority_mdelem)) { send_metadata[num_metadata++] = authority_mdelem; - } else if (channel->default_authority != NULL) { + } else if (!GRPC_MDISNULL(channel->default_authority)) { send_metadata[num_metadata++] = GRPC_MDELEM_REF(channel->default_authority); } @@ -218,7 +257,7 @@ static grpc_call *grpc_channel_create_call_internal( args.send_deadline = deadline; grpc_call *call; - GRPC_LOG_IF_ERROR("call_create", grpc_call_create(&args, &call)); + GRPC_LOG_IF_ERROR("call_create", grpc_call_create(exec_ctx, &args, &call)); return call; } @@ -226,41 +265,34 @@ grpc_call *grpc_channel_create_call(grpc_channel *channel, grpc_call *parent_call, uint32_t propagation_mask, grpc_completion_queue *cq, - const char *method, const char *host, + grpc_slice method, const grpc_slice *host, gpr_timespec deadline, void *reserved) { - GRPC_API_TRACE( - "grpc_channel_create_call(" - "channel=%p, parent_call=%p, propagation_mask=%x, cq=%p, method=%s, " - "host=%s, " - "deadline=gpr_timespec { tv_sec: %" PRId64 - ", tv_nsec: %d, clock_type: %d }, " - "reserved=%p)", - 10, - (channel, parent_call, (unsigned)propagation_mask, cq, method, host, - deadline.tv_sec, deadline.tv_nsec, (int)deadline.clock_type, reserved)); GPR_ASSERT(!reserved); - return grpc_channel_create_call_internal( - channel, parent_call, propagation_mask, cq, NULL, - grpc_mdelem_from_metadata_strings(GRPC_MDSTR_PATH, - grpc_mdstr_from_string(method)), - host ? grpc_mdelem_from_metadata_strings(GRPC_MDSTR_AUTHORITY, - grpc_mdstr_from_string(host)) - : NULL, + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + grpc_call *call = grpc_channel_create_call_internal( + &exec_ctx, channel, parent_call, propagation_mask, cq, NULL, + grpc_mdelem_from_slices(&exec_ctx, GRPC_MDSTR_PATH, + grpc_slice_ref_internal(method)), + host != NULL ? grpc_mdelem_from_slices(&exec_ctx, GRPC_MDSTR_AUTHORITY, + grpc_slice_ref_internal(*host)) + : GRPC_MDNULL, deadline); + grpc_exec_ctx_finish(&exec_ctx); + return call; } grpc_call *grpc_channel_create_pollset_set_call( - grpc_channel *channel, grpc_call *parent_call, uint32_t propagation_mask, - grpc_pollset_set *pollset_set, const char *method, const char *host, - gpr_timespec deadline, void *reserved) { + grpc_exec_ctx *exec_ctx, grpc_channel *channel, grpc_call *parent_call, + uint32_t propagation_mask, grpc_pollset_set *pollset_set, grpc_slice method, + const grpc_slice *host, gpr_timespec deadline, void *reserved) { GPR_ASSERT(!reserved); return grpc_channel_create_call_internal( - channel, parent_call, propagation_mask, NULL, pollset_set, - grpc_mdelem_from_metadata_strings(GRPC_MDSTR_PATH, - grpc_mdstr_from_string(method)), - host ? grpc_mdelem_from_metadata_strings(GRPC_MDSTR_AUTHORITY, - grpc_mdstr_from_string(host)) - : NULL, + exec_ctx, channel, parent_call, propagation_mask, NULL, pollset_set, + grpc_mdelem_from_slices(exec_ctx, GRPC_MDSTR_PATH, + grpc_slice_ref_internal(method)), + host != NULL ? grpc_mdelem_from_slices(exec_ctx, GRPC_MDSTR_AUTHORITY, + grpc_slice_ref_internal(*host)) + : GRPC_MDNULL, deadline); } @@ -271,15 +303,21 @@ void *grpc_channel_register_call(grpc_channel *channel, const char *method, "grpc_channel_register_call(channel=%p, method=%s, host=%s, reserved=%p)", 4, (channel, method, host, reserved)); GPR_ASSERT(!reserved); - rc->path = grpc_mdelem_from_metadata_strings(GRPC_MDSTR_PATH, - grpc_mdstr_from_string(method)); - rc->authority = host ? grpc_mdelem_from_metadata_strings( - GRPC_MDSTR_AUTHORITY, grpc_mdstr_from_string(host)) - : NULL; + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + + rc->path = grpc_mdelem_from_slices( + &exec_ctx, GRPC_MDSTR_PATH, + grpc_slice_intern(grpc_slice_from_static_string(method))); + rc->authority = + host ? grpc_mdelem_from_slices( + &exec_ctx, GRPC_MDSTR_AUTHORITY, + grpc_slice_intern(grpc_slice_from_static_string(host))) + : GRPC_MDNULL; gpr_mu_lock(&channel->registered_call_mu); rc->next = channel->registered_calls; channel->registered_calls = rc; gpr_mu_unlock(&channel->registered_call_mu); + grpc_exec_ctx_finish(&exec_ctx); return rc; } @@ -299,13 +337,15 @@ grpc_call *grpc_channel_create_registered_call( registered_call_handle, deadline.tv_sec, deadline.tv_nsec, (int)deadline.clock_type, reserved)); GPR_ASSERT(!reserved); - return grpc_channel_create_call_internal( - channel, parent_call, propagation_mask, completion_queue, NULL, - GRPC_MDELEM_REF(rc->path), - rc->authority ? GRPC_MDELEM_REF(rc->authority) : NULL, deadline); + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + grpc_call *call = grpc_channel_create_call_internal( + &exec_ctx, channel, parent_call, propagation_mask, completion_queue, NULL, + GRPC_MDELEM_REF(rc->path), GRPC_MDELEM_REF(rc->authority), deadline); + grpc_exec_ctx_finish(&exec_ctx); + return call; } -#ifdef GRPC_STREAM_REFCOUNT_DEBUG +#ifndef NDEBUG #define REF_REASON reason #define REF_ARG , const char *reason #else @@ -328,15 +368,11 @@ static void destroy_channel(grpc_exec_ctx *exec_ctx, void *arg, while (channel->registered_calls) { registered_call *rc = channel->registered_calls; channel->registered_calls = rc->next; - GRPC_MDELEM_UNREF(rc->path); - if (rc->authority) { - GRPC_MDELEM_UNREF(rc->authority); - } + GRPC_MDELEM_UNREF(exec_ctx, rc->path); + GRPC_MDELEM_UNREF(exec_ctx, rc->authority); gpr_free(rc); } - if (channel->default_authority != NULL) { - GRPC_MDELEM_UNREF(channel->default_authority); - } + GRPC_MDELEM_UNREF(exec_ctx, channel->default_authority); gpr_mu_destroy(&channel->registered_call_mu); gpr_free(channel->target); gpr_free(channel); @@ -347,7 +383,8 @@ void grpc_channel_destroy(grpc_channel *channel) { grpc_channel_element *elem; grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; GRPC_API_TRACE("grpc_channel_destroy(channel=%p)", 1, (channel)); - op->disconnect_with_error = GRPC_ERROR_CREATE("Channel Destroyed"); + op->disconnect_with_error = + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Channel Destroyed"); elem = grpc_channel_stack_element(CHANNEL_STACK_FROM_CHANNEL(channel), 0); elem->filter->start_transport_op(&exec_ctx, elem, op); @@ -365,7 +402,8 @@ grpc_compression_options grpc_channel_compression_options( return channel->compression_options; } -grpc_mdelem *grpc_channel_get_reffed_status_elem(grpc_channel *channel, int i) { +grpc_mdelem grpc_channel_get_reffed_status_elem(grpc_exec_ctx *exec_ctx, + grpc_channel *channel, int i) { char tmp[GPR_LTOA_MIN_BUFSIZE]; switch (i) { case 0: @@ -376,6 +414,6 @@ grpc_mdelem *grpc_channel_get_reffed_status_elem(grpc_channel *channel, int i) { return GRPC_MDELEM_GRPC_STATUS_2; } gpr_ltoa(i, tmp); - return grpc_mdelem_from_metadata_strings(GRPC_MDSTR_GRPC_STATUS, - grpc_mdstr_from_string(tmp)); + return grpc_mdelem_from_slices(exec_ctx, GRPC_MDSTR_GRPC_STATUS, + grpc_slice_from_copied_string(tmp)); } diff --git a/Sources/CgRPC/src/core/lib/surface/channel.h b/Sources/CgRPC/src/core/lib/surface/channel.h index 23cc8656c..528bb868e 100644 --- a/Sources/CgRPC/src/core/lib/surface/channel.h +++ b/Sources/CgRPC/src/core/lib/surface/channel.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -35,6 +20,7 @@ #define GRPC_CORE_LIB_SURFACE_CHANNEL_H #include "src/core/lib/channel/channel_stack.h" +#include "src/core/lib/channel/channel_stack_builder.h" #include "src/core/lib/surface/channel_stack_type.h" grpc_channel *grpc_channel_create(grpc_exec_ctx *exec_ctx, const char *target, @@ -42,6 +28,10 @@ grpc_channel *grpc_channel_create(grpc_exec_ctx *exec_ctx, const char *target, grpc_channel_stack_type channel_stack_type, grpc_transport *optional_transport); +grpc_channel *grpc_channel_create_with_builder( + grpc_exec_ctx *exec_ctx, grpc_channel_stack_builder *builder, + grpc_channel_stack_type channel_stack_type); + /** Create a call given a grpc_channel, in order to call \a method. Progress is tied to activity on \a pollset_set. The returned call object is meant to be used with \a grpc_call_start_batch_and_execute, which relies on @@ -51,9 +41,9 @@ grpc_channel *grpc_channel_create(grpc_exec_ctx *exec_ctx, const char *target, properties from the server call to this new client call, depending on the value of \a propagation_mask (see propagation_bits.h for possible values) */ grpc_call *grpc_channel_create_pollset_set_call( - grpc_channel *channel, grpc_call *parent_call, uint32_t propagation_mask, - grpc_pollset_set *pollset_set, const char *method, const char *host, - gpr_timespec deadline, void *reserved); + grpc_exec_ctx *exec_ctx, grpc_channel *channel, grpc_call *parent_call, + uint32_t propagation_mask, grpc_pollset_set *pollset_set, grpc_slice method, + const grpc_slice *host, gpr_timespec deadline, void *reserved); /** Get a (borrowed) pointer to this channels underlying channel stack */ grpc_channel_stack *grpc_channel_get_channel_stack(grpc_channel *channel); @@ -62,10 +52,14 @@ grpc_channel_stack *grpc_channel_get_channel_stack(grpc_channel *channel); status_code. The returned elem is owned by the caller. */ -grpc_mdelem *grpc_channel_get_reffed_status_elem(grpc_channel *channel, - int status_code); +grpc_mdelem grpc_channel_get_reffed_status_elem(grpc_exec_ctx *exec_ctx, + grpc_channel *channel, + int status_code); + +size_t grpc_channel_get_call_size_estimate(grpc_channel *channel); +void grpc_channel_update_call_size_estimate(grpc_channel *channel, size_t size); -#ifdef GRPC_STREAM_REFCOUNT_DEBUG +#ifndef NDEBUG void grpc_channel_internal_ref(grpc_channel *channel, const char *reason); void grpc_channel_internal_unref(grpc_exec_ctx *exec_ctx, grpc_channel *channel, const char *reason); diff --git a/Sources/CgRPC/src/core/lib/surface/channel_init.c b/Sources/CgRPC/src/core/lib/surface/channel_init.c index 0627b3447..a1391ffe5 100644 --- a/Sources/CgRPC/src/core/lib/surface/channel_init.c +++ b/Sources/CgRPC/src/core/lib/surface/channel_init.c @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -104,34 +89,17 @@ void grpc_channel_init_shutdown(void) { } } -static const char *name_for_type(grpc_channel_stack_type type) { - switch (type) { - case GRPC_CLIENT_CHANNEL: - return "CLIENT_CHANNEL"; - case GRPC_CLIENT_SUBCHANNEL: - return "CLIENT_SUBCHANNEL"; - case GRPC_SERVER_CHANNEL: - return "SERVER_CHANNEL"; - case GRPC_CLIENT_LAME_CHANNEL: - return "CLIENT_LAME_CHANNEL"; - case GRPC_CLIENT_DIRECT_CHANNEL: - return "CLIENT_DIRECT_CHANNEL"; - case GRPC_NUM_CHANNEL_STACK_TYPES: - break; - } - GPR_UNREACHABLE_CODE(return "UNKNOWN"); -} - bool grpc_channel_init_create_stack(grpc_exec_ctx *exec_ctx, grpc_channel_stack_builder *builder, grpc_channel_stack_type type) { GPR_ASSERT(g_finalized); - grpc_channel_stack_builder_set_name(builder, name_for_type(type)); + grpc_channel_stack_builder_set_name(builder, + grpc_channel_stack_type_string(type)); for (size_t i = 0; i < g_slots[type].num_slots; i++) { const stage_slot *slot = &g_slots[type].slots[i]; - if (!slot->fn(builder, slot->arg)) { + if (!slot->fn(exec_ctx, builder, slot->arg)) { return false; } } diff --git a/Sources/CgRPC/src/core/lib/surface/channel_init.h b/Sources/CgRPC/src/core/lib/surface/channel_init.h index b53f2aefb..5f109332a 100644 --- a/Sources/CgRPC/src/core/lib/surface/channel_init.h +++ b/Sources/CgRPC/src/core/lib/surface/channel_init.h @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -51,7 +36,8 @@ extern "C" { /// One stage of mutation: call functions against \a builder to influence the /// finally constructed channel stack -typedef bool (*grpc_channel_init_stage)(grpc_channel_stack_builder *builder, +typedef bool (*grpc_channel_init_stage)(grpc_exec_ctx *exec_ctx, + grpc_channel_stack_builder *builder, void *arg); /// Global initialization of the system diff --git a/Sources/CgRPC/src/core/lib/surface/channel_ping.c b/Sources/CgRPC/src/core/lib/surface/channel_ping.c index 0d2f01a64..e85b30885 100644 --- a/Sources/CgRPC/src/core/lib/surface/channel_ping.c +++ b/Sources/CgRPC/src/core/lib/surface/channel_ping.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -71,10 +56,10 @@ void grpc_channel_ping(grpc_channel *channel, grpc_completion_queue *cq, GPR_ASSERT(reserved == NULL); pr->tag = tag; pr->cq = cq; - grpc_closure_init(&pr->closure, ping_done, pr); + GRPC_CLOSURE_INIT(&pr->closure, ping_done, pr, grpc_schedule_on_exec_ctx); op->send_ping = &pr->closure; op->bind_pollset = grpc_cq_pollset(cq); - grpc_cq_begin_op(cq, tag); + GPR_ASSERT(grpc_cq_begin_op(cq, tag)); top_elem->filter->start_transport_op(&exec_ctx, top_elem, op); grpc_exec_ctx_finish(&exec_ctx); } diff --git a/Sources/CgRPC/src/core/lib/surface/channel_stack_type.c b/Sources/CgRPC/src/core/lib/surface/channel_stack_type.c index c35d603ca..5f5c87772 100644 --- a/Sources/CgRPC/src/core/lib/surface/channel_stack_type.c +++ b/Sources/CgRPC/src/core/lib/surface/channel_stack_type.c @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -52,3 +37,21 @@ bool grpc_channel_stack_type_is_client(grpc_channel_stack_type type) { } GPR_UNREACHABLE_CODE(return true;); } + +const char *grpc_channel_stack_type_string(grpc_channel_stack_type type) { + switch (type) { + case GRPC_CLIENT_CHANNEL: + return "CLIENT_CHANNEL"; + case GRPC_CLIENT_SUBCHANNEL: + return "CLIENT_SUBCHANNEL"; + case GRPC_SERVER_CHANNEL: + return "SERVER_CHANNEL"; + case GRPC_CLIENT_LAME_CHANNEL: + return "CLIENT_LAME_CHANNEL"; + case GRPC_CLIENT_DIRECT_CHANNEL: + return "CLIENT_DIRECT_CHANNEL"; + case GRPC_NUM_CHANNEL_STACK_TYPES: + break; + } + GPR_UNREACHABLE_CODE(return "UNKNOWN"); +} diff --git a/Sources/CgRPC/src/core/lib/surface/channel_stack_type.h b/Sources/CgRPC/src/core/lib/surface/channel_stack_type.h index 4eea4f1b0..3f0e14ffc 100644 --- a/Sources/CgRPC/src/core/lib/surface/channel_stack_type.h +++ b/Sources/CgRPC/src/core/lib/surface/channel_stack_type.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -55,4 +40,6 @@ typedef enum { bool grpc_channel_stack_type_is_client(grpc_channel_stack_type type); +const char *grpc_channel_stack_type_string(grpc_channel_stack_type type); + #endif /* GRPC_CORE_LIB_SURFACE_CHANNEL_STACK_TYPE_H */ diff --git a/Sources/CgRPC/src/core/lib/surface/completion_queue.c b/Sources/CgRPC/src/core/lib/surface/completion_queue.c index 184c1a1a1..c20cfbc74 100644 --- a/Sources/CgRPC/src/core/lib/surface/completion_queue.c +++ b/Sources/CgRPC/src/core/lib/surface/completion_queue.c @@ -1,36 +1,20 @@ /* * - * Copyright 2015-2016, Google Inc. - * All rights reserved. + * Copyright 2015-2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 "src/core/lib/surface/completion_queue.h" #include @@ -45,14 +29,19 @@ #include "src/core/lib/iomgr/pollset.h" #include "src/core/lib/iomgr/timer.h" #include "src/core/lib/profiling/timers.h" +#include "src/core/lib/support/spinlock.h" #include "src/core/lib/support/string.h" #include "src/core/lib/surface/api_trace.h" #include "src/core/lib/surface/call.h" #include "src/core/lib/surface/event_string.h" -int grpc_trace_operation_failures; +grpc_tracer_flag grpc_trace_operation_failures = + GRPC_TRACER_INITIALIZER(false, "op_failure"); #ifndef NDEBUG -int grpc_trace_pending_tags; +grpc_tracer_flag grpc_trace_pending_tags = + GRPC_TRACER_INITIALIZER(false, "pending_tags"); +grpc_tracer_flag grpc_trace_cq_refcount = + GRPC_TRACER_INITIALIZER(false, "cq_refcount"); #endif typedef struct { @@ -60,29 +49,230 @@ typedef struct { void *tag; } plucker; -/* Completion queue structure */ -struct grpc_completion_queue { - /** owned by pollset */ - gpr_mu *mu; - /** completed events */ +typedef struct { + bool can_get_pollset; + bool can_listen; + size_t (*size)(void); + void (*init)(grpc_pollset *pollset, gpr_mu **mu); + grpc_error *(*kick)(grpc_pollset *pollset, + grpc_pollset_worker *specific_worker); + grpc_error *(*work)(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, + grpc_pollset_worker **worker, gpr_timespec now, + gpr_timespec deadline); + void (*shutdown)(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, + grpc_closure *closure); + void (*destroy)(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset); +} cq_poller_vtable; + +typedef struct non_polling_worker { + gpr_cv cv; + bool kicked; + struct non_polling_worker *next; + struct non_polling_worker *prev; +} non_polling_worker; + +typedef struct { + gpr_mu mu; + non_polling_worker *root; + grpc_closure *shutdown; +} non_polling_poller; + +static size_t non_polling_poller_size(void) { + return sizeof(non_polling_poller); +} + +static void non_polling_poller_init(grpc_pollset *pollset, gpr_mu **mu) { + non_polling_poller *npp = (non_polling_poller *)pollset; + gpr_mu_init(&npp->mu); + *mu = &npp->mu; +} + +static void non_polling_poller_destroy(grpc_exec_ctx *exec_ctx, + grpc_pollset *pollset) { + non_polling_poller *npp = (non_polling_poller *)pollset; + gpr_mu_destroy(&npp->mu); +} + +static grpc_error *non_polling_poller_work(grpc_exec_ctx *exec_ctx, + grpc_pollset *pollset, + grpc_pollset_worker **worker, + gpr_timespec now, + gpr_timespec deadline) { + non_polling_poller *npp = (non_polling_poller *)pollset; + if (npp->shutdown) return GRPC_ERROR_NONE; + non_polling_worker w; + gpr_cv_init(&w.cv); + if (worker != NULL) *worker = (grpc_pollset_worker *)&w; + if (npp->root == NULL) { + npp->root = w.next = w.prev = &w; + } else { + w.next = npp->root; + w.prev = w.next->prev; + w.next->prev = w.prev->next = &w; + } + w.kicked = false; + while (!npp->shutdown && !w.kicked && !gpr_cv_wait(&w.cv, &npp->mu, deadline)) + ; + if (&w == npp->root) { + npp->root = w.next; + if (&w == npp->root) { + if (npp->shutdown) { + GRPC_CLOSURE_SCHED(exec_ctx, npp->shutdown, GRPC_ERROR_NONE); + } + npp->root = NULL; + } + } + w.next->prev = w.prev; + w.prev->next = w.next; + gpr_cv_destroy(&w.cv); + if (worker != NULL) *worker = NULL; + return GRPC_ERROR_NONE; +} + +static grpc_error *non_polling_poller_kick( + grpc_pollset *pollset, grpc_pollset_worker *specific_worker) { + non_polling_poller *p = (non_polling_poller *)pollset; + if (specific_worker == NULL) specific_worker = (grpc_pollset_worker *)p->root; + if (specific_worker != NULL) { + non_polling_worker *w = (non_polling_worker *)specific_worker; + if (!w->kicked) { + w->kicked = true; + gpr_cv_signal(&w->cv); + } + } + return GRPC_ERROR_NONE; +} + +static void non_polling_poller_shutdown(grpc_exec_ctx *exec_ctx, + grpc_pollset *pollset, + grpc_closure *closure) { + non_polling_poller *p = (non_polling_poller *)pollset; + GPR_ASSERT(closure != NULL); + p->shutdown = closure; + if (p->root == NULL) { + GRPC_CLOSURE_SCHED(exec_ctx, closure, GRPC_ERROR_NONE); + } else { + non_polling_worker *w = p->root; + do { + gpr_cv_signal(&w->cv); + w = w->next; + } while (w != p->root); + } +} + +static const cq_poller_vtable g_poller_vtable_by_poller_type[] = { + /* GRPC_CQ_DEFAULT_POLLING */ + {.can_get_pollset = true, + .can_listen = true, + .size = grpc_pollset_size, + .init = grpc_pollset_init, + .kick = grpc_pollset_kick, + .work = grpc_pollset_work, + .shutdown = grpc_pollset_shutdown, + .destroy = grpc_pollset_destroy}, + /* GRPC_CQ_NON_LISTENING */ + {.can_get_pollset = true, + .can_listen = false, + .size = grpc_pollset_size, + .init = grpc_pollset_init, + .kick = grpc_pollset_kick, + .work = grpc_pollset_work, + .shutdown = grpc_pollset_shutdown, + .destroy = grpc_pollset_destroy}, + /* GRPC_CQ_NON_POLLING */ + {.can_get_pollset = false, + .can_listen = false, + .size = non_polling_poller_size, + .init = non_polling_poller_init, + .kick = non_polling_poller_kick, + .work = non_polling_poller_work, + .shutdown = non_polling_poller_shutdown, + .destroy = non_polling_poller_destroy}, +}; + +typedef struct cq_vtable { + grpc_cq_completion_type cq_completion_type; + size_t data_size; + void (*init)(void *data); + void (*shutdown)(grpc_exec_ctx *exec_ctx, grpc_completion_queue *cq); + void (*destroy)(void *data); + bool (*begin_op)(grpc_completion_queue *cq, void *tag); + void (*end_op)(grpc_exec_ctx *exec_ctx, grpc_completion_queue *cq, void *tag, + grpc_error *error, + void (*done)(grpc_exec_ctx *exec_ctx, void *done_arg, + grpc_cq_completion *storage), + void *done_arg, grpc_cq_completion *storage); + grpc_event (*next)(grpc_completion_queue *cq, gpr_timespec deadline, + void *reserved); + grpc_event (*pluck)(grpc_completion_queue *cq, void *tag, + gpr_timespec deadline, void *reserved); +} cq_vtable; + +/* Queue that holds the cq_completion_events. Internally uses gpr_mpscq queue + * (a lockfree multiproducer single consumer queue). It uses a queue_lock + * to support multiple consumers. + * Only used in completion queues whose completion_type is GRPC_CQ_NEXT */ +typedef struct grpc_cq_event_queue { + /* Spinlock to serialize consumers i.e pop() operations */ + gpr_spinlock queue_lock; + + gpr_mpscq queue; + + /* A lazy counter of number of items in the queue. This is NOT atomically + incremented/decremented along with push/pop operations and hence is only + eventually consistent */ + gpr_atm num_queue_items; +} grpc_cq_event_queue; + +typedef struct cq_next_data { + /** Completed events for completion-queues of type GRPC_CQ_NEXT */ + grpc_cq_event_queue queue; + + /** Counter of how many things have ever been queued on this completion queue + useful for avoiding locks to check the queue */ + gpr_atm things_queued_ever; + + /* Number of outstanding events (+1 if not shut down) */ + gpr_atm pending_events; + + /** 0 initially. 1 once we initiated shutdown */ + bool shutdown_called; +} cq_next_data; + +typedef struct cq_pluck_data { + /** Completed events for completion-queues of type GRPC_CQ_PLUCK */ grpc_cq_completion completed_head; grpc_cq_completion *completed_tail; + /** Number of pending events (+1 if we're not shutdown) */ - gpr_refcount pending_events; - /** Once owning_refs drops to zero, we will destroy the cq */ - gpr_refcount owning_refs; - /** counter of how many things have ever been queued on this completion queue + gpr_atm pending_events; + + /** Counter of how many things have ever been queued on this completion queue useful for avoiding locks to check the queue */ gpr_atm things_queued_ever; - /** 0 initially, 1 once we've begun shutting down */ - int shutdown; - int shutdown_called; - int is_server_cq; - /** Can the server cq accept incoming channels */ - int is_non_listening_server_cq; + + /** 0 initially. 1 once we completed shutting */ + /* TODO: (sreek) This is not needed since (shutdown == 1) if and only if + * (pending_events == 0). So consider removing this in future and use + * pending_events */ + gpr_atm shutdown; + + /** 0 initially. 1 once we initiated shutdown */ + bool shutdown_called; + int num_pluckers; plucker pluckers[GRPC_MAX_COMPLETION_QUEUE_PLUCKERS]; - grpc_closure pollset_shutdown_done; +} cq_pluck_data; + +/* Completion queue structure */ +struct grpc_completion_queue { + /** Once owning_refs drops to zero, we will destroy the cq */ + gpr_refcount owning_refs; + + gpr_mu *mu; + + const cq_vtable *vtable; + const cq_poller_vtable *poller_vtable; #ifndef NDEBUG void **outstanding_tags; @@ -90,229 +280,482 @@ struct grpc_completion_queue { size_t outstanding_tag_capacity; #endif - grpc_completion_queue *next_free; + grpc_closure pollset_shutdown_done; + int num_polls; }; -#define POLLSET_FROM_CQ(cq) ((grpc_pollset *)(cq + 1)) -#define CQ_FROM_POLLSET(ps) (((grpc_completion_queue *)ps) - 1) - -static gpr_mu g_freelist_mu; -static grpc_completion_queue *g_freelist; - -int grpc_cq_pluck_trace; -int grpc_cq_event_timeout_trace; +/* Forward declarations */ +static void cq_finish_shutdown_next(grpc_exec_ctx *exec_ctx, + grpc_completion_queue *cq); +static void cq_finish_shutdown_pluck(grpc_exec_ctx *exec_ctx, + grpc_completion_queue *cq); +static void cq_shutdown_next(grpc_exec_ctx *exec_ctx, + grpc_completion_queue *cq); +static void cq_shutdown_pluck(grpc_exec_ctx *exec_ctx, + grpc_completion_queue *cq); + +static bool cq_begin_op_for_next(grpc_completion_queue *cq, void *tag); +static bool cq_begin_op_for_pluck(grpc_completion_queue *cq, void *tag); + +static void cq_end_op_for_next(grpc_exec_ctx *exec_ctx, + grpc_completion_queue *cq, void *tag, + grpc_error *error, + void (*done)(grpc_exec_ctx *exec_ctx, + void *done_arg, + grpc_cq_completion *storage), + void *done_arg, grpc_cq_completion *storage); + +static void cq_end_op_for_pluck(grpc_exec_ctx *exec_ctx, + grpc_completion_queue *cq, void *tag, + grpc_error *error, + void (*done)(grpc_exec_ctx *exec_ctx, + void *done_arg, + grpc_cq_completion *storage), + void *done_arg, grpc_cq_completion *storage); + +static grpc_event cq_next(grpc_completion_queue *cq, gpr_timespec deadline, + void *reserved); + +static grpc_event cq_pluck(grpc_completion_queue *cq, void *tag, + gpr_timespec deadline, void *reserved); + +static void cq_init_next(void *data); +static void cq_init_pluck(void *data); +static void cq_destroy_next(void *data); +static void cq_destroy_pluck(void *data); + +/* Completion queue vtables based on the completion-type */ +static const cq_vtable g_cq_vtable[] = { + /* GRPC_CQ_NEXT */ + {.data_size = sizeof(cq_next_data), + .cq_completion_type = GRPC_CQ_NEXT, + .init = cq_init_next, + .shutdown = cq_shutdown_next, + .destroy = cq_destroy_next, + .begin_op = cq_begin_op_for_next, + .end_op = cq_end_op_for_next, + .next = cq_next, + .pluck = NULL}, + /* GRPC_CQ_PLUCK */ + {.data_size = sizeof(cq_pluck_data), + .cq_completion_type = GRPC_CQ_PLUCK, + .init = cq_init_pluck, + .shutdown = cq_shutdown_pluck, + .destroy = cq_destroy_pluck, + .begin_op = cq_begin_op_for_pluck, + .end_op = cq_end_op_for_pluck, + .next = NULL, + .pluck = cq_pluck}, +}; -#define GRPC_SURFACE_TRACE_RETURNED_EVENT(cq, event) \ - if (grpc_api_trace && \ - (grpc_cq_pluck_trace || (event)->type != GRPC_QUEUE_TIMEOUT)) { \ - char *_ev = grpc_event_string(event); \ - gpr_log(GPR_INFO, "RETURN_EVENT[%p]: %s", cq, _ev); \ - gpr_free(_ev); \ +#define DATA_FROM_CQ(cq) ((void *)(cq + 1)) +#define POLLSET_FROM_CQ(cq) \ + ((grpc_pollset *)(cq->vtable->data_size + (char *)DATA_FROM_CQ(cq))) + +grpc_tracer_flag grpc_cq_pluck_trace = + GRPC_TRACER_INITIALIZER(true, "queue_pluck"); +grpc_tracer_flag grpc_cq_event_timeout_trace = + GRPC_TRACER_INITIALIZER(true, "queue_timeout"); + +#define GRPC_SURFACE_TRACE_RETURNED_EVENT(cq, event) \ + if (GRPC_TRACER_ON(grpc_api_trace) && \ + (GRPC_TRACER_ON(grpc_cq_pluck_trace) || \ + (event)->type != GRPC_QUEUE_TIMEOUT)) { \ + char *_ev = grpc_event_string(event); \ + gpr_log(GPR_INFO, "RETURN_EVENT[%p]: %s", cq, _ev); \ + gpr_free(_ev); \ } -static void on_pollset_shutdown_done(grpc_exec_ctx *exec_ctx, void *cc, +static void on_pollset_shutdown_done(grpc_exec_ctx *exec_ctx, void *cq, grpc_error *error); -void grpc_cq_global_init(void) { gpr_mu_init(&g_freelist_mu); } +static void cq_event_queue_init(grpc_cq_event_queue *q) { + gpr_mpscq_init(&q->queue); + q->queue_lock = GPR_SPINLOCK_INITIALIZER; + gpr_atm_no_barrier_store(&q->num_queue_items, 0); +} -void grpc_cq_global_shutdown(void) { - gpr_mu_destroy(&g_freelist_mu); - while (g_freelist) { - grpc_completion_queue *next = g_freelist->next_free; - grpc_pollset_destroy(POLLSET_FROM_CQ(g_freelist)); -#ifndef NDEBUG - gpr_free(g_freelist->outstanding_tags); -#endif - gpr_free(g_freelist); - g_freelist = next; +static void cq_event_queue_destroy(grpc_cq_event_queue *q) { + gpr_mpscq_destroy(&q->queue); +} + +static bool cq_event_queue_push(grpc_cq_event_queue *q, grpc_cq_completion *c) { + gpr_mpscq_push(&q->queue, (gpr_mpscq_node *)c); + return gpr_atm_no_barrier_fetch_add(&q->num_queue_items, 1) == 0; +} + +static grpc_cq_completion *cq_event_queue_pop(grpc_cq_event_queue *q) { + grpc_cq_completion *c = NULL; + if (gpr_spinlock_trylock(&q->queue_lock)) { + c = (grpc_cq_completion *)gpr_mpscq_pop(&q->queue); + gpr_spinlock_unlock(&q->queue_lock); } + + if (c) { + gpr_atm_no_barrier_fetch_add(&q->num_queue_items, -1); + } + + return c; } -grpc_completion_queue *grpc_completion_queue_create(void *reserved) { - grpc_completion_queue *cc; - GPR_ASSERT(!reserved); +/* Note: The counter is not incremented/decremented atomically with push/pop. + * The count is only eventually consistent */ +static long cq_event_queue_num_items(grpc_cq_event_queue *q) { + return (long)gpr_atm_no_barrier_load(&q->num_queue_items); +} - GPR_TIMER_BEGIN("grpc_completion_queue_create", 0); +grpc_completion_queue *grpc_completion_queue_create_internal( + grpc_cq_completion_type completion_type, + grpc_cq_polling_type polling_type) { + grpc_completion_queue *cq; - GRPC_API_TRACE("grpc_completion_queue_create(reserved=%p)", 1, (reserved)); + GPR_TIMER_BEGIN("grpc_completion_queue_create_internal", 0); - gpr_mu_lock(&g_freelist_mu); - if (g_freelist == NULL) { - gpr_mu_unlock(&g_freelist_mu); + GRPC_API_TRACE( + "grpc_completion_queue_create_internal(completion_type=%d, " + "polling_type=%d)", + 2, (completion_type, polling_type)); - cc = gpr_malloc(sizeof(grpc_completion_queue) + grpc_pollset_size()); - grpc_pollset_init(POLLSET_FROM_CQ(cc), &cc->mu); -#ifndef NDEBUG - cc->outstanding_tags = NULL; - cc->outstanding_tag_capacity = 0; -#endif - } else { - cc = g_freelist; - g_freelist = g_freelist->next_free; - gpr_mu_unlock(&g_freelist_mu); - /* pollset already initialized */ - } + const cq_vtable *vtable = &g_cq_vtable[completion_type]; + const cq_poller_vtable *poller_vtable = + &g_poller_vtable_by_poller_type[polling_type]; + + cq = gpr_zalloc(sizeof(grpc_completion_queue) + vtable->data_size + + poller_vtable->size()); + + cq->vtable = vtable; + cq->poller_vtable = poller_vtable; - /* Initial ref is dropped by grpc_completion_queue_shutdown */ - gpr_ref_init(&cc->pending_events, 1); /* One for destroy(), one for pollset_shutdown */ - gpr_ref_init(&cc->owning_refs, 2); - cc->completed_tail = &cc->completed_head; - cc->completed_head.next = (uintptr_t)cc->completed_tail; - cc->shutdown = 0; - cc->shutdown_called = 0; - cc->is_server_cq = 0; - cc->is_non_listening_server_cq = 0; - cc->num_pluckers = 0; - gpr_atm_no_barrier_store(&cc->things_queued_ever, 0); -#ifndef NDEBUG - cc->outstanding_tag_count = 0; -#endif - grpc_closure_init(&cc->pollset_shutdown_done, on_pollset_shutdown_done, cc); + gpr_ref_init(&cq->owning_refs, 2); + + poller_vtable->init(POLLSET_FROM_CQ(cq), &cq->mu); + vtable->init(DATA_FROM_CQ(cq)); + + GRPC_CLOSURE_INIT(&cq->pollset_shutdown_done, on_pollset_shutdown_done, cq, + grpc_schedule_on_exec_ctx); + + GPR_TIMER_END("grpc_completion_queue_create_internal", 0); + + return cq; +} + +static void cq_init_next(void *ptr) { + cq_next_data *cqd = ptr; + /* Initial count is dropped by grpc_completion_queue_shutdown */ + gpr_atm_no_barrier_store(&cqd->pending_events, 1); + cqd->shutdown_called = false; + gpr_atm_no_barrier_store(&cqd->things_queued_ever, 0); + cq_event_queue_init(&cqd->queue); +} - GPR_TIMER_END("grpc_completion_queue_create", 0); +static void cq_destroy_next(void *ptr) { + cq_next_data *cqd = ptr; + GPR_ASSERT(cq_event_queue_num_items(&cqd->queue) == 0); + cq_event_queue_destroy(&cqd->queue); +} - return cc; +static void cq_init_pluck(void *ptr) { + cq_pluck_data *cqd = ptr; + /* Initial count is dropped by grpc_completion_queue_shutdown */ + gpr_atm_no_barrier_store(&cqd->pending_events, 1); + cqd->completed_tail = &cqd->completed_head; + cqd->completed_head.next = (uintptr_t)cqd->completed_tail; + gpr_atm_no_barrier_store(&cqd->shutdown, 0); + cqd->shutdown_called = false; + cqd->num_pluckers = 0; + gpr_atm_no_barrier_store(&cqd->things_queued_ever, 0); } -#ifdef GRPC_CQ_REF_COUNT_DEBUG -void grpc_cq_internal_ref(grpc_completion_queue *cc, const char *reason, +static void cq_destroy_pluck(void *ptr) { + cq_pluck_data *cqd = ptr; + GPR_ASSERT(cqd->completed_head.next == (uintptr_t)&cqd->completed_head); +} + +grpc_cq_completion_type grpc_get_cq_completion_type(grpc_completion_queue *cq) { + return cq->vtable->cq_completion_type; +} + +int grpc_get_cq_poll_num(grpc_completion_queue *cq) { + int cur_num_polls; + gpr_mu_lock(cq->mu); + cur_num_polls = cq->num_polls; + gpr_mu_unlock(cq->mu); + return cur_num_polls; +} + +#ifndef NDEBUG +void grpc_cq_internal_ref(grpc_completion_queue *cq, const char *reason, const char *file, int line) { - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "CQ:%p ref %d -> %d %s", cc, - (int)cc->owning_refs.count, (int)cc->owning_refs.count + 1, reason); + if (GRPC_TRACER_ON(grpc_trace_cq_refcount)) { + gpr_atm val = gpr_atm_no_barrier_load(&cq->owning_refs.count); + gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, + "CQ:%p ref %" PRIdPTR " -> %" PRIdPTR " %s", cq, val, val + 1, + reason); + } #else -void grpc_cq_internal_ref(grpc_completion_queue *cc) { +void grpc_cq_internal_ref(grpc_completion_queue *cq) { #endif - gpr_ref(&cc->owning_refs); + gpr_ref(&cq->owning_refs); } static void on_pollset_shutdown_done(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { - grpc_completion_queue *cc = arg; - GRPC_CQ_INTERNAL_UNREF(cc, "pollset_destroy"); + grpc_completion_queue *cq = arg; + GRPC_CQ_INTERNAL_UNREF(exec_ctx, cq, "pollset_destroy"); } -#ifdef GRPC_CQ_REF_COUNT_DEBUG -void grpc_cq_internal_unref(grpc_completion_queue *cc, const char *reason, - const char *file, int line) { - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "CQ:%p unref %d -> %d %s", cc, - (int)cc->owning_refs.count, (int)cc->owning_refs.count - 1, reason); +#ifndef NDEBUG +void grpc_cq_internal_unref(grpc_exec_ctx *exec_ctx, grpc_completion_queue *cq, + const char *reason, const char *file, int line) { + if (GRPC_TRACER_ON(grpc_trace_cq_refcount)) { + gpr_atm val = gpr_atm_no_barrier_load(&cq->owning_refs.count); + gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, + "CQ:%p unref %" PRIdPTR " -> %" PRIdPTR " %s", cq, val, val - 1, + reason); + } #else -void grpc_cq_internal_unref(grpc_completion_queue *cc) { +void grpc_cq_internal_unref(grpc_exec_ctx *exec_ctx, + grpc_completion_queue *cq) { +#endif + if (gpr_unref(&cq->owning_refs)) { + cq->vtable->destroy(DATA_FROM_CQ(cq)); + cq->poller_vtable->destroy(exec_ctx, POLLSET_FROM_CQ(cq)); +#ifndef NDEBUG + gpr_free(cq->outstanding_tags); #endif - if (gpr_unref(&cc->owning_refs)) { - GPR_ASSERT(cc->completed_head.next == (uintptr_t)&cc->completed_head); - grpc_pollset_reset(POLLSET_FROM_CQ(cc)); - gpr_mu_lock(&g_freelist_mu); - cc->next_free = g_freelist; - g_freelist = cc; - gpr_mu_unlock(&g_freelist_mu); + gpr_free(cq); } } -void grpc_cq_begin_op(grpc_completion_queue *cc, void *tag) { #ifndef NDEBUG - gpr_mu_lock(cc->mu); - GPR_ASSERT(!cc->shutdown_called); - if (cc->outstanding_tag_count == cc->outstanding_tag_capacity) { - cc->outstanding_tag_capacity = GPR_MAX(4, 2 * cc->outstanding_tag_capacity); - cc->outstanding_tags = - gpr_realloc(cc->outstanding_tags, sizeof(*cc->outstanding_tags) * - cc->outstanding_tag_capacity); - } - cc->outstanding_tags[cc->outstanding_tag_count++] = tag; - gpr_mu_unlock(cc->mu); +static void cq_check_tag(grpc_completion_queue *cq, void *tag, bool lock_cq) { + int found = 0; + if (lock_cq) { + gpr_mu_lock(cq->mu); + } + + for (int i = 0; i < (int)cq->outstanding_tag_count; i++) { + if (cq->outstanding_tags[i] == tag) { + cq->outstanding_tag_count--; + GPR_SWAP(void *, cq->outstanding_tags[i], + cq->outstanding_tags[cq->outstanding_tag_count]); + found = 1; + break; + } + } + + if (lock_cq) { + gpr_mu_unlock(cq->mu); + } + + GPR_ASSERT(found); +} +#else +static void cq_check_tag(grpc_completion_queue *cq, void *tag, bool lock_cq) {} #endif - gpr_ref(&cc->pending_events); + +/* Atomically increments a counter only if the counter is not zero. Returns + * true if the increment was successful; false if the counter is zero */ +static bool atm_inc_if_nonzero(gpr_atm *counter) { + while (true) { + gpr_atm count = gpr_atm_no_barrier_load(counter); + /* If zero, we are done. If not, we must to a CAS (instead of an atomic + * increment) to maintain the contract: do not increment the counter if it + * is zero. */ + if (count == 0) { + return false; + } else if (gpr_atm_no_barrier_cas(counter, count, count + 1)) { + break; + } + } + + return true; } -/* Signal the end of an operation - if this is the last waiting-to-be-queued - event, then enter shutdown mode */ -/* Queue a GRPC_OP_COMPLETED operation */ -void grpc_cq_end_op(grpc_exec_ctx *exec_ctx, grpc_completion_queue *cc, - void *tag, grpc_error *error, - void (*done)(grpc_exec_ctx *exec_ctx, void *done_arg, - grpc_cq_completion *storage), - void *done_arg, grpc_cq_completion *storage) { - int shutdown; - int i; - grpc_pollset_worker *pluck_worker; +static bool cq_begin_op_for_next(grpc_completion_queue *cq, void *tag) { + cq_next_data *cqd = DATA_FROM_CQ(cq); + return atm_inc_if_nonzero(&cqd->pending_events); +} + +static bool cq_begin_op_for_pluck(grpc_completion_queue *cq, void *tag) { + cq_pluck_data *cqd = DATA_FROM_CQ(cq); + return atm_inc_if_nonzero(&cqd->pending_events); +} + +bool grpc_cq_begin_op(grpc_completion_queue *cq, void *tag) { #ifndef NDEBUG - int found = 0; + gpr_mu_lock(cq->mu); + if (cq->outstanding_tag_count == cq->outstanding_tag_capacity) { + cq->outstanding_tag_capacity = GPR_MAX(4, 2 * cq->outstanding_tag_capacity); + cq->outstanding_tags = + gpr_realloc(cq->outstanding_tags, sizeof(*cq->outstanding_tags) * + cq->outstanding_tag_capacity); + } + cq->outstanding_tags[cq->outstanding_tag_count++] = tag; + gpr_mu_unlock(cq->mu); #endif + return cq->vtable->begin_op(cq, tag); +} - GPR_TIMER_BEGIN("grpc_cq_end_op", 0); - if (grpc_api_trace || - (grpc_trace_operation_failures && error != GRPC_ERROR_NONE)) { +/* Queue a GRPC_OP_COMPLETED operation to a completion queue (with a + * completion + * type of GRPC_CQ_NEXT) */ +static void cq_end_op_for_next(grpc_exec_ctx *exec_ctx, + grpc_completion_queue *cq, void *tag, + grpc_error *error, + void (*done)(grpc_exec_ctx *exec_ctx, + void *done_arg, + grpc_cq_completion *storage), + void *done_arg, grpc_cq_completion *storage) { + GPR_TIMER_BEGIN("cq_end_op_for_next", 0); + + if (GRPC_TRACER_ON(grpc_api_trace) || + (GRPC_TRACER_ON(grpc_trace_operation_failures) && + error != GRPC_ERROR_NONE)) { const char *errmsg = grpc_error_string(error); GRPC_API_TRACE( - "grpc_cq_end_op(exec_ctx=%p, cc=%p, tag=%p, error=%s, done=%p, " - "done_arg=%p, storage=%p)", - 7, (exec_ctx, cc, tag, errmsg, done, done_arg, storage)); - if (grpc_trace_operation_failures && error != GRPC_ERROR_NONE) { + "cq_end_op_for_next(exec_ctx=%p, cq=%p, tag=%p, error=%s, " + "done=%p, done_arg=%p, storage=%p)", + 7, (exec_ctx, cq, tag, errmsg, done, done_arg, storage)); + if (GRPC_TRACER_ON(grpc_trace_operation_failures) && + error != GRPC_ERROR_NONE) { gpr_log(GPR_ERROR, "Operation failed: tag=%p, error=%s", tag, errmsg); } - grpc_error_free_string(errmsg); } + cq_next_data *cqd = DATA_FROM_CQ(cq); + int is_success = (error == GRPC_ERROR_NONE); + storage->tag = tag; storage->done = done; storage->done_arg = done_arg; - storage->next = ((uintptr_t)&cc->completed_head) | - ((uintptr_t)(error == GRPC_ERROR_NONE)); + storage->next = (uintptr_t)(is_success); + + cq_check_tag(cq, tag, true); /* Used in debug builds only */ + + /* Add the completion to the queue */ + bool is_first = cq_event_queue_push(&cqd->queue, storage); + gpr_atm_no_barrier_fetch_add(&cqd->things_queued_ever, 1); + bool will_definitely_shutdown = + gpr_atm_no_barrier_load(&cqd->pending_events) == 1; + + if (!will_definitely_shutdown) { + /* Only kick if this is the first item queued */ + if (is_first) { + gpr_mu_lock(cq->mu); + grpc_error *kick_error = + cq->poller_vtable->kick(POLLSET_FROM_CQ(cq), NULL); + gpr_mu_unlock(cq->mu); - gpr_mu_lock(cc->mu); -#ifndef NDEBUG - for (i = 0; i < (int)cc->outstanding_tag_count; i++) { - if (cc->outstanding_tags[i] == tag) { - cc->outstanding_tag_count--; - GPR_SWAP(void *, cc->outstanding_tags[i], - cc->outstanding_tags[cc->outstanding_tag_count]); - found = 1; - break; + if (kick_error != GRPC_ERROR_NONE) { + const char *msg = grpc_error_string(kick_error); + gpr_log(GPR_ERROR, "Kick failed: %s", msg); + GRPC_ERROR_UNREF(kick_error); + } + } + if (gpr_atm_full_fetch_add(&cqd->pending_events, -1) == 1) { + GRPC_CQ_INTERNAL_REF(cq, "shutting_down"); + gpr_mu_lock(cq->mu); + cq_finish_shutdown_next(exec_ctx, cq); + gpr_mu_unlock(cq->mu); + GRPC_CQ_INTERNAL_UNREF(exec_ctx, cq, "shutting_down"); } + } else { + GRPC_CQ_INTERNAL_REF(cq, "shutting_down"); + gpr_atm_rel_store(&cqd->pending_events, 0); + gpr_mu_lock(cq->mu); + cq_finish_shutdown_next(exec_ctx, cq); + gpr_mu_unlock(cq->mu); + GRPC_CQ_INTERNAL_UNREF(exec_ctx, cq, "shutting_down"); } - GPR_ASSERT(found); -#endif - shutdown = gpr_unref(&cc->pending_events); - gpr_atm_no_barrier_fetch_add(&cc->things_queued_ever, 1); - if (!shutdown) { - cc->completed_tail->next = - ((uintptr_t)storage) | (1u & (uintptr_t)cc->completed_tail->next); - cc->completed_tail = storage; - pluck_worker = NULL; - for (i = 0; i < cc->num_pluckers; i++) { - if (cc->pluckers[i].tag == tag) { - pluck_worker = *cc->pluckers[i].worker; + + GPR_TIMER_END("cq_end_op_for_next", 0); + + GRPC_ERROR_UNREF(error); +} + +/* Queue a GRPC_OP_COMPLETED operation to a completion queue (with a + * completion + * type of GRPC_CQ_PLUCK) */ +static void cq_end_op_for_pluck(grpc_exec_ctx *exec_ctx, + grpc_completion_queue *cq, void *tag, + grpc_error *error, + void (*done)(grpc_exec_ctx *exec_ctx, + void *done_arg, + grpc_cq_completion *storage), + void *done_arg, grpc_cq_completion *storage) { + cq_pluck_data *cqd = DATA_FROM_CQ(cq); + int is_success = (error == GRPC_ERROR_NONE); + + GPR_TIMER_BEGIN("cq_end_op_for_pluck", 0); + + if (GRPC_TRACER_ON(grpc_api_trace) || + (GRPC_TRACER_ON(grpc_trace_operation_failures) && + error != GRPC_ERROR_NONE)) { + const char *errmsg = grpc_error_string(error); + GRPC_API_TRACE( + "cq_end_op_for_pluck(exec_ctx=%p, cq=%p, tag=%p, error=%s, " + "done=%p, done_arg=%p, storage=%p)", + 7, (exec_ctx, cq, tag, errmsg, done, done_arg, storage)); + if (GRPC_TRACER_ON(grpc_trace_operation_failures) && + error != GRPC_ERROR_NONE) { + gpr_log(GPR_ERROR, "Operation failed: tag=%p, error=%s", tag, errmsg); + } + } + + storage->tag = tag; + storage->done = done; + storage->done_arg = done_arg; + storage->next = ((uintptr_t)&cqd->completed_head) | ((uintptr_t)(is_success)); + + gpr_mu_lock(cq->mu); + cq_check_tag(cq, tag, false); /* Used in debug builds only */ + + /* Add to the list of completions */ + gpr_atm_no_barrier_fetch_add(&cqd->things_queued_ever, 1); + cqd->completed_tail->next = + ((uintptr_t)storage) | (1u & (uintptr_t)cqd->completed_tail->next); + cqd->completed_tail = storage; + + if (gpr_atm_full_fetch_add(&cqd->pending_events, -1) == 1) { + cq_finish_shutdown_pluck(exec_ctx, cq); + gpr_mu_unlock(cq->mu); + } else { + grpc_pollset_worker *pluck_worker = NULL; + for (int i = 0; i < cqd->num_pluckers; i++) { + if (cqd->pluckers[i].tag == tag) { + pluck_worker = *cqd->pluckers[i].worker; break; } } + grpc_error *kick_error = - grpc_pollset_kick(POLLSET_FROM_CQ(cc), pluck_worker); - gpr_mu_unlock(cc->mu); + cq->poller_vtable->kick(POLLSET_FROM_CQ(cq), pluck_worker); + + gpr_mu_unlock(cq->mu); + if (kick_error != GRPC_ERROR_NONE) { const char *msg = grpc_error_string(kick_error); gpr_log(GPR_ERROR, "Kick failed: %s", msg); - grpc_error_free_string(msg); + GRPC_ERROR_UNREF(kick_error); } - } else { - cc->completed_tail->next = - ((uintptr_t)storage) | (1u & (uintptr_t)cc->completed_tail->next); - cc->completed_tail = storage; - GPR_ASSERT(!cc->shutdown); - GPR_ASSERT(cc->shutdown_called); - cc->shutdown = 1; - grpc_pollset_shutdown(exec_ctx, POLLSET_FROM_CQ(cc), - &cc->pollset_shutdown_done); - gpr_mu_unlock(cc->mu); } - GPR_TIMER_END("grpc_cq_end_op", 0); + GPR_TIMER_END("cq_end_op_for_pluck", 0); GRPC_ERROR_UNREF(error); } +void grpc_cq_end_op(grpc_exec_ctx *exec_ctx, grpc_completion_queue *cq, + void *tag, grpc_error *error, + void (*done)(grpc_exec_ctx *exec_ctx, void *done_arg, + grpc_cq_completion *storage), + void *done_arg, grpc_cq_completion *storage) { + cq->vtable->end_op(exec_ctx, cq, tag, error, done, done_arg, storage); +} + typedef struct { gpr_atm last_seen_things_queued_ever; grpc_completion_queue *cq; @@ -325,88 +768,92 @@ typedef struct { static bool cq_is_next_finished(grpc_exec_ctx *exec_ctx, void *arg) { cq_is_finished_arg *a = arg; grpc_completion_queue *cq = a->cq; + cq_next_data *cqd = DATA_FROM_CQ(cq); GPR_ASSERT(a->stolen_completion == NULL); + gpr_atm current_last_seen_things_queued_ever = - gpr_atm_no_barrier_load(&cq->things_queued_ever); + gpr_atm_no_barrier_load(&cqd->things_queued_ever); + if (current_last_seen_things_queued_ever != a->last_seen_things_queued_ever) { - gpr_mu_lock(cq->mu); a->last_seen_things_queued_ever = - gpr_atm_no_barrier_load(&cq->things_queued_ever); - if (cq->completed_tail != &cq->completed_head) { - a->stolen_completion = (grpc_cq_completion *)cq->completed_head.next; - cq->completed_head.next = a->stolen_completion->next & ~(uintptr_t)1; - if (a->stolen_completion == cq->completed_tail) { - cq->completed_tail = &cq->completed_head; - } - gpr_mu_unlock(cq->mu); + gpr_atm_no_barrier_load(&cqd->things_queued_ever); + + /* Pop a cq_completion from the queue. Returns NULL if the queue is empty + * might return NULL in some cases even if the queue is not empty; but + * that + * is ok and doesn't affect correctness. Might effect the tail latencies a + * bit) */ + a->stolen_completion = cq_event_queue_pop(&cqd->queue); + if (a->stolen_completion != NULL) { return true; } - gpr_mu_unlock(cq->mu); } return !a->first_loop && gpr_time_cmp(a->deadline, gpr_now(a->deadline.clock_type)) < 0; } #ifndef NDEBUG -static void dump_pending_tags(grpc_completion_queue *cc) { - if (!grpc_trace_pending_tags) return; +static void dump_pending_tags(grpc_completion_queue *cq) { + if (!GRPC_TRACER_ON(grpc_trace_pending_tags)) return; gpr_strvec v; gpr_strvec_init(&v); gpr_strvec_add(&v, gpr_strdup("PENDING TAGS:")); - gpr_mu_lock(cc->mu); - for (size_t i = 0; i < cc->outstanding_tag_count; i++) { + gpr_mu_lock(cq->mu); + for (size_t i = 0; i < cq->outstanding_tag_count; i++) { char *s; - gpr_asprintf(&s, " %p", cc->outstanding_tags[i]); + gpr_asprintf(&s, " %p", cq->outstanding_tags[i]); gpr_strvec_add(&v, s); } - gpr_mu_unlock(cc->mu); + gpr_mu_unlock(cq->mu); char *out = gpr_strvec_flatten(&v, NULL); gpr_strvec_destroy(&v); gpr_log(GPR_DEBUG, "%s", out); gpr_free(out); } #else -static void dump_pending_tags(grpc_completion_queue *cc) {} +static void dump_pending_tags(grpc_completion_queue *cq) {} #endif -grpc_event grpc_completion_queue_next(grpc_completion_queue *cc, - gpr_timespec deadline, void *reserved) { +static grpc_event cq_next(grpc_completion_queue *cq, gpr_timespec deadline, + void *reserved) { grpc_event ret; - grpc_pollset_worker *worker = NULL; gpr_timespec now; + cq_next_data *cqd = DATA_FROM_CQ(cq); GPR_TIMER_BEGIN("grpc_completion_queue_next", 0); GRPC_API_TRACE( "grpc_completion_queue_next(" - "cc=%p, " + "cq=%p, " "deadline=gpr_timespec { tv_sec: %" PRId64 ", tv_nsec: %d, clock_type: %d }, " "reserved=%p)", - 5, (cc, deadline.tv_sec, deadline.tv_nsec, (int)deadline.clock_type, + 5, (cq, deadline.tv_sec, deadline.tv_nsec, (int)deadline.clock_type, reserved)); GPR_ASSERT(!reserved); - dump_pending_tags(cc); + dump_pending_tags(cq); deadline = gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC); - GRPC_CQ_INTERNAL_REF(cc, "next"); - gpr_mu_lock(cc->mu); + GRPC_CQ_INTERNAL_REF(cq, "next"); + cq_is_finished_arg is_finished_arg = { .last_seen_things_queued_ever = - gpr_atm_no_barrier_load(&cc->things_queued_ever), - .cq = cc, + gpr_atm_no_barrier_load(&cqd->things_queued_ever), + .cq = cq, .deadline = deadline, .stolen_completion = NULL, .tag = NULL, .first_loop = true}; - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT_WITH_FINISH_CHECK( - cq_is_next_finished, &is_finished_arg); + grpc_exec_ctx exec_ctx = + GRPC_EXEC_CTX_INITIALIZER(0, cq_is_next_finished, &is_finished_arg); + for (;;) { + gpr_timespec iteration_deadline = deadline; + if (is_finished_arg.stolen_completion != NULL) { - gpr_mu_unlock(cc->mu); grpc_cq_completion *c = is_finished_arg.stolen_completion; is_finished_arg.stolen_completion = NULL; ret.type = GRPC_OP_COMPLETE; @@ -415,63 +862,80 @@ grpc_event grpc_completion_queue_next(grpc_completion_queue *cc, c->done(&exec_ctx, c->done_arg, c); break; } - if (cc->completed_tail != &cc->completed_head) { - grpc_cq_completion *c = (grpc_cq_completion *)cc->completed_head.next; - cc->completed_head.next = c->next & ~(uintptr_t)1; - if (c == cc->completed_tail) { - cc->completed_tail = &cc->completed_head; - } - gpr_mu_unlock(cc->mu); + + grpc_cq_completion *c = cq_event_queue_pop(&cqd->queue); + + if (c != NULL) { ret.type = GRPC_OP_COMPLETE; ret.success = c->next & 1u; ret.tag = c->tag; c->done(&exec_ctx, c->done_arg, c); break; + } else { + /* If c == NULL it means either the queue is empty OR in an transient + inconsistent state. If it is the latter, we shold do a 0-timeout poll + so that the thread comes back quickly from poll to make a second + attempt at popping. Not doing this can potentially deadlock this + thread forever (if the deadline is infinity) */ + if (cq_event_queue_num_items(&cqd->queue) > 0) { + iteration_deadline = gpr_time_0(GPR_CLOCK_MONOTONIC); + } } - if (cc->shutdown) { - gpr_mu_unlock(cc->mu); + + if (gpr_atm_no_barrier_load(&cqd->pending_events) == 0) { + /* Before returning, check if the queue has any items left over (since + gpr_mpscq_pop() can sometimes return NULL even if the queue is not + empty. If so, keep retrying but do not return GRPC_QUEUE_SHUTDOWN */ + if (cq_event_queue_num_items(&cqd->queue) > 0) { + /* Go to the beginning of the loop. No point doing a poll because + (cq->shutdown == true) is only possible when there is no pending + work (i.e cq->pending_events == 0) and any outstanding completion + events should have already been queued on this cq */ + continue; + } + memset(&ret, 0, sizeof(ret)); ret.type = GRPC_QUEUE_SHUTDOWN; break; } + now = gpr_now(GPR_CLOCK_MONOTONIC); if (!is_finished_arg.first_loop && gpr_time_cmp(now, deadline) >= 0) { - gpr_mu_unlock(cc->mu); memset(&ret, 0, sizeof(ret)); ret.type = GRPC_QUEUE_TIMEOUT; - dump_pending_tags(cc); + dump_pending_tags(cq); break; } - /* Check alarms - these are a global resource so we just ping - each time through on every pollset. - May update deadline to ensure timely wakeups. - TODO(ctiller): can this work be localized? */ - gpr_timespec iteration_deadline = deadline; - if (grpc_timer_check(&exec_ctx, now, &iteration_deadline)) { - GPR_TIMER_MARK("alarm_triggered", 0); - gpr_mu_unlock(cc->mu); - grpc_exec_ctx_flush(&exec_ctx); - gpr_mu_lock(cc->mu); - continue; - } else { - grpc_error *err = grpc_pollset_work(&exec_ctx, POLLSET_FROM_CQ(cc), - &worker, now, iteration_deadline); - if (err != GRPC_ERROR_NONE) { - gpr_mu_unlock(cc->mu); - const char *msg = grpc_error_string(err); - gpr_log(GPR_ERROR, "Completion queue next failed: %s", msg); - grpc_error_free_string(msg); - GRPC_ERROR_UNREF(err); - memset(&ret, 0, sizeof(ret)); - ret.type = GRPC_QUEUE_TIMEOUT; - dump_pending_tags(cc); - break; - } + + /* The main polling work happens in grpc_pollset_work */ + gpr_mu_lock(cq->mu); + cq->num_polls++; + grpc_error *err = cq->poller_vtable->work(&exec_ctx, POLLSET_FROM_CQ(cq), + NULL, now, iteration_deadline); + gpr_mu_unlock(cq->mu); + + if (err != GRPC_ERROR_NONE) { + const char *msg = grpc_error_string(err); + gpr_log(GPR_ERROR, "Completion queue next failed: %s", msg); + + GRPC_ERROR_UNREF(err); + memset(&ret, 0, sizeof(ret)); + ret.type = GRPC_QUEUE_TIMEOUT; + dump_pending_tags(cq); + break; } is_finished_arg.first_loop = false; } - GRPC_SURFACE_TRACE_RETURNED_EVENT(cc, &ret); - GRPC_CQ_INTERNAL_UNREF(cc, "next"); + + if (cq_event_queue_num_items(&cqd->queue) > 0 && + gpr_atm_no_barrier_load(&cqd->pending_events) > 0) { + gpr_mu_lock(cq->mu); + cq->poller_vtable->kick(POLLSET_FROM_CQ(cq), NULL); + gpr_mu_unlock(cq->mu); + } + + GRPC_SURFACE_TRACE_RETURNED_EVENT(cq, &ret); + GRPC_CQ_INTERNAL_UNREF(&exec_ctx, cq, "next"); grpc_exec_ctx_finish(&exec_ctx); GPR_ASSERT(is_finished_arg.stolen_completion == NULL); @@ -480,24 +944,73 @@ grpc_event grpc_completion_queue_next(grpc_completion_queue *cc, return ret; } -static int add_plucker(grpc_completion_queue *cc, void *tag, +/* Finishes the completion queue shutdown. This means that there are no more + completion events / tags expected from the completion queue + - Must be called under completion queue lock + - Must be called only once in completion queue's lifetime + - grpc_completion_queue_shutdown() MUST have been called before calling + this function */ +static void cq_finish_shutdown_next(grpc_exec_ctx *exec_ctx, + grpc_completion_queue *cq) { + cq_next_data *cqd = DATA_FROM_CQ(cq); + + GPR_ASSERT(cqd->shutdown_called); + GPR_ASSERT(gpr_atm_no_barrier_load(&cqd->pending_events) == 0); + + cq->poller_vtable->shutdown(exec_ctx, POLLSET_FROM_CQ(cq), + &cq->pollset_shutdown_done); +} + +static void cq_shutdown_next(grpc_exec_ctx *exec_ctx, + grpc_completion_queue *cq) { + cq_next_data *cqd = DATA_FROM_CQ(cq); + + /* Need an extra ref for cq here because: + * We call cq_finish_shutdown_next() below, that would call pollset shutdown. + * Pollset shutdown decrements the cq ref count which can potentially destroy + * the cq (if that happens to be the last ref). + * Creating an extra ref here prevents the cq from getting destroyed while + * this function is still active */ + GRPC_CQ_INTERNAL_REF(cq, "shutting_down"); + gpr_mu_lock(cq->mu); + if (cqd->shutdown_called) { + gpr_mu_unlock(cq->mu); + GRPC_CQ_INTERNAL_UNREF(exec_ctx, cq, "shutting_down"); + GPR_TIMER_END("grpc_completion_queue_shutdown", 0); + return; + } + cqd->shutdown_called = true; + if (gpr_atm_full_fetch_add(&cqd->pending_events, -1) == 1) { + cq_finish_shutdown_next(exec_ctx, cq); + } + gpr_mu_unlock(cq->mu); + GRPC_CQ_INTERNAL_UNREF(exec_ctx, cq, "shutting_down"); +} + +grpc_event grpc_completion_queue_next(grpc_completion_queue *cq, + gpr_timespec deadline, void *reserved) { + return cq->vtable->next(cq, deadline, reserved); +} + +static int add_plucker(grpc_completion_queue *cq, void *tag, grpc_pollset_worker **worker) { - if (cc->num_pluckers == GRPC_MAX_COMPLETION_QUEUE_PLUCKERS) { + cq_pluck_data *cqd = DATA_FROM_CQ(cq); + if (cqd->num_pluckers == GRPC_MAX_COMPLETION_QUEUE_PLUCKERS) { return 0; } - cc->pluckers[cc->num_pluckers].tag = tag; - cc->pluckers[cc->num_pluckers].worker = worker; - cc->num_pluckers++; + cqd->pluckers[cqd->num_pluckers].tag = tag; + cqd->pluckers[cqd->num_pluckers].worker = worker; + cqd->num_pluckers++; return 1; } -static void del_plucker(grpc_completion_queue *cc, void *tag, +static void del_plucker(grpc_completion_queue *cq, void *tag, grpc_pollset_worker **worker) { - int i; - for (i = 0; i < cc->num_pluckers; i++) { - if (cc->pluckers[i].tag == tag && cc->pluckers[i].worker == worker) { - cc->num_pluckers--; - GPR_SWAP(plucker, cc->pluckers[i], cc->pluckers[cc->num_pluckers]); + cq_pluck_data *cqd = DATA_FROM_CQ(cq); + for (int i = 0; i < cqd->num_pluckers; i++) { + if (cqd->pluckers[i].tag == tag && cqd->pluckers[i].worker == worker) { + cqd->num_pluckers--; + GPR_SWAP(plucker, cqd->pluckers[i], cqd->pluckers[cqd->num_pluckers]); return; } } @@ -507,21 +1020,23 @@ static void del_plucker(grpc_completion_queue *cc, void *tag, static bool cq_is_pluck_finished(grpc_exec_ctx *exec_ctx, void *arg) { cq_is_finished_arg *a = arg; grpc_completion_queue *cq = a->cq; + cq_pluck_data *cqd = DATA_FROM_CQ(cq); + GPR_ASSERT(a->stolen_completion == NULL); gpr_atm current_last_seen_things_queued_ever = - gpr_atm_no_barrier_load(&cq->things_queued_ever); + gpr_atm_no_barrier_load(&cqd->things_queued_ever); if (current_last_seen_things_queued_ever != a->last_seen_things_queued_ever) { gpr_mu_lock(cq->mu); a->last_seen_things_queued_ever = - gpr_atm_no_barrier_load(&cq->things_queued_ever); + gpr_atm_no_barrier_load(&cqd->things_queued_ever); grpc_cq_completion *c; - grpc_cq_completion *prev = &cq->completed_head; + grpc_cq_completion *prev = &cqd->completed_head; while ((c = (grpc_cq_completion *)(prev->next & ~(uintptr_t)1)) != - &cq->completed_head) { + &cqd->completed_head) { if (c->tag == a->tag) { prev->next = (prev->next & (uintptr_t)1) | (c->next & ~(uintptr_t)1); - if (c == cq->completed_tail) { - cq->completed_tail = prev; + if (c == cqd->completed_tail) { + cqd->completed_tail = prev; } gpr_mu_unlock(cq->mu); a->stolen_completion = c; @@ -535,47 +1050,48 @@ static bool cq_is_pluck_finished(grpc_exec_ctx *exec_ctx, void *arg) { gpr_time_cmp(a->deadline, gpr_now(a->deadline.clock_type)) < 0; } -grpc_event grpc_completion_queue_pluck(grpc_completion_queue *cc, void *tag, - gpr_timespec deadline, void *reserved) { +static grpc_event cq_pluck(grpc_completion_queue *cq, void *tag, + gpr_timespec deadline, void *reserved) { grpc_event ret; grpc_cq_completion *c; grpc_cq_completion *prev; grpc_pollset_worker *worker = NULL; gpr_timespec now; + cq_pluck_data *cqd = DATA_FROM_CQ(cq); GPR_TIMER_BEGIN("grpc_completion_queue_pluck", 0); - if (grpc_cq_pluck_trace) { + if (GRPC_TRACER_ON(grpc_cq_pluck_trace)) { GRPC_API_TRACE( "grpc_completion_queue_pluck(" - "cc=%p, tag=%p, " + "cq=%p, tag=%p, " "deadline=gpr_timespec { tv_sec: %" PRId64 ", tv_nsec: %d, clock_type: %d }, " "reserved=%p)", - 6, (cc, tag, deadline.tv_sec, deadline.tv_nsec, + 6, (cq, tag, deadline.tv_sec, deadline.tv_nsec, (int)deadline.clock_type, reserved)); } GPR_ASSERT(!reserved); - dump_pending_tags(cc); + dump_pending_tags(cq); deadline = gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC); - GRPC_CQ_INTERNAL_REF(cc, "pluck"); - gpr_mu_lock(cc->mu); + GRPC_CQ_INTERNAL_REF(cq, "pluck"); + gpr_mu_lock(cq->mu); cq_is_finished_arg is_finished_arg = { .last_seen_things_queued_ever = - gpr_atm_no_barrier_load(&cc->things_queued_ever), - .cq = cc, + gpr_atm_no_barrier_load(&cqd->things_queued_ever), + .cq = cq, .deadline = deadline, .stolen_completion = NULL, .tag = tag, .first_loop = true}; - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT_WITH_FINISH_CHECK( - cq_is_pluck_finished, &is_finished_arg); + grpc_exec_ctx exec_ctx = + GRPC_EXEC_CTX_INITIALIZER(0, cq_is_pluck_finished, &is_finished_arg); for (;;) { if (is_finished_arg.stolen_completion != NULL) { - gpr_mu_unlock(cc->mu); + gpr_mu_unlock(cq->mu); c = is_finished_arg.stolen_completion; is_finished_arg.stolen_completion = NULL; ret.type = GRPC_OP_COMPLETE; @@ -584,15 +1100,15 @@ grpc_event grpc_completion_queue_pluck(grpc_completion_queue *cc, void *tag, c->done(&exec_ctx, c->done_arg, c); break; } - prev = &cc->completed_head; + prev = &cqd->completed_head; while ((c = (grpc_cq_completion *)(prev->next & ~(uintptr_t)1)) != - &cc->completed_head) { + &cqd->completed_head) { if (c->tag == tag) { prev->next = (prev->next & (uintptr_t)1) | (c->next & ~(uintptr_t)1); - if (c == cc->completed_tail) { - cc->completed_tail = prev; + if (c == cqd->completed_tail) { + cqd->completed_tail = prev; } - gpr_mu_unlock(cc->mu); + gpr_mu_unlock(cq->mu); ret.type = GRPC_OP_COMPLETE; ret.success = c->next & 1u; ret.tag = c->tag; @@ -601,65 +1117,55 @@ grpc_event grpc_completion_queue_pluck(grpc_completion_queue *cc, void *tag, } prev = c; } - if (cc->shutdown) { - gpr_mu_unlock(cc->mu); + if (gpr_atm_no_barrier_load(&cqd->shutdown)) { + gpr_mu_unlock(cq->mu); memset(&ret, 0, sizeof(ret)); ret.type = GRPC_QUEUE_SHUTDOWN; break; } - if (!add_plucker(cc, tag, &worker)) { + if (!add_plucker(cq, tag, &worker)) { gpr_log(GPR_DEBUG, "Too many outstanding grpc_completion_queue_pluck calls: maximum " "is %d", GRPC_MAX_COMPLETION_QUEUE_PLUCKERS); - gpr_mu_unlock(cc->mu); + gpr_mu_unlock(cq->mu); memset(&ret, 0, sizeof(ret)); /* TODO(ctiller): should we use a different result here */ ret.type = GRPC_QUEUE_TIMEOUT; - dump_pending_tags(cc); + dump_pending_tags(cq); break; } now = gpr_now(GPR_CLOCK_MONOTONIC); if (!is_finished_arg.first_loop && gpr_time_cmp(now, deadline) >= 0) { - del_plucker(cc, tag, &worker); - gpr_mu_unlock(cc->mu); + del_plucker(cq, tag, &worker); + gpr_mu_unlock(cq->mu); memset(&ret, 0, sizeof(ret)); ret.type = GRPC_QUEUE_TIMEOUT; - dump_pending_tags(cc); + dump_pending_tags(cq); break; } - /* Check alarms - these are a global resource so we just ping - each time through on every pollset. - May update deadline to ensure timely wakeups. - TODO(ctiller): can this work be localized? */ - gpr_timespec iteration_deadline = deadline; - if (grpc_timer_check(&exec_ctx, now, &iteration_deadline)) { - GPR_TIMER_MARK("alarm_triggered", 0); - gpr_mu_unlock(cc->mu); - grpc_exec_ctx_flush(&exec_ctx); - gpr_mu_lock(cc->mu); - } else { - grpc_error *err = grpc_pollset_work(&exec_ctx, POLLSET_FROM_CQ(cc), - &worker, now, iteration_deadline); - if (err != GRPC_ERROR_NONE) { - del_plucker(cc, tag, &worker); - gpr_mu_unlock(cc->mu); - const char *msg = grpc_error_string(err); - gpr_log(GPR_ERROR, "Completion queue next failed: %s", msg); - grpc_error_free_string(msg); - GRPC_ERROR_UNREF(err); - memset(&ret, 0, sizeof(ret)); - ret.type = GRPC_QUEUE_TIMEOUT; - dump_pending_tags(cc); - break; - } + + cq->num_polls++; + grpc_error *err = cq->poller_vtable->work(&exec_ctx, POLLSET_FROM_CQ(cq), + &worker, now, deadline); + if (err != GRPC_ERROR_NONE) { + del_plucker(cq, tag, &worker); + gpr_mu_unlock(cq->mu); + const char *msg = grpc_error_string(err); + gpr_log(GPR_ERROR, "Completion queue pluck failed: %s", msg); + + GRPC_ERROR_UNREF(err); + memset(&ret, 0, sizeof(ret)); + ret.type = GRPC_QUEUE_TIMEOUT; + dump_pending_tags(cq); + break; } is_finished_arg.first_loop = false; - del_plucker(cc, tag, &worker); + del_plucker(cq, tag, &worker); } done: - GRPC_SURFACE_TRACE_RETURNED_EVENT(cc, &ret); - GRPC_CQ_INTERNAL_UNREF(cc, "pluck"); + GRPC_SURFACE_TRACE_RETURNED_EVENT(cq, &ret); + GRPC_CQ_INTERNAL_UNREF(&exec_ctx, cq, "pluck"); grpc_exec_ctx_finish(&exec_ctx); GPR_ASSERT(is_finished_arg.stolen_completion == NULL); @@ -668,54 +1174,77 @@ grpc_event grpc_completion_queue_pluck(grpc_completion_queue *cc, void *tag, return ret; } -/* Shutdown simply drops a ref that we reserved at creation time; if we drop - to zero here, then enter shutdown mode and wake up any waiters */ -void grpc_completion_queue_shutdown(grpc_completion_queue *cc) { - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - GPR_TIMER_BEGIN("grpc_completion_queue_shutdown", 0); - GRPC_API_TRACE("grpc_completion_queue_shutdown(cc=%p)", 1, (cc)); - gpr_mu_lock(cc->mu); - if (cc->shutdown_called) { - gpr_mu_unlock(cc->mu); +grpc_event grpc_completion_queue_pluck(grpc_completion_queue *cq, void *tag, + gpr_timespec deadline, void *reserved) { + return cq->vtable->pluck(cq, tag, deadline, reserved); +} + +static void cq_finish_shutdown_pluck(grpc_exec_ctx *exec_ctx, + grpc_completion_queue *cq) { + cq_pluck_data *cqd = DATA_FROM_CQ(cq); + + GPR_ASSERT(cqd->shutdown_called); + GPR_ASSERT(!gpr_atm_no_barrier_load(&cqd->shutdown)); + gpr_atm_no_barrier_store(&cqd->shutdown, 1); + + cq->poller_vtable->shutdown(exec_ctx, POLLSET_FROM_CQ(cq), + &cq->pollset_shutdown_done); +} + +/* NOTE: This function is almost exactly identical to cq_shutdown_next() but + * merging them is a bit tricky and probably not worth it */ +static void cq_shutdown_pluck(grpc_exec_ctx *exec_ctx, + grpc_completion_queue *cq) { + cq_pluck_data *cqd = DATA_FROM_CQ(cq); + + /* Need an extra ref for cq here because: + * We call cq_finish_shutdown_pluck() below, that would call pollset shutdown. + * Pollset shutdown decrements the cq ref count which can potentially destroy + * the cq (if that happens to be the last ref). + * Creating an extra ref here prevents the cq from getting destroyed while + * this function is still active */ + GRPC_CQ_INTERNAL_REF(cq, "shutting_down (pluck cq)"); + gpr_mu_lock(cq->mu); + if (cqd->shutdown_called) { + gpr_mu_unlock(cq->mu); + GRPC_CQ_INTERNAL_UNREF(exec_ctx, cq, "shutting_down (pluck cq)"); GPR_TIMER_END("grpc_completion_queue_shutdown", 0); return; } - cc->shutdown_called = 1; - if (gpr_unref(&cc->pending_events)) { - GPR_ASSERT(!cc->shutdown); - cc->shutdown = 1; - grpc_pollset_shutdown(&exec_ctx, POLLSET_FROM_CQ(cc), - &cc->pollset_shutdown_done); + cqd->shutdown_called = true; + if (gpr_atm_full_fetch_add(&cqd->pending_events, -1) == 1) { + cq_finish_shutdown_pluck(exec_ctx, cq); } - gpr_mu_unlock(cc->mu); + gpr_mu_unlock(cq->mu); + GRPC_CQ_INTERNAL_UNREF(exec_ctx, cq, "shutting_down (pluck cq)"); +} + +/* Shutdown simply drops a ref that we reserved at creation time; if we drop + to zero here, then enter shutdown mode and wake up any waiters */ +void grpc_completion_queue_shutdown(grpc_completion_queue *cq) { + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + GPR_TIMER_BEGIN("grpc_completion_queue_shutdown", 0); + GRPC_API_TRACE("grpc_completion_queue_shutdown(cq=%p)", 1, (cq)); + cq->vtable->shutdown(&exec_ctx, cq); grpc_exec_ctx_finish(&exec_ctx); GPR_TIMER_END("grpc_completion_queue_shutdown", 0); } -void grpc_completion_queue_destroy(grpc_completion_queue *cc) { - GRPC_API_TRACE("grpc_completion_queue_destroy(cc=%p)", 1, (cc)); +void grpc_completion_queue_destroy(grpc_completion_queue *cq) { + GRPC_API_TRACE("grpc_completion_queue_destroy(cq=%p)", 1, (cq)); GPR_TIMER_BEGIN("grpc_completion_queue_destroy", 0); - grpc_completion_queue_shutdown(cc); - GRPC_CQ_INTERNAL_UNREF(cc, "destroy"); - GPR_TIMER_END("grpc_completion_queue_destroy", 0); -} - -grpc_pollset *grpc_cq_pollset(grpc_completion_queue *cc) { - return POLLSET_FROM_CQ(cc); -} + grpc_completion_queue_shutdown(cq); -grpc_completion_queue *grpc_cq_from_pollset(grpc_pollset *ps) { - return CQ_FROM_POLLSET(ps); + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + GRPC_CQ_INTERNAL_UNREF(&exec_ctx, cq, "destroy"); + grpc_exec_ctx_finish(&exec_ctx); + GPR_TIMER_END("grpc_completion_queue_destroy", 0); } -void grpc_cq_mark_non_listening_server_cq(grpc_completion_queue *cc) { - cc->is_non_listening_server_cq = 1; +grpc_pollset *grpc_cq_pollset(grpc_completion_queue *cq) { + return cq->poller_vtable->can_get_pollset ? POLLSET_FROM_CQ(cq) : NULL; } -bool grpc_cq_is_non_listening_server_cq(grpc_completion_queue *cc) { - return (cc->is_non_listening_server_cq == 1); +bool grpc_cq_can_listen(grpc_completion_queue *cq) { + return cq->poller_vtable->can_listen; } - -void grpc_cq_mark_server_cq(grpc_completion_queue *cc) { cc->is_server_cq = 1; } - -int grpc_cq_is_server_cq(grpc_completion_queue *cc) { return cc->is_server_cq; } diff --git a/Sources/CgRPC/src/core/lib/surface/completion_queue.h b/Sources/CgRPC/src/core/lib/surface/completion_queue.h index c1cafba5f..69d144bd9 100644 --- a/Sources/CgRPC/src/core/lib/surface/completion_queue.h +++ b/Sources/CgRPC/src/core/lib/surface/completion_queue.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015-2016, Google Inc. - * All rights reserved. + * Copyright 2015-2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -37,18 +22,27 @@ /* Internal API for completion queues */ #include +#include "src/core/lib/debug/trace.h" #include "src/core/lib/iomgr/pollset.h" /* These trace flags default to 1. The corresponding lines are only traced if grpc_api_trace is also truthy */ -extern int grpc_cq_pluck_trace; -extern int grpc_cq_event_timeout_trace; -extern int grpc_trace_operation_failures; +extern grpc_tracer_flag grpc_cq_pluck_trace; +extern grpc_tracer_flag grpc_cq_event_timeout_trace; +extern grpc_tracer_flag grpc_trace_operation_failures; + #ifndef NDEBUG -extern int grpc_trace_pending_tags; +extern grpc_tracer_flag grpc_trace_pending_tags; +extern grpc_tracer_flag grpc_trace_cq_refcount; +#endif + +#ifdef __cplusplus +extern "C" { #endif typedef struct grpc_cq_completion { + gpr_mpscq_node node; + /** user supplied tag */ void *tag; /** done callback - called when this queue element is no longer @@ -60,28 +54,27 @@ typedef struct grpc_cq_completion { uintptr_t next; } grpc_cq_completion; -//#define GRPC_CQ_REF_COUNT_DEBUG - -#ifdef GRPC_CQ_REF_COUNT_DEBUG +#ifndef NDEBUG void grpc_cq_internal_ref(grpc_completion_queue *cc, const char *reason, const char *file, int line); -void grpc_cq_internal_unref(grpc_completion_queue *cc, const char *reason, - const char *file, int line); +void grpc_cq_internal_unref(grpc_exec_ctx *exec_ctx, grpc_completion_queue *cc, + const char *reason, const char *file, int line); #define GRPC_CQ_INTERNAL_REF(cc, reason) \ grpc_cq_internal_ref(cc, reason, __FILE__, __LINE__) -#define GRPC_CQ_INTERNAL_UNREF(cc, reason) \ - grpc_cq_internal_unref(cc, reason, __FILE__, __LINE__) +#define GRPC_CQ_INTERNAL_UNREF(ec, cc, reason) \ + grpc_cq_internal_unref(ec, cc, reason, __FILE__, __LINE__) #else void grpc_cq_internal_ref(grpc_completion_queue *cc); -void grpc_cq_internal_unref(grpc_completion_queue *cc); +void grpc_cq_internal_unref(grpc_exec_ctx *exec_ctx, grpc_completion_queue *cc); #define GRPC_CQ_INTERNAL_REF(cc, reason) grpc_cq_internal_ref(cc) -#define GRPC_CQ_INTERNAL_UNREF(cc, reason) grpc_cq_internal_unref(cc) +#define GRPC_CQ_INTERNAL_UNREF(ec, cc, reason) grpc_cq_internal_unref(ec, cc) #endif /* Flag that an operation is beginning: the completion channel will not finish shutdown until a corrensponding grpc_cq_end_* call is made. - \a tag is currently used only in debug builds. */ -void grpc_cq_begin_op(grpc_completion_queue *cc, void *tag); + \a tag is currently used only in debug builds. Return true on success, and + false if completion_queue has been shutdown. */ +bool grpc_cq_begin_op(grpc_completion_queue *cc, void *tag); /* Queue a GRPC_OP_COMPLETED operation; tag must correspond to the tag passed to grpc_cq_begin_op */ @@ -92,14 +85,18 @@ void grpc_cq_end_op(grpc_exec_ctx *exec_ctx, grpc_completion_queue *cc, void *done_arg, grpc_cq_completion *storage); grpc_pollset *grpc_cq_pollset(grpc_completion_queue *cc); -grpc_completion_queue *grpc_cq_from_pollset(grpc_pollset *ps); -void grpc_cq_mark_non_listening_server_cq(grpc_completion_queue *cc); -bool grpc_cq_is_non_listening_server_cq(grpc_completion_queue *cc); -void grpc_cq_mark_server_cq(grpc_completion_queue *cc); -int grpc_cq_is_server_cq(grpc_completion_queue *cc); +bool grpc_cq_can_listen(grpc_completion_queue *cc); + +grpc_cq_completion_type grpc_get_cq_completion_type(grpc_completion_queue *cc); + +int grpc_get_cq_poll_num(grpc_completion_queue *cc); -void grpc_cq_global_init(void); -void grpc_cq_global_shutdown(void); +grpc_completion_queue *grpc_completion_queue_create_internal( + grpc_cq_completion_type completion_type, grpc_cq_polling_type polling_type); + +#ifdef __cplusplus +} +#endif #endif /* GRPC_CORE_LIB_SURFACE_COMPLETION_QUEUE_H */ diff --git a/Sources/CgRPC/src/core/lib/surface/completion_queue_factory.c b/Sources/CgRPC/src/core/lib/surface/completion_queue_factory.c new file mode 100644 index 000000000..aeecff530 --- /dev/null +++ b/Sources/CgRPC/src/core/lib/surface/completion_queue_factory.c @@ -0,0 +1,77 @@ +/* + * + * Copyright 2017 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 "src/core/lib/surface/completion_queue_factory.h" +#include "src/core/lib/surface/completion_queue.h" + +#include + +/* + * == Default completion queue factory implementation == + */ + +static grpc_completion_queue* default_create( + const grpc_completion_queue_factory* factory, + const grpc_completion_queue_attributes* attr) { + return grpc_completion_queue_create_internal(attr->cq_completion_type, + attr->cq_polling_type); +} + +static grpc_completion_queue_factory_vtable default_vtable = {default_create}; + +static const grpc_completion_queue_factory g_default_cq_factory = { + "Default Factory", NULL, &default_vtable}; + +/* + * == Completion queue factory APIs + */ + +const grpc_completion_queue_factory* grpc_completion_queue_factory_lookup( + const grpc_completion_queue_attributes* attributes) { + GPR_ASSERT(attributes->version >= 1 && + attributes->version <= GRPC_CQ_CURRENT_VERSION); + + /* The default factory can handle version 1 of the attributes structure. We + may have to change this as more fields are added to the structure */ + return &g_default_cq_factory; +} + +/* + * == Completion queue creation APIs == + */ + +grpc_completion_queue* grpc_completion_queue_create_for_next(void* reserved) { + GPR_ASSERT(!reserved); + grpc_completion_queue_attributes attr = {1, GRPC_CQ_NEXT, + GRPC_CQ_DEFAULT_POLLING}; + return g_default_cq_factory.vtable->create(&g_default_cq_factory, &attr); +} + +grpc_completion_queue* grpc_completion_queue_create_for_pluck(void* reserved) { + GPR_ASSERT(!reserved); + grpc_completion_queue_attributes attr = {1, GRPC_CQ_PLUCK, + GRPC_CQ_DEFAULT_POLLING}; + return g_default_cq_factory.vtable->create(&g_default_cq_factory, &attr); +} + +grpc_completion_queue* grpc_completion_queue_create( + const grpc_completion_queue_factory* factory, + const grpc_completion_queue_attributes* attr, void* reserved) { + GPR_ASSERT(!reserved); + return factory->vtable->create(factory, attr); +} diff --git a/Sources/CgRPC/src/core/lib/surface/completion_queue_factory.h b/Sources/CgRPC/src/core/lib/surface/completion_queue_factory.h new file mode 100644 index 000000000..89be8f821 --- /dev/null +++ b/Sources/CgRPC/src/core/lib/surface/completion_queue_factory.h @@ -0,0 +1,36 @@ +/* + * + * Copyright 2017 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 GRPC_CORE_LIB_SURFACE_COMPLETION_QUEUE_FACTORY_H +#define GRPC_CORE_LIB_SURFACE_COMPLETION_QUEUE_FACTORY_H + +#include +#include "src/core/lib/surface/completion_queue.h" + +typedef struct grpc_completion_queue_factory_vtable { + grpc_completion_queue* (*create)(const grpc_completion_queue_factory*, + const grpc_completion_queue_attributes*); +} grpc_completion_queue_factory_vtable; + +struct grpc_completion_queue_factory { + const char* name; + void* data; /* Factory specific data */ + grpc_completion_queue_factory_vtable* vtable; +}; + +#endif /* GRPC_CORE_LIB_SURFACE_COMPLETION_QUEUE_FACTORY_H */ diff --git a/Sources/CgRPC/src/core/lib/surface/event_string.c b/Sources/CgRPC/src/core/lib/surface/event_string.c index 1abc6ebf8..f236272e2 100644 --- a/Sources/CgRPC/src/core/lib/surface/event_string.c +++ b/Sources/CgRPC/src/core/lib/surface/event_string.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/surface/event_string.h b/Sources/CgRPC/src/core/lib/surface/event_string.h index bc1464380..f00efca7f 100644 --- a/Sources/CgRPC/src/core/lib/surface/event_string.h +++ b/Sources/CgRPC/src/core/lib/surface/event_string.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/surface/init.c b/Sources/CgRPC/src/core/lib/surface/init.c index 7903f57a6..d199ac060 100644 --- a/Sources/CgRPC/src/core/lib/surface/init.c +++ b/Sources/CgRPC/src/core/lib/surface/init.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -41,12 +26,8 @@ #include #include #include "src/core/lib/channel/channel_stack.h" -#include "src/core/lib/channel/compress_filter.h" #include "src/core/lib/channel/connected_channel.h" -#include "src/core/lib/channel/deadline_filter.h" -#include "src/core/lib/channel/http_client_filter.h" -#include "src/core/lib/channel/http_server_filter.h" -#include "src/core/lib/channel/message_size_filter.h" +#include "src/core/lib/channel/handshaker_registry.h" #include "src/core/lib/debug/trace.h" #include "src/core/lib/http/parser.h" #include "src/core/lib/iomgr/combiner.h" @@ -54,6 +35,8 @@ #include "src/core/lib/iomgr/iomgr.h" #include "src/core/lib/iomgr/resource_quota.h" #include "src/core/lib/profiling/timers.h" +#include "src/core/lib/slice/slice_internal.h" +#include "src/core/lib/surface/alarm_internal.h" #include "src/core/lib/surface/api_trace.h" #include "src/core/lib/surface/call.h" #include "src/core/lib/surface/channel_init.h" @@ -61,6 +44,7 @@ #include "src/core/lib/surface/init.h" #include "src/core/lib/surface/lame_client.h" #include "src/core/lib/surface/server.h" +#include "src/core/lib/transport/bdp_estimator.h" #include "src/core/lib/transport/connectivity_state.h" #include "src/core/lib/transport/transport_impl.h" @@ -80,66 +64,25 @@ static void do_basic_init(void) { g_initializations = 0; } -static bool append_filter(grpc_channel_stack_builder *builder, void *arg) { +static bool append_filter(grpc_exec_ctx *exec_ctx, + grpc_channel_stack_builder *builder, void *arg) { return grpc_channel_stack_builder_append_filter( builder, (const grpc_channel_filter *)arg, NULL, NULL); } -static bool prepend_filter(grpc_channel_stack_builder *builder, void *arg) { +static bool prepend_filter(grpc_exec_ctx *exec_ctx, + grpc_channel_stack_builder *builder, void *arg) { return grpc_channel_stack_builder_prepend_filter( builder, (const grpc_channel_filter *)arg, NULL, NULL); } -static bool maybe_add_http_filter(grpc_channel_stack_builder *builder, - void *arg) { - grpc_transport *t = grpc_channel_stack_builder_get_transport(builder); - if (t && strstr(t->vtable->name, "http")) { - return grpc_channel_stack_builder_prepend_filter( - builder, (const grpc_channel_filter *)arg, NULL, NULL); - } - return true; -} - static void register_builtin_channel_init() { - grpc_channel_init_register_stage( - GRPC_CLIENT_DIRECT_CHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, - prepend_filter, (void *)&grpc_client_deadline_filter); - grpc_channel_init_register_stage( - GRPC_SERVER_CHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, prepend_filter, - (void *)&grpc_server_deadline_filter); - grpc_channel_init_register_stage( - GRPC_CLIENT_SUBCHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, - prepend_filter, (void *)&grpc_message_size_filter); - grpc_channel_init_register_stage( - GRPC_CLIENT_DIRECT_CHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, - prepend_filter, (void *)&grpc_message_size_filter); - grpc_channel_init_register_stage( - GRPC_SERVER_CHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, prepend_filter, - (void *)&grpc_message_size_filter); - grpc_channel_init_register_stage( - GRPC_CLIENT_CHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, prepend_filter, - (void *)&grpc_compress_filter); - grpc_channel_init_register_stage( - GRPC_CLIENT_DIRECT_CHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, - prepend_filter, (void *)&grpc_compress_filter); - grpc_channel_init_register_stage( - GRPC_SERVER_CHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, prepend_filter, - (void *)&grpc_compress_filter); - grpc_channel_init_register_stage( - GRPC_CLIENT_SUBCHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, - maybe_add_http_filter, (void *)&grpc_http_client_filter); grpc_channel_init_register_stage(GRPC_CLIENT_SUBCHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, grpc_add_connected_filter, NULL); - grpc_channel_init_register_stage( - GRPC_CLIENT_DIRECT_CHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, - maybe_add_http_filter, (void *)&grpc_http_client_filter); grpc_channel_init_register_stage(GRPC_CLIENT_DIRECT_CHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, grpc_add_connected_filter, NULL); - grpc_channel_init_register_stage( - GRPC_SERVER_CHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, - maybe_add_http_filter, (void *)&grpc_http_server_filter); grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, grpc_add_connected_filter, NULL); @@ -171,36 +114,41 @@ void grpc_init(void) { int i; gpr_once_init(&g_basic_init, do_basic_init); + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; gpr_mu_lock(&g_init_mu); if (++g_initializations == 1) { gpr_time_init(); + grpc_slice_intern_init(); grpc_mdctx_global_init(); grpc_channel_init_init(); - grpc_register_tracer("api", &grpc_api_trace); - grpc_register_tracer("channel", &grpc_trace_channel); - grpc_register_tracer("connectivity_state", &grpc_connectivity_state_trace); - grpc_register_tracer("channel_stack_builder", - &grpc_trace_channel_stack_builder); - grpc_register_tracer("http1", &grpc_http1_trace); - grpc_register_tracer("compression", &grpc_compression_trace); - grpc_register_tracer("queue_pluck", &grpc_cq_pluck_trace); - grpc_register_tracer("combiner", &grpc_combiner_trace); - grpc_register_tracer("server_channel", &grpc_server_channel_trace); - // Default pluck trace to 1 - grpc_cq_pluck_trace = 1; - grpc_register_tracer("queue_timeout", &grpc_cq_event_timeout_trace); - // Default timeout trace to 1 - grpc_cq_event_timeout_trace = 1; - grpc_register_tracer("op_failure", &grpc_trace_operation_failures); - grpc_register_tracer("resource_quota", &grpc_resource_quota_trace); + grpc_register_tracer(&grpc_api_trace); + grpc_register_tracer(&grpc_trace_channel); + grpc_register_tracer(&grpc_connectivity_state_trace); + grpc_register_tracer(&grpc_trace_channel_stack_builder); + grpc_register_tracer(&grpc_http1_trace); + grpc_register_tracer(&grpc_cq_pluck_trace); // default on + grpc_register_tracer(&grpc_combiner_trace); + grpc_register_tracer(&grpc_server_channel_trace); + grpc_register_tracer(&grpc_bdp_estimator_trace); + grpc_register_tracer(&grpc_cq_event_timeout_trace); // default on + grpc_register_tracer(&grpc_trace_operation_failures); + grpc_register_tracer(&grpc_resource_quota_trace); + grpc_register_tracer(&grpc_call_error_trace); #ifndef NDEBUG - grpc_register_tracer("pending_tags", &grpc_trace_pending_tags); + grpc_register_tracer(&grpc_trace_pending_tags); + grpc_register_tracer(&grpc_trace_alarm_refcount); + grpc_register_tracer(&grpc_trace_cq_refcount); + grpc_register_tracer(&grpc_trace_closure); + grpc_register_tracer(&grpc_trace_error_refcount); + grpc_register_tracer(&grpc_trace_stream_refcount); + grpc_register_tracer(&grpc_trace_fd_refcount); + grpc_register_tracer(&grpc_trace_metadata); #endif grpc_security_pre_init(); - grpc_iomgr_init(); - grpc_executor_init(); + grpc_iomgr_init(&exec_ctx); gpr_timers_global_init(); - grpc_cq_global_init(); + grpc_handshaker_factory_registry_init(); + grpc_security_init(); for (i = 0; i < g_number_of_plugins; i++) { if (g_all_of_the_plugins[i].init != NULL) { g_all_of_the_plugins[i].init(); @@ -213,19 +161,21 @@ void grpc_init(void) { grpc_tracer_init("GRPC_TRACE"); /* no more changes to channel init pipelines */ grpc_channel_init_finalize(); + grpc_iomgr_start(&exec_ctx); } gpr_mu_unlock(&g_init_mu); + grpc_exec_ctx_finish(&exec_ctx); GRPC_API_TRACE("grpc_init(void)", 0, ()); } void grpc_shutdown(void) { int i; GRPC_API_TRACE("grpc_shutdown(void)", 0, ()); + grpc_exec_ctx exec_ctx = + GRPC_EXEC_CTX_INITIALIZER(0, grpc_never_ready_to_finish, NULL); gpr_mu_lock(&g_init_mu); if (--g_initializations == 0) { - grpc_executor_shutdown(); - grpc_cq_global_shutdown(); - grpc_iomgr_shutdown(); + grpc_iomgr_shutdown(&exec_ctx); gpr_timers_global_destroy(); grpc_tracer_shutdown(); for (i = g_number_of_plugins; i >= 0; i--) { @@ -233,9 +183,12 @@ void grpc_shutdown(void) { g_all_of_the_plugins[i].destroy(); } } - grpc_mdctx_global_shutdown(); + grpc_mdctx_global_shutdown(&exec_ctx); + grpc_handshaker_factory_registry_shutdown(&exec_ctx); + grpc_slice_intern_shutdown(); } gpr_mu_unlock(&g_init_mu); + grpc_exec_ctx_finish(&exec_ctx); } int grpc_is_initialized(void) { diff --git a/Sources/CgRPC/src/core/lib/surface/init.h b/Sources/CgRPC/src/core/lib/surface/init.h index b1bf57c10..935320833 100644 --- a/Sources/CgRPC/src/core/lib/surface/init.h +++ b/Sources/CgRPC/src/core/lib/surface/init.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -36,6 +21,7 @@ void grpc_register_security_filters(void); void grpc_security_pre_init(void); +void grpc_security_init(void); int grpc_is_initialized(void); #endif /* GRPC_CORE_LIB_SURFACE_INIT_H */ diff --git a/Sources/CgRPC/src/core/lib/surface/init_secure.c b/Sources/CgRPC/src/core/lib/surface/init_secure.c index 7ee7b5156..2366c2491 100644 --- a/Sources/CgRPC/src/core/lib/surface/init_secure.c +++ b/Sources/CgRPC/src/core/lib/surface/init_secure.c @@ -1,36 +1,23 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 + #include "src/core/lib/surface/init.h" #include @@ -41,21 +28,30 @@ #include "src/core/lib/security/transport/auth_filters.h" #include "src/core/lib/security/transport/secure_endpoint.h" #include "src/core/lib/security/transport/security_connector.h" +#include "src/core/lib/security/transport/security_handshaker.h" #include "src/core/lib/surface/channel_init.h" -#include "src/core/lib/tsi/transport_security_interface.h" +#include "src/core/tsi/transport_security_interface.h" + +#ifndef NDEBUG +#include "src/core/lib/security/context/security_context.h" +#endif void grpc_security_pre_init(void) { - grpc_register_tracer("secure_endpoint", &grpc_trace_secure_endpoint); - grpc_register_tracer("transport_security", &tsi_tracing_enabled); + grpc_register_tracer(&grpc_trace_secure_endpoint); + grpc_register_tracer(&tsi_tracing_enabled); +#ifndef NDEBUG + grpc_register_tracer(&grpc_trace_auth_context_refcount); + grpc_register_tracer(&grpc_trace_security_connector_refcount); +#endif } static bool maybe_prepend_client_auth_filter( - grpc_channel_stack_builder *builder, void *arg) { + grpc_exec_ctx *exec_ctx, grpc_channel_stack_builder *builder, void *arg) { const grpc_channel_args *args = grpc_channel_stack_builder_get_channel_arguments(builder); if (args) { for (size_t i = 0; i < args->num_args; i++) { - if (0 == strcmp(GRPC_SECURITY_CONNECTOR_ARG, args->args[i].key)) { + if (0 == strcmp(GRPC_ARG_SECURITY_CONNECTOR, args->args[i].key)) { return grpc_channel_stack_builder_prepend_filter( builder, &grpc_client_auth_filter, NULL, NULL); } @@ -65,7 +61,7 @@ static bool maybe_prepend_client_auth_filter( } static bool maybe_prepend_server_auth_filter( - grpc_channel_stack_builder *builder, void *arg) { + grpc_exec_ctx *exec_ctx, grpc_channel_stack_builder *builder, void *arg) { const grpc_channel_args *args = grpc_channel_stack_builder_get_channel_arguments(builder); if (args) { @@ -87,3 +83,5 @@ void grpc_register_security_filters(void) { grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL, INT_MAX, maybe_prepend_server_auth_filter, NULL); } + +void grpc_security_init() { grpc_security_register_handshaker_factories(); } diff --git a/Sources/CgRPC/src/core/lib/surface/lame_client.c b/Sources/CgRPC/src/core/lib/surface/lame_client.cc similarity index 50% rename from Sources/CgRPC/src/core/lib/surface/lame_client.c rename to Sources/CgRPC/src/core/lib/surface/lame_client.cc index 57da94ac1..a0791080a 100644 --- a/Sources/CgRPC/src/core/lib/surface/lame_client.c +++ b/Sources/CgRPC/src/core/lib/surface/lame_client.cc @@ -1,87 +1,94 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 "src/core/lib/surface/lame_client.h" - #include #include #include #include + +#include "src/core/lib/support/atomic.h" + +extern "C" { #include "src/core/lib/channel/channel_stack.h" #include "src/core/lib/support/string.h" #include "src/core/lib/surface/api_trace.h" #include "src/core/lib/surface/call.h" #include "src/core/lib/surface/channel.h" +#include "src/core/lib/surface/lame_client.h" +#include "src/core/lib/transport/static_metadata.h" +} + +namespace grpc_core { -typedef struct { +namespace { + +struct CallData { grpc_linked_mdelem status; grpc_linked_mdelem details; -} call_data; + grpc_core::atomic filled_metadata; +}; -typedef struct { +struct ChannelData { grpc_status_code error_code; const char *error_message; -} channel_data; +}; -static void fill_metadata(grpc_call_element *elem, grpc_metadata_batch *mdb) { - call_data *calld = elem->call_data; - channel_data *chand = elem->channel_data; +static void fill_metadata(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, + grpc_metadata_batch *mdb) { + CallData *calld = static_cast(elem->call_data); + bool expected = false; + if (!calld->filled_metadata.compare_exchange_strong( + expected, true, grpc_core::memory_order_relaxed, + grpc_core::memory_order_relaxed)) { + return; + } + ChannelData *chand = static_cast(elem->channel_data); char tmp[GPR_LTOA_MIN_BUFSIZE]; gpr_ltoa(chand->error_code, tmp); - calld->status.md = grpc_mdelem_from_strings("grpc-status", tmp); - calld->details.md = - grpc_mdelem_from_strings("grpc-message", chand->error_message); + calld->status.md = grpc_mdelem_from_slices( + exec_ctx, GRPC_MDSTR_GRPC_STATUS, grpc_slice_from_copied_string(tmp)); + calld->details.md = grpc_mdelem_from_slices( + exec_ctx, GRPC_MDSTR_GRPC_MESSAGE, + grpc_slice_from_copied_string(chand->error_message)); calld->status.prev = calld->details.next = NULL; calld->status.next = &calld->details; calld->details.prev = &calld->status; mdb->list.head = &calld->status; mdb->list.tail = &calld->details; + mdb->list.count = 2; mdb->deadline = gpr_inf_future(GPR_CLOCK_REALTIME); } -static void lame_start_transport_stream_op(grpc_exec_ctx *exec_ctx, - grpc_call_element *elem, - grpc_transport_stream_op *op) { - GRPC_CALL_LOG_OP(GPR_INFO, elem, op); - if (op->recv_initial_metadata != NULL) { - fill_metadata(elem, op->recv_initial_metadata); - } else if (op->recv_trailing_metadata != NULL) { - fill_metadata(elem, op->recv_trailing_metadata); +static void lame_start_transport_stream_op_batch( + grpc_exec_ctx *exec_ctx, grpc_call_element *elem, + grpc_transport_stream_op_batch *op) { + if (op->recv_initial_metadata) { + fill_metadata(exec_ctx, elem, + op->payload->recv_initial_metadata.recv_initial_metadata); + } else if (op->recv_trailing_metadata) { + fill_metadata(exec_ctx, elem, + op->payload->recv_trailing_metadata.recv_trailing_metadata); } - grpc_transport_stream_op_finish_with_failure( - exec_ctx, op, GRPC_ERROR_CREATE("lame client channel")); + grpc_transport_stream_op_batch_finish_with_failure( + exec_ctx, op, + GRPC_ERROR_CREATE_FROM_STATIC_STRING("lame client channel")); } static char *lame_get_peer(grpc_exec_ctx *exec_ctx, grpc_call_element *elem) { @@ -98,29 +105,30 @@ static void lame_start_transport_op(grpc_exec_ctx *exec_ctx, if (op->on_connectivity_state_change) { GPR_ASSERT(*op->connectivity_state != GRPC_CHANNEL_SHUTDOWN); *op->connectivity_state = GRPC_CHANNEL_SHUTDOWN; - grpc_exec_ctx_sched(exec_ctx, op->on_connectivity_state_change, - GRPC_ERROR_NONE, NULL); + GRPC_CLOSURE_SCHED(exec_ctx, op->on_connectivity_state_change, + GRPC_ERROR_NONE); } if (op->send_ping != NULL) { - grpc_exec_ctx_sched(exec_ctx, op->send_ping, - GRPC_ERROR_CREATE("lame client channel"), NULL); + GRPC_CLOSURE_SCHED( + exec_ctx, op->send_ping, + GRPC_ERROR_CREATE_FROM_STATIC_STRING("lame client channel")); } GRPC_ERROR_UNREF(op->disconnect_with_error); if (op->on_consumed != NULL) { - grpc_exec_ctx_sched(exec_ctx, op->on_consumed, GRPC_ERROR_NONE, NULL); + GRPC_CLOSURE_SCHED(exec_ctx, op->on_consumed, GRPC_ERROR_NONE); } } static grpc_error *init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, - grpc_call_element_args *args) { + const grpc_call_element_args *args) { return GRPC_ERROR_NONE; } static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, const grpc_call_final_info *final_info, - void *and_free_memory) { - gpr_free(and_free_memory); + grpc_closure *then_schedule_closure) { + GRPC_CLOSURE_SCHED(exec_ctx, then_schedule_closure, GRPC_ERROR_NONE); } static grpc_error *init_channel_elem(grpc_exec_ctx *exec_ctx, @@ -134,18 +142,22 @@ static grpc_error *init_channel_elem(grpc_exec_ctx *exec_ctx, static void destroy_channel_elem(grpc_exec_ctx *exec_ctx, grpc_channel_element *elem) {} -const grpc_channel_filter grpc_lame_filter = { - lame_start_transport_stream_op, - lame_start_transport_op, - sizeof(call_data), - init_call_elem, +} // namespace + +} // namespace grpc_core + +extern "C" const grpc_channel_filter grpc_lame_filter = { + grpc_core::lame_start_transport_stream_op_batch, + grpc_core::lame_start_transport_op, + sizeof(grpc_core::CallData), + grpc_core::init_call_elem, grpc_call_stack_ignore_set_pollset_or_pollset_set, - destroy_call_elem, - sizeof(channel_data), - init_channel_elem, - destroy_channel_elem, - lame_get_peer, - lame_get_channel_info, + grpc_core::destroy_call_elem, + sizeof(grpc_core::ChannelData), + grpc_core::init_channel_elem, + grpc_core::destroy_channel_elem, + grpc_core::lame_get_peer, + grpc_core::lame_get_channel_info, "lame-client", }; @@ -156,7 +168,6 @@ grpc_channel *grpc_lame_client_channel_create(const char *target, const char *error_message) { grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_channel_element *elem; - channel_data *chand; grpc_channel *channel = grpc_channel_create(&exec_ctx, target, NULL, GRPC_CLIENT_LAME_CHANNEL, NULL); elem = grpc_channel_stack_element(grpc_channel_get_channel_stack(channel), 0); @@ -165,7 +176,7 @@ grpc_channel *grpc_lame_client_channel_create(const char *target, "error_message=%s)", 3, (target, (int)error_code, error_message)); GPR_ASSERT(elem->filter == &grpc_lame_filter); - chand = (channel_data *)elem->channel_data; + auto chand = static_cast(elem->channel_data); chand->error_code = error_code; chand->error_message = error_message; grpc_exec_ctx_finish(&exec_ctx); diff --git a/Sources/CgRPC/src/core/lib/surface/lame_client.h b/Sources/CgRPC/src/core/lib/surface/lame_client.h index 5f6ea34d4..3ce353f10 100644 --- a/Sources/CgRPC/src/core/lib/surface/lame_client.h +++ b/Sources/CgRPC/src/core/lib/surface/lame_client.h @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/surface/metadata_array.c b/Sources/CgRPC/src/core/lib/surface/metadata_array.c index 6c2b750e1..0afb8b4b8 100644 --- a/Sources/CgRPC/src/core/lib/surface/metadata_array.c +++ b/Sources/CgRPC/src/core/lib/surface/metadata_array.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ diff --git a/Sources/CgRPC/src/core/lib/surface/server.c b/Sources/CgRPC/src/core/lib/surface/server.c index 62d7afc8d..66dcc299a 100644 --- a/Sources/CgRPC/src/core/lib/surface/server.c +++ b/Sources/CgRPC/src/core/lib/surface/server.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015-2016, Google Inc. - * All rights reserved. + * Copyright 2015-2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -44,7 +29,9 @@ #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/channel/connected_channel.h" +#include "src/core/lib/iomgr/executor.h" #include "src/core/lib/iomgr/iomgr.h" +#include "src/core/lib/slice/slice_internal.h" #include "src/core/lib/support/stack_lockfree.h" #include "src/core/lib/support/string.h" #include "src/core/lib/surface/api_trace.h" @@ -71,7 +58,8 @@ typedef struct registered_method registered_method; typedef enum { BATCH_CALL, REGISTERED_CALL } requested_call_type; -int grpc_server_channel_trace = 0; +grpc_tracer_flag grpc_server_channel_trace = + GRPC_TRACER_INITIALIZER(false, "server_channel"); typedef struct requested_call { requested_call_type type; @@ -97,8 +85,9 @@ typedef struct requested_call { typedef struct channel_registered_method { registered_method *server_registered_method; uint32_t flags; - grpc_mdstr *method; - grpc_mdstr *host; + bool has_host; + grpc_slice method; + grpc_slice host; } channel_registered_method; struct channel_data { @@ -143,15 +132,16 @@ struct call_data { /** the current state of a call - see call_state */ call_state state; - grpc_mdstr *path; - grpc_mdstr *host; + bool path_set; + bool host_set; + grpc_slice path; + grpc_slice host; gpr_timespec deadline; grpc_completion_queue *cq_new; grpc_metadata_batch *recv_initial_metadata; - bool recv_idempotent_request; - bool recv_cacheable_request; + uint32_t recv_initial_metadata_flags; grpc_metadata_array initial_metadata; request_matcher *request_matcher; @@ -208,6 +198,11 @@ struct grpc_server { gpr_mu mu_global; /* mutex for server and channel state */ gpr_mu mu_call; /* mutex for call-specific state */ + /* startup synchronization: flag is protected by mu_global, signals whether + we are doing the listener start routine or not */ + bool starting; + gpr_cv starting_cv; + registered_method *registered_methods; /** one request matcher for unregistered methods */ request_matcher unregistered_request_matcher; @@ -271,22 +266,25 @@ struct shutdown_cleanup_args { static void shutdown_cleanup(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { struct shutdown_cleanup_args *a = arg; - grpc_slice_unref(a->slice); + grpc_slice_unref_internal(exec_ctx, a->slice); gpr_free(a); } static void send_shutdown(grpc_exec_ctx *exec_ctx, grpc_channel *channel, - int send_goaway, grpc_error *send_disconnect) { + bool send_goaway, grpc_error *send_disconnect) { struct shutdown_cleanup_args *sc = gpr_malloc(sizeof(*sc)); - grpc_closure_init(&sc->closure, shutdown_cleanup, sc); + GRPC_CLOSURE_INIT(&sc->closure, shutdown_cleanup, sc, + grpc_schedule_on_exec_ctx); grpc_transport_op *op = grpc_make_transport_op(&sc->closure); grpc_channel_element *elem; - op->send_goaway = send_goaway; + op->goaway_error = + send_goaway ? grpc_error_set_int( + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Server shutdown"), + GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_OK) + : GRPC_ERROR_NONE; op->set_accept_stream = true; sc->slice = grpc_slice_from_copied_string("Server shutdown"); - op->goaway_message = &sc->slice; - op->goaway_status = GRPC_STATUS_OK; op->disconnect_with_error = send_disconnect; elem = grpc_channel_stack_element(grpc_channel_get_channel_stack(channel), 0); @@ -333,7 +331,7 @@ static void request_matcher_destroy(request_matcher *rm) { static void kill_zombie(grpc_exec_ctx *exec_ctx, void *elem, grpc_error *error) { - grpc_call_destroy(grpc_call_from_top_element(elem)); + grpc_call_unref(grpc_call_from_top_element(elem)); } static void request_matcher_zombify_all_pending_calls(grpc_exec_ctx *exec_ctx, @@ -344,11 +342,11 @@ static void request_matcher_zombify_all_pending_calls(grpc_exec_ctx *exec_ctx, gpr_mu_lock(&calld->mu_state); calld->state = ZOMBIED; gpr_mu_unlock(&calld->mu_state); - grpc_closure_init( + GRPC_CLOSURE_INIT( &calld->kill_zombie_closure, kill_zombie, - grpc_call_stack_element(grpc_call_get_call_stack(calld->call), 0)); - grpc_exec_ctx_sched(exec_ctx, &calld->kill_zombie_closure, GRPC_ERROR_NONE, - NULL); + grpc_call_stack_element(grpc_call_get_call_stack(calld->call), 0), + grpc_schedule_on_exec_ctx); + GRPC_CLOSURE_SCHED(exec_ctx, &calld->kill_zombie_closure, GRPC_ERROR_NONE); } } @@ -379,9 +377,10 @@ static void server_ref(grpc_server *server) { static void server_delete(grpc_exec_ctx *exec_ctx, grpc_server *server) { registered_method *rm; size_t i; - grpc_channel_args_destroy(server->channel_args); + grpc_channel_args_destroy(exec_ctx, server->channel_args); gpr_mu_destroy(&server->mu_global); gpr_mu_destroy(&server->mu_call); + gpr_cv_destroy(&server->starting_cv); while ((rm = server->registered_methods) != NULL) { server->registered_methods = rm->next; if (server->started) { @@ -395,7 +394,7 @@ static void server_delete(grpc_exec_ctx *exec_ctx, grpc_server *server) { request_matcher_destroy(&server->unregistered_request_matcher); } for (i = 0; i < server->cq_count; i++) { - GRPC_CQ_INTERNAL_UNREF(server->cqs[i], "server"); + GRPC_CQ_INTERNAL_UNREF(exec_ctx, server->cqs[i], "server"); if (server->started) { gpr_stack_lockfree_destroy(server->request_freelist_per_cq[i]); gpr_free(server->requested_calls_per_cq[i]); @@ -440,13 +439,12 @@ static void destroy_channel(grpc_exec_ctx *exec_ctx, channel_data *chand, orphan_channel(chand); server_ref(chand->server); maybe_finish_shutdown(exec_ctx, chand->server); - chand->finish_destroy_channel_closure.cb = finish_destroy_channel; - chand->finish_destroy_channel_closure.cb_arg = chand; + GRPC_CLOSURE_INIT(&chand->finish_destroy_channel_closure, + finish_destroy_channel, chand, grpc_schedule_on_exec_ctx); - if (grpc_server_channel_trace && error != GRPC_ERROR_NONE) { + if (GRPC_TRACER_ON(grpc_server_channel_trace) && error != GRPC_ERROR_NONE) { const char *msg = grpc_error_string(error); gpr_log(GPR_INFO, "Disconnected client: %s", msg); - grpc_error_free_string(msg); } GRPC_ERROR_UNREF(error); @@ -459,17 +457,6 @@ static void destroy_channel(grpc_exec_ctx *exec_ctx, channel_data *chand, op); } -static void cpstr(char **dest, size_t *capacity, grpc_mdstr *value) { - grpc_slice slice = value->slice; - size_t len = GRPC_SLICE_LENGTH(slice); - - if (len + 1 > *capacity) { - *capacity = GPR_MAX(len + 1, *capacity * 2); - *dest = gpr_realloc(*dest, *capacity); - } - memcpy(*dest, grpc_mdstr_as_c_string(value), len + 1); -} - static void done_request_event(grpc_exec_ctx *exec_ctx, void *req, grpc_cq_completion *c) { requested_call *rc = req; @@ -498,25 +485,18 @@ static void publish_call(grpc_exec_ctx *exec_ctx, grpc_server *server, GPR_SWAP(grpc_metadata_array, *rc->initial_metadata, calld->initial_metadata); switch (rc->type) { case BATCH_CALL: - GPR_ASSERT(calld->host != NULL); - GPR_ASSERT(calld->path != NULL); - cpstr(&rc->data.batch.details->host, - &rc->data.batch.details->host_capacity, calld->host); - cpstr(&rc->data.batch.details->method, - &rc->data.batch.details->method_capacity, calld->path); + GPR_ASSERT(calld->host_set); + GPR_ASSERT(calld->path_set); + rc->data.batch.details->host = grpc_slice_ref_internal(calld->host); + rc->data.batch.details->method = grpc_slice_ref_internal(calld->path); rc->data.batch.details->deadline = calld->deadline; - rc->data.batch.details->flags = - (calld->recv_idempotent_request - ? GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST - : 0) | - (calld->recv_cacheable_request - ? GRPC_INITIAL_METADATA_CACHEABLE_REQUEST - : 0); + rc->data.batch.details->flags = calld->recv_initial_metadata_flags; break; case REGISTERED_CALL: *rc->data.registered.deadline = calld->deadline; if (rc->data.registered.optional_payload) { *rc->data.registered.optional_payload = calld->payload; + calld->payload = NULL; } break; default: @@ -543,10 +523,12 @@ static void publish_new_rpc(grpc_exec_ctx *exec_ctx, void *arg, gpr_mu_lock(&calld->mu_state); calld->state = ZOMBIED; gpr_mu_unlock(&calld->mu_state); - grpc_closure_init( + GRPC_CLOSURE_INIT( &calld->kill_zombie_closure, kill_zombie, - grpc_call_stack_element(grpc_call_get_call_stack(calld->call), 0)); - grpc_exec_ctx_sched(exec_ctx, &calld->kill_zombie_closure, error, NULL); + grpc_call_stack_element(grpc_call_get_call_stack(calld->call), 0), + grpc_schedule_on_exec_ctx); + GRPC_CLOSURE_SCHED(exec_ctx, &calld->kill_zombie_closure, + GRPC_ERROR_REF(error)); return; } @@ -590,9 +572,9 @@ static void finish_start_new_rpc( gpr_mu_lock(&calld->mu_state); calld->state = ZOMBIED; gpr_mu_unlock(&calld->mu_state); - grpc_closure_init(&calld->kill_zombie_closure, kill_zombie, elem); - grpc_exec_ctx_sched(exec_ctx, &calld->kill_zombie_closure, GRPC_ERROR_NONE, - NULL); + GRPC_CLOSURE_INIT(&calld->kill_zombie_closure, kill_zombie, elem, + grpc_schedule_on_exec_ctx); + GRPC_CLOSURE_SCHED(exec_ctx, &calld->kill_zombie_closure, GRPC_ERROR_NONE); return; } @@ -606,8 +588,9 @@ static void finish_start_new_rpc( grpc_op op; memset(&op, 0, sizeof(op)); op.op = GRPC_OP_RECV_MESSAGE; - op.data.recv_message = &calld->payload; - grpc_closure_init(&calld->publish, publish_new_rpc, elem); + op.data.recv_message.recv_message = &calld->payload; + GRPC_CLOSURE_INIT(&calld->publish, publish_new_rpc, elem, + grpc_schedule_on_exec_ctx); grpc_call_start_batch_and_execute(exec_ctx, calld->call, &op, 1, &calld->publish); break; @@ -623,35 +606,41 @@ static void start_new_rpc(grpc_exec_ctx *exec_ctx, grpc_call_element *elem) { uint32_t hash; channel_registered_method *rm; - if (chand->registered_methods && calld->path && calld->host) { + if (chand->registered_methods && calld->path_set && calld->host_set) { /* TODO(ctiller): unify these two searches */ /* check for an exact match with host */ - hash = GRPC_MDSTR_KV_HASH(calld->host->hash, calld->path->hash); + hash = GRPC_MDSTR_KV_HASH(grpc_slice_hash(calld->host), + grpc_slice_hash(calld->path)); for (i = 0; i <= chand->registered_method_max_probes; i++) { rm = &chand->registered_methods[(hash + i) % chand->registered_method_slots]; if (!rm) break; - if (rm->host != calld->host) continue; - if (rm->method != calld->path) continue; + if (!rm->has_host) continue; + if (!grpc_slice_eq(rm->host, calld->host)) continue; + if (!grpc_slice_eq(rm->method, calld->path)) continue; if ((rm->flags & GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST) && - !calld->recv_idempotent_request) + 0 == (calld->recv_initial_metadata_flags & + GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST)) { continue; + } finish_start_new_rpc(exec_ctx, server, elem, &rm->server_registered_method->request_matcher, rm->server_registered_method->payload_handling); return; } /* check for a wildcard method definition (no host set) */ - hash = GRPC_MDSTR_KV_HASH(0, calld->path->hash); + hash = GRPC_MDSTR_KV_HASH(0, grpc_slice_hash(calld->path)); for (i = 0; i <= chand->registered_method_max_probes; i++) { rm = &chand->registered_methods[(hash + i) % chand->registered_method_slots]; if (!rm) break; - if (rm->host != NULL) continue; - if (rm->method != calld->path) continue; + if (rm->has_host) continue; + if (!grpc_slice_eq(rm->method, calld->path)) continue; if ((rm->flags & GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST) && - !calld->recv_idempotent_request) + 0 == (calld->recv_initial_metadata_flags & + GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST)) { continue; + } finish_start_new_rpc(exec_ctx, server, elem, &rm->server_registered_method->request_matcher, rm->server_registered_method->payload_handling); @@ -712,8 +701,9 @@ static void maybe_finish_shutdown(grpc_exec_ctx *exec_ctx, return; } - kill_pending_work_locked(exec_ctx, server, - GRPC_ERROR_CREATE("Server Shutdown")); + kill_pending_work_locked( + exec_ctx, server, + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Server Shutdown")); if (server->root_channel_data.next != &server->root_channel_data || server->listeners_destroyed < num_listeners(server)) { @@ -740,63 +730,65 @@ static void maybe_finish_shutdown(grpc_exec_ctx *exec_ctx, } } -static grpc_mdelem *server_filter(void *user_data, grpc_mdelem *md) { - grpc_call_element *elem = user_data; - call_data *calld = elem->call_data; - if (md->key == GRPC_MDSTR_PATH) { - if (calld->path == NULL) { - calld->path = GRPC_MDSTR_REF(md->value); - } - return NULL; - } else if (md->key == GRPC_MDSTR_AUTHORITY) { - if (calld->host == NULL) { - calld->host = GRPC_MDSTR_REF(md->value); - } - return NULL; - } - return md; -} - static void server_on_recv_initial_metadata(grpc_exec_ctx *exec_ctx, void *ptr, grpc_error *error) { grpc_call_element *elem = ptr; call_data *calld = elem->call_data; gpr_timespec op_deadline; - GRPC_ERROR_REF(error); - grpc_metadata_batch_filter(calld->recv_initial_metadata, server_filter, elem); + if (error == GRPC_ERROR_NONE) { + GPR_ASSERT(calld->recv_initial_metadata->idx.named.path != NULL); + GPR_ASSERT(calld->recv_initial_metadata->idx.named.authority != NULL); + calld->path = grpc_slice_ref_internal( + GRPC_MDVALUE(calld->recv_initial_metadata->idx.named.path->md)); + calld->host = grpc_slice_ref_internal( + GRPC_MDVALUE(calld->recv_initial_metadata->idx.named.authority->md)); + calld->path_set = true; + calld->host_set = true; + grpc_metadata_batch_remove(exec_ctx, calld->recv_initial_metadata, + calld->recv_initial_metadata->idx.named.path); + grpc_metadata_batch_remove( + exec_ctx, calld->recv_initial_metadata, + calld->recv_initial_metadata->idx.named.authority); + } else { + GRPC_ERROR_REF(error); + } op_deadline = calld->recv_initial_metadata->deadline; if (0 != gpr_time_cmp(op_deadline, gpr_inf_future(op_deadline.clock_type))) { calld->deadline = op_deadline; } - if (calld->host && calld->path) { + if (calld->host_set && calld->path_set) { /* do nothing */ } else { - GRPC_ERROR_UNREF(error); - error = - GRPC_ERROR_CREATE_REFERENCING("Missing :authority or :path", &error, 1); + grpc_error *src_error = error; + error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( + "Missing :authority or :path", &error, 1); + GRPC_ERROR_UNREF(src_error); } - grpc_closure_run(exec_ctx, calld->on_done_recv_initial_metadata, error); + GRPC_CLOSURE_RUN(exec_ctx, calld->on_done_recv_initial_metadata, error); } static void server_mutate_op(grpc_call_element *elem, - grpc_transport_stream_op *op) { + grpc_transport_stream_op_batch *op) { call_data *calld = elem->call_data; - if (op->recv_initial_metadata != NULL) { - GPR_ASSERT(op->recv_idempotent_request == NULL); - calld->recv_initial_metadata = op->recv_initial_metadata; - calld->on_done_recv_initial_metadata = op->recv_initial_metadata_ready; - op->recv_initial_metadata_ready = &calld->server_on_recv_initial_metadata; - op->recv_idempotent_request = &calld->recv_idempotent_request; - op->recv_cacheable_request = &calld->recv_cacheable_request; + if (op->recv_initial_metadata) { + GPR_ASSERT(op->payload->recv_initial_metadata.recv_flags == NULL); + calld->recv_initial_metadata = + op->payload->recv_initial_metadata.recv_initial_metadata; + calld->on_done_recv_initial_metadata = + op->payload->recv_initial_metadata.recv_initial_metadata_ready; + op->payload->recv_initial_metadata.recv_initial_metadata_ready = + &calld->server_on_recv_initial_metadata; + op->payload->recv_initial_metadata.recv_flags = + &calld->recv_initial_metadata_flags; } } -static void server_start_transport_stream_op(grpc_exec_ctx *exec_ctx, - grpc_call_element *elem, - grpc_transport_stream_op *op) { +static void server_start_transport_stream_op_batch( + grpc_exec_ctx *exec_ctx, grpc_call_element *elem, + grpc_transport_stream_op_batch *op) { GRPC_CALL_LOG_OP(GPR_INFO, elem, op); server_mutate_op(elem, op); grpc_call_next_op(exec_ctx, elem, op); @@ -813,9 +805,10 @@ static void got_initial_metadata(grpc_exec_ctx *exec_ctx, void *ptr, if (calld->state == NOT_STARTED) { calld->state = ZOMBIED; gpr_mu_unlock(&calld->mu_state); - grpc_closure_init(&calld->kill_zombie_closure, kill_zombie, elem); - grpc_exec_ctx_sched(exec_ctx, &calld->kill_zombie_closure, - GRPC_ERROR_NONE, NULL); + GRPC_CLOSURE_INIT(&calld->kill_zombie_closure, kill_zombie, elem, + grpc_schedule_on_exec_ctx); + GRPC_CLOSURE_SCHED(exec_ctx, &calld->kill_zombie_closure, + GRPC_ERROR_NONE); } else if (calld->state == PENDING) { calld->state = ZOMBIED; gpr_mu_unlock(&calld->mu_state); @@ -838,7 +831,7 @@ static void accept_stream(grpc_exec_ctx *exec_ctx, void *cd, args.server_transport_data = transport_server_data; args.send_deadline = gpr_inf_future(GPR_CLOCK_MONOTONIC); grpc_call *call; - grpc_error *error = grpc_call_create(&args, &call); + grpc_error *error = grpc_call_create(exec_ctx, &args, &call); grpc_call_element *elem = grpc_call_stack_element(grpc_call_get_call_stack(call), 0); if (error != GRPC_ERROR_NONE) { @@ -850,8 +843,10 @@ static void accept_stream(grpc_exec_ctx *exec_ctx, void *cd, grpc_op op; memset(&op, 0, sizeof(op)); op.op = GRPC_OP_RECV_INITIAL_METADATA; - op.data.recv_initial_metadata = &calld->initial_metadata; - grpc_closure_init(&calld->got_initial_metadata, got_initial_metadata, elem); + op.data.recv_initial_metadata.recv_initial_metadata = + &calld->initial_metadata; + GRPC_CLOSURE_INIT(&calld->got_initial_metadata, got_initial_metadata, elem, + grpc_schedule_on_exec_ctx); grpc_call_start_batch_and_execute(exec_ctx, call, &op, 1, &calld->got_initial_metadata); } @@ -878,7 +873,7 @@ static void channel_connectivity_changed(grpc_exec_ctx *exec_ctx, void *cd, static grpc_error *init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, - grpc_call_element_args *args) { + const grpc_call_element_args *args) { call_data *calld = elem->call_data; channel_data *chand = elem->channel_data; memset(calld, 0, sizeof(call_data)); @@ -886,8 +881,9 @@ static grpc_error *init_call_elem(grpc_exec_ctx *exec_ctx, calld->call = grpc_call_from_top_element(elem); gpr_mu_init(&calld->mu_state); - grpc_closure_init(&calld->server_on_recv_initial_metadata, - server_on_recv_initial_metadata, elem); + GRPC_CLOSURE_INIT(&calld->server_on_recv_initial_metadata, + server_on_recv_initial_metadata, elem, + grpc_schedule_on_exec_ctx); server_ref(chand->server); return GRPC_ERROR_NONE; @@ -895,19 +891,20 @@ static grpc_error *init_call_elem(grpc_exec_ctx *exec_ctx, static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, const grpc_call_final_info *final_info, - void *ignored) { + grpc_closure *ignored) { channel_data *chand = elem->channel_data; call_data *calld = elem->call_data; GPR_ASSERT(calld->state != PENDING); - if (calld->host) { - GRPC_MDSTR_UNREF(calld->host); + if (calld->host_set) { + grpc_slice_unref_internal(exec_ctx, calld->host); } - if (calld->path) { - GRPC_MDSTR_UNREF(calld->path); + if (calld->path_set) { + grpc_slice_unref_internal(exec_ctx, calld->path); } grpc_metadata_array_destroy(&calld->initial_metadata); + grpc_byte_buffer_destroy(calld->payload); gpr_mu_destroy(&calld->mu_state); @@ -925,8 +922,9 @@ static grpc_error *init_channel_elem(grpc_exec_ctx *exec_ctx, chand->next = chand->prev = chand; chand->registered_methods = NULL; chand->connectivity_state = GRPC_CHANNEL_IDLE; - grpc_closure_init(&chand->channel_connectivity_changed, - channel_connectivity_changed, chand); + GRPC_CLOSURE_INIT(&chand->channel_connectivity_changed, + channel_connectivity_changed, chand, + grpc_schedule_on_exec_ctx); return GRPC_ERROR_NONE; } @@ -936,11 +934,9 @@ static void destroy_channel_elem(grpc_exec_ctx *exec_ctx, channel_data *chand = elem->channel_data; if (chand->registered_methods) { for (i = 0; i < chand->registered_method_slots; i++) { - if (chand->registered_methods[i].method) { - GRPC_MDSTR_UNREF(chand->registered_methods[i].method); - } - if (chand->registered_methods[i].host) { - GRPC_MDSTR_UNREF(chand->registered_methods[i].host); + grpc_slice_unref_internal(exec_ctx, chand->registered_methods[i].method); + if (chand->registered_methods[i].has_host) { + grpc_slice_unref_internal(exec_ctx, chand->registered_methods[i].host); } } gpr_free(chand->registered_methods); @@ -957,7 +953,7 @@ static void destroy_channel_elem(grpc_exec_ctx *exec_ctx, } const grpc_channel_filter grpc_server_top_filter = { - server_start_transport_stream_op, + server_start_transport_stream_op_batch, grpc_channel_next_op, sizeof(call_data), init_call_elem, @@ -973,19 +969,13 @@ const grpc_channel_filter grpc_server_top_filter = { static void register_completion_queue(grpc_server *server, grpc_completion_queue *cq, - bool is_non_listening, void *reserved) { + void *reserved) { size_t i, n; GPR_ASSERT(!reserved); for (i = 0; i < server->cq_count; i++) { if (server->cqs[i] == cq) return; } - grpc_cq_mark_server_cq(cq); - - if (is_non_listening) { - grpc_cq_mark_non_listening_server_cq(cq); - } - GRPC_CQ_INTERNAL_REF(cq, "server"); n = server->cq_count++; server->cqs = gpr_realloc(server->cqs, @@ -999,29 +989,26 @@ void grpc_server_register_completion_queue(grpc_server *server, GRPC_API_TRACE( "grpc_server_register_completion_queue(server=%p, cq=%p, reserved=%p)", 3, (server, cq, reserved)); - register_completion_queue(server, cq, false, reserved); -} -void grpc_server_register_non_listening_completion_queue( - grpc_server *server, grpc_completion_queue *cq, void *reserved) { - GRPC_API_TRACE( - "grpc_server_register_non_listening_completion_queue(server=%p, cq=%p, " - "reserved=%p)", - 3, (server, cq, reserved)); - register_completion_queue(server, cq, true, reserved); + if (grpc_get_cq_completion_type(cq) != GRPC_CQ_NEXT) { + gpr_log(GPR_INFO, + "Completion queue which is not of type GRPC_CQ_NEXT is being " + "registered as a server-completion-queue"); + /* Ideally we should log an error and abort but ruby-wrapped-language API + calls grpc_completion_queue_pluck() on server completion queues */ + } + + register_completion_queue(server, cq, reserved); } grpc_server *grpc_server_create(const grpc_channel_args *args, void *reserved) { GRPC_API_TRACE("grpc_server_create(%p, %p)", 2, (args, reserved)); - grpc_server *server = gpr_malloc(sizeof(grpc_server)); - - GPR_ASSERT(grpc_is_initialized() && "call grpc_init()"); - - memset(server, 0, sizeof(grpc_server)); + grpc_server *server = gpr_zalloc(sizeof(grpc_server)); gpr_mu_init(&server->mu_global); gpr_mu_init(&server->mu_call); + gpr_cv_init(&server->starting_cv); /* decremented by grpc_server_destroy */ gpr_ref_init(&server->internal_refcount, 1); @@ -1068,8 +1055,7 @@ void *grpc_server_register_method( flags); return NULL; } - m = gpr_malloc(sizeof(registered_method)); - memset(m, 0, sizeof(*m)); + m = gpr_zalloc(sizeof(registered_method)); m->method = gpr_strdup(method); m->host = gpr_strdup(host); m->next = server->registered_methods; @@ -1079,8 +1065,22 @@ void *grpc_server_register_method( return m; } +static void start_listeners(grpc_exec_ctx *exec_ctx, void *s, + grpc_error *error) { + grpc_server *server = s; + for (listener *l = server->listeners; l; l = l->next) { + l->start(exec_ctx, server, l->arg, server->pollsets, server->pollset_count); + } + + gpr_mu_lock(&server->mu_global); + server->starting = false; + gpr_cv_signal(&server->starting_cv); + gpr_mu_unlock(&server->mu_global); + + server_unref(exec_ctx, server); +} + void grpc_server_start(grpc_server *server) { - listener *l; size_t i; grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; @@ -1094,7 +1094,7 @@ void grpc_server_start(grpc_server *server) { server->requested_calls_per_cq = gpr_malloc(sizeof(*server->requested_calls_per_cq) * server->cq_count); for (i = 0; i < server->cq_count; i++) { - if (!grpc_cq_is_non_listening_server_cq(server->cqs[i])) { + if (grpc_cq_can_listen(server->cqs[i])) { server->pollsets[server->pollset_count++] = grpc_cq_pollset(server->cqs[i]); } @@ -1114,10 +1114,11 @@ void grpc_server_start(grpc_server *server) { (size_t)server->max_requested_calls_per_cq, server); } - for (l = server->listeners; l; l = l->next) { - l->start(&exec_ctx, server, l->arg, server->pollsets, - server->pollset_count); - } + server_ref(server); + server->starting = true; + GRPC_CLOSURE_SCHED(&exec_ctx, GRPC_CLOSURE_CREATE(start_listeners, server, + grpc_executor_scheduler), + GRPC_ERROR_NONE); grpc_exec_ctx_finish(&exec_ctx); } @@ -1138,8 +1139,6 @@ void grpc_server_setup_transport(grpc_exec_ctx *exec_ctx, grpc_server *s, channel_registered_method *crm; grpc_channel *channel; channel_data *chand; - grpc_mdstr *host; - grpc_mdstr *method; uint32_t hash; size_t slots; uint32_t probes; @@ -1156,9 +1155,8 @@ void grpc_server_setup_transport(grpc_exec_ctx *exec_ctx, grpc_server *s, chand->channel = channel; size_t cq_idx; - grpc_completion_queue *accepting_cq = grpc_cq_from_pollset(accepting_pollset); for (cq_idx = 0; cq_idx < s->cq_count; cq_idx++) { - if (s->cqs[cq_idx] == accepting_cq) break; + if (grpc_cq_pollset(s->cqs[cq_idx]) == accepting_pollset) break; } if (cq_idx == s->cq_count) { /* completion queue not found: pick a random one to publish new calls to */ @@ -1175,12 +1173,20 @@ void grpc_server_setup_transport(grpc_exec_ctx *exec_ctx, grpc_server *s, if (num_registered_methods > 0) { slots = 2 * num_registered_methods; alloc = sizeof(channel_registered_method) * slots; - chand->registered_methods = gpr_malloc(alloc); - memset(chand->registered_methods, 0, alloc); + chand->registered_methods = gpr_zalloc(alloc); for (rm = s->registered_methods; rm; rm = rm->next) { - host = rm->host ? grpc_mdstr_from_string(rm->host) : NULL; - method = grpc_mdstr_from_string(rm->method); - hash = GRPC_MDSTR_KV_HASH(host ? host->hash : 0, method->hash); + grpc_slice host; + bool has_host; + grpc_slice method; + if (rm->host != NULL) { + host = grpc_slice_intern(grpc_slice_from_static_string(rm->host)); + has_host = true; + } else { + has_host = false; + } + method = grpc_slice_intern(grpc_slice_from_static_string(rm->method)); + hash = GRPC_MDSTR_KV_HASH(has_host ? grpc_slice_hash(host) : 0, + grpc_slice_hash(method)); for (probes = 0; chand->registered_methods[(hash + probes) % slots] .server_registered_method != NULL; probes++) @@ -1189,7 +1195,10 @@ void grpc_server_setup_transport(grpc_exec_ctx *exec_ctx, grpc_server *s, crm = &chand->registered_methods[(hash + probes) % slots]; crm->server_registered_method = rm; crm->flags = rm->flags; - crm->host = host; + crm->has_host = has_host; + if (has_host) { + crm->host = host; + } crm->method = method; } GPR_ASSERT(slots <= UINT32_MAX); @@ -1211,7 +1220,8 @@ void grpc_server_setup_transport(grpc_exec_ctx *exec_ctx, grpc_server *s, op->on_connectivity_state_change = &chand->channel_connectivity_changed; op->connectivity_state = &chand->connectivity_state; if (gpr_atm_acq_load(&s->shutdown_flag) != 0) { - op->disconnect_with_error = GRPC_ERROR_CREATE("Server shutdown"); + op->disconnect_with_error = + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Server shutdown"); } grpc_transport_perform_op(exec_ctx, transport, op); } @@ -1241,9 +1251,15 @@ void grpc_server_shutdown_and_notify(grpc_server *server, GRPC_API_TRACE("grpc_server_shutdown_and_notify(server=%p, cq=%p, tag=%p)", 3, (server, cq, tag)); - /* lock, and gather up some stuff to do */ + /* wait for startup to be finished: locks mu_global */ gpr_mu_lock(&server->mu_global); - grpc_cq_begin_op(cq, tag); + while (server->starting) { + gpr_cv_wait(&server->starting_cv, &server->mu_global, + gpr_inf_future(GPR_CLOCK_REALTIME)); + } + + /* stay locked, and gather up some stuff to do */ + GPR_ASSERT(grpc_cq_begin_op(cq, tag)); if (server->shutdown_published) { grpc_cq_end_op(&exec_ctx, cq, tag, GRPC_ERROR_NONE, done_published_shutdown, NULL, gpr_malloc(sizeof(grpc_cq_completion))); @@ -1269,8 +1285,9 @@ void grpc_server_shutdown_and_notify(grpc_server *server, /* collect all unregistered then registered calls */ gpr_mu_lock(&server->mu_call); - kill_pending_work_locked(&exec_ctx, server, - GRPC_ERROR_CREATE("Server Shutdown")); + kill_pending_work_locked( + &exec_ctx, server, + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Server Shutdown")); gpr_mu_unlock(&server->mu_call); maybe_finish_shutdown(&exec_ctx, server); @@ -1278,7 +1295,8 @@ void grpc_server_shutdown_and_notify(grpc_server *server, /* Shutdown listeners */ for (l = server->listeners; l; l = l->next) { - grpc_closure_init(&l->destroy_done, listener_destroy_done, server); + GRPC_CLOSURE_INIT(&l->destroy_done, listener_destroy_done, server, + grpc_schedule_on_exec_ctx); l->destroy(&exec_ctx, server, l->arg, &l->destroy_done); } @@ -1299,8 +1317,9 @@ void grpc_server_cancel_all_calls(grpc_server *server) { channel_broadcaster_init(server, &broadcaster); gpr_mu_unlock(&server->mu_global); - channel_broadcaster_shutdown(&exec_ctx, &broadcaster, false /* send_goaway */, - GRPC_ERROR_CREATE("Cancelling all calls")); + channel_broadcaster_shutdown( + &exec_ctx, &broadcaster, false /* send_goaway */, + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Cancelling all calls")); grpc_exec_ctx_finish(&exec_ctx); } @@ -1348,16 +1367,16 @@ static grpc_call_error queue_call_request(grpc_exec_ctx *exec_ctx, int request_id; if (gpr_atm_acq_load(&server->shutdown_flag)) { fail_call(exec_ctx, server, cq_idx, rc, - GRPC_ERROR_CREATE("Server Shutdown")); + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Server Shutdown")); return GRPC_CALL_OK; } request_id = gpr_stack_lockfree_pop(server->request_freelist_per_cq[cq_idx]); if (request_id == -1) { /* out of request ids: just fail this one */ fail_call(exec_ctx, server, cq_idx, rc, - grpc_error_set_int(GRPC_ERROR_CREATE("Out of request ids"), - GRPC_ERROR_INT_LIMIT, - server->max_requested_calls_per_cq)); + grpc_error_set_int( + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Out of request ids"), + GRPC_ERROR_INT_LIMIT, server->max_requested_calls_per_cq)); return GRPC_CALL_OK; } switch (rc->type) { @@ -1382,11 +1401,12 @@ static grpc_call_error queue_call_request(grpc_exec_ctx *exec_ctx, gpr_mu_lock(&calld->mu_state); if (calld->state == ZOMBIED) { gpr_mu_unlock(&calld->mu_state); - grpc_closure_init( + GRPC_CLOSURE_INIT( &calld->kill_zombie_closure, kill_zombie, - grpc_call_stack_element(grpc_call_get_call_stack(calld->call), 0)); - grpc_exec_ctx_sched(exec_ctx, &calld->kill_zombie_closure, - GRPC_ERROR_NONE, NULL); + grpc_call_stack_element(grpc_call_get_call_stack(calld->call), 0), + grpc_schedule_on_exec_ctx); + GRPC_CLOSURE_SCHED(exec_ctx, &calld->kill_zombie_closure, + GRPC_ERROR_NONE); } else { GPR_ASSERT(calld->state == PENDING); calld->state = ACTIVATED; @@ -1426,7 +1446,11 @@ grpc_call_error grpc_server_request_call( error = GRPC_CALL_ERROR_NOT_SERVER_COMPLETION_QUEUE; goto done; } - grpc_cq_begin_op(cq_for_notification, tag); + if (grpc_cq_begin_op(cq_for_notification, tag) == false) { + gpr_free(rc); + error = GRPC_CALL_ERROR_COMPLETION_QUEUE_SHUTDOWN; + goto done; + } details->reserved = NULL; rc->cq_idx = cq_idx; rc->type = BATCH_CALL; @@ -1476,7 +1500,11 @@ grpc_call_error grpc_server_request_registered_call( error = GRPC_CALL_ERROR_PAYLOAD_TYPE_MISMATCH; goto done; } - grpc_cq_begin_op(cq_for_notification, tag); + if (grpc_cq_begin_op(cq_for_notification, tag) == false) { + gpr_free(rc); + error = GRPC_CALL_ERROR_COMPLETION_QUEUE_SHUTDOWN; + goto done; + } rc->cq_idx = cq_idx; rc->type = REGISTERED_CALL; rc->server = server; diff --git a/Sources/CgRPC/src/core/lib/surface/server.h b/Sources/CgRPC/src/core/lib/surface/server.h index a85d9f496..dd5639d97 100644 --- a/Sources/CgRPC/src/core/lib/surface/server.h +++ b/Sources/CgRPC/src/core/lib/surface/server.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -36,12 +21,13 @@ #include #include "src/core/lib/channel/channel_stack.h" +#include "src/core/lib/debug/trace.h" #include "src/core/lib/transport/transport.h" extern const grpc_channel_filter grpc_server_top_filter; /** Lightweight tracing of server channel state */ -extern int grpc_server_channel_trace; +extern grpc_tracer_flag grpc_server_channel_trace; /* Add a listener to the server: when the server starts, it will call start, and when it shuts down, it will call destroy */ diff --git a/Sources/CgRPC/src/core/lib/surface/validate_metadata.c b/Sources/CgRPC/src/core/lib/surface/validate_metadata.c index 84f0a083b..61209ae48 100644 --- a/Sources/CgRPC/src/core/lib/surface/validate_metadata.c +++ b/Sources/CgRPC/src/core/lib/surface/validate_metadata.c @@ -1,73 +1,93 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 #include +#include +#include #include -static int conforms_to(const char *s, size_t len, const uint8_t *legal_bits) { - const char *p = s; - const char *e = s + len; +#include "src/core/lib/iomgr/error.h" +#include "src/core/lib/slice/slice_internal.h" +#include "src/core/lib/slice/slice_string_helpers.h" + +static grpc_error *conforms_to(grpc_slice slice, const uint8_t *legal_bits, + const char *err_desc) { + const uint8_t *p = GRPC_SLICE_START_PTR(slice); + const uint8_t *e = GRPC_SLICE_END_PTR(slice); for (; p != e; p++) { - int idx = (uint8_t)*p; + int idx = *p; int byte = idx / 8; int bit = idx % 8; - if ((legal_bits[byte] & (1 << bit)) == 0) return 0; + if ((legal_bits[byte] & (1 << bit)) == 0) { + char *dump = grpc_dump_slice(slice, GPR_DUMP_HEX | GPR_DUMP_ASCII); + grpc_error *error = grpc_error_set_str( + grpc_error_set_int(GRPC_ERROR_CREATE_FROM_COPIED_STRING(err_desc), + GRPC_ERROR_INT_OFFSET, + p - GRPC_SLICE_START_PTR(slice)), + GRPC_ERROR_STR_RAW_BYTES, grpc_slice_from_copied_string(dump)); + gpr_free(dump); + return error; + } } - return 1; + return GRPC_ERROR_NONE; +} + +static int error2int(grpc_error *error) { + int r = (error == GRPC_ERROR_NONE); + GRPC_ERROR_UNREF(error); + return r; } -int grpc_header_key_is_legal(const char *key, size_t length) { +grpc_error *grpc_validate_header_key_is_legal(grpc_slice slice) { static const uint8_t legal_header_bits[256 / 8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0xff, 0x03, 0x00, 0x00, 0x00, 0x80, 0xfe, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - if (length == 0) { - return 0; + if (GRPC_SLICE_LENGTH(slice) == 0) { + return GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "Metadata keys cannot be zero length"); + } + if (GRPC_SLICE_START_PTR(slice)[0] == ':') { + return GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "Metadata keys cannot start with :"); } - return conforms_to(key, length, legal_header_bits); + return conforms_to(slice, legal_header_bits, "Illegal header key"); } -int grpc_header_nonbin_value_is_legal(const char *value, size_t length) { +int grpc_header_key_is_legal(grpc_slice slice) { + return error2int(grpc_validate_header_key_is_legal(slice)); +} + +grpc_error *grpc_validate_header_nonbin_value_is_legal(grpc_slice slice) { static const uint8_t legal_header_bits[256 / 8] = { 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - return conforms_to(value, length, legal_header_bits); + return conforms_to(slice, legal_header_bits, "Illegal header value"); +} + +int grpc_header_nonbin_value_is_legal(grpc_slice slice) { + return error2int(grpc_validate_header_nonbin_value_is_legal(slice)); } -int grpc_is_binary_header(const char *key, size_t length) { - if (length < 5) return 0; - return 0 == memcmp(key + length - 4, "-bin", 4); +int grpc_is_binary_header(grpc_slice slice) { + if (GRPC_SLICE_LENGTH(slice) < 5) return 0; + return 0 == memcmp(GRPC_SLICE_END_PTR(slice) - 4, "-bin", 4); } diff --git a/Sources/CgRPC/src/core/lib/surface/validate_metadata.h b/Sources/CgRPC/src/core/lib/surface/validate_metadata.h new file mode 100644 index 000000000..de869d89b --- /dev/null +++ b/Sources/CgRPC/src/core/lib/surface/validate_metadata.h @@ -0,0 +1,28 @@ +/* + * + * Copyright 2017 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 GRPC_CORE_LIB_SURFACE_VALIDATE_METADATA_H +#define GRPC_CORE_LIB_SURFACE_VALIDATE_METADATA_H + +#include +#include "src/core/lib/iomgr/error.h" + +grpc_error *grpc_validate_header_key_is_legal(grpc_slice slice); +grpc_error *grpc_validate_header_nonbin_value_is_legal(grpc_slice slice); + +#endif /* GRPC_CORE_LIB_SURFACE_VALIDATE_METADATA_H */ diff --git a/Sources/CgRPC/src/core/lib/surface/version.c b/Sources/CgRPC/src/core/lib/surface/version.c index 0db8b41aa..96c16105e 100644 --- a/Sources/CgRPC/src/core/lib/surface/version.c +++ b/Sources/CgRPC/src/core/lib/surface/version.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -36,6 +21,6 @@ #include -const char *grpc_version_string(void) { return "2.0.0-dev"; } +const char *grpc_version_string(void) { return "4.0.0-dev"; } -const char *grpc_g_stands_for(void) { return "good"; } +const char *grpc_g_stands_for(void) { return "gambit"; } diff --git a/Sources/CgRPC/src/core/lib/transport/bdp_estimator.c b/Sources/CgRPC/src/core/lib/transport/bdp_estimator.c new file mode 100644 index 000000000..8b5769341 --- /dev/null +++ b/Sources/CgRPC/src/core/lib/transport/bdp_estimator.c @@ -0,0 +1,110 @@ +/* + * + * Copyright 2016 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 "src/core/lib/transport/bdp_estimator.h" + +#include + +#include +#include + +grpc_tracer_flag grpc_bdp_estimator_trace = + GRPC_TRACER_INITIALIZER(false, "bdp_estimator"); + +void grpc_bdp_estimator_init(grpc_bdp_estimator *estimator, const char *name) { + estimator->estimate = 65536; + estimator->ping_state = GRPC_BDP_PING_UNSCHEDULED; + estimator->name = name; + estimator->bw_est = 0; +} + +bool grpc_bdp_estimator_get_estimate(const grpc_bdp_estimator *estimator, + int64_t *estimate) { + *estimate = estimator->estimate; + return true; +} + +bool grpc_bdp_estimator_get_bw(const grpc_bdp_estimator *estimator, + double *bw) { + *bw = estimator->bw_est; + return true; +} + +void grpc_bdp_estimator_add_incoming_bytes(grpc_bdp_estimator *estimator, + int64_t num_bytes) { + estimator->accumulator += num_bytes; +} + +bool grpc_bdp_estimator_need_ping(const grpc_bdp_estimator *estimator) { + switch (estimator->ping_state) { + case GRPC_BDP_PING_UNSCHEDULED: + return true; + case GRPC_BDP_PING_SCHEDULED: + return false; + case GRPC_BDP_PING_STARTED: + return false; + } + GPR_UNREACHABLE_CODE(return false); +} + +void grpc_bdp_estimator_schedule_ping(grpc_bdp_estimator *estimator) { + if (GRPC_TRACER_ON(grpc_bdp_estimator_trace)) { + gpr_log(GPR_DEBUG, "bdp[%s]:sched acc=%" PRId64 " est=%" PRId64, + estimator->name, estimator->accumulator, estimator->estimate); + } + GPR_ASSERT(estimator->ping_state == GRPC_BDP_PING_UNSCHEDULED); + estimator->ping_state = GRPC_BDP_PING_SCHEDULED; + estimator->accumulator = 0; +} + +void grpc_bdp_estimator_start_ping(grpc_bdp_estimator *estimator) { + if (GRPC_TRACER_ON(grpc_bdp_estimator_trace)) { + gpr_log(GPR_DEBUG, "bdp[%s]:start acc=%" PRId64 " est=%" PRId64, + estimator->name, estimator->accumulator, estimator->estimate); + } + GPR_ASSERT(estimator->ping_state == GRPC_BDP_PING_SCHEDULED); + estimator->ping_state = GRPC_BDP_PING_STARTED; + estimator->accumulator = 0; + estimator->ping_start_time = gpr_now(GPR_CLOCK_MONOTONIC); +} + +void grpc_bdp_estimator_complete_ping(grpc_bdp_estimator *estimator) { + gpr_timespec dt_ts = + gpr_time_sub(gpr_now(GPR_CLOCK_MONOTONIC), estimator->ping_start_time); + double dt = (double)dt_ts.tv_sec + 1e-9 * (double)dt_ts.tv_nsec; + double bw = dt > 0 ? ((double)estimator->accumulator / dt) : 0; + if (GRPC_TRACER_ON(grpc_bdp_estimator_trace)) { + gpr_log(GPR_DEBUG, "bdp[%s]:complete acc=%" PRId64 " est=%" PRId64 + " dt=%lf bw=%lfMbs bw_est=%lfMbs", + estimator->name, estimator->accumulator, estimator->estimate, dt, + bw / 125000.0, estimator->bw_est / 125000.0); + } + GPR_ASSERT(estimator->ping_state == GRPC_BDP_PING_STARTED); + if (estimator->accumulator > 2 * estimator->estimate / 3 && + bw > estimator->bw_est) { + estimator->estimate = + GPR_MAX(estimator->accumulator, estimator->estimate * 2); + estimator->bw_est = bw; + if (GRPC_TRACER_ON(grpc_bdp_estimator_trace)) { + gpr_log(GPR_DEBUG, "bdp[%s]: estimate increased to %" PRId64, + estimator->name, estimator->estimate); + } + } + estimator->ping_state = GRPC_BDP_PING_UNSCHEDULED; + estimator->accumulator = 0; +} diff --git a/Sources/CgRPC/src/core/lib/transport/bdp_estimator.h b/Sources/CgRPC/src/core/lib/transport/bdp_estimator.h new file mode 100644 index 000000000..1ef0dc99d --- /dev/null +++ b/Sources/CgRPC/src/core/lib/transport/bdp_estimator.h @@ -0,0 +1,69 @@ +/* + * + * Copyright 2016 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 GRPC_CORE_LIB_TRANSPORT_BDP_ESTIMATOR_H +#define GRPC_CORE_LIB_TRANSPORT_BDP_ESTIMATOR_H + +#include +#include +#include +#include "src/core/lib/debug/trace.h" + +#define GRPC_BDP_SAMPLES 16 +#define GRPC_BDP_MIN_SAMPLES_FOR_ESTIMATE 3 + +extern grpc_tracer_flag grpc_bdp_estimator_trace; + +typedef enum { + GRPC_BDP_PING_UNSCHEDULED, + GRPC_BDP_PING_SCHEDULED, + GRPC_BDP_PING_STARTED +} grpc_bdp_estimator_ping_state; + +typedef struct grpc_bdp_estimator { + grpc_bdp_estimator_ping_state ping_state; + int64_t accumulator; + int64_t estimate; + gpr_timespec ping_start_time; + double bw_est; + const char *name; +} grpc_bdp_estimator; + +void grpc_bdp_estimator_init(grpc_bdp_estimator *estimator, const char *name); + +// Returns true if a reasonable estimate could be obtained +bool grpc_bdp_estimator_get_estimate(const grpc_bdp_estimator *estimator, + int64_t *estimate); +// Tracks new bytes read. +bool grpc_bdp_estimator_get_bw(const grpc_bdp_estimator *estimator, double *bw); +// Returns true if the user should schedule a ping +void grpc_bdp_estimator_add_incoming_bytes(grpc_bdp_estimator *estimator, + int64_t num_bytes); +// Returns true if the user should schedule a ping +bool grpc_bdp_estimator_need_ping(const grpc_bdp_estimator *estimator); +// Schedule a ping: call in response to receiving a true from +// grpc_bdp_estimator_add_incoming_bytes once a ping has been scheduled by a +// transport (but not necessarily started) +void grpc_bdp_estimator_schedule_ping(grpc_bdp_estimator *estimator); +// Start a ping: call after calling grpc_bdp_estimator_schedule_ping and once +// the ping is on the wire +void grpc_bdp_estimator_start_ping(grpc_bdp_estimator *estimator); +// Completes a previously started ping +void grpc_bdp_estimator_complete_ping(grpc_bdp_estimator *estimator); + +#endif /* GRPC_CORE_LIB_TRANSPORT_BDP_ESTIMATOR_H */ diff --git a/Sources/CgRPC/src/core/lib/transport/byte_stream.c b/Sources/CgRPC/src/core/lib/transport/byte_stream.c index 2f1d7b7c6..fb03a1031 100644 --- a/Sources/CgRPC/src/core/lib/transport/byte_stream.c +++ b/Sources/CgRPC/src/core/lib/transport/byte_stream.c @@ -1,69 +1,96 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 "src/core/lib/transport/byte_stream.h" #include +#include #include -int grpc_byte_stream_next(grpc_exec_ctx *exec_ctx, - grpc_byte_stream *byte_stream, grpc_slice *slice, - size_t max_size_hint, grpc_closure *on_complete) { - return byte_stream->next(exec_ctx, byte_stream, slice, max_size_hint, - on_complete); +#include "src/core/lib/slice/slice_internal.h" + +bool grpc_byte_stream_next(grpc_exec_ctx *exec_ctx, + grpc_byte_stream *byte_stream, size_t max_size_hint, + grpc_closure *on_complete) { + return byte_stream->vtable->next(exec_ctx, byte_stream, max_size_hint, + on_complete); +} + +grpc_error *grpc_byte_stream_pull(grpc_exec_ctx *exec_ctx, + grpc_byte_stream *byte_stream, + grpc_slice *slice) { + return byte_stream->vtable->pull(exec_ctx, byte_stream, slice); +} + +void grpc_byte_stream_shutdown(grpc_exec_ctx *exec_ctx, + grpc_byte_stream *byte_stream, + grpc_error *error) { + byte_stream->vtable->shutdown(exec_ctx, byte_stream, error); } void grpc_byte_stream_destroy(grpc_exec_ctx *exec_ctx, grpc_byte_stream *byte_stream) { - byte_stream->destroy(exec_ctx, byte_stream); + byte_stream->vtable->destroy(exec_ctx, byte_stream); } -/* slice_buffer_stream */ +// grpc_slice_buffer_stream + +static bool slice_buffer_stream_next(grpc_exec_ctx *exec_ctx, + grpc_byte_stream *byte_stream, + size_t max_size_hint, + grpc_closure *on_complete) { + grpc_slice_buffer_stream *stream = (grpc_slice_buffer_stream *)byte_stream; + GPR_ASSERT(stream->cursor < stream->backing_buffer->count); + return true; +} -static int slice_buffer_stream_next(grpc_exec_ctx *exec_ctx, - grpc_byte_stream *byte_stream, - grpc_slice *slice, size_t max_size_hint, - grpc_closure *on_complete) { +static grpc_error *slice_buffer_stream_pull(grpc_exec_ctx *exec_ctx, + grpc_byte_stream *byte_stream, + grpc_slice *slice) { grpc_slice_buffer_stream *stream = (grpc_slice_buffer_stream *)byte_stream; + if (stream->shutdown_error != GRPC_ERROR_NONE) { + return GRPC_ERROR_REF(stream->shutdown_error); + } GPR_ASSERT(stream->cursor < stream->backing_buffer->count); - *slice = grpc_slice_ref(stream->backing_buffer->slices[stream->cursor]); + *slice = + grpc_slice_ref_internal(stream->backing_buffer->slices[stream->cursor]); stream->cursor++; - return 1; + return GRPC_ERROR_NONE; +} + +static void slice_buffer_stream_shutdown(grpc_exec_ctx *exec_ctx, + grpc_byte_stream *byte_stream, + grpc_error *error) { + grpc_slice_buffer_stream *stream = (grpc_slice_buffer_stream *)byte_stream; + GRPC_ERROR_UNREF(stream->shutdown_error); + stream->shutdown_error = error; } static void slice_buffer_stream_destroy(grpc_exec_ctx *exec_ctx, - grpc_byte_stream *byte_stream) {} + grpc_byte_stream *byte_stream) { + grpc_slice_buffer_stream *stream = (grpc_slice_buffer_stream *)byte_stream; + GRPC_ERROR_UNREF(stream->shutdown_error); +} + +static const grpc_byte_stream_vtable slice_buffer_stream_vtable = { + slice_buffer_stream_next, slice_buffer_stream_pull, + slice_buffer_stream_shutdown, slice_buffer_stream_destroy}; void grpc_slice_buffer_stream_init(grpc_slice_buffer_stream *stream, grpc_slice_buffer *slice_buffer, @@ -71,8 +98,89 @@ void grpc_slice_buffer_stream_init(grpc_slice_buffer_stream *stream, GPR_ASSERT(slice_buffer->length <= UINT32_MAX); stream->base.length = (uint32_t)slice_buffer->length; stream->base.flags = flags; - stream->base.next = slice_buffer_stream_next; - stream->base.destroy = slice_buffer_stream_destroy; + stream->base.vtable = &slice_buffer_stream_vtable; stream->backing_buffer = slice_buffer; stream->cursor = 0; + stream->shutdown_error = GRPC_ERROR_NONE; +} + +// grpc_caching_byte_stream + +void grpc_byte_stream_cache_init(grpc_byte_stream_cache *cache, + grpc_byte_stream *underlying_stream) { + cache->underlying_stream = underlying_stream; + grpc_slice_buffer_init(&cache->cache_buffer); +} + +void grpc_byte_stream_cache_destroy(grpc_exec_ctx *exec_ctx, + grpc_byte_stream_cache *cache) { + grpc_byte_stream_destroy(exec_ctx, cache->underlying_stream); + grpc_slice_buffer_destroy_internal(exec_ctx, &cache->cache_buffer); +} + +static bool caching_byte_stream_next(grpc_exec_ctx *exec_ctx, + grpc_byte_stream *byte_stream, + size_t max_size_hint, + grpc_closure *on_complete) { + grpc_caching_byte_stream *stream = (grpc_caching_byte_stream *)byte_stream; + if (stream->shutdown_error != GRPC_ERROR_NONE) return true; + if (stream->cursor < stream->cache->cache_buffer.count) return true; + return grpc_byte_stream_next(exec_ctx, stream->cache->underlying_stream, + max_size_hint, on_complete); +} + +static grpc_error *caching_byte_stream_pull(grpc_exec_ctx *exec_ctx, + grpc_byte_stream *byte_stream, + grpc_slice *slice) { + grpc_caching_byte_stream *stream = (grpc_caching_byte_stream *)byte_stream; + if (stream->shutdown_error != GRPC_ERROR_NONE) { + return GRPC_ERROR_REF(stream->shutdown_error); + } + if (stream->cursor < stream->cache->cache_buffer.count) { + *slice = grpc_slice_ref_internal( + stream->cache->cache_buffer.slices[stream->cursor]); + ++stream->cursor; + return GRPC_ERROR_NONE; + } + grpc_error *error = + grpc_byte_stream_pull(exec_ctx, stream->cache->underlying_stream, slice); + if (error == GRPC_ERROR_NONE) { + ++stream->cursor; + grpc_slice_buffer_add(&stream->cache->cache_buffer, + grpc_slice_ref_internal(*slice)); + } + return error; +} + +static void caching_byte_stream_shutdown(grpc_exec_ctx *exec_ctx, + grpc_byte_stream *byte_stream, + grpc_error *error) { + grpc_caching_byte_stream *stream = (grpc_caching_byte_stream *)byte_stream; + GRPC_ERROR_UNREF(stream->shutdown_error); + stream->shutdown_error = GRPC_ERROR_REF(error); + grpc_byte_stream_shutdown(exec_ctx, stream->cache->underlying_stream, error); +} + +static void caching_byte_stream_destroy(grpc_exec_ctx *exec_ctx, + grpc_byte_stream *byte_stream) { + grpc_caching_byte_stream *stream = (grpc_caching_byte_stream *)byte_stream; + GRPC_ERROR_UNREF(stream->shutdown_error); +} + +static const grpc_byte_stream_vtable caching_byte_stream_vtable = { + caching_byte_stream_next, caching_byte_stream_pull, + caching_byte_stream_shutdown, caching_byte_stream_destroy}; + +void grpc_caching_byte_stream_init(grpc_caching_byte_stream *stream, + grpc_byte_stream_cache *cache) { + memset(stream, 0, sizeof(*stream)); + stream->base.length = cache->underlying_stream->length; + stream->base.flags = cache->underlying_stream->flags; + stream->base.vtable = &caching_byte_stream_vtable; + stream->cache = cache; + stream->shutdown_error = GRPC_ERROR_NONE; +} + +void grpc_caching_byte_stream_reset(grpc_caching_byte_stream *stream) { + stream->cursor = 0; } diff --git a/Sources/CgRPC/src/core/lib/transport/byte_stream.h b/Sources/CgRPC/src/core/lib/transport/byte_stream.h index 1fdd5b4d7..1e1e8310b 100644 --- a/Sources/CgRPC/src/core/lib/transport/byte_stream.h +++ b/Sources/CgRPC/src/core/lib/transport/byte_stream.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -43,43 +28,109 @@ /** Mask of all valid internal flags. */ #define GRPC_WRITE_INTERNAL_USED_MASK (GRPC_WRITE_INTERNAL_COMPRESS) -struct grpc_byte_stream; typedef struct grpc_byte_stream grpc_byte_stream; +typedef struct { + bool (*next)(grpc_exec_ctx *exec_ctx, grpc_byte_stream *byte_stream, + size_t max_size_hint, grpc_closure *on_complete); + grpc_error *(*pull)(grpc_exec_ctx *exec_ctx, grpc_byte_stream *byte_stream, + grpc_slice *slice); + void (*shutdown)(grpc_exec_ctx *exec_ctx, grpc_byte_stream *byte_stream, + grpc_error *error); + void (*destroy)(grpc_exec_ctx *exec_ctx, grpc_byte_stream *byte_stream); +} grpc_byte_stream_vtable; + struct grpc_byte_stream { uint32_t length; uint32_t flags; - int (*next)(grpc_exec_ctx *exec_ctx, grpc_byte_stream *byte_stream, - grpc_slice *slice, size_t max_size_hint, - grpc_closure *on_complete); - void (*destroy)(grpc_exec_ctx *exec_ctx, grpc_byte_stream *byte_stream); + const grpc_byte_stream_vtable *vtable; }; -/* returns 1 if the bytes are available immediately (in which case - * on_complete will not be called), 0 if the bytes will be available - * asynchronously. - * - * max_size_hint can be set as a hint as to the maximum number - * of bytes that would be acceptable to read. - * - * once a slice is returned into *slice, it is owned by the caller. - */ -int grpc_byte_stream_next(grpc_exec_ctx *exec_ctx, - grpc_byte_stream *byte_stream, grpc_slice *slice, - size_t max_size_hint, grpc_closure *on_complete); +// Returns true if the bytes are available immediately (in which case +// on_complete will not be called), false if the bytes will be available +// asynchronously. +// +// max_size_hint can be set as a hint as to the maximum number +// of bytes that would be acceptable to read. +bool grpc_byte_stream_next(grpc_exec_ctx *exec_ctx, + grpc_byte_stream *byte_stream, size_t max_size_hint, + grpc_closure *on_complete); + +// Returns the next slice in the byte stream when it is ready (indicated by +// either grpc_byte_stream_next returning true or on_complete passed to +// grpc_byte_stream_next is called). +// +// Once a slice is returned into *slice, it is owned by the caller. +grpc_error *grpc_byte_stream_pull(grpc_exec_ctx *exec_ctx, + grpc_byte_stream *byte_stream, + grpc_slice *slice); + +// Shuts down the byte stream. +// +// If there is a pending call to on_complete from grpc_byte_stream_next(), +// it will be invoked with the error passed to grpc_byte_stream_shutdown(). +// +// The next call to grpc_byte_stream_pull() (if any) will return the error +// passed to grpc_byte_stream_shutdown(). +void grpc_byte_stream_shutdown(grpc_exec_ctx *exec_ctx, + grpc_byte_stream *byte_stream, + grpc_error *error); void grpc_byte_stream_destroy(grpc_exec_ctx *exec_ctx, grpc_byte_stream *byte_stream); -/* grpc_byte_stream that wraps a slice buffer */ +// grpc_slice_buffer_stream +// +// A grpc_byte_stream that wraps a slice buffer. + typedef struct grpc_slice_buffer_stream { grpc_byte_stream base; grpc_slice_buffer *backing_buffer; size_t cursor; + grpc_error *shutdown_error; } grpc_slice_buffer_stream; void grpc_slice_buffer_stream_init(grpc_slice_buffer_stream *stream, grpc_slice_buffer *slice_buffer, uint32_t flags); +// grpc_caching_byte_stream +// +// A grpc_byte_stream that that wraps an underlying byte stream but caches +// the resulting slices in a slice buffer. If an initial attempt fails +// without fully draining the underlying stream, a new caching stream +// can be created from the same underlying cache, in which case it will +// return whatever is in the backing buffer before continuing to read the +// underlying stream. +// +// NOTE: No synchronization is done, so it is not safe to have multiple +// grpc_caching_byte_streams simultaneously drawing from the same underlying +// grpc_byte_stream_cache at the same time. + +typedef struct { + grpc_byte_stream *underlying_stream; + grpc_slice_buffer cache_buffer; +} grpc_byte_stream_cache; + +// Takes ownership of underlying_stream. +void grpc_byte_stream_cache_init(grpc_byte_stream_cache *cache, + grpc_byte_stream *underlying_stream); + +// Must not be called while still in use by a grpc_caching_byte_stream. +void grpc_byte_stream_cache_destroy(grpc_exec_ctx *exec_ctx, + grpc_byte_stream_cache *cache); + +typedef struct { + grpc_byte_stream base; + grpc_byte_stream_cache *cache; + size_t cursor; + grpc_error *shutdown_error; +} grpc_caching_byte_stream; + +void grpc_caching_byte_stream_init(grpc_caching_byte_stream *stream, + grpc_byte_stream_cache *cache); + +// Resets the byte stream to the start of the underlying stream. +void grpc_caching_byte_stream_reset(grpc_caching_byte_stream *stream); + #endif /* GRPC_CORE_LIB_TRANSPORT_BYTE_STREAM_H */ diff --git a/Sources/CgRPC/src/core/lib/transport/connectivity_state.c b/Sources/CgRPC/src/core/lib/transport/connectivity_state.c index 4f49d7cf7..73a9178ae 100644 --- a/Sources/CgRPC/src/core/lib/transport/connectivity_state.c +++ b/Sources/CgRPC/src/core/lib/transport/connectivity_state.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -39,7 +24,8 @@ #include #include -int grpc_connectivity_state_trace = 0; +grpc_tracer_flag grpc_connectivity_state_trace = + GRPC_TRACER_INITIALIZER(false, "connectivity_state"); const char *grpc_connectivity_state_name(grpc_connectivity_state state) { switch (state) { @@ -62,7 +48,7 @@ const char *grpc_connectivity_state_name(grpc_connectivity_state state) { void grpc_connectivity_state_init(grpc_connectivity_state_tracker *tracker, grpc_connectivity_state init_state, const char *name) { - tracker->current_state = init_state; + gpr_atm_no_barrier_store(&tracker->current_state_atm, init_state); tracker->current_error = GRPC_ERROR_NONE; tracker->watchers = NULL; tracker->name = gpr_strdup(name); @@ -79,9 +65,10 @@ void grpc_connectivity_state_destroy(grpc_exec_ctx *exec_ctx, *w->current = GRPC_CHANNEL_SHUTDOWN; error = GRPC_ERROR_NONE; } else { - error = GRPC_ERROR_CREATE("Shutdown connectivity owner"); + error = + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Shutdown connectivity owner"); } - grpc_exec_ctx_sched(exec_ctx, w->notify, error, NULL); + GRPC_CLOSURE_SCHED(exec_ctx, w->notify, error); gpr_free(w); } GRPC_ERROR_UNREF(tracker->current_error); @@ -89,15 +76,30 @@ void grpc_connectivity_state_destroy(grpc_exec_ctx *exec_ctx, } grpc_connectivity_state grpc_connectivity_state_check( + grpc_connectivity_state_tracker *tracker) { + grpc_connectivity_state cur = + (grpc_connectivity_state)gpr_atm_no_barrier_load( + &tracker->current_state_atm); + if (GRPC_TRACER_ON(grpc_connectivity_state_trace)) { + gpr_log(GPR_DEBUG, "CONWATCH: %p %s: get %s", tracker, tracker->name, + grpc_connectivity_state_name(cur)); + } + return cur; +} + +grpc_connectivity_state grpc_connectivity_state_get( grpc_connectivity_state_tracker *tracker, grpc_error **error) { - if (grpc_connectivity_state_trace) { + grpc_connectivity_state cur = + (grpc_connectivity_state)gpr_atm_no_barrier_load( + &tracker->current_state_atm); + if (GRPC_TRACER_ON(grpc_connectivity_state_trace)) { gpr_log(GPR_DEBUG, "CONWATCH: %p %s: get %s", tracker, tracker->name, - grpc_connectivity_state_name(tracker->current_state)); + grpc_connectivity_state_name(cur)); } if (error != NULL) { *error = GRPC_ERROR_REF(tracker->current_error); } - return tracker->current_state; + return cur; } bool grpc_connectivity_state_has_watchers( @@ -108,20 +110,23 @@ bool grpc_connectivity_state_has_watchers( bool grpc_connectivity_state_notify_on_state_change( grpc_exec_ctx *exec_ctx, grpc_connectivity_state_tracker *tracker, grpc_connectivity_state *current, grpc_closure *notify) { - if (grpc_connectivity_state_trace) { + grpc_connectivity_state cur = + (grpc_connectivity_state)gpr_atm_no_barrier_load( + &tracker->current_state_atm); + if (GRPC_TRACER_ON(grpc_connectivity_state_trace)) { if (current == NULL) { gpr_log(GPR_DEBUG, "CONWATCH: %p %s: unsubscribe notify=%p", tracker, tracker->name, notify); } else { gpr_log(GPR_DEBUG, "CONWATCH: %p %s: from %s [cur=%s] notify=%p", tracker, tracker->name, grpc_connectivity_state_name(*current), - grpc_connectivity_state_name(tracker->current_state), notify); + grpc_connectivity_state_name(cur), notify); } } if (current == NULL) { grpc_connectivity_state_watcher *w = tracker->watchers; if (w != NULL && w->notify == notify) { - grpc_exec_ctx_sched(exec_ctx, notify, GRPC_ERROR_CANCELLED, NULL); + GRPC_CLOSURE_SCHED(exec_ctx, notify, GRPC_ERROR_CANCELLED); tracker->watchers = w->next; gpr_free(w); return false; @@ -129,7 +134,7 @@ bool grpc_connectivity_state_notify_on_state_change( while (w != NULL) { grpc_connectivity_state_watcher *rm_candidate = w->next; if (rm_candidate != NULL && rm_candidate->notify == notify) { - grpc_exec_ctx_sched(exec_ctx, notify, GRPC_ERROR_CANCELLED, NULL); + GRPC_CLOSURE_SCHED(exec_ctx, notify, GRPC_ERROR_CANCELLED); w->next = w->next->next; gpr_free(rm_candidate); return false; @@ -138,10 +143,10 @@ bool grpc_connectivity_state_notify_on_state_change( } return false; } else { - if (tracker->current_state != *current) { - *current = tracker->current_state; - grpc_exec_ctx_sched(exec_ctx, notify, - GRPC_ERROR_REF(tracker->current_error), NULL); + if (cur != *current) { + *current = cur; + GRPC_CLOSURE_SCHED(exec_ctx, notify, + GRPC_ERROR_REF(tracker->current_error)); } else { grpc_connectivity_state_watcher *w = gpr_malloc(sizeof(*w)); w->current = current; @@ -149,7 +154,7 @@ bool grpc_connectivity_state_notify_on_state_change( w->next = tracker->watchers; tracker->watchers = w; } - return tracker->current_state == GRPC_CHANNEL_IDLE; + return cur == GRPC_CHANNEL_IDLE; } } @@ -157,13 +162,15 @@ void grpc_connectivity_state_set(grpc_exec_ctx *exec_ctx, grpc_connectivity_state_tracker *tracker, grpc_connectivity_state state, grpc_error *error, const char *reason) { + grpc_connectivity_state cur = + (grpc_connectivity_state)gpr_atm_no_barrier_load( + &tracker->current_state_atm); grpc_connectivity_state_watcher *w; - if (grpc_connectivity_state_trace) { + if (GRPC_TRACER_ON(grpc_connectivity_state_trace)) { const char *error_string = grpc_error_string(error); gpr_log(GPR_DEBUG, "SET: %p %s: %s --> %s [%s] error=%p %s", tracker, - tracker->name, grpc_connectivity_state_name(tracker->current_state), + tracker->name, grpc_connectivity_state_name(cur), grpc_connectivity_state_name(state), reason, error, error_string); - grpc_error_free_string(error_string); } switch (state) { case GRPC_CHANNEL_INIT: @@ -179,20 +186,20 @@ void grpc_connectivity_state_set(grpc_exec_ctx *exec_ctx, } GRPC_ERROR_UNREF(tracker->current_error); tracker->current_error = error; - if (tracker->current_state == state) { + if (cur == state) { return; } - GPR_ASSERT(tracker->current_state != GRPC_CHANNEL_SHUTDOWN); - tracker->current_state = state; + GPR_ASSERT(cur != GRPC_CHANNEL_SHUTDOWN); + gpr_atm_no_barrier_store(&tracker->current_state_atm, state); while ((w = tracker->watchers) != NULL) { - *w->current = tracker->current_state; + *w->current = state; tracker->watchers = w->next; - if (grpc_connectivity_state_trace) { + if (GRPC_TRACER_ON(grpc_connectivity_state_trace)) { gpr_log(GPR_DEBUG, "NOTIFY: %p %s: %p", tracker, tracker->name, w->notify); } - grpc_exec_ctx_sched(exec_ctx, w->notify, - GRPC_ERROR_REF(tracker->current_error), NULL); + GRPC_CLOSURE_SCHED(exec_ctx, w->notify, + GRPC_ERROR_REF(tracker->current_error)); gpr_free(w); } } diff --git a/Sources/CgRPC/src/core/lib/transport/connectivity_state.h b/Sources/CgRPC/src/core/lib/transport/connectivity_state.h index 769c675b7..2fece6cc2 100644 --- a/Sources/CgRPC/src/core/lib/transport/connectivity_state.h +++ b/Sources/CgRPC/src/core/lib/transport/connectivity_state.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -35,6 +20,7 @@ #define GRPC_CORE_LIB_TRANSPORT_CONNECTIVITY_STATE_H #include +#include "src/core/lib/debug/trace.h" #include "src/core/lib/iomgr/exec_ctx.h" typedef struct grpc_connectivity_state_watcher { @@ -47,8 +33,8 @@ typedef struct grpc_connectivity_state_watcher { } grpc_connectivity_state_watcher; typedef struct { - /** current connectivity state */ - grpc_connectivity_state current_state; + /** current grpc_connectivity_state */ + gpr_atm current_state_atm; /** error associated with state */ grpc_error *current_error; /** all our watchers */ @@ -57,8 +43,9 @@ typedef struct { char *name; } grpc_connectivity_state_tracker; -extern int grpc_connectivity_state_trace; +extern grpc_tracer_flag grpc_connectivity_state_trace; +/** enum --> string conversion */ const char *grpc_connectivity_state_name(grpc_connectivity_state state); void grpc_connectivity_state_init(grpc_connectivity_state_tracker *tracker, @@ -68,22 +55,31 @@ void grpc_connectivity_state_destroy(grpc_exec_ctx *exec_ctx, grpc_connectivity_state_tracker *tracker); /** Set connectivity state; not thread safe; access must be serialized with an - * external lock */ + * external lock */ void grpc_connectivity_state_set(grpc_exec_ctx *exec_ctx, grpc_connectivity_state_tracker *tracker, grpc_connectivity_state state, grpc_error *associated_error, const char *reason); +/** Return true if this connectivity state has watchers. + Access must be serialized with an external lock. */ bool grpc_connectivity_state_has_watchers( grpc_connectivity_state_tracker *tracker); +/** Return the last seen connectivity state. No need to synchronize access. */ grpc_connectivity_state grpc_connectivity_state_check( - grpc_connectivity_state_tracker *tracker, grpc_error **current_error); + grpc_connectivity_state_tracker *tracker); + +/** Return the last seen connectivity state, and the associated error. + Access must be serialized with an external lock. */ +grpc_connectivity_state grpc_connectivity_state_get( + grpc_connectivity_state_tracker *tracker, grpc_error **error); /** Return 1 if the channel should start connecting, 0 otherwise. If current==NULL cancel notify if it is already queued (success==0 in that - case) */ + case). + Access must be serialized with an external lock. */ bool grpc_connectivity_state_notify_on_state_change( grpc_exec_ctx *exec_ctx, grpc_connectivity_state_tracker *tracker, grpc_connectivity_state *current, grpc_closure *notify); diff --git a/Sources/CgRPC/src/core/lib/transport/error_utils.c b/Sources/CgRPC/src/core/lib/transport/error_utils.c new file mode 100644 index 000000000..5e3920b62 --- /dev/null +++ b/Sources/CgRPC/src/core/lib/transport/error_utils.c @@ -0,0 +1,109 @@ +/* + * + * Copyright 2016 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 "src/core/lib/transport/error_utils.h" + +#include "src/core/lib/iomgr/error_internal.h" +#include "src/core/lib/transport/status_conversion.h" + +static grpc_error *recursively_find_error_with_field(grpc_error *error, + grpc_error_ints which) { + // If the error itself has a status code, return it. + if (grpc_error_get_int(error, which, NULL)) { + return error; + } + if (grpc_error_is_special(error)) return NULL; + // Otherwise, search through its children. + uint8_t slot = error->first_err; + while (slot != UINT8_MAX) { + grpc_linked_error *lerr = (grpc_linked_error *)(error->arena + slot); + grpc_error *result = recursively_find_error_with_field(lerr->err, which); + if (result) return result; + slot = lerr->next; + } + return NULL; +} + +void grpc_error_get_status(grpc_error *error, gpr_timespec deadline, + grpc_status_code *code, grpc_slice *slice, + grpc_http2_error_code *http_error) { + // Start with the parent error and recurse through the tree of children + // until we find the first one that has a status code. + grpc_error *found_error = + recursively_find_error_with_field(error, GRPC_ERROR_INT_GRPC_STATUS); + if (found_error == NULL) { + /// If no grpc-status exists, retry through the tree to find a http2 error + /// code + found_error = + recursively_find_error_with_field(error, GRPC_ERROR_INT_HTTP2_ERROR); + } + + // If we found an error with a status code above, use that; otherwise, + // fall back to using the parent error. + if (found_error == NULL) found_error = error; + + grpc_status_code status = GRPC_STATUS_UNKNOWN; + intptr_t integer; + if (grpc_error_get_int(found_error, GRPC_ERROR_INT_GRPC_STATUS, &integer)) { + status = (grpc_status_code)integer; + } else if (grpc_error_get_int(found_error, GRPC_ERROR_INT_HTTP2_ERROR, + &integer)) { + status = grpc_http2_error_to_grpc_status((grpc_http2_error_code)integer, + deadline); + } + if (code != NULL) *code = status; + + if (http_error != NULL) { + if (grpc_error_get_int(found_error, GRPC_ERROR_INT_HTTP2_ERROR, &integer)) { + *http_error = (grpc_http2_error_code)integer; + } else if (grpc_error_get_int(found_error, GRPC_ERROR_INT_GRPC_STATUS, + &integer)) { + *http_error = grpc_status_to_http2_error((grpc_status_code)integer); + } else { + *http_error = found_error == GRPC_ERROR_NONE ? GRPC_HTTP2_NO_ERROR + : GRPC_HTTP2_INTERNAL_ERROR; + } + } + + // If the error has a status message, use it. Otherwise, fall back to + // the error description. + if (slice != NULL) { + if (!grpc_error_get_str(found_error, GRPC_ERROR_STR_GRPC_MESSAGE, slice)) { + if (!grpc_error_get_str(found_error, GRPC_ERROR_STR_DESCRIPTION, slice)) { + *slice = grpc_slice_from_static_string("unknown error"); + } + } + } + + if (found_error == NULL) found_error = error; +} + +bool grpc_error_has_clear_grpc_status(grpc_error *error) { + if (grpc_error_get_int(error, GRPC_ERROR_INT_GRPC_STATUS, NULL)) { + return true; + } + uint8_t slot = error->first_err; + while (slot != UINT8_MAX) { + grpc_linked_error *lerr = (grpc_linked_error *)(error->arena + slot); + if (grpc_error_has_clear_grpc_status(lerr->err)) { + return true; + } + slot = lerr->next; + } + return false; +} diff --git a/Sources/CgRPC/src/core/lib/transport/error_utils.h b/Sources/CgRPC/src/core/lib/transport/error_utils.h new file mode 100644 index 000000000..e53088421 --- /dev/null +++ b/Sources/CgRPC/src/core/lib/transport/error_utils.h @@ -0,0 +1,41 @@ +/* + * + * Copyright 2016 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 GRPC_CORE_LIB_TRANSPORT_ERROR_UTILS_H +#define GRPC_CORE_LIB_TRANSPORT_ERROR_UTILS_H + +#include "src/core/lib/iomgr/error.h" +#include "src/core/lib/transport/http2_errors.h" + +/// A utility function to get the status code and message to be returned +/// to the application. If not set in the top-level message, looks +/// through child errors until it finds the first one with these attributes. +/// All attributes are pulled from the same child error. If any of the +/// attributes (code, msg, http_status) are unneeded, they can be passed as +/// NULL. +void grpc_error_get_status(grpc_error *error, gpr_timespec deadline, + grpc_status_code *code, grpc_slice *slice, + grpc_http2_error_code *http_status); + +/// A utility function to check whether there is a clear status code that +/// doesn't need to be guessed in \a error. This means that \a error or some +/// child has GRPC_ERROR_INT_GRPC_STATUS set, or that it is GRPC_ERROR_NONE or +/// GRPC_ERROR_CANCELLED +bool grpc_error_has_clear_grpc_status(grpc_error *error); + +#endif /* GRPC_CORE_LIB_TRANSPORT_ERROR_UTILS_H */ diff --git a/Sources/CgRPC/src/core/lib/transport/http2_errors.h b/Sources/CgRPC/src/core/lib/transport/http2_errors.h new file mode 100644 index 000000000..d412c5dff --- /dev/null +++ b/Sources/CgRPC/src/core/lib/transport/http2_errors.h @@ -0,0 +1,41 @@ +/* + * + * 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 GRPC_CORE_LIB_TRANSPORT_HTTP2_ERRORS_H +#define GRPC_CORE_LIB_TRANSPORT_HTTP2_ERRORS_H + +/* error codes for RST_STREAM from http2 draft 14 section 7 */ +typedef enum { + GRPC_HTTP2_NO_ERROR = 0x0, + GRPC_HTTP2_PROTOCOL_ERROR = 0x1, + GRPC_HTTP2_INTERNAL_ERROR = 0x2, + GRPC_HTTP2_FLOW_CONTROL_ERROR = 0x3, + GRPC_HTTP2_SETTINGS_TIMEOUT = 0x4, + GRPC_HTTP2_STREAM_CLOSED = 0x5, + GRPC_HTTP2_FRAME_SIZE_ERROR = 0x6, + GRPC_HTTP2_REFUSED_STREAM = 0x7, + GRPC_HTTP2_CANCEL = 0x8, + GRPC_HTTP2_COMPRESSION_ERROR = 0x9, + GRPC_HTTP2_CONNECT_ERROR = 0xa, + GRPC_HTTP2_ENHANCE_YOUR_CALM = 0xb, + GRPC_HTTP2_INADEQUATE_SECURITY = 0xc, + /* force use of a default clause */ + GRPC_HTTP2__ERROR_DO_NOT_USE = -1 +} grpc_http2_error_code; + +#endif /* GRPC_CORE_LIB_TRANSPORT_HTTP2_ERRORS_H */ diff --git a/Sources/CgRPC/src/core/lib/transport/mdstr_hash_table.c b/Sources/CgRPC/src/core/lib/transport/mdstr_hash_table.c deleted file mode 100644 index 3d01e56df..000000000 --- a/Sources/CgRPC/src/core/lib/transport/mdstr_hash_table.c +++ /dev/null @@ -1,117 +0,0 @@ -// -// Copyright 2016, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// - -#include "src/core/lib/transport/mdstr_hash_table.h" - -#include -#include - -#include -#include - -#include "src/core/lib/transport/metadata.h" - -struct grpc_mdstr_hash_table { - gpr_refcount refs; - size_t size; - grpc_mdstr_hash_table_entry* entries; -}; - -// Helper function for insert and get operations that performs quadratic -// probing (https://en.wikipedia.org/wiki/Quadratic_probing). -static size_t grpc_mdstr_hash_table_find_index( - const grpc_mdstr_hash_table* table, const grpc_mdstr* key, - bool find_empty) { - for (size_t i = 0; i < table->size; ++i) { - const size_t idx = (key->hash + i * i) % table->size; - if (table->entries[idx].key == NULL) return find_empty ? idx : table->size; - if (table->entries[idx].key == key) return idx; - } - return table->size; // Not found. -} - -static void grpc_mdstr_hash_table_add( - grpc_mdstr_hash_table* table, grpc_mdstr* key, void* value, - const grpc_mdstr_hash_table_vtable* vtable) { - GPR_ASSERT(value != NULL); - const size_t idx = - grpc_mdstr_hash_table_find_index(table, key, true /* find_empty */); - GPR_ASSERT(idx != table->size); // Table should never be full. - grpc_mdstr_hash_table_entry* entry = &table->entries[idx]; - entry->key = GRPC_MDSTR_REF(key); - entry->value = vtable->copy_value(value); - entry->vtable = vtable; -} - -grpc_mdstr_hash_table* grpc_mdstr_hash_table_create( - size_t num_entries, grpc_mdstr_hash_table_entry* entries) { - grpc_mdstr_hash_table* table = gpr_malloc(sizeof(*table)); - memset(table, 0, sizeof(*table)); - gpr_ref_init(&table->refs, 1); - // Quadratic probing gets best performance when the table is no more - // than half full. - table->size = num_entries * 2; - const size_t entry_size = sizeof(grpc_mdstr_hash_table_entry) * table->size; - table->entries = gpr_malloc(entry_size); - memset(table->entries, 0, entry_size); - for (size_t i = 0; i < num_entries; ++i) { - grpc_mdstr_hash_table_entry* entry = &entries[i]; - grpc_mdstr_hash_table_add(table, entry->key, entry->value, entry->vtable); - } - return table; -} - -grpc_mdstr_hash_table* grpc_mdstr_hash_table_ref(grpc_mdstr_hash_table* table) { - if (table != NULL) gpr_ref(&table->refs); - return table; -} - -void grpc_mdstr_hash_table_unref(grpc_mdstr_hash_table* table) { - if (table != NULL && gpr_unref(&table->refs)) { - for (size_t i = 0; i < table->size; ++i) { - grpc_mdstr_hash_table_entry* entry = &table->entries[i]; - if (entry->key != NULL) { - GRPC_MDSTR_UNREF(entry->key); - entry->vtable->destroy_value(entry->value); - } - } - gpr_free(table->entries); - gpr_free(table); - } -} - -void* grpc_mdstr_hash_table_get(const grpc_mdstr_hash_table* table, - const grpc_mdstr* key) { - const size_t idx = - grpc_mdstr_hash_table_find_index(table, key, false /* find_empty */); - if (idx == table->size) return NULL; // Not found. - return table->entries[idx].value; -} diff --git a/Sources/CgRPC/src/core/lib/transport/mdstr_hash_table.h b/Sources/CgRPC/src/core/lib/transport/mdstr_hash_table.h deleted file mode 100644 index 8982ec3a8..000000000 --- a/Sources/CgRPC/src/core/lib/transport/mdstr_hash_table.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2016, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef GRPC_CORE_LIB_TRANSPORT_MDSTR_HASH_TABLE_H -#define GRPC_CORE_LIB_TRANSPORT_MDSTR_HASH_TABLE_H - -#include "src/core/lib/transport/metadata.h" - -/** Hash table implementation. - * - * This implementation uses open addressing - * (https://en.wikipedia.org/wiki/Open_addressing) with quadratic - * probing (https://en.wikipedia.org/wiki/Quadratic_probing). - * - * The keys are \a grpc_mdstr objects. The values are arbitrary pointers - * with a common vtable. - * - * Hash tables are intentionally immutable, to avoid the need for locking. - */ - -typedef struct grpc_mdstr_hash_table grpc_mdstr_hash_table; - -typedef struct grpc_mdstr_hash_table_vtable { - void (*destroy_value)(void* value); - void* (*copy_value)(void* value); -} grpc_mdstr_hash_table_vtable; - -typedef struct grpc_mdstr_hash_table_entry { - grpc_mdstr* key; - void* value; /* Must not be NULL. */ - const grpc_mdstr_hash_table_vtable* vtable; -} grpc_mdstr_hash_table_entry; - -/** Creates a new hash table of containing \a entries, which is an array - of length \a num_entries. - Creates its own copy of all keys and values from \a entries. */ -grpc_mdstr_hash_table* grpc_mdstr_hash_table_create( - size_t num_entries, grpc_mdstr_hash_table_entry* entries); - -grpc_mdstr_hash_table* grpc_mdstr_hash_table_ref(grpc_mdstr_hash_table* table); -void grpc_mdstr_hash_table_unref(grpc_mdstr_hash_table* table); - -/** Returns the value from \a table associated with \a key. - Returns NULL if \a key is not found. */ -void* grpc_mdstr_hash_table_get(const grpc_mdstr_hash_table* table, - const grpc_mdstr* key); - -#endif /* GRPC_CORE_LIB_TRANSPORT_MDSTR_HASH_TABLE_H */ diff --git a/Sources/CgRPC/src/core/lib/transport/metadata.c b/Sources/CgRPC/src/core/lib/transport/metadata.c index fac19b91d..2fea36607 100644 --- a/Sources/CgRPC/src/core/lib/transport/metadata.c +++ b/Sources/CgRPC/src/core/lib/transport/metadata.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -47,12 +32,12 @@ #include "src/core/lib/iomgr/iomgr_internal.h" #include "src/core/lib/profiling/timers.h" +#include "src/core/lib/slice/slice_internal.h" +#include "src/core/lib/slice/slice_string_helpers.h" #include "src/core/lib/support/murmur_hash.h" #include "src/core/lib/support/string.h" #include "src/core/lib/transport/static_metadata.h" -grpc_slice (*grpc_chttp2_base64_encode_and_huffman_compress)(grpc_slice input); - /* There are two kinds of mdelem and mdstr instances. * Static instances are declared in static_metadata.{h,c} and * are initialized by grpc_mdctx_global_init(). @@ -62,10 +47,9 @@ grpc_slice (*grpc_chttp2_base64_encode_and_huffman_compress)(grpc_slice input); * used to determine which kind of element a pointer refers to. */ -#define INITIAL_STRTAB_CAPACITY 4 -#define INITIAL_MDTAB_CAPACITY 4 - -#ifdef GRPC_METADATA_REFCOUNT_DEBUG +#ifndef NDEBUG +grpc_tracer_flag grpc_trace_metadata = + GRPC_TRACER_INITIALIZER(false, "metadata"); #define DEBUG_ARGS , const char *file, int line #define FWD_DEBUG_ARGS , file, line #define REF_MD_LOCKED(shard, s) ref_md_locked((shard), (s), __FILE__, __LINE__) @@ -75,37 +59,20 @@ grpc_slice (*grpc_chttp2_base64_encode_and_huffman_compress)(grpc_slice input); #define REF_MD_LOCKED(shard, s) ref_md_locked((shard), (s)) #endif -#define TABLE_IDX(hash, log2_shards, capacity) \ - (((hash) >> (log2_shards)) % (capacity)) -#define SHARD_IDX(hash, log2_shards) ((hash) & ((1 << (log2_shards)) - 1)) - -typedef void (*destroy_user_data_func)(void *user_data); - -#define SIZE_IN_DECODER_TABLE_NOT_SET -1 -/* Shadow structure for grpc_mdstr for non-static values */ -typedef struct internal_string { - /* must be byte compatible with grpc_mdstr */ - grpc_slice slice; - uint32_t hash; - - /* private only data */ - gpr_atm refcnt; - - uint8_t has_base64_and_huffman_encoded; - grpc_slice_refcount refcount; +#define INITIAL_SHARD_CAPACITY 8 +#define LOG2_SHARD_COUNT 4 +#define SHARD_COUNT ((size_t)(1 << LOG2_SHARD_COUNT)) - grpc_slice base64_and_huffman; +#define TABLE_IDX(hash, capacity) (((hash) >> (LOG2_SHARD_COUNT)) % (capacity)) +#define SHARD_IDX(hash) ((hash) & ((1 << (LOG2_SHARD_COUNT)) - 1)) - gpr_atm size_in_decoder_table; - - struct internal_string *bucket_next; -} internal_string; +typedef void (*destroy_user_data_func)(void *user_data); -/* Shadow structure for grpc_mdelem for non-static elements */ -typedef struct internal_metadata { - /* must be byte compatible with grpc_mdelem */ - internal_string *key; - internal_string *value; +/* Shadow structure for grpc_mdelem_data for interned elements */ +typedef struct interned_metadata { + /* must be byte compatible with grpc_mdelem_data */ + grpc_slice key; + grpc_slice value; /* private only data */ gpr_atm refcnt; @@ -114,19 +81,22 @@ typedef struct internal_metadata { gpr_atm destroy_user_data; gpr_atm user_data; - struct internal_metadata *bucket_next; -} internal_metadata; + struct interned_metadata *bucket_next; +} interned_metadata; -typedef struct strtab_shard { - gpr_mu mu; - internal_string **strs; - size_t count; - size_t capacity; -} strtab_shard; +/* Shadow structure for grpc_mdelem_data for allocated elements */ +typedef struct allocated_metadata { + /* must be byte compatible with grpc_mdelem_data */ + grpc_slice key; + grpc_slice value; + + /* private only data */ + gpr_atm refcnt; +} allocated_metadata; typedef struct mdtab_shard { gpr_mu mu; - internal_metadata **elems; + interned_metadata **elems; size_t count; size_t capacity; /** Estimate of the number of unreferenced mdelems in the hash table. @@ -135,104 +105,27 @@ typedef struct mdtab_shard { gpr_atm free_estimate; } mdtab_shard; -#define LOG2_STRTAB_SHARD_COUNT 5 -#define LOG2_MDTAB_SHARD_COUNT 4 -#define STRTAB_SHARD_COUNT ((size_t)(1 << LOG2_STRTAB_SHARD_COUNT)) -#define MDTAB_SHARD_COUNT ((size_t)(1 << LOG2_MDTAB_SHARD_COUNT)) - -/* hash seed: decided at initialization time */ -static uint32_t g_hash_seed; -static int g_forced_hash_seed = 0; +static mdtab_shard g_shards[SHARD_COUNT]; -/* linearly probed hash tables for static element lookup */ -static grpc_mdstr *g_static_strtab[GRPC_STATIC_MDSTR_COUNT * 2]; -static grpc_mdelem *g_static_mdtab[GRPC_STATIC_MDELEM_COUNT * 2]; -static size_t g_static_strtab_maxprobe; -static size_t g_static_mdtab_maxprobe; - -static strtab_shard g_strtab_shard[STRTAB_SHARD_COUNT]; -static mdtab_shard g_mdtab_shard[MDTAB_SHARD_COUNT]; - -static void gc_mdtab(mdtab_shard *shard); - -void grpc_test_only_set_metadata_hash_seed(uint32_t seed) { - g_hash_seed = seed; - g_forced_hash_seed = 1; -} +static void gc_mdtab(grpc_exec_ctx *exec_ctx, mdtab_shard *shard); void grpc_mdctx_global_init(void) { - size_t i, j; - if (!g_forced_hash_seed) { - g_hash_seed = (uint32_t)gpr_now(GPR_CLOCK_REALTIME).tv_nsec; - } - g_static_strtab_maxprobe = 0; - g_static_mdtab_maxprobe = 0; - /* build static tables */ - memset(g_static_mdtab, 0, sizeof(g_static_mdtab)); - memset(g_static_strtab, 0, sizeof(g_static_strtab)); - for (i = 0; i < GRPC_STATIC_MDSTR_COUNT; i++) { - grpc_mdstr *elem = &grpc_static_mdstr_table[i]; - const char *str = grpc_static_metadata_strings[i]; - uint32_t hash = gpr_murmur_hash3(str, strlen(str), g_hash_seed); - *(grpc_slice *)&elem->slice = grpc_slice_from_static_string(str); - *(uint32_t *)&elem->hash = hash; - for (j = 0;; j++) { - size_t idx = (hash + j) % GPR_ARRAY_SIZE(g_static_strtab); - if (g_static_strtab[idx] == NULL) { - g_static_strtab[idx] = &grpc_static_mdstr_table[i]; - break; - } - } - if (j > g_static_strtab_maxprobe) { - g_static_strtab_maxprobe = j; - } - } - for (i = 0; i < GRPC_STATIC_MDELEM_COUNT; i++) { - grpc_mdelem *elem = &grpc_static_mdelem_table[i]; - grpc_mdstr *key = - &grpc_static_mdstr_table[grpc_static_metadata_elem_indices[2 * i + 0]]; - grpc_mdstr *value = - &grpc_static_mdstr_table[grpc_static_metadata_elem_indices[2 * i + 1]]; - uint32_t hash = GRPC_MDSTR_KV_HASH(key->hash, value->hash); - *(grpc_mdstr **)&elem->key = key; - *(grpc_mdstr **)&elem->value = value; - for (j = 0;; j++) { - size_t idx = (hash + j) % GPR_ARRAY_SIZE(g_static_mdtab); - if (g_static_mdtab[idx] == NULL) { - g_static_mdtab[idx] = elem; - break; - } - } - if (j > g_static_mdtab_maxprobe) { - g_static_mdtab_maxprobe = j; - } - } /* initialize shards */ - for (i = 0; i < STRTAB_SHARD_COUNT; i++) { - strtab_shard *shard = &g_strtab_shard[i]; - gpr_mu_init(&shard->mu); - shard->count = 0; - shard->capacity = INITIAL_STRTAB_CAPACITY; - shard->strs = gpr_malloc(sizeof(*shard->strs) * shard->capacity); - memset(shard->strs, 0, sizeof(*shard->strs) * shard->capacity); - } - for (i = 0; i < MDTAB_SHARD_COUNT; i++) { - mdtab_shard *shard = &g_mdtab_shard[i]; + for (size_t i = 0; i < SHARD_COUNT; i++) { + mdtab_shard *shard = &g_shards[i]; gpr_mu_init(&shard->mu); shard->count = 0; gpr_atm_no_barrier_store(&shard->free_estimate, 0); - shard->capacity = INITIAL_MDTAB_CAPACITY; - shard->elems = gpr_malloc(sizeof(*shard->elems) * shard->capacity); - memset(shard->elems, 0, sizeof(*shard->elems) * shard->capacity); + shard->capacity = INITIAL_SHARD_CAPACITY; + shard->elems = gpr_zalloc(sizeof(*shard->elems) * shard->capacity); } } -void grpc_mdctx_global_shutdown(void) { - size_t i; - for (i = 0; i < MDTAB_SHARD_COUNT; i++) { - mdtab_shard *shard = &g_mdtab_shard[i]; +void grpc_mdctx_global_shutdown(grpc_exec_ctx *exec_ctx) { + for (size_t i = 0; i < SHARD_COUNT; i++) { + mdtab_shard *shard = &g_shards[i]; gpr_mu_destroy(&shard->mu); - gc_mdtab(shard); + gc_mdtab(exec_ctx, shard); /* TODO(ctiller): GPR_ASSERT(shard->count == 0); */ if (shard->count != 0) { gpr_log(GPR_DEBUG, "WARNING: %" PRIuPTR " metadata elements were leaked", @@ -243,211 +136,37 @@ void grpc_mdctx_global_shutdown(void) { } gpr_free(shard->elems); } - for (i = 0; i < STRTAB_SHARD_COUNT; i++) { - strtab_shard *shard = &g_strtab_shard[i]; - gpr_mu_destroy(&shard->mu); - /* TODO(ctiller): GPR_ASSERT(shard->count == 0); */ - if (shard->count != 0) { - gpr_log(GPR_DEBUG, "WARNING: %" PRIuPTR " metadata strings were leaked", - shard->count); - for (size_t j = 0; j < shard->capacity; j++) { - for (internal_string *s = shard->strs[j]; s; s = s->bucket_next) { - gpr_log(GPR_DEBUG, "LEAKED: %s", - grpc_mdstr_as_c_string((grpc_mdstr *)s)); - } - } - if (grpc_iomgr_abort_on_leaks()) { - abort(); - } - } - gpr_free(shard->strs); - } } -static int is_mdstr_static(grpc_mdstr *s) { - return s >= &grpc_static_mdstr_table[0] && - s < &grpc_static_mdstr_table[GRPC_STATIC_MDSTR_COUNT]; -} - -static int is_mdelem_static(grpc_mdelem *e) { - return e >= &grpc_static_mdelem_table[0] && - e < &grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT]; +static int is_mdelem_static(grpc_mdelem e) { + return GRPC_MDELEM_DATA(e) >= &grpc_static_mdelem_table[0] && + GRPC_MDELEM_DATA(e) < + &grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT]; } static void ref_md_locked(mdtab_shard *shard, - internal_metadata *md DEBUG_ARGS) { -#ifdef GRPC_METADATA_REFCOUNT_DEBUG - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, - "ELM REF:%p:%zu->%zu: '%s' = '%s'", (void *)md, - gpr_atm_no_barrier_load(&md->refcnt), - gpr_atm_no_barrier_load(&md->refcnt) + 1, - grpc_mdstr_as_c_string((grpc_mdstr *)md->key), - grpc_mdstr_as_c_string((grpc_mdstr *)md->value)); + interned_metadata *md DEBUG_ARGS) { +#ifndef NDEBUG + if (GRPC_TRACER_ON(grpc_trace_metadata)) { + char *key_str = grpc_slice_to_c_string(md->key); + char *value_str = grpc_slice_to_c_string(md->value); + gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, + "ELM REF:%p:%" PRIdPTR "->%" PRIdPTR ": '%s' = '%s'", (void *)md, + gpr_atm_no_barrier_load(&md->refcnt), + gpr_atm_no_barrier_load(&md->refcnt) + 1, key_str, value_str); + gpr_free(key_str); + gpr_free(value_str); + } #endif if (0 == gpr_atm_no_barrier_fetch_add(&md->refcnt, 1)) { gpr_atm_no_barrier_fetch_add(&shard->free_estimate, -1); } } -static void grow_strtab(strtab_shard *shard) { - size_t capacity = shard->capacity * 2; +static void gc_mdtab(grpc_exec_ctx *exec_ctx, mdtab_shard *shard) { size_t i; - internal_string **strtab; - internal_string *s, *next; - - GPR_TIMER_BEGIN("grow_strtab", 0); - - strtab = gpr_malloc(sizeof(internal_string *) * capacity); - memset(strtab, 0, sizeof(internal_string *) * capacity); - - for (i = 0; i < shard->capacity; i++) { - for (s = shard->strs[i]; s; s = next) { - size_t idx = TABLE_IDX(s->hash, LOG2_STRTAB_SHARD_COUNT, capacity); - next = s->bucket_next; - s->bucket_next = strtab[idx]; - strtab[idx] = s; - } - } - - gpr_free(shard->strs); - shard->strs = strtab; - shard->capacity = capacity; - - GPR_TIMER_END("grow_strtab", 0); -} - -static void internal_destroy_string(strtab_shard *shard, internal_string *is) { - internal_string **prev_next; - internal_string *cur; - GPR_TIMER_BEGIN("internal_destroy_string", 0); - if (is->has_base64_and_huffman_encoded) { - grpc_slice_unref(is->base64_and_huffman); - } - for (prev_next = &shard->strs[TABLE_IDX(is->hash, LOG2_STRTAB_SHARD_COUNT, - shard->capacity)], - cur = *prev_next; - cur != is; prev_next = &cur->bucket_next, cur = cur->bucket_next) - ; - *prev_next = cur->bucket_next; - shard->count--; - gpr_free(is); - GPR_TIMER_END("internal_destroy_string", 0); -} - -static void slice_ref(void *p) { - internal_string *is = - (internal_string *)((char *)p - offsetof(internal_string, refcount)); - GRPC_MDSTR_REF((grpc_mdstr *)(is)); -} - -static void slice_unref(void *p) { - internal_string *is = - (internal_string *)((char *)p - offsetof(internal_string, refcount)); - GRPC_MDSTR_UNREF((grpc_mdstr *)(is)); -} - -grpc_mdstr *grpc_mdstr_from_string(const char *str) { - return grpc_mdstr_from_buffer((const uint8_t *)str, strlen(str)); -} - -grpc_mdstr *grpc_mdstr_from_slice(grpc_slice slice) { - grpc_mdstr *result = grpc_mdstr_from_buffer(GRPC_SLICE_START_PTR(slice), - GRPC_SLICE_LENGTH(slice)); - grpc_slice_unref(slice); - return result; -} - -grpc_mdstr *grpc_mdstr_from_buffer(const uint8_t *buf, size_t length) { - uint32_t hash = gpr_murmur_hash3(buf, length, g_hash_seed); - internal_string *s; - strtab_shard *shard = - &g_strtab_shard[SHARD_IDX(hash, LOG2_STRTAB_SHARD_COUNT)]; - size_t i; - size_t idx; - - GPR_TIMER_BEGIN("grpc_mdstr_from_buffer", 0); - - /* search for a static string */ - for (i = 0; i <= g_static_strtab_maxprobe; i++) { - grpc_mdstr *ss; - idx = (hash + i) % GPR_ARRAY_SIZE(g_static_strtab); - ss = g_static_strtab[idx]; - if (ss == NULL) break; - if (ss->hash == hash && GRPC_SLICE_LENGTH(ss->slice) == length && - (length == 0 || - 0 == memcmp(buf, GRPC_SLICE_START_PTR(ss->slice), length))) { - GPR_TIMER_END("grpc_mdstr_from_buffer", 0); - return ss; - } - } - - gpr_mu_lock(&shard->mu); - - /* search for an existing string */ - idx = TABLE_IDX(hash, LOG2_STRTAB_SHARD_COUNT, shard->capacity); - for (s = shard->strs[idx]; s; s = s->bucket_next) { - if (s->hash == hash && GRPC_SLICE_LENGTH(s->slice) == length && - 0 == memcmp(buf, GRPC_SLICE_START_PTR(s->slice), length)) { - if (gpr_atm_full_fetch_add(&s->refcnt, 1) == 0) { - /* If we get here, we've added a ref to something that was about to - * die - drop it immediately. - * The *only* possible path here (given the shard mutex) should be to - * drop from one ref back to zero - assert that with a CAS */ - GPR_ASSERT(gpr_atm_rel_cas(&s->refcnt, 1, 0)); - /* and treat this as if we were never here... sshhh */ - } else { - gpr_mu_unlock(&shard->mu); - GPR_TIMER_END("grpc_mdstr_from_buffer", 0); - return (grpc_mdstr *)s; - } - } - } - - /* not found: create a new string */ - if (length + 1 < GRPC_SLICE_INLINED_SIZE) { - /* string data goes directly into the slice */ - s = gpr_malloc(sizeof(internal_string)); - gpr_atm_rel_store(&s->refcnt, 1); - s->slice.refcount = NULL; - memcpy(s->slice.data.inlined.bytes, buf, length); - s->slice.data.inlined.bytes[length] = 0; - s->slice.data.inlined.length = (uint8_t)length; - } else { - /* string data goes after the internal_string header, and we +1 for null - terminator */ - s = gpr_malloc(sizeof(internal_string) + length + 1); - gpr_atm_rel_store(&s->refcnt, 1); - s->refcount.ref = slice_ref; - s->refcount.unref = slice_unref; - s->slice.refcount = &s->refcount; - s->slice.data.refcounted.bytes = (uint8_t *)(s + 1); - s->slice.data.refcounted.length = length; - memcpy(s->slice.data.refcounted.bytes, buf, length); - /* add a null terminator for cheap c string conversion when desired */ - s->slice.data.refcounted.bytes[length] = 0; - } - s->has_base64_and_huffman_encoded = 0; - s->hash = hash; - s->size_in_decoder_table = SIZE_IN_DECODER_TABLE_NOT_SET; - s->bucket_next = shard->strs[idx]; - shard->strs[idx] = s; - - shard->count++; - - if (shard->count > shard->capacity * 2) { - grow_strtab(shard); - } - - gpr_mu_unlock(&shard->mu); - GPR_TIMER_END("grpc_mdstr_from_buffer", 0); - - return (grpc_mdstr *)s; -} - -static void gc_mdtab(mdtab_shard *shard) { - size_t i; - internal_metadata **prev_next; - internal_metadata *md, *next; + interned_metadata **prev_next; + interned_metadata *md, *next; gpr_atm num_freed = 0; GPR_TIMER_BEGIN("gc_mdtab", 0); @@ -457,8 +176,8 @@ static void gc_mdtab(mdtab_shard *shard) { void *user_data = (void *)gpr_atm_no_barrier_load(&md->user_data); next = md->bucket_next; if (gpr_atm_acq_load(&md->refcnt) == 0) { - GRPC_MDSTR_UNREF((grpc_mdstr *)md->key); - GRPC_MDSTR_UNREF((grpc_mdstr *)md->value); + grpc_slice_unref_internal(exec_ctx, md->key); + grpc_slice_unref_internal(exec_ctx, md->value); if (md->user_data) { ((destroy_user_data_func)gpr_atm_no_barrier_load( &md->destroy_user_data))(user_data); @@ -479,21 +198,21 @@ static void gc_mdtab(mdtab_shard *shard) { static void grow_mdtab(mdtab_shard *shard) { size_t capacity = shard->capacity * 2; size_t i; - internal_metadata **mdtab; - internal_metadata *md, *next; + interned_metadata **mdtab; + interned_metadata *md, *next; uint32_t hash; GPR_TIMER_BEGIN("grow_mdtab", 0); - mdtab = gpr_malloc(sizeof(internal_metadata *) * capacity); - memset(mdtab, 0, sizeof(internal_metadata *) * capacity); + mdtab = gpr_zalloc(sizeof(interned_metadata *) * capacity); for (i = 0; i < shard->capacity; i++) { for (md = shard->elems[i]; md; md = next) { size_t idx; - hash = GRPC_MDSTR_KV_HASH(md->key->hash, md->value->hash); + hash = GRPC_MDSTR_KV_HASH(grpc_slice_hash(md->key), + grpc_slice_hash(md->value)); next = md->bucket_next; - idx = TABLE_IDX(hash, LOG2_MDTAB_SHARD_COUNT, capacity); + idx = TABLE_IDX(hash, capacity); md->bucket_next = mdtab[idx]; mdtab[idx] = md; } @@ -506,99 +225,122 @@ static void grow_mdtab(mdtab_shard *shard) { GPR_TIMER_END("grow_mdtab", 0); } -static void rehash_mdtab(mdtab_shard *shard) { +static void rehash_mdtab(grpc_exec_ctx *exec_ctx, mdtab_shard *shard) { if (gpr_atm_no_barrier_load(&shard->free_estimate) > (gpr_atm)(shard->capacity / 4)) { - gc_mdtab(shard); + gc_mdtab(exec_ctx, shard); } else { grow_mdtab(shard); } } -grpc_mdelem *grpc_mdelem_from_metadata_strings(grpc_mdstr *mkey, - grpc_mdstr *mvalue) { - internal_string *key = (internal_string *)mkey; - internal_string *value = (internal_string *)mvalue; - uint32_t hash = GRPC_MDSTR_KV_HASH(mkey->hash, mvalue->hash); - internal_metadata *md; - mdtab_shard *shard = &g_mdtab_shard[SHARD_IDX(hash, LOG2_MDTAB_SHARD_COUNT)]; - size_t i; - size_t idx; +grpc_mdelem grpc_mdelem_create( + grpc_exec_ctx *exec_ctx, grpc_slice key, grpc_slice value, + grpc_mdelem_data *compatible_external_backing_store) { + if (!grpc_slice_is_interned(key) || !grpc_slice_is_interned(value)) { + if (compatible_external_backing_store != NULL) { + return GRPC_MAKE_MDELEM(compatible_external_backing_store, + GRPC_MDELEM_STORAGE_EXTERNAL); + } - GPR_TIMER_BEGIN("grpc_mdelem_from_metadata_strings", 0); + allocated_metadata *allocated = gpr_malloc(sizeof(*allocated)); + allocated->key = grpc_slice_ref_internal(key); + allocated->value = grpc_slice_ref_internal(value); + gpr_atm_rel_store(&allocated->refcnt, 1); +#ifndef NDEBUG + if (GRPC_TRACER_ON(grpc_trace_metadata)) { + char *key_str = grpc_slice_to_c_string(allocated->key); + char *value_str = grpc_slice_to_c_string(allocated->value); + gpr_log(GPR_DEBUG, "ELM ALLOC:%p:%" PRIdPTR ": '%s' = '%s'", + (void *)allocated, gpr_atm_no_barrier_load(&allocated->refcnt), + key_str, value_str); + gpr_free(key_str); + gpr_free(value_str); + } +#endif + return GRPC_MAKE_MDELEM(allocated, GRPC_MDELEM_STORAGE_ALLOCATED); + } - if (is_mdstr_static(mkey) && is_mdstr_static(mvalue)) { - for (i = 0; i <= g_static_mdtab_maxprobe; i++) { - grpc_mdelem *smd; - idx = (hash + i) % GPR_ARRAY_SIZE(g_static_mdtab); - smd = g_static_mdtab[idx]; - if (smd == NULL) break; - if (smd->key == mkey && smd->value == mvalue) { - GPR_TIMER_END("grpc_mdelem_from_metadata_strings", 0); - return smd; - } + if (GRPC_IS_STATIC_METADATA_STRING(key) && + GRPC_IS_STATIC_METADATA_STRING(value)) { + grpc_mdelem static_elem = grpc_static_mdelem_for_static_strings( + GRPC_STATIC_METADATA_INDEX(key), GRPC_STATIC_METADATA_INDEX(value)); + if (!GRPC_MDISNULL(static_elem)) { + return static_elem; } } + uint32_t hash = + GRPC_MDSTR_KV_HASH(grpc_slice_hash(key), grpc_slice_hash(value)); + interned_metadata *md; + mdtab_shard *shard = &g_shards[SHARD_IDX(hash)]; + size_t idx; + + GPR_TIMER_BEGIN("grpc_mdelem_from_metadata_strings", 0); + gpr_mu_lock(&shard->mu); - idx = TABLE_IDX(hash, LOG2_MDTAB_SHARD_COUNT, shard->capacity); + idx = TABLE_IDX(hash, shard->capacity); /* search for an existing pair */ for (md = shard->elems[idx]; md; md = md->bucket_next) { - if (md->key == key && md->value == value) { + if (grpc_slice_eq(key, md->key) && grpc_slice_eq(value, md->value)) { REF_MD_LOCKED(shard, md); - GRPC_MDSTR_UNREF((grpc_mdstr *)key); - GRPC_MDSTR_UNREF((grpc_mdstr *)value); gpr_mu_unlock(&shard->mu); GPR_TIMER_END("grpc_mdelem_from_metadata_strings", 0); - return (grpc_mdelem *)md; + return GRPC_MAKE_MDELEM(md, GRPC_MDELEM_STORAGE_INTERNED); } } /* not found: create a new pair */ - md = gpr_malloc(sizeof(internal_metadata)); + md = gpr_malloc(sizeof(interned_metadata)); gpr_atm_rel_store(&md->refcnt, 1); - md->key = key; - md->value = value; + md->key = grpc_slice_ref_internal(key); + md->value = grpc_slice_ref_internal(value); md->user_data = 0; md->destroy_user_data = 0; md->bucket_next = shard->elems[idx]; shard->elems[idx] = md; gpr_mu_init(&md->mu_user_data); -#ifdef GRPC_METADATA_REFCOUNT_DEBUG - gpr_log(GPR_DEBUG, "ELM NEW:%p:%zu: '%s' = '%s'", (void *)md, - gpr_atm_no_barrier_load(&md->refcnt), - grpc_mdstr_as_c_string((grpc_mdstr *)md->key), - grpc_mdstr_as_c_string((grpc_mdstr *)md->value)); +#ifndef NDEBUG + if (GRPC_TRACER_ON(grpc_trace_metadata)) { + char *key_str = grpc_slice_to_c_string(md->key); + char *value_str = grpc_slice_to_c_string(md->value); + gpr_log(GPR_DEBUG, "ELM NEW:%p:%" PRIdPTR ": '%s' = '%s'", (void *)md, + gpr_atm_no_barrier_load(&md->refcnt), key_str, value_str); + gpr_free(key_str); + gpr_free(value_str); + } #endif shard->count++; if (shard->count > shard->capacity * 2) { - rehash_mdtab(shard); + rehash_mdtab(exec_ctx, shard); } gpr_mu_unlock(&shard->mu); GPR_TIMER_END("grpc_mdelem_from_metadata_strings", 0); - return (grpc_mdelem *)md; + return GRPC_MAKE_MDELEM(md, GRPC_MDELEM_STORAGE_INTERNED); } -grpc_mdelem *grpc_mdelem_from_strings(const char *key, const char *value) { - return grpc_mdelem_from_metadata_strings(grpc_mdstr_from_string(key), - grpc_mdstr_from_string(value)); +grpc_mdelem grpc_mdelem_from_slices(grpc_exec_ctx *exec_ctx, grpc_slice key, + grpc_slice value) { + grpc_mdelem out = grpc_mdelem_create(exec_ctx, key, value, NULL); + grpc_slice_unref_internal(exec_ctx, key); + grpc_slice_unref_internal(exec_ctx, value); + return out; } -grpc_mdelem *grpc_mdelem_from_slices(grpc_slice key, grpc_slice value) { - return grpc_mdelem_from_metadata_strings(grpc_mdstr_from_slice(key), - grpc_mdstr_from_slice(value)); -} - -grpc_mdelem *grpc_mdelem_from_string_and_buffer(const char *key, - const uint8_t *value, - size_t value_length) { - return grpc_mdelem_from_metadata_strings( - grpc_mdstr_from_string(key), grpc_mdstr_from_buffer(value, value_length)); +grpc_mdelem grpc_mdelem_from_grpc_metadata(grpc_exec_ctx *exec_ctx, + grpc_metadata *metadata) { + bool changed = false; + grpc_slice key_slice = + grpc_slice_maybe_static_intern(metadata->key, &changed); + grpc_slice value_slice = + grpc_slice_maybe_static_intern(metadata->value, &changed); + return grpc_mdelem_create(exec_ctx, key_slice, value_slice, + changed ? NULL : (grpc_mdelem_data *)metadata); } static size_t get_base64_encoded_size(size_t raw_length) { @@ -606,160 +348,184 @@ static size_t get_base64_encoded_size(size_t raw_length) { return raw_length / 3 * 4 + tail_xtra[raw_length % 3]; } -size_t grpc_mdelem_get_size_in_hpack_table(grpc_mdelem *elem) { - size_t overhead_and_key = 32 + GRPC_SLICE_LENGTH(elem->key->slice); - size_t value_len = GRPC_SLICE_LENGTH(elem->value->slice); - if (is_mdstr_static(elem->value)) { - if (grpc_is_binary_header( - (const char *)GRPC_SLICE_START_PTR(elem->key->slice), - GRPC_SLICE_LENGTH(elem->key->slice))) { - return overhead_and_key + get_base64_encoded_size(value_len); - } else { - return overhead_and_key + value_len; - } +size_t grpc_mdelem_get_size_in_hpack_table(grpc_mdelem elem) { + size_t overhead_and_key = 32 + GRPC_SLICE_LENGTH(GRPC_MDKEY(elem)); + size_t value_len = GRPC_SLICE_LENGTH(GRPC_MDVALUE(elem)); + if (grpc_is_binary_header(GRPC_MDKEY(elem))) { + return overhead_and_key + get_base64_encoded_size(value_len); } else { - internal_string *is = (internal_string *)elem->value; - gpr_atm current_size = gpr_atm_acq_load(&is->size_in_decoder_table); - if (current_size == SIZE_IN_DECODER_TABLE_NOT_SET) { - if (grpc_is_binary_header( - (const char *)GRPC_SLICE_START_PTR(elem->key->slice), - GRPC_SLICE_LENGTH(elem->key->slice))) { - current_size = (gpr_atm)get_base64_encoded_size(value_len); - } else { - current_size = (gpr_atm)value_len; - } - gpr_atm_rel_store(&is->size_in_decoder_table, current_size); - } - return overhead_and_key + (size_t)current_size; + return overhead_and_key + value_len; } } -grpc_mdelem *grpc_mdelem_ref(grpc_mdelem *gmd DEBUG_ARGS) { - internal_metadata *md = (internal_metadata *)gmd; - if (is_mdelem_static(gmd)) return gmd; -#ifdef GRPC_METADATA_REFCOUNT_DEBUG - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, - "ELM REF:%p:%zu->%zu: '%s' = '%s'", (void *)md, - gpr_atm_no_barrier_load(&md->refcnt), - gpr_atm_no_barrier_load(&md->refcnt) + 1, - grpc_mdstr_as_c_string((grpc_mdstr *)md->key), - grpc_mdstr_as_c_string((grpc_mdstr *)md->value)); +grpc_mdelem grpc_mdelem_ref(grpc_mdelem gmd DEBUG_ARGS) { + switch (GRPC_MDELEM_STORAGE(gmd)) { + case GRPC_MDELEM_STORAGE_EXTERNAL: + case GRPC_MDELEM_STORAGE_STATIC: + break; + case GRPC_MDELEM_STORAGE_INTERNED: { + interned_metadata *md = (interned_metadata *)GRPC_MDELEM_DATA(gmd); +#ifndef NDEBUG + if (GRPC_TRACER_ON(grpc_trace_metadata)) { + char *key_str = grpc_slice_to_c_string(md->key); + char *value_str = grpc_slice_to_c_string(md->value); + gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, + "ELM REF:%p:%" PRIdPTR "->%" PRIdPTR ": '%s' = '%s'", + (void *)md, gpr_atm_no_barrier_load(&md->refcnt), + gpr_atm_no_barrier_load(&md->refcnt) + 1, key_str, value_str); + gpr_free(key_str); + gpr_free(value_str); + } #endif - /* we can assume the ref count is >= 1 as the application is calling - this function - meaning that no adjustment to mdtab_free is necessary, - simplifying the logic here to be just an atomic increment */ - /* use C assert to have this removed in opt builds */ - GPR_ASSERT(gpr_atm_no_barrier_load(&md->refcnt) >= 1); - gpr_atm_no_barrier_fetch_add(&md->refcnt, 1); - return gmd; -} - -void grpc_mdelem_unref(grpc_mdelem *gmd DEBUG_ARGS) { - internal_metadata *md = (internal_metadata *)gmd; - if (!md) return; - if (is_mdelem_static(gmd)) return; -#ifdef GRPC_METADATA_REFCOUNT_DEBUG - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, - "ELM UNREF:%p:%zu->%zu: '%s' = '%s'", (void *)md, - gpr_atm_no_barrier_load(&md->refcnt), - gpr_atm_no_barrier_load(&md->refcnt) - 1, - grpc_mdstr_as_c_string((grpc_mdstr *)md->key), - grpc_mdstr_as_c_string((grpc_mdstr *)md->value)); + /* we can assume the ref count is >= 1 as the application is calling + this function - meaning that no adjustment to mdtab_free is necessary, + simplifying the logic here to be just an atomic increment */ + /* use C assert to have this removed in opt builds */ + GPR_ASSERT(gpr_atm_no_barrier_load(&md->refcnt) >= 1); + gpr_atm_no_barrier_fetch_add(&md->refcnt, 1); + break; + } + case GRPC_MDELEM_STORAGE_ALLOCATED: { + allocated_metadata *md = (allocated_metadata *)GRPC_MDELEM_DATA(gmd); +#ifndef NDEBUG + if (GRPC_TRACER_ON(grpc_trace_metadata)) { + char *key_str = grpc_slice_to_c_string(md->key); + char *value_str = grpc_slice_to_c_string(md->value); + gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, + "ELM REF:%p:%" PRIdPTR "->%" PRIdPTR ": '%s' = '%s'", + (void *)md, gpr_atm_no_barrier_load(&md->refcnt), + gpr_atm_no_barrier_load(&md->refcnt) + 1, key_str, value_str); + gpr_free(key_str); + gpr_free(value_str); + } #endif - uint32_t hash = GRPC_MDSTR_KV_HASH(md->key->hash, md->value->hash); - const gpr_atm prev_refcount = gpr_atm_full_fetch_add(&md->refcnt, -1); - GPR_ASSERT(prev_refcount >= 1); - if (1 == prev_refcount) { - /* once the refcount hits zero, some other thread can come along and - free md at any time: it's unsafe from this point on to access it */ - mdtab_shard *shard = - &g_mdtab_shard[SHARD_IDX(hash, LOG2_MDTAB_SHARD_COUNT)]; - gpr_atm_no_barrier_fetch_add(&shard->free_estimate, 1); + /* we can assume the ref count is >= 1 as the application is calling + this function - meaning that no adjustment to mdtab_free is necessary, + simplifying the logic here to be just an atomic increment */ + /* use C assert to have this removed in opt builds */ + gpr_atm_no_barrier_fetch_add(&md->refcnt, 1); + break; + } } + return gmd; } -const char *grpc_mdstr_as_c_string(const grpc_mdstr *s) { - return (const char *)GRPC_SLICE_START_PTR(s->slice); -} - -size_t grpc_mdstr_length(const grpc_mdstr *s) { return GRPC_MDSTR_LENGTH(s); } - -grpc_mdstr *grpc_mdstr_ref(grpc_mdstr *gs DEBUG_ARGS) { - internal_string *s = (internal_string *)gs; - if (is_mdstr_static(gs)) return gs; -#ifdef GRPC_METADATA_REFCOUNT_DEBUG - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "STR REF:%p:%zu->%zu: '%s'", - (void *)s, gpr_atm_no_barrier_load(&s->refcnt), - gpr_atm_no_barrier_load(&s->refcnt) + 1, grpc_mdstr_as_c_string(gs)); +void grpc_mdelem_unref(grpc_exec_ctx *exec_ctx, grpc_mdelem gmd DEBUG_ARGS) { + switch (GRPC_MDELEM_STORAGE(gmd)) { + case GRPC_MDELEM_STORAGE_EXTERNAL: + case GRPC_MDELEM_STORAGE_STATIC: + break; + case GRPC_MDELEM_STORAGE_INTERNED: { + interned_metadata *md = (interned_metadata *)GRPC_MDELEM_DATA(gmd); +#ifndef NDEBUG + if (GRPC_TRACER_ON(grpc_trace_metadata)) { + char *key_str = grpc_slice_to_c_string(md->key); + char *value_str = grpc_slice_to_c_string(md->value); + gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, + "ELM UNREF:%p:%" PRIdPTR "->%" PRIdPTR ": '%s' = '%s'", + (void *)md, gpr_atm_no_barrier_load(&md->refcnt), + gpr_atm_no_barrier_load(&md->refcnt) - 1, key_str, value_str); + gpr_free(key_str); + gpr_free(value_str); + } #endif - GPR_ASSERT(gpr_atm_full_fetch_add(&s->refcnt, 1) > 0); - return gs; -} - -void grpc_mdstr_unref(grpc_mdstr *gs DEBUG_ARGS) { - internal_string *s = (internal_string *)gs; - if (is_mdstr_static(gs)) return; -#ifdef GRPC_METADATA_REFCOUNT_DEBUG - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "STR UNREF:%p:%zu->%zu: '%s'", - (void *)s, gpr_atm_no_barrier_load(&s->refcnt), - gpr_atm_no_barrier_load(&s->refcnt) - 1, grpc_mdstr_as_c_string(gs)); + uint32_t hash = GRPC_MDSTR_KV_HASH(grpc_slice_hash(md->key), + grpc_slice_hash(md->value)); + const gpr_atm prev_refcount = gpr_atm_full_fetch_add(&md->refcnt, -1); + GPR_ASSERT(prev_refcount >= 1); + if (1 == prev_refcount) { + /* once the refcount hits zero, some other thread can come along and + free md at any time: it's unsafe from this point on to access it */ + mdtab_shard *shard = &g_shards[SHARD_IDX(hash)]; + gpr_atm_no_barrier_fetch_add(&shard->free_estimate, 1); + } + break; + } + case GRPC_MDELEM_STORAGE_ALLOCATED: { + allocated_metadata *md = (allocated_metadata *)GRPC_MDELEM_DATA(gmd); +#ifndef NDEBUG + if (GRPC_TRACER_ON(grpc_trace_metadata)) { + char *key_str = grpc_slice_to_c_string(md->key); + char *value_str = grpc_slice_to_c_string(md->value); + gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, + "ELM UNREF:%p:%" PRIdPTR "->%" PRIdPTR ": '%s' = '%s'", + (void *)md, gpr_atm_no_barrier_load(&md->refcnt), + gpr_atm_no_barrier_load(&md->refcnt) - 1, key_str, value_str); + gpr_free(key_str); + gpr_free(value_str); + } #endif - if (1 == gpr_atm_full_fetch_add(&s->refcnt, -1)) { - strtab_shard *shard = - &g_strtab_shard[SHARD_IDX(s->hash, LOG2_STRTAB_SHARD_COUNT)]; - gpr_mu_lock(&shard->mu); - GPR_ASSERT(0 == gpr_atm_no_barrier_load(&s->refcnt)); - internal_destroy_string(shard, s); - gpr_mu_unlock(&shard->mu); + const gpr_atm prev_refcount = gpr_atm_full_fetch_add(&md->refcnt, -1); + GPR_ASSERT(prev_refcount >= 1); + if (1 == prev_refcount) { + grpc_slice_unref_internal(exec_ctx, md->key); + grpc_slice_unref_internal(exec_ctx, md->value); + gpr_free(md); + } + break; + } } } -void *grpc_mdelem_get_user_data(grpc_mdelem *md, void (*destroy_func)(void *)) { - internal_metadata *im = (internal_metadata *)md; - void *result; - if (is_mdelem_static(md)) { - return (void *)grpc_static_mdelem_user_data[md - grpc_static_mdelem_table]; - } - if (gpr_atm_acq_load(&im->destroy_user_data) == (gpr_atm)destroy_func) { - return (void *)gpr_atm_no_barrier_load(&im->user_data); - } else { - return NULL; +void *grpc_mdelem_get_user_data(grpc_mdelem md, void (*destroy_func)(void *)) { + switch (GRPC_MDELEM_STORAGE(md)) { + case GRPC_MDELEM_STORAGE_EXTERNAL: + case GRPC_MDELEM_STORAGE_ALLOCATED: + return NULL; + case GRPC_MDELEM_STORAGE_STATIC: + return (void *)grpc_static_mdelem_user_data[GRPC_MDELEM_DATA(md) - + grpc_static_mdelem_table]; + case GRPC_MDELEM_STORAGE_INTERNED: { + interned_metadata *im = (interned_metadata *)GRPC_MDELEM_DATA(md); + void *result; + if (gpr_atm_acq_load(&im->destroy_user_data) == (gpr_atm)destroy_func) { + return (void *)gpr_atm_no_barrier_load(&im->user_data); + } else { + return NULL; + } + return result; + } } - return result; + GPR_UNREACHABLE_CODE(return NULL); } -void *grpc_mdelem_set_user_data(grpc_mdelem *md, void (*destroy_func)(void *), +void *grpc_mdelem_set_user_data(grpc_mdelem md, void (*destroy_func)(void *), void *user_data) { - internal_metadata *im = (internal_metadata *)md; - GPR_ASSERT(!is_mdelem_static(md)); - GPR_ASSERT((user_data == NULL) == (destroy_func == NULL)); - gpr_mu_lock(&im->mu_user_data); - if (gpr_atm_no_barrier_load(&im->destroy_user_data)) { - /* user data can only be set once */ - gpr_mu_unlock(&im->mu_user_data); - if (destroy_func != NULL) { + switch (GRPC_MDELEM_STORAGE(md)) { + case GRPC_MDELEM_STORAGE_EXTERNAL: + case GRPC_MDELEM_STORAGE_ALLOCATED: destroy_func(user_data); + return NULL; + case GRPC_MDELEM_STORAGE_STATIC: + destroy_func(user_data); + return (void *)grpc_static_mdelem_user_data[GRPC_MDELEM_DATA(md) - + grpc_static_mdelem_table]; + case GRPC_MDELEM_STORAGE_INTERNED: { + interned_metadata *im = (interned_metadata *)GRPC_MDELEM_DATA(md); + GPR_ASSERT(!is_mdelem_static(md)); + GPR_ASSERT((user_data == NULL) == (destroy_func == NULL)); + gpr_mu_lock(&im->mu_user_data); + if (gpr_atm_no_barrier_load(&im->destroy_user_data)) { + /* user data can only be set once */ + gpr_mu_unlock(&im->mu_user_data); + if (destroy_func != NULL) { + destroy_func(user_data); + } + return (void *)gpr_atm_no_barrier_load(&im->user_data); + } + gpr_atm_no_barrier_store(&im->user_data, (gpr_atm)user_data); + gpr_atm_rel_store(&im->destroy_user_data, (gpr_atm)destroy_func); + gpr_mu_unlock(&im->mu_user_data); + return user_data; } - return (void *)gpr_atm_no_barrier_load(&im->user_data); } - gpr_atm_no_barrier_store(&im->user_data, (gpr_atm)user_data); - gpr_atm_rel_store(&im->destroy_user_data, (gpr_atm)destroy_func); - gpr_mu_unlock(&im->mu_user_data); - return user_data; + GPR_UNREACHABLE_CODE(return NULL); } -grpc_slice grpc_mdstr_as_base64_encoded_and_huffman_compressed(grpc_mdstr *gs) { - internal_string *s = (internal_string *)gs; - grpc_slice slice; - strtab_shard *shard = - &g_strtab_shard[SHARD_IDX(s->hash, LOG2_STRTAB_SHARD_COUNT)]; - gpr_mu_lock(&shard->mu); - if (!s->has_base64_and_huffman_encoded) { - s->base64_and_huffman = - grpc_chttp2_base64_encode_and_huffman_compress(s->slice); - s->has_base64_and_huffman_encoded = 1; - } - slice = s->base64_and_huffman; - gpr_mu_unlock(&shard->mu); - return slice; +bool grpc_mdelem_eq(grpc_mdelem a, grpc_mdelem b) { + if (a.payload == b.payload) return true; + if (GRPC_MDELEM_IS_INTERNED(a) && GRPC_MDELEM_IS_INTERNED(b)) return false; + if (GRPC_MDISNULL(a) || GRPC_MDISNULL(b)) return false; + return grpc_slice_eq(GRPC_MDKEY(a), GRPC_MDKEY(b)) && + grpc_slice_eq(GRPC_MDVALUE(a), GRPC_MDVALUE(b)); } diff --git a/Sources/CgRPC/src/core/lib/transport/metadata.h b/Sources/CgRPC/src/core/lib/transport/metadata.h index a4955a1ea..974469e43 100644 --- a/Sources/CgRPC/src/core/lib/transport/metadata.h +++ b/Sources/CgRPC/src/core/lib/transport/metadata.h @@ -1,42 +1,34 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 GRPC_CORE_LIB_TRANSPORT_METADATA_H #define GRPC_CORE_LIB_TRANSPORT_METADATA_H +#include #include #include +#include "src/core/lib/iomgr/exec_ctx.h" + +#ifndef NDEBUG +extern grpc_tracer_flag grpc_trace_metadata; +#endif + #ifdef __cplusplus extern "C" { #endif @@ -72,101 +64,107 @@ extern "C" { declared here - in which case those functions are effectively no-ops. */ /* Forward declarations */ -typedef struct grpc_mdstr grpc_mdstr; typedef struct grpc_mdelem grpc_mdelem; -/* if changing this, make identical changes in internal_string in metadata.c */ -struct grpc_mdstr { - const grpc_slice slice; - const uint32_t hash; +/* if changing this, make identical changes in: + - interned_metadata, allocated_metadata in metadata.c + - grpc_metadata in grpc_types.h */ +typedef struct grpc_mdelem_data { + const grpc_slice key; + const grpc_slice value; /* there is a private part to this in metadata.c */ -}; +} grpc_mdelem_data; + +/* GRPC_MDELEM_STORAGE_* enum values that can be treated as interned always have + this bit set in their integer value */ +#define GRPC_MDELEM_STORAGE_INTERNED_BIT 1 + +typedef enum { + /* memory pointed to by grpc_mdelem::payload is owned by an external system */ + GRPC_MDELEM_STORAGE_EXTERNAL = 0, + /* memory pointed to by grpc_mdelem::payload is interned by the metadata + system */ + GRPC_MDELEM_STORAGE_INTERNED = GRPC_MDELEM_STORAGE_INTERNED_BIT, + /* memory pointed to by grpc_mdelem::payload is allocated by the metadata + system */ + GRPC_MDELEM_STORAGE_ALLOCATED = 2, + /* memory is in the static metadata table */ + GRPC_MDELEM_STORAGE_STATIC = 2 | GRPC_MDELEM_STORAGE_INTERNED_BIT, +} grpc_mdelem_data_storage; -/* if changing this, make identical changes in internal_metadata in - metadata.c */ struct grpc_mdelem { - grpc_mdstr *const key; - grpc_mdstr *const value; - /* there is a private part to this in metadata.c */ + /* a grpc_mdelem_data* generally, with the two lower bits signalling memory + ownership as per grpc_mdelem_data_storage */ + uintptr_t payload; }; -void grpc_test_only_set_metadata_hash_seed(uint32_t seed); +#define GRPC_MDELEM_DATA(md) \ + ((grpc_mdelem_data *)((md).payload & ~(uintptr_t)3)) +#define GRPC_MDELEM_STORAGE(md) \ + ((grpc_mdelem_data_storage)((md).payload & (uintptr_t)3)) +#define GRPC_MAKE_MDELEM(data, storage) \ + ((grpc_mdelem){((uintptr_t)(data)) | ((uintptr_t)storage)}) +#define GRPC_MDELEM_IS_INTERNED(md) \ + ((grpc_mdelem_data_storage)((md).payload & \ + (uintptr_t)GRPC_MDELEM_STORAGE_INTERNED_BIT)) -/* Constructors for grpc_mdstr instances; take a variety of data types that - clients may have handy */ -grpc_mdstr *grpc_mdstr_from_string(const char *str); -/* Unrefs the slice. */ -grpc_mdstr *grpc_mdstr_from_slice(grpc_slice slice); -grpc_mdstr *grpc_mdstr_from_buffer(const uint8_t *str, size_t length); +/* Unrefs the slices. */ +grpc_mdelem grpc_mdelem_from_slices(grpc_exec_ctx *exec_ctx, grpc_slice key, + grpc_slice value); -/* Returns a borrowed slice from the mdstr with its contents base64 encoded - and huffman compressed */ -grpc_slice grpc_mdstr_as_base64_encoded_and_huffman_compressed(grpc_mdstr *str); +/* Cheaply convert a grpc_metadata to a grpc_mdelem; may use the grpc_metadata + object as backing storage (so lifetimes should align) */ +grpc_mdelem grpc_mdelem_from_grpc_metadata(grpc_exec_ctx *exec_ctx, + grpc_metadata *metadata); -/* Constructors for grpc_mdelem instances; take a variety of data types that - clients may have handy */ -grpc_mdelem *grpc_mdelem_from_metadata_strings(grpc_mdstr *key, - grpc_mdstr *value); -grpc_mdelem *grpc_mdelem_from_strings(const char *key, const char *value); -/* Unrefs the slices. */ -grpc_mdelem *grpc_mdelem_from_slices(grpc_slice key, grpc_slice value); -grpc_mdelem *grpc_mdelem_from_string_and_buffer(const char *key, - const uint8_t *value, - size_t value_length); +/* Does not unref the slices; if a new non-interned mdelem is needed, allocates + one if compatible_external_backing_store is NULL, or uses + compatible_external_backing_store if it is non-NULL (in which case it's the + users responsibility to ensure that it outlives usage) */ +grpc_mdelem grpc_mdelem_create( + grpc_exec_ctx *exec_ctx, grpc_slice key, grpc_slice value, + grpc_mdelem_data *compatible_external_backing_store); + +bool grpc_mdelem_eq(grpc_mdelem a, grpc_mdelem b); -size_t grpc_mdelem_get_size_in_hpack_table(grpc_mdelem *elem); +size_t grpc_mdelem_get_size_in_hpack_table(grpc_mdelem elem); /* Mutator and accessor for grpc_mdelem user data. The destructor function is used as a type tag and is checked during user_data fetch. */ -void *grpc_mdelem_get_user_data(grpc_mdelem *md, +void *grpc_mdelem_get_user_data(grpc_mdelem md, void (*if_destroy_func)(void *)); -void *grpc_mdelem_set_user_data(grpc_mdelem *md, void (*destroy_func)(void *), +void *grpc_mdelem_set_user_data(grpc_mdelem md, void (*destroy_func)(void *), void *user_data); -/* Reference counting */ -//#define GRPC_METADATA_REFCOUNT_DEBUG -#ifdef GRPC_METADATA_REFCOUNT_DEBUG -#define GRPC_MDSTR_REF(s) grpc_mdstr_ref((s), __FILE__, __LINE__) -#define GRPC_MDSTR_UNREF(s) grpc_mdstr_unref((s), __FILE__, __LINE__) +#ifndef NDEBUG #define GRPC_MDELEM_REF(s) grpc_mdelem_ref((s), __FILE__, __LINE__) -#define GRPC_MDELEM_UNREF(s) grpc_mdelem_unref((s), __FILE__, __LINE__) -grpc_mdstr *grpc_mdstr_ref(grpc_mdstr *s, const char *file, int line); -void grpc_mdstr_unref(grpc_mdstr *s, const char *file, int line); -grpc_mdelem *grpc_mdelem_ref(grpc_mdelem *md, const char *file, int line); -void grpc_mdelem_unref(grpc_mdelem *md, const char *file, int line); +#define GRPC_MDELEM_UNREF(exec_ctx, s) \ + grpc_mdelem_unref((exec_ctx), (s), __FILE__, __LINE__) +grpc_mdelem grpc_mdelem_ref(grpc_mdelem md, const char *file, int line); +void grpc_mdelem_unref(grpc_exec_ctx *exec_ctx, grpc_mdelem md, + const char *file, int line); #else -#define GRPC_MDSTR_REF(s) grpc_mdstr_ref((s)) -#define GRPC_MDSTR_UNREF(s) grpc_mdstr_unref((s)) #define GRPC_MDELEM_REF(s) grpc_mdelem_ref((s)) -#define GRPC_MDELEM_UNREF(s) grpc_mdelem_unref((s)) -grpc_mdstr *grpc_mdstr_ref(grpc_mdstr *s); -void grpc_mdstr_unref(grpc_mdstr *s); -grpc_mdelem *grpc_mdelem_ref(grpc_mdelem *md); -void grpc_mdelem_unref(grpc_mdelem *md); +#define GRPC_MDELEM_UNREF(exec_ctx, s) grpc_mdelem_unref((exec_ctx), (s)) +grpc_mdelem grpc_mdelem_ref(grpc_mdelem md); +void grpc_mdelem_unref(grpc_exec_ctx *exec_ctx, grpc_mdelem md); #endif -/* Recover a char* from a grpc_mdstr. The returned string is null terminated. - Does not promise that the returned string has no embedded nulls however. */ -const char *grpc_mdstr_as_c_string(const grpc_mdstr *s); +#define GRPC_MDKEY(md) (GRPC_MDELEM_DATA(md)->key) +#define GRPC_MDVALUE(md) (GRPC_MDELEM_DATA(md)->value) -#define GRPC_MDSTR_LENGTH(s) (GRPC_SLICE_LENGTH(s->slice)) +#define GRPC_MDNULL GRPC_MAKE_MDELEM(NULL, GRPC_MDELEM_STORAGE_EXTERNAL) +#define GRPC_MDISNULL(md) (GRPC_MDELEM_DATA(md) == NULL) /* We add 32 bytes of padding as per RFC-7540 section 6.5.2. */ -#define GRPC_MDELEM_LENGTH(e) \ - (GRPC_MDSTR_LENGTH((e)->key) + GRPC_MDSTR_LENGTH((e)->value) + 32) - -int grpc_mdstr_is_legal_header(grpc_mdstr *s); -int grpc_mdstr_is_legal_nonbin_header(grpc_mdstr *s); -int grpc_mdstr_is_bin_suffixed(grpc_mdstr *s); +#define GRPC_MDELEM_LENGTH(e) \ + (GRPC_SLICE_LENGTH(GRPC_MDKEY((e))) + GRPC_SLICE_LENGTH(GRPC_MDVALUE((e))) + \ + 32) #define GRPC_MDSTR_KV_HASH(k_hash, v_hash) (GPR_ROTL((k_hash), 2) ^ (v_hash)) void grpc_mdctx_global_init(void); -void grpc_mdctx_global_shutdown(void); - -/* Implementation provided by chttp2_transport */ -extern grpc_slice (*grpc_chttp2_base64_encode_and_huffman_compress)( - grpc_slice input); +void grpc_mdctx_global_shutdown(grpc_exec_ctx *exec_ctx); #ifdef __cplusplus } diff --git a/Sources/CgRPC/src/core/lib/transport/metadata_batch.c b/Sources/CgRPC/src/core/lib/transport/metadata_batch.c index 84b5a74d5..8f24b8527 100644 --- a/Sources/CgRPC/src/core/lib/transport/metadata_batch.c +++ b/Sources/CgRPC/src/core/lib/transport/metadata_batch.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -40,6 +25,8 @@ #include #include "src/core/lib/profiling/timers.h" +#include "src/core/lib/slice/slice_internal.h" +#include "src/core/lib/slice/slice_string_helpers.h" static void assert_valid_list(grpc_mdelem_list *list) { #ifndef NDEBUG @@ -51,16 +38,34 @@ static void assert_valid_list(grpc_mdelem_list *list) { GPR_ASSERT(list->tail->next == NULL); GPR_ASSERT((list->head == list->tail) == (list->head->next == NULL)); + size_t verified_count = 0; for (l = list->head; l; l = l->next) { - GPR_ASSERT(l->md); + GPR_ASSERT(!GRPC_MDISNULL(l->md)); GPR_ASSERT((l->prev == NULL) == (l == list->head)); GPR_ASSERT((l->next == NULL) == (l == list->tail)); if (l->next) GPR_ASSERT(l->next->prev == l); if (l->prev) GPR_ASSERT(l->prev->next == l); + verified_count++; } + GPR_ASSERT(list->count == verified_count); #endif /* NDEBUG */ } +static void assert_valid_callouts(grpc_exec_ctx *exec_ctx, + grpc_metadata_batch *batch) { +#ifndef NDEBUG + for (grpc_linked_mdelem *l = batch->list.head; l != NULL; l = l->next) { + grpc_slice key_interned = grpc_slice_intern(GRPC_MDKEY(l->md)); + grpc_metadata_batch_callouts_index callout_idx = + GRPC_BATCH_INDEX_OF(key_interned); + if (callout_idx != GRPC_BATCH_CALLOUTS_COUNT) { + GPR_ASSERT(batch->idx.array[callout_idx] == l); + } + grpc_slice_unref_internal(exec_ctx, key_interned); + } +#endif +} + #ifndef NDEBUG void grpc_metadata_batch_assert_ok(grpc_metadata_batch *batch) { assert_valid_list(&batch->list); @@ -68,28 +73,69 @@ void grpc_metadata_batch_assert_ok(grpc_metadata_batch *batch) { #endif /* NDEBUG */ void grpc_metadata_batch_init(grpc_metadata_batch *batch) { - batch->list.head = batch->list.tail = NULL; + memset(batch, 0, sizeof(*batch)); batch->deadline = gpr_inf_future(GPR_CLOCK_REALTIME); } -void grpc_metadata_batch_destroy(grpc_metadata_batch *batch) { +void grpc_metadata_batch_destroy(grpc_exec_ctx *exec_ctx, + grpc_metadata_batch *batch) { grpc_linked_mdelem *l; for (l = batch->list.head; l; l = l->next) { - GRPC_MDELEM_UNREF(l->md); + GRPC_MDELEM_UNREF(exec_ctx, l->md); + } +} + +grpc_error *grpc_attach_md_to_error(grpc_error *src, grpc_mdelem md) { + grpc_error *out = grpc_error_set_str( + grpc_error_set_str(src, GRPC_ERROR_STR_KEY, + grpc_slice_ref_internal(GRPC_MDKEY(md))), + GRPC_ERROR_STR_VALUE, grpc_slice_ref_internal(GRPC_MDVALUE(md))); + return out; +} + +static grpc_error *maybe_link_callout(grpc_metadata_batch *batch, + grpc_linked_mdelem *storage) + GRPC_MUST_USE_RESULT; + +static grpc_error *maybe_link_callout(grpc_metadata_batch *batch, + grpc_linked_mdelem *storage) { + grpc_metadata_batch_callouts_index idx = + GRPC_BATCH_INDEX_OF(GRPC_MDKEY(storage->md)); + if (idx == GRPC_BATCH_CALLOUTS_COUNT) { + return GRPC_ERROR_NONE; + } + if (batch->idx.array[idx] == NULL) { + batch->idx.array[idx] = storage; + return GRPC_ERROR_NONE; + } + return grpc_attach_md_to_error( + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Unallowed duplicate metadata"), + storage->md); +} + +static void maybe_unlink_callout(grpc_metadata_batch *batch, + grpc_linked_mdelem *storage) { + grpc_metadata_batch_callouts_index idx = + GRPC_BATCH_INDEX_OF(GRPC_MDKEY(storage->md)); + if (idx == GRPC_BATCH_CALLOUTS_COUNT) { + return; } + GPR_ASSERT(batch->idx.array[idx] != NULL); + batch->idx.array[idx] = NULL; } -void grpc_metadata_batch_add_head(grpc_metadata_batch *batch, - grpc_linked_mdelem *storage, - grpc_mdelem *elem_to_add) { - GPR_ASSERT(elem_to_add); +grpc_error *grpc_metadata_batch_add_head(grpc_exec_ctx *exec_ctx, + grpc_metadata_batch *batch, + grpc_linked_mdelem *storage, + grpc_mdelem elem_to_add) { + GPR_ASSERT(!GRPC_MDISNULL(elem_to_add)); storage->md = elem_to_add; - grpc_metadata_batch_link_head(batch, storage); + return grpc_metadata_batch_link_head(exec_ctx, batch, storage); } static void link_head(grpc_mdelem_list *list, grpc_linked_mdelem *storage) { assert_valid_list(list); - GPR_ASSERT(storage->md); + GPR_ASSERT(!GRPC_MDISNULL(storage->md)); storage->prev = NULL; storage->next = list->head; if (list->head != NULL) { @@ -98,25 +144,36 @@ static void link_head(grpc_mdelem_list *list, grpc_linked_mdelem *storage) { list->tail = storage; } list->head = storage; + list->count++; assert_valid_list(list); } -void grpc_metadata_batch_link_head(grpc_metadata_batch *batch, - grpc_linked_mdelem *storage) { +grpc_error *grpc_metadata_batch_link_head(grpc_exec_ctx *exec_ctx, + grpc_metadata_batch *batch, + grpc_linked_mdelem *storage) { + assert_valid_callouts(exec_ctx, batch); + grpc_error *err = maybe_link_callout(batch, storage); + if (err != GRPC_ERROR_NONE) { + assert_valid_callouts(exec_ctx, batch); + return err; + } link_head(&batch->list, storage); + assert_valid_callouts(exec_ctx, batch); + return GRPC_ERROR_NONE; } -void grpc_metadata_batch_add_tail(grpc_metadata_batch *batch, - grpc_linked_mdelem *storage, - grpc_mdelem *elem_to_add) { - GPR_ASSERT(elem_to_add); +grpc_error *grpc_metadata_batch_add_tail(grpc_exec_ctx *exec_ctx, + grpc_metadata_batch *batch, + grpc_linked_mdelem *storage, + grpc_mdelem elem_to_add) { + GPR_ASSERT(!GRPC_MDISNULL(elem_to_add)); storage->md = elem_to_add; - grpc_metadata_batch_link_tail(batch, storage); + return grpc_metadata_batch_link_tail(exec_ctx, batch, storage); } static void link_tail(grpc_mdelem_list *list, grpc_linked_mdelem *storage) { assert_valid_list(list); - GPR_ASSERT(storage->md); + GPR_ASSERT(!GRPC_MDISNULL(storage->md)); storage->prev = list->tail; storage->next = NULL; storage->reserved = NULL; @@ -126,66 +183,88 @@ static void link_tail(grpc_mdelem_list *list, grpc_linked_mdelem *storage) { list->head = storage; } list->tail = storage; + list->count++; assert_valid_list(list); } -void grpc_metadata_batch_link_tail(grpc_metadata_batch *batch, - grpc_linked_mdelem *storage) { +grpc_error *grpc_metadata_batch_link_tail(grpc_exec_ctx *exec_ctx, + grpc_metadata_batch *batch, + grpc_linked_mdelem *storage) { + assert_valid_callouts(exec_ctx, batch); + grpc_error *err = maybe_link_callout(batch, storage); + if (err != GRPC_ERROR_NONE) { + assert_valid_callouts(exec_ctx, batch); + return err; + } link_tail(&batch->list, storage); + assert_valid_callouts(exec_ctx, batch); + return GRPC_ERROR_NONE; } -void grpc_metadata_batch_move(grpc_metadata_batch *dst, - grpc_metadata_batch *src) { - *dst = *src; - memset(src, 0, sizeof(grpc_metadata_batch)); +static void unlink_storage(grpc_mdelem_list *list, + grpc_linked_mdelem *storage) { + assert_valid_list(list); + if (storage->prev != NULL) { + storage->prev->next = storage->next; + } else { + list->head = storage->next; + } + if (storage->next != NULL) { + storage->next->prev = storage->prev; + } else { + list->tail = storage->prev; + } + list->count--; + assert_valid_list(list); } -void grpc_metadata_batch_filter(grpc_metadata_batch *batch, - grpc_mdelem *(*filter)(void *user_data, - grpc_mdelem *elem), - void *user_data) { - grpc_linked_mdelem *l; - grpc_linked_mdelem *next; +void grpc_metadata_batch_remove(grpc_exec_ctx *exec_ctx, + grpc_metadata_batch *batch, + grpc_linked_mdelem *storage) { + assert_valid_callouts(exec_ctx, batch); + maybe_unlink_callout(batch, storage); + unlink_storage(&batch->list, storage); + GRPC_MDELEM_UNREF(exec_ctx, storage->md); + assert_valid_callouts(exec_ctx, batch); +} - GPR_TIMER_BEGIN("grpc_metadata_batch_filter", 0); +void grpc_metadata_batch_set_value(grpc_exec_ctx *exec_ctx, + grpc_linked_mdelem *storage, + grpc_slice value) { + grpc_mdelem old = storage->md; + grpc_mdelem new = grpc_mdelem_from_slices( + exec_ctx, grpc_slice_ref_internal(GRPC_MDKEY(old)), value); + storage->md = new; + GRPC_MDELEM_UNREF(exec_ctx, old); +} - assert_valid_list(&batch->list); - for (l = batch->list.head; l; l = next) { - grpc_mdelem *orig = l->md; - grpc_mdelem *filt = filter(user_data, orig); - next = l->next; - if (filt == NULL) { - if (l->prev) { - l->prev->next = l->next; - } - if (l->next) { - l->next->prev = l->prev; - } - if (batch->list.head == l) { - batch->list.head = l->next; - } - if (batch->list.tail == l) { - batch->list.tail = l->prev; - } - assert_valid_list(&batch->list); - GRPC_MDELEM_UNREF(l->md); - } else if (filt != orig) { - GRPC_MDELEM_UNREF(orig); - l->md = filt; +grpc_error *grpc_metadata_batch_substitute(grpc_exec_ctx *exec_ctx, + grpc_metadata_batch *batch, + grpc_linked_mdelem *storage, + grpc_mdelem new) { + assert_valid_callouts(exec_ctx, batch); + grpc_error *error = GRPC_ERROR_NONE; + grpc_mdelem old = storage->md; + if (!grpc_slice_eq(GRPC_MDKEY(new), GRPC_MDKEY(old))) { + maybe_unlink_callout(batch, storage); + storage->md = new; + error = maybe_link_callout(batch, storage); + if (error != GRPC_ERROR_NONE) { + unlink_storage(&batch->list, storage); + GRPC_MDELEM_UNREF(exec_ctx, storage->md); } + } else { + storage->md = new; } - assert_valid_list(&batch->list); - - GPR_TIMER_END("grpc_metadata_batch_filter", 0); + GRPC_MDELEM_UNREF(exec_ctx, old); + assert_valid_callouts(exec_ctx, batch); + return error; } -static grpc_mdelem *no_metadata_for_you(void *user_data, grpc_mdelem *elem) { - return NULL; -} - -void grpc_metadata_batch_clear(grpc_metadata_batch *batch) { - batch->deadline = gpr_inf_future(GPR_CLOCK_REALTIME); - grpc_metadata_batch_filter(batch, no_metadata_for_you, NULL); +void grpc_metadata_batch_clear(grpc_exec_ctx *exec_ctx, + grpc_metadata_batch *batch) { + grpc_metadata_batch_destroy(exec_ctx, batch); + grpc_metadata_batch_init(batch); } bool grpc_metadata_batch_is_empty(grpc_metadata_batch *batch) { @@ -202,3 +281,33 @@ size_t grpc_metadata_batch_size(grpc_metadata_batch *batch) { } return size; } + +static void add_error(grpc_error **composite, grpc_error *error, + const char *composite_error_string) { + if (error == GRPC_ERROR_NONE) return; + if (*composite == GRPC_ERROR_NONE) { + *composite = GRPC_ERROR_CREATE_FROM_COPIED_STRING(composite_error_string); + } + *composite = grpc_error_add_child(*composite, error); +} + +grpc_error *grpc_metadata_batch_filter(grpc_exec_ctx *exec_ctx, + grpc_metadata_batch *batch, + grpc_metadata_batch_filter_func func, + void *user_data, + const char *composite_error_string) { + grpc_linked_mdelem *l = batch->list.head; + grpc_error *error = GRPC_ERROR_NONE; + while (l) { + grpc_linked_mdelem *next = l->next; + grpc_filtered_mdelem new = func(exec_ctx, user_data, l->md); + add_error(&error, new.error, composite_error_string); + if (GRPC_MDISNULL(new.md)) { + grpc_metadata_batch_remove(exec_ctx, batch, l); + } else if (new.md.payload != l->md.payload) { + grpc_metadata_batch_substitute(exec_ctx, batch, l, new.md); + } + l = next; + } + return error; +} diff --git a/Sources/CgRPC/src/core/lib/transport/metadata_batch.h b/Sources/CgRPC/src/core/lib/transport/metadata_batch.h index 7a9ccb4bc..1b11a3e25 100644 --- a/Sources/CgRPC/src/core/lib/transport/metadata_batch.h +++ b/Sources/CgRPC/src/core/lib/transport/metadata_batch.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -41,19 +26,21 @@ #include #include #include "src/core/lib/transport/metadata.h" +#include "src/core/lib/transport/static_metadata.h" #ifdef __cplusplus extern "C" { #endif typedef struct grpc_linked_mdelem { - grpc_mdelem *md; + grpc_mdelem md; struct grpc_linked_mdelem *next; struct grpc_linked_mdelem *prev; void *reserved; } grpc_linked_mdelem; typedef struct grpc_mdelem_list { + size_t count; grpc_linked_mdelem *head; grpc_linked_mdelem *tail; } grpc_mdelem_list; @@ -61,6 +48,7 @@ typedef struct grpc_mdelem_list { typedef struct grpc_metadata_batch { /** Metadata elements in this batch */ grpc_mdelem_list list; + grpc_metadata_batch_callouts idx; /** Used to calculate grpc-timeout at the point of sending, or gpr_inf_future if this batch does not need to send a grpc-timeout */ @@ -68,32 +56,46 @@ typedef struct grpc_metadata_batch { } grpc_metadata_batch; void grpc_metadata_batch_init(grpc_metadata_batch *batch); -void grpc_metadata_batch_destroy(grpc_metadata_batch *batch); -void grpc_metadata_batch_clear(grpc_metadata_batch *batch); +void grpc_metadata_batch_destroy(grpc_exec_ctx *exec_ctx, + grpc_metadata_batch *batch); +void grpc_metadata_batch_clear(grpc_exec_ctx *exec_ctx, + grpc_metadata_batch *batch); bool grpc_metadata_batch_is_empty(grpc_metadata_batch *batch); /* Returns the transport size of the batch. */ size_t grpc_metadata_batch_size(grpc_metadata_batch *batch); -/** Moves the metadata information from \a src to \a dst. Upon return, \a src is - * zeroed. */ -void grpc_metadata_batch_move(grpc_metadata_batch *dst, - grpc_metadata_batch *src); +/** Remove \a storage from the batch, unreffing the mdelem contained */ +void grpc_metadata_batch_remove(grpc_exec_ctx *exec_ctx, + grpc_metadata_batch *batch, + grpc_linked_mdelem *storage); + +/** Substitute a new mdelem for an old value */ +grpc_error *grpc_metadata_batch_substitute(grpc_exec_ctx *exec_ctx, + grpc_metadata_batch *batch, + grpc_linked_mdelem *storage, + grpc_mdelem new_value); + +void grpc_metadata_batch_set_value(grpc_exec_ctx *exec_ctx, + grpc_linked_mdelem *storage, + grpc_slice value); /** Add \a storage to the beginning of \a batch. storage->md is assumed to be valid. \a storage is owned by the caller and must survive for the lifetime of batch. This usually means it should be around for the lifetime of the call. */ -void grpc_metadata_batch_link_head(grpc_metadata_batch *batch, - grpc_linked_mdelem *storage); +grpc_error *grpc_metadata_batch_link_head( + grpc_exec_ctx *exec_ctx, grpc_metadata_batch *batch, + grpc_linked_mdelem *storage) GRPC_MUST_USE_RESULT; /** Add \a storage to the end of \a batch. storage->md is assumed to be valid. \a storage is owned by the caller and must survive for the lifetime of batch. This usually means it should be around for the lifetime of the call. */ -void grpc_metadata_batch_link_tail(grpc_metadata_batch *batch, - grpc_linked_mdelem *storage); +grpc_error *grpc_metadata_batch_link_tail( + grpc_exec_ctx *exec_ctx, grpc_metadata_batch *batch, + grpc_linked_mdelem *storage) GRPC_MUST_USE_RESULT; /** Add \a elem_to_add as the first element in \a batch, using \a storage as backing storage for the linked list element. @@ -101,27 +103,38 @@ void grpc_metadata_batch_link_tail(grpc_metadata_batch *batch, lifetime of batch. This usually means it should be around for the lifetime of the call. Takes ownership of \a elem_to_add */ -void grpc_metadata_batch_add_head(grpc_metadata_batch *batch, - grpc_linked_mdelem *storage, - grpc_mdelem *elem_to_add); +grpc_error *grpc_metadata_batch_add_head( + grpc_exec_ctx *exec_ctx, grpc_metadata_batch *batch, + grpc_linked_mdelem *storage, grpc_mdelem elem_to_add) GRPC_MUST_USE_RESULT; /** Add \a elem_to_add as the last element in \a batch, using \a storage as backing storage for the linked list element. \a storage is owned by the caller and must survive for the lifetime of batch. This usually means it should be around for the lifetime of the call. Takes ownership of \a elem_to_add */ -void grpc_metadata_batch_add_tail(grpc_metadata_batch *batch, - grpc_linked_mdelem *storage, - grpc_mdelem *elem_to_add); - -/** For each element in \a batch, execute \a filter. - The return value from \a filter will be substituted for the - grpc_mdelem passed to \a filter. If \a filter returns NULL, - the element will be moved to the garbage list. */ -void grpc_metadata_batch_filter(grpc_metadata_batch *batch, - grpc_mdelem *(*filter)(void *user_data, - grpc_mdelem *elem), - void *user_data); +grpc_error *grpc_metadata_batch_add_tail( + grpc_exec_ctx *exec_ctx, grpc_metadata_batch *batch, + grpc_linked_mdelem *storage, grpc_mdelem elem_to_add) GRPC_MUST_USE_RESULT; + +grpc_error *grpc_attach_md_to_error(grpc_error *src, grpc_mdelem md); + +typedef struct { + grpc_error *error; + grpc_mdelem md; +} grpc_filtered_mdelem; + +#define GRPC_FILTERED_ERROR(error) \ + ((grpc_filtered_mdelem){(error), GRPC_MDNULL}) +#define GRPC_FILTERED_MDELEM(md) ((grpc_filtered_mdelem){GRPC_ERROR_NONE, (md)}) +#define GRPC_FILTERED_REMOVE() \ + ((grpc_filtered_mdelem){GRPC_ERROR_NONE, GRPC_MDNULL}) + +typedef grpc_filtered_mdelem (*grpc_metadata_batch_filter_func)( + grpc_exec_ctx *exec_ctx, void *user_data, grpc_mdelem elem); +grpc_error *grpc_metadata_batch_filter( + grpc_exec_ctx *exec_ctx, grpc_metadata_batch *batch, + grpc_metadata_batch_filter_func func, void *user_data, + const char *composite_error_string) GRPC_MUST_USE_RESULT; #ifndef NDEBUG void grpc_metadata_batch_assert_ok(grpc_metadata_batch *comd); diff --git a/Sources/CgRPC/src/core/lib/transport/pid_controller.c b/Sources/CgRPC/src/core/lib/transport/pid_controller.c index 3cef225d4..4b304f17b 100644 --- a/Sources/CgRPC/src/core/lib/transport/pid_controller.c +++ b/Sources/CgRPC/src/core/lib/transport/pid_controller.c @@ -1,57 +1,63 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 "src/core/lib/transport/pid_controller.h" +#include void grpc_pid_controller_init(grpc_pid_controller *pid_controller, - double gain_p, double gain_i, double gain_d) { - pid_controller->gain_p = gain_p; - pid_controller->gain_i = gain_i; - pid_controller->gain_d = gain_d; + grpc_pid_controller_args args) { + pid_controller->args = args; + pid_controller->last_control_value = args.initial_control_value; grpc_pid_controller_reset(pid_controller); } void grpc_pid_controller_reset(grpc_pid_controller *pid_controller) { pid_controller->last_error = 0.0; + pid_controller->last_dc_dt = 0.0; pid_controller->error_integral = 0.0; } double grpc_pid_controller_update(grpc_pid_controller *pid_controller, double error, double dt) { - pid_controller->error_integral += error * dt; + if (dt == 0) return pid_controller->last_control_value; + /* integrate error using the trapezoid rule */ + pid_controller->error_integral += + dt * (pid_controller->last_error + error) * 0.5; + pid_controller->error_integral = GPR_CLAMP( + pid_controller->error_integral, -pid_controller->args.integral_range, + pid_controller->args.integral_range); double diff_error = (error - pid_controller->last_error) / dt; + /* calculate derivative of control value vs time */ + double dc_dt = pid_controller->args.gain_p * error + + pid_controller->args.gain_i * pid_controller->error_integral + + pid_controller->args.gain_d * diff_error; + /* and perform trapezoidal integration */ + double new_control_value = pid_controller->last_control_value + + dt * (pid_controller->last_dc_dt + dc_dt) * 0.5; + new_control_value = + GPR_CLAMP(new_control_value, pid_controller->args.min_control_value, + pid_controller->args.max_control_value); pid_controller->last_error = error; - return dt * (pid_controller->gain_p * error + - pid_controller->gain_i * pid_controller->error_integral + - pid_controller->gain_d * diff_error); + pid_controller->last_dc_dt = dc_dt; + pid_controller->last_control_value = new_control_value; + return new_control_value; +} + +double grpc_pid_controller_last(grpc_pid_controller *pid_controller) { + return pid_controller->last_control_value; } diff --git a/Sources/CgRPC/src/core/lib/transport/pid_controller.h b/Sources/CgRPC/src/core/lib/transport/pid_controller.h index 059b5b083..9352b2643 100644 --- a/Sources/CgRPC/src/core/lib/transport/pid_controller.h +++ b/Sources/CgRPC/src/core/lib/transport/pid_controller.h @@ -1,33 +1,18 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -45,20 +30,33 @@ typedef struct { double gain_p; double gain_i; double gain_d; + double initial_control_value; + double min_control_value; + double max_control_value; + double integral_range; +} grpc_pid_controller_args; + +typedef struct { double last_error; double error_integral; + double last_control_value; + double last_dc_dt; + grpc_pid_controller_args args; } grpc_pid_controller; /** Initialize the controller */ void grpc_pid_controller_init(grpc_pid_controller *pid_controller, - double gain_p, double gain_i, double gain_d); + grpc_pid_controller_args args); /** Reset the controller: useful when things have changed significantly */ void grpc_pid_controller_reset(grpc_pid_controller *pid_controller); /** Update the controller: given a current error estimate, and the time since - the last update, returns a delta to the control value */ + the last update, returns a new control value */ double grpc_pid_controller_update(grpc_pid_controller *pid_controller, double error, double dt); -#endif +/** Returns the last control value calculated */ +double grpc_pid_controller_last(grpc_pid_controller *pid_controller); + +#endif /* GRPC_CORE_LIB_TRANSPORT_PID_CONTROLLER_H */ diff --git a/Sources/CgRPC/src/core/lib/transport/service_config.c b/Sources/CgRPC/src/core/lib/transport/service_config.c index 2e2b59e3f..0379d0010 100644 --- a/Sources/CgRPC/src/core/lib/transport/service_config.c +++ b/Sources/CgRPC/src/core/lib/transport/service_config.c @@ -1,32 +1,17 @@ // -// Copyright 2015, Google Inc. -// All rights reserved. +// Copyright 2015 gRPC authors. // -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: +// 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 // -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. +// http://www.apache.org/licenses/LICENSE-2.0 // -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// 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 "src/core/lib/transport/service_config.h" @@ -39,8 +24,10 @@ #include #include "src/core/lib/json/json.h" +#include "src/core/lib/slice/slice_hash_table.h" +#include "src/core/lib/slice/slice_internal.h" +#include "src/core/lib/slice/slice_string_helpers.h" #include "src/core/lib/support/string.h" -#include "src/core/lib/transport/mdstr_hash_table.h" // The main purpose of the code here is to parse the service config in // JSON form, which will look like this: @@ -91,6 +78,18 @@ void grpc_service_config_destroy(grpc_service_config* service_config) { gpr_free(service_config); } +void grpc_service_config_parse_global_params( + const grpc_service_config* service_config, + void (*process_json)(const grpc_json* json, void* arg), void* arg) { + const grpc_json* json = service_config->json_tree; + if (json->type != GRPC_JSON_OBJECT || json->key != NULL) return; + for (grpc_json* field = json->child; field != NULL; field = field->next) { + if (field->key == NULL) return; + if (strcmp(field->key, "methodConfig") == 0) continue; + process_json(field, arg); + } +} + const char* grpc_service_config_get_lb_policy_name( const grpc_service_config* service_config) { const grpc_json* json = service_config->json_tree; @@ -146,9 +145,9 @@ static char* parse_json_method_name(grpc_json* json) { // each name found, incrementing \a idx for each entry added. // Returns false on error. static bool parse_json_method_config( - grpc_json* json, void* (*create_value)(const grpc_json* method_config_json), - const grpc_mdstr_hash_table_vtable* vtable, - grpc_mdstr_hash_table_entry* entries, size_t* idx) { + grpc_exec_ctx* exec_ctx, grpc_json* json, + void* (*create_value)(const grpc_json* method_config_json), + grpc_slice_hash_table_entry* entries, size_t* idx) { // Construct value. void* method_config = create_value(json); if (method_config == NULL) return false; @@ -169,27 +168,25 @@ static bool parse_json_method_config( if (paths.count == 0) goto done; // No names specified. // Add entry for each path. for (size_t i = 0; i < paths.count; ++i) { - entries[*idx].key = grpc_mdstr_from_string(paths.strs[i]); - entries[*idx].value = vtable->copy_value(method_config); - entries[*idx].vtable = vtable; + entries[*idx].key = grpc_slice_from_copied_string(paths.strs[i]); + entries[*idx].value = method_config; ++*idx; } success = true; done: - vtable->destroy_value(method_config); gpr_strvec_destroy(&paths); return success; } -grpc_mdstr_hash_table* grpc_service_config_create_method_config_table( - const grpc_service_config* service_config, +grpc_slice_hash_table* grpc_service_config_create_method_config_table( + grpc_exec_ctx* exec_ctx, const grpc_service_config* service_config, void* (*create_value)(const grpc_json* method_config_json), - const grpc_mdstr_hash_table_vtable* vtable) { + void (*destroy_value)(grpc_exec_ctx* exec_ctx, void* value)) { const grpc_json* json = service_config->json_tree; // Traverse parsed JSON tree. if (json->type != GRPC_JSON_OBJECT || json->key != NULL) return NULL; size_t num_entries = 0; - grpc_mdstr_hash_table_entry* entries = NULL; + grpc_slice_hash_table_entry* entries = NULL; for (grpc_json* field = json->child; field != NULL; field = field->next) { if (field->key == NULL) return NULL; if (strcmp(field->key, "methodConfig") == 0) { @@ -201,11 +198,11 @@ grpc_mdstr_hash_table* grpc_service_config_create_method_config_table( num_entries += count_names_in_method_config_json(method); } // Populate method config table entries. - entries = gpr_malloc(num_entries * sizeof(grpc_mdstr_hash_table_entry)); + entries = gpr_malloc(num_entries * sizeof(grpc_slice_hash_table_entry)); size_t idx = 0; for (grpc_json* method = field->child; method != NULL; method = method->next) { - if (!parse_json_method_config(method, create_value, vtable, entries, + if (!parse_json_method_config(exec_ctx, method, create_value, entries, &idx)) { return NULL; } @@ -214,36 +211,34 @@ grpc_mdstr_hash_table* grpc_service_config_create_method_config_table( } } // Instantiate method config table. - grpc_mdstr_hash_table* method_config_table = NULL; + grpc_slice_hash_table* method_config_table = NULL; if (entries != NULL) { - method_config_table = grpc_mdstr_hash_table_create(num_entries, entries); - // Clean up. - for (size_t i = 0; i < num_entries; ++i) { - GRPC_MDSTR_UNREF(entries[i].key); - vtable->destroy_value(entries[i].value); - } + method_config_table = + grpc_slice_hash_table_create(num_entries, entries, destroy_value, NULL); gpr_free(entries); } return method_config_table; } -void* grpc_method_config_table_get(const grpc_mdstr_hash_table* table, - const grpc_mdstr* path) { - void* value = grpc_mdstr_hash_table_get(table, path); +void* grpc_method_config_table_get(grpc_exec_ctx* exec_ctx, + const grpc_slice_hash_table* table, + grpc_slice path) { + void* value = grpc_slice_hash_table_get(table, path); // If we didn't find a match for the path, try looking for a wildcard // entry (i.e., change "/service/method" to "/service/*"). if (value == NULL) { - const char* path_str = grpc_mdstr_as_c_string(path); + char* path_str = grpc_slice_to_c_string(path); const char* sep = strrchr(path_str, '/') + 1; const size_t len = (size_t)(sep - path_str); char* buf = gpr_malloc(len + 2); // '*' and NUL memcpy(buf, path_str, len); buf[len] = '*'; buf[len + 1] = '\0'; - grpc_mdstr* wildcard_path = grpc_mdstr_from_string(buf); + grpc_slice wildcard_path = grpc_slice_from_copied_string(buf); gpr_free(buf); - value = grpc_mdstr_hash_table_get(table, wildcard_path); - GRPC_MDSTR_UNREF(wildcard_path); + value = grpc_slice_hash_table_get(table, wildcard_path); + grpc_slice_unref_internal(exec_ctx, wildcard_path); + gpr_free(path_str); } return value; } diff --git a/Sources/CgRPC/src/core/lib/transport/service_config.h b/Sources/CgRPC/src/core/lib/transport/service_config.h index 2ffe47519..84110abc3 100644 --- a/Sources/CgRPC/src/core/lib/transport/service_config.h +++ b/Sources/CgRPC/src/core/lib/transport/service_config.h @@ -1,32 +1,17 @@ // -// Copyright 2016, Google Inc. -// All rights reserved. +// Copyright 2016 gRPC authors. // -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: +// 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 // -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. +// http://www.apache.org/licenses/LICENSE-2.0 // -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// 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 GRPC_CORE_LIB_TRANSPORT_SERVICE_CONFIG_H @@ -35,13 +20,19 @@ #include #include "src/core/lib/json/json.h" -#include "src/core/lib/transport/mdstr_hash_table.h" +#include "src/core/lib/slice/slice_hash_table.h" typedef struct grpc_service_config grpc_service_config; grpc_service_config* grpc_service_config_create(const char* json_string); void grpc_service_config_destroy(grpc_service_config* service_config); +/// Invokes \a process_json() for each global parameter in the service +/// config. \a arg is passed as the second argument to \a process_json(). +void grpc_service_config_parse_global_params( + const grpc_service_config* service_config, + void (*process_json)(const grpc_json* json, void* arg), void* arg); + /// Gets the LB policy name from \a service_config. /// Returns NULL if no LB policy name was specified. /// Caller does NOT take ownership. @@ -51,12 +42,12 @@ const char* grpc_service_config_get_lb_policy_name( /// Creates a method config table based on the data in \a json. /// The table's keys are request paths. The table's value type is /// returned by \a create_value(), based on data parsed from the JSON tree. -/// \a vtable provides methods used to manage the values. +/// \a destroy_value is used to clean up values. /// Returns NULL on error. -grpc_mdstr_hash_table* grpc_service_config_create_method_config_table( - const grpc_service_config* service_config, +grpc_slice_hash_table* grpc_service_config_create_method_config_table( + grpc_exec_ctx* exec_ctx, const grpc_service_config* service_config, void* (*create_value)(const grpc_json* method_config_json), - const grpc_mdstr_hash_table_vtable* vtable); + void (*destroy_value)(grpc_exec_ctx* exec_ctx, void* value)); /// A helper function for looking up values in the table returned by /// \a grpc_service_config_create_method_config_table(). @@ -64,7 +55,8 @@ grpc_mdstr_hash_table* grpc_service_config_create_method_config_table( /// the form "/service/method". /// Returns NULL if the method has no config. /// Caller does NOT own a reference to the result. -void* grpc_method_config_table_get(const grpc_mdstr_hash_table* table, - const grpc_mdstr* path); +void* grpc_method_config_table_get(grpc_exec_ctx* exec_ctx, + const grpc_slice_hash_table* table, + grpc_slice path); #endif /* GRPC_CORE_LIB_TRANSPORT_SERVICE_CONFIG_H */ diff --git a/Sources/CgRPC/src/core/lib/transport/static_metadata.c b/Sources/CgRPC/src/core/lib/transport/static_metadata.c index 8b22592b4..2388f19f8 100644 --- a/Sources/CgRPC/src/core/lib/transport/static_metadata.c +++ b/Sources/CgRPC/src/core/lib/transport/static_metadata.c @@ -1,32 +1,17 @@ /* - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. */ /* @@ -41,120 +26,776 @@ #include "src/core/lib/transport/static_metadata.h" -grpc_mdstr grpc_static_mdstr_table[GRPC_STATIC_MDSTR_COUNT]; +#include "src/core/lib/slice/slice_internal.h" + +static uint8_t g_bytes[] = { + 58, 112, 97, 116, 104, 58, 109, 101, 116, 104, 111, 100, 58, 115, 116, + 97, 116, 117, 115, 58, 97, 117, 116, 104, 111, 114, 105, 116, 121, 58, + 115, 99, 104, 101, 109, 101, 116, 101, 103, 114, 112, 99, 45, 109, 101, + 115, 115, 97, 103, 101, 103, 114, 112, 99, 45, 115, 116, 97, 116, 117, + 115, 103, 114, 112, 99, 45, 112, 97, 121, 108, 111, 97, 100, 45, 98, + 105, 110, 103, 114, 112, 99, 45, 101, 110, 99, 111, 100, 105, 110, 103, + 103, 114, 112, 99, 45, 97, 99, 99, 101, 112, 116, 45, 101, 110, 99, + 111, 100, 105, 110, 103, 103, 114, 112, 99, 45, 115, 101, 114, 118, 101, + 114, 45, 115, 116, 97, 116, 115, 45, 98, 105, 110, 103, 114, 112, 99, + 45, 116, 97, 103, 115, 45, 98, 105, 110, 103, 114, 112, 99, 45, 116, + 114, 97, 99, 101, 45, 98, 105, 110, 99, 111, 110, 116, 101, 110, 116, + 45, 116, 121, 112, 101, 103, 114, 112, 99, 45, 105, 110, 116, 101, 114, + 110, 97, 108, 45, 101, 110, 99, 111, 100, 105, 110, 103, 45, 114, 101, + 113, 117, 101, 115, 116, 117, 115, 101, 114, 45, 97, 103, 101, 110, 116, + 104, 111, 115, 116, 108, 98, 45, 116, 111, 107, 101, 110, 103, 114, 112, + 99, 45, 116, 105, 109, 101, 111, 117, 116, 103, 114, 112, 99, 46, 119, + 97, 105, 116, 95, 102, 111, 114, 95, 114, 101, 97, 100, 121, 103, 114, + 112, 99, 46, 116, 105, 109, 101, 111, 117, 116, 103, 114, 112, 99, 46, + 109, 97, 120, 95, 114, 101, 113, 117, 101, 115, 116, 95, 109, 101, 115, + 115, 97, 103, 101, 95, 98, 121, 116, 101, 115, 103, 114, 112, 99, 46, + 109, 97, 120, 95, 114, 101, 115, 112, 111, 110, 115, 101, 95, 109, 101, + 115, 115, 97, 103, 101, 95, 98, 121, 116, 101, 115, 47, 103, 114, 112, + 99, 46, 108, 98, 46, 118, 49, 46, 76, 111, 97, 100, 66, 97, 108, + 97, 110, 99, 101, 114, 47, 66, 97, 108, 97, 110, 99, 101, 76, 111, + 97, 100, 48, 49, 50, 105, 100, 101, 110, 116, 105, 116, 121, 103, 122, + 105, 112, 100, 101, 102, 108, 97, 116, 101, 116, 114, 97, 105, 108, 101, + 114, 115, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 47, 103, + 114, 112, 99, 80, 79, 83, 84, 50, 48, 48, 52, 48, 52, 104, 116, + 116, 112, 104, 116, 116, 112, 115, 103, 114, 112, 99, 71, 69, 84, 80, + 85, 84, 47, 47, 105, 110, 100, 101, 120, 46, 104, 116, 109, 108, 50, + 48, 52, 50, 48, 54, 51, 48, 52, 52, 48, 48, 53, 48, 48, 97, + 99, 99, 101, 112, 116, 45, 99, 104, 97, 114, 115, 101, 116, 97, 99, + 99, 101, 112, 116, 45, 101, 110, 99, 111, 100, 105, 110, 103, 103, 122, + 105, 112, 44, 32, 100, 101, 102, 108, 97, 116, 101, 97, 99, 99, 101, + 112, 116, 45, 108, 97, 110, 103, 117, 97, 103, 101, 97, 99, 99, 101, + 112, 116, 45, 114, 97, 110, 103, 101, 115, 97, 99, 99, 101, 112, 116, + 97, 99, 99, 101, 115, 115, 45, 99, 111, 110, 116, 114, 111, 108, 45, + 97, 108, 108, 111, 119, 45, 111, 114, 105, 103, 105, 110, 97, 103, 101, + 97, 108, 108, 111, 119, 97, 117, 116, 104, 111, 114, 105, 122, 97, 116, + 105, 111, 110, 99, 97, 99, 104, 101, 45, 99, 111, 110, 116, 114, 111, + 108, 99, 111, 110, 116, 101, 110, 116, 45, 100, 105, 115, 112, 111, 115, + 105, 116, 105, 111, 110, 99, 111, 110, 116, 101, 110, 116, 45, 101, 110, + 99, 111, 100, 105, 110, 103, 99, 111, 110, 116, 101, 110, 116, 45, 108, + 97, 110, 103, 117, 97, 103, 101, 99, 111, 110, 116, 101, 110, 116, 45, + 108, 101, 110, 103, 116, 104, 99, 111, 110, 116, 101, 110, 116, 45, 108, + 111, 99, 97, 116, 105, 111, 110, 99, 111, 110, 116, 101, 110, 116, 45, + 114, 97, 110, 103, 101, 99, 111, 111, 107, 105, 101, 100, 97, 116, 101, + 101, 116, 97, 103, 101, 120, 112, 101, 99, 116, 101, 120, 112, 105, 114, + 101, 115, 102, 114, 111, 109, 105, 102, 45, 109, 97, 116, 99, 104, 105, + 102, 45, 109, 111, 100, 105, 102, 105, 101, 100, 45, 115, 105, 110, 99, + 101, 105, 102, 45, 110, 111, 110, 101, 45, 109, 97, 116, 99, 104, 105, + 102, 45, 114, 97, 110, 103, 101, 105, 102, 45, 117, 110, 109, 111, 100, + 105, 102, 105, 101, 100, 45, 115, 105, 110, 99, 101, 108, 97, 115, 116, + 45, 109, 111, 100, 105, 102, 105, 101, 100, 108, 98, 45, 99, 111, 115, + 116, 45, 98, 105, 110, 108, 105, 110, 107, 108, 111, 99, 97, 116, 105, + 111, 110, 109, 97, 120, 45, 102, 111, 114, 119, 97, 114, 100, 115, 112, + 114, 111, 120, 121, 45, 97, 117, 116, 104, 101, 110, 116, 105, 99, 97, + 116, 101, 112, 114, 111, 120, 121, 45, 97, 117, 116, 104, 111, 114, 105, + 122, 97, 116, 105, 111, 110, 114, 97, 110, 103, 101, 114, 101, 102, 101, + 114, 101, 114, 114, 101, 102, 114, 101, 115, 104, 114, 101, 116, 114, 121, + 45, 97, 102, 116, 101, 114, 115, 101, 114, 118, 101, 114, 115, 101, 116, + 45, 99, 111, 111, 107, 105, 101, 115, 116, 114, 105, 99, 116, 45, 116, + 114, 97, 110, 115, 112, 111, 114, 116, 45, 115, 101, 99, 117, 114, 105, + 116, 121, 116, 114, 97, 110, 115, 102, 101, 114, 45, 101, 110, 99, 111, + 100, 105, 110, 103, 118, 97, 114, 121, 118, 105, 97, 119, 119, 119, 45, + 97, 117, 116, 104, 101, 110, 116, 105, 99, 97, 116, 101, 105, 100, 101, + 110, 116, 105, 116, 121, 44, 100, 101, 102, 108, 97, 116, 101, 105, 100, + 101, 110, 116, 105, 116, 121, 44, 103, 122, 105, 112, 100, 101, 102, 108, + 97, 116, 101, 44, 103, 122, 105, 112, 105, 100, 101, 110, 116, 105, 116, + 121, 44, 100, 101, 102, 108, 97, 116, 101, 44, 103, 122, 105, 112}; + +static void static_ref(void *unused) {} +static void static_unref(grpc_exec_ctx *exec_ctx, void *unused) {} +static const grpc_slice_refcount_vtable static_sub_vtable = { + static_ref, static_unref, grpc_slice_default_eq_impl, + grpc_slice_default_hash_impl}; +const grpc_slice_refcount_vtable grpc_static_metadata_vtable = { + static_ref, static_unref, grpc_static_slice_eq, grpc_static_slice_hash}; +static grpc_slice_refcount static_sub_refcnt = {&static_sub_vtable, + &static_sub_refcnt}; +grpc_slice_refcount grpc_static_metadata_refcounts[GRPC_STATIC_MDSTR_COUNT] = { + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, + {&grpc_static_metadata_vtable, &static_sub_refcnt}, +}; + +const grpc_slice grpc_static_slice_table[GRPC_STATIC_MDSTR_COUNT] = { + {.refcount = &grpc_static_metadata_refcounts[0], + .data.refcounted = {g_bytes + 0, 5}}, + {.refcount = &grpc_static_metadata_refcounts[1], + .data.refcounted = {g_bytes + 5, 7}}, + {.refcount = &grpc_static_metadata_refcounts[2], + .data.refcounted = {g_bytes + 12, 7}}, + {.refcount = &grpc_static_metadata_refcounts[3], + .data.refcounted = {g_bytes + 19, 10}}, + {.refcount = &grpc_static_metadata_refcounts[4], + .data.refcounted = {g_bytes + 29, 7}}, + {.refcount = &grpc_static_metadata_refcounts[5], + .data.refcounted = {g_bytes + 36, 2}}, + {.refcount = &grpc_static_metadata_refcounts[6], + .data.refcounted = {g_bytes + 38, 12}}, + {.refcount = &grpc_static_metadata_refcounts[7], + .data.refcounted = {g_bytes + 50, 11}}, + {.refcount = &grpc_static_metadata_refcounts[8], + .data.refcounted = {g_bytes + 61, 16}}, + {.refcount = &grpc_static_metadata_refcounts[9], + .data.refcounted = {g_bytes + 77, 13}}, + {.refcount = &grpc_static_metadata_refcounts[10], + .data.refcounted = {g_bytes + 90, 20}}, + {.refcount = &grpc_static_metadata_refcounts[11], + .data.refcounted = {g_bytes + 110, 21}}, + {.refcount = &grpc_static_metadata_refcounts[12], + .data.refcounted = {g_bytes + 131, 13}}, + {.refcount = &grpc_static_metadata_refcounts[13], + .data.refcounted = {g_bytes + 144, 14}}, + {.refcount = &grpc_static_metadata_refcounts[14], + .data.refcounted = {g_bytes + 158, 12}}, + {.refcount = &grpc_static_metadata_refcounts[15], + .data.refcounted = {g_bytes + 170, 30}}, + {.refcount = &grpc_static_metadata_refcounts[16], + .data.refcounted = {g_bytes + 200, 10}}, + {.refcount = &grpc_static_metadata_refcounts[17], + .data.refcounted = {g_bytes + 210, 4}}, + {.refcount = &grpc_static_metadata_refcounts[18], + .data.refcounted = {g_bytes + 214, 8}}, + {.refcount = &grpc_static_metadata_refcounts[19], + .data.refcounted = {g_bytes + 222, 12}}, + {.refcount = &grpc_static_metadata_refcounts[20], + .data.refcounted = {g_bytes + 234, 0}}, + {.refcount = &grpc_static_metadata_refcounts[21], + .data.refcounted = {g_bytes + 234, 19}}, + {.refcount = &grpc_static_metadata_refcounts[22], + .data.refcounted = {g_bytes + 253, 12}}, + {.refcount = &grpc_static_metadata_refcounts[23], + .data.refcounted = {g_bytes + 265, 30}}, + {.refcount = &grpc_static_metadata_refcounts[24], + .data.refcounted = {g_bytes + 295, 31}}, + {.refcount = &grpc_static_metadata_refcounts[25], + .data.refcounted = {g_bytes + 326, 36}}, + {.refcount = &grpc_static_metadata_refcounts[26], + .data.refcounted = {g_bytes + 362, 1}}, + {.refcount = &grpc_static_metadata_refcounts[27], + .data.refcounted = {g_bytes + 363, 1}}, + {.refcount = &grpc_static_metadata_refcounts[28], + .data.refcounted = {g_bytes + 364, 1}}, + {.refcount = &grpc_static_metadata_refcounts[29], + .data.refcounted = {g_bytes + 365, 8}}, + {.refcount = &grpc_static_metadata_refcounts[30], + .data.refcounted = {g_bytes + 373, 4}}, + {.refcount = &grpc_static_metadata_refcounts[31], + .data.refcounted = {g_bytes + 377, 7}}, + {.refcount = &grpc_static_metadata_refcounts[32], + .data.refcounted = {g_bytes + 384, 8}}, + {.refcount = &grpc_static_metadata_refcounts[33], + .data.refcounted = {g_bytes + 392, 16}}, + {.refcount = &grpc_static_metadata_refcounts[34], + .data.refcounted = {g_bytes + 408, 4}}, + {.refcount = &grpc_static_metadata_refcounts[35], + .data.refcounted = {g_bytes + 412, 3}}, + {.refcount = &grpc_static_metadata_refcounts[36], + .data.refcounted = {g_bytes + 415, 3}}, + {.refcount = &grpc_static_metadata_refcounts[37], + .data.refcounted = {g_bytes + 418, 4}}, + {.refcount = &grpc_static_metadata_refcounts[38], + .data.refcounted = {g_bytes + 422, 5}}, + {.refcount = &grpc_static_metadata_refcounts[39], + .data.refcounted = {g_bytes + 427, 4}}, + {.refcount = &grpc_static_metadata_refcounts[40], + .data.refcounted = {g_bytes + 431, 3}}, + {.refcount = &grpc_static_metadata_refcounts[41], + .data.refcounted = {g_bytes + 434, 3}}, + {.refcount = &grpc_static_metadata_refcounts[42], + .data.refcounted = {g_bytes + 437, 1}}, + {.refcount = &grpc_static_metadata_refcounts[43], + .data.refcounted = {g_bytes + 438, 11}}, + {.refcount = &grpc_static_metadata_refcounts[44], + .data.refcounted = {g_bytes + 449, 3}}, + {.refcount = &grpc_static_metadata_refcounts[45], + .data.refcounted = {g_bytes + 452, 3}}, + {.refcount = &grpc_static_metadata_refcounts[46], + .data.refcounted = {g_bytes + 455, 3}}, + {.refcount = &grpc_static_metadata_refcounts[47], + .data.refcounted = {g_bytes + 458, 3}}, + {.refcount = &grpc_static_metadata_refcounts[48], + .data.refcounted = {g_bytes + 461, 3}}, + {.refcount = &grpc_static_metadata_refcounts[49], + .data.refcounted = {g_bytes + 464, 14}}, + {.refcount = &grpc_static_metadata_refcounts[50], + .data.refcounted = {g_bytes + 478, 15}}, + {.refcount = &grpc_static_metadata_refcounts[51], + .data.refcounted = {g_bytes + 493, 13}}, + {.refcount = &grpc_static_metadata_refcounts[52], + .data.refcounted = {g_bytes + 506, 15}}, + {.refcount = &grpc_static_metadata_refcounts[53], + .data.refcounted = {g_bytes + 521, 13}}, + {.refcount = &grpc_static_metadata_refcounts[54], + .data.refcounted = {g_bytes + 534, 6}}, + {.refcount = &grpc_static_metadata_refcounts[55], + .data.refcounted = {g_bytes + 540, 27}}, + {.refcount = &grpc_static_metadata_refcounts[56], + .data.refcounted = {g_bytes + 567, 3}}, + {.refcount = &grpc_static_metadata_refcounts[57], + .data.refcounted = {g_bytes + 570, 5}}, + {.refcount = &grpc_static_metadata_refcounts[58], + .data.refcounted = {g_bytes + 575, 13}}, + {.refcount = &grpc_static_metadata_refcounts[59], + .data.refcounted = {g_bytes + 588, 13}}, + {.refcount = &grpc_static_metadata_refcounts[60], + .data.refcounted = {g_bytes + 601, 19}}, + {.refcount = &grpc_static_metadata_refcounts[61], + .data.refcounted = {g_bytes + 620, 16}}, + {.refcount = &grpc_static_metadata_refcounts[62], + .data.refcounted = {g_bytes + 636, 16}}, + {.refcount = &grpc_static_metadata_refcounts[63], + .data.refcounted = {g_bytes + 652, 14}}, + {.refcount = &grpc_static_metadata_refcounts[64], + .data.refcounted = {g_bytes + 666, 16}}, + {.refcount = &grpc_static_metadata_refcounts[65], + .data.refcounted = {g_bytes + 682, 13}}, + {.refcount = &grpc_static_metadata_refcounts[66], + .data.refcounted = {g_bytes + 695, 6}}, + {.refcount = &grpc_static_metadata_refcounts[67], + .data.refcounted = {g_bytes + 701, 4}}, + {.refcount = &grpc_static_metadata_refcounts[68], + .data.refcounted = {g_bytes + 705, 4}}, + {.refcount = &grpc_static_metadata_refcounts[69], + .data.refcounted = {g_bytes + 709, 6}}, + {.refcount = &grpc_static_metadata_refcounts[70], + .data.refcounted = {g_bytes + 715, 7}}, + {.refcount = &grpc_static_metadata_refcounts[71], + .data.refcounted = {g_bytes + 722, 4}}, + {.refcount = &grpc_static_metadata_refcounts[72], + .data.refcounted = {g_bytes + 726, 8}}, + {.refcount = &grpc_static_metadata_refcounts[73], + .data.refcounted = {g_bytes + 734, 17}}, + {.refcount = &grpc_static_metadata_refcounts[74], + .data.refcounted = {g_bytes + 751, 13}}, + {.refcount = &grpc_static_metadata_refcounts[75], + .data.refcounted = {g_bytes + 764, 8}}, + {.refcount = &grpc_static_metadata_refcounts[76], + .data.refcounted = {g_bytes + 772, 19}}, + {.refcount = &grpc_static_metadata_refcounts[77], + .data.refcounted = {g_bytes + 791, 13}}, + {.refcount = &grpc_static_metadata_refcounts[78], + .data.refcounted = {g_bytes + 804, 11}}, + {.refcount = &grpc_static_metadata_refcounts[79], + .data.refcounted = {g_bytes + 815, 4}}, + {.refcount = &grpc_static_metadata_refcounts[80], + .data.refcounted = {g_bytes + 819, 8}}, + {.refcount = &grpc_static_metadata_refcounts[81], + .data.refcounted = {g_bytes + 827, 12}}, + {.refcount = &grpc_static_metadata_refcounts[82], + .data.refcounted = {g_bytes + 839, 18}}, + {.refcount = &grpc_static_metadata_refcounts[83], + .data.refcounted = {g_bytes + 857, 19}}, + {.refcount = &grpc_static_metadata_refcounts[84], + .data.refcounted = {g_bytes + 876, 5}}, + {.refcount = &grpc_static_metadata_refcounts[85], + .data.refcounted = {g_bytes + 881, 7}}, + {.refcount = &grpc_static_metadata_refcounts[86], + .data.refcounted = {g_bytes + 888, 7}}, + {.refcount = &grpc_static_metadata_refcounts[87], + .data.refcounted = {g_bytes + 895, 11}}, + {.refcount = &grpc_static_metadata_refcounts[88], + .data.refcounted = {g_bytes + 906, 6}}, + {.refcount = &grpc_static_metadata_refcounts[89], + .data.refcounted = {g_bytes + 912, 10}}, + {.refcount = &grpc_static_metadata_refcounts[90], + .data.refcounted = {g_bytes + 922, 25}}, + {.refcount = &grpc_static_metadata_refcounts[91], + .data.refcounted = {g_bytes + 947, 17}}, + {.refcount = &grpc_static_metadata_refcounts[92], + .data.refcounted = {g_bytes + 964, 4}}, + {.refcount = &grpc_static_metadata_refcounts[93], + .data.refcounted = {g_bytes + 968, 3}}, + {.refcount = &grpc_static_metadata_refcounts[94], + .data.refcounted = {g_bytes + 971, 16}}, + {.refcount = &grpc_static_metadata_refcounts[95], + .data.refcounted = {g_bytes + 987, 16}}, + {.refcount = &grpc_static_metadata_refcounts[96], + .data.refcounted = {g_bytes + 1003, 13}}, + {.refcount = &grpc_static_metadata_refcounts[97], + .data.refcounted = {g_bytes + 1016, 12}}, + {.refcount = &grpc_static_metadata_refcounts[98], + .data.refcounted = {g_bytes + 1028, 21}}, +}; -grpc_mdelem grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT]; uintptr_t grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 4, 8, 6, 2, 4, 8, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 4, 6, 6, 8, 8}; + +static const int8_t elems_r[] = { + 10, 8, -3, 0, 9, 21, -77, 22, 0, 10, -7, 0, 0, 0, + 14, 0, 13, 12, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, -50, -51, 16, -53, -54, -55, -56, + -56, -57, -58, -59, 0, 37, 36, 35, 34, 33, 32, 31, 30, 29, + 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, + 14, 13, 12, 11, 10, 13, 12, 11, 10, 9, 8, 7, 0}; +static uint32_t elems_phash(uint32_t i) { + i -= 42; + uint32_t x = i % 97; + uint32_t y = i / 97; + uint32_t h = x; + if (y < GPR_ARRAY_SIZE(elems_r)) { + uint32_t delta = (uint32_t)elems_r[y]; + h += delta; + } + return h; +} -const uint8_t grpc_static_metadata_elem_indices[GRPC_STATIC_MDELEM_COUNT * 2] = - {11, 33, 10, 33, 12, 33, 12, 50, 13, 33, 14, 33, 15, 33, 16, 33, 17, 33, - 19, 33, 20, 33, 21, 33, 22, 33, 23, 33, 24, 33, 25, 33, 26, 33, 27, 33, - 28, 18, 28, 33, 29, 33, 30, 33, 34, 33, 35, 33, 36, 33, 37, 33, 40, 31, - 40, 32, 40, 49, 40, 54, 40, 55, 40, 56, 40, 57, 41, 31, 41, 49, 41, 54, - 46, 0, 46, 1, 46, 2, 51, 33, 58, 33, 59, 33, 60, 33, 61, 33, 62, 33, - 63, 33, 64, 33, 65, 33, 66, 33, 67, 33, 68, 33, 69, 38, 69, 71, 69, 74, - 70, 82, 70, 83, 72, 33, 73, 33, 75, 33, 76, 33, 77, 33, 78, 33, 79, 39, - 79, 52, 79, 53, 80, 33, 81, 33, 84, 3, 84, 4, 84, 5, 84, 6, 84, 7, - 84, 8, 84, 9, 85, 33, 86, 87, 88, 33, 89, 33, 90, 33, 91, 33, 92, 33}; +static const uint16_t elem_keys[] = { + 1019, 1020, 1021, 242, 243, 244, 245, 246, 139, 140, 42, 43, + 433, 434, 435, 920, 921, 922, 719, 720, 1406, 527, 721, 1604, + 1703, 1802, 4871, 4970, 5001, 5168, 5267, 5366, 5465, 1419, 5564, 5663, + 5762, 5861, 5960, 6059, 6158, 6257, 6356, 6455, 6554, 6653, 6752, 6851, + 6950, 7049, 7148, 7247, 7346, 7445, 7544, 7643, 7742, 7841, 7940, 8039, + 8138, 8237, 8336, 8435, 8534, 8633, 1085, 1086, 1087, 1088, 8732, 8831, + 8930, 9029, 9128, 9227, 9326, 0, 317, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 133, 233, 234, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0}; +static const uint8_t elem_idxs[] = { + 74, 77, 75, 19, 20, 21, 22, 23, 15, 16, 17, 18, 11, 12, 13, + 3, 4, 5, 0, 1, 41, 6, 2, 70, 48, 55, 24, 25, 26, 27, + 28, 29, 30, 7, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 42, + 43, 44, 45, 46, 47, 49, 50, 51, 52, 53, 54, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 65, 76, 78, 79, 80, 66, 67, 68, 69, 71, + 72, 73, 255, 14, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 8, 9, 10}; -const char *const grpc_static_metadata_strings[GRPC_STATIC_MDSTR_COUNT] = { - "0", - "1", - "2", - "200", - "204", - "206", - "304", - "400", - "404", - "500", - "accept", - "accept-charset", - "accept-encoding", - "accept-language", - "accept-ranges", - "access-control-allow-origin", - "age", - "allow", - "application/grpc", - ":authority", - "authorization", - "cache-control", - "content-disposition", - "content-encoding", - "content-language", - "content-length", - "content-location", - "content-range", - "content-type", - "cookie", - "date", - "deflate", - "deflate,gzip", - "", - "etag", - "expect", - "expires", - "from", - "GET", - "grpc", - "grpc-accept-encoding", - "grpc-encoding", - "grpc-internal-encoding-request", - "grpc-message", - "grpc-payload-bin", - "grpc-stats-bin", - "grpc-status", - "grpc-timeout", - "grpc-tracing-bin", - "gzip", - "gzip, deflate", - "host", - "http", - "https", - "identity", - "identity,deflate", - "identity,deflate,gzip", - "identity,gzip", - "if-match", - "if-modified-since", - "if-none-match", - "if-range", - "if-unmodified-since", - "last-modified", - "lb-cost-bin", - "lb-token", - "link", - "location", - "max-forwards", - ":method", - ":path", - "POST", - "proxy-authenticate", - "proxy-authorization", - "PUT", - "range", - "referer", - "refresh", - "retry-after", - ":scheme", - "server", - "set-cookie", - "/", - "/index.html", - ":status", - "strict-transport-security", - "te", - "trailers", - "transfer-encoding", - "user-agent", - "vary", - "via", - "www-authenticate"}; +grpc_mdelem grpc_static_mdelem_for_static_strings(int a, int b) { + if (a == -1 || b == -1) return GRPC_MDNULL; + uint32_t k = (uint32_t)(a * 99 + b); + uint32_t h = elems_phash(k); + return h < GPR_ARRAY_SIZE(elem_keys) && elem_keys[h] == k && + elem_idxs[h] != 255 + ? GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[elem_idxs[h]], + GRPC_MDELEM_STORAGE_STATIC) + : GRPC_MDNULL; +} -const uint8_t grpc_static_accept_encoding_metadata[8] = {0, 29, 26, 30, - 28, 32, 27, 31}; +grpc_mdelem_data grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT] = { + {{.refcount = &grpc_static_metadata_refcounts[7], + .data.refcounted = {g_bytes + 50, 11}}, + {.refcount = &grpc_static_metadata_refcounts[26], + .data.refcounted = {g_bytes + 362, 1}}}, + {{.refcount = &grpc_static_metadata_refcounts[7], + .data.refcounted = {g_bytes + 50, 11}}, + {.refcount = &grpc_static_metadata_refcounts[27], + .data.refcounted = {g_bytes + 363, 1}}}, + {{.refcount = &grpc_static_metadata_refcounts[7], + .data.refcounted = {g_bytes + 50, 11}}, + {.refcount = &grpc_static_metadata_refcounts[28], + .data.refcounted = {g_bytes + 364, 1}}}, + {{.refcount = &grpc_static_metadata_refcounts[9], + .data.refcounted = {g_bytes + 77, 13}}, + {.refcount = &grpc_static_metadata_refcounts[29], + .data.refcounted = {g_bytes + 365, 8}}}, + {{.refcount = &grpc_static_metadata_refcounts[9], + .data.refcounted = {g_bytes + 77, 13}}, + {.refcount = &grpc_static_metadata_refcounts[30], + .data.refcounted = {g_bytes + 373, 4}}}, + {{.refcount = &grpc_static_metadata_refcounts[9], + .data.refcounted = {g_bytes + 77, 13}}, + {.refcount = &grpc_static_metadata_refcounts[31], + .data.refcounted = {g_bytes + 377, 7}}}, + {{.refcount = &grpc_static_metadata_refcounts[5], + .data.refcounted = {g_bytes + 36, 2}}, + {.refcount = &grpc_static_metadata_refcounts[32], + .data.refcounted = {g_bytes + 384, 8}}}, + {{.refcount = &grpc_static_metadata_refcounts[14], + .data.refcounted = {g_bytes + 158, 12}}, + {.refcount = &grpc_static_metadata_refcounts[33], + .data.refcounted = {g_bytes + 392, 16}}}, + {{.refcount = &grpc_static_metadata_refcounts[1], + .data.refcounted = {g_bytes + 5, 7}}, + {.refcount = &grpc_static_metadata_refcounts[34], + .data.refcounted = {g_bytes + 408, 4}}}, + {{.refcount = &grpc_static_metadata_refcounts[2], + .data.refcounted = {g_bytes + 12, 7}}, + {.refcount = &grpc_static_metadata_refcounts[35], + .data.refcounted = {g_bytes + 412, 3}}}, + {{.refcount = &grpc_static_metadata_refcounts[2], + .data.refcounted = {g_bytes + 12, 7}}, + {.refcount = &grpc_static_metadata_refcounts[36], + .data.refcounted = {g_bytes + 415, 3}}}, + {{.refcount = &grpc_static_metadata_refcounts[4], + .data.refcounted = {g_bytes + 29, 7}}, + {.refcount = &grpc_static_metadata_refcounts[37], + .data.refcounted = {g_bytes + 418, 4}}}, + {{.refcount = &grpc_static_metadata_refcounts[4], + .data.refcounted = {g_bytes + 29, 7}}, + {.refcount = &grpc_static_metadata_refcounts[38], + .data.refcounted = {g_bytes + 422, 5}}}, + {{.refcount = &grpc_static_metadata_refcounts[4], + .data.refcounted = {g_bytes + 29, 7}}, + {.refcount = &grpc_static_metadata_refcounts[39], + .data.refcounted = {g_bytes + 427, 4}}}, + {{.refcount = &grpc_static_metadata_refcounts[3], + .data.refcounted = {g_bytes + 19, 10}}, + {.refcount = &grpc_static_metadata_refcounts[20], + .data.refcounted = {g_bytes + 234, 0}}}, + {{.refcount = &grpc_static_metadata_refcounts[1], + .data.refcounted = {g_bytes + 5, 7}}, + {.refcount = &grpc_static_metadata_refcounts[40], + .data.refcounted = {g_bytes + 431, 3}}}, + {{.refcount = &grpc_static_metadata_refcounts[1], + .data.refcounted = {g_bytes + 5, 7}}, + {.refcount = &grpc_static_metadata_refcounts[41], + .data.refcounted = {g_bytes + 434, 3}}}, + {{.refcount = &grpc_static_metadata_refcounts[0], + .data.refcounted = {g_bytes + 0, 5}}, + {.refcount = &grpc_static_metadata_refcounts[42], + .data.refcounted = {g_bytes + 437, 1}}}, + {{.refcount = &grpc_static_metadata_refcounts[0], + .data.refcounted = {g_bytes + 0, 5}}, + {.refcount = &grpc_static_metadata_refcounts[43], + .data.refcounted = {g_bytes + 438, 11}}}, + {{.refcount = &grpc_static_metadata_refcounts[2], + .data.refcounted = {g_bytes + 12, 7}}, + {.refcount = &grpc_static_metadata_refcounts[44], + .data.refcounted = {g_bytes + 449, 3}}}, + {{.refcount = &grpc_static_metadata_refcounts[2], + .data.refcounted = {g_bytes + 12, 7}}, + {.refcount = &grpc_static_metadata_refcounts[45], + .data.refcounted = {g_bytes + 452, 3}}}, + {{.refcount = &grpc_static_metadata_refcounts[2], + .data.refcounted = {g_bytes + 12, 7}}, + {.refcount = &grpc_static_metadata_refcounts[46], + .data.refcounted = {g_bytes + 455, 3}}}, + {{.refcount = &grpc_static_metadata_refcounts[2], + .data.refcounted = {g_bytes + 12, 7}}, + {.refcount = &grpc_static_metadata_refcounts[47], + .data.refcounted = {g_bytes + 458, 3}}}, + {{.refcount = &grpc_static_metadata_refcounts[2], + .data.refcounted = {g_bytes + 12, 7}}, + {.refcount = &grpc_static_metadata_refcounts[48], + .data.refcounted = {g_bytes + 461, 3}}}, + {{.refcount = &grpc_static_metadata_refcounts[49], + .data.refcounted = {g_bytes + 464, 14}}, + {.refcount = &grpc_static_metadata_refcounts[20], + .data.refcounted = {g_bytes + 234, 0}}}, + {{.refcount = &grpc_static_metadata_refcounts[50], + .data.refcounted = {g_bytes + 478, 15}}, + {.refcount = &grpc_static_metadata_refcounts[20], + .data.refcounted = {g_bytes + 234, 0}}}, + {{.refcount = &grpc_static_metadata_refcounts[50], + .data.refcounted = {g_bytes + 478, 15}}, + {.refcount = &grpc_static_metadata_refcounts[51], + .data.refcounted = {g_bytes + 493, 13}}}, + {{.refcount = &grpc_static_metadata_refcounts[52], + .data.refcounted = {g_bytes + 506, 15}}, + {.refcount = &grpc_static_metadata_refcounts[20], + .data.refcounted = {g_bytes + 234, 0}}}, + {{.refcount = &grpc_static_metadata_refcounts[53], + .data.refcounted = {g_bytes + 521, 13}}, + {.refcount = &grpc_static_metadata_refcounts[20], + .data.refcounted = {g_bytes + 234, 0}}}, + {{.refcount = &grpc_static_metadata_refcounts[54], + .data.refcounted = {g_bytes + 534, 6}}, + {.refcount = &grpc_static_metadata_refcounts[20], + .data.refcounted = {g_bytes + 234, 0}}}, + {{.refcount = &grpc_static_metadata_refcounts[55], + .data.refcounted = {g_bytes + 540, 27}}, + {.refcount = &grpc_static_metadata_refcounts[20], + .data.refcounted = {g_bytes + 234, 0}}}, + {{.refcount = &grpc_static_metadata_refcounts[56], + .data.refcounted = {g_bytes + 567, 3}}, + {.refcount = &grpc_static_metadata_refcounts[20], + .data.refcounted = {g_bytes + 234, 0}}}, + {{.refcount = &grpc_static_metadata_refcounts[57], + .data.refcounted = {g_bytes + 570, 5}}, + {.refcount = &grpc_static_metadata_refcounts[20], + .data.refcounted = {g_bytes + 234, 0}}}, + {{.refcount = &grpc_static_metadata_refcounts[58], + .data.refcounted = {g_bytes + 575, 13}}, + {.refcount = &grpc_static_metadata_refcounts[20], + .data.refcounted = {g_bytes + 234, 0}}}, + {{.refcount = &grpc_static_metadata_refcounts[59], + .data.refcounted = {g_bytes + 588, 13}}, + {.refcount = &grpc_static_metadata_refcounts[20], + .data.refcounted = {g_bytes + 234, 0}}}, + {{.refcount = &grpc_static_metadata_refcounts[60], + .data.refcounted = {g_bytes + 601, 19}}, + {.refcount = &grpc_static_metadata_refcounts[20], + .data.refcounted = {g_bytes + 234, 0}}}, + {{.refcount = &grpc_static_metadata_refcounts[61], + .data.refcounted = {g_bytes + 620, 16}}, + {.refcount = &grpc_static_metadata_refcounts[20], + .data.refcounted = {g_bytes + 234, 0}}}, + {{.refcount = &grpc_static_metadata_refcounts[62], + .data.refcounted = {g_bytes + 636, 16}}, + {.refcount = &grpc_static_metadata_refcounts[20], + .data.refcounted = {g_bytes + 234, 0}}}, + {{.refcount = &grpc_static_metadata_refcounts[63], + .data.refcounted = {g_bytes + 652, 14}}, + {.refcount = &grpc_static_metadata_refcounts[20], + .data.refcounted = {g_bytes + 234, 0}}}, + {{.refcount = &grpc_static_metadata_refcounts[64], + .data.refcounted = {g_bytes + 666, 16}}, + {.refcount = &grpc_static_metadata_refcounts[20], + .data.refcounted = {g_bytes + 234, 0}}}, + {{.refcount = &grpc_static_metadata_refcounts[65], + .data.refcounted = {g_bytes + 682, 13}}, + {.refcount = &grpc_static_metadata_refcounts[20], + .data.refcounted = {g_bytes + 234, 0}}}, + {{.refcount = &grpc_static_metadata_refcounts[14], + .data.refcounted = {g_bytes + 158, 12}}, + {.refcount = &grpc_static_metadata_refcounts[20], + .data.refcounted = {g_bytes + 234, 0}}}, + {{.refcount = &grpc_static_metadata_refcounts[66], + .data.refcounted = {g_bytes + 695, 6}}, + {.refcount = &grpc_static_metadata_refcounts[20], + .data.refcounted = {g_bytes + 234, 0}}}, + {{.refcount = &grpc_static_metadata_refcounts[67], + .data.refcounted = {g_bytes + 701, 4}}, + {.refcount = &grpc_static_metadata_refcounts[20], + .data.refcounted = {g_bytes + 234, 0}}}, + {{.refcount = &grpc_static_metadata_refcounts[68], + .data.refcounted = {g_bytes + 705, 4}}, + {.refcount = &grpc_static_metadata_refcounts[20], + .data.refcounted = {g_bytes + 234, 0}}}, + {{.refcount = &grpc_static_metadata_refcounts[69], + .data.refcounted = {g_bytes + 709, 6}}, + {.refcount = &grpc_static_metadata_refcounts[20], + .data.refcounted = {g_bytes + 234, 0}}}, + {{.refcount = &grpc_static_metadata_refcounts[70], + .data.refcounted = {g_bytes + 715, 7}}, + {.refcount = &grpc_static_metadata_refcounts[20], + .data.refcounted = {g_bytes + 234, 0}}}, + {{.refcount = &grpc_static_metadata_refcounts[71], + .data.refcounted = {g_bytes + 722, 4}}, + {.refcount = &grpc_static_metadata_refcounts[20], + .data.refcounted = {g_bytes + 234, 0}}}, + {{.refcount = &grpc_static_metadata_refcounts[17], + .data.refcounted = {g_bytes + 210, 4}}, + {.refcount = &grpc_static_metadata_refcounts[20], + .data.refcounted = {g_bytes + 234, 0}}}, + {{.refcount = &grpc_static_metadata_refcounts[72], + .data.refcounted = {g_bytes + 726, 8}}, + {.refcount = &grpc_static_metadata_refcounts[20], + .data.refcounted = {g_bytes + 234, 0}}}, + {{.refcount = &grpc_static_metadata_refcounts[73], + .data.refcounted = {g_bytes + 734, 17}}, + {.refcount = &grpc_static_metadata_refcounts[20], + .data.refcounted = {g_bytes + 234, 0}}}, + {{.refcount = &grpc_static_metadata_refcounts[74], + .data.refcounted = {g_bytes + 751, 13}}, + {.refcount = &grpc_static_metadata_refcounts[20], + .data.refcounted = {g_bytes + 234, 0}}}, + {{.refcount = &grpc_static_metadata_refcounts[75], + .data.refcounted = {g_bytes + 764, 8}}, + {.refcount = &grpc_static_metadata_refcounts[20], + .data.refcounted = {g_bytes + 234, 0}}}, + {{.refcount = &grpc_static_metadata_refcounts[76], + .data.refcounted = {g_bytes + 772, 19}}, + {.refcount = &grpc_static_metadata_refcounts[20], + .data.refcounted = {g_bytes + 234, 0}}}, + {{.refcount = &grpc_static_metadata_refcounts[77], + .data.refcounted = {g_bytes + 791, 13}}, + {.refcount = &grpc_static_metadata_refcounts[20], + .data.refcounted = {g_bytes + 234, 0}}}, + {{.refcount = &grpc_static_metadata_refcounts[18], + .data.refcounted = {g_bytes + 214, 8}}, + {.refcount = &grpc_static_metadata_refcounts[20], + .data.refcounted = {g_bytes + 234, 0}}}, + {{.refcount = &grpc_static_metadata_refcounts[78], + .data.refcounted = {g_bytes + 804, 11}}, + {.refcount = &grpc_static_metadata_refcounts[20], + .data.refcounted = {g_bytes + 234, 0}}}, + {{.refcount = &grpc_static_metadata_refcounts[79], + .data.refcounted = {g_bytes + 815, 4}}, + {.refcount = &grpc_static_metadata_refcounts[20], + .data.refcounted = {g_bytes + 234, 0}}}, + {{.refcount = &grpc_static_metadata_refcounts[80], + .data.refcounted = {g_bytes + 819, 8}}, + {.refcount = &grpc_static_metadata_refcounts[20], + .data.refcounted = {g_bytes + 234, 0}}}, + {{.refcount = &grpc_static_metadata_refcounts[81], + .data.refcounted = {g_bytes + 827, 12}}, + {.refcount = &grpc_static_metadata_refcounts[20], + .data.refcounted = {g_bytes + 234, 0}}}, + {{.refcount = &grpc_static_metadata_refcounts[82], + .data.refcounted = {g_bytes + 839, 18}}, + {.refcount = &grpc_static_metadata_refcounts[20], + .data.refcounted = {g_bytes + 234, 0}}}, + {{.refcount = &grpc_static_metadata_refcounts[83], + .data.refcounted = {g_bytes + 857, 19}}, + {.refcount = &grpc_static_metadata_refcounts[20], + .data.refcounted = {g_bytes + 234, 0}}}, + {{.refcount = &grpc_static_metadata_refcounts[84], + .data.refcounted = {g_bytes + 876, 5}}, + {.refcount = &grpc_static_metadata_refcounts[20], + .data.refcounted = {g_bytes + 234, 0}}}, + {{.refcount = &grpc_static_metadata_refcounts[85], + .data.refcounted = {g_bytes + 881, 7}}, + {.refcount = &grpc_static_metadata_refcounts[20], + .data.refcounted = {g_bytes + 234, 0}}}, + {{.refcount = &grpc_static_metadata_refcounts[86], + .data.refcounted = {g_bytes + 888, 7}}, + {.refcount = &grpc_static_metadata_refcounts[20], + .data.refcounted = {g_bytes + 234, 0}}}, + {{.refcount = &grpc_static_metadata_refcounts[87], + .data.refcounted = {g_bytes + 895, 11}}, + {.refcount = &grpc_static_metadata_refcounts[20], + .data.refcounted = {g_bytes + 234, 0}}}, + {{.refcount = &grpc_static_metadata_refcounts[88], + .data.refcounted = {g_bytes + 906, 6}}, + {.refcount = &grpc_static_metadata_refcounts[20], + .data.refcounted = {g_bytes + 234, 0}}}, + {{.refcount = &grpc_static_metadata_refcounts[89], + .data.refcounted = {g_bytes + 912, 10}}, + {.refcount = &grpc_static_metadata_refcounts[20], + .data.refcounted = {g_bytes + 234, 0}}}, + {{.refcount = &grpc_static_metadata_refcounts[90], + .data.refcounted = {g_bytes + 922, 25}}, + {.refcount = &grpc_static_metadata_refcounts[20], + .data.refcounted = {g_bytes + 234, 0}}}, + {{.refcount = &grpc_static_metadata_refcounts[91], + .data.refcounted = {g_bytes + 947, 17}}, + {.refcount = &grpc_static_metadata_refcounts[20], + .data.refcounted = {g_bytes + 234, 0}}}, + {{.refcount = &grpc_static_metadata_refcounts[16], + .data.refcounted = {g_bytes + 200, 10}}, + {.refcount = &grpc_static_metadata_refcounts[20], + .data.refcounted = {g_bytes + 234, 0}}}, + {{.refcount = &grpc_static_metadata_refcounts[92], + .data.refcounted = {g_bytes + 964, 4}}, + {.refcount = &grpc_static_metadata_refcounts[20], + .data.refcounted = {g_bytes + 234, 0}}}, + {{.refcount = &grpc_static_metadata_refcounts[93], + .data.refcounted = {g_bytes + 968, 3}}, + {.refcount = &grpc_static_metadata_refcounts[20], + .data.refcounted = {g_bytes + 234, 0}}}, + {{.refcount = &grpc_static_metadata_refcounts[94], + .data.refcounted = {g_bytes + 971, 16}}, + {.refcount = &grpc_static_metadata_refcounts[20], + .data.refcounted = {g_bytes + 234, 0}}}, + {{.refcount = &grpc_static_metadata_refcounts[10], + .data.refcounted = {g_bytes + 90, 20}}, + {.refcount = &grpc_static_metadata_refcounts[29], + .data.refcounted = {g_bytes + 365, 8}}}, + {{.refcount = &grpc_static_metadata_refcounts[10], + .data.refcounted = {g_bytes + 90, 20}}, + {.refcount = &grpc_static_metadata_refcounts[31], + .data.refcounted = {g_bytes + 377, 7}}}, + {{.refcount = &grpc_static_metadata_refcounts[10], + .data.refcounted = {g_bytes + 90, 20}}, + {.refcount = &grpc_static_metadata_refcounts[95], + .data.refcounted = {g_bytes + 987, 16}}}, + {{.refcount = &grpc_static_metadata_refcounts[10], + .data.refcounted = {g_bytes + 90, 20}}, + {.refcount = &grpc_static_metadata_refcounts[30], + .data.refcounted = {g_bytes + 373, 4}}}, + {{.refcount = &grpc_static_metadata_refcounts[10], + .data.refcounted = {g_bytes + 90, 20}}, + {.refcount = &grpc_static_metadata_refcounts[96], + .data.refcounted = {g_bytes + 1003, 13}}}, + {{.refcount = &grpc_static_metadata_refcounts[10], + .data.refcounted = {g_bytes + 90, 20}}, + {.refcount = &grpc_static_metadata_refcounts[97], + .data.refcounted = {g_bytes + 1016, 12}}}, + {{.refcount = &grpc_static_metadata_refcounts[10], + .data.refcounted = {g_bytes + 90, 20}}, + {.refcount = &grpc_static_metadata_refcounts[98], + .data.refcounted = {g_bytes + 1028, 21}}}, +}; +const uint8_t grpc_static_accept_encoding_metadata[8] = {0, 74, 75, 76, + 77, 78, 79, 80}; diff --git a/Sources/CgRPC/src/core/lib/transport/static_metadata.h b/Sources/CgRPC/src/core/lib/transport/static_metadata.h index 28ad6f296..baa86de14 100644 --- a/Sources/CgRPC/src/core/lib/transport/static_metadata.h +++ b/Sources/CgRPC/src/core/lib/transport/static_metadata.h @@ -1,32 +1,17 @@ /* - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. */ /* @@ -44,375 +29,527 @@ #include "src/core/lib/transport/metadata.h" -#define GRPC_STATIC_MDSTR_COUNT 93 -extern grpc_mdstr grpc_static_mdstr_table[GRPC_STATIC_MDSTR_COUNT]; +#define GRPC_STATIC_MDSTR_COUNT 99 +extern const grpc_slice grpc_static_slice_table[GRPC_STATIC_MDSTR_COUNT]; +/* ":path" */ +#define GRPC_MDSTR_PATH (grpc_static_slice_table[0]) +/* ":method" */ +#define GRPC_MDSTR_METHOD (grpc_static_slice_table[1]) +/* ":status" */ +#define GRPC_MDSTR_STATUS (grpc_static_slice_table[2]) +/* ":authority" */ +#define GRPC_MDSTR_AUTHORITY (grpc_static_slice_table[3]) +/* ":scheme" */ +#define GRPC_MDSTR_SCHEME (grpc_static_slice_table[4]) +/* "te" */ +#define GRPC_MDSTR_TE (grpc_static_slice_table[5]) +/* "grpc-message" */ +#define GRPC_MDSTR_GRPC_MESSAGE (grpc_static_slice_table[6]) +/* "grpc-status" */ +#define GRPC_MDSTR_GRPC_STATUS (grpc_static_slice_table[7]) +/* "grpc-payload-bin" */ +#define GRPC_MDSTR_GRPC_PAYLOAD_BIN (grpc_static_slice_table[8]) +/* "grpc-encoding" */ +#define GRPC_MDSTR_GRPC_ENCODING (grpc_static_slice_table[9]) +/* "grpc-accept-encoding" */ +#define GRPC_MDSTR_GRPC_ACCEPT_ENCODING (grpc_static_slice_table[10]) +/* "grpc-server-stats-bin" */ +#define GRPC_MDSTR_GRPC_SERVER_STATS_BIN (grpc_static_slice_table[11]) +/* "grpc-tags-bin" */ +#define GRPC_MDSTR_GRPC_TAGS_BIN (grpc_static_slice_table[12]) +/* "grpc-trace-bin" */ +#define GRPC_MDSTR_GRPC_TRACE_BIN (grpc_static_slice_table[13]) +/* "content-type" */ +#define GRPC_MDSTR_CONTENT_TYPE (grpc_static_slice_table[14]) +/* "grpc-internal-encoding-request" */ +#define GRPC_MDSTR_GRPC_INTERNAL_ENCODING_REQUEST (grpc_static_slice_table[15]) +/* "user-agent" */ +#define GRPC_MDSTR_USER_AGENT (grpc_static_slice_table[16]) +/* "host" */ +#define GRPC_MDSTR_HOST (grpc_static_slice_table[17]) +/* "lb-token" */ +#define GRPC_MDSTR_LB_TOKEN (grpc_static_slice_table[18]) +/* "grpc-timeout" */ +#define GRPC_MDSTR_GRPC_TIMEOUT (grpc_static_slice_table[19]) +/* "" */ +#define GRPC_MDSTR_EMPTY (grpc_static_slice_table[20]) +/* "grpc.wait_for_ready" */ +#define GRPC_MDSTR_GRPC_DOT_WAIT_FOR_READY (grpc_static_slice_table[21]) +/* "grpc.timeout" */ +#define GRPC_MDSTR_GRPC_DOT_TIMEOUT (grpc_static_slice_table[22]) +/* "grpc.max_request_message_bytes" */ +#define GRPC_MDSTR_GRPC_DOT_MAX_REQUEST_MESSAGE_BYTES \ + (grpc_static_slice_table[23]) +/* "grpc.max_response_message_bytes" */ +#define GRPC_MDSTR_GRPC_DOT_MAX_RESPONSE_MESSAGE_BYTES \ + (grpc_static_slice_table[24]) +/* "/grpc.lb.v1.LoadBalancer/BalanceLoad" */ +#define GRPC_MDSTR_SLASH_GRPC_DOT_LB_DOT_V1_DOT_LOADBALANCER_SLASH_BALANCELOAD \ + (grpc_static_slice_table[25]) /* "0" */ -#define GRPC_MDSTR_0 (&grpc_static_mdstr_table[0]) +#define GRPC_MDSTR_0 (grpc_static_slice_table[26]) /* "1" */ -#define GRPC_MDSTR_1 (&grpc_static_mdstr_table[1]) +#define GRPC_MDSTR_1 (grpc_static_slice_table[27]) /* "2" */ -#define GRPC_MDSTR_2 (&grpc_static_mdstr_table[2]) +#define GRPC_MDSTR_2 (grpc_static_slice_table[28]) +/* "identity" */ +#define GRPC_MDSTR_IDENTITY (grpc_static_slice_table[29]) +/* "gzip" */ +#define GRPC_MDSTR_GZIP (grpc_static_slice_table[30]) +/* "deflate" */ +#define GRPC_MDSTR_DEFLATE (grpc_static_slice_table[31]) +/* "trailers" */ +#define GRPC_MDSTR_TRAILERS (grpc_static_slice_table[32]) +/* "application/grpc" */ +#define GRPC_MDSTR_APPLICATION_SLASH_GRPC (grpc_static_slice_table[33]) +/* "POST" */ +#define GRPC_MDSTR_POST (grpc_static_slice_table[34]) /* "200" */ -#define GRPC_MDSTR_200 (&grpc_static_mdstr_table[3]) +#define GRPC_MDSTR_200 (grpc_static_slice_table[35]) +/* "404" */ +#define GRPC_MDSTR_404 (grpc_static_slice_table[36]) +/* "http" */ +#define GRPC_MDSTR_HTTP (grpc_static_slice_table[37]) +/* "https" */ +#define GRPC_MDSTR_HTTPS (grpc_static_slice_table[38]) +/* "grpc" */ +#define GRPC_MDSTR_GRPC (grpc_static_slice_table[39]) +/* "GET" */ +#define GRPC_MDSTR_GET (grpc_static_slice_table[40]) +/* "PUT" */ +#define GRPC_MDSTR_PUT (grpc_static_slice_table[41]) +/* "/" */ +#define GRPC_MDSTR_SLASH (grpc_static_slice_table[42]) +/* "/index.html" */ +#define GRPC_MDSTR_SLASH_INDEX_DOT_HTML (grpc_static_slice_table[43]) /* "204" */ -#define GRPC_MDSTR_204 (&grpc_static_mdstr_table[4]) +#define GRPC_MDSTR_204 (grpc_static_slice_table[44]) /* "206" */ -#define GRPC_MDSTR_206 (&grpc_static_mdstr_table[5]) +#define GRPC_MDSTR_206 (grpc_static_slice_table[45]) /* "304" */ -#define GRPC_MDSTR_304 (&grpc_static_mdstr_table[6]) +#define GRPC_MDSTR_304 (grpc_static_slice_table[46]) /* "400" */ -#define GRPC_MDSTR_400 (&grpc_static_mdstr_table[7]) -/* "404" */ -#define GRPC_MDSTR_404 (&grpc_static_mdstr_table[8]) +#define GRPC_MDSTR_400 (grpc_static_slice_table[47]) /* "500" */ -#define GRPC_MDSTR_500 (&grpc_static_mdstr_table[9]) -/* "accept" */ -#define GRPC_MDSTR_ACCEPT (&grpc_static_mdstr_table[10]) +#define GRPC_MDSTR_500 (grpc_static_slice_table[48]) /* "accept-charset" */ -#define GRPC_MDSTR_ACCEPT_CHARSET (&grpc_static_mdstr_table[11]) +#define GRPC_MDSTR_ACCEPT_CHARSET (grpc_static_slice_table[49]) /* "accept-encoding" */ -#define GRPC_MDSTR_ACCEPT_ENCODING (&grpc_static_mdstr_table[12]) +#define GRPC_MDSTR_ACCEPT_ENCODING (grpc_static_slice_table[50]) +/* "gzip, deflate" */ +#define GRPC_MDSTR_GZIP_COMMA_DEFLATE (grpc_static_slice_table[51]) /* "accept-language" */ -#define GRPC_MDSTR_ACCEPT_LANGUAGE (&grpc_static_mdstr_table[13]) +#define GRPC_MDSTR_ACCEPT_LANGUAGE (grpc_static_slice_table[52]) /* "accept-ranges" */ -#define GRPC_MDSTR_ACCEPT_RANGES (&grpc_static_mdstr_table[14]) +#define GRPC_MDSTR_ACCEPT_RANGES (grpc_static_slice_table[53]) +/* "accept" */ +#define GRPC_MDSTR_ACCEPT (grpc_static_slice_table[54]) /* "access-control-allow-origin" */ -#define GRPC_MDSTR_ACCESS_CONTROL_ALLOW_ORIGIN (&grpc_static_mdstr_table[15]) +#define GRPC_MDSTR_ACCESS_CONTROL_ALLOW_ORIGIN (grpc_static_slice_table[55]) /* "age" */ -#define GRPC_MDSTR_AGE (&grpc_static_mdstr_table[16]) +#define GRPC_MDSTR_AGE (grpc_static_slice_table[56]) /* "allow" */ -#define GRPC_MDSTR_ALLOW (&grpc_static_mdstr_table[17]) -/* "application/grpc" */ -#define GRPC_MDSTR_APPLICATION_SLASH_GRPC (&grpc_static_mdstr_table[18]) -/* ":authority" */ -#define GRPC_MDSTR_AUTHORITY (&grpc_static_mdstr_table[19]) +#define GRPC_MDSTR_ALLOW (grpc_static_slice_table[57]) /* "authorization" */ -#define GRPC_MDSTR_AUTHORIZATION (&grpc_static_mdstr_table[20]) +#define GRPC_MDSTR_AUTHORIZATION (grpc_static_slice_table[58]) /* "cache-control" */ -#define GRPC_MDSTR_CACHE_CONTROL (&grpc_static_mdstr_table[21]) +#define GRPC_MDSTR_CACHE_CONTROL (grpc_static_slice_table[59]) /* "content-disposition" */ -#define GRPC_MDSTR_CONTENT_DISPOSITION (&grpc_static_mdstr_table[22]) +#define GRPC_MDSTR_CONTENT_DISPOSITION (grpc_static_slice_table[60]) /* "content-encoding" */ -#define GRPC_MDSTR_CONTENT_ENCODING (&grpc_static_mdstr_table[23]) +#define GRPC_MDSTR_CONTENT_ENCODING (grpc_static_slice_table[61]) /* "content-language" */ -#define GRPC_MDSTR_CONTENT_LANGUAGE (&grpc_static_mdstr_table[24]) +#define GRPC_MDSTR_CONTENT_LANGUAGE (grpc_static_slice_table[62]) /* "content-length" */ -#define GRPC_MDSTR_CONTENT_LENGTH (&grpc_static_mdstr_table[25]) +#define GRPC_MDSTR_CONTENT_LENGTH (grpc_static_slice_table[63]) /* "content-location" */ -#define GRPC_MDSTR_CONTENT_LOCATION (&grpc_static_mdstr_table[26]) +#define GRPC_MDSTR_CONTENT_LOCATION (grpc_static_slice_table[64]) /* "content-range" */ -#define GRPC_MDSTR_CONTENT_RANGE (&grpc_static_mdstr_table[27]) -/* "content-type" */ -#define GRPC_MDSTR_CONTENT_TYPE (&grpc_static_mdstr_table[28]) +#define GRPC_MDSTR_CONTENT_RANGE (grpc_static_slice_table[65]) /* "cookie" */ -#define GRPC_MDSTR_COOKIE (&grpc_static_mdstr_table[29]) +#define GRPC_MDSTR_COOKIE (grpc_static_slice_table[66]) /* "date" */ -#define GRPC_MDSTR_DATE (&grpc_static_mdstr_table[30]) -/* "deflate" */ -#define GRPC_MDSTR_DEFLATE (&grpc_static_mdstr_table[31]) -/* "deflate,gzip" */ -#define GRPC_MDSTR_DEFLATE_COMMA_GZIP (&grpc_static_mdstr_table[32]) -/* "" */ -#define GRPC_MDSTR_EMPTY (&grpc_static_mdstr_table[33]) +#define GRPC_MDSTR_DATE (grpc_static_slice_table[67]) /* "etag" */ -#define GRPC_MDSTR_ETAG (&grpc_static_mdstr_table[34]) +#define GRPC_MDSTR_ETAG (grpc_static_slice_table[68]) /* "expect" */ -#define GRPC_MDSTR_EXPECT (&grpc_static_mdstr_table[35]) +#define GRPC_MDSTR_EXPECT (grpc_static_slice_table[69]) /* "expires" */ -#define GRPC_MDSTR_EXPIRES (&grpc_static_mdstr_table[36]) +#define GRPC_MDSTR_EXPIRES (grpc_static_slice_table[70]) /* "from" */ -#define GRPC_MDSTR_FROM (&grpc_static_mdstr_table[37]) -/* "GET" */ -#define GRPC_MDSTR_GET (&grpc_static_mdstr_table[38]) -/* "grpc" */ -#define GRPC_MDSTR_GRPC (&grpc_static_mdstr_table[39]) -/* "grpc-accept-encoding" */ -#define GRPC_MDSTR_GRPC_ACCEPT_ENCODING (&grpc_static_mdstr_table[40]) -/* "grpc-encoding" */ -#define GRPC_MDSTR_GRPC_ENCODING (&grpc_static_mdstr_table[41]) -/* "grpc-internal-encoding-request" */ -#define GRPC_MDSTR_GRPC_INTERNAL_ENCODING_REQUEST (&grpc_static_mdstr_table[42]) -/* "grpc-message" */ -#define GRPC_MDSTR_GRPC_MESSAGE (&grpc_static_mdstr_table[43]) -/* "grpc-payload-bin" */ -#define GRPC_MDSTR_GRPC_PAYLOAD_BIN (&grpc_static_mdstr_table[44]) -/* "grpc-stats-bin" */ -#define GRPC_MDSTR_GRPC_STATS_BIN (&grpc_static_mdstr_table[45]) -/* "grpc-status" */ -#define GRPC_MDSTR_GRPC_STATUS (&grpc_static_mdstr_table[46]) -/* "grpc-timeout" */ -#define GRPC_MDSTR_GRPC_TIMEOUT (&grpc_static_mdstr_table[47]) -/* "grpc-tracing-bin" */ -#define GRPC_MDSTR_GRPC_TRACING_BIN (&grpc_static_mdstr_table[48]) -/* "gzip" */ -#define GRPC_MDSTR_GZIP (&grpc_static_mdstr_table[49]) -/* "gzip, deflate" */ -#define GRPC_MDSTR_GZIP_COMMA_DEFLATE (&grpc_static_mdstr_table[50]) -/* "host" */ -#define GRPC_MDSTR_HOST (&grpc_static_mdstr_table[51]) -/* "http" */ -#define GRPC_MDSTR_HTTP (&grpc_static_mdstr_table[52]) -/* "https" */ -#define GRPC_MDSTR_HTTPS (&grpc_static_mdstr_table[53]) -/* "identity" */ -#define GRPC_MDSTR_IDENTITY (&grpc_static_mdstr_table[54]) -/* "identity,deflate" */ -#define GRPC_MDSTR_IDENTITY_COMMA_DEFLATE (&grpc_static_mdstr_table[55]) -/* "identity,deflate,gzip" */ -#define GRPC_MDSTR_IDENTITY_COMMA_DEFLATE_COMMA_GZIP \ - (&grpc_static_mdstr_table[56]) -/* "identity,gzip" */ -#define GRPC_MDSTR_IDENTITY_COMMA_GZIP (&grpc_static_mdstr_table[57]) +#define GRPC_MDSTR_FROM (grpc_static_slice_table[71]) /* "if-match" */ -#define GRPC_MDSTR_IF_MATCH (&grpc_static_mdstr_table[58]) +#define GRPC_MDSTR_IF_MATCH (grpc_static_slice_table[72]) /* "if-modified-since" */ -#define GRPC_MDSTR_IF_MODIFIED_SINCE (&grpc_static_mdstr_table[59]) +#define GRPC_MDSTR_IF_MODIFIED_SINCE (grpc_static_slice_table[73]) /* "if-none-match" */ -#define GRPC_MDSTR_IF_NONE_MATCH (&grpc_static_mdstr_table[60]) +#define GRPC_MDSTR_IF_NONE_MATCH (grpc_static_slice_table[74]) /* "if-range" */ -#define GRPC_MDSTR_IF_RANGE (&grpc_static_mdstr_table[61]) +#define GRPC_MDSTR_IF_RANGE (grpc_static_slice_table[75]) /* "if-unmodified-since" */ -#define GRPC_MDSTR_IF_UNMODIFIED_SINCE (&grpc_static_mdstr_table[62]) +#define GRPC_MDSTR_IF_UNMODIFIED_SINCE (grpc_static_slice_table[76]) /* "last-modified" */ -#define GRPC_MDSTR_LAST_MODIFIED (&grpc_static_mdstr_table[63]) +#define GRPC_MDSTR_LAST_MODIFIED (grpc_static_slice_table[77]) /* "lb-cost-bin" */ -#define GRPC_MDSTR_LB_COST_BIN (&grpc_static_mdstr_table[64]) -/* "lb-token" */ -#define GRPC_MDSTR_LB_TOKEN (&grpc_static_mdstr_table[65]) +#define GRPC_MDSTR_LB_COST_BIN (grpc_static_slice_table[78]) /* "link" */ -#define GRPC_MDSTR_LINK (&grpc_static_mdstr_table[66]) +#define GRPC_MDSTR_LINK (grpc_static_slice_table[79]) /* "location" */ -#define GRPC_MDSTR_LOCATION (&grpc_static_mdstr_table[67]) +#define GRPC_MDSTR_LOCATION (grpc_static_slice_table[80]) /* "max-forwards" */ -#define GRPC_MDSTR_MAX_FORWARDS (&grpc_static_mdstr_table[68]) -/* ":method" */ -#define GRPC_MDSTR_METHOD (&grpc_static_mdstr_table[69]) -/* ":path" */ -#define GRPC_MDSTR_PATH (&grpc_static_mdstr_table[70]) -/* "POST" */ -#define GRPC_MDSTR_POST (&grpc_static_mdstr_table[71]) +#define GRPC_MDSTR_MAX_FORWARDS (grpc_static_slice_table[81]) /* "proxy-authenticate" */ -#define GRPC_MDSTR_PROXY_AUTHENTICATE (&grpc_static_mdstr_table[72]) +#define GRPC_MDSTR_PROXY_AUTHENTICATE (grpc_static_slice_table[82]) /* "proxy-authorization" */ -#define GRPC_MDSTR_PROXY_AUTHORIZATION (&grpc_static_mdstr_table[73]) -/* "PUT" */ -#define GRPC_MDSTR_PUT (&grpc_static_mdstr_table[74]) +#define GRPC_MDSTR_PROXY_AUTHORIZATION (grpc_static_slice_table[83]) /* "range" */ -#define GRPC_MDSTR_RANGE (&grpc_static_mdstr_table[75]) +#define GRPC_MDSTR_RANGE (grpc_static_slice_table[84]) /* "referer" */ -#define GRPC_MDSTR_REFERER (&grpc_static_mdstr_table[76]) +#define GRPC_MDSTR_REFERER (grpc_static_slice_table[85]) /* "refresh" */ -#define GRPC_MDSTR_REFRESH (&grpc_static_mdstr_table[77]) +#define GRPC_MDSTR_REFRESH (grpc_static_slice_table[86]) /* "retry-after" */ -#define GRPC_MDSTR_RETRY_AFTER (&grpc_static_mdstr_table[78]) -/* ":scheme" */ -#define GRPC_MDSTR_SCHEME (&grpc_static_mdstr_table[79]) +#define GRPC_MDSTR_RETRY_AFTER (grpc_static_slice_table[87]) /* "server" */ -#define GRPC_MDSTR_SERVER (&grpc_static_mdstr_table[80]) +#define GRPC_MDSTR_SERVER (grpc_static_slice_table[88]) /* "set-cookie" */ -#define GRPC_MDSTR_SET_COOKIE (&grpc_static_mdstr_table[81]) -/* "/" */ -#define GRPC_MDSTR_SLASH (&grpc_static_mdstr_table[82]) -/* "/index.html" */ -#define GRPC_MDSTR_SLASH_INDEX_DOT_HTML (&grpc_static_mdstr_table[83]) -/* ":status" */ -#define GRPC_MDSTR_STATUS (&grpc_static_mdstr_table[84]) +#define GRPC_MDSTR_SET_COOKIE (grpc_static_slice_table[89]) /* "strict-transport-security" */ -#define GRPC_MDSTR_STRICT_TRANSPORT_SECURITY (&grpc_static_mdstr_table[85]) -/* "te" */ -#define GRPC_MDSTR_TE (&grpc_static_mdstr_table[86]) -/* "trailers" */ -#define GRPC_MDSTR_TRAILERS (&grpc_static_mdstr_table[87]) +#define GRPC_MDSTR_STRICT_TRANSPORT_SECURITY (grpc_static_slice_table[90]) /* "transfer-encoding" */ -#define GRPC_MDSTR_TRANSFER_ENCODING (&grpc_static_mdstr_table[88]) -/* "user-agent" */ -#define GRPC_MDSTR_USER_AGENT (&grpc_static_mdstr_table[89]) +#define GRPC_MDSTR_TRANSFER_ENCODING (grpc_static_slice_table[91]) /* "vary" */ -#define GRPC_MDSTR_VARY (&grpc_static_mdstr_table[90]) +#define GRPC_MDSTR_VARY (grpc_static_slice_table[92]) /* "via" */ -#define GRPC_MDSTR_VIA (&grpc_static_mdstr_table[91]) +#define GRPC_MDSTR_VIA (grpc_static_slice_table[93]) /* "www-authenticate" */ -#define GRPC_MDSTR_WWW_AUTHENTICATE (&grpc_static_mdstr_table[92]) +#define GRPC_MDSTR_WWW_AUTHENTICATE (grpc_static_slice_table[94]) +/* "identity,deflate" */ +#define GRPC_MDSTR_IDENTITY_COMMA_DEFLATE (grpc_static_slice_table[95]) +/* "identity,gzip" */ +#define GRPC_MDSTR_IDENTITY_COMMA_GZIP (grpc_static_slice_table[96]) +/* "deflate,gzip" */ +#define GRPC_MDSTR_DEFLATE_COMMA_GZIP (grpc_static_slice_table[97]) +/* "identity,deflate,gzip" */ +#define GRPC_MDSTR_IDENTITY_COMMA_DEFLATE_COMMA_GZIP \ + (grpc_static_slice_table[98]) + +extern const grpc_slice_refcount_vtable grpc_static_metadata_vtable; +extern grpc_slice_refcount + grpc_static_metadata_refcounts[GRPC_STATIC_MDSTR_COUNT]; +#define GRPC_IS_STATIC_METADATA_STRING(slice) \ + ((slice).refcount != NULL && \ + (slice).refcount->vtable == &grpc_static_metadata_vtable) + +#define GRPC_STATIC_METADATA_INDEX(static_slice) \ + ((int)((static_slice).refcount - grpc_static_metadata_refcounts)) #define GRPC_STATIC_MDELEM_COUNT 81 -extern grpc_mdelem grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT]; +extern grpc_mdelem_data grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT]; extern uintptr_t grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT]; +/* "grpc-status": "0" */ +#define GRPC_MDELEM_GRPC_STATUS_0 \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[0], GRPC_MDELEM_STORAGE_STATIC)) +/* "grpc-status": "1" */ +#define GRPC_MDELEM_GRPC_STATUS_1 \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[1], GRPC_MDELEM_STORAGE_STATIC)) +/* "grpc-status": "2" */ +#define GRPC_MDELEM_GRPC_STATUS_2 \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[2], GRPC_MDELEM_STORAGE_STATIC)) +/* "grpc-encoding": "identity" */ +#define GRPC_MDELEM_GRPC_ENCODING_IDENTITY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[3], GRPC_MDELEM_STORAGE_STATIC)) +/* "grpc-encoding": "gzip" */ +#define GRPC_MDELEM_GRPC_ENCODING_GZIP \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[4], GRPC_MDELEM_STORAGE_STATIC)) +/* "grpc-encoding": "deflate" */ +#define GRPC_MDELEM_GRPC_ENCODING_DEFLATE \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[5], GRPC_MDELEM_STORAGE_STATIC)) +/* "te": "trailers" */ +#define GRPC_MDELEM_TE_TRAILERS \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[6], GRPC_MDELEM_STORAGE_STATIC)) +/* "content-type": "application/grpc" */ +#define GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[7], GRPC_MDELEM_STORAGE_STATIC)) +/* ":method": "POST" */ +#define GRPC_MDELEM_METHOD_POST \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[8], GRPC_MDELEM_STORAGE_STATIC)) +/* ":status": "200" */ +#define GRPC_MDELEM_STATUS_200 \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[9], GRPC_MDELEM_STORAGE_STATIC)) +/* ":status": "404" */ +#define GRPC_MDELEM_STATUS_404 \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[10], GRPC_MDELEM_STORAGE_STATIC)) +/* ":scheme": "http" */ +#define GRPC_MDELEM_SCHEME_HTTP \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[11], GRPC_MDELEM_STORAGE_STATIC)) +/* ":scheme": "https" */ +#define GRPC_MDELEM_SCHEME_HTTPS \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[12], GRPC_MDELEM_STORAGE_STATIC)) +/* ":scheme": "grpc" */ +#define GRPC_MDELEM_SCHEME_GRPC \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[13], GRPC_MDELEM_STORAGE_STATIC)) +/* ":authority": "" */ +#define GRPC_MDELEM_AUTHORITY_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[14], GRPC_MDELEM_STORAGE_STATIC)) +/* ":method": "GET" */ +#define GRPC_MDELEM_METHOD_GET \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[15], GRPC_MDELEM_STORAGE_STATIC)) +/* ":method": "PUT" */ +#define GRPC_MDELEM_METHOD_PUT \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[16], GRPC_MDELEM_STORAGE_STATIC)) +/* ":path": "/" */ +#define GRPC_MDELEM_PATH_SLASH \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[17], GRPC_MDELEM_STORAGE_STATIC)) +/* ":path": "/index.html" */ +#define GRPC_MDELEM_PATH_SLASH_INDEX_DOT_HTML \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[18], GRPC_MDELEM_STORAGE_STATIC)) +/* ":status": "204" */ +#define GRPC_MDELEM_STATUS_204 \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[19], GRPC_MDELEM_STORAGE_STATIC)) +/* ":status": "206" */ +#define GRPC_MDELEM_STATUS_206 \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[20], GRPC_MDELEM_STORAGE_STATIC)) +/* ":status": "304" */ +#define GRPC_MDELEM_STATUS_304 \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[21], GRPC_MDELEM_STORAGE_STATIC)) +/* ":status": "400" */ +#define GRPC_MDELEM_STATUS_400 \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[22], GRPC_MDELEM_STORAGE_STATIC)) +/* ":status": "500" */ +#define GRPC_MDELEM_STATUS_500 \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[23], GRPC_MDELEM_STORAGE_STATIC)) /* "accept-charset": "" */ -#define GRPC_MDELEM_ACCEPT_CHARSET_EMPTY (&grpc_static_mdelem_table[0]) -/* "accept": "" */ -#define GRPC_MDELEM_ACCEPT_EMPTY (&grpc_static_mdelem_table[1]) +#define GRPC_MDELEM_ACCEPT_CHARSET_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[24], GRPC_MDELEM_STORAGE_STATIC)) /* "accept-encoding": "" */ -#define GRPC_MDELEM_ACCEPT_ENCODING_EMPTY (&grpc_static_mdelem_table[2]) +#define GRPC_MDELEM_ACCEPT_ENCODING_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[25], GRPC_MDELEM_STORAGE_STATIC)) /* "accept-encoding": "gzip, deflate" */ #define GRPC_MDELEM_ACCEPT_ENCODING_GZIP_COMMA_DEFLATE \ - (&grpc_static_mdelem_table[3]) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[26], GRPC_MDELEM_STORAGE_STATIC)) /* "accept-language": "" */ -#define GRPC_MDELEM_ACCEPT_LANGUAGE_EMPTY (&grpc_static_mdelem_table[4]) +#define GRPC_MDELEM_ACCEPT_LANGUAGE_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[27], GRPC_MDELEM_STORAGE_STATIC)) /* "accept-ranges": "" */ -#define GRPC_MDELEM_ACCEPT_RANGES_EMPTY (&grpc_static_mdelem_table[5]) +#define GRPC_MDELEM_ACCEPT_RANGES_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[28], GRPC_MDELEM_STORAGE_STATIC)) +/* "accept": "" */ +#define GRPC_MDELEM_ACCEPT_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[29], GRPC_MDELEM_STORAGE_STATIC)) /* "access-control-allow-origin": "" */ #define GRPC_MDELEM_ACCESS_CONTROL_ALLOW_ORIGIN_EMPTY \ - (&grpc_static_mdelem_table[6]) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[30], GRPC_MDELEM_STORAGE_STATIC)) /* "age": "" */ -#define GRPC_MDELEM_AGE_EMPTY (&grpc_static_mdelem_table[7]) +#define GRPC_MDELEM_AGE_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[31], GRPC_MDELEM_STORAGE_STATIC)) /* "allow": "" */ -#define GRPC_MDELEM_ALLOW_EMPTY (&grpc_static_mdelem_table[8]) -/* ":authority": "" */ -#define GRPC_MDELEM_AUTHORITY_EMPTY (&grpc_static_mdelem_table[9]) +#define GRPC_MDELEM_ALLOW_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[32], GRPC_MDELEM_STORAGE_STATIC)) /* "authorization": "" */ -#define GRPC_MDELEM_AUTHORIZATION_EMPTY (&grpc_static_mdelem_table[10]) +#define GRPC_MDELEM_AUTHORIZATION_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[33], GRPC_MDELEM_STORAGE_STATIC)) /* "cache-control": "" */ -#define GRPC_MDELEM_CACHE_CONTROL_EMPTY (&grpc_static_mdelem_table[11]) +#define GRPC_MDELEM_CACHE_CONTROL_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[34], GRPC_MDELEM_STORAGE_STATIC)) /* "content-disposition": "" */ -#define GRPC_MDELEM_CONTENT_DISPOSITION_EMPTY (&grpc_static_mdelem_table[12]) +#define GRPC_MDELEM_CONTENT_DISPOSITION_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[35], GRPC_MDELEM_STORAGE_STATIC)) /* "content-encoding": "" */ -#define GRPC_MDELEM_CONTENT_ENCODING_EMPTY (&grpc_static_mdelem_table[13]) +#define GRPC_MDELEM_CONTENT_ENCODING_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[36], GRPC_MDELEM_STORAGE_STATIC)) /* "content-language": "" */ -#define GRPC_MDELEM_CONTENT_LANGUAGE_EMPTY (&grpc_static_mdelem_table[14]) +#define GRPC_MDELEM_CONTENT_LANGUAGE_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[37], GRPC_MDELEM_STORAGE_STATIC)) /* "content-length": "" */ -#define GRPC_MDELEM_CONTENT_LENGTH_EMPTY (&grpc_static_mdelem_table[15]) +#define GRPC_MDELEM_CONTENT_LENGTH_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[38], GRPC_MDELEM_STORAGE_STATIC)) /* "content-location": "" */ -#define GRPC_MDELEM_CONTENT_LOCATION_EMPTY (&grpc_static_mdelem_table[16]) +#define GRPC_MDELEM_CONTENT_LOCATION_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[39], GRPC_MDELEM_STORAGE_STATIC)) /* "content-range": "" */ -#define GRPC_MDELEM_CONTENT_RANGE_EMPTY (&grpc_static_mdelem_table[17]) -/* "content-type": "application/grpc" */ -#define GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC \ - (&grpc_static_mdelem_table[18]) +#define GRPC_MDELEM_CONTENT_RANGE_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[40], GRPC_MDELEM_STORAGE_STATIC)) /* "content-type": "" */ -#define GRPC_MDELEM_CONTENT_TYPE_EMPTY (&grpc_static_mdelem_table[19]) +#define GRPC_MDELEM_CONTENT_TYPE_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[41], GRPC_MDELEM_STORAGE_STATIC)) /* "cookie": "" */ -#define GRPC_MDELEM_COOKIE_EMPTY (&grpc_static_mdelem_table[20]) +#define GRPC_MDELEM_COOKIE_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[42], GRPC_MDELEM_STORAGE_STATIC)) /* "date": "" */ -#define GRPC_MDELEM_DATE_EMPTY (&grpc_static_mdelem_table[21]) +#define GRPC_MDELEM_DATE_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[43], GRPC_MDELEM_STORAGE_STATIC)) /* "etag": "" */ -#define GRPC_MDELEM_ETAG_EMPTY (&grpc_static_mdelem_table[22]) +#define GRPC_MDELEM_ETAG_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[44], GRPC_MDELEM_STORAGE_STATIC)) /* "expect": "" */ -#define GRPC_MDELEM_EXPECT_EMPTY (&grpc_static_mdelem_table[23]) +#define GRPC_MDELEM_EXPECT_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[45], GRPC_MDELEM_STORAGE_STATIC)) /* "expires": "" */ -#define GRPC_MDELEM_EXPIRES_EMPTY (&grpc_static_mdelem_table[24]) +#define GRPC_MDELEM_EXPIRES_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[46], GRPC_MDELEM_STORAGE_STATIC)) /* "from": "" */ -#define GRPC_MDELEM_FROM_EMPTY (&grpc_static_mdelem_table[25]) -/* "grpc-accept-encoding": "deflate" */ -#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_DEFLATE (&grpc_static_mdelem_table[26]) -/* "grpc-accept-encoding": "deflate,gzip" */ -#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_DEFLATE_COMMA_GZIP \ - (&grpc_static_mdelem_table[27]) -/* "grpc-accept-encoding": "gzip" */ -#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_GZIP (&grpc_static_mdelem_table[28]) -/* "grpc-accept-encoding": "identity" */ -#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY \ - (&grpc_static_mdelem_table[29]) -/* "grpc-accept-encoding": "identity,deflate" */ -#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY_COMMA_DEFLATE \ - (&grpc_static_mdelem_table[30]) -/* "grpc-accept-encoding": "identity,deflate,gzip" */ -#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY_COMMA_DEFLATE_COMMA_GZIP \ - (&grpc_static_mdelem_table[31]) -/* "grpc-accept-encoding": "identity,gzip" */ -#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY_COMMA_GZIP \ - (&grpc_static_mdelem_table[32]) -/* "grpc-encoding": "deflate" */ -#define GRPC_MDELEM_GRPC_ENCODING_DEFLATE (&grpc_static_mdelem_table[33]) -/* "grpc-encoding": "gzip" */ -#define GRPC_MDELEM_GRPC_ENCODING_GZIP (&grpc_static_mdelem_table[34]) -/* "grpc-encoding": "identity" */ -#define GRPC_MDELEM_GRPC_ENCODING_IDENTITY (&grpc_static_mdelem_table[35]) -/* "grpc-status": "0" */ -#define GRPC_MDELEM_GRPC_STATUS_0 (&grpc_static_mdelem_table[36]) -/* "grpc-status": "1" */ -#define GRPC_MDELEM_GRPC_STATUS_1 (&grpc_static_mdelem_table[37]) -/* "grpc-status": "2" */ -#define GRPC_MDELEM_GRPC_STATUS_2 (&grpc_static_mdelem_table[38]) +#define GRPC_MDELEM_FROM_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[47], GRPC_MDELEM_STORAGE_STATIC)) /* "host": "" */ -#define GRPC_MDELEM_HOST_EMPTY (&grpc_static_mdelem_table[39]) +#define GRPC_MDELEM_HOST_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[48], GRPC_MDELEM_STORAGE_STATIC)) /* "if-match": "" */ -#define GRPC_MDELEM_IF_MATCH_EMPTY (&grpc_static_mdelem_table[40]) +#define GRPC_MDELEM_IF_MATCH_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[49], GRPC_MDELEM_STORAGE_STATIC)) /* "if-modified-since": "" */ -#define GRPC_MDELEM_IF_MODIFIED_SINCE_EMPTY (&grpc_static_mdelem_table[41]) +#define GRPC_MDELEM_IF_MODIFIED_SINCE_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[50], GRPC_MDELEM_STORAGE_STATIC)) /* "if-none-match": "" */ -#define GRPC_MDELEM_IF_NONE_MATCH_EMPTY (&grpc_static_mdelem_table[42]) +#define GRPC_MDELEM_IF_NONE_MATCH_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[51], GRPC_MDELEM_STORAGE_STATIC)) /* "if-range": "" */ -#define GRPC_MDELEM_IF_RANGE_EMPTY (&grpc_static_mdelem_table[43]) +#define GRPC_MDELEM_IF_RANGE_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[52], GRPC_MDELEM_STORAGE_STATIC)) /* "if-unmodified-since": "" */ -#define GRPC_MDELEM_IF_UNMODIFIED_SINCE_EMPTY (&grpc_static_mdelem_table[44]) +#define GRPC_MDELEM_IF_UNMODIFIED_SINCE_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[53], GRPC_MDELEM_STORAGE_STATIC)) /* "last-modified": "" */ -#define GRPC_MDELEM_LAST_MODIFIED_EMPTY (&grpc_static_mdelem_table[45]) -/* "lb-cost-bin": "" */ -#define GRPC_MDELEM_LB_COST_BIN_EMPTY (&grpc_static_mdelem_table[46]) +#define GRPC_MDELEM_LAST_MODIFIED_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[54], GRPC_MDELEM_STORAGE_STATIC)) /* "lb-token": "" */ -#define GRPC_MDELEM_LB_TOKEN_EMPTY (&grpc_static_mdelem_table[47]) +#define GRPC_MDELEM_LB_TOKEN_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[55], GRPC_MDELEM_STORAGE_STATIC)) +/* "lb-cost-bin": "" */ +#define GRPC_MDELEM_LB_COST_BIN_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[56], GRPC_MDELEM_STORAGE_STATIC)) /* "link": "" */ -#define GRPC_MDELEM_LINK_EMPTY (&grpc_static_mdelem_table[48]) +#define GRPC_MDELEM_LINK_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[57], GRPC_MDELEM_STORAGE_STATIC)) /* "location": "" */ -#define GRPC_MDELEM_LOCATION_EMPTY (&grpc_static_mdelem_table[49]) +#define GRPC_MDELEM_LOCATION_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[58], GRPC_MDELEM_STORAGE_STATIC)) /* "max-forwards": "" */ -#define GRPC_MDELEM_MAX_FORWARDS_EMPTY (&grpc_static_mdelem_table[50]) -/* ":method": "GET" */ -#define GRPC_MDELEM_METHOD_GET (&grpc_static_mdelem_table[51]) -/* ":method": "POST" */ -#define GRPC_MDELEM_METHOD_POST (&grpc_static_mdelem_table[52]) -/* ":method": "PUT" */ -#define GRPC_MDELEM_METHOD_PUT (&grpc_static_mdelem_table[53]) -/* ":path": "/" */ -#define GRPC_MDELEM_PATH_SLASH (&grpc_static_mdelem_table[54]) -/* ":path": "/index.html" */ -#define GRPC_MDELEM_PATH_SLASH_INDEX_DOT_HTML (&grpc_static_mdelem_table[55]) +#define GRPC_MDELEM_MAX_FORWARDS_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[59], GRPC_MDELEM_STORAGE_STATIC)) /* "proxy-authenticate": "" */ -#define GRPC_MDELEM_PROXY_AUTHENTICATE_EMPTY (&grpc_static_mdelem_table[56]) +#define GRPC_MDELEM_PROXY_AUTHENTICATE_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[60], GRPC_MDELEM_STORAGE_STATIC)) /* "proxy-authorization": "" */ -#define GRPC_MDELEM_PROXY_AUTHORIZATION_EMPTY (&grpc_static_mdelem_table[57]) +#define GRPC_MDELEM_PROXY_AUTHORIZATION_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[61], GRPC_MDELEM_STORAGE_STATIC)) /* "range": "" */ -#define GRPC_MDELEM_RANGE_EMPTY (&grpc_static_mdelem_table[58]) +#define GRPC_MDELEM_RANGE_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[62], GRPC_MDELEM_STORAGE_STATIC)) /* "referer": "" */ -#define GRPC_MDELEM_REFERER_EMPTY (&grpc_static_mdelem_table[59]) +#define GRPC_MDELEM_REFERER_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[63], GRPC_MDELEM_STORAGE_STATIC)) /* "refresh": "" */ -#define GRPC_MDELEM_REFRESH_EMPTY (&grpc_static_mdelem_table[60]) +#define GRPC_MDELEM_REFRESH_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[64], GRPC_MDELEM_STORAGE_STATIC)) /* "retry-after": "" */ -#define GRPC_MDELEM_RETRY_AFTER_EMPTY (&grpc_static_mdelem_table[61]) -/* ":scheme": "grpc" */ -#define GRPC_MDELEM_SCHEME_GRPC (&grpc_static_mdelem_table[62]) -/* ":scheme": "http" */ -#define GRPC_MDELEM_SCHEME_HTTP (&grpc_static_mdelem_table[63]) -/* ":scheme": "https" */ -#define GRPC_MDELEM_SCHEME_HTTPS (&grpc_static_mdelem_table[64]) +#define GRPC_MDELEM_RETRY_AFTER_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[65], GRPC_MDELEM_STORAGE_STATIC)) /* "server": "" */ -#define GRPC_MDELEM_SERVER_EMPTY (&grpc_static_mdelem_table[65]) +#define GRPC_MDELEM_SERVER_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[66], GRPC_MDELEM_STORAGE_STATIC)) /* "set-cookie": "" */ -#define GRPC_MDELEM_SET_COOKIE_EMPTY (&grpc_static_mdelem_table[66]) -/* ":status": "200" */ -#define GRPC_MDELEM_STATUS_200 (&grpc_static_mdelem_table[67]) -/* ":status": "204" */ -#define GRPC_MDELEM_STATUS_204 (&grpc_static_mdelem_table[68]) -/* ":status": "206" */ -#define GRPC_MDELEM_STATUS_206 (&grpc_static_mdelem_table[69]) -/* ":status": "304" */ -#define GRPC_MDELEM_STATUS_304 (&grpc_static_mdelem_table[70]) -/* ":status": "400" */ -#define GRPC_MDELEM_STATUS_400 (&grpc_static_mdelem_table[71]) -/* ":status": "404" */ -#define GRPC_MDELEM_STATUS_404 (&grpc_static_mdelem_table[72]) -/* ":status": "500" */ -#define GRPC_MDELEM_STATUS_500 (&grpc_static_mdelem_table[73]) +#define GRPC_MDELEM_SET_COOKIE_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[67], GRPC_MDELEM_STORAGE_STATIC)) /* "strict-transport-security": "" */ #define GRPC_MDELEM_STRICT_TRANSPORT_SECURITY_EMPTY \ - (&grpc_static_mdelem_table[74]) -/* "te": "trailers" */ -#define GRPC_MDELEM_TE_TRAILERS (&grpc_static_mdelem_table[75]) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[68], GRPC_MDELEM_STORAGE_STATIC)) /* "transfer-encoding": "" */ -#define GRPC_MDELEM_TRANSFER_ENCODING_EMPTY (&grpc_static_mdelem_table[76]) +#define GRPC_MDELEM_TRANSFER_ENCODING_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[69], GRPC_MDELEM_STORAGE_STATIC)) /* "user-agent": "" */ -#define GRPC_MDELEM_USER_AGENT_EMPTY (&grpc_static_mdelem_table[77]) +#define GRPC_MDELEM_USER_AGENT_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[70], GRPC_MDELEM_STORAGE_STATIC)) /* "vary": "" */ -#define GRPC_MDELEM_VARY_EMPTY (&grpc_static_mdelem_table[78]) +#define GRPC_MDELEM_VARY_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[71], GRPC_MDELEM_STORAGE_STATIC)) /* "via": "" */ -#define GRPC_MDELEM_VIA_EMPTY (&grpc_static_mdelem_table[79]) +#define GRPC_MDELEM_VIA_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[72], GRPC_MDELEM_STORAGE_STATIC)) /* "www-authenticate": "" */ -#define GRPC_MDELEM_WWW_AUTHENTICATE_EMPTY (&grpc_static_mdelem_table[80]) +#define GRPC_MDELEM_WWW_AUTHENTICATE_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[73], GRPC_MDELEM_STORAGE_STATIC)) +/* "grpc-accept-encoding": "identity" */ +#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[74], GRPC_MDELEM_STORAGE_STATIC)) +/* "grpc-accept-encoding": "deflate" */ +#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_DEFLATE \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[75], GRPC_MDELEM_STORAGE_STATIC)) +/* "grpc-accept-encoding": "identity,deflate" */ +#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY_COMMA_DEFLATE \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[76], GRPC_MDELEM_STORAGE_STATIC)) +/* "grpc-accept-encoding": "gzip" */ +#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_GZIP \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[77], GRPC_MDELEM_STORAGE_STATIC)) +/* "grpc-accept-encoding": "identity,gzip" */ +#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY_COMMA_GZIP \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[78], GRPC_MDELEM_STORAGE_STATIC)) +/* "grpc-accept-encoding": "deflate,gzip" */ +#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_DEFLATE_COMMA_GZIP \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[79], GRPC_MDELEM_STORAGE_STATIC)) +/* "grpc-accept-encoding": "identity,deflate,gzip" */ +#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY_COMMA_DEFLATE_COMMA_GZIP \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[80], GRPC_MDELEM_STORAGE_STATIC)) + +grpc_mdelem grpc_static_mdelem_for_static_strings(int a, int b); +typedef enum { + GRPC_BATCH_PATH, + GRPC_BATCH_METHOD, + GRPC_BATCH_STATUS, + GRPC_BATCH_AUTHORITY, + GRPC_BATCH_SCHEME, + GRPC_BATCH_TE, + GRPC_BATCH_GRPC_MESSAGE, + GRPC_BATCH_GRPC_STATUS, + GRPC_BATCH_GRPC_PAYLOAD_BIN, + GRPC_BATCH_GRPC_ENCODING, + GRPC_BATCH_GRPC_ACCEPT_ENCODING, + GRPC_BATCH_GRPC_SERVER_STATS_BIN, + GRPC_BATCH_GRPC_TAGS_BIN, + GRPC_BATCH_GRPC_TRACE_BIN, + GRPC_BATCH_CONTENT_TYPE, + GRPC_BATCH_GRPC_INTERNAL_ENCODING_REQUEST, + GRPC_BATCH_USER_AGENT, + GRPC_BATCH_HOST, + GRPC_BATCH_LB_TOKEN, + GRPC_BATCH_CALLOUTS_COUNT +} grpc_metadata_batch_callouts_index; + +typedef union { + struct grpc_linked_mdelem *array[GRPC_BATCH_CALLOUTS_COUNT]; + struct { + struct grpc_linked_mdelem *path; + struct grpc_linked_mdelem *method; + struct grpc_linked_mdelem *status; + struct grpc_linked_mdelem *authority; + struct grpc_linked_mdelem *scheme; + struct grpc_linked_mdelem *te; + struct grpc_linked_mdelem *grpc_message; + struct grpc_linked_mdelem *grpc_status; + struct grpc_linked_mdelem *grpc_payload_bin; + struct grpc_linked_mdelem *grpc_encoding; + struct grpc_linked_mdelem *grpc_accept_encoding; + struct grpc_linked_mdelem *grpc_server_stats_bin; + struct grpc_linked_mdelem *grpc_tags_bin; + struct grpc_linked_mdelem *grpc_trace_bin; + struct grpc_linked_mdelem *content_type; + struct grpc_linked_mdelem *grpc_internal_encoding_request; + struct grpc_linked_mdelem *user_agent; + struct grpc_linked_mdelem *host; + struct grpc_linked_mdelem *lb_token; + } named; +} grpc_metadata_batch_callouts; + +#define GRPC_BATCH_INDEX_OF(slice) \ + (GRPC_IS_STATIC_METADATA_STRING((slice)) \ + ? (grpc_metadata_batch_callouts_index)GPR_CLAMP( \ + GRPC_STATIC_METADATA_INDEX((slice)), 0, \ + GRPC_BATCH_CALLOUTS_COUNT) \ + : GRPC_BATCH_CALLOUTS_COUNT) -extern const uint8_t - grpc_static_metadata_elem_indices[GRPC_STATIC_MDELEM_COUNT * 2]; -extern const char *const grpc_static_metadata_strings[GRPC_STATIC_MDSTR_COUNT]; extern const uint8_t grpc_static_accept_encoding_metadata[8]; -#define GRPC_MDELEM_ACCEPT_ENCODING_FOR_ALGORITHMS(algs) \ - (&grpc_static_mdelem_table[grpc_static_accept_encoding_metadata[(algs)]]) +#define GRPC_MDELEM_ACCEPT_ENCODING_FOR_ALGORITHMS(algs) \ + (GRPC_MAKE_MDELEM( \ + &grpc_static_mdelem_table[grpc_static_accept_encoding_metadata[(algs)]], \ + GRPC_MDELEM_STORAGE_STATIC)) #endif /* GRPC_CORE_LIB_TRANSPORT_STATIC_METADATA_H */ diff --git a/Sources/CgRPC/src/core/lib/transport/status_conversion.c b/Sources/CgRPC/src/core/lib/transport/status_conversion.c new file mode 100644 index 000000000..9a76977e4 --- /dev/null +++ b/Sources/CgRPC/src/core/lib/transport/status_conversion.c @@ -0,0 +1,98 @@ +/* + * + * 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 "src/core/lib/transport/status_conversion.h" + +int grpc_status_to_http2_error(grpc_status_code status) { + switch (status) { + case GRPC_STATUS_OK: + return GRPC_HTTP2_NO_ERROR; + case GRPC_STATUS_CANCELLED: + return GRPC_HTTP2_CANCEL; + case GRPC_STATUS_DEADLINE_EXCEEDED: + return GRPC_HTTP2_CANCEL; + case GRPC_STATUS_RESOURCE_EXHAUSTED: + return GRPC_HTTP2_ENHANCE_YOUR_CALM; + case GRPC_STATUS_PERMISSION_DENIED: + return GRPC_HTTP2_INADEQUATE_SECURITY; + case GRPC_STATUS_UNAVAILABLE: + return GRPC_HTTP2_REFUSED_STREAM; + default: + return GRPC_HTTP2_INTERNAL_ERROR; + } +} + +grpc_status_code grpc_http2_error_to_grpc_status(grpc_http2_error_code error, + gpr_timespec deadline) { + switch (error) { + case GRPC_HTTP2_NO_ERROR: + /* should never be received */ + return GRPC_STATUS_INTERNAL; + case GRPC_HTTP2_CANCEL: + /* http2 cancel translates to STATUS_CANCELLED iff deadline hasn't been + * exceeded */ + return gpr_time_cmp(gpr_now(deadline.clock_type), deadline) >= 0 + ? GRPC_STATUS_DEADLINE_EXCEEDED + : GRPC_STATUS_CANCELLED; + case GRPC_HTTP2_ENHANCE_YOUR_CALM: + return GRPC_STATUS_RESOURCE_EXHAUSTED; + case GRPC_HTTP2_INADEQUATE_SECURITY: + return GRPC_STATUS_PERMISSION_DENIED; + case GRPC_HTTP2_REFUSED_STREAM: + return GRPC_STATUS_UNAVAILABLE; + default: + return GRPC_STATUS_INTERNAL; + } +} + +grpc_status_code grpc_http2_status_to_grpc_status(int status) { + switch (status) { + /* these HTTP2 status codes are called out explicitly in status.proto */ + case 200: + return GRPC_STATUS_OK; + case 400: + return GRPC_STATUS_INVALID_ARGUMENT; + case 401: + return GRPC_STATUS_UNAUTHENTICATED; + case 403: + return GRPC_STATUS_PERMISSION_DENIED; + case 404: + return GRPC_STATUS_NOT_FOUND; + case 409: + return GRPC_STATUS_ABORTED; + case 412: + return GRPC_STATUS_FAILED_PRECONDITION; + case 429: + return GRPC_STATUS_RESOURCE_EXHAUSTED; + case 499: + return GRPC_STATUS_CANCELLED; + case 500: + return GRPC_STATUS_UNKNOWN; + case 501: + return GRPC_STATUS_UNIMPLEMENTED; + case 503: + return GRPC_STATUS_UNAVAILABLE; + case 504: + return GRPC_STATUS_DEADLINE_EXCEEDED; + /* everything else is unknown */ + default: + return GRPC_STATUS_UNKNOWN; + } +} + +int grpc_status_to_http2_status(grpc_status_code status) { return 200; } diff --git a/Sources/CgRPC/src/core/lib/transport/status_conversion.h b/Sources/CgRPC/src/core/lib/transport/status_conversion.h new file mode 100644 index 000000000..e93f3dfd9 --- /dev/null +++ b/Sources/CgRPC/src/core/lib/transport/status_conversion.h @@ -0,0 +1,34 @@ +/* + * + * 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 GRPC_CORE_LIB_TRANSPORT_STATUS_CONVERSION_H +#define GRPC_CORE_LIB_TRANSPORT_STATUS_CONVERSION_H + +#include +#include "src/core/lib/transport/http2_errors.h" + +/* Conversion of grpc status codes to http2 error codes (for RST_STREAM) */ +grpc_http2_error_code grpc_status_to_http2_error(grpc_status_code status); +grpc_status_code grpc_http2_error_to_grpc_status(grpc_http2_error_code error, + gpr_timespec deadline); + +/* Conversion of HTTP status codes (:status) to grpc status codes */ +grpc_status_code grpc_http2_status_to_grpc_status(int status); +int grpc_status_to_http2_status(grpc_status_code status); + +#endif /* GRPC_CORE_LIB_TRANSPORT_STATUS_CONVERSION_H */ diff --git a/Sources/CgRPC/src/core/lib/transport/timeout_encoding.c b/Sources/CgRPC/src/core/lib/transport/timeout_encoding.c index b58ebbd0a..02f179d6a 100644 --- a/Sources/CgRPC/src/core/lib/transport/timeout_encoding.c +++ b/Sources/CgRPC/src/core/lib/transport/timeout_encoding.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -131,20 +116,21 @@ void grpc_http2_encode_timeout(gpr_timespec timeout, char *buffer) { } } -static int is_all_whitespace(const char *p) { - while (*p == ' ') p++; - return *p == 0; +static int is_all_whitespace(const char *p, const char *end) { + while (p != end && *p == ' ') p++; + return p == end; } -int grpc_http2_decode_timeout(const char *buffer, gpr_timespec *timeout) { +int grpc_http2_decode_timeout(grpc_slice text, gpr_timespec *timeout) { int32_t x = 0; - const uint8_t *p = (const uint8_t *)buffer; + const uint8_t *p = GRPC_SLICE_START_PTR(text); + const uint8_t *end = GRPC_SLICE_END_PTR(text); int have_digit = 0; /* skip whitespace */ - for (; *p == ' '; p++) + for (; p != end && *p == ' '; p++) ; /* decode numeric part */ - for (; *p >= '0' && *p <= '9'; p++) { + for (; p != end && *p >= '0' && *p <= '9'; p++) { int32_t digit = (int32_t)(*p - (uint8_t)'0'); have_digit = 1; /* spec allows max. 8 digits, but we allow values up to 1,000,000,000 */ @@ -158,8 +144,9 @@ int grpc_http2_decode_timeout(const char *buffer, gpr_timespec *timeout) { } if (!have_digit) return 0; /* skip whitespace */ - for (; *p == ' '; p++) + for (; p != end && *p == ' '; p++) ; + if (p == end) return 0; /* decode unit specifier */ switch (*p) { case 'n': @@ -184,5 +171,5 @@ int grpc_http2_decode_timeout(const char *buffer, gpr_timespec *timeout) { return 0; } p++; - return is_all_whitespace((const char *)p); + return is_all_whitespace((const char *)p, (const char *)end); } diff --git a/Sources/CgRPC/src/core/lib/transport/timeout_encoding.h b/Sources/CgRPC/src/core/lib/transport/timeout_encoding.h index 92f02f6ec..7ff35c408 100644 --- a/Sources/CgRPC/src/core/lib/transport/timeout_encoding.h +++ b/Sources/CgRPC/src/core/lib/transport/timeout_encoding.h @@ -1,40 +1,27 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 GRPC_CORE_LIB_TRANSPORT_TIMEOUT_ENCODING_H #define GRPC_CORE_LIB_TRANSPORT_TIMEOUT_ENCODING_H +#include #include + #include "src/core/lib/support/string.h" #define GRPC_HTTP2_TIMEOUT_ENCODE_MIN_BUFSIZE (GPR_LTOA_MIN_BUFSIZE + 1) @@ -42,6 +29,6 @@ /* Encode/decode timeouts to the GRPC over HTTP/2 format; encoding may round up arbitrarily */ void grpc_http2_encode_timeout(gpr_timespec timeout, char *buffer); -int grpc_http2_decode_timeout(const char *buffer, gpr_timespec *timeout); +int grpc_http2_decode_timeout(grpc_slice text, gpr_timespec *timeout); #endif /* GRPC_CORE_LIB_TRANSPORT_TIMEOUT_ENCODING_H */ diff --git a/Sources/CgRPC/src/core/lib/transport/transport.c b/Sources/CgRPC/src/core/lib/transport/transport.c index b448126da..6c61f4b8d 100644 --- a/Sources/CgRPC/src/core/lib/transport/transport.c +++ b/Sources/CgRPC/src/core/lib/transport/transport.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -40,39 +25,93 @@ #include #include +#include "src/core/lib/iomgr/executor.h" +#include "src/core/lib/slice/slice_internal.h" #include "src/core/lib/slice/slice_string_helpers.h" #include "src/core/lib/support/string.h" #include "src/core/lib/transport/transport_impl.h" -#ifdef GRPC_STREAM_REFCOUNT_DEBUG +#ifndef NDEBUG +grpc_tracer_flag grpc_trace_stream_refcount = + GRPC_TRACER_INITIALIZER(false, "stream_refcount"); +#endif + +#ifndef NDEBUG void grpc_stream_ref(grpc_stream_refcount *refcount, const char *reason) { - gpr_atm val = gpr_atm_no_barrier_load(&refcount->refs.count); - gpr_log(GPR_DEBUG, "%s %p:%p REF %" PRIdPTR "->%" PRIdPTR " %s", - refcount->object_type, refcount, refcount->destroy.cb_arg, val, - val + 1, reason); + if (GRPC_TRACER_ON(grpc_trace_stream_refcount)) { + gpr_atm val = gpr_atm_no_barrier_load(&refcount->refs.count); + gpr_log(GPR_DEBUG, "%s %p:%p REF %" PRIdPTR "->%" PRIdPTR " %s", + refcount->object_type, refcount, refcount->destroy.cb_arg, val, + val + 1, reason); + } #else void grpc_stream_ref(grpc_stream_refcount *refcount) { #endif gpr_ref_non_zero(&refcount->refs); } -#ifdef GRPC_STREAM_REFCOUNT_DEBUG +#ifndef NDEBUG void grpc_stream_unref(grpc_exec_ctx *exec_ctx, grpc_stream_refcount *refcount, const char *reason) { - gpr_atm val = gpr_atm_no_barrier_load(&refcount->refs.count); - gpr_log(GPR_DEBUG, "%s %p:%p UNREF %" PRIdPTR "->%" PRIdPTR " %s", - refcount->object_type, refcount, refcount->destroy.cb_arg, val, - val - 1, reason); + if (GRPC_TRACER_ON(grpc_trace_stream_refcount)) { + gpr_atm val = gpr_atm_no_barrier_load(&refcount->refs.count); + gpr_log(GPR_DEBUG, "%s %p:%p UNREF %" PRIdPTR "->%" PRIdPTR " %s", + refcount->object_type, refcount, refcount->destroy.cb_arg, val, + val - 1, reason); + } #else void grpc_stream_unref(grpc_exec_ctx *exec_ctx, grpc_stream_refcount *refcount) { #endif if (gpr_unref(&refcount->refs)) { - grpc_exec_ctx_sched(exec_ctx, &refcount->destroy, GRPC_ERROR_NONE, NULL); + if (exec_ctx->flags & GRPC_EXEC_CTX_FLAG_THREAD_RESOURCE_LOOP) { + /* Ick. + The thread we're running on MAY be owned (indirectly) by a call-stack. + If that's the case, destroying the call-stack MAY try to destroy the + thread, which is a tangled mess that we just don't want to ever have to + cope with. + Throw this over to the executor (on a core-owned thread) and process it + there. */ + refcount->destroy.scheduler = grpc_executor_scheduler; + } + GRPC_CLOSURE_SCHED(exec_ctx, &refcount->destroy, GRPC_ERROR_NONE); } } -#ifdef GRPC_STREAM_REFCOUNT_DEBUG +#define STREAM_REF_FROM_SLICE_REF(p) \ + ((grpc_stream_refcount *)(((uint8_t *)p) - \ + offsetof(grpc_stream_refcount, slice_refcount))) + +static void slice_stream_ref(void *p) { +#ifndef NDEBUG + grpc_stream_ref(STREAM_REF_FROM_SLICE_REF(p), "slice"); +#else + grpc_stream_ref(STREAM_REF_FROM_SLICE_REF(p)); +#endif +} + +static void slice_stream_unref(grpc_exec_ctx *exec_ctx, void *p) { +#ifndef NDEBUG + grpc_stream_unref(exec_ctx, STREAM_REF_FROM_SLICE_REF(p), "slice"); +#else + grpc_stream_unref(exec_ctx, STREAM_REF_FROM_SLICE_REF(p)); +#endif +} + +grpc_slice grpc_slice_from_stream_owned_buffer(grpc_stream_refcount *refcount, + void *buffer, size_t length) { + slice_stream_ref(&refcount->slice_refcount); + return (grpc_slice){.refcount = &refcount->slice_refcount, + .data.refcounted = {.bytes = buffer, .length = length}}; +} + +static const grpc_slice_refcount_vtable stream_ref_slice_vtable = { + .ref = slice_stream_ref, + .unref = slice_stream_unref, + .eq = grpc_slice_default_eq_impl, + .hash = grpc_slice_default_hash_impl}; + +#ifndef NDEBUG void grpc_stream_ref_init(grpc_stream_refcount *refcount, int initial_refs, grpc_iomgr_cb_func cb, void *cb_arg, const char *object_type) { @@ -82,7 +121,9 @@ void grpc_stream_ref_init(grpc_stream_refcount *refcount, int initial_refs, grpc_iomgr_cb_func cb, void *cb_arg) { #endif gpr_ref_init(&refcount->refs, initial_refs); - grpc_closure_init(&refcount->destroy, cb, cb_arg); + GRPC_CLOSURE_INIT(&refcount->destroy, cb, cb_arg, grpc_schedule_on_exec_ctx); + refcount->slice_refcount.vtable = &stream_ref_slice_vtable; + refcount->slice_refcount.sub_refcount = &refcount->slice_refcount; } static void move64(uint64_t *from, uint64_t *to) { @@ -115,15 +156,15 @@ void grpc_transport_destroy(grpc_exec_ctx *exec_ctx, int grpc_transport_init_stream(grpc_exec_ctx *exec_ctx, grpc_transport *transport, grpc_stream *stream, grpc_stream_refcount *refcount, - const void *server_data) { + const void *server_data, gpr_arena *arena) { return transport->vtable->init_stream(exec_ctx, transport, stream, refcount, - server_data); + server_data, arena); } void grpc_transport_perform_stream_op(grpc_exec_ctx *exec_ctx, grpc_transport *transport, grpc_stream *stream, - grpc_transport_stream_op *op) { + grpc_transport_stream_op_batch *op) { transport->vtable->perform_stream_op(exec_ctx, transport, stream, op); } @@ -150,9 +191,10 @@ void grpc_transport_set_pops(grpc_exec_ctx *exec_ctx, grpc_transport *transport, void grpc_transport_destroy_stream(grpc_exec_ctx *exec_ctx, grpc_transport *transport, - grpc_stream *stream, void *and_free_memory) { + grpc_stream *stream, + grpc_closure *then_schedule_closure) { transport->vtable->destroy_stream(exec_ctx, transport, stream, - and_free_memory); + then_schedule_closure); } char *grpc_transport_get_peer(grpc_exec_ctx *exec_ctx, @@ -165,99 +207,36 @@ grpc_endpoint *grpc_transport_get_endpoint(grpc_exec_ctx *exec_ctx, return transport->vtable->get_endpoint(exec_ctx, transport); } -void grpc_transport_stream_op_finish_with_failure(grpc_exec_ctx *exec_ctx, - grpc_transport_stream_op *op, - grpc_error *error) { - grpc_exec_ctx_sched(exec_ctx, op->recv_message_ready, GRPC_ERROR_REF(error), - NULL); - grpc_exec_ctx_sched(exec_ctx, op->recv_initial_metadata_ready, - GRPC_ERROR_REF(error), NULL); - grpc_exec_ctx_sched(exec_ctx, op->on_complete, error, NULL); -} - -typedef struct { - grpc_error *error; - grpc_closure *then_call; - grpc_closure closure; -} close_message_data; - -static void free_message(grpc_exec_ctx *exec_ctx, void *p, grpc_error *error) { - close_message_data *cmd = p; - GRPC_ERROR_UNREF(cmd->error); - if (cmd->then_call != NULL) { - cmd->then_call->cb(exec_ctx, cmd->then_call->cb_arg, error); +// This comment should be sung to the tune of +// "Supercalifragilisticexpialidocious": +// +// grpc_transport_stream_op_batch_finish_with_failure +// is a function that must always unref cancel_error +// though it lives in lib, it handles transport stream ops sure +// it's grpc_transport_stream_op_batch_finish_with_failure + +void grpc_transport_stream_op_batch_finish_with_failure( + grpc_exec_ctx *exec_ctx, grpc_transport_stream_op_batch *batch, + grpc_error *error) { + if (batch->send_message) { + grpc_byte_stream_destroy(exec_ctx, + batch->payload->send_message.send_message); } - gpr_free(cmd); -} - -static void add_error(grpc_transport_stream_op *op, grpc_error **which, - grpc_error *error) { - close_message_data *cmd; - cmd = gpr_malloc(sizeof(*cmd)); - cmd->error = error; - cmd->then_call = op->on_complete; - grpc_closure_init(&cmd->closure, free_message, cmd); - op->on_complete = &cmd->closure; - *which = error; -} - -void grpc_transport_stream_op_add_cancellation(grpc_transport_stream_op *op, - grpc_status_code status) { - GPR_ASSERT(status != GRPC_STATUS_OK); - if (op->cancel_error == GRPC_ERROR_NONE) { - op->cancel_error = grpc_error_set_int(GRPC_ERROR_CANCELLED, - GRPC_ERROR_INT_GRPC_STATUS, status); - op->close_error = GRPC_ERROR_NONE; + if (batch->recv_message) { + GRPC_CLOSURE_SCHED(exec_ctx, + batch->payload->recv_message.recv_message_ready, + GRPC_ERROR_REF(error)); } -} - -void grpc_transport_stream_op_add_cancellation_with_message( - grpc_transport_stream_op *op, grpc_status_code status, - grpc_slice *optional_message) { - GPR_ASSERT(status != GRPC_STATUS_OK); - if (op->cancel_error != GRPC_ERROR_NONE) { - if (optional_message) { - grpc_slice_unref(*optional_message); - } - return; + if (batch->recv_initial_metadata) { + GRPC_CLOSURE_SCHED( + exec_ctx, + batch->payload->recv_initial_metadata.recv_initial_metadata_ready, + GRPC_ERROR_REF(error)); } - grpc_error *error; - if (optional_message != NULL) { - char *msg = grpc_dump_slice(*optional_message, GPR_DUMP_ASCII); - error = grpc_error_set_str(GRPC_ERROR_CREATE(msg), - GRPC_ERROR_STR_GRPC_MESSAGE, msg); - gpr_free(msg); - grpc_slice_unref(*optional_message); - } else { - error = GRPC_ERROR_CREATE("Call cancelled"); - } - error = grpc_error_set_int(error, GRPC_ERROR_INT_GRPC_STATUS, status); - add_error(op, &op->cancel_error, error); -} - -void grpc_transport_stream_op_add_close(grpc_transport_stream_op *op, - grpc_status_code status, - grpc_slice *optional_message) { - GPR_ASSERT(status != GRPC_STATUS_OK); - if (op->cancel_error != GRPC_ERROR_NONE || - op->close_error != GRPC_ERROR_NONE) { - if (optional_message) { - grpc_slice_unref(*optional_message); - } - return; - } - grpc_error *error; - if (optional_message != NULL) { - char *msg = grpc_dump_slice(*optional_message, GPR_DUMP_ASCII); - error = grpc_error_set_str(GRPC_ERROR_CREATE(msg), - GRPC_ERROR_STR_GRPC_MESSAGE, msg); - gpr_free(msg); - grpc_slice_unref(*optional_message); - } else { - error = GRPC_ERROR_CREATE("Call force closed"); + GRPC_CLOSURE_SCHED(exec_ctx, batch->on_complete, error); + if (batch->cancel_stream) { + GRPC_ERROR_UNREF(batch->payload->cancel_stream.cancel_error); } - error = grpc_error_set_int(error, GRPC_ERROR_INT_GRPC_STATUS, status); - add_error(op, &op->close_error, error); } typedef struct { @@ -269,14 +248,14 @@ typedef struct { static void destroy_made_transport_op(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { made_transport_op *op = arg; - grpc_exec_ctx_sched(exec_ctx, op->inner_on_complete, GRPC_ERROR_REF(error), - NULL); + GRPC_CLOSURE_SCHED(exec_ctx, op->inner_on_complete, GRPC_ERROR_REF(error)); gpr_free(op); } grpc_transport_op *grpc_make_transport_op(grpc_closure *on_complete) { made_transport_op *op = gpr_malloc(sizeof(*op)); - grpc_closure_init(&op->outer_on_complete, destroy_made_transport_op, op); + GRPC_CLOSURE_INIT(&op->outer_on_complete, destroy_made_transport_op, op, + grpc_schedule_on_exec_ctx); op->inner_on_complete = on_complete; memset(&op->op, 0, sizeof(op->op)); op->op.on_consumed = &op->outer_on_complete; @@ -286,24 +265,25 @@ grpc_transport_op *grpc_make_transport_op(grpc_closure *on_complete) { typedef struct { grpc_closure outer_on_complete; grpc_closure *inner_on_complete; - grpc_transport_stream_op op; + grpc_transport_stream_op_batch op; + grpc_transport_stream_op_batch_payload payload; } made_transport_stream_op; static void destroy_made_transport_stream_op(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { made_transport_stream_op *op = arg; - grpc_exec_ctx_sched(exec_ctx, op->inner_on_complete, GRPC_ERROR_REF(error), - NULL); + grpc_closure *c = op->inner_on_complete; gpr_free(op); + GRPC_CLOSURE_RUN(exec_ctx, c, GRPC_ERROR_REF(error)); } -grpc_transport_stream_op *grpc_make_transport_stream_op( +grpc_transport_stream_op_batch *grpc_make_transport_stream_op( grpc_closure *on_complete) { - made_transport_stream_op *op = gpr_malloc(sizeof(*op)); - grpc_closure_init(&op->outer_on_complete, destroy_made_transport_stream_op, - op); + made_transport_stream_op *op = gpr_zalloc(sizeof(*op)); + op->op.payload = &op->payload; + GRPC_CLOSURE_INIT(&op->outer_on_complete, destroy_made_transport_stream_op, + op, grpc_schedule_on_exec_ctx); op->inner_on_complete = on_complete; - memset(&op->op, 0, sizeof(op->op)); op->op.on_complete = &op->outer_on_complete; return &op->op; } diff --git a/Sources/CgRPC/src/core/lib/transport/transport.h b/Sources/CgRPC/src/core/lib/transport/transport.h index 96c26749c..099138ea1 100644 --- a/Sources/CgRPC/src/core/lib/transport/transport.h +++ b/Sources/CgRPC/src/core/lib/transport/transport.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -41,6 +26,7 @@ #include "src/core/lib/iomgr/polling_entity.h" #include "src/core/lib/iomgr/pollset.h" #include "src/core/lib/iomgr/pollset_set.h" +#include "src/core/lib/support/arena.h" #include "src/core/lib/transport/byte_stream.h" #include "src/core/lib/transport/metadata_batch.h" @@ -56,17 +42,20 @@ typedef struct grpc_transport grpc_transport; for a stream. */ typedef struct grpc_stream grpc_stream; -//#define GRPC_STREAM_REFCOUNT_DEBUG +#ifndef NDEBUG +extern grpc_tracer_flag grpc_trace_stream_refcount; +#endif typedef struct grpc_stream_refcount { gpr_refcount refs; grpc_closure destroy; -#ifdef GRPC_STREAM_REFCOUNT_DEBUG +#ifndef NDEBUG const char *object_type; #endif + grpc_slice_refcount slice_refcount; } grpc_stream_refcount; -#ifdef GRPC_STREAM_REFCOUNT_DEBUG +#ifndef NDEBUG void grpc_stream_ref_init(grpc_stream_refcount *refcount, int initial_refs, grpc_iomgr_cb_func cb, void *cb_arg, const char *object_type); @@ -84,6 +73,11 @@ void grpc_stream_unref(grpc_exec_ctx *exec_ctx, grpc_stream_refcount *refcount); grpc_stream_ref_init(rc, ir, cb, cb_arg) #endif +/* Wrap a buffer that is owned by some stream object into a slice that shares + the same refcount */ +grpc_slice grpc_slice_from_stream_owned_buffer(grpc_stream_refcount *refcount, + void *buffer, size_t length); + typedef struct { uint64_t framing_bytes; uint64_t data_bytes; @@ -102,70 +96,125 @@ void grpc_transport_move_stats(grpc_transport_stream_stats *from, grpc_transport_stream_stats *to); typedef struct { + void *extra_arg; grpc_closure closure; - void *args[2]; -} grpc_transport_private_op_data; +} grpc_handler_private_op_data; + +typedef struct grpc_transport_stream_op_batch_payload + grpc_transport_stream_op_batch_payload; /* Transport stream op: a set of operations to perform on a transport against a single stream */ -typedef struct grpc_transport_stream_op { +typedef struct grpc_transport_stream_op_batch { /** Should be enqueued when all requested operations (excluding recv_message and recv_initial_metadata which have their own closures) in a given batch have been completed. */ grpc_closure *on_complete; - /** Is the completion of this op covered by a poller (if false: the op should - complete independently of some pollset being polled) */ - bool covered_by_poller; + /** Values for the stream op (fields set are determined by flags above) */ + grpc_transport_stream_op_batch_payload *payload; - /** Send initial metadata to the peer, from the provided metadata batch. - idempotent_request MUST be set if this is non-null */ - grpc_metadata_batch *send_initial_metadata; - /** Iff send_initial_metadata != NULL, flags associated with - send_initial_metadata: a bitfield of GRPC_INITIAL_METADATA_xxx */ - uint32_t send_initial_metadata_flags; + /** Send initial metadata to the peer, from the provided metadata batch. */ + bool send_initial_metadata : 1; /** Send trailing metadata to the peer, from the provided metadata batch. */ - grpc_metadata_batch *send_trailing_metadata; + bool send_trailing_metadata : 1; /** Send message data to the peer, from the provided byte stream. */ - grpc_byte_stream *send_message; + bool send_message : 1; /** Receive initial metadata from the stream, into provided metadata batch. */ - grpc_metadata_batch *recv_initial_metadata; - bool *recv_idempotent_request; - bool *recv_cacheable_request; - /** Should be enqueued when initial metadata is ready to be processed. */ - grpc_closure *recv_initial_metadata_ready; + bool recv_initial_metadata : 1; /** Receive message data from the stream, into provided byte stream. */ - grpc_byte_stream **recv_message; - /** Should be enqueued when one message is ready to be processed. */ - grpc_closure *recv_message_ready; + bool recv_message : 1; /** Receive trailing metadata from the stream, into provided metadata batch. */ - grpc_metadata_batch *recv_trailing_metadata; + bool recv_trailing_metadata : 1; /** Collect any stats into provided buffer, zero internal stat counters */ - grpc_transport_stream_stats *collect_stats; - - /** If != GRPC_ERROR_NONE, cancel this stream */ - grpc_error *cancel_error; + bool collect_stats : 1; - /** If != GRPC_ERROR_NONE, send grpc-status, grpc-message, and close this - stream for both reading and writing */ - grpc_error *close_error; - - /* Indexes correspond to grpc_context_index enum values */ - grpc_call_context_element *context; + /** Cancel this stream with the provided error */ + bool cancel_stream : 1; /*************************************************************************** * remaining fields are initialized and used at the discretion of the - * transport implementation */ + * current handler of the op */ + + grpc_handler_private_op_data handler_private; +} grpc_transport_stream_op_batch; + +struct grpc_transport_stream_op_batch_payload { + struct { + grpc_metadata_batch *send_initial_metadata; + /** Iff send_initial_metadata != NULL, flags associated with + send_initial_metadata: a bitfield of GRPC_INITIAL_METADATA_xxx */ + uint32_t send_initial_metadata_flags; + } send_initial_metadata; + + struct { + grpc_metadata_batch *send_trailing_metadata; + } send_trailing_metadata; + + struct { + // The transport (or a filter that decides to return a failure before + // the op gets down to the transport) is responsible for calling + // grpc_byte_stream_destroy() on this. + // The batch's on_complete will not be called until after the byte + // stream is destroyed. + grpc_byte_stream *send_message; + } send_message; + + struct { + grpc_metadata_batch *recv_initial_metadata; + uint32_t *recv_flags; + /** Should be enqueued when initial metadata is ready to be processed. */ + grpc_closure *recv_initial_metadata_ready; + // If not NULL, will be set to true if trailing metadata is + // immediately available. This may be a signal that we received a + // Trailers-Only response. + bool *trailing_metadata_available; + } recv_initial_metadata; + + struct { + // Will be set by the transport to point to the byte stream + // containing a received message. + // The caller is responsible for calling grpc_byte_stream_destroy() + // on this byte stream. + grpc_byte_stream **recv_message; + /** Should be enqueued when one message is ready to be processed. */ + grpc_closure *recv_message_ready; + } recv_message; + + struct { + grpc_metadata_batch *recv_trailing_metadata; + } recv_trailing_metadata; + + struct { + grpc_transport_stream_stats *collect_stats; + } collect_stats; + + /** Forcefully close this stream. + The HTTP2 semantics should be: + - server side: if cancel_error has GRPC_ERROR_INT_GRPC_STATUS, and + trailing metadata has not been sent, send trailing metadata with status + and message from cancel_error (use grpc_error_get_status) followed by + a RST_STREAM with error=GRPC_CHTTP2_NO_ERROR to force a full close + - at all other times: use grpc_error_get_status to get a status code, and + convert to a HTTP2 error code using + grpc_chttp2_grpc_status_to_http2_error. Send a RST_STREAM with this + error. */ + struct { + // Error contract: the transport that gets this op must cause cancel_error + // to be unref'ed after processing it + grpc_error *cancel_error; + } cancel_stream; - grpc_transport_private_op_data transport_private; -} grpc_transport_stream_op; + /* Indexes correspond to grpc_context_index enum values */ + grpc_call_context_element *context; +}; /** Transport op: a set of operations to perform on a transport as a whole */ typedef struct grpc_transport_op { @@ -174,15 +223,14 @@ typedef struct grpc_transport_op { /** connectivity monitoring - set connectivity_state to NULL to unsubscribe */ grpc_closure *on_connectivity_state_change; grpc_connectivity_state *connectivity_state; - /** should the transport be disconnected */ + /** should the transport be disconnected + * Error contract: the transport that gets this op must cause + * disconnect_with_error to be unref'ed after processing it */ grpc_error *disconnect_with_error; - /** should we send a goaway? - after a goaway is sent, once there are no more active calls on - the transport, the transport should disconnect */ - bool send_goaway; - /** what should the goaway contain? */ - grpc_status_code goaway_status; - grpc_slice *goaway_message; + /** what should the goaway contain? + * Error contract: the transport that gets this op must cause + * goaway_error to be unref'ed after processing it */ + grpc_error *goaway_error; /** set the callback for accepting new streams; this is a permanent callback, unlike the other one-shot closures. If true, the callback is set to set_accept_stream_fn, with its @@ -203,7 +251,7 @@ typedef struct grpc_transport_op { * remaining fields are initialized and used at the discretion of the * transport implementation */ - grpc_transport_private_op_data transport_private; + grpc_handler_private_op_data handler_private; } grpc_transport_op; /* Returns the amount of memory required to store a grpc_stream for this @@ -213,6 +261,7 @@ size_t grpc_transport_stream_size(grpc_transport *transport); /* Initialize transport data for a stream. Returns 0 on success, any other (transport-defined) value for failure. + May assume that stream contains all-zeros. Arguments: transport - the transport on which to create this stream @@ -222,7 +271,7 @@ size_t grpc_transport_stream_size(grpc_transport *transport); int grpc_transport_init_stream(grpc_exec_ctx *exec_ctx, grpc_transport *transport, grpc_stream *stream, grpc_stream_refcount *refcount, - const void *server_data); + const void *server_data, gpr_arena *arena); void grpc_transport_set_pops(grpc_exec_ctx *exec_ctx, grpc_transport *transport, grpc_stream *stream, grpc_polling_entity *pollent); @@ -239,24 +288,14 @@ void grpc_transport_set_pops(grpc_exec_ctx *exec_ctx, grpc_transport *transport, caller, but any child memory must be cleaned up) */ void grpc_transport_destroy_stream(grpc_exec_ctx *exec_ctx, grpc_transport *transport, - grpc_stream *stream, void *and_free_memory); - -void grpc_transport_stream_op_finish_with_failure(grpc_exec_ctx *exec_ctx, - grpc_transport_stream_op *op, - grpc_error *error); + grpc_stream *stream, + grpc_closure *then_schedule_closure); -void grpc_transport_stream_op_add_cancellation(grpc_transport_stream_op *op, - grpc_status_code status); +void grpc_transport_stream_op_batch_finish_with_failure( + grpc_exec_ctx *exec_ctx, grpc_transport_stream_op_batch *op, + grpc_error *error); -void grpc_transport_stream_op_add_cancellation_with_message( - grpc_transport_stream_op *op, grpc_status_code status, - grpc_slice *optional_message); - -void grpc_transport_stream_op_add_close(grpc_transport_stream_op *op, - grpc_status_code status, - grpc_slice *optional_message); - -char *grpc_transport_stream_op_string(grpc_transport_stream_op *op); +char *grpc_transport_stream_op_batch_string(grpc_transport_stream_op_batch *op); char *grpc_transport_op_string(grpc_transport_op *op); /* Send a batch of operations on a transport @@ -267,11 +306,12 @@ char *grpc_transport_op_string(grpc_transport_op *op); transport - the transport on which to initiate the stream stream - the stream on which to send the operations. This must be non-NULL and previously initialized by the same transport. - op - a grpc_transport_stream_op specifying the op to perform */ + op - a grpc_transport_stream_op_batch specifying the op to perform + */ void grpc_transport_perform_stream_op(grpc_exec_ctx *exec_ctx, grpc_transport *transport, grpc_stream *stream, - grpc_transport_stream_op *op); + grpc_transport_stream_op_batch *op); void grpc_transport_perform_op(grpc_exec_ctx *exec_ctx, grpc_transport *transport, @@ -303,9 +343,10 @@ grpc_endpoint *grpc_transport_get_endpoint(grpc_exec_ctx *exec_ctx, /* Allocate a grpc_transport_op, and preconfigure the on_consumed closure to \a on_consumed and then delete the returned transport op */ grpc_transport_op *grpc_make_transport_op(grpc_closure *on_consumed); -/* Allocate a grpc_transport_stream_op, and preconfigure the on_consumed closure +/* Allocate a grpc_transport_stream_op_batch, and preconfigure the on_consumed + closure to \a on_consumed and then delete the returned transport op */ -grpc_transport_stream_op *grpc_make_transport_stream_op( +grpc_transport_stream_op_batch *grpc_make_transport_stream_op( grpc_closure *on_consumed); #ifdef __cplusplus diff --git a/Sources/CgRPC/src/core/lib/transport/transport_impl.h b/Sources/CgRPC/src/core/lib/transport/transport_impl.h index 8553148c3..fc772c6dd 100644 --- a/Sources/CgRPC/src/core/lib/transport/transport_impl.h +++ b/Sources/CgRPC/src/core/lib/transport/transport_impl.h @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -47,7 +32,7 @@ typedef struct grpc_transport_vtable { /* implementation of grpc_transport_init_stream */ int (*init_stream)(grpc_exec_ctx *exec_ctx, grpc_transport *self, grpc_stream *stream, grpc_stream_refcount *refcount, - const void *server_data); + const void *server_data, gpr_arena *arena); /* implementation of grpc_transport_set_pollset */ void (*set_pollset)(grpc_exec_ctx *exec_ctx, grpc_transport *self, @@ -59,7 +44,8 @@ typedef struct grpc_transport_vtable { /* implementation of grpc_transport_perform_stream_op */ void (*perform_stream_op)(grpc_exec_ctx *exec_ctx, grpc_transport *self, - grpc_stream *stream, grpc_transport_stream_op *op); + grpc_stream *stream, + grpc_transport_stream_op_batch *op); /* implementation of grpc_transport_perform_op */ void (*perform_op)(grpc_exec_ctx *exec_ctx, grpc_transport *self, @@ -67,7 +53,8 @@ typedef struct grpc_transport_vtable { /* implementation of grpc_transport_destroy_stream */ void (*destroy_stream)(grpc_exec_ctx *exec_ctx, grpc_transport *self, - grpc_stream *stream, void *and_free_memory); + grpc_stream *stream, + grpc_closure *then_schedule_closure); /* implementation of grpc_transport_destroy */ void (*destroy)(grpc_exec_ctx *exec_ctx, grpc_transport *self); diff --git a/Sources/CgRPC/src/core/lib/transport/transport_op_string.c b/Sources/CgRPC/src/core/lib/transport/transport_op_string.c index 58d6ad508..7b18229ba 100644 --- a/Sources/CgRPC/src/core/lib/transport/transport_op_string.c +++ b/Sources/CgRPC/src/core/lib/transport/transport_op_string.c @@ -1,33 +1,18 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * */ @@ -47,14 +32,14 @@ /* These routines are here to facilitate debugging - they produce string representations of various transport data structures */ -static void put_metadata(gpr_strvec *b, grpc_mdelem *md) { +static void put_metadata(gpr_strvec *b, grpc_mdelem md) { gpr_strvec_add(b, gpr_strdup("key=")); gpr_strvec_add( - b, grpc_dump_slice(md->key->slice, GPR_DUMP_HEX | GPR_DUMP_ASCII)); + b, grpc_dump_slice(GRPC_MDKEY(md), GPR_DUMP_HEX | GPR_DUMP_ASCII)); gpr_strvec_add(b, gpr_strdup(" value=")); gpr_strvec_add( - b, grpc_dump_slice(md->value->slice, GPR_DUMP_HEX | GPR_DUMP_ASCII)); + b, grpc_dump_slice(GRPC_MDVALUE(md), GPR_DUMP_HEX | GPR_DUMP_ASCII)); } static void put_metadata_list(gpr_strvec *b, grpc_metadata_batch md) { @@ -71,65 +56,59 @@ static void put_metadata_list(gpr_strvec *b, grpc_metadata_batch md) { } } -char *grpc_transport_stream_op_string(grpc_transport_stream_op *op) { +char *grpc_transport_stream_op_batch_string( + grpc_transport_stream_op_batch *op) { char *tmp; char *out; gpr_strvec b; gpr_strvec_init(&b); - gpr_strvec_add( - &b, gpr_strdup(op->covered_by_poller ? "[COVERED]" : "[UNCOVERED]")); - - if (op->send_initial_metadata != NULL) { + if (op->send_initial_metadata) { gpr_strvec_add(&b, gpr_strdup(" ")); gpr_strvec_add(&b, gpr_strdup("SEND_INITIAL_METADATA{")); - put_metadata_list(&b, *op->send_initial_metadata); + put_metadata_list( + &b, *op->payload->send_initial_metadata.send_initial_metadata); gpr_strvec_add(&b, gpr_strdup("}")); } - if (op->send_message != NULL) { + if (op->send_message) { gpr_strvec_add(&b, gpr_strdup(" ")); gpr_asprintf(&tmp, "SEND_MESSAGE:flags=0x%08x:len=%d", - op->send_message->flags, op->send_message->length); + op->payload->send_message.send_message->flags, + op->payload->send_message.send_message->length); gpr_strvec_add(&b, tmp); } - if (op->send_trailing_metadata != NULL) { + if (op->send_trailing_metadata) { gpr_strvec_add(&b, gpr_strdup(" ")); gpr_strvec_add(&b, gpr_strdup("SEND_TRAILING_METADATA{")); - put_metadata_list(&b, *op->send_trailing_metadata); + put_metadata_list( + &b, *op->payload->send_trailing_metadata.send_trailing_metadata); gpr_strvec_add(&b, gpr_strdup("}")); } - if (op->recv_initial_metadata != NULL) { + if (op->recv_initial_metadata) { gpr_strvec_add(&b, gpr_strdup(" ")); gpr_strvec_add(&b, gpr_strdup("RECV_INITIAL_METADATA")); } - if (op->recv_message != NULL) { + if (op->recv_message) { gpr_strvec_add(&b, gpr_strdup(" ")); gpr_strvec_add(&b, gpr_strdup("RECV_MESSAGE")); } - if (op->recv_trailing_metadata != NULL) { + if (op->recv_trailing_metadata) { gpr_strvec_add(&b, gpr_strdup(" ")); gpr_strvec_add(&b, gpr_strdup("RECV_TRAILING_METADATA")); } - if (op->cancel_error != GRPC_ERROR_NONE) { + if (op->cancel_stream) { gpr_strvec_add(&b, gpr_strdup(" ")); - const char *msg = grpc_error_string(op->cancel_error); + const char *msg = + grpc_error_string(op->payload->cancel_stream.cancel_error); gpr_asprintf(&tmp, "CANCEL:%s", msg); - grpc_error_free_string(msg); - gpr_strvec_add(&b, tmp); - } - if (op->close_error != GRPC_ERROR_NONE) { - gpr_strvec_add(&b, gpr_strdup(" ")); - const char *msg = grpc_error_string(op->close_error); - gpr_asprintf(&tmp, "CLOSE:%s", msg); - grpc_error_free_string(msg); gpr_strvec_add(&b, tmp); } @@ -168,18 +147,14 @@ char *grpc_transport_op_string(grpc_transport_op *op) { const char *err = grpc_error_string(op->disconnect_with_error); gpr_asprintf(&tmp, "DISCONNECT:%s", err); gpr_strvec_add(&b, tmp); - grpc_error_free_string(err); } - if (op->send_goaway) { + if (op->goaway_error) { if (!first) gpr_strvec_add(&b, gpr_strdup(" ")); first = false; - char *msg = op->goaway_message == NULL - ? "null" - : grpc_dump_slice(*op->goaway_message, - GPR_DUMP_ASCII | GPR_DUMP_HEX); - gpr_asprintf(&tmp, "SEND_GOAWAY:status=%d:msg=%s", op->goaway_status, msg); - if (op->goaway_message != NULL) gpr_free(msg); + const char *msg = grpc_error_string(op->goaway_error); + gpr_asprintf(&tmp, "SEND_GOAWAY:%s", msg); + gpr_strvec_add(&b, tmp); } @@ -216,8 +191,9 @@ char *grpc_transport_op_string(grpc_transport_op *op) { } void grpc_call_log_op(char *file, int line, gpr_log_severity severity, - grpc_call_element *elem, grpc_transport_stream_op *op) { - char *str = grpc_transport_stream_op_string(op); + grpc_call_element *elem, + grpc_transport_stream_op_batch *op) { + char *str = grpc_transport_stream_op_batch_string(op); gpr_log(file, line, severity, "OP[%s:%p]: %s", elem->filter->name, elem, str); gpr_free(str); } diff --git a/Sources/CgRPC/src/core/lib/tsi/fake_transport_security.h b/Sources/CgRPC/src/core/lib/tsi/fake_transport_security.h deleted file mode 100644 index 54a9469b5..000000000 --- a/Sources/CgRPC/src/core/lib/tsi/fake_transport_security.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#ifndef GRPC_CORE_LIB_TSI_FAKE_TRANSPORT_SECURITY_H -#define GRPC_CORE_LIB_TSI_FAKE_TRANSPORT_SECURITY_H - -#include "src/core/lib/tsi/transport_security_interface.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* Value for the TSI_CERTIFICATE_TYPE_PEER_PROPERTY property for FAKE certs. */ -#define TSI_FAKE_CERTIFICATE_TYPE "FAKE" - -/* Creates a fake handshaker that will create a fake frame protector. - - No cryptography is performed in these objects. They just simulate handshake - messages going back and forth for the handshaker and do some framing on - cleartext data for the protector. */ -tsi_handshaker *tsi_create_fake_handshaker(int is_client); - -/* Creates a protector directly without going through the handshake phase. */ -tsi_frame_protector *tsi_create_fake_protector( - size_t *max_protected_frame_size); - -#ifdef __cplusplus -} -#endif - -#endif /* GRPC_CORE_LIB_TSI_FAKE_TRANSPORT_SECURITY_H */ diff --git a/Sources/CgRPC/src/core/lib/tsi/ssl_transport_security.h b/Sources/CgRPC/src/core/lib/tsi/ssl_transport_security.h deleted file mode 100644 index 740724611..000000000 --- a/Sources/CgRPC/src/core/lib/tsi/ssl_transport_security.h +++ /dev/null @@ -1,191 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#ifndef GRPC_CORE_LIB_TSI_SSL_TRANSPORT_SECURITY_H -#define GRPC_CORE_LIB_TSI_SSL_TRANSPORT_SECURITY_H - -#include "src/core/lib/tsi/transport_security_interface.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* Value for the TSI_CERTIFICATE_TYPE_PEER_PROPERTY property for X509 certs. */ -#define TSI_X509_CERTIFICATE_TYPE "X509" - -/* This property is of type TSI_PEER_PROPERTY_STRING. */ -#define TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY "x509_subject_common_name" -#define TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY \ - "x509_subject_alternative_name" - -#define TSI_X509_PEM_CERT_PROPERTY "x509_pem_cert" - -#define TSI_SSL_ALPN_SELECTED_PROTOCOL "ssl_alpn_selected_protocol" - -/* --- tsi_ssl_handshaker_factory object --- - - This object creates tsi_handshaker objects implemented in terms of the - TLS 1.2 specificiation. */ - -typedef struct tsi_ssl_handshaker_factory tsi_ssl_handshaker_factory; - -/* Creates a client handshaker factory. - - pem_private_key is the buffer containing the PEM encoding of the client's - private key. This parameter can be NULL if the client does not have a - private key. - - pem_private_key_size is the size of the associated buffer. - - pem_cert_chain is the buffer containing the PEM encoding of the client's - certificate chain. This parameter can be NULL if the client does not have - a certificate chain. - - pem_cert_chain_size is the size of the associated buffer. - - pem_roots_cert is the buffer containing the PEM encoding of the server - root certificates. This parameter cannot be NULL. - - pem_roots_cert_size is the size of the associated buffer. - - cipher_suites contains an optional list of the ciphers that the client - supports. The format of this string is described in: - https://www.openssl.org/docs/apps/ciphers.html. - This parameter can be set to NULL to use the default set of ciphers. - TODO(jboeuf): Revisit the format of this parameter. - - alpn_protocols is an array containing the protocol names that the - handshakers created with this factory support. This parameter can be NULL. - - alpn_protocols_lengths is an array containing the lengths of the alpn - protocols specified in alpn_protocols. This parameter can be NULL. - - num_alpn_protocols is the number of alpn protocols and associated lengths - specified. If this parameter is 0, the other alpn parameters must be NULL. - - factory is the address of the factory pointer to be created. - - - This method returns TSI_OK on success or TSI_INVALID_PARAMETER in the case - where a parameter is invalid. */ -tsi_result tsi_create_ssl_client_handshaker_factory( - const unsigned char *pem_private_key, size_t pem_private_key_size, - const unsigned char *pem_cert_chain, size_t pem_cert_chain_size, - const unsigned char *pem_root_certs, size_t pem_root_certs_size, - const char *cipher_suites, const unsigned char **alpn_protocols, - const unsigned char *alpn_protocols_lengths, uint16_t num_alpn_protocols, - tsi_ssl_handshaker_factory **factory); - -/* Creates a server handshaker factory. - - version indicates which version of the specification to use. - - pem_private_keys is an array containing the PEM encoding of the server's - private keys. This parameter cannot be NULL. The size of the array is - given by the key_cert_pair_count parameter. - - pem_private_keys_sizes is the array containing the sizes of the associated - buffers. - - pem_cert_chains is an array containing the PEM encoding of the server's - cert chains. This parameter cannot be NULL. The size of the array is - given by the key_cert_pair_count parameter. - - pem_cert_chains_sizes is the array containing the sizes of the associated - buffers. - - key_cert_pair_count indicates the number of items in the private_key_files - and cert_chain_files parameters. - - pem_client_roots is the buffer containing the PEM encoding of the client - root certificates. This parameter may be NULL in which case the server will - not authenticate the client. If not NULL, the force_client_auth parameter - specifies if the server will accept only authenticated clients or both - authenticated and non-authenticated clients. - - pem_client_root_certs_size is the size of the associated buffer. - - force_client_auth, if set to non-zero will force the client to authenticate - with an SSL cert. Note that this option is ignored if pem_client_root_certs - is NULL or pem_client_roots_certs_size is 0 - - cipher_suites contains an optional list of the ciphers that the server - supports. The format of this string is described in: - https://www.openssl.org/docs/apps/ciphers.html. - This parameter can be set to NULL to use the default set of ciphers. - TODO(jboeuf): Revisit the format of this parameter. - - alpn_protocols is an array containing the protocol names that the - handshakers created with this factory support. This parameter can be NULL. - - alpn_protocols_lengths is an array containing the lengths of the alpn - protocols specified in alpn_protocols. This parameter can be NULL. - - num_alpn_protocols is the number of alpn protocols and associated lengths - specified. If this parameter is 0, the other alpn parameters must be NULL. - - factory is the address of the factory pointer to be created. - - - This method returns TSI_OK on success or TSI_INVALID_PARAMETER in the case - where a parameter is invalid. */ -tsi_result tsi_create_ssl_server_handshaker_factory( - const unsigned char **pem_private_keys, - const size_t *pem_private_keys_sizes, const unsigned char **pem_cert_chains, - const size_t *pem_cert_chains_sizes, size_t key_cert_pair_count, - const unsigned char *pem_client_root_certs, - size_t pem_client_root_certs_size, int force_client_auth, - const char *cipher_suites, const unsigned char **alpn_protocols, - const unsigned char *alpn_protocols_lengths, uint16_t num_alpn_protocols, - tsi_ssl_handshaker_factory **factory); - -/* Same as tsi_create_ssl_server_handshaker_factory method except uses - tsi_client_certificate_request_type to support more ways to handle client - certificate authentication. - - client_certificate_request, if set to non-zero will force the client to - authenticate with an SSL cert. Note that this option is ignored if - pem_client_root_certs is NULL or pem_client_roots_certs_size is 0 */ -tsi_result tsi_create_ssl_server_handshaker_factory_ex( - const unsigned char **pem_private_keys, - const size_t *pem_private_keys_sizes, const unsigned char **pem_cert_chains, - const size_t *pem_cert_chains_sizes, size_t key_cert_pair_count, - const unsigned char *pem_client_root_certs, - size_t pem_client_root_certs_size, - tsi_client_certificate_request_type client_certificate_request, - const char *cipher_suites, const unsigned char **alpn_protocols, - const unsigned char *alpn_protocols_lengths, uint16_t num_alpn_protocols, - tsi_ssl_handshaker_factory **factory); - -/* Creates a handshaker. - - self is the factory from which the handshaker will be created. - - server_name_indication indicates the name of the server the client is - trying to connect to which will be relayed to the server using the SNI - extension. - This parameter must be NULL for a server handshaker factory. - - handhshaker is the address of the handshaker pointer to be created. - - - This method returns TSI_OK on success or TSI_INVALID_PARAMETER in the case - where a parameter is invalid. */ -tsi_result tsi_ssl_handshaker_factory_create_handshaker( - tsi_ssl_handshaker_factory *self, const char *server_name_indication, - tsi_handshaker **handshaker); - -/* Destroys the handshaker factory. WARNING: it is unsafe to destroy a factory - while handshakers created with this factory are still in use. */ -void tsi_ssl_handshaker_factory_destroy(tsi_ssl_handshaker_factory *self); - -/* Util that checks that an ssl peer matches a specific name. - Still TODO(jboeuf): - - handle mixed case. - - handle %encoded chars. - - handle public suffix wildchar more strictly (e.g. *.co.uk) */ -int tsi_ssl_peer_matches_name(const tsi_peer *peer, const char *name); - -#ifdef __cplusplus -} -#endif - -#endif /* GRPC_CORE_LIB_TSI_SSL_TRANSPORT_SECURITY_H */ diff --git a/Sources/CgRPC/src/core/lib/tsi/ssl_types.h b/Sources/CgRPC/src/core/lib/tsi/ssl_types.h deleted file mode 100644 index 0a988effd..000000000 --- a/Sources/CgRPC/src/core/lib/tsi/ssl_types.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#ifndef GRPC_CORE_LIB_TSI_SSL_TYPES_H -#define GRPC_CORE_LIB_TSI_SSL_TYPES_H - -/* A collection of macros to cast between various integer types that are - * used differently between BoringSSL and OpenSSL: - * TSI_INT_AS_SIZE(x): convert 'int x' to a length parameter for an OpenSSL - * function - * TSI_SIZE_AS_SIZE(x): convert 'size_t x' to a length parameter for an OpenSSL - * function - */ - -#include - -#ifdef OPENSSL_IS_BORINGSSL -#define TSI_INT_AS_SIZE(x) ((size_t)(x)) -#define TSI_SIZE_AS_SIZE(x) (x) -#else -#define TSI_INT_AS_SIZE(x) (x) -#define TSI_SIZE_AS_SIZE(x) ((int)(x)) -#endif - -#endif /* GRPC_CORE_LIB_TSI_SSL_TYPES_H */ diff --git a/Sources/CgRPC/src/core/plugin_registry/grpc_plugin_registry.c b/Sources/CgRPC/src/core/plugin_registry/grpc_plugin_registry.c index 2efd9cd1a..fa9974952 100644 --- a/Sources/CgRPC/src/core/plugin_registry/grpc_plugin_registry.c +++ b/Sources/CgRPC/src/core/plugin_registry/grpc_plugin_registry.c @@ -1,48 +1,45 @@ /* * - * Copyright 2016, Google Inc. - * All rights reserved. + * Copyright 2016 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 +extern void grpc_http_filters_init(void); +extern void grpc_http_filters_shutdown(void); extern void grpc_chttp2_plugin_init(void); extern void grpc_chttp2_plugin_shutdown(void); +extern void grpc_tsi_gts_init(void); +extern void grpc_tsi_gts_shutdown(void); +extern void grpc_deadline_filter_init(void); +extern void grpc_deadline_filter_shutdown(void); extern void grpc_client_channel_init(void); extern void grpc_client_channel_shutdown(void); +extern void grpc_inproc_plugin_init(void); +extern void grpc_inproc_plugin_shutdown(void); +extern void grpc_resolver_fake_init(void); +extern void grpc_resolver_fake_shutdown(void); extern void grpc_lb_policy_grpclb_init(void); extern void grpc_lb_policy_grpclb_shutdown(void); extern void grpc_lb_policy_pick_first_init(void); extern void grpc_lb_policy_pick_first_shutdown(void); extern void grpc_lb_policy_round_robin_init(void); extern void grpc_lb_policy_round_robin_shutdown(void); +extern void grpc_resolver_dns_ares_init(void); +extern void grpc_resolver_dns_ares_shutdown(void); extern void grpc_resolver_dns_native_init(void); extern void grpc_resolver_dns_native_shutdown(void); extern void grpc_resolver_sockaddr_init(void); @@ -51,18 +48,36 @@ extern void grpc_load_reporting_plugin_init(void); extern void grpc_load_reporting_plugin_shutdown(void); extern void census_grpc_plugin_init(void); extern void census_grpc_plugin_shutdown(void); +extern void grpc_max_age_filter_init(void); +extern void grpc_max_age_filter_shutdown(void); +extern void grpc_message_size_filter_init(void); +extern void grpc_message_size_filter_shutdown(void); +extern void grpc_workaround_cronet_compression_filter_init(void); +extern void grpc_workaround_cronet_compression_filter_shutdown(void); void grpc_register_built_in_plugins(void) { + grpc_register_plugin(grpc_http_filters_init, + grpc_http_filters_shutdown); grpc_register_plugin(grpc_chttp2_plugin_init, grpc_chttp2_plugin_shutdown); + grpc_register_plugin(grpc_tsi_gts_init, + grpc_tsi_gts_shutdown); + grpc_register_plugin(grpc_deadline_filter_init, + grpc_deadline_filter_shutdown); grpc_register_plugin(grpc_client_channel_init, grpc_client_channel_shutdown); + grpc_register_plugin(grpc_inproc_plugin_init, + grpc_inproc_plugin_shutdown); + grpc_register_plugin(grpc_resolver_fake_init, + grpc_resolver_fake_shutdown); grpc_register_plugin(grpc_lb_policy_grpclb_init, grpc_lb_policy_grpclb_shutdown); grpc_register_plugin(grpc_lb_policy_pick_first_init, grpc_lb_policy_pick_first_shutdown); grpc_register_plugin(grpc_lb_policy_round_robin_init, grpc_lb_policy_round_robin_shutdown); + grpc_register_plugin(grpc_resolver_dns_ares_init, + grpc_resolver_dns_ares_shutdown); grpc_register_plugin(grpc_resolver_dns_native_init, grpc_resolver_dns_native_shutdown); grpc_register_plugin(grpc_resolver_sockaddr_init, @@ -71,4 +86,10 @@ void grpc_register_built_in_plugins(void) { grpc_load_reporting_plugin_shutdown); grpc_register_plugin(census_grpc_plugin_init, census_grpc_plugin_shutdown); + grpc_register_plugin(grpc_max_age_filter_init, + grpc_max_age_filter_shutdown); + grpc_register_plugin(grpc_message_size_filter_init, + grpc_message_size_filter_shutdown); + grpc_register_plugin(grpc_workaround_cronet_compression_filter_init, + grpc_workaround_cronet_compression_filter_shutdown); } diff --git a/Sources/CgRPC/src/core/lib/tsi/fake_transport_security.c b/Sources/CgRPC/src/core/tsi/fake_transport_security.c similarity index 61% rename from Sources/CgRPC/src/core/lib/tsi/fake_transport_security.c rename to Sources/CgRPC/src/core/tsi/fake_transport_security.c index 0e20d6fd7..967126ece 100644 --- a/Sources/CgRPC/src/core/lib/tsi/fake_transport_security.c +++ b/Sources/CgRPC/src/core/tsi/fake_transport_security.c @@ -1,37 +1,22 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 "src/core/lib/tsi/fake_transport_security.h" +#include "src/core/tsi/fake_transport_security.h" #include #include @@ -40,12 +25,13 @@ #include #include #include -#include "src/core/lib/tsi/transport_security.h" +#include "src/core/tsi/transport_security.h" /* --- Constants. ---*/ #define TSI_FAKE_FRAME_HEADER_SIZE 4 #define TSI_FAKE_FRAME_INITIAL_ALLOCATED_SIZE 64 #define TSI_FAKE_DEFAULT_FRAME_SIZE 16384 +#define TSI_FAKE_HANDSHAKER_OUTGOING_BUFFER_INITIAL_SIZE 256 /* --- Structure definitions. ---*/ @@ -74,8 +60,10 @@ typedef struct { int is_client; tsi_fake_handshake_message next_message_to_send; int needs_incoming_message; - tsi_fake_frame incoming; - tsi_fake_frame outgoing; + tsi_fake_frame incoming_frame; + tsi_fake_frame outgoing_frame; + unsigned char *outgoing_bytes_buffer; + size_t outgoing_bytes_buffer_size; tsi_result result; } tsi_fake_handshaker; @@ -131,27 +119,23 @@ static void tsi_fake_frame_reset(tsi_fake_frame *frame, int needs_draining) { if (!needs_draining) frame->size = 0; } -/* Returns 1 if successful, 0 otherwise. */ -static int tsi_fake_frame_ensure_size(tsi_fake_frame *frame) { +/* Checks if the frame's allocated size is at least frame->size, and reallocs + * more memory if necessary. */ +static void tsi_fake_frame_ensure_size(tsi_fake_frame *frame) { if (frame->data == NULL) { frame->allocated_size = frame->size; frame->data = gpr_malloc(frame->allocated_size); - if (frame->data == NULL) return 0; } else if (frame->size > frame->allocated_size) { unsigned char *new_data = gpr_realloc(frame->data, frame->size); - if (new_data == NULL) { - gpr_free(frame->data); - frame->data = NULL; - return 0; - } frame->data = new_data; frame->allocated_size = frame->size; } - return 1; } -/* This method should not be called if frame->needs_framing is not 0. */ -static tsi_result fill_frame_from_bytes(const unsigned char *incoming_bytes, +/* Decodes the serialized fake frame contained in incoming_bytes, and fills + * frame with the contents of the decoded frame. + * This method should not be called if frame->needs_framing is not 0. */ +static tsi_result tsi_fake_frame_decode(const unsigned char *incoming_bytes, size_t *incoming_bytes_size, tsi_fake_frame *frame) { size_t available_size = *incoming_bytes_size; @@ -162,7 +146,6 @@ static tsi_result fill_frame_from_bytes(const unsigned char *incoming_bytes, if (frame->data == NULL) { frame->allocated_size = TSI_FAKE_FRAME_INITIAL_ALLOCATED_SIZE; frame->data = gpr_malloc(frame->allocated_size); - if (frame->data == NULL) return TSI_OUT_OF_RESOURCES; } if (frame->offset < TSI_FAKE_FRAME_HEADER_SIZE) { @@ -180,7 +163,7 @@ static tsi_result fill_frame_from_bytes(const unsigned char *incoming_bytes, frame->offset += to_read_size; available_size -= to_read_size; frame->size = load32_little_endian(frame->data); - if (!tsi_fake_frame_ensure_size(frame)) return TSI_OUT_OF_RESOURCES; + tsi_fake_frame_ensure_size(frame); } to_read_size = frame->size - frame->offset; @@ -198,10 +181,12 @@ static tsi_result fill_frame_from_bytes(const unsigned char *incoming_bytes, return TSI_OK; } -/* This method should not be called if frame->needs_framing is 0. */ -static tsi_result drain_frame_to_bytes(unsigned char *outgoing_bytes, - size_t *outgoing_bytes_size, - tsi_fake_frame *frame) { +/* Encodes a fake frame into its wire format and places the result in + * outgoing_bytes. outgoing_bytes_size indicates the size of the encoded frame. + * This method should not be called if frame->needs_framing is 0. */ +static tsi_result tsi_fake_frame_encode(unsigned char *outgoing_bytes, + size_t *outgoing_bytes_size, + tsi_fake_frame *frame) { size_t to_write_size = frame->size - frame->offset; if (!frame->needs_draining) return TSI_INTERNAL_ERROR; if (*outgoing_bytes_size < to_write_size) { @@ -215,17 +200,20 @@ static tsi_result drain_frame_to_bytes(unsigned char *outgoing_bytes, return TSI_OK; } -static tsi_result bytes_to_frame(unsigned char *bytes, size_t bytes_size, - tsi_fake_frame *frame) { +/* Sets the payload of a fake frame to contain the given data blob, where + * data_size indicates the size of data. */ +static tsi_result tsi_fake_frame_set_data(unsigned char *data, size_t data_size, + tsi_fake_frame *frame) { frame->offset = 0; - frame->size = bytes_size + TSI_FAKE_FRAME_HEADER_SIZE; - if (!tsi_fake_frame_ensure_size(frame)) return TSI_OUT_OF_RESOURCES; + frame->size = data_size + TSI_FAKE_FRAME_HEADER_SIZE; + tsi_fake_frame_ensure_size(frame); store32_little_endian((uint32_t)frame->size, frame->data); - memcpy(frame->data + TSI_FAKE_FRAME_HEADER_SIZE, bytes, bytes_size); + memcpy(frame->data + TSI_FAKE_FRAME_HEADER_SIZE, data, data_size); tsi_fake_frame_reset(frame, 1 /* needs draining */); return TSI_OK; } +/* Destroys the contents of a fake frame. */ static void tsi_fake_frame_destruct(tsi_fake_frame *frame) { if (frame->data != NULL) gpr_free(frame->data); } @@ -250,7 +238,7 @@ static tsi_result fake_protector_protect(tsi_frame_protector *self, if (frame->needs_draining) { drained_size = saved_output_size - *num_bytes_written; result = - drain_frame_to_bytes(protected_output_frames, &drained_size, frame); + tsi_fake_frame_encode(protected_output_frames, &drained_size, frame); *num_bytes_written += drained_size; protected_output_frames += drained_size; if (result != TSI_OK) { @@ -269,15 +257,15 @@ static tsi_result fake_protector_protect(tsi_frame_protector *self, size_t written_in_frame_size = 0; store32_little_endian((uint32_t)impl->max_frame_size, frame_header); written_in_frame_size = TSI_FAKE_FRAME_HEADER_SIZE; - result = fill_frame_from_bytes(frame_header, &written_in_frame_size, frame); + result = tsi_fake_frame_decode(frame_header, &written_in_frame_size, frame); if (result != TSI_INCOMPLETE_DATA) { - gpr_log(GPR_ERROR, "fill_frame_from_bytes returned %s", + gpr_log(GPR_ERROR, "tsi_fake_frame_decode returned %s", tsi_result_to_string(result)); return result; } } result = - fill_frame_from_bytes(unprotected_bytes, unprotected_bytes_size, frame); + tsi_fake_frame_decode(unprotected_bytes, unprotected_bytes_size, frame); if (result != TSI_OK) { if (result == TSI_INCOMPLETE_DATA) result = TSI_OK; return result; @@ -287,7 +275,7 @@ static tsi_result fake_protector_protect(tsi_frame_protector *self, if (!frame->needs_draining) return TSI_INTERNAL_ERROR; if (frame->offset != 0) return TSI_INTERNAL_ERROR; drained_size = saved_output_size - *num_bytes_written; - result = drain_frame_to_bytes(protected_output_frames, &drained_size, frame); + result = tsi_fake_frame_encode(protected_output_frames, &drained_size, frame); *num_bytes_written += drained_size; if (result == TSI_INCOMPLETE_DATA) result = TSI_OK; return result; @@ -307,8 +295,8 @@ static tsi_result fake_protector_protect_flush( store32_little_endian((uint32_t)frame->size, frame->data); /* Overwrite header. */ } - result = drain_frame_to_bytes(protected_output_frames, - protected_output_frames_size, frame); + result = tsi_fake_frame_encode(protected_output_frames, + protected_output_frames_size, frame); if (result == TSI_INCOMPLETE_DATA) result = TSI_OK; *still_pending_size = frame->size - frame->offset; return result; @@ -331,7 +319,7 @@ static tsi_result fake_protector_unprotect( /* Go past the header if needed. */ if (frame->offset == 0) frame->offset = TSI_FAKE_FRAME_HEADER_SIZE; drained_size = saved_output_size - *num_bytes_written; - result = drain_frame_to_bytes(unprotected_bytes, &drained_size, frame); + result = tsi_fake_frame_encode(unprotected_bytes, &drained_size, frame); unprotected_bytes += drained_size; *num_bytes_written += drained_size; if (result != TSI_OK) { @@ -345,7 +333,7 @@ static tsi_result fake_protector_unprotect( /* Now process the protected_bytes. */ if (frame->needs_draining) return TSI_INTERNAL_ERROR; - result = fill_frame_from_bytes(protected_frames_bytes, + result = tsi_fake_frame_decode(protected_frames_bytes, protected_frames_bytes_size, frame); if (result != TSI_OK) { if (result == TSI_INCOMPLETE_DATA) result = TSI_OK; @@ -357,7 +345,7 @@ static tsi_result fake_protector_unprotect( if (frame->offset != 0) return TSI_INTERNAL_ERROR; frame->offset = TSI_FAKE_FRAME_HEADER_SIZE; /* Go past the header. */ drained_size = saved_output_size - *num_bytes_written; - result = drain_frame_to_bytes(unprotected_bytes, &drained_size, frame); + result = tsi_fake_frame_encode(unprotected_bytes, &drained_size, frame); *num_bytes_written += drained_size; if (result == TSI_INCOMPLETE_DATA) result = TSI_OK; return result; @@ -375,6 +363,74 @@ static const tsi_frame_protector_vtable frame_protector_vtable = { fake_protector_unprotect, fake_protector_destroy, }; +/* --- tsi_handshaker_result methods implementation. ---*/ + +typedef struct { + tsi_handshaker_result base; + unsigned char *unused_bytes; + size_t unused_bytes_size; +} fake_handshaker_result; + +static tsi_result fake_handshaker_result_extract_peer( + const tsi_handshaker_result *self, tsi_peer *peer) { + /* Construct a tsi_peer with 1 property: certificate type. */ + tsi_result result = tsi_construct_peer(1, peer); + if (result != TSI_OK) return result; + result = tsi_construct_string_peer_property_from_cstring( + TSI_CERTIFICATE_TYPE_PEER_PROPERTY, TSI_FAKE_CERTIFICATE_TYPE, + &peer->properties[0]); + if (result != TSI_OK) tsi_peer_destruct(peer); + return result; +} + +static tsi_result fake_handshaker_result_create_frame_protector( + const tsi_handshaker_result *self, size_t *max_output_protected_frame_size, + tsi_frame_protector **protector) { + *protector = tsi_create_fake_frame_protector(max_output_protected_frame_size); + return TSI_OK; +} + +static tsi_result fake_handshaker_result_get_unused_bytes( + const tsi_handshaker_result *self, const unsigned char **bytes, + size_t *bytes_size) { + fake_handshaker_result *result = (fake_handshaker_result *)self; + *bytes_size = result->unused_bytes_size; + *bytes = result->unused_bytes; + return TSI_OK; +} + +static void fake_handshaker_result_destroy(tsi_handshaker_result *self) { + fake_handshaker_result *result = (fake_handshaker_result *)self; + gpr_free(result->unused_bytes); + gpr_free(self); +} + +static const tsi_handshaker_result_vtable handshaker_result_vtable = { + fake_handshaker_result_extract_peer, + NULL, /* create_zero_copy_grpc_protector */ + fake_handshaker_result_create_frame_protector, + fake_handshaker_result_get_unused_bytes, + fake_handshaker_result_destroy, +}; + +static tsi_result fake_handshaker_result_create( + const unsigned char *unused_bytes, size_t unused_bytes_size, + tsi_handshaker_result **handshaker_result) { + if ((unused_bytes_size > 0 && unused_bytes == NULL) || + handshaker_result == NULL) { + return TSI_INVALID_ARGUMENT; + } + fake_handshaker_result *result = gpr_zalloc(sizeof(*result)); + result->base.vtable = &handshaker_result_vtable; + if (unused_bytes_size > 0) { + result->unused_bytes = gpr_malloc(unused_bytes_size); + memcpy(result->unused_bytes, unused_bytes, unused_bytes_size); + } + result->unused_bytes_size = unused_bytes_size; + *handshaker_result = &result->base; + return TSI_OK; +} + /* --- tsi_handshaker methods implementation. ---*/ static tsi_result fake_handshaker_get_bytes_to_send_to_peer( @@ -385,30 +441,30 @@ static tsi_result fake_handshaker_get_bytes_to_send_to_peer( *bytes_size = 0; return TSI_OK; } - if (!impl->outgoing.needs_draining) { + if (!impl->outgoing_frame.needs_draining) { tsi_fake_handshake_message next_message_to_send = impl->next_message_to_send + 2; const char *msg_string = tsi_fake_handshake_message_to_string(impl->next_message_to_send); - result = bytes_to_frame((unsigned char *)msg_string, strlen(msg_string), - &impl->outgoing); + result = tsi_fake_frame_set_data((unsigned char *)msg_string, + strlen(msg_string), &impl->outgoing_frame); if (result != TSI_OK) return result; if (next_message_to_send > TSI_FAKE_HANDSHAKE_MESSAGE_MAX) { next_message_to_send = TSI_FAKE_HANDSHAKE_MESSAGE_MAX; } - if (tsi_tracing_enabled) { + if (GRPC_TRACER_ON(tsi_tracing_enabled)) { gpr_log(GPR_INFO, "%s prepared %s.", impl->is_client ? "Client" : "Server", tsi_fake_handshake_message_to_string(impl->next_message_to_send)); } impl->next_message_to_send = next_message_to_send; } - result = drain_frame_to_bytes(bytes, bytes_size, &impl->outgoing); + result = tsi_fake_frame_encode(bytes, bytes_size, &impl->outgoing_frame); if (result != TSI_OK) return result; if (!impl->is_client && impl->next_message_to_send == TSI_FAKE_HANDSHAKE_MESSAGE_MAX) { /* We're done. */ - if (tsi_tracing_enabled) { + if (GRPC_TRACER_ON(tsi_tracing_enabled)) { gpr_log(GPR_INFO, "Server is done."); } impl->result = TSI_OK; @@ -429,12 +485,12 @@ static tsi_result fake_handshaker_process_bytes_from_peer( *bytes_size = 0; return TSI_OK; } - result = fill_frame_from_bytes(bytes, bytes_size, &impl->incoming); + result = tsi_fake_frame_decode(bytes, bytes_size, &impl->incoming_frame); if (result != TSI_OK) return result; /* We now have a complete frame. */ result = tsi_fake_handshake_message_from_string( - (const char *)impl->incoming.data + TSI_FAKE_FRAME_HEADER_SIZE, + (const char *)impl->incoming_frame.data + TSI_FAKE_FRAME_HEADER_SIZE, &received_msg); if (result != TSI_OK) { impl->result = result; @@ -445,15 +501,15 @@ static tsi_result fake_handshaker_process_bytes_from_peer( tsi_fake_handshake_message_to_string(received_msg), tsi_fake_handshake_message_to_string(expected_msg)); } - if (tsi_tracing_enabled) { + if (GRPC_TRACER_ON(tsi_tracing_enabled)) { gpr_log(GPR_INFO, "%s received %s.", impl->is_client ? "Client" : "Server", tsi_fake_handshake_message_to_string(received_msg)); } - tsi_fake_frame_reset(&impl->incoming, 0 /* needs_draining */); + tsi_fake_frame_reset(&impl->incoming_frame, 0 /* needs_draining */); impl->needs_incoming_message = 0; if (impl->next_message_to_send == TSI_FAKE_HANDSHAKE_MESSAGE_MAX) { /* We're done. */ - if (tsi_tracing_enabled) { + if (GRPC_TRACER_ON(tsi_tracing_enabled)) { gpr_log(GPR_INFO, "%s is done.", impl->is_client ? "Client" : "Server"); } impl->result = TSI_OK; @@ -466,47 +522,96 @@ static tsi_result fake_handshaker_get_result(tsi_handshaker *self) { return impl->result; } -static tsi_result fake_handshaker_extract_peer(tsi_handshaker *self, - tsi_peer *peer) { - tsi_result result = tsi_construct_peer(1, peer); - if (result != TSI_OK) return result; - result = tsi_construct_string_peer_property_from_cstring( - TSI_CERTIFICATE_TYPE_PEER_PROPERTY, TSI_FAKE_CERTIFICATE_TYPE, - &peer->properties[0]); - if (result != TSI_OK) tsi_peer_destruct(peer); - return result; -} - -static tsi_result fake_handshaker_create_frame_protector( - tsi_handshaker *self, size_t *max_protected_frame_size, - tsi_frame_protector **protector) { - *protector = tsi_create_fake_protector(max_protected_frame_size); - if (*protector == NULL) return TSI_OUT_OF_RESOURCES; - return TSI_OK; -} - static void fake_handshaker_destroy(tsi_handshaker *self) { tsi_fake_handshaker *impl = (tsi_fake_handshaker *)self; - tsi_fake_frame_destruct(&impl->incoming); - tsi_fake_frame_destruct(&impl->outgoing); + tsi_fake_frame_destruct(&impl->incoming_frame); + tsi_fake_frame_destruct(&impl->outgoing_frame); + gpr_free(impl->outgoing_bytes_buffer); gpr_free(self); } +static tsi_result fake_handshaker_next( + tsi_handshaker *self, const unsigned char *received_bytes, + size_t received_bytes_size, const unsigned char **bytes_to_send, + size_t *bytes_to_send_size, tsi_handshaker_result **handshaker_result, + tsi_handshaker_on_next_done_cb cb, void *user_data) { + /* Sanity check the arguments. */ + if ((received_bytes_size > 0 && received_bytes == NULL) || + bytes_to_send == NULL || bytes_to_send_size == NULL || + handshaker_result == NULL) { + return TSI_INVALID_ARGUMENT; + } + tsi_fake_handshaker *handshaker = (tsi_fake_handshaker *)self; + tsi_result result = TSI_OK; + + /* Decode and process a handshake frame from the peer. */ + size_t consumed_bytes_size = received_bytes_size; + if (received_bytes_size > 0) { + result = fake_handshaker_process_bytes_from_peer(self, received_bytes, + &consumed_bytes_size); + if (result != TSI_OK) return result; + } + + /* Create a handshake message to send to the peer and encode it as a fake + * frame. */ + size_t offset = 0; + do { + size_t sent_bytes_size = handshaker->outgoing_bytes_buffer_size - offset; + result = fake_handshaker_get_bytes_to_send_to_peer( + self, handshaker->outgoing_bytes_buffer + offset, &sent_bytes_size); + offset += sent_bytes_size; + if (result == TSI_INCOMPLETE_DATA) { + handshaker->outgoing_bytes_buffer_size *= 2; + handshaker->outgoing_bytes_buffer = + gpr_realloc(handshaker->outgoing_bytes_buffer, + handshaker->outgoing_bytes_buffer_size); + } + } while (result == TSI_INCOMPLETE_DATA); + if (result != TSI_OK) return result; + *bytes_to_send = handshaker->outgoing_bytes_buffer; + *bytes_to_send_size = offset; + + /* Check if the handshake was completed. */ + if (fake_handshaker_get_result(self) == TSI_HANDSHAKE_IN_PROGRESS) { + *handshaker_result = NULL; + } else { + /* Calculate the unused bytes. */ + const unsigned char *unused_bytes = NULL; + size_t unused_bytes_size = received_bytes_size - consumed_bytes_size; + if (unused_bytes_size > 0) { + unused_bytes = received_bytes + consumed_bytes_size; + } + + /* Create a handshaker_result containing the unused bytes. */ + result = fake_handshaker_result_create(unused_bytes, unused_bytes_size, + handshaker_result); + if (result == TSI_OK) { + /* Indicate that the handshake has completed and that a handshaker_result + * has been created. */ + self->handshaker_result_created = true; + } + } + return result; +} + static const tsi_handshaker_vtable handshaker_vtable = { - fake_handshaker_get_bytes_to_send_to_peer, - fake_handshaker_process_bytes_from_peer, - fake_handshaker_get_result, - fake_handshaker_extract_peer, - fake_handshaker_create_frame_protector, + NULL, /* get_bytes_to_send_to_peer -- deprecated */ + NULL, /* process_bytes_from_peer -- deprecated */ + NULL, /* get_result -- deprecated */ + NULL, /* extract_peer -- deprecated */ + NULL, /* create_frame_protector -- deprecated */ fake_handshaker_destroy, + fake_handshaker_next, }; tsi_handshaker *tsi_create_fake_handshaker(int is_client) { - tsi_fake_handshaker *impl = gpr_malloc(sizeof(*impl)); - memset(impl, 0, sizeof(*impl)); + tsi_fake_handshaker *impl = gpr_zalloc(sizeof(*impl)); impl->base.vtable = &handshaker_vtable; impl->is_client = is_client; impl->result = TSI_HANDSHAKE_IN_PROGRESS; + impl->outgoing_bytes_buffer_size = + TSI_FAKE_HANDSHAKER_OUTGOING_BUFFER_INITIAL_SIZE; + impl->outgoing_bytes_buffer = gpr_malloc(impl->outgoing_bytes_buffer_size); if (is_client) { impl->needs_incoming_message = 0; impl->next_message_to_send = TSI_FAKE_CLIENT_INIT; @@ -517,10 +622,9 @@ tsi_handshaker *tsi_create_fake_handshaker(int is_client) { return &impl->base; } -tsi_frame_protector *tsi_create_fake_protector( +tsi_frame_protector *tsi_create_fake_frame_protector( size_t *max_protected_frame_size) { - tsi_fake_frame_protector *impl = gpr_malloc(sizeof(*impl)); - memset(impl, 0, sizeof(*impl)); + tsi_fake_frame_protector *impl = gpr_zalloc(sizeof(*impl)); impl->max_frame_size = (max_protected_frame_size == NULL) ? TSI_FAKE_DEFAULT_FRAME_SIZE : *max_protected_frame_size; diff --git a/Sources/CgRPC/src/core/tsi/fake_transport_security.h b/Sources/CgRPC/src/core/tsi/fake_transport_security.h new file mode 100644 index 000000000..934b3cbeb --- /dev/null +++ b/Sources/CgRPC/src/core/tsi/fake_transport_security.h @@ -0,0 +1,46 @@ +/* + * + * 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 GRPC_CORE_TSI_FAKE_TRANSPORT_SECURITY_H +#define GRPC_CORE_TSI_FAKE_TRANSPORT_SECURITY_H + +#include "src/core/tsi/transport_security_interface.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Value for the TSI_CERTIFICATE_TYPE_PEER_PROPERTY property for FAKE certs. */ +#define TSI_FAKE_CERTIFICATE_TYPE "FAKE" + +/* Creates a fake handshaker that will create a fake frame protector. + + No cryptography is performed in these objects. They just simulate handshake + messages going back and forth for the handshaker and do some framing on + cleartext data for the protector. */ +tsi_handshaker *tsi_create_fake_handshaker(int is_client); + +/* Creates a protector directly without going through the handshake phase. */ +tsi_frame_protector *tsi_create_fake_frame_protector( + size_t *max_protected_frame_size); + +#ifdef __cplusplus +} +#endif + +#endif /* GRPC_CORE_TSI_FAKE_TRANSPORT_SECURITY_H */ diff --git a/Sources/CgRPC/src/core/tsi/gts_transport_security.c b/Sources/CgRPC/src/core/tsi/gts_transport_security.c new file mode 100644 index 000000000..e2ac685e4 --- /dev/null +++ b/Sources/CgRPC/src/core/tsi/gts_transport_security.c @@ -0,0 +1,40 @@ +/* + * + * Copyright 2017 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 "src/core/tsi/gts_transport_security.h" + +#include + +static gts_shared_resource g_gts_resource; + +gts_shared_resource *gts_get_shared_resource(void) { return &g_gts_resource; } + +void grpc_tsi_gts_init() { + memset(&g_gts_resource, 0, sizeof(gts_shared_resource)); + gpr_mu_init(&g_gts_resource.mu); +} + +void grpc_tsi_gts_shutdown() { + gpr_mu_destroy(&g_gts_resource.mu); + if (g_gts_resource.cq == NULL) { + return; + } + grpc_completion_queue_destroy(g_gts_resource.cq); + grpc_channel_destroy(g_gts_resource.channel); + gpr_thd_join(g_gts_resource.thread_id); +} diff --git a/Sources/CgRPC/src/core/tsi/gts_transport_security.h b/Sources/CgRPC/src/core/tsi/gts_transport_security.h new file mode 100644 index 000000000..538e1030b --- /dev/null +++ b/Sources/CgRPC/src/core/tsi/gts_transport_security.h @@ -0,0 +1,37 @@ +/* + * + * Copyright 2017 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 GRPC_CORE_TSI_GTS_TRANSPORT_SECURITY_H +#define GRPC_CORE_TSI_GTS_TRANSPORT_SECURITY_H + +#include +#include +#include + +typedef struct gts_shared_resource { + gpr_thd_id thread_id; + grpc_channel *channel; + grpc_completion_queue *cq; + gpr_mu mu; +} gts_shared_resource; + +/* This method returns the address of gts_shared_resource object shared by all + * TSI handshakes. */ +gts_shared_resource *gts_get_shared_resource(void); + +#endif /* GRPC_CORE_TSI_GTS_TRANSPORT_SECURITY_H */ diff --git a/Sources/CgRPC/src/core/lib/tsi/ssl_transport_security.c b/Sources/CgRPC/src/core/tsi/ssl_transport_security.c similarity index 81% rename from Sources/CgRPC/src/core/lib/tsi/ssl_transport_security.c rename to Sources/CgRPC/src/core/tsi/ssl_transport_security.c index 366dca950..1fd65928f 100644 --- a/Sources/CgRPC/src/core/lib/tsi/ssl_transport_security.c +++ b/Sources/CgRPC/src/core/tsi/ssl_transport_security.c @@ -1,37 +1,22 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 "src/core/lib/tsi/ssl_transport_security.h" +#include "src/core/tsi/ssl_transport_security.h" #include @@ -45,6 +30,7 @@ #include #else #include +#include #endif #include @@ -60,8 +46,8 @@ #include #include -#include "src/core/lib/tsi/ssl_types.h" -#include "src/core/lib/tsi/transport_security.h" +#include "src/core/tsi/ssl_types.h" +#include "src/core/tsi/transport_security.h" /* --- Constants. ---*/ @@ -81,23 +67,13 @@ /* --- Structure definitions. ---*/ -struct tsi_ssl_handshaker_factory { - tsi_result (*create_handshaker)(tsi_ssl_handshaker_factory *self, - const char *server_name_indication, - tsi_handshaker **handshaker); - void (*destroy)(tsi_ssl_handshaker_factory *self); -}; - -typedef struct { - tsi_ssl_handshaker_factory base; +struct tsi_ssl_client_handshaker_factory { SSL_CTX *ssl_context; unsigned char *alpn_protocol_list; size_t alpn_protocol_list_length; -} tsi_ssl_client_handshaker_factory; - -typedef struct { - tsi_ssl_handshaker_factory base; +}; +struct tsi_ssl_server_handshaker_factory { /* Several contexts to support SNI. The tsi_peer array contains the subject names of the server certificates associated with the contexts at the same index. */ @@ -106,7 +82,7 @@ typedef struct { size_t ssl_context_count; unsigned char *alpn_protocol_list; size_t alpn_protocol_list_length; -} tsi_ssl_server_handshaker_factory; +}; typedef struct { tsi_handshaker base; @@ -189,7 +165,7 @@ static const char *ssl_error_string(int error) { /* TODO(jboeuf): Remove when we are past the debugging phase with this code. */ static void ssl_log_where_info(const SSL *ssl, int where, int flag, const char *msg) { - if ((where & flag) && tsi_tracing_enabled) { + if ((where & flag) && GRPC_TRACER_ON(tsi_tracing_enabled)) { gpr_log(GPR_INFO, "%20.20s - %30.30s - %5.10s", msg, SSL_state_string_long(ssl), SSL_state_string(ssl)); } @@ -435,15 +411,11 @@ static tsi_result do_ssl_read(SSL *ssl, unsigned char *unprotected_bytes, GPR_ASSERT(*unprotected_bytes_size <= INT_MAX); read_from_ssl = SSL_read(ssl, unprotected_bytes, (int)*unprotected_bytes_size); - if (read_from_ssl == 0) { - gpr_log(GPR_ERROR, "SSL_read returned 0 unexpectedly."); - return TSI_INTERNAL_ERROR; - } - if (read_from_ssl < 0) { + if (read_from_ssl <= 0) { read_from_ssl = SSL_get_error(ssl, read_from_ssl); switch (read_from_ssl) { - case SSL_ERROR_WANT_READ: - /* We need more data to finish the frame. */ + case SSL_ERROR_ZERO_RETURN: /* Received a close_notify alert. */ + case SSL_ERROR_WANT_READ: /* We need more data to finish the frame. */ *unprotected_bytes_size = 0; return TSI_OK; case SSL_ERROR_WANT_WRITE: @@ -488,9 +460,9 @@ static tsi_result do_ssl_write(SSL *ssl, unsigned char *unprotected_bytes, } /* Loads an in-memory PEM certificate chain into the SSL context. */ -static tsi_result ssl_ctx_use_certificate_chain( - SSL_CTX *context, const unsigned char *pem_cert_chain, - size_t pem_cert_chain_size) { +static tsi_result ssl_ctx_use_certificate_chain(SSL_CTX *context, + const char *pem_cert_chain, + size_t pem_cert_chain_size) { tsi_result result = TSI_OK; X509 *certificate = NULL; BIO *pem; @@ -531,8 +503,7 @@ static tsi_result ssl_ctx_use_certificate_chain( } /* Loads an in-memory PEM private key into the SSL context. */ -static tsi_result ssl_ctx_use_private_key(SSL_CTX *context, - const unsigned char *pem_key, +static tsi_result ssl_ctx_use_private_key(SSL_CTX *context, const char *pem_key, size_t pem_key_size) { tsi_result result = TSI_OK; EVP_PKEY *private_key = NULL; @@ -558,9 +529,11 @@ static tsi_result ssl_ctx_use_private_key(SSL_CTX *context, /* Loads in-memory PEM verification certs into the SSL context and optionally returns the verification cert names (root_names can be NULL). */ -static tsi_result ssl_ctx_load_verification_certs( - SSL_CTX *context, const unsigned char *pem_roots, size_t pem_roots_size, - STACK_OF(X509_NAME) * *root_names) { +static tsi_result ssl_ctx_load_verification_certs(SSL_CTX *context, + const char *pem_roots, + size_t pem_roots_size, + STACK_OF(X509_NAME) * + *root_names) { tsi_result result = TSI_OK; size_t num_roots = 0; X509 *root = NULL; @@ -627,24 +600,25 @@ static tsi_result ssl_ctx_load_verification_certs( /* Populates the SSL context with a private key and a cert chain, and sets the cipher list and the ephemeral ECDH key. */ static tsi_result populate_ssl_context( - SSL_CTX *context, const unsigned char *pem_private_key, - size_t pem_private_key_size, const unsigned char *pem_certificate_chain, - size_t pem_certificate_chain_size, const char *cipher_list) { + SSL_CTX *context, const tsi_ssl_pem_key_cert_pair *key_cert_pair, + const char *cipher_list) { tsi_result result = TSI_OK; - if (pem_certificate_chain != NULL) { - result = ssl_ctx_use_certificate_chain(context, pem_certificate_chain, - pem_certificate_chain_size); - if (result != TSI_OK) { - gpr_log(GPR_ERROR, "Invalid cert chain file."); - return result; + if (key_cert_pair != NULL) { + if (key_cert_pair->cert_chain != NULL) { + result = ssl_ctx_use_certificate_chain(context, key_cert_pair->cert_chain, + strlen(key_cert_pair->cert_chain)); + if (result != TSI_OK) { + gpr_log(GPR_ERROR, "Invalid cert chain file."); + return result; + } } - } - if (pem_private_key != NULL) { - result = - ssl_ctx_use_private_key(context, pem_private_key, pem_private_key_size); - if (result != TSI_OK || !SSL_CTX_check_private_key(context)) { - gpr_log(GPR_ERROR, "Invalid private key."); - return result != TSI_OK ? result : TSI_INVALID_ARGUMENT; + if (key_cert_pair->private_key != NULL) { + result = ssl_ctx_use_private_key(context, key_cert_pair->private_key, + strlen(key_cert_pair->private_key)); + if (result != TSI_OK || !SSL_CTX_check_private_key(context)) { + gpr_log(GPR_ERROR, "Invalid private key."); + return result != TSI_OK ? result : TSI_INVALID_ARGUMENT; + } } } if ((cipher_list != NULL) && !SSL_CTX_set_cipher_list(context, cipher_list)) { @@ -665,13 +639,12 @@ static tsi_result populate_ssl_context( } /* Extracts the CN and the SANs from an X509 cert as a peer object. */ -static tsi_result extract_x509_subject_names_from_pem_cert( - const unsigned char *pem_cert, size_t pem_cert_size, tsi_peer *peer) { +static tsi_result extract_x509_subject_names_from_pem_cert(const char *pem_cert, + tsi_peer *peer) { tsi_result result = TSI_OK; X509 *cert = NULL; BIO *pem; - GPR_ASSERT(pem_cert_size <= INT_MAX); - pem = BIO_new_mem_buf((void *)pem_cert, (int)pem_cert_size); + pem = BIO_new_mem_buf((void *)pem_cert, (int)strlen(pem_cert)); if (pem == NULL) return TSI_OUT_OF_RESOURCES; cert = PEM_read_bio_X509(pem, NULL, NULL, ""); @@ -688,8 +661,7 @@ static tsi_result extract_x509_subject_names_from_pem_cert( /* Builds the alpn protocol name list according to rfc 7301. */ static tsi_result build_alpn_protocol_name_list( - const unsigned char **alpn_protocols, - const unsigned char *alpn_protocols_lengths, uint16_t num_alpn_protocols, + const char **alpn_protocols, uint16_t num_alpn_protocols, unsigned char **protocol_name_list, size_t *protocol_name_list_length) { uint16_t i; unsigned char *current; @@ -697,19 +669,21 @@ static tsi_result build_alpn_protocol_name_list( *protocol_name_list_length = 0; if (num_alpn_protocols == 0) return TSI_INVALID_ARGUMENT; for (i = 0; i < num_alpn_protocols; i++) { - if (alpn_protocols_lengths[i] == 0) { - gpr_log(GPR_ERROR, "Invalid 0-length protocol name."); + size_t length = alpn_protocols[i] == NULL ? 0 : strlen(alpn_protocols[i]); + if (length == 0 || length > 255) { + gpr_log(GPR_ERROR, "Invalid protocol name length: %d.", (int)length); return TSI_INVALID_ARGUMENT; } - *protocol_name_list_length += (size_t)alpn_protocols_lengths[i] + 1; + *protocol_name_list_length += length + 1; } *protocol_name_list = gpr_malloc(*protocol_name_list_length); if (*protocol_name_list == NULL) return TSI_OUT_OF_RESOURCES; current = *protocol_name_list; for (i = 0; i < num_alpn_protocols; i++) { - *(current++) = alpn_protocols_lengths[i]; - memcpy(current, alpn_protocols[i], alpn_protocols_lengths[i]); - current += alpn_protocols_lengths[i]; + size_t length = strlen(alpn_protocols[i]); + *(current++) = (uint8_t)length; /* max checked above. */ + memcpy(current, alpn_protocols[i], length); + current += length; } /* Safety check. */ if ((current < *protocol_name_list) || @@ -976,9 +950,7 @@ static tsi_result ssl_handshaker_extract_peer(tsi_handshaker *self, if (alpn_selected != NULL) { size_t i; tsi_peer_property *new_properties = - gpr_malloc(sizeof(*new_properties) * (peer->property_count + 1)); - memset(new_properties, 0, - sizeof(*new_properties) * (peer->property_count + 1)); + gpr_zalloc(sizeof(*new_properties) * (peer->property_count + 1)); for (i = 0; i < peer->property_count; i++) { new_properties[i] = peer->properties[i]; } @@ -1002,8 +974,7 @@ static tsi_result ssl_handshaker_create_frame_protector( size_t actual_max_output_protected_frame_size = TSI_SSL_MAX_PROTECTED_FRAME_SIZE_UPPER_BOUND; tsi_ssl_handshaker *impl = (tsi_ssl_handshaker *)self; - tsi_ssl_frame_protector *protector_impl = gpr_malloc(sizeof(*protector_impl)); - memset(protector_impl, 0, sizeof(*protector_impl)); + tsi_ssl_frame_protector *protector_impl = gpr_zalloc(sizeof(*protector_impl)); if (max_output_protected_frame_size != NULL) { if (*max_output_protected_frame_size > @@ -1052,22 +1023,11 @@ static const tsi_handshaker_vtable handshaker_vtable = { ssl_handshaker_extract_peer, ssl_handshaker_create_frame_protector, ssl_handshaker_destroy, + NULL, }; /* --- tsi_ssl_handshaker_factory common methods. --- */ -tsi_result tsi_ssl_handshaker_factory_create_handshaker( - tsi_ssl_handshaker_factory *self, const char *server_name_indication, - tsi_handshaker **handshaker) { - if (self == NULL || handshaker == NULL) return TSI_INVALID_ARGUMENT; - return self->create_handshaker(self, server_name_indication, handshaker); -} - -void tsi_ssl_handshaker_factory_destroy(tsi_ssl_handshaker_factory *self) { - if (self == NULL) return; - self->destroy(self); -} - static tsi_result create_tsi_ssl_handshaker(SSL_CTX *ctx, int is_client, const char *server_name_indication, tsi_handshaker **handshaker) { @@ -1119,8 +1079,7 @@ static tsi_result create_tsi_ssl_handshaker(SSL_CTX *ctx, int is_client, SSL_set_accept_state(ssl); } - impl = gpr_malloc(sizeof(*impl)); - memset(impl, 0, sizeof(*impl)); + impl = gpr_zalloc(sizeof(*impl)); impl->ssl = ssl; impl->into_ssl = into_ssl; impl->from_ssl = from_ssl; @@ -1156,24 +1115,20 @@ static int select_protocol_list(const unsigned char **out, return SSL_TLSEXT_ERR_NOACK; } -/* --- tsi_ssl__client_handshaker_factory methods implementation. --- */ +/* --- tsi_ssl_client_handshaker_factory methods implementation. --- */ -static tsi_result ssl_client_handshaker_factory_create_handshaker( - tsi_ssl_handshaker_factory *self, const char *server_name_indication, +tsi_result tsi_ssl_client_handshaker_factory_create_handshaker( + tsi_ssl_client_handshaker_factory *self, const char *server_name_indication, tsi_handshaker **handshaker) { - tsi_ssl_client_handshaker_factory *impl = - (tsi_ssl_client_handshaker_factory *)self; - return create_tsi_ssl_handshaker(impl->ssl_context, 1, server_name_indication, + return create_tsi_ssl_handshaker(self->ssl_context, 1, server_name_indication, handshaker); } -static void ssl_client_handshaker_factory_destroy( - tsi_ssl_handshaker_factory *self) { - tsi_ssl_client_handshaker_factory *impl = - (tsi_ssl_client_handshaker_factory *)self; - if (impl->ssl_context != NULL) SSL_CTX_free(impl->ssl_context); - if (impl->alpn_protocol_list != NULL) gpr_free(impl->alpn_protocol_list); - gpr_free(impl); +void tsi_ssl_client_handshaker_factory_destroy( + tsi_ssl_client_handshaker_factory *self) { + if (self->ssl_context != NULL) SSL_CTX_free(self->ssl_context); + if (self->alpn_protocol_list != NULL) gpr_free(self->alpn_protocol_list); + gpr_free(self); } static int client_handshaker_factory_npn_callback(SSL *ssl, unsigned char **out, @@ -1190,36 +1145,29 @@ static int client_handshaker_factory_npn_callback(SSL *ssl, unsigned char **out, /* --- tsi_ssl_server_handshaker_factory methods implementation. --- */ -static tsi_result ssl_server_handshaker_factory_create_handshaker( - tsi_ssl_handshaker_factory *self, const char *server_name_indication, - tsi_handshaker **handshaker) { - tsi_ssl_server_handshaker_factory *impl = - (tsi_ssl_server_handshaker_factory *)self; - if (impl->ssl_context_count == 0 || server_name_indication != NULL) { - return TSI_INVALID_ARGUMENT; - } +tsi_result tsi_ssl_server_handshaker_factory_create_handshaker( + tsi_ssl_server_handshaker_factory *self, tsi_handshaker **handshaker) { + if (self->ssl_context_count == 0) return TSI_INVALID_ARGUMENT; /* Create the handshaker with the first context. We will switch if needed because of SNI in ssl_server_handshaker_factory_servername_callback. */ - return create_tsi_ssl_handshaker(impl->ssl_contexts[0], 0, NULL, handshaker); + return create_tsi_ssl_handshaker(self->ssl_contexts[0], 0, NULL, handshaker); } -static void ssl_server_handshaker_factory_destroy( - tsi_ssl_handshaker_factory *self) { - tsi_ssl_server_handshaker_factory *impl = - (tsi_ssl_server_handshaker_factory *)self; +void tsi_ssl_server_handshaker_factory_destroy( + tsi_ssl_server_handshaker_factory *self) { size_t i; - for (i = 0; i < impl->ssl_context_count; i++) { - if (impl->ssl_contexts[i] != NULL) { - SSL_CTX_free(impl->ssl_contexts[i]); - tsi_peer_destruct(&impl->ssl_context_x509_subject_names[i]); + for (i = 0; i < self->ssl_context_count; i++) { + if (self->ssl_contexts[i] != NULL) { + SSL_CTX_free(self->ssl_contexts[i]); + tsi_peer_destruct(&self->ssl_context_x509_subject_names[i]); } } - if (impl->ssl_contexts != NULL) gpr_free(impl->ssl_contexts); - if (impl->ssl_context_x509_subject_names != NULL) { - gpr_free(impl->ssl_context_x509_subject_names); + if (self->ssl_contexts != NULL) gpr_free(self->ssl_contexts); + if (self->ssl_context_x509_subject_names != NULL) { + gpr_free(self->ssl_context_x509_subject_names); } - if (impl->alpn_protocol_list != NULL) gpr_free(impl->alpn_protocol_list); - gpr_free(impl); + if (self->alpn_protocol_list != NULL) gpr_free(self->alpn_protocol_list); + gpr_free(self); } static int does_entry_match_name(const char *entry, size_t entry_length, @@ -1316,12 +1264,10 @@ static int server_handshaker_factory_npn_advertised_callback( /* --- tsi_ssl_handshaker_factory constructors. --- */ tsi_result tsi_create_ssl_client_handshaker_factory( - const unsigned char *pem_private_key, size_t pem_private_key_size, - const unsigned char *pem_cert_chain, size_t pem_cert_chain_size, - const unsigned char *pem_root_certs, size_t pem_root_certs_size, - const char *cipher_list, const unsigned char **alpn_protocols, - const unsigned char *alpn_protocols_lengths, uint16_t num_alpn_protocols, - tsi_ssl_handshaker_factory **factory) { + const tsi_ssl_pem_key_cert_pair *pem_key_cert_pair, + const char *pem_root_certs, const char *cipher_suites, + const char **alpn_protocols, uint16_t num_alpn_protocols, + tsi_ssl_client_handshaker_factory **factory) { SSL_CTX *ssl_context = NULL; tsi_ssl_client_handshaker_factory *impl = NULL; tsi_result result = TSI_OK; @@ -1338,26 +1284,24 @@ tsi_result tsi_create_ssl_client_handshaker_factory( return TSI_INVALID_ARGUMENT; } - impl = gpr_malloc(sizeof(*impl)); - memset(impl, 0, sizeof(*impl)); + impl = gpr_zalloc(sizeof(*impl)); impl->ssl_context = ssl_context; do { result = - populate_ssl_context(ssl_context, pem_private_key, pem_private_key_size, - pem_cert_chain, pem_cert_chain_size, cipher_list); + populate_ssl_context(ssl_context, pem_key_cert_pair, cipher_suites); if (result != TSI_OK) break; result = ssl_ctx_load_verification_certs(ssl_context, pem_root_certs, - pem_root_certs_size, NULL); + strlen(pem_root_certs), NULL); if (result != TSI_OK) { gpr_log(GPR_ERROR, "Cannot load server root certificates."); break; } if (num_alpn_protocols != 0) { - result = build_alpn_protocol_name_list( - alpn_protocols, alpn_protocols_lengths, num_alpn_protocols, - &impl->alpn_protocol_list, &impl->alpn_protocol_list_length); + result = build_alpn_protocol_name_list(alpn_protocols, num_alpn_protocols, + &impl->alpn_protocol_list, + &impl->alpn_protocol_list_length); if (result != TSI_OK) { gpr_log(GPR_ERROR, "Building alpn list failed with error %s.", tsi_result_to_string(result)); @@ -1378,48 +1322,35 @@ tsi_result tsi_create_ssl_client_handshaker_factory( } } while (0); if (result != TSI_OK) { - ssl_client_handshaker_factory_destroy(&impl->base); + tsi_ssl_client_handshaker_factory_destroy(impl); return result; } SSL_CTX_set_verify(ssl_context, SSL_VERIFY_PEER, NULL); /* TODO(jboeuf): Add revocation verification. */ - impl->base.create_handshaker = - ssl_client_handshaker_factory_create_handshaker; - impl->base.destroy = ssl_client_handshaker_factory_destroy; - *factory = &impl->base; + *factory = impl; return TSI_OK; } tsi_result tsi_create_ssl_server_handshaker_factory( - const unsigned char **pem_private_keys, - const size_t *pem_private_keys_sizes, const unsigned char **pem_cert_chains, - const size_t *pem_cert_chains_sizes, size_t key_cert_pair_count, - const unsigned char *pem_client_root_certs, - size_t pem_client_root_certs_size, int force_client_auth, - const char *cipher_list, const unsigned char **alpn_protocols, - const unsigned char *alpn_protocols_lengths, uint16_t num_alpn_protocols, - tsi_ssl_handshaker_factory **factory) { + const tsi_ssl_pem_key_cert_pair *pem_key_cert_pairs, + size_t num_key_cert_pairs, const char *pem_client_root_certs, + int force_client_auth, const char *cipher_suites, + const char **alpn_protocols, uint16_t num_alpn_protocols, + tsi_ssl_server_handshaker_factory **factory) { return tsi_create_ssl_server_handshaker_factory_ex( - pem_private_keys, pem_private_keys_sizes, pem_cert_chains, - pem_cert_chains_sizes, key_cert_pair_count, pem_client_root_certs, - pem_client_root_certs_size, + pem_key_cert_pairs, num_key_cert_pairs, pem_client_root_certs, force_client_auth ? TSI_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY : TSI_DONT_REQUEST_CLIENT_CERTIFICATE, - cipher_list, alpn_protocols, alpn_protocols_lengths, num_alpn_protocols, - factory); + cipher_suites, alpn_protocols, num_alpn_protocols, factory); } tsi_result tsi_create_ssl_server_handshaker_factory_ex( - const unsigned char **pem_private_keys, - const size_t *pem_private_keys_sizes, const unsigned char **pem_cert_chains, - const size_t *pem_cert_chains_sizes, size_t key_cert_pair_count, - const unsigned char *pem_client_root_certs, - size_t pem_client_root_certs_size, + const tsi_ssl_pem_key_cert_pair *pem_key_cert_pairs, + size_t num_key_cert_pairs, const char *pem_client_root_certs, tsi_client_certificate_request_type client_certificate_request, - const char *cipher_list, const unsigned char **alpn_protocols, - const unsigned char *alpn_protocols_lengths, uint16_t num_alpn_protocols, - tsi_ssl_handshaker_factory **factory) { + const char *cipher_suites, const char **alpn_protocols, + uint16_t num_alpn_protocols, tsi_ssl_server_handshaker_factory **factory) { tsi_ssl_server_handshaker_factory *impl = NULL; tsi_result result = TSI_OK; size_t i = 0; @@ -1428,40 +1359,32 @@ tsi_result tsi_create_ssl_server_handshaker_factory_ex( if (factory == NULL) return TSI_INVALID_ARGUMENT; *factory = NULL; - if (key_cert_pair_count == 0 || pem_private_keys == NULL || - pem_cert_chains == NULL) { + if (num_key_cert_pairs == 0 || pem_key_cert_pairs == NULL) { return TSI_INVALID_ARGUMENT; } - impl = gpr_malloc(sizeof(*impl)); - memset(impl, 0, sizeof(*impl)); - impl->base.create_handshaker = - ssl_server_handshaker_factory_create_handshaker; - impl->base.destroy = ssl_server_handshaker_factory_destroy; - impl->ssl_contexts = gpr_malloc(key_cert_pair_count * sizeof(SSL_CTX *)); - memset(impl->ssl_contexts, 0, key_cert_pair_count * sizeof(SSL_CTX *)); + impl = gpr_zalloc(sizeof(*impl)); + impl->ssl_contexts = gpr_zalloc(num_key_cert_pairs * sizeof(SSL_CTX *)); impl->ssl_context_x509_subject_names = - gpr_malloc(key_cert_pair_count * sizeof(tsi_peer)); - memset(impl->ssl_context_x509_subject_names, 0, - key_cert_pair_count * sizeof(tsi_peer)); + gpr_zalloc(num_key_cert_pairs * sizeof(tsi_peer)); if (impl->ssl_contexts == NULL || impl->ssl_context_x509_subject_names == NULL) { - tsi_ssl_handshaker_factory_destroy(&impl->base); + tsi_ssl_server_handshaker_factory_destroy(impl); return TSI_OUT_OF_RESOURCES; } - impl->ssl_context_count = key_cert_pair_count; + impl->ssl_context_count = num_key_cert_pairs; if (num_alpn_protocols > 0) { - result = build_alpn_protocol_name_list( - alpn_protocols, alpn_protocols_lengths, num_alpn_protocols, - &impl->alpn_protocol_list, &impl->alpn_protocol_list_length); + result = build_alpn_protocol_name_list(alpn_protocols, num_alpn_protocols, + &impl->alpn_protocol_list, + &impl->alpn_protocol_list_length); if (result != TSI_OK) { - tsi_ssl_handshaker_factory_destroy(&impl->base); + tsi_ssl_server_handshaker_factory_destroy(impl); return result; } } - for (i = 0; i < key_cert_pair_count; i++) { + for (i = 0; i < num_key_cert_pairs; i++) { do { impl->ssl_contexts[i] = SSL_CTX_new(TLSv1_2_method()); if (impl->ssl_contexts[i] == NULL) { @@ -1469,16 +1392,15 @@ tsi_result tsi_create_ssl_server_handshaker_factory_ex( result = TSI_OUT_OF_RESOURCES; break; } - result = populate_ssl_context( - impl->ssl_contexts[i], pem_private_keys[i], pem_private_keys_sizes[i], - pem_cert_chains[i], pem_cert_chains_sizes[i], cipher_list); + result = populate_ssl_context(impl->ssl_contexts[i], + &pem_key_cert_pairs[i], cipher_suites); if (result != TSI_OK) break; if (pem_client_root_certs != NULL) { STACK_OF(X509_NAME) *root_names = NULL; result = ssl_ctx_load_verification_certs( impl->ssl_contexts[i], pem_client_root_certs, - pem_client_root_certs_size, &root_names); + strlen(pem_client_root_certs), &root_names); if (result != TSI_OK) { gpr_log(GPR_ERROR, "Invalid verification certs."); break; @@ -1511,7 +1433,7 @@ tsi_result tsi_create_ssl_server_handshaker_factory_ex( } result = extract_x509_subject_names_from_pem_cert( - pem_cert_chains[i], pem_cert_chains_sizes[i], + pem_key_cert_pairs[i].cert_chain, &impl->ssl_context_x509_subject_names[i]); if (result != TSI_OK) break; @@ -1529,11 +1451,11 @@ tsi_result tsi_create_ssl_server_handshaker_factory_ex( } while (0); if (result != TSI_OK) { - tsi_ssl_handshaker_factory_destroy(&impl->base); + tsi_ssl_server_handshaker_factory_destroy(impl); return result; } } - *factory = &impl->base; + *factory = impl; return TSI_OK; } diff --git a/Sources/CgRPC/src/core/tsi/ssl_transport_security.h b/Sources/CgRPC/src/core/tsi/ssl_transport_security.h new file mode 100644 index 000000000..177599930 --- /dev/null +++ b/Sources/CgRPC/src/core/tsi/ssl_transport_security.h @@ -0,0 +1,177 @@ +/* + * + * 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 GRPC_CORE_TSI_SSL_TRANSPORT_SECURITY_H +#define GRPC_CORE_TSI_SSL_TRANSPORT_SECURITY_H + +#include "src/core/tsi/transport_security_interface.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Value for the TSI_CERTIFICATE_TYPE_PEER_PROPERTY property for X509 certs. */ +#define TSI_X509_CERTIFICATE_TYPE "X509" + +/* This property is of type TSI_PEER_PROPERTY_STRING. */ +#define TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY "x509_subject_common_name" +#define TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY \ + "x509_subject_alternative_name" + +#define TSI_X509_PEM_CERT_PROPERTY "x509_pem_cert" + +#define TSI_SSL_ALPN_SELECTED_PROTOCOL "ssl_alpn_selected_protocol" + +/* --- tsi_ssl_client_handshaker_factory object --- + + This object creates a client tsi_handshaker objects implemented in terms of + the TLS 1.2 specificiation. */ + +typedef struct tsi_ssl_client_handshaker_factory + tsi_ssl_client_handshaker_factory; + +/* Object that holds a private key / certificate chain pair in PEM format. */ +typedef struct { + /* private_key is the NULL-terminated string containing the PEM encoding of + the client's private key. */ + const char *private_key; + + /* cert_chain is the NULL-terminated string containing the PEM encoding of + the client's certificate chain. */ + const char *cert_chain; +} tsi_ssl_pem_key_cert_pair; + +/* Creates a client handshaker factory. + - pem_key_cert_pair is a pointer to the object containing client's private + key and certificate chain. This parameter can be NULL if the client does + not have such a key/cert pair. + - pem_roots_cert is the NULL-terminated string containing the PEM encoding of + the client root certificates. This parameter may be NULL if the server does + not want the client to be authenticated with SSL. + - cipher_suites contains an optional list of the ciphers that the client + supports. The format of this string is described in: + https://www.openssl.org/docs/apps/ciphers.html. + This parameter can be set to NULL to use the default set of ciphers. + TODO(jboeuf): Revisit the format of this parameter. + - alpn_protocols is an array containing the NULL terminated protocol names + that the handshakers created with this factory support. This parameter can + be NULL. + - num_alpn_protocols is the number of alpn protocols and associated lengths + specified. If this parameter is 0, the other alpn parameters must be NULL. + - factory is the address of the factory pointer to be created. + + - This method returns TSI_OK on success or TSI_INVALID_PARAMETER in the case + where a parameter is invalid. */ +tsi_result tsi_create_ssl_client_handshaker_factory( + const tsi_ssl_pem_key_cert_pair *pem_key_cert_pair, + const char *pem_root_certs, const char *cipher_suites, + const char **alpn_protocols, uint16_t num_alpn_protocols, + tsi_ssl_client_handshaker_factory **factory); + +/* Creates a client handshaker. + - self is the factory from which the handshaker will be created. + - server_name_indication indicates the name of the server the client is + trying to connect to which will be relayed to the server using the SNI + extension. + - handshaker is the address of the handshaker pointer to be created. + + - This method returns TSI_OK on success or TSI_INVALID_PARAMETER in the case + where a parameter is invalid. */ +tsi_result tsi_ssl_client_handshaker_factory_create_handshaker( + tsi_ssl_client_handshaker_factory *self, const char *server_name_indication, + tsi_handshaker **handshaker); + +/* Destroys the handshaker factory. WARNING: it is unsafe to destroy a factory + while handshakers created with this factory are still in use. */ +void tsi_ssl_client_handshaker_factory_destroy( + tsi_ssl_client_handshaker_factory *self); + +/* --- tsi_ssl_server_handshaker_factory object --- + + This object creates a client tsi_handshaker objects implemented in terms of + the TLS 1.2 specificiation. */ + +typedef struct tsi_ssl_server_handshaker_factory + tsi_ssl_server_handshaker_factory; + +/* Creates a server handshaker factory. + - pem_key_cert_pairs is an array private key / certificate chains of the + server. + - num_key_cert_pairs is the number of items in the pem_key_cert_pairs array. + - pem_root_certs is the NULL-terminated string containing the PEM encoding + of the server root certificates. + - cipher_suites contains an optional list of the ciphers that the server + supports. The format of this string is described in: + https://www.openssl.org/docs/apps/ciphers.html. + This parameter can be set to NULL to use the default set of ciphers. + TODO(jboeuf): Revisit the format of this parameter. + - alpn_protocols is an array containing the NULL terminated protocol names + that the handshakers created with this factory support. This parameter can + be NULL. + - num_alpn_protocols is the number of alpn protocols and associated lengths + specified. If this parameter is 0, the other alpn parameters must be NULL. + - factory is the address of the factory pointer to be created. + + - This method returns TSI_OK on success or TSI_INVALID_PARAMETER in the case + where a parameter is invalid. */ +tsi_result tsi_create_ssl_server_handshaker_factory( + const tsi_ssl_pem_key_cert_pair *pem_key_cert_pairs, + size_t num_key_cert_pairs, const char *pem_client_root_certs, + int force_client_auth, const char *cipher_suites, + const char **alpn_protocols, uint16_t num_alpn_protocols, + tsi_ssl_server_handshaker_factory **factory); + +/* Same as tsi_create_ssl_server_handshaker_factory method except uses + tsi_client_certificate_request_type to support more ways to handle client + certificate authentication. + - client_certificate_request, if set to non-zero will force the client to + authenticate with an SSL cert. Note that this option is ignored if + pem_client_root_certs is NULL or pem_client_roots_certs_size is 0 */ +tsi_result tsi_create_ssl_server_handshaker_factory_ex( + const tsi_ssl_pem_key_cert_pair *pem_key_cert_pairs, + size_t num_key_cert_pairs, const char *pem_client_root_certs, + tsi_client_certificate_request_type client_certificate_request, + const char *cipher_suites, const char **alpn_protocols, + uint16_t num_alpn_protocols, tsi_ssl_server_handshaker_factory **factory); + +/* Creates a server handshaker. + - self is the factory from which the handshaker will be created. + - handshaker is the address of the handshaker pointer to be created. + + - This method returns TSI_OK on success or TSI_INVALID_PARAMETER in the case + where a parameter is invalid. */ +tsi_result tsi_ssl_server_handshaker_factory_create_handshaker( + tsi_ssl_server_handshaker_factory *self, tsi_handshaker **handshaker); + +/* Destroys the handshaker factory. WARNING: it is unsafe to destroy a factory + while handshakers created with this factory are still in use. */ +void tsi_ssl_server_handshaker_factory_destroy( + tsi_ssl_server_handshaker_factory *self); + +/* Util that checks that an ssl peer matches a specific name. + Still TODO(jboeuf): + - handle mixed case. + - handle %encoded chars. + - handle public suffix wildchar more strictly (e.g. *.co.uk) */ +int tsi_ssl_peer_matches_name(const tsi_peer *peer, const char *name); + +#ifdef __cplusplus +} +#endif + +#endif /* GRPC_CORE_TSI_SSL_TRANSPORT_SECURITY_H */ diff --git a/Sources/CgRPC/src/core/tsi/ssl_types.h b/Sources/CgRPC/src/core/tsi/ssl_types.h new file mode 100644 index 000000000..378864335 --- /dev/null +++ b/Sources/CgRPC/src/core/tsi/ssl_types.h @@ -0,0 +1,40 @@ +/* + * + * 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 GRPC_CORE_TSI_SSL_TYPES_H +#define GRPC_CORE_TSI_SSL_TYPES_H + +/* A collection of macros to cast between various integer types that are + * used differently between BoringSSL and OpenSSL: + * TSI_INT_AS_SIZE(x): convert 'int x' to a length parameter for an OpenSSL + * function + * TSI_SIZE_AS_SIZE(x): convert 'size_t x' to a length parameter for an OpenSSL + * function + */ + +#include + +#ifdef OPENSSL_IS_BORINGSSL +#define TSI_INT_AS_SIZE(x) ((size_t)(x)) +#define TSI_SIZE_AS_SIZE(x) (x) +#else +#define TSI_INT_AS_SIZE(x) (x) +#define TSI_SIZE_AS_SIZE(x) ((int)(x)) +#endif + +#endif /* GRPC_CORE_TSI_SSL_TYPES_H */ diff --git a/Sources/CgRPC/src/core/lib/tsi/transport_security.c b/Sources/CgRPC/src/core/tsi/transport_security.c similarity index 62% rename from Sources/CgRPC/src/core/lib/tsi/transport_security.c rename to Sources/CgRPC/src/core/tsi/transport_security.c index 830cf0958..76213072a 100644 --- a/Sources/CgRPC/src/core/lib/tsi/transport_security.c +++ b/Sources/CgRPC/src/core/tsi/transport_security.c @@ -1,37 +1,22 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 "src/core/lib/tsi/transport_security.h" +#include "src/core/tsi/transport_security.h" #include #include @@ -41,7 +26,7 @@ /* --- Tracing. --- */ -int tsi_tracing_enabled = 0; +grpc_tracer_flag tsi_tracing_enabled = GRPC_TRACER_INITIALIZER(false, "tsi"); /* --- tsi_result common implementation. --- */ @@ -73,6 +58,8 @@ const char *tsi_result_to_string(tsi_result result) { return "TSI_HANDSHAKE_IN_PROGRESS"; case TSI_OUT_OF_RESOURCES: return "TSI_OUT_OF_RESOURCES"; + case TSI_ASYNC: + return "TSI_ASYNC"; default: return "UNKNOWN"; } @@ -87,11 +74,12 @@ tsi_result tsi_frame_protector_protect(tsi_frame_protector *self, size_t *unprotected_bytes_size, unsigned char *protected_output_frames, size_t *protected_output_frames_size) { - if (self == NULL || unprotected_bytes == NULL || + if (self == NULL || self->vtable == NULL || unprotected_bytes == NULL || unprotected_bytes_size == NULL || protected_output_frames == NULL || protected_output_frames_size == NULL) { return TSI_INVALID_ARGUMENT; } + if (self->vtable->protect == NULL) return TSI_UNIMPLEMENTED; return self->vtable->protect(self, unprotected_bytes, unprotected_bytes_size, protected_output_frames, protected_output_frames_size); @@ -100,10 +88,11 @@ tsi_result tsi_frame_protector_protect(tsi_frame_protector *self, tsi_result tsi_frame_protector_protect_flush( tsi_frame_protector *self, unsigned char *protected_output_frames, size_t *protected_output_frames_size, size_t *still_pending_size) { - if (self == NULL || protected_output_frames == NULL || - protected_output_frames == NULL || still_pending_size == NULL) { + if (self == NULL || self->vtable == NULL || protected_output_frames == NULL || + protected_output_frames_size == NULL || still_pending_size == NULL) { return TSI_INVALID_ARGUMENT; } + if (self->vtable->protect_flush == NULL) return TSI_UNIMPLEMENTED; return self->vtable->protect_flush(self, protected_output_frames, protected_output_frames_size, still_pending_size); @@ -113,11 +102,12 @@ tsi_result tsi_frame_protector_unprotect( tsi_frame_protector *self, const unsigned char *protected_frames_bytes, size_t *protected_frames_bytes_size, unsigned char *unprotected_bytes, size_t *unprotected_bytes_size) { - if (self == NULL || protected_frames_bytes == NULL || + if (self == NULL || self->vtable == NULL || protected_frames_bytes == NULL || protected_frames_bytes_size == NULL || unprotected_bytes == NULL || unprotected_bytes_size == NULL) { return TSI_INVALID_ARGUMENT; } + if (self->vtable->unprotect == NULL) return TSI_UNIMPLEMENTED; return self->vtable->unprotect(self, protected_frames_bytes, protected_frames_bytes_size, unprotected_bytes, unprotected_bytes_size); @@ -135,36 +125,44 @@ void tsi_frame_protector_destroy(tsi_frame_protector *self) { tsi_result tsi_handshaker_get_bytes_to_send_to_peer(tsi_handshaker *self, unsigned char *bytes, size_t *bytes_size) { - if (self == NULL || bytes == NULL || bytes_size == NULL) { + if (self == NULL || self->vtable == NULL || bytes == NULL || + bytes_size == NULL) { return TSI_INVALID_ARGUMENT; } if (self->frame_protector_created) return TSI_FAILED_PRECONDITION; + if (self->vtable->get_bytes_to_send_to_peer == NULL) return TSI_UNIMPLEMENTED; return self->vtable->get_bytes_to_send_to_peer(self, bytes, bytes_size); } tsi_result tsi_handshaker_process_bytes_from_peer(tsi_handshaker *self, const unsigned char *bytes, size_t *bytes_size) { - if (self == NULL || bytes == NULL || bytes_size == NULL) { + if (self == NULL || self->vtable == NULL || bytes == NULL || + bytes_size == NULL) { return TSI_INVALID_ARGUMENT; } if (self->frame_protector_created) return TSI_FAILED_PRECONDITION; + if (self->vtable->process_bytes_from_peer == NULL) return TSI_UNIMPLEMENTED; return self->vtable->process_bytes_from_peer(self, bytes, bytes_size); } tsi_result tsi_handshaker_get_result(tsi_handshaker *self) { - if (self == NULL) return TSI_INVALID_ARGUMENT; + if (self == NULL || self->vtable == NULL) return TSI_INVALID_ARGUMENT; if (self->frame_protector_created) return TSI_FAILED_PRECONDITION; + if (self->vtable->get_result == NULL) return TSI_UNIMPLEMENTED; return self->vtable->get_result(self); } tsi_result tsi_handshaker_extract_peer(tsi_handshaker *self, tsi_peer *peer) { - if (self == NULL || peer == NULL) return TSI_INVALID_ARGUMENT; + if (self == NULL || self->vtable == NULL || peer == NULL) { + return TSI_INVALID_ARGUMENT; + } memset(peer, 0, sizeof(tsi_peer)); if (self->frame_protector_created) return TSI_FAILED_PRECONDITION; if (tsi_handshaker_get_result(self) != TSI_OK) { return TSI_FAILED_PRECONDITION; } + if (self->vtable->extract_peer == NULL) return TSI_UNIMPLEMENTED; return self->vtable->extract_peer(self, peer); } @@ -172,24 +170,77 @@ tsi_result tsi_handshaker_create_frame_protector( tsi_handshaker *self, size_t *max_protected_frame_size, tsi_frame_protector **protector) { tsi_result result; - if (self == NULL || protector == NULL) return TSI_INVALID_ARGUMENT; - if (self->frame_protector_created) return TSI_FAILED_PRECONDITION; - if (tsi_handshaker_get_result(self) != TSI_OK) { - return TSI_FAILED_PRECONDITION; + if (self == NULL || self->vtable == NULL || protector == NULL) { + return TSI_INVALID_ARGUMENT; } + if (self->frame_protector_created) return TSI_FAILED_PRECONDITION; + if (tsi_handshaker_get_result(self) != TSI_OK) return TSI_FAILED_PRECONDITION; + if (self->vtable->create_frame_protector == NULL) return TSI_UNIMPLEMENTED; result = self->vtable->create_frame_protector(self, max_protected_frame_size, protector); if (result == TSI_OK) { - self->frame_protector_created = 1; + self->frame_protector_created = true; } return result; } +tsi_result tsi_handshaker_next( + tsi_handshaker *self, const unsigned char *received_bytes, + size_t received_bytes_size, const unsigned char **bytes_to_send, + size_t *bytes_to_send_size, tsi_handshaker_result **handshaker_result, + tsi_handshaker_on_next_done_cb cb, void *user_data) { + if (self == NULL || self->vtable == NULL) return TSI_INVALID_ARGUMENT; + if (self->handshaker_result_created) return TSI_FAILED_PRECONDITION; + if (self->vtable->next == NULL) return TSI_UNIMPLEMENTED; + return self->vtable->next(self, received_bytes, received_bytes_size, + bytes_to_send, bytes_to_send_size, + handshaker_result, cb, user_data); +} + void tsi_handshaker_destroy(tsi_handshaker *self) { if (self == NULL) return; self->vtable->destroy(self); } +/* --- tsi_handshaker_result implementation. --- */ + +tsi_result tsi_handshaker_result_extract_peer(const tsi_handshaker_result *self, + tsi_peer *peer) { + if (self == NULL || self->vtable == NULL || peer == NULL) { + return TSI_INVALID_ARGUMENT; + } + memset(peer, 0, sizeof(tsi_peer)); + if (self->vtable->extract_peer == NULL) return TSI_UNIMPLEMENTED; + return self->vtable->extract_peer(self, peer); +} + +tsi_result tsi_handshaker_result_create_frame_protector( + const tsi_handshaker_result *self, size_t *max_protected_frame_size, + tsi_frame_protector **protector) { + if (self == NULL || self->vtable == NULL || protector == NULL) { + return TSI_INVALID_ARGUMENT; + } + if (self->vtable->create_frame_protector == NULL) return TSI_UNIMPLEMENTED; + return self->vtable->create_frame_protector(self, max_protected_frame_size, + protector); +} + +tsi_result tsi_handshaker_result_get_unused_bytes( + const tsi_handshaker_result *self, const unsigned char **bytes, + size_t *bytes_size) { + if (self == NULL || self->vtable == NULL || bytes == NULL || + bytes_size == NULL) { + return TSI_INVALID_ARGUMENT; + } + if (self->vtable->get_unused_bytes == NULL) return TSI_UNIMPLEMENTED; + return self->vtable->get_unused_bytes(self, bytes, bytes_size); +} + +void tsi_handshaker_result_destroy(tsi_handshaker_result *self) { + if (self == NULL) return; + self->vtable->destroy(self); +} + /* --- tsi_peer implementation. --- */ tsi_peer_property tsi_init_peer_property(void) { @@ -231,8 +282,7 @@ tsi_result tsi_construct_allocated_string_peer_property( *property = tsi_init_peer_property(); if (name != NULL) property->name = gpr_strdup(name); if (value_length > 0) { - property->value.data = gpr_malloc(value_length); - memset(property->value.data, 0, value_length); + property->value.data = gpr_zalloc(value_length); property->value.length = value_length; } return TSI_OK; @@ -260,8 +310,7 @@ tsi_result tsi_construct_string_peer_property(const char *name, tsi_result tsi_construct_peer(size_t property_count, tsi_peer *peer) { memset(peer, 0, sizeof(tsi_peer)); if (property_count > 0) { - peer->properties = gpr_malloc(property_count * sizeof(tsi_peer_property)); - memset(peer->properties, 0, property_count * sizeof(tsi_peer_property)); + peer->properties = gpr_zalloc(property_count * sizeof(tsi_peer_property)); peer->property_count = property_count; } return TSI_OK; diff --git a/Sources/CgRPC/src/core/lib/tsi/transport_security.h b/Sources/CgRPC/src/core/tsi/transport_security.h similarity index 57% rename from Sources/CgRPC/src/core/lib/tsi/transport_security.h rename to Sources/CgRPC/src/core/tsi/transport_security.h index aaf110ee0..b0d703985 100644 --- a/Sources/CgRPC/src/core/lib/tsi/transport_security.h +++ b/Sources/CgRPC/src/core/tsi/transport_security.h @@ -1,46 +1,34 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 GRPC_CORE_LIB_TSI_TRANSPORT_SECURITY_H -#define GRPC_CORE_LIB_TSI_TRANSPORT_SECURITY_H +#ifndef GRPC_CORE_TSI_TRANSPORT_SECURITY_H +#define GRPC_CORE_TSI_TRANSPORT_SECURITY_H -#include "src/core/lib/tsi/transport_security_interface.h" +#include + +#include "src/core/lib/debug/trace.h" +#include "src/core/tsi/transport_security_interface.h" #ifdef __cplusplus extern "C" { #endif -extern int tsi_tracing_enabled; +extern grpc_tracer_flag tsi_tracing_enabled; /* Base for tsi_frame_protector implementations. See transport_security_interface.h for documentation. */ @@ -81,11 +69,39 @@ typedef struct { size_t *max_protected_frame_size, tsi_frame_protector **protector); void (*destroy)(tsi_handshaker *self); + tsi_result (*next)(tsi_handshaker *self, const unsigned char *received_bytes, + size_t received_bytes_size, + const unsigned char **bytes_to_send, + size_t *bytes_to_send_size, + tsi_handshaker_result **handshaker_result, + tsi_handshaker_on_next_done_cb cb, void *user_data); } tsi_handshaker_vtable; struct tsi_handshaker { const tsi_handshaker_vtable *vtable; - int frame_protector_created; + bool frame_protector_created; + bool handshaker_result_created; +}; + +/* Base for tsi_handshaker_result implementations. + See transport_security_interface.h for documentation. */ +typedef struct { + tsi_result (*extract_peer)(const tsi_handshaker_result *self, tsi_peer *peer); + tsi_result (*create_zero_copy_grpc_protector)( + const tsi_handshaker_result *self, + size_t *max_output_protected_frame_size, + tsi_zero_copy_grpc_protector **protector); + tsi_result (*create_frame_protector)(const tsi_handshaker_result *self, + size_t *max_output_protected_frame_size, + tsi_frame_protector **protector); + tsi_result (*get_unused_bytes)(const tsi_handshaker_result *self, + const unsigned char **bytes, + size_t *bytes_size); + void (*destroy)(tsi_handshaker_result *self); +} tsi_handshaker_result_vtable; + +struct tsi_handshaker_result { + const tsi_handshaker_result_vtable *vtable; }; /* Peer and property construction/destruction functions. */ @@ -108,4 +124,4 @@ char *tsi_strdup(const char *src); /* Sadly, no strdup in C89. */ } #endif -#endif /* GRPC_CORE_LIB_TSI_TRANSPORT_SECURITY_H */ +#endif /* GRPC_CORE_TSI_TRANSPORT_SECURITY_H */ diff --git a/Sources/CgRPC/src/core/tsi/transport_security_adapter.c b/Sources/CgRPC/src/core/tsi/transport_security_adapter.c new file mode 100644 index 000000000..1c2a57b3b --- /dev/null +++ b/Sources/CgRPC/src/core/tsi/transport_security_adapter.c @@ -0,0 +1,224 @@ +/* + * + * Copyright 2017 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 "src/core/tsi/transport_security_adapter.h" + +#include + +#include +#include +#include "src/core/tsi/transport_security.h" + +#define TSI_ADAPTER_INITIAL_BUFFER_SIZE 256 + +/* --- tsi_adapter_handshaker_result implementation ---*/ + +typedef struct { + tsi_handshaker_result base; + tsi_handshaker *wrapped; + unsigned char *unused_bytes; + size_t unused_bytes_size; +} tsi_adapter_handshaker_result; + +static tsi_result adapter_result_extract_peer(const tsi_handshaker_result *self, + tsi_peer *peer) { + tsi_adapter_handshaker_result *impl = (tsi_adapter_handshaker_result *)self; + return tsi_handshaker_extract_peer(impl->wrapped, peer); +} + +static tsi_result adapter_result_create_frame_protector( + const tsi_handshaker_result *self, size_t *max_output_protected_frame_size, + tsi_frame_protector **protector) { + tsi_adapter_handshaker_result *impl = (tsi_adapter_handshaker_result *)self; + return tsi_handshaker_create_frame_protector( + impl->wrapped, max_output_protected_frame_size, protector); +} + +static tsi_result adapter_result_get_unused_bytes( + const tsi_handshaker_result *self, const unsigned char **bytes, + size_t *byte_size) { + tsi_adapter_handshaker_result *impl = (tsi_adapter_handshaker_result *)self; + *bytes = impl->unused_bytes; + *byte_size = impl->unused_bytes_size; + return TSI_OK; +} + +static void adapter_result_destroy(tsi_handshaker_result *self) { + tsi_adapter_handshaker_result *impl = (tsi_adapter_handshaker_result *)self; + tsi_handshaker_destroy(impl->wrapped); + gpr_free(impl->unused_bytes); + gpr_free(self); +} + +static const tsi_handshaker_result_vtable result_vtable = { + adapter_result_extract_peer, + NULL, /* create_zero_copy_grpc_protector */ + adapter_result_create_frame_protector, + adapter_result_get_unused_bytes, + adapter_result_destroy, +}; + +/* Ownership of wrapped tsi_handshaker is transferred to the result object. */ +static tsi_result tsi_adapter_create_handshaker_result( + tsi_handshaker *wrapped, const unsigned char *unused_bytes, + size_t unused_bytes_size, tsi_handshaker_result **handshaker_result) { + if (wrapped == NULL || (unused_bytes_size > 0 && unused_bytes == NULL)) { + return TSI_INVALID_ARGUMENT; + } + tsi_adapter_handshaker_result *impl = gpr_zalloc(sizeof(*impl)); + impl->base.vtable = &result_vtable; + impl->wrapped = wrapped; + impl->unused_bytes_size = unused_bytes_size; + if (unused_bytes_size > 0) { + impl->unused_bytes = gpr_malloc(unused_bytes_size); + memcpy(impl->unused_bytes, unused_bytes, unused_bytes_size); + } else { + impl->unused_bytes = NULL; + } + *handshaker_result = &impl->base; + return TSI_OK; +} + +/* --- tsi_adapter_handshaker implementation ---*/ + +typedef struct { + tsi_handshaker base; + tsi_handshaker *wrapped; + unsigned char *adapter_buffer; + size_t adapter_buffer_size; +} tsi_adapter_handshaker; + +static tsi_result adapter_get_bytes_to_send_to_peer(tsi_handshaker *self, + unsigned char *bytes, + size_t *bytes_size) { + return tsi_handshaker_get_bytes_to_send_to_peer( + tsi_adapter_handshaker_get_wrapped(self), bytes, bytes_size); +} + +static tsi_result adapter_process_bytes_from_peer(tsi_handshaker *self, + const unsigned char *bytes, + size_t *bytes_size) { + return tsi_handshaker_process_bytes_from_peer( + tsi_adapter_handshaker_get_wrapped(self), bytes, bytes_size); +} + +static tsi_result adapter_get_result(tsi_handshaker *self) { + return tsi_handshaker_get_result(tsi_adapter_handshaker_get_wrapped(self)); +} + +static tsi_result adapter_extract_peer(tsi_handshaker *self, tsi_peer *peer) { + return tsi_handshaker_extract_peer(tsi_adapter_handshaker_get_wrapped(self), + peer); +} + +static tsi_result adapter_create_frame_protector( + tsi_handshaker *self, size_t *max_protected_frame_size, + tsi_frame_protector **protector) { + return tsi_handshaker_create_frame_protector( + tsi_adapter_handshaker_get_wrapped(self), max_protected_frame_size, + protector); +} + +static void adapter_destroy(tsi_handshaker *self) { + tsi_adapter_handshaker *impl = (tsi_adapter_handshaker *)self; + tsi_handshaker_destroy(impl->wrapped); + gpr_free(impl->adapter_buffer); + gpr_free(self); +} + +static tsi_result adapter_next( + tsi_handshaker *self, const unsigned char *received_bytes, + size_t received_bytes_size, const unsigned char **bytes_to_send, + size_t *bytes_to_send_size, tsi_handshaker_result **handshaker_result, + tsi_handshaker_on_next_done_cb cb, void *user_data) { + /* Input sanity check. */ + if ((received_bytes_size > 0 && received_bytes == NULL) || + bytes_to_send == NULL || bytes_to_send_size == NULL || + handshaker_result == NULL) { + return TSI_INVALID_ARGUMENT; + } + + /* If there are received bytes, process them first. */ + tsi_adapter_handshaker *impl = (tsi_adapter_handshaker *)self; + tsi_result status = TSI_OK; + size_t bytes_consumed = received_bytes_size; + if (received_bytes_size > 0) { + status = tsi_handshaker_process_bytes_from_peer( + impl->wrapped, received_bytes, &bytes_consumed); + if (status != TSI_OK) return status; + } + + /* Get bytes to send to the peer, if available. */ + size_t offset = 0; + do { + size_t to_send_size = impl->adapter_buffer_size - offset; + status = tsi_handshaker_get_bytes_to_send_to_peer( + impl->wrapped, impl->adapter_buffer + offset, &to_send_size); + offset += to_send_size; + if (status == TSI_INCOMPLETE_DATA) { + impl->adapter_buffer_size *= 2; + impl->adapter_buffer = + gpr_realloc(impl->adapter_buffer, impl->adapter_buffer_size); + } + } while (status == TSI_INCOMPLETE_DATA); + if (status != TSI_OK) return status; + *bytes_to_send = impl->adapter_buffer; + *bytes_to_send_size = offset; + + /* If handshake completes, create tsi_handshaker_result. */ + if (tsi_handshaker_is_in_progress(impl->wrapped)) { + *handshaker_result = NULL; + } else { + size_t unused_bytes_size = received_bytes_size - bytes_consumed; + const unsigned char *unused_bytes = + unused_bytes_size == 0 ? NULL : received_bytes + bytes_consumed; + status = tsi_adapter_create_handshaker_result( + impl->wrapped, unused_bytes, unused_bytes_size, handshaker_result); + if (status == TSI_OK) { + impl->base.handshaker_result_created = true; + impl->wrapped = NULL; + } + } + return status; +} + +static const tsi_handshaker_vtable handshaker_vtable = { + adapter_get_bytes_to_send_to_peer, + adapter_process_bytes_from_peer, + adapter_get_result, + adapter_extract_peer, + adapter_create_frame_protector, + adapter_destroy, + adapter_next, +}; + +tsi_handshaker *tsi_create_adapter_handshaker(tsi_handshaker *wrapped) { + GPR_ASSERT(wrapped != NULL); + tsi_adapter_handshaker *impl = gpr_zalloc(sizeof(*impl)); + impl->base.vtable = &handshaker_vtable; + impl->wrapped = wrapped; + impl->adapter_buffer_size = TSI_ADAPTER_INITIAL_BUFFER_SIZE; + impl->adapter_buffer = gpr_malloc(impl->adapter_buffer_size); + return &impl->base; +} + +tsi_handshaker *tsi_adapter_handshaker_get_wrapped(tsi_handshaker *adapter) { + if (adapter == NULL) return NULL; + tsi_adapter_handshaker *impl = (tsi_adapter_handshaker *)adapter; + return impl->wrapped; +} diff --git a/Sources/CgRPC/src/core/tsi/transport_security_adapter.h b/Sources/CgRPC/src/core/tsi/transport_security_adapter.h new file mode 100644 index 000000000..02f33d4c1 --- /dev/null +++ b/Sources/CgRPC/src/core/tsi/transport_security_adapter.h @@ -0,0 +1,47 @@ +/* + * + * Copyright 2017 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 GRPC_CORE_TSI_TRANSPORT_SECURITY_ADAPTER_H +#define GRPC_CORE_TSI_TRANSPORT_SECURITY_ADAPTER_H + +#include "src/core/tsi/transport_security_interface.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Create a tsi handshaker that takes an implementation of old interface and + converts into an implementation of new interface. In the old interface, + there are get_bytes_to_send_to_peer, process_bytes_from_peer, get_result, + extract_peer, and create_frame_protector. In the new interface, only next + method is needed. See transport_security_interface.h for details. Note that + this tsi adapter handshaker is temporary. It will be removed once TSI has + been fully migrated to the new interface. + Ownership of input tsi_handshaker is transferred to this new adapter. */ +tsi_handshaker *tsi_create_adapter_handshaker(tsi_handshaker *wrapped); + +/* Given a tsi adapter handshaker, return the original wrapped handshaker. The + adapter still owns the wrapped handshaker which should not be destroyed by + the caller. */ +tsi_handshaker *tsi_adapter_handshaker_get_wrapped(tsi_handshaker *adapter); + +#ifdef __cplusplus +} +#endif + +#endif /* GRPC_CORE_TSI_TRANSPORT_SECURITY_ADAPTER_H */ diff --git a/Sources/CgRPC/src/core/tsi/transport_security_grpc.c b/Sources/CgRPC/src/core/tsi/transport_security_grpc.c new file mode 100644 index 000000000..5bcfdfa61 --- /dev/null +++ b/Sources/CgRPC/src/core/tsi/transport_security_grpc.c @@ -0,0 +1,64 @@ +/* + * + * Copyright 2017 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 "src/core/tsi/transport_security_grpc.h" + +/* This method creates a tsi_zero_copy_grpc_protector object. */ +tsi_result tsi_handshaker_result_create_zero_copy_grpc_protector( + const tsi_handshaker_result *self, size_t *max_output_protected_frame_size, + tsi_zero_copy_grpc_protector **protector) { + if (self == NULL || self->vtable == NULL || protector == NULL) { + return TSI_INVALID_ARGUMENT; + } + if (self->vtable->create_zero_copy_grpc_protector == NULL) { + return TSI_UNIMPLEMENTED; + } + return self->vtable->create_zero_copy_grpc_protector( + self, max_output_protected_frame_size, protector); +} + +/* --- tsi_zero_copy_grpc_protector common implementation. --- + + Calls specific implementation after state/input validation. */ + +tsi_result tsi_zero_copy_grpc_protector_protect( + tsi_zero_copy_grpc_protector *self, grpc_slice_buffer *unprotected_slices, + grpc_slice_buffer *protected_slices) { + if (self == NULL || self->vtable == NULL || unprotected_slices == NULL || + protected_slices == NULL) { + return TSI_INVALID_ARGUMENT; + } + if (self->vtable->protect == NULL) return TSI_UNIMPLEMENTED; + return self->vtable->protect(self, unprotected_slices, protected_slices); +} + +tsi_result tsi_zero_copy_grpc_protector_unprotect( + tsi_zero_copy_grpc_protector *self, grpc_slice_buffer *protected_slices, + grpc_slice_buffer *unprotected_slices) { + if (self == NULL || self->vtable == NULL || protected_slices == NULL || + unprotected_slices == NULL) { + return TSI_INVALID_ARGUMENT; + } + if (self->vtable->unprotect == NULL) return TSI_UNIMPLEMENTED; + return self->vtable->unprotect(self, protected_slices, unprotected_slices); +} + +void tsi_zero_copy_grpc_protector_destroy(tsi_zero_copy_grpc_protector *self) { + if (self == NULL) return; + self->vtable->destroy(self); +} diff --git a/Sources/CgRPC/src/core/tsi/transport_security_grpc.h b/Sources/CgRPC/src/core/tsi/transport_security_grpc.h new file mode 100644 index 000000000..5ab5297cc --- /dev/null +++ b/Sources/CgRPC/src/core/tsi/transport_security_grpc.h @@ -0,0 +1,80 @@ +/* + * + * Copyright 2017 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 GRPC_CORE_TSI_TRANSPORT_SECURITY_GRPC_H +#define GRPC_CORE_TSI_TRANSPORT_SECURITY_GRPC_H + +#include +#include "src/core/tsi/transport_security.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* This method creates a tsi_zero_copy_grpc_protector object. It return TSI_OK + assuming there is no fatal error. + The caller is responsible for destroying the protector. */ +tsi_result tsi_handshaker_result_create_zero_copy_grpc_protector( + const tsi_handshaker_result *self, size_t *max_output_protected_frame_size, + tsi_zero_copy_grpc_protector **protector); + +/* -- tsi_zero_copy_grpc_protector object -- */ + +/* Outputs protected frames. + - unprotected_slices is the unprotected data to be protected. + - protected_slices is the protected output frames. One or more frames + may be produced in this protect function. + - This method returns TSI_OK in case of success or a specific error code in + case of failure. */ +tsi_result tsi_zero_copy_grpc_protector_protect( + tsi_zero_copy_grpc_protector *self, grpc_slice_buffer *unprotected_slices, + grpc_slice_buffer *protected_slices); + +/* Outputs unprotected bytes. + - protected_slices is the bytes of protected frames. + - unprotected_slices is the unprotected output data. + - This method returns TSI_OK in case of success. Success includes cases where + there is not enough data to output in which case unprotected_slices has 0 + bytes. */ +tsi_result tsi_zero_copy_grpc_protector_unprotect( + tsi_zero_copy_grpc_protector *self, grpc_slice_buffer *protected_slices, + grpc_slice_buffer *unprotected_slices); + +/* Destroys the tsi_zero_copy_grpc_protector object. */ +void tsi_zero_copy_grpc_protector_destroy(tsi_zero_copy_grpc_protector *self); + +/* Base for tsi_zero_copy_grpc_protector implementations. */ +typedef struct { + tsi_result (*protect)(tsi_zero_copy_grpc_protector *self, + grpc_slice_buffer *unprotected_slices, + grpc_slice_buffer *protected_slices); + tsi_result (*unprotect)(tsi_zero_copy_grpc_protector *self, + grpc_slice_buffer *protected_slices, + grpc_slice_buffer *unprotected_slices); + void (*destroy)(tsi_zero_copy_grpc_protector *self); +} tsi_zero_copy_grpc_protector_vtable; + +struct tsi_zero_copy_grpc_protector { + const tsi_zero_copy_grpc_protector_vtable *vtable; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* GRPC_CORE_TSI_TRANSPORT_SECURITY_GRPC_H */ diff --git a/Sources/CgRPC/src/core/lib/tsi/transport_security_interface.h b/Sources/CgRPC/src/core/tsi/transport_security_interface.h similarity index 54% rename from Sources/CgRPC/src/core/lib/tsi/transport_security_interface.h rename to Sources/CgRPC/src/core/tsi/transport_security_interface.h index 3e8c9d7ff..80c426bbd 100644 --- a/Sources/CgRPC/src/core/lib/tsi/transport_security_interface.h +++ b/Sources/CgRPC/src/core/tsi/transport_security_interface.h @@ -1,42 +1,29 @@ /* * - * Copyright 2015, Google Inc. - * All rights reserved. + * Copyright 2015 gRPC authors. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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 * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 GRPC_CORE_LIB_TSI_TRANSPORT_SECURITY_INTERFACE_H -#define GRPC_CORE_LIB_TSI_TRANSPORT_SECURITY_INTERFACE_H +#ifndef GRPC_CORE_TSI_TRANSPORT_SECURITY_INTERFACE_H +#define GRPC_CORE_TSI_TRANSPORT_SECURITY_INTERFACE_H #include #include +#include "src/core/lib/debug/trace.h" + #ifdef __cplusplus extern "C" { #endif @@ -56,7 +43,8 @@ typedef enum { TSI_NOT_FOUND = 9, TSI_PROTOCOL_FAILURE = 10, TSI_HANDSHAKE_IN_PROGRESS = 11, - TSI_OUT_OF_RESOURCES = 12 + TSI_OUT_OF_RESOURCES = 12, + TSI_ASYNC = 13 } tsi_result; typedef enum { @@ -72,8 +60,16 @@ const char *tsi_result_to_string(tsi_result result); /* --- tsi tracing --- */ -/* Set this early to avoid races */ -extern int tsi_tracing_enabled; +extern grpc_tracer_flag tsi_tracing_enabled; + +/* -- tsi_zero_copy_grpc_protector object -- + + This object protects and unprotects grpc slice buffers with zero or minimized + memory copy once the handshake is done. Implementations of this object must be + thread compatible. This object depends on grpc and the details of this object + is defined in transport_security_grpc.h. */ + +typedef struct tsi_zero_copy_grpc_protector tsi_zero_copy_grpc_protector; /* --- tsi_frame_protector object --- @@ -208,76 +204,138 @@ typedef struct { /* Destructs the tsi_peer object. */ void tsi_peer_destruct(tsi_peer *self); +/* --- tsi_handshaker_result object --- + + This object contains all necessary handshake results and data such as peer + info, negotiated keys, unused handshake bytes, when the handshake completes. + Implementations of this object must be thread compatible. */ + +typedef struct tsi_handshaker_result tsi_handshaker_result; + +/* This method extracts tsi peer. It returns TSI_OK assuming there is no fatal + error. + The caller is responsible for destructing the peer. */ +tsi_result tsi_handshaker_result_extract_peer(const tsi_handshaker_result *self, + tsi_peer *peer); + +/* This method creates a tsi_frame_protector object. It returns TSI_OK assuming + there is no fatal error. + The caller is responsible for destroying the protector. */ +tsi_result tsi_handshaker_result_create_frame_protector( + const tsi_handshaker_result *self, size_t *max_output_protected_frame_size, + tsi_frame_protector **protector); + +/* This method returns the unused bytes from the handshake. It returns TSI_OK + assuming there is no fatal error. + Ownership of the bytes is retained by the handshaker result. As a + consequence, the caller must not free the bytes. */ +tsi_result tsi_handshaker_result_get_unused_bytes( + const tsi_handshaker_result *self, const unsigned char **bytes, + size_t *byte_size); + +/* This method releases the tsi_handshaker_handshaker object. After this method + is called, no other method can be called on the object. */ +void tsi_handshaker_result_destroy(tsi_handshaker_result *self); + /* --- tsi_handshaker objects ---- Implementations of this object must be thread compatible. - A typical usage of this object would be: + ------------------------------------------------------------------------ + + A typical usage supporting both synchronous and asynchronous TSI handshaker + implementations would be: ------------------------------------------------------------------------ - tsi_result result = TSI_OK; - unsigned char buf[4096]; - size_t buf_offset; - size_t buf_size; - while (1) { - // See if we need to send some bytes to the peer. - do { - size_t buf_size_to_send = sizeof(buf); - result = tsi_handshaker_get_bytes_to_send_to_peer(handshaker, buf, - &buf_size_to_send); - if (buf_size_to_send > 0) send_bytes_to_peer(buf, buf_size_to_send); - } while (result == TSI_INCOMPLETE_DATA); - if (result != TSI_OK) return result; - if (!tsi_handshaker_is_in_progress(handshaker)) break; - - do { - // Read bytes from the peer. - buf_size = sizeof(buf); - buf_offset = 0; - read_bytes_from_peer(buf, &buf_size); - if (buf_size == 0) break; - - // Process the bytes from the peer. We have to be careful as these bytes - // may contain non-handshake data (protected data). If this is the case, - // we will exit from the loop with buf_size > 0. - size_t consumed_by_handshaker = buf_size; - result = tsi_handshaker_process_bytes_from_peer( - handshaker, buf, &consumed_by_handshaker); - buf_size -= consumed_by_handshaker; - buf_offset += consumed_by_handshaker; - } while (result == TSI_INCOMPLETE_DATA); - - if (result != TSI_OK) return result; - if (!tsi_handshaker_is_in_progress(handshaker)) break; + + typedef struct { + tsi_handshaker *handshaker; + tsi_handshaker_result *handshaker_result; + unsigned char *handshake_buffer; + size_t handshake_buffer_size; + ... + } security_handshaker; + + void do_handshake(security_handshaker *h, ...) { + // Start the handshake by the calling do_handshake_next. + do_handshake_next(h, NULL, 0); + ... } - // Check the Peer. - tsi_peer peer; - do { - result = tsi_handshaker_extract_peer(handshaker, &peer); - if (result != TSI_OK) break; - result = check_peer(&peer); - } while (0); - tsi_peer_destruct(&peer); - if (result != TSI_OK) return result; - - // Create the protector. - tsi_frame_protector* protector = NULL; - result = tsi_handshaker_create_frame_protector(handshaker, NULL, - &protector); - if (result != TSI_OK) return result; - - // Do not forget to unprotect outstanding data if any. - if (buf_size > 0) { - result = tsi_frame_protector_unprotect(protector, buf + buf_offset, - buf_size, ..., ...); - .... + // This method is the callback function when data is received from the + // peer. This method will read bytes into the handshake buffer and call + // do_handshake_next. + void on_handshake_data_received_from_peer(void *user_data) { + security_handshaker *h = (security_handshaker *)user_data; + size_t bytes_received_size = h->handshake_buffer_size; + read_bytes_from_peer(h->handshake_buffer, &bytes_received_size); + do_handshake_next(h, h->handshake_buffer, bytes_received_size); + } + + // This method processes a step of handshake, calling tsi_handshaker_next. + void do_handshake_next(security_handshaker *h, + const unsigned char* bytes_received, + size_t bytes_received_size) { + tsi_result status = TSI_OK; + unsigned char *bytes_to_send = NULL; + size_t bytes_to_send_size = 0; + tsi_handshaker_result *result = NULL; + status = tsi_handshaker_next( + handshaker, bytes_received, bytes_received_size, &bytes_to_send, + &bytes_to_send_size, &result, on_handshake_next_done, h); + // If TSI handshaker is asynchronous, on_handshake_next_done will be + // executed inside tsi_handshaker_next. + if (status == TSI_ASYNC) return; + // If TSI handshaker is synchronous, invoke callback directly in this + // thread. + on_handshake_next_done(status, (void *)h, bytes_to_send, + bytes_to_send_size, result); + } + + // This is the callback function to execute after tsi_handshaker_next. + // It is passed to tsi_handshaker_next as a function parameter. + void on_handshake_next_done( + tsi_result status, void *user_data, const unsigned char *bytes_to_send, + size_t bytes_to_send_size, tsi_handshaker_result *result) { + security_handshaker *h = (security_handshaker *)user_data; + if (status == TSI_INCOMPLETE_DATA) { + // Schedule an asynchronous read from the peer. If handshake data are + // received, on_handshake_data_received_from_peer will be called. + async_read_from_peer(..., ..., on_handshake_data_received_from_peer); + return; + } + if (status != TSI_OK) return; + + if (bytes_to_send_size > 0) { + send_bytes_to_peer(bytes_to_send, bytes_to_send_size); + } + + if (result != NULL) { + // Handshake completed. + h->result = result; + // Check the Peer. + tsi_peer peer; + status = tsi_handshaker_result_extract_peer(result, &peer); + if (status != TSI_OK) return; + status = check_peer(&peer); + tsi_peer_destruct(&peer); + if (status != TSI_OK) return; + + // Create the protector. + tsi_frame_protector* protector = NULL; + status = tsi_handshaker_result_create_frame_protector(result, NULL, + &protector); + if (status != TSI_OK) return; + + // Do not forget to unprotect outstanding data if any. + .... + } } - ... ------------------------------------------------------------------------ */ typedef struct tsi_handshaker tsi_handshaker; -/* Gets bytes that need to be sent to the peer. +/* TO BE DEPRECATED SOON. Use tsi_handshaker_next instead. + Gets bytes that need to be sent to the peer. - bytes is the buffer that will be written with the data to be sent to the peer. - bytes_size is an input/output parameter specifying the capacity of the @@ -292,7 +350,8 @@ tsi_result tsi_handshaker_get_bytes_to_send_to_peer(tsi_handshaker *self, unsigned char *bytes, size_t *bytes_size); -/* Processes bytes received from the peer. +/* TO BE DEPRECATED SOON. Use tsi_handshaker_next instead. + Processes bytes received from the peer. - bytes is the buffer containing the data. - bytes_size is an input/output parameter specifying the size of the data as input and the number of bytes consumed as output. @@ -305,24 +364,29 @@ tsi_result tsi_handshaker_process_bytes_from_peer(tsi_handshaker *self, const unsigned char *bytes, size_t *bytes_size); -/* Gets the result of the handshaker. +/* TO BE DEPRECATED SOON. + Gets the result of the handshaker. Returns TSI_OK if the hanshake completed successfully and there has been no errors. Returns TSI_HANDSHAKE_IN_PROGRESS if the handshaker is not done yet but no error has been encountered so far. Otherwise the handshaker failed with the returned error. */ tsi_result tsi_handshaker_get_result(tsi_handshaker *self); -/* Returns 1 if the handshake is in progress, 0 otherwise. */ +/* TO BE DEPRECATED SOON. + Returns 1 if the handshake is in progress, 0 otherwise. */ #define tsi_handshaker_is_in_progress(h) \ (tsi_handshaker_get_result((h)) == TSI_HANDSHAKE_IN_PROGRESS) -/* This method may return TSI_FAILED_PRECONDITION if +/* TO BE DEPRECATED SOON. Use tsi_handshaker_result_extract_peer instead. + This method may return TSI_FAILED_PRECONDITION if tsi_handshaker_is_in_progress returns 1, it returns TSI_OK otherwise assuming the handshaker is not in a fatal error state. The caller is responsible for destructing the peer. */ tsi_result tsi_handshaker_extract_peer(tsi_handshaker *self, tsi_peer *peer); -/* This method creates a tsi_frame_protector object after the handshake phase +/* TO BE DEPRECATED SOON. Use tsi_handshaker_result_create_frame_protector + instead. + This method creates a tsi_frame_protector object after the handshake phase is done. After this method has been called successfully, the only method that can be called on this object is Destroy. - max_output_protected_frame_size is an input/output parameter specifying the @@ -342,12 +406,55 @@ tsi_result tsi_handshaker_create_frame_protector( tsi_handshaker *self, size_t *max_output_protected_frame_size, tsi_frame_protector **protector); +/* Callback function definition for tsi_handshaker_next. + - status indicates the status of the next operation. + - user_data is the argument to callback function passed from the caller. + - bytes_to_send is the data buffer to be sent to the peer. + - bytes_to_send_size is the size of data buffer to be sent to the peer. + - handshaker_result is the result of handshake when the handshake completes, + is NULL otherwise. */ +typedef void (*tsi_handshaker_on_next_done_cb)( + tsi_result status, void *user_data, const unsigned char *bytes_to_send, + size_t bytes_to_send_size, tsi_handshaker_result *handshaker_result); + +/* Conduct a next step of the handshake. + - received_bytes is the buffer containing the data received from the peer. + - received_bytes_size is the size of the data received from the peer. + - bytes_to_send is the data buffer to be sent to the peer. + - bytes_to_send_size is the size of data buffer to be sent to the peer. + - handshaker_result is the result of handshake if the handshake completes. + - cb is the callback function defined above. It can be NULL for synchronous + TSI handshaker implementation. + - user_data is the argument to callback function passed from the caller. + This method returns TSI_ASYNC if the TSI handshaker implementation is + asynchronous, and in this case, the callback is guaranteed to run in another + thread owned by TSI. It returns TSI_OK if the handshake completes or if + there are data to send to the peer, otherwise returns TSI_INCOMPLETE_DATA + which indicates that this method needs to be called again with more data + from the peer. In case of a fatal error in the handshake, another specific + error code is returned. + The caller is responsible for destroying the handshaker_result. However, + the caller should not free bytes_to_send, as the buffer is owned by the + tsi_handshaker object. */ +tsi_result tsi_handshaker_next( + tsi_handshaker *self, const unsigned char *received_bytes, + size_t received_bytes_size, const unsigned char **bytes_to_send, + size_t *bytes_to_send_size, tsi_handshaker_result **handshaker_result, + tsi_handshaker_on_next_done_cb cb, void *user_data); + /* This method releases the tsi_handshaker object. After this method is called, no other method can be called on the object. */ void tsi_handshaker_destroy(tsi_handshaker *self); +/* This method initializes the necessary shared objects used for tsi + implementation. */ +void tsi_init(); + +/* This method destroys the shared objects created by tsi_init. */ +void tsi_destroy(); + #ifdef __cplusplus } #endif -#endif /* GRPC_CORE_LIB_TSI_TRANSPORT_SECURITY_INTERFACE_H */ +#endif /* GRPC_CORE_TSI_TRANSPORT_SECURITY_INTERFACE_H */ diff --git a/Sources/gRPC/Handler.swift b/Sources/gRPC/Handler.swift index 131ce47a2..9dfa94735 100644 --- a/Sources/gRPC/Handler.swift +++ b/Sources/gRPC/Handler.swift @@ -38,14 +38,26 @@ public class Handler { /// The host name sent with the request public lazy var host: String = { - return String(cString:cgrpc_handler_host(self.underlyingHandler), - encoding:.utf8)!; + if let string = cgrpc_handler_copy_host(self.underlyingHandler) { + defer { + cgrpc_free_copied_string(string); + } + return String(cString:string, encoding:.utf8)!; + } else { + return "" + } }() /// The method name sent with the request public lazy var method: String = { - return String(cString:cgrpc_handler_method(self.underlyingHandler), - encoding:.utf8)!; + if let string = cgrpc_handler_copy_method(self.underlyingHandler) { + defer { + cgrpc_free_copied_string(string); + } + return String(cString:string, encoding:.utf8)!; + } else { + return "" + } }() /// The caller address associated with the request diff --git a/Sources/gRPC/Metadata.swift b/Sources/gRPC/Metadata.swift index bc9d26066..14f6b52ba 100644 --- a/Sources/gRPC/Metadata.swift +++ b/Sources/gRPC/Metadata.swift @@ -71,21 +71,27 @@ public class Metadata : CustomStringConvertible, NSCopying { } public func key(_ index: Int) -> (String) { - if let key = String(cString:cgrpc_metadata_array_get_key_at_index(underlyingArray, index), - encoding:String.Encoding.utf8) { - return key - } else { - return "" + if let string = cgrpc_metadata_array_copy_key_at_index(underlyingArray, index) { + defer { + cgrpc_free_copied_string(string) + } + if let key = String(cString:string, encoding:String.Encoding.utf8) { + return key + } } + return "" } public func value(_ index: Int) -> (String) { - if let value = String(cString:cgrpc_metadata_array_get_value_at_index(underlyingArray, index), - encoding:String.Encoding.utf8) { - return value - } else { - return "" + if let string = cgrpc_metadata_array_copy_value_at_index(underlyingArray, index) { + defer { + cgrpc_free_copied_string(string) + } + if let value = String(cString:string, encoding:String.Encoding.utf8) { + return value + } } + return "" } public func add(key:String, value:String) { diff --git a/Sources/gRPC/OperationGroup.swift b/Sources/gRPC/OperationGroup.swift index ba1bbbe9a..ef7c4f99e 100644 --- a/Sources/gRPC/OperationGroup.swift +++ b/Sources/gRPC/OperationGroup.swift @@ -165,8 +165,14 @@ internal class OperationGroup { for (i, operation) in operations.enumerated() { switch (operation) { case .receiveStatusOnClient: - return String(cString:cgrpc_observer_recv_status_on_client_get_status_details(underlyingObservers[i]), - encoding:String.Encoding.utf8)! + if let string = cgrpc_observer_recv_status_on_client_copy_status_details(underlyingObservers[i]) { + defer { + cgrpc_free_copied_string(string); + } + return String(cString:string, encoding:String.Encoding.utf8)! + } else { + return nil + } default: continue } diff --git a/Tests/gRPCTests/GRPCTests.swift b/Tests/gRPCTests/GRPCTests.swift index b6e18c8bb..275f8cb6b 100644 --- a/Tests/gRPCTests/GRPCTests.swift +++ b/Tests/gRPCTests/GRPCTests.swift @@ -1,98 +1,106 @@ -/* - * Copyright 2017, gRPC Authors All rights reserved. - * - * 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. - */ -import XCTest -import Foundation -import Dispatch -@testable import gRPC + /* + * Copyright 2017, gRPC Authors All rights reserved. + * + * 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. + */ + import XCTest + import Foundation + import Dispatch + @testable import gRPC -func Log(_ message : String) { + func Log(_ message : String) { FileHandle.standardError.write((message + "\n").data(using:.utf8)!) -} + } -class gRPCTests: XCTestCase { + + + class gRPCTests: XCTestCase { func testBasicSanity() { gRPC.initialize() - let latch = CountDownLatch(2) + let server = gRPC.Server(address:address) + let sem = DispatchSemaphore(value: 0) + + // start the server DispatchQueue.global().async() { do { - try server() + try runServer(server:server) } catch (let error) { XCTFail("server error \(error)") } - latch.signal() + sem.signal() // when the server exits, the test is finished } - DispatchQueue.global().async() { - do { - try client() - } catch (let error) { - XCTFail("client error \(error)") - } - latch.signal() + + // run the client + do { + try runClient() + } catch (let error) { + XCTFail("client error \(error)") } - latch.wait() + + // stop the server + server.stop() + + // wait until the server has shut down + _ = sem.wait(timeout: DispatchTime.distantFuture) } -} + } -extension gRPCTests { + extension gRPCTests { static var allTests : [(String, (gRPCTests) -> () throws -> Void)] { return [ ("testBasicSanity", testBasicSanity), ] } -} + } -let address = "localhost:8999" -let host = "foo.test.google.fr" -let clientText = "hello, server!" -let serverText = "hello, client!" -let initialClientMetadata = + let address = "localhost:8081" + let host = "foo.test.google.fr" + let clientText = "hello, server!" + let serverText = "hello, client!" + let initialClientMetadata = ["x": "xylophone", "y": "yu", "z": "zither"] -let initialServerMetadata = + let initialServerMetadata = ["a": "Apple", "b": "Banana", "c": "Cherry"] -let trailingServerMetadata = + let trailingServerMetadata = ["0": "zero", "1": "one", "2": "two"] -let steps = 30 -let hello = "/hello" -let goodbye = "/goodbye" -let statusCode = 0 -let statusMessage = "OK" + let steps = 10 + let hello = "/hello" + let statusCode = 0 + let statusMessage = "OK" -func verify_metadata(_ metadata: Metadata, expected: [String:String]) { + func verify_metadata(_ metadata: Metadata, expected: [String:String]) { XCTAssertGreaterThanOrEqual(metadata.count(), expected.count) for i in 0.. + public_headers=(${sh_multiline_list(grpc_public_headers(libs), 2)}) + + source_files=(${sh_multiline_list(grpc_private_files(libs), 2)}) + + private_headers=(${sh_multiline_list(grpc_private_headers(libs), 2)}) + diff --git a/third_party/RUNME.sh b/third_party/RUNME.sh index 288f9c8e7..bb8f78779 100755 --- a/third_party/RUNME.sh +++ b/third_party/RUNME.sh @@ -16,12 +16,12 @@ # printf "\033c" read -p "Would you like to download swift-protobuf / grpc [y/N]" CONDITION; -if [ "$CONDITION" = "y" ] ; then - read -p "Use last known stable swift-protobuf - 0.9.903 ? or latest master ? [S/l] " CONDITION; - if [ "$CONDITION" = "l" ] ; then +if [ "$CONDITION" == "y" ] ; then + read -p "Use last known stable swift-protobuf - 0.9.904 ? or latest master ? [S/l] " CONDITION; + if [ "$CONDITION" == "l" ] ; then git clone https://github.com/apple/swift-protobuf.git else - git clone -b 0.9.903 https://github.com/apple/swift-protobuf.git + git clone -b 0.9.904 https://github.com/apple/swift-protobuf.git fi git clone https://github.com/grpc/grpc.git cd grpc diff --git a/vendor-boringssl.sh b/vendor-boringssl.sh index 98b3f5bc7..80ffd26c6 100755 --- a/vendor-boringssl.sh +++ b/vendor-boringssl.sh @@ -67,3 +67,5 @@ do echo "EXCLUDE $exclude" find $DSTROOT -name "$exclude" -exec rm -rf {} \; done + +perl -pi -e '$_ .= qq(\n#define OPENSSL_NO_ASM\n) if /#define OPENSSL_HEADER_BASE_H/' Sources/BoringSSL/include/openssl/base.h diff --git a/vendor-grpc.sh b/vendor-grpc.sh index aad1ab4d6..d2aa1e134 100755 --- a/vendor-grpc.sh +++ b/vendor-grpc.sh @@ -19,727 +19,18 @@ # the Swift Package Manager. # -public_headers=( -'include/grpc/support/alloc.h' -'include/grpc/support/atm.h' -'include/grpc/support/atm_gcc_atomic.h' -'include/grpc/support/atm_gcc_sync.h' -'include/grpc/support/atm_windows.h' -'include/grpc/support/avl.h' -'include/grpc/support/cmdline.h' -'include/grpc/support/cpu.h' -'include/grpc/support/histogram.h' -'include/grpc/support/host_port.h' -'include/grpc/support/log.h' -'include/grpc/support/log_windows.h' -'include/grpc/support/port_platform.h' -'include/grpc/support/string_util.h' -'include/grpc/support/subprocess.h' -'include/grpc/support/sync.h' -'include/grpc/support/sync_generic.h' -'include/grpc/support/sync_posix.h' -'include/grpc/support/sync_windows.h' -'include/grpc/support/thd.h' -'include/grpc/support/time.h' -'include/grpc/support/tls.h' -'include/grpc/support/tls_gcc.h' -'include/grpc/support/tls_msvc.h' -'include/grpc/support/tls_pthread.h' -'include/grpc/support/useful.h' -'include/grpc/impl/codegen/atm.h' -'include/grpc/impl/codegen/atm_gcc_atomic.h' -'include/grpc/impl/codegen/atm_gcc_sync.h' -'include/grpc/impl/codegen/atm_windows.h' -'include/grpc/impl/codegen/gpr_types.h' -'include/grpc/impl/codegen/port_platform.h' -'include/grpc/impl/codegen/slice.h' -'include/grpc/impl/codegen/sync.h' -'include/grpc/impl/codegen/sync_generic.h' -'include/grpc/impl/codegen/sync_posix.h' -'include/grpc/impl/codegen/sync_windows.h' -'include/grpc/byte_buffer.h' -'include/grpc/byte_buffer_reader.h' -'include/grpc/compression.h' -'include/grpc/grpc.h' -'include/grpc/grpc_posix.h' -'include/grpc/grpc_security_constants.h' -'include/grpc/slice.h' -'include/grpc/slice_buffer.h' -'include/grpc/status.h' -'include/grpc/impl/codegen/byte_buffer_reader.h' -'include/grpc/impl/codegen/compression_types.h' -'include/grpc/impl/codegen/connectivity_state.h' -'include/grpc/impl/codegen/grpc_types.h' -'include/grpc/impl/codegen/propagation_bits.h' -'include/grpc/impl/codegen/status.h' -'include/grpc/impl/codegen/atm.h' -'include/grpc/impl/codegen/atm_gcc_atomic.h' -'include/grpc/impl/codegen/atm_gcc_sync.h' -'include/grpc/impl/codegen/atm_windows.h' -'include/grpc/impl/codegen/gpr_types.h' -'include/grpc/impl/codegen/port_platform.h' -'include/grpc/impl/codegen/slice.h' -'include/grpc/impl/codegen/sync.h' -'include/grpc/impl/codegen/sync_generic.h' -'include/grpc/impl/codegen/sync_posix.h' -'include/grpc/impl/codegen/sync_windows.h' -'include/grpc/grpc_security.h' -'include/grpc/census.h') - -source_files=( -'src/core/lib/profiling/timers.h' -'src/core/lib/support/backoff.h' -'src/core/lib/support/block_annotate.h' -'src/core/lib/support/env.h' -'src/core/lib/support/mpscq.h' -'src/core/lib/support/murmur_hash.h' -'src/core/lib/support/stack_lockfree.h' -'src/core/lib/support/string.h' -'src/core/lib/support/string_windows.h' -'src/core/lib/support/thd_internal.h' -'src/core/lib/support/time_precise.h' -'src/core/lib/support/tmpfile.h' -'src/core/lib/profiling/basic_timers.c' -'src/core/lib/profiling/stap_timers.c' -'src/core/lib/support/alloc.c' -'src/core/lib/support/avl.c' -'src/core/lib/support/backoff.c' -'src/core/lib/support/cmdline.c' -'src/core/lib/support/cpu_iphone.c' -'src/core/lib/support/cpu_linux.c' -'src/core/lib/support/cpu_posix.c' -'src/core/lib/support/cpu_windows.c' -'src/core/lib/support/env_linux.c' -'src/core/lib/support/env_posix.c' -'src/core/lib/support/env_windows.c' -'src/core/lib/support/histogram.c' -'src/core/lib/support/host_port.c' -'src/core/lib/support/log.c' -'src/core/lib/support/log_android.c' -'src/core/lib/support/log_linux.c' -'src/core/lib/support/log_posix.c' -'src/core/lib/support/log_windows.c' -'src/core/lib/support/mpscq.c' -'src/core/lib/support/murmur_hash.c' -'src/core/lib/support/stack_lockfree.c' -'src/core/lib/support/string.c' -'src/core/lib/support/string_posix.c' -'src/core/lib/support/string_util_windows.c' -'src/core/lib/support/string_windows.c' -'src/core/lib/support/subprocess_posix.c' -'src/core/lib/support/subprocess_windows.c' -'src/core/lib/support/sync.c' -'src/core/lib/support/sync_posix.c' -'src/core/lib/support/sync_windows.c' -'src/core/lib/support/thd.c' -'src/core/lib/support/thd_posix.c' -'src/core/lib/support/thd_windows.c' -'src/core/lib/support/time.c' -'src/core/lib/support/time_posix.c' -'src/core/lib/support/time_precise.c' -'src/core/lib/support/time_windows.c' -'src/core/lib/support/tls_pthread.c' -'src/core/lib/support/tmpfile_msys.c' -'src/core/lib/support/tmpfile_posix.c' -'src/core/lib/support/tmpfile_windows.c' -'src/core/lib/support/wrap_memcpy.c' -'src/core/lib/channel/channel_args.h' -'src/core/lib/channel/channel_stack.h' -'src/core/lib/channel/channel_stack_builder.h' -'src/core/lib/channel/compress_filter.h' -'src/core/lib/channel/connected_channel.h' -'src/core/lib/channel/context.h' -'src/core/lib/channel/deadline_filter.h' -'src/core/lib/channel/handshaker.h' -'src/core/lib/channel/http_client_filter.h' -'src/core/lib/channel/http_server_filter.h' -'src/core/lib/channel/message_size_filter.h' -'src/core/lib/compression/algorithm_metadata.h' -'src/core/lib/compression/message_compress.h' -'src/core/lib/debug/trace.h' -'src/core/lib/http/format_request.h' -'src/core/lib/http/httpcli.h' -'src/core/lib/http/parser.h' -'src/core/lib/iomgr/closure.h' -'src/core/lib/iomgr/combiner.h' -'src/core/lib/iomgr/endpoint.h' -'src/core/lib/iomgr/endpoint_pair.h' -'src/core/lib/iomgr/error.h' -'src/core/lib/iomgr/ev_epoll_linux.h' -'src/core/lib/iomgr/ev_poll_posix.h' -'src/core/lib/iomgr/ev_posix.h' -'src/core/lib/iomgr/exec_ctx.h' -'src/core/lib/iomgr/executor.h' -'src/core/lib/iomgr/iocp_windows.h' -'src/core/lib/iomgr/iomgr.h' -'src/core/lib/iomgr/iomgr_internal.h' -'src/core/lib/iomgr/iomgr_posix.h' -'src/core/lib/iomgr/load_file.h' -'src/core/lib/iomgr/network_status_tracker.h' -'src/core/lib/iomgr/polling_entity.h' -'src/core/lib/iomgr/pollset.h' -'src/core/lib/iomgr/pollset_set.h' -'src/core/lib/iomgr/pollset_set_windows.h' -'src/core/lib/iomgr/pollset_uv.h' -'src/core/lib/iomgr/pollset_windows.h' -'src/core/lib/iomgr/port.h' -'src/core/lib/iomgr/resolve_address.h' -'src/core/lib/iomgr/resource_quota.h' -'src/core/lib/iomgr/sockaddr.h' -'src/core/lib/iomgr/sockaddr_posix.h' -'src/core/lib/iomgr/sockaddr_utils.h' -'src/core/lib/iomgr/sockaddr_windows.h' -'src/core/lib/iomgr/socket_mutator.h' -'src/core/lib/iomgr/socket_utils.h' -'src/core/lib/iomgr/socket_utils_posix.h' -'src/core/lib/iomgr/socket_windows.h' -'src/core/lib/iomgr/tcp_client.h' -'src/core/lib/iomgr/tcp_client_posix.h' -'src/core/lib/iomgr/tcp_posix.h' -'src/core/lib/iomgr/tcp_server.h' -'src/core/lib/iomgr/tcp_uv.h' -'src/core/lib/iomgr/tcp_windows.h' -'src/core/lib/iomgr/time_averaged_stats.h' -'src/core/lib/iomgr/timer.h' -'src/core/lib/iomgr/timer_generic.h' -'src/core/lib/iomgr/timer_heap.h' -'src/core/lib/iomgr/timer_uv.h' -'src/core/lib/iomgr/udp_server.h' -'src/core/lib/iomgr/unix_sockets_posix.h' -'src/core/lib/iomgr/wakeup_fd_cv.h' -'src/core/lib/iomgr/wakeup_fd_pipe.h' -'src/core/lib/iomgr/wakeup_fd_posix.h' -'src/core/lib/iomgr/workqueue.h' -'src/core/lib/iomgr/workqueue_uv.h' -'src/core/lib/iomgr/workqueue_windows.h' -'src/core/lib/json/json.h' -'src/core/lib/json/json_common.h' -'src/core/lib/json/json_reader.h' -'src/core/lib/json/json_writer.h' -'src/core/lib/slice/percent_encoding.h' -'src/core/lib/slice/slice_string_helpers.h' -'src/core/lib/surface/api_trace.h' -'src/core/lib/surface/call.h' -'src/core/lib/surface/call_test_only.h' -'src/core/lib/surface/channel.h' -'src/core/lib/surface/channel_init.h' -'src/core/lib/surface/channel_stack_type.h' -'src/core/lib/surface/completion_queue.h' -'src/core/lib/surface/event_string.h' -'src/core/lib/surface/init.h' -'src/core/lib/surface/lame_client.h' -'src/core/lib/surface/server.h' -'src/core/lib/transport/byte_stream.h' -'src/core/lib/transport/connectivity_state.h' -'src/core/lib/transport/mdstr_hash_table.h' -'src/core/lib/transport/metadata.h' -'src/core/lib/transport/metadata_batch.h' -'src/core/lib/transport/pid_controller.h' -'src/core/lib/transport/service_config.h' -'src/core/lib/transport/static_metadata.h' -'src/core/lib/transport/timeout_encoding.h' -'src/core/lib/transport/transport.h' -'src/core/lib/transport/transport_impl.h' -'src/core/ext/transport/chttp2/transport/bin_decoder.h' -'src/core/ext/transport/chttp2/transport/bin_encoder.h' -'src/core/ext/transport/chttp2/transport/chttp2_transport.h' -'src/core/ext/transport/chttp2/transport/frame.h' -'src/core/ext/transport/chttp2/transport/frame_data.h' -'src/core/ext/transport/chttp2/transport/frame_goaway.h' -'src/core/ext/transport/chttp2/transport/frame_ping.h' -'src/core/ext/transport/chttp2/transport/frame_rst_stream.h' -'src/core/ext/transport/chttp2/transport/frame_settings.h' -'src/core/ext/transport/chttp2/transport/frame_window_update.h' -'src/core/ext/transport/chttp2/transport/hpack_encoder.h' -'src/core/ext/transport/chttp2/transport/hpack_parser.h' -'src/core/ext/transport/chttp2/transport/hpack_table.h' -'src/core/ext/transport/chttp2/transport/http2_errors.h' -'src/core/ext/transport/chttp2/transport/huffsyms.h' -'src/core/ext/transport/chttp2/transport/incoming_metadata.h' -'src/core/ext/transport/chttp2/transport/internal.h' -'src/core/ext/transport/chttp2/transport/status_conversion.h' -'src/core/ext/transport/chttp2/transport/stream_map.h' -'src/core/ext/transport/chttp2/transport/varint.h' -'src/core/ext/transport/chttp2/alpn/alpn.h' -'src/core/lib/security/context/security_context.h' -'src/core/lib/security/credentials/composite/composite_credentials.h' -'src/core/lib/security/credentials/credentials.h' -'src/core/lib/security/credentials/fake/fake_credentials.h' -'src/core/lib/security/credentials/google_default/google_default_credentials.h' -'src/core/lib/security/credentials/iam/iam_credentials.h' -'src/core/lib/security/credentials/jwt/json_token.h' -'src/core/lib/security/credentials/jwt/jwt_credentials.h' -'src/core/lib/security/credentials/jwt/jwt_verifier.h' -'src/core/lib/security/credentials/oauth2/oauth2_credentials.h' -'src/core/lib/security/credentials/plugin/plugin_credentials.h' -'src/core/lib/security/credentials/ssl/ssl_credentials.h' -'src/core/lib/security/transport/auth_filters.h' -'src/core/lib/security/transport/secure_endpoint.h' -'src/core/lib/security/transport/security_connector.h' -'src/core/lib/security/transport/security_handshaker.h' -'src/core/lib/security/transport/tsi_error.h' -'src/core/lib/security/util/b64.h' -'src/core/lib/security/util/json_util.h' -'src/core/lib/tsi/fake_transport_security.h' -'src/core/lib/tsi/ssl_transport_security.h' -'src/core/lib/tsi/ssl_types.h' -'src/core/lib/tsi/transport_security.h' -'src/core/lib/tsi/transport_security_interface.h' -'src/core/ext/transport/chttp2/server/chttp2_server.h' -'src/core/ext/client_channel/client_channel.h' -'src/core/ext/client_channel/client_channel_factory.h' -'src/core/ext/client_channel/connector.h' -'src/core/ext/client_channel/http_connect_handshaker.h' -'src/core/ext/client_channel/initial_connect_string.h' -'src/core/ext/client_channel/lb_policy.h' -'src/core/ext/client_channel/lb_policy_factory.h' -'src/core/ext/client_channel/lb_policy_registry.h' -'src/core/ext/client_channel/parse_address.h' -'src/core/ext/client_channel/resolver.h' -'src/core/ext/client_channel/resolver_factory.h' -'src/core/ext/client_channel/resolver_registry.h' -'src/core/ext/client_channel/subchannel.h' -'src/core/ext/client_channel/subchannel_index.h' -'src/core/ext/client_channel/uri_parser.h' -'src/core/ext/transport/chttp2/client/chttp2_connector.h' -'src/core/ext/lb_policy/grpclb/grpclb.h' -'src/core/ext/lb_policy/grpclb/load_balancer_api.h' -'src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h' -'third_party/nanopb/pb.h' -'third_party/nanopb/pb_common.h' -'third_party/nanopb/pb_decode.h' -'third_party/nanopb/pb_encode.h' -'src/core/ext/load_reporting/load_reporting.h' -'src/core/ext/load_reporting/load_reporting_filter.h' -'src/core/ext/census/aggregation.h' -'src/core/ext/census/base_resources.h' -'src/core/ext/census/census_interface.h' -'src/core/ext/census/census_rpc_stats.h' -'src/core/ext/census/gen/census.pb.h' -'src/core/ext/census/gen/trace_context.pb.h' -'src/core/ext/census/grpc_filter.h' -'src/core/ext/census/mlog.h' -'src/core/ext/census/resource.h' -'src/core/ext/census/rpc_metric_id.h' -'src/core/ext/census/trace_context.h' -'src/core/lib/surface/init.c' -'src/core/lib/channel/channel_args.c' -'src/core/lib/channel/channel_stack.c' -'src/core/lib/channel/channel_stack_builder.c' -'src/core/lib/channel/compress_filter.c' -'src/core/lib/channel/connected_channel.c' -'src/core/lib/channel/deadline_filter.c' -'src/core/lib/channel/handshaker.c' -'src/core/lib/channel/http_client_filter.c' -'src/core/lib/channel/http_server_filter.c' -'src/core/lib/channel/message_size_filter.c' -'src/core/lib/compression/compression.c' -'src/core/lib/compression/message_compress.c' -'src/core/lib/debug/trace.c' -'src/core/lib/http/format_request.c' -'src/core/lib/http/httpcli.c' -'src/core/lib/http/parser.c' -'src/core/lib/iomgr/closure.c' -'src/core/lib/iomgr/combiner.c' -'src/core/lib/iomgr/endpoint.c' -'src/core/lib/iomgr/endpoint_pair_posix.c' -'src/core/lib/iomgr/endpoint_pair_uv.c' -'src/core/lib/iomgr/endpoint_pair_windows.c' -'src/core/lib/iomgr/error.c' -'src/core/lib/iomgr/ev_epoll_linux.c' -'src/core/lib/iomgr/ev_poll_posix.c' -'src/core/lib/iomgr/ev_posix.c' -'src/core/lib/iomgr/exec_ctx.c' -'src/core/lib/iomgr/executor.c' -'src/core/lib/iomgr/iocp_windows.c' -'src/core/lib/iomgr/iomgr.c' -'src/core/lib/iomgr/iomgr_posix.c' -'src/core/lib/iomgr/iomgr_uv.c' -'src/core/lib/iomgr/iomgr_windows.c' -'src/core/lib/iomgr/load_file.c' -'src/core/lib/iomgr/network_status_tracker.c' -'src/core/lib/iomgr/polling_entity.c' -'src/core/lib/iomgr/pollset_set_uv.c' -'src/core/lib/iomgr/pollset_set_windows.c' -'src/core/lib/iomgr/pollset_uv.c' -'src/core/lib/iomgr/pollset_windows.c' -'src/core/lib/iomgr/resolve_address_posix.c' -'src/core/lib/iomgr/resolve_address_uv.c' -'src/core/lib/iomgr/resolve_address_windows.c' -'src/core/lib/iomgr/resource_quota.c' -'src/core/lib/iomgr/sockaddr_utils.c' -'src/core/lib/iomgr/socket_mutator.c' -'src/core/lib/iomgr/socket_utils_common_posix.c' -'src/core/lib/iomgr/socket_utils_linux.c' -'src/core/lib/iomgr/socket_utils_posix.c' -'src/core/lib/iomgr/socket_utils_uv.c' -'src/core/lib/iomgr/socket_utils_windows.c' -'src/core/lib/iomgr/socket_windows.c' -'src/core/lib/iomgr/tcp_client_posix.c' -'src/core/lib/iomgr/tcp_client_uv.c' -'src/core/lib/iomgr/tcp_client_windows.c' -'src/core/lib/iomgr/tcp_posix.c' -'src/core/lib/iomgr/tcp_server_posix.c' -'src/core/lib/iomgr/tcp_server_uv.c' -'src/core/lib/iomgr/tcp_server_windows.c' -'src/core/lib/iomgr/tcp_uv.c' -'src/core/lib/iomgr/tcp_windows.c' -'src/core/lib/iomgr/time_averaged_stats.c' -'src/core/lib/iomgr/timer_generic.c' -'src/core/lib/iomgr/timer_heap.c' -'src/core/lib/iomgr/timer_uv.c' -'src/core/lib/iomgr/udp_server.c' -'src/core/lib/iomgr/unix_sockets_posix.c' -'src/core/lib/iomgr/unix_sockets_posix_noop.c' -'src/core/lib/iomgr/wakeup_fd_cv.c' -'src/core/lib/iomgr/wakeup_fd_eventfd.c' -'src/core/lib/iomgr/wakeup_fd_nospecial.c' -'src/core/lib/iomgr/wakeup_fd_pipe.c' -'src/core/lib/iomgr/wakeup_fd_posix.c' -'src/core/lib/iomgr/workqueue_uv.c' -'src/core/lib/iomgr/workqueue_windows.c' -'src/core/lib/json/json.c' -'src/core/lib/json/json_reader.c' -'src/core/lib/json/json_string.c' -'src/core/lib/json/json_writer.c' -'src/core/lib/slice/percent_encoding.c' -'src/core/lib/slice/slice.c' -'src/core/lib/slice/slice_buffer.c' -'src/core/lib/slice/slice_string_helpers.c' -'src/core/lib/surface/alarm.c' -'src/core/lib/surface/api_trace.c' -'src/core/lib/surface/byte_buffer.c' -'src/core/lib/surface/byte_buffer_reader.c' -'src/core/lib/surface/call.c' -'src/core/lib/surface/call_details.c' -'src/core/lib/surface/call_log_batch.c' -'src/core/lib/surface/channel.c' -'src/core/lib/surface/channel_init.c' -'src/core/lib/surface/channel_ping.c' -'src/core/lib/surface/channel_stack_type.c' -'src/core/lib/surface/completion_queue.c' -'src/core/lib/surface/event_string.c' -'src/core/lib/surface/lame_client.c' -'src/core/lib/surface/metadata_array.c' -'src/core/lib/surface/server.c' -'src/core/lib/surface/validate_metadata.c' -'src/core/lib/surface/version.c' -'src/core/lib/transport/byte_stream.c' -'src/core/lib/transport/connectivity_state.c' -'src/core/lib/transport/mdstr_hash_table.c' -'src/core/lib/transport/metadata.c' -'src/core/lib/transport/metadata_batch.c' -'src/core/lib/transport/pid_controller.c' -'src/core/lib/transport/service_config.c' -'src/core/lib/transport/static_metadata.c' -'src/core/lib/transport/timeout_encoding.c' -'src/core/lib/transport/transport.c' -'src/core/lib/transport/transport_op_string.c' -'src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c' -'src/core/ext/transport/chttp2/transport/bin_decoder.c' -'src/core/ext/transport/chttp2/transport/bin_encoder.c' -'src/core/ext/transport/chttp2/transport/chttp2_plugin.c' -'src/core/ext/transport/chttp2/transport/chttp2_transport.c' -'src/core/ext/transport/chttp2/transport/frame_data.c' -'src/core/ext/transport/chttp2/transport/frame_goaway.c' -'src/core/ext/transport/chttp2/transport/frame_ping.c' -'src/core/ext/transport/chttp2/transport/frame_rst_stream.c' -'src/core/ext/transport/chttp2/transport/frame_settings.c' -'src/core/ext/transport/chttp2/transport/frame_window_update.c' -'src/core/ext/transport/chttp2/transport/hpack_encoder.c' -'src/core/ext/transport/chttp2/transport/hpack_parser.c' -'src/core/ext/transport/chttp2/transport/hpack_table.c' -'src/core/ext/transport/chttp2/transport/huffsyms.c' -'src/core/ext/transport/chttp2/transport/incoming_metadata.c' -'src/core/ext/transport/chttp2/transport/parsing.c' -'src/core/ext/transport/chttp2/transport/status_conversion.c' -'src/core/ext/transport/chttp2/transport/stream_lists.c' -'src/core/ext/transport/chttp2/transport/stream_map.c' -'src/core/ext/transport/chttp2/transport/varint.c' -'src/core/ext/transport/chttp2/transport/writing.c' -'src/core/ext/transport/chttp2/alpn/alpn.c' -'src/core/lib/http/httpcli_security_connector.c' -'src/core/lib/security/context/security_context.c' -'src/core/lib/security/credentials/composite/composite_credentials.c' -'src/core/lib/security/credentials/credentials.c' -'src/core/lib/security/credentials/credentials_metadata.c' -'src/core/lib/security/credentials/fake/fake_credentials.c' -'src/core/lib/security/credentials/google_default/credentials_generic.c' -'src/core/lib/security/credentials/google_default/google_default_credentials.c' -'src/core/lib/security/credentials/iam/iam_credentials.c' -'src/core/lib/security/credentials/jwt/json_token.c' -'src/core/lib/security/credentials/jwt/jwt_credentials.c' -'src/core/lib/security/credentials/jwt/jwt_verifier.c' -'src/core/lib/security/credentials/oauth2/oauth2_credentials.c' -'src/core/lib/security/credentials/plugin/plugin_credentials.c' -'src/core/lib/security/credentials/ssl/ssl_credentials.c' -'src/core/lib/security/transport/client_auth_filter.c' -'src/core/lib/security/transport/secure_endpoint.c' -'src/core/lib/security/transport/security_connector.c' -'src/core/lib/security/transport/security_handshaker.c' -'src/core/lib/security/transport/server_auth_filter.c' -'src/core/lib/security/transport/tsi_error.c' -'src/core/lib/security/util/b64.c' -'src/core/lib/security/util/json_util.c' -'src/core/lib/surface/init_secure.c' -'src/core/lib/tsi/fake_transport_security.c' -'src/core/lib/tsi/ssl_transport_security.c' -'src/core/lib/tsi/transport_security.c' -'src/core/ext/transport/chttp2/server/chttp2_server.c' -'src/core/ext/transport/chttp2/client/secure/secure_channel_create.c' -'src/core/ext/client_channel/channel_connectivity.c' -'src/core/ext/client_channel/client_channel.c' -'src/core/ext/client_channel/client_channel_factory.c' -'src/core/ext/client_channel/client_channel_plugin.c' -'src/core/ext/client_channel/connector.c' -'src/core/ext/client_channel/default_initial_connect_string.c' -'src/core/ext/client_channel/http_connect_handshaker.c' -'src/core/ext/client_channel/initial_connect_string.c' -'src/core/ext/client_channel/lb_policy.c' -'src/core/ext/client_channel/lb_policy_factory.c' -'src/core/ext/client_channel/lb_policy_registry.c' -'src/core/ext/client_channel/parse_address.c' -'src/core/ext/client_channel/resolver.c' -'src/core/ext/client_channel/resolver_factory.c' -'src/core/ext/client_channel/resolver_registry.c' -'src/core/ext/client_channel/subchannel.c' -'src/core/ext/client_channel/subchannel_index.c' -'src/core/ext/client_channel/uri_parser.c' -'src/core/ext/transport/chttp2/client/chttp2_connector.c' -'src/core/ext/transport/chttp2/server/insecure/server_chttp2.c' -'src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c' -'src/core/ext/transport/chttp2/client/insecure/channel_create.c' -'src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c' -'src/core/ext/lb_policy/grpclb/grpclb.c' -'src/core/ext/lb_policy/grpclb/load_balancer_api.c' -'src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c' -'third_party/nanopb/pb_common.c' -'third_party/nanopb/pb_decode.c' -'third_party/nanopb/pb_encode.c' -'src/core/ext/lb_policy/pick_first/pick_first.c' -'src/core/ext/lb_policy/round_robin/round_robin.c' -'src/core/ext/resolver/dns/native/dns_resolver.c' -'src/core/ext/resolver/sockaddr/sockaddr_resolver.c' -'src/core/ext/load_reporting/load_reporting.c' -'src/core/ext/load_reporting/load_reporting_filter.c' -'src/core/ext/census/base_resources.c' -'src/core/ext/census/context.c' -'src/core/ext/census/gen/census.pb.c' -'src/core/ext/census/gen/trace_context.pb.c' -'src/core/ext/census/grpc_context.c' -'src/core/ext/census/grpc_filter.c' -'src/core/ext/census/grpc_plugin.c' -'src/core/ext/census/initialize.c' -'src/core/ext/census/mlog.c' -'src/core/ext/census/operation.c' -'src/core/ext/census/placeholders.c' -'src/core/ext/census/resource.c' -'src/core/ext/census/trace_context.c' -'src/core/ext/census/tracing.c' -'src/core/plugin_registry/grpc_plugin_registry.c') - -private_headers=( -'src/core/lib/profiling/timers.h' -'src/core/lib/support/backoff.h' -'src/core/lib/support/block_annotate.h' -'src/core/lib/support/env.h' -'src/core/lib/support/mpscq.h' -'src/core/lib/support/murmur_hash.h' -'src/core/lib/support/stack_lockfree.h' -'src/core/lib/support/string.h' -'src/core/lib/support/string_windows.h' -'src/core/lib/support/thd_internal.h' -'src/core/lib/support/time_precise.h' -'src/core/lib/support/tmpfile.h' -'src/core/lib/channel/channel_args.h' -'src/core/lib/channel/channel_stack.h' -'src/core/lib/channel/channel_stack_builder.h' -'src/core/lib/channel/compress_filter.h' -'src/core/lib/channel/connected_channel.h' -'src/core/lib/channel/context.h' -'src/core/lib/channel/deadline_filter.h' -'src/core/lib/channel/handshaker.h' -'src/core/lib/channel/http_client_filter.h' -'src/core/lib/channel/http_server_filter.h' -'src/core/lib/channel/message_size_filter.h' -'src/core/lib/compression/algorithm_metadata.h' -'src/core/lib/compression/message_compress.h' -'src/core/lib/debug/trace.h' -'src/core/lib/http/format_request.h' -'src/core/lib/http/httpcli.h' -'src/core/lib/http/parser.h' -'src/core/lib/iomgr/closure.h' -'src/core/lib/iomgr/combiner.h' -'src/core/lib/iomgr/endpoint.h' -'src/core/lib/iomgr/endpoint_pair.h' -'src/core/lib/iomgr/error.h' -'src/core/lib/iomgr/ev_epoll_linux.h' -'src/core/lib/iomgr/ev_poll_posix.h' -'src/core/lib/iomgr/ev_posix.h' -'src/core/lib/iomgr/exec_ctx.h' -'src/core/lib/iomgr/executor.h' -'src/core/lib/iomgr/iocp_windows.h' -'src/core/lib/iomgr/iomgr.h' -'src/core/lib/iomgr/iomgr_internal.h' -'src/core/lib/iomgr/iomgr_posix.h' -'src/core/lib/iomgr/load_file.h' -'src/core/lib/iomgr/network_status_tracker.h' -'src/core/lib/iomgr/polling_entity.h' -'src/core/lib/iomgr/pollset.h' -'src/core/lib/iomgr/pollset_set.h' -'src/core/lib/iomgr/pollset_set_windows.h' -'src/core/lib/iomgr/pollset_uv.h' -'src/core/lib/iomgr/pollset_windows.h' -'src/core/lib/iomgr/port.h' -'src/core/lib/iomgr/resolve_address.h' -'src/core/lib/iomgr/resource_quota.h' -'src/core/lib/iomgr/sockaddr.h' -'src/core/lib/iomgr/sockaddr_posix.h' -'src/core/lib/iomgr/sockaddr_utils.h' -'src/core/lib/iomgr/sockaddr_windows.h' -'src/core/lib/iomgr/socket_mutator.h' -'src/core/lib/iomgr/socket_utils.h' -'src/core/lib/iomgr/socket_utils_posix.h' -'src/core/lib/iomgr/socket_windows.h' -'src/core/lib/iomgr/tcp_client.h' -'src/core/lib/iomgr/tcp_client_posix.h' -'src/core/lib/iomgr/tcp_posix.h' -'src/core/lib/iomgr/tcp_server.h' -'src/core/lib/iomgr/tcp_uv.h' -'src/core/lib/iomgr/tcp_windows.h' -'src/core/lib/iomgr/time_averaged_stats.h' -'src/core/lib/iomgr/timer.h' -'src/core/lib/iomgr/timer_generic.h' -'src/core/lib/iomgr/timer_heap.h' -'src/core/lib/iomgr/timer_uv.h' -'src/core/lib/iomgr/udp_server.h' -'src/core/lib/iomgr/unix_sockets_posix.h' -'src/core/lib/iomgr/wakeup_fd_cv.h' -'src/core/lib/iomgr/wakeup_fd_pipe.h' -'src/core/lib/iomgr/wakeup_fd_posix.h' -'src/core/lib/iomgr/workqueue.h' -'src/core/lib/iomgr/workqueue_uv.h' -'src/core/lib/iomgr/workqueue_windows.h' -'src/core/lib/json/json.h' -'src/core/lib/json/json_common.h' -'src/core/lib/json/json_reader.h' -'src/core/lib/json/json_writer.h' -'src/core/lib/slice/percent_encoding.h' -'src/core/lib/slice/slice_string_helpers.h' -'src/core/lib/surface/api_trace.h' -'src/core/lib/surface/call.h' -'src/core/lib/surface/call_test_only.h' -'src/core/lib/surface/channel.h' -'src/core/lib/surface/channel_init.h' -'src/core/lib/surface/channel_stack_type.h' -'src/core/lib/surface/completion_queue.h' -'src/core/lib/surface/event_string.h' -'src/core/lib/surface/init.h' -'src/core/lib/surface/lame_client.h' -'src/core/lib/surface/server.h' -'src/core/lib/transport/byte_stream.h' -'src/core/lib/transport/connectivity_state.h' -'src/core/lib/transport/mdstr_hash_table.h' -'src/core/lib/transport/metadata.h' -'src/core/lib/transport/metadata_batch.h' -'src/core/lib/transport/pid_controller.h' -'src/core/lib/transport/service_config.h' -'src/core/lib/transport/static_metadata.h' -'src/core/lib/transport/timeout_encoding.h' -'src/core/lib/transport/transport.h' -'src/core/lib/transport/transport_impl.h' -'src/core/ext/transport/chttp2/transport/bin_decoder.h' -'src/core/ext/transport/chttp2/transport/bin_encoder.h' -'src/core/ext/transport/chttp2/transport/chttp2_transport.h' -'src/core/ext/transport/chttp2/transport/frame.h' -'src/core/ext/transport/chttp2/transport/frame_data.h' -'src/core/ext/transport/chttp2/transport/frame_goaway.h' -'src/core/ext/transport/chttp2/transport/frame_ping.h' -'src/core/ext/transport/chttp2/transport/frame_rst_stream.h' -'src/core/ext/transport/chttp2/transport/frame_settings.h' -'src/core/ext/transport/chttp2/transport/frame_window_update.h' -'src/core/ext/transport/chttp2/transport/hpack_encoder.h' -'src/core/ext/transport/chttp2/transport/hpack_parser.h' -'src/core/ext/transport/chttp2/transport/hpack_table.h' -'src/core/ext/transport/chttp2/transport/http2_errors.h' -'src/core/ext/transport/chttp2/transport/huffsyms.h' -'src/core/ext/transport/chttp2/transport/incoming_metadata.h' -'src/core/ext/transport/chttp2/transport/internal.h' -'src/core/ext/transport/chttp2/transport/status_conversion.h' -'src/core/ext/transport/chttp2/transport/stream_map.h' -'src/core/ext/transport/chttp2/transport/varint.h' -'src/core/ext/transport/chttp2/alpn/alpn.h' -'src/core/lib/security/context/security_context.h' -'src/core/lib/security/credentials/composite/composite_credentials.h' -'src/core/lib/security/credentials/credentials.h' -'src/core/lib/security/credentials/fake/fake_credentials.h' -'src/core/lib/security/credentials/google_default/google_default_credentials.h' -'src/core/lib/security/credentials/iam/iam_credentials.h' -'src/core/lib/security/credentials/jwt/json_token.h' -'src/core/lib/security/credentials/jwt/jwt_credentials.h' -'src/core/lib/security/credentials/jwt/jwt_verifier.h' -'src/core/lib/security/credentials/oauth2/oauth2_credentials.h' -'src/core/lib/security/credentials/plugin/plugin_credentials.h' -'src/core/lib/security/credentials/ssl/ssl_credentials.h' -'src/core/lib/security/transport/auth_filters.h' -'src/core/lib/security/transport/secure_endpoint.h' -'src/core/lib/security/transport/security_connector.h' -'src/core/lib/security/transport/security_handshaker.h' -'src/core/lib/security/transport/tsi_error.h' -'src/core/lib/security/util/b64.h' -'src/core/lib/security/util/json_util.h' -'src/core/lib/tsi/fake_transport_security.h' -'src/core/lib/tsi/ssl_transport_security.h' -'src/core/lib/tsi/ssl_types.h' -'src/core/lib/tsi/transport_security.h' -'src/core/lib/tsi/transport_security_interface.h' -'src/core/ext/transport/chttp2/server/chttp2_server.h' -'src/core/ext/client_channel/client_channel.h' -'src/core/ext/client_channel/client_channel_factory.h' -'src/core/ext/client_channel/connector.h' -'src/core/ext/client_channel/http_connect_handshaker.h' -'src/core/ext/client_channel/initial_connect_string.h' -'src/core/ext/client_channel/lb_policy.h' -'src/core/ext/client_channel/lb_policy_factory.h' -'src/core/ext/client_channel/lb_policy_registry.h' -'src/core/ext/client_channel/parse_address.h' -'src/core/ext/client_channel/resolver.h' -'src/core/ext/client_channel/resolver_factory.h' -'src/core/ext/client_channel/resolver_registry.h' -'src/core/ext/client_channel/subchannel.h' -'src/core/ext/client_channel/subchannel_index.h' -'src/core/ext/client_channel/uri_parser.h' -'src/core/ext/transport/chttp2/client/chttp2_connector.h' -'src/core/ext/lb_policy/grpclb/grpclb.h' -'src/core/ext/lb_policy/grpclb/load_balancer_api.h' -'src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h' -'third_party/nanopb/pb.h' -'third_party/nanopb/pb_common.h' -'third_party/nanopb/pb_decode.h' -'third_party/nanopb/pb_encode.h' -'src/core/ext/load_reporting/load_reporting.h' -'src/core/ext/load_reporting/load_reporting_filter.h' -'src/core/ext/census/aggregation.h' -'src/core/ext/census/base_resources.h' -'src/core/ext/census/census_interface.h' -'src/core/ext/census/census_rpc_stats.h' -'src/core/ext/census/gen/census.pb.h' -'src/core/ext/census/gen/trace_context.pb.h' -'src/core/ext/census/grpc_filter.h' -'src/core/ext/census/mlog.h' -'src/core/ext/census/resource.h' -'src/core/ext/census/rpc_metric_id.h' -'src/core/ext/census/trace_context.h') +source third_party/grpc/swift-vendoring.sh rm -rf Sources/CgRPC/src -rm -rf Sources/CgRPC/third_party rm -rf Sources/CgRPC/grpc +rm -rf Sources/CgRPC/third_party +rm Sources/CgRPC/include/grpc for src in "${public_headers[@]}" do dest="Sources/CgRPC/$src" dest_dir=$(dirname $dest) - mkdir -p $dest_dir + mkdir -pv $dest_dir cp third_party/grpc/$src $dest done @@ -749,7 +40,7 @@ for src in "${source_files[@]}" do dest="Sources/CgRPC/$src" dest_dir=$(dirname $dest) - mkdir -p $dest_dir + mkdir -pv $dest_dir cp third_party/grpc/$src $dest done @@ -757,10 +48,18 @@ for src in "${private_headers[@]}" do dest="Sources/CgRPC/$src" dest_dir=$(dirname $dest) - mkdir -p $dest_dir + mkdir -pv $dest_dir cp third_party/grpc/$src $dest done +echo "TODO:" +echo "link the grpc headers" +cd Sources/CgRPC/include; ln -s ../grpc; cd ../../.. +echo "get the nanopb headers" +cp third_party/grpc/third_party/nanopb/*.h Sources/CgRPC/third_party/nanopb/ +echo "#define GRPC_ARES 0 in grpc/impl/codegen/port_platform.h" +perl -pi -e 's/#define GRPC_ARES 1/#define GRPC_ARES 0/' Sources/CgRPC/grpc/impl/codegen/port_platform.h echo "ok" -exit + +